1/* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)locore.s 7.18 (Berkeley) 05/08/91 7 */ 8 9#include "tahoe/include/mtpr.h" 10#include "tahoe/include/trap.h" 11#include "tahoe/include/psl.h" 12#include "tahoe/include/pte.h" 13#include "tahoe/tahoe/cp.h" 14#include "tahoe/tahoe/mem.h" 15#include "tahoe/tahoe/SYS.h" 16 17#include "tahoe/math/fp.h" 18 19#include "sys/errno.h" 20#include "sys/syscall.h" 21#include "sys/cmap.h" 22 23 .set HIGH,0x1f # mask for total disable 24 .set NISP,3 # number of interrupt stack pages 25 .set SYSTEM,0xC0000000 # virtual address of system start 26 .set PPAGES,0x100000 # possible pages in P0,P1, etc. 27 28/* ACBL for non-negative '_add' */ 29#define ACBL(_limit,_add,_index,_displ) \ 30 addl2 _add,_index; \ 31 cmpl _index,_limit; \ 32 bleq _displ 33 34/* _ACBL for negative '_add' */ 35#define _ACBL(_limit,_add,_index,_displ) \ 36 addl2 _add,_index; \ 37 cmpl _index,_limit; \ 38 bgeq _displ 39 40#define MOVC3(_srcaddr,_dstaddr,_len) \ 41 movl _srcaddr,r0; \ 42 movl _dstaddr,r1; \ 43 movl _len,r2; \ 44 movblk 45 46/* keep address of psl if coming from user mode */ 47#define CHECK_SFE(_delta) \ 48 bitl $PSL_CURMOD,_delta(sp); \ 49 jeql 1f; \ 50 moval _delta(sp),_user_psl; \ 511: 52 53/* 54 * User structure is UPAGES at top of user space. 55 */ 56 .globl _u 57 .set _u,SYSTEM - UPAGES*NBPG 58 59/* 60 * Restart stack. Used on power recovery or panic. 61 * Takes a core-dump and then halts. 62 */ 63 .globl _rsstk 64 .globl pwfl_stk 65_rsstk: 66 .space 1024-8 67pwfl_stk: 68 .space 4 69dumpflag: 70 .space 4 71 72 .globl _intstack 73_intstack: 74 .space NISP*NBPG 75eintstack: 76 77/* 78 * Power failure storage block and 79 * macros for saving and restoring. 80 */ 81#define POWERFAIL(id,longs) \ 82 .globl pwfl_/**/id \ 83pwfl_/**/id: .space longs*4 84 .data 85 POWERFAIL(r0, 14) # r0-r13 86 POWERFAIL(sp, 1) # r14 87 POWERFAIL(SCBB, 1) # system control block base 88 POWERFAIL(SBR, 1) # system pte base 89 POWERFAIL(SLR, 1) # system pte length 90 POWERFAIL(P0BR, 1) # p0 pte base 91 POWERFAIL(P0LR, 1) # p0 pte length 92 POWERFAIL(P1BR, 1) # p1 pte base 93 POWERFAIL(P1LR, 1) # p1 pte length 94 POWERFAIL(P2BR, 1) # p2 pte base 95 POWERFAIL(P2LR, 1) # p2 pte length 96 POWERFAIL(IPL, 1) # interrupt priority level 97 POWERFAIL(DCK, 1) # data cache key 98 POWERFAIL(CCK, 1) # code cache key 99 POWERFAIL(PCBB, 1) # process control block base 100 POWERFAIL(ISP, 1) # interrupt stack pointer 101 POWERFAIL(KSP, 1) # kernel mode stack pointer 102 POWERFAIL(USP, 1) # user mode stack pointer 103 POWERFAIL(MME, 1) # memory management enable 104 POWERFAIL(PSL, 1) # processor status longword 105 106/* 107 * Save current state in power fail storage block. 108 */ 109#define SAVEpwfl() \ 110 movpsl pwfl_PSL # Keeps all flags, etc. \ 111 storer $0x3fff,pwfl_r0 # Saves r0-r13 \ 112 moval 0(sp),pwfl_sp # Saves sp (=r14) \ 113 mfpr $SBR,pwfl_SBR # Save all re_loadable registers \ 114 mfpr $SLR,pwfl_SLR \ 115 mfpr $P0BR,pwfl_P0BR \ 116 mfpr $P0LR,pwfl_P0LR \ 117 mfpr $P1BR,pwfl_P1BR \ 118 mfpr $P1LR,pwfl_P1LR \ 119 mfpr $P2BR,pwfl_P2BR \ 120 mfpr $P2LR,pwfl_P2LR \ 121 mfpr $IPL,pwfl_IPL \ 122 mfpr $MME,pwfl_MME \ 123 mfpr $DCK,pwfl_DCK \ 124 mfpr $CCK,pwfl_CCK \ 125 mfpr $PCBB,pwfl_PCBB \ 126 mfpr $ISP,pwfl_ISP \ 127 mfpr $SCBB,pwfl_SCBB \ 128 mfpr $KSP,pwfl_KSP \ 129 mfpr $USP,pwfl_USP 130 131/* 132 * Restore state saved in power fail block and 133 * jmp to location specified after (possibly) 134 * enabling memory management. 135 */ 136#define RESTOREpwfl(loc) \ 137 loadr $0x3fff,pwfl_r0 # Restore r0-r13 \ 138 movl pwfl_sp,sp # Restore sp (=r14) \ 139 mtpr pwfl_SCBB,$SCBB \ 140 mtpr pwfl_SBR,$SBR # Restore all re_loadable registers \ 141 mtpr pwfl_SLR,$SLR \ 142 mtpr pwfl_P0BR,$P0BR \ 143 mtpr pwfl_P0LR,$P0LR \ 144 mtpr pwfl_P1BR,$P1BR \ 145 mtpr pwfl_P1LR,$P1LR \ 146 mtpr pwfl_P2BR,$P2BR \ 147 mtpr pwfl_P2LR,$P2LR \ 148 mtpr pwfl_IPL,$IPL \ 149 mtpr pwfl_DCK,$DCK \ 150 mtpr pwfl_CCK,$CCK \ 151 mtpr pwfl_PCBB,$PCBB \ 152 mtpr pwfl_ISP,$ISP \ 153 mtpr pwfl_KSP,$KSP \ 154 mtpr pwfl_USP,$USP \ 155\ 156 bicpsw $0xff # Restore PSW. \ 157 bispsw pwfl_PSL+2 # Set original bits back (just in case..) \ 158# now go to mapped mode \ 159# Have to change PC to system addresses \ 160 mtpr $1,$PACC # Thoroughly clean up caches. \ 161 mtpr $1,$PADC \ 162 mtpr $1,$TBIA \ 163 mtpr pwfl_MME,$MME # Restore MME. Last thing to be done. \ 164 jmp loc 165 166/* 167 * Do a dump. 168 * Called by auto-restart. 169 * May be called manually. 170 */ 171 .align 2 172 .text 173 .globl _Xdoadump 174 .globl _doadump 175_Xdoadump: # CP comes here after power fail 176 RESTOREpwfl(*0f) # restore state 177_doadump: 178 .word 0 1790: mtpr $HIGH,$IPL 180#define _rsstkmap _Sysmap+12 # powerfail storage, scb, rsstk, int stack 181 tstl dumpflag # dump only once! 182 bneq 1f 183 andl2 $~PG_PROT,_rsstkmap 184 orl2 $PG_KW,_rsstkmap # Make dump stack r/w 185 mtpr $0,$TBIA 186 movl $1,dumpflag 187 movab dumpflag,sp 188 callf $4,_dumpsys 1891: 190 halt 191 192/* 193 * Interrupt vector routines 194 */ 195 .globl _waittime 196#define SCBVEC(name) \ 197 .align 2; \ 198 .globl _X/**/name; \ 199_X/**/name 200#define PANIC(msg) \ 201 clrl _waittime; pushab 1f; callf $8,_panic; 1: .asciz msg 202#define PRINTF(n,msg) \ 203 pushab 1f; callf $(n+2)*4,_printf; MSG(msg) 204#define MSG(msg) .data; 1: .asciz msg; .text 205/* 206 * r0-r5 are saved across all faults and interrupts. 207 * Routines below and those hidden in vbglue.s (device 208 * interrupts) invoke the PUSHR/POPR macros to execute 209 * this. Also, certain stack frame offset calculations 210 * use this, using the REGSPC definition (and FPSPC defined below). 211 */ 212#define REGSPC 6*4 213#define PUSHR movab -REGSPC(sp),sp; storer $0x3f,(sp) 214#define POPR loadr $0x3f,(sp); movab REGSPC(sp),sp 215 216/* 217 * Floating point state is saved across faults and 218 * interrupts. The state occupies 4 longwords on 219 * the stack: 220 * precision indicator (single = 0/double = 1) 221 * double representation of accumulator 222 * save accumulator status flag (pcb_savacc) 223 */ 224#define FPSPC (4*4) 225 226#define SAVE_FPSTAT(_delta) \ 227 bitl $PSL_DBL,_delta(sp); \ 228 beql 1f; \ 229 pushl $1; \ 230 pushd; \ 231 jmp 2f; \ 2321: pushl $0; \ 233 pushl $0; \ 234 stf -(sp); \ 2352: tstl _u+PCB_SAVACC; \ 236 bneq 3f; \ 237 moval 0(sp),_u+PCB_SAVACC; \ 238 orl2 $2,8(sp);\ 2393: pushl $0; 240 241#define REST_FPSTAT \ 242 tstl (sp)+; \ 243 bitl $2,8(sp);\ 244 beql 1f;\ 245 movl $0,_u+PCB_SAVACC; \ 2461: bitl $1,8(sp); \ 247 beql 2f; \ 248 ldd (sp); \ 249 jmp 3f; \ 2502: ldf (sp); \ 2513: moval 12(sp),sp; 252 253#define REST_ACC \ 254 tstl _u+PCB_SAVACC; \ 255 beql 2f; \ 256 movl _u+PCB_SAVACC,r1; \ 257 andl3 $(EXPMASK|SIGNBIT),(r1),-(sp); \ 258 cmpl $0x80000000,(sp)+; \ 259 bneq 3f; \ 260 clrl (r1); \ 2613: bitl $1,8(r1); \ 262 beql 1f; \ 263 ldd (r1); \ 264 jmp 2f; \ 2651: ldf (r1); \ 2662: ; 267 268 .data 269nofault: .space 4 # bus error non-local goto label 270 271 .text 272SCBVEC(buserr): 273 CHECK_SFE(12) 274 SAVE_FPSTAT(12) 275 incl _intrcnt+I_BUSERR # keep stats... 276 pushl r0 # must save 277 andl3 24(sp),$ERRCD,r0 # grab pushed MER value 278 cmpl r0,$APE # address parity error? 279 jneq 1f 280 halt 2811: cmpl r0,$VBE # versabus error? 282 jneq 2f 283 halt 2842: 285 movl (sp)+,r0 # restore r0 and... 286 bitl $PSL_CURMOD,4*4+3*4(sp) # check if happened in user mode? 287 jeql 3f # yes, then shift stack up for trap... 288 movl 12(sp),16(sp) # sorry, no space for which-buss... 289 movl 8(sp),12(sp) 290 movl 4(sp),8(sp) 291 movl 0(sp),4(sp) 292 movl $T_BUSERR,0(sp) # push trap type code and... 293 jbr alltraps # ...merge with all other traps 2943: # kernel mode, check to see if... 295 tstl nofault # ...doing peek/poke? 296 jeql 4f # nofault set? if so, jump to it... 297 movl nofault,4*4+2*4(sp) # ...setup for non-local goto 298 clrl nofault 299 jbr 5f 3004: 301 PUSHR 302 pushab 4*4+REGSPC(sp) # address of bus error parameters 303 callf $8,_buserror 304 POPR 3055: 306 REST_FPSTAT 307 movab 8(sp),sp # remove bus error parameters 308 rei 309 310SCBVEC(powfail): # We should be on interrupt stack now. 311 SAVEpwfl() # save machine state 312 moval _Xdoadump-SYSTEM,_scb+SCB_DOADUMP 313 halt 314 315SCBVEC(stray): 316 incl _cnt+V_INTR # add to statistics 317 rei 318 319#include "net/netisr.h" 320 .globl _netisr 321SCBVEC(netintr): 322 CHECK_SFE(4) 323 SAVE_FPSTAT(4); PUSHR 324#include "imp.h" 325#if NIMP > 0 326 bbc $NETISR_IMP,_netisr,1f; 327 andl2 $~(1<<NETISR_IMP),_netisr 328 callf $4,_impintr; 3291: 330#endif 331#ifdef INET 332 bbc $NETISR_IP,_netisr,1f 333 andl2 $~(1<<NETISR_IP),_netisr 334 callf $4,_ipintr 3351: 336#endif 337#ifdef NS 338 bbc $NETISR_NS,_netisr,1f 339 andl2 $~(1<<NETISR_NS),_netisr 340 callf $4,_nsintr 3411: 342#endif 343#ifdef ISO 344 bbc $NETISR_ISO,_netisr,1f 345 andl2 $~(1<<NETISR_ISO),_netisr 346 callf $4,_clnlintr 3471: 348#endif 349 incl _cnt+V_SOFT 350 POPR; REST_FPSTAT 351 rei 352 353SCBVEC(cnrint): 354 CHECK_SFE(4) 355 SAVE_FPSTAT(4); PUSHR; 356 pushl $CPCONS; callf $8,_cnrint; 357 incl _intrcnt+I_CNR 358 incl _cnt+V_INTR 359 POPR; REST_FPSTAT; 360 rei 361SCBVEC(cnxint): 362 CHECK_SFE(4) 363 SAVE_FPSTAT(4); PUSHR; 364 pushl $CPCONS; callf $8,_cnxint; 365 incl _intrcnt+I_CNX 366 incl _cnt+V_INTR 367 POPR; REST_FPSTAT; 368 rei 369SCBVEC(rmtrint): 370 CHECK_SFE(4) 371 SAVE_FPSTAT(4); PUSHR; 372 pushl $CPREMOT; callf $8,_cnrint; 373 incl _intrcnt+I_RMTR 374 incl _cnt+V_INTR 375 POPR; REST_FPSTAT; 376 rei 377SCBVEC(rmtxint): 378 CHECK_SFE(4) 379 SAVE_FPSTAT(4); PUSHR; 380 pushl $CPREMOT; callf $8,_cnxint; 381 incl _intrcnt+I_RMTX 382 incl _cnt+V_INTR 383 POPR; REST_FPSTAT; 384 rei 385 386#define PUSHPCPSL pushl 4+FPSPC+REGSPC(sp); pushl 4+FPSPC+REGSPC(sp); 387 388SCBVEC(hardclock): 389 tstl _clk_enable 390 bneq 1f 391 rei 3921: 393 CHECK_SFE(4) 394 SAVE_FPSTAT(4); PUSHR 395 PUSHPCPSL # push pc and psl 396 callf $12,_hardclock # hardclock(pc,psl) 397 incl _intrcnt+I_CLOCK 398 incl _cnt+V_INTR ## temp so not to break vmstat -= HZ 399 POPR; REST_FPSTAT 400 rei 401SCBVEC(softclock): 402 CHECK_SFE(4) 403 SAVE_FPSTAT(4); PUSHR; 404 PUSHPCPSL # push pc and psl 405 callf $12,_softclock # softclock(pc,psl) 406 incl _cnt+V_SOFT 407 POPR; REST_FPSTAT 408 rei 409 410/* 411 * Stray VERSAbus interrupt catch routines 412 */ 413 .data 414#define PJ .align 2; callf $4,_Xvstray 415 .globl _catcher 416_catcher: 417 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 418 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 419 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 420 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 421 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 422 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 423 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 424 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 425 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 426 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 427 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 428 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 429 430 .align 2 431 .globl _cold 432_cold: .long 0x3 433 434 .text 435SCBVEC(vstray): 436 .word 0 437 bbc $0,_cold,2f # system running? 438 bbc $1,_cold,1f # doing autoconfig? 439 jbr 3f # random interrupt, ignore 4401: 441 mfpr $IPL,r12 # ...setup br and cvec 442 subl3 $_catcher+7,-8(fp),r11; shar $3,r11,r11 443 addl2 $SCB_DEVBASE,r11 444 jbr 3f 4452: 446 PUSHR 447 subl3 $_catcher+7,-8(fp),r0; shar $3,r0,r0 448 addl3 $SCB_DEVBASE,r0,-(sp); 449 mfpr $IPL,-(sp) 450 PRINTF(2, "stray intr ipl %x vec %x\n") 451 POPR 4523: moval 0f,-8(fp); ret # pop callf frame... 4530: rei # ...and return 454 455/* 456 * Trap and fault vector routines 457 */ 458#define TRAP(a) pushl $T_/**/a; jbr alltraps 459 460/* 461 * Ast delivery (profiling and/or reschedule) 462 */ 463 464SCBVEC(kspnotval): 465 CHECK_SFE(4) 466 pushl $0; 467 SAVE_FPSTAT(8) 468 TRAP(KSPNOTVAL) 469SCBVEC(privinflt): 470 CHECK_SFE(4) 471 pushl $0; 472 SAVE_FPSTAT(8) 473 TRAP(PRIVINFLT) 474SCBVEC(resopflt): 475 CHECK_SFE(4) 476 pushl $0; 477 SAVE_FPSTAT(8) 478 TRAP(RESOPFLT) 479SCBVEC(resadflt): 480 CHECK_SFE(4) 481 pushl $0; 482 SAVE_FPSTAT(8) 483 TRAP(RESADFLT) 484SCBVEC(bptflt): 485 CHECK_SFE(4) 486 pushl $0; 487 SAVE_FPSTAT(8) 488 TRAP(BPTFLT) 489SCBVEC(kdbintr): 490 CHECK_SFE(4); 491 pushl $0; 492 SAVE_FPSTAT(8); 493 TRAP(KDBTRAP); 494SCBVEC(tracep): 495 CHECK_SFE(4) 496 pushl $0; 497 SAVE_FPSTAT(8) 498 TRAP(TRCTRAP) 499SCBVEC(alignflt): 500#ifdef ALIGN 501 bitl $PSL_CURMOD,4(sp) 502 jeql align_excp # Can't emulate for kernel mode ! 503 jbr non_aligned # Only emulated for user mode. 504align_excp: 505#else 506 CHECK_SFE(4) 507#endif 508 pushl $0; 509 SAVE_FPSTAT(8) 510 TRAP(ALIGNFLT) 511SCBVEC(arithtrap): 512 CHECK_SFE(8) 513 SAVE_FPSTAT(8) 514 TRAP(ARITHTRAP) 515 516SCBVEC(protflt): 517 CHECK_SFE(12) 518 bitl $1,(sp)+ 519 jneq segflt 520 SAVE_FPSTAT(8) 521 TRAP(PROTFLT) 522segflt: 523 SAVE_FPSTAT(8) 524 TRAP(SEGFLT) 525 526SCBVEC(fpm): # Floating Point Emulation 527#ifdef FPE 528 CHECK_SFE(16) 529 SAVE_FPSTAT(16) 530 incl _cnt+V_FPE # count emulation traps 531 callf $4,_fpemulate 532 REST_FPSTAT 533#endif 534 moval 8(sp),sp # Pop operand 535 tstl (sp) # Stack= PSL, PC, return_code 536 jneq _Xarithtrap # If not OK, emulate F.P. exception 537 movab 4(sp),sp # Else remove return_code and 538 rei 539 540SCBVEC(sfexcep): 541 CHECK_SFE(4) 542 pushl $0 543 SAVE_FPSTAT(8) 544 TRAP(ASTFLT) 545 546SCBVEC(transflt): 547 CHECK_SFE(12) 548 bitl $2,(sp)+ 549 bneq tableflt 550pageflt: 551 SAVE_FPSTAT(8) 552 TRAP(PAGEFLT) 553tableflt: 554 SAVE_FPSTAT(8) 555 TRAP(TABLEFLT) 556 557#define REST_STACK movab 4(sp), sp; REST_FPSTAT; movab 4(sp), sp 558 559alltraps: 560 mfpr $USP,-(sp); 561 callf $4,_trap; 562 mtpr (sp)+,$USP 563 incl _cnt+V_TRAP 564 REST_STACK # pop type, code, and fp stuff 565 mtpr $HIGH,$IPL ## dont go to a higher IPL (GROT) 566 rei 567 568SCBVEC(syscall): 569 CHECK_SFE(8) 570 SAVE_FPSTAT(8) 571 pushl $T_SYSCALL 572 mfpr $USP,-(sp); 573 callf $4,_syscall; 574 mtpr (sp)+,$USP 575 incl _cnt+V_SYSCALL 576 REST_STACK # pop type, code, and fp stuff 577 mtpr $HIGH,$IPL ## dont go to a higher IPL (GROT) 578 rei 579 580/* 581 * System page table. 582 * 583 * Mbmap and Usrptmap are enlarged by CLSIZE entries 584 * as they are managed by resource maps starting with index 1 or CLSIZE. 585 */ 586#define vaddr(x) ((((x)-_Sysmap)/4)*NBPG+SYSTEM) 587#define SYSMAP(mname, vname, npte) \ 588_/**/mname: .globl _/**/mname; \ 589 .space (npte)*4; \ 590 .globl _/**/vname; \ 591 .set _/**/vname,vaddr(_/**/mname) 592#define ADDMAP(npte) .space (npte)*4 593 594 .data 595 .align 2 596 SYSMAP(Sysmap ,Sysbase ,SYSPTSIZE ) 597 SYSMAP(Forkmap ,forkutl ,UPAGES ) 598 SYSMAP(Xswapmap ,xswaputl ,UPAGES ) 599 SYSMAP(Xswap2map,xswap2utl ,UPAGES ) 600 SYSMAP(Swapmap ,swaputl ,UPAGES ) 601 SYSMAP(Pushmap ,pushutl ,UPAGES ) 602 SYSMAP(Vfmap ,vfutl ,UPAGES ) 603 SYSMAP(CMAP1 ,CADDR1 ,1 ) 604 SYSMAP(CMAP2 ,CADDR2 ,1 ) 605 SYSMAP(mmap ,vmmap ,1 ) 606 SYSMAP(alignmap ,alignutl ,1 ) /* XXX */ 607 SYSMAP(msgbufmap,msgbuf ,MSGBUFPTECNT ) 608 SYSMAP(Mbmap ,mbutl ,NMBCLUSTERS*MCLBYTES/NBPG+CLSIZE ) 609#ifdef MFS 610#include "ufs/mfsiom.h" 611 /* 612 * Used by the mfs_doio() routine for physical I/O 613 */ 614 SYSMAP(Mfsiomap ,mfsiobuf ,MFS_MAPREG ) 615#endif /* MFS */ 616#ifdef NFS 617#include "nfs/nfsiom.h" 618 /* 619 * Used by the nfs_doio() routine for physical I/O 620 */ 621 SYSMAP(Nfsiomap ,nfsiobuf ,NFS_MAPREG ) 622#endif /* NFS */ 623 /* 624 * This is the map used by the kernel memory allocator. 625 * It is expanded as necessary by the special features 626 * that use it. 627 */ 628 SYSMAP(kmempt ,kmembase ,NKMEMCLUSTERS*CLSIZE ) 629#ifdef SYSVSHM 630 ADDMAP( SHMMAXPGS ) 631#endif 632#ifdef GPROF 633 ADDMAP( 600*CLSIZE ) 634#endif 635 /* 636 * Enlarge kmempt as needed for bounce buffers allocated 637 * by tahoe controllers. 638 */ 639#include "hd.h" 640#if NHD > 0 641 ADDMAP( NHDC*(MAXPHYS/NBPG+CLSIZE) ) 642#endif 643#include "dk.h" 644#if NDK > 0 645 ADDMAP( NVD*(MAXPHYS/NBPG+CLSIZE) ) 646#endif 647#include "yc.h" 648#if NYC > 0 649 ADDMAP( NCY*(MAXPHYS/NBPG+CLSIZE) ) 650#endif 651#include "mp.h" 652 ADDMAP( NMP*14 ) 653 SYSMAP(ekmempt ,kmemlimit ,0 ) 654 655 SYSMAP(VMEMbeg ,vmembeg ,0 ) 656 SYSMAP(VMEMmap ,vmem ,VBIOSIZE ) 657 SYSMAP(VMEMmap1 ,vmem1 ,0 ) 658#include "ace.h" 659#if NACE > 0 660 ADDMAP( NACE*32 ) 661#endif 662#if NHD > 0 663 ADDMAP( NHDC ) 664#endif 665#include "vx.h" 666#if NVX > 0 667 ADDMAP( NVX * 16384/NBPG ) 668#endif 669 SYSMAP(VMEMend ,vmemend ,0 ) 670 671 SYSMAP(VBmap ,vbbase ,CLSIZE ) 672#if NHD > 0 673 ADDMAP( NHDC*(MAXPHYS/NBPG+CLSIZE) ) 674#endif 675#if NDK > 0 676 ADDMAP( NVD*(MAXPHYS/NBPG+CLSIZE) ) 677#endif 678#if NYC > 0 679 ADDMAP( NCY*(MAXPHYS/NBPG+CLSIZE) ) 680#endif 681 ADDMAP( NMP*14 ) 682 SYSMAP(eVBmap ,vbend ,0 ) 683 684 SYSMAP(Usrptmap ,usrpt ,USRPTSIZE+CLSIZE ) 685eSysmap: 686 .globl _Syssize 687 .set _Syssize,(eSysmap-_Sysmap)/4 688 689 .text 690/* 691 * Initialization 692 * 693 * IPL 0x1f; MME 0; scbb, pcbb, sbr, slr, isp, ksp not set 694 */ 695 .align 2 696 .globl start 697start: 698 .word 0 699/* set system control block base and system page table params */ 700 mtpr $_scb-SYSTEM,$SCBB 701 mtpr $_Sysmap-SYSTEM,$SBR 702 mtpr $_Syssize,$SLR 703/* double map the kernel into the virtual user addresses of phys mem */ 704 mtpr $_Sysmap,$P0BR 705 mtpr $_Syssize,$P0LR 706 mtpr $_Sysmap,$P1BR # against Murphy 707 mtpr $_Syssize,$P1LR 708/* set ISP */ 709 movl $_intstack-SYSTEM+NISP*NBPG,sp # still physical 710 mtpr $_intstack+NISP*NBPG,$ISP 711/* count up memory; _physmem contains limit */ 712 clrl r7 713 shll $PGSHIFT,_physmem,r8 714 decl r8 7151: pushl $1; pushl r7; callf $12,_badaddr; tstl r0; bneq 9f 716 ACBL(r8,$64*1024,r7,1b) 7179: 718/* clear memory from kernel bss and pages for proc 0 u. and page table */ 719 movab _edata,r6; andl2 $~SYSTEM,r6 720 movab _end,r5; andl2 $~SYSTEM,r5 721#ifdef KADB 722 subl2 $4,r5 7231: clrl (r6); ACBL(r5,$4,r6,1b) # clear just bss 724 addl2 $4,r5 725 bbc $6,r11,0f # check RB_KDB 726 andl3 $~SYSTEM,r9,r5 # skip symbol & string tables 727 andl3 $~SYSTEM,r9,r6 728#endif 7290: orl3 $SYSTEM,r5,r9 # convert to virtual address 730 addl2 $NBPG-1,r9 # roundup to next page 731 addl2 $(UPAGES*NBPG)+NBPG+NBPG,r5 7321: clrl (r6); ACBL(r5,$4,r6,1b) 733/* trap(), syscall(), and fpemulate() save r0-r12 in the entry mask */ 734 orw2 $0x01fff,_trap 735 orw2 $0x01fff,_syscall 736#ifdef FPE 737 orw2 $0x01fff,_fpemulate 738#endif 739 orw2 $0x01ffc,_panic # for debugging (no r0|r1) 740 callf $4,_fixctlrmask # setup for autoconfig 741/* initialize system page table: scb and int stack writeable */ 742 clrl r2 743 movab eintstack,r1 744 andl2 $~SYSTEM,r1 745 shrl $PGSHIFT,r1,r1 # r1-page number of eintstack 746/* make 1st page processor storage read/only, 2nd read/write */ 747 orl3 $PG_V|PG_KR,r2,_Sysmap[r2]; incl r2; 748 orl3 $PG_V|PG_KW,r2,_Sysmap[r2]; incl r2; 749/* other parts of the system are read/write for kernel */ 7501: orl3 $PG_V|PG_KW,r2,_Sysmap[r2]; # data:kernel write+phys=virtual 751 aoblss r1,r2,1b 752/* make rsstk read-only as red zone for interrupt stack */ 753 andl2 $~PG_PROT,_rsstkmap 754 orl2 $PG_V|PG_KR,_rsstkmap 755/* make kernel text space read-only */ 756 movab _etext+NBPG-1,r1 757 andl2 $~SYSTEM,r1 758 shrl $PGSHIFT,r1,r1 7591: orl3 $PG_V|PG_KR,r2,_Sysmap[r2] 760 aoblss r1,r2,1b 761/* make kernel data, bss, read-write */ 762 andl3 $~SYSTEM,r9,r1 763 shrl $PGSHIFT,r1,r1 7641: orl3 $PG_V|PG_KW,r2,_Sysmap[r2] 765 aoblss r1,r2,1b 766/* go to mapped mode, have to change both pc and sp to system addresses */ 767 mtpr $1,$TBIA 768 mtpr $1,$PADC # needed by HW parity&ECC logic 769 mtpr $1,$PACC # just in case 770 mtpr $1,$MME 771 movab SYSTEM(sp),sp 772 jmp *$0f 7730: 774/* disable any interrupts */ 775 movl $0,_intenable 776/* init mem sizes */ 777 shrl $PGSHIFT,r7,_physmem 778/* setup context for proc[0] == scheduler */ 779 andl3 $~SYSTEM,r9,r6 # convert to physical 780 andl2 $~(NBPG-1),r6 # make page boundary 781/* setup page table for proc[0] */ 782 shrl $PGSHIFT,r6,r3 # r3 = btoc(r6) 783 orl3 $PG_V|PG_KW,r3,_Usrptmap # init first upt entry 784 incl r3 # r3 - next page 785 movab _usrpt,r0 # r0 - first user page 786 mtpr r0,$TBIS 787/* init p0br, p0lr */ 788 mtpr r0,$P0BR # no p0 for proc[0] 789 mtpr $0,$P0LR 790 mtpr r0,$P1BR # no p1 either 791 mtpr $0,$P1LR 792/* init p2br, p2lr */ 793 movab NBPG(r0),r0 794 movl $PPAGES-UPAGES,r1 795 mtpr r1,$P2LR 796 moval -4*PPAGES(r0),r2 797 mtpr r2,$P2BR 798/* setup mapping for UPAGES of _u */ 799 clrl r2 800 movl $SYSTEM,r1 801 addl2 $UPAGES,r3 802 jbr 2f 8031: decl r3 804 moval -NBPG(r1),r1 # r1 = virtual add of next (downward) _u page 805 subl2 $4,r0 # r0 = pte address 806 orl3 $PG_V|PG_URKW,r3,(r0) 807 mtpr r1,$TBIS 8082: aobleq $UPAGES,r2,1b 809/* initialize (slightly) the pcb */ 810 movab UPAGES*NBPG(r1),PCB_KSP(r1) # KSP starts at end of _u 811 movl r1,PCB_USP(r1) # USP starts just below _u 812 mfpr $P0BR,PCB_P0BR(r1) 813 mfpr $P0LR,PCB_P0LR(r1) 814 mfpr $P1BR,PCB_P1BR(r1) 815 mfpr $P1LR,PCB_P1LR(r1) 816 mfpr $P2BR,PCB_P2BR(r1) 817 mfpr $P2LR,PCB_P2LR(r1) 818 movl $CLSIZE,PCB_SZPT(r1) # init u.u_pcb.pcb_szpt 819 movl r9,PCB_R9(r1) # r9 obtained from boot 820 movl r10,PCB_R10(r1) # r10 obtained from boot 821 movl r11,PCB_R11(r1) # r11 obtained from CP on boot 822 movab 1f,PCB_PC(r1) # initial pc 823 clrl PCB_PSL(r1) # kernel mode, ipl=0 824 shll $PGSHIFT,r3,r3 825 mtpr r3,$PCBB # first pcbb (physical) 826/* go to kernel mode */ 827 ldpctx 828 rei # Actually next instruction: 829/* put signal trampoline code in u. area */ 8301: movab sigcode,r0 831 movab _u+PCB_SIGC,r1 832 movl $19,r2 833 movblk 834/* save boot device in global _bootdev */ 835 movl r10,_bootdev 836/* save reboot flags in global _boothowto */ 837 movl r11,_boothowto 838#ifdef KADB 839/* save end of symbol & string table in global _bootesym */ 840 subl3 $NBPG-1,r9,_bootesym 841#endif 842/* calculate firstaddr, and call main() */ 843 andl3 $~SYSTEM,r9,r0 844 shrl $PGSHIFT,r0,-(sp) 845 addl2 $UPAGES+1,(sp) # first physical unused page 846 callf $8,_main 847/* proc[1] == /etc/init now running here in kernel mode; run icode */ 848 pushl $PSL_CURMOD # User mode PSL 849 pushl $0 # PC = 0 (virtual now) 850 rei 851 852/* 853 * Mask for saving/restoring registers on entry to 854 * a user signal handler. Space for the registers 855 * is reserved in sendsig, so beware if you want 856 * to change the mask. 857 */ 858#define SIGREGS (R0|R1|R2|R3|R4|R5) 859 .align 2 860 .globl sigcode 861sigcode: 862 storer $SIGREGS,16(sp) # save volatile registers 863 calls $4*3+4,*12(sp) # params pushed by sendsig for handler 864 loadr $SIGREGS,4(sp) # restore volatile registers 865 movab 24(sp),fp # use parameter list set up in sendsig 866 kcall $SYS_sigreturn # cleanup mask and onsigstack 867 halt # sigreturn does not return! 868 869 .globl _icode 870 .globl _initflags 871 .globl _szicode 872 .data 873/* 874 * Icode is copied out to process 1 to exec /etc/init. 875 * If the exec fails, process 1 exits. 876 */ 877 .align 2 878_icode: 879 /* try /sbin/init */ 880 pushl $0 881 pushab b`argv1-l0(pc) 882l0: pushab b`init1-l1(pc) 883l1: pushl $2 884 movab (sp),fp 885 kcall $SYS_execve 886 /* try /etc/init */ 887 pushl $0 888 pushab b`argv2-l2(pc) 889l2: pushab b`init2-l3(pc) 890l3: pushl $2 891 movab (sp),fp 892 kcall $SYS_execve 893 /* give up */ 894 pushl r0 895 pushl $1 896 movab (sp),fp 897 kcall $SYS_exit 898 899init1: .asciz "/sbin/init" 900init2: .asciz "/etc/init" 901 .align 2 902_initflags: 903 .long 0 904argv1: .long init1+6-_icode 905 .long _initflags-_icode 906 .long 0 907argv2: .long init2+5-_icode 908 .long _initflags-_icode 909 .long 0 910_szicode: 911 .long _szicode-_icode 912 .text 913 914/* 915 * Primitives 916 */ 917 918/* 919 * badaddr(addr, len) 920 * see if access addr with a len type instruction causes a machine check 921 * len is length of access (1=byte, 2=short, 4=long) 922 * r0 = 0 means good(exists); r0 =1 means does not exist. 923 */ 924ENTRY(badaddr, R3|R4) 925 mfpr $IPL,r1 926 mtpr $HIGH,$IPL 927 movl _scb+SCB_BUSERR,r2 928 movl 4(fp),r3 929 movl 8(fp),r4 930 movab 9f,_scb+SCB_BUSERR 931 bbc $0,r4,1f; tstb (r3) 9321: bbc $1,r4,1f; tstw (r3) 9331: bbc $2,r4,1f; tstl (r3) 9341: clrl r0 9352: movl r2,_scb+SCB_BUSERR 936 mtpr r1,$IPL 937 ret 938 939/* 940 * wbadaddr(addr, len, value) 941 * see if write of value to addr with a len type instruction causes 942 * a machine check 943 * len is length of access (1=byte, 2=short, 4=long) 944 * r0 = 0 means good(exists); r0 =1 means does not exist. 945 */ 946ENTRY(wbadaddr, R3|R4) 947 mfpr $IPL,r1 948 mtpr $HIGH,$IPL 949 movl _scb+SCB_BUSERR,r2 950 movl 4(fp),r3 951 movl 8(fp),r4 952 movab 9f,_scb+SCB_BUSERR 953 bbc $0,r4,1f; movb 15(fp), (r3) 9541: bbc $1,r4,1f; movw 14(fp), (r3) 9551: bbc $2,r4,1f; movl 12(fp), (r3) 9561: movl $30000,r0 # delay for error interrupt 9571: decl r0 958 jneq 1b 9592: movl r2,_scb+SCB_BUSERR # made it w/o machine checks; r0 is 0 960 mtpr r1,$IPL 961 ret 962 963 .align 2 9649: # catch buss error (if it comes) 965 andl3 4(sp),$ERRCD,r0 966 cmpl r0,$APE 967 jneq 1f 968 halt # address parity error 9691: cmpl r0,$VBE 970 jneq 1f 971 halt # Versabus error 9721: 973 movl $1,r0 # Anything else = bad address 974 movab 8(sp),sp # discard buss error trash 975 movab 2b,(sp) # new program counter on stack. 976 rei 977 978/* 979 * badcyaddr(addr) 980 * see if access tape master controller addr causes a bus error 981 * r0 = 0: no error; r0 = 1: timeout error. 982 */ 983ENTRY(badcyaddr, 0) 984 mfpr $IPL,r1 985 mtpr $HIGH,$IPL 986 clrl r2 987 movab 2f,nofault 988 movob $-1, *4(fp) 9891: aobleq $1000, r2, 1b 990 clrl nofault # made it w/o bus error 991 clrl r0 992 jbr 3f 9932: movl $1,r0 9943: mtpr r1,$IPL 995 ret 996 997/* 998 * peek(addr) 999 * fetch word and catch any bus error 1000 */ 1001ENTRY(peek, 0) 1002 mfpr $IPL,r1 1003 mtpr $0x18,$IPL # not reentrant 1004 movl 4(fp),r2 1005 movab 1f,nofault 1006 movw (r2),r0 1007 clrl nofault 1008 andl2 $0xffff,r0 1009 jbr 2f 10101: movl $-1,r0 # bus error 10112: mtpr r1,$IPL 1012 ret 1013 1014/* 1015 * poke(addr, val) 1016 * write word and catch any bus error 1017 */ 1018ENTRY(poke, R3) 1019 mfpr $IPL,r1 1020 mtpr $0x18,$IPL # not reentrant 1021 movl 4(fp),r2 1022 movl 8(fp),r3 1023 clrl r0 1024 movab 1f,nofault 1025 movw r3,(r2) 1026 clrl nofault 1027 jbr 2f 10281: movl $-1,r0 # bus error 10292: mtpr r1,$IPL 1030 ret 1031 1032/* 1033 * Copy a potentially overlapping block of memory. 1034 * 1035 * ovbcopy(src, dst, count) 1036 * caddr_t src, dst; unsigned count; 1037 */ 1038ENTRY(ovbcopy, R3|R4) 1039 movl 4(fp),r0 1040 movl 8(fp),r1 1041 movl 12(fp),r2 1042 cmpl r0,r1 1043 bgtru 1f # normal forward case 1044 beql 2f # equal, nothing to do 1045 addl2 r2,r0 # may be overlapping 1046 cmpl r0,r1 1047 bgtru 3f 1048 subl2 r2,r0 # normal forward case 10491: 1050 movblk 10512: 1052 ret 10533: 1054 addl2 r2,r1 # overlapping, must do backwards 1055 subl3 r0,r1,r3 1056 movl r2,r4 1057 jbr 5f 10584: 1059 subl2 r3,r0 1060 subl2 r3,r1 1061 movl r3,r2 1062 movblk 1063 subl2 r3,r0 1064 subl2 r3,r1 1065 subl2 r3,r4 10665: 1067 cmpl r4,r3 1068 jgtr 4b 1069 movl r4,r2 1070 subl2 r2,r0 1071 subl2 r2,r1 1072 movblk 1073 ret 1074 1075/* 1076 * Copy a null terminated string from the user address space into 1077 * the kernel address space. 1078 * 1079 * copyinstr(fromaddr, toaddr, maxlength, &lencopied) 1080 */ 1081ENTRY(copyinstr, 0) 1082 movl 12(fp),r5 # r5 = max length 1083 jlss 5f 1084 movl 8(fp),r4 # r4 = kernel address 1085 movl 4(fp),r0 # r0 = user address 1086 andl3 $(NBPG*CLSIZE-1),r0,r2 # r2 = bytes on first page 1087 subl3 r2,$(NBPG*CLSIZE),r2 10881: 1089 cmpl r5,r2 # r2 = min(bytes on page, length left); 1090 jgeq 2f 1091 movl r5,r2 10922: 1093 prober $1,(r0),r2 # bytes accessible? 1094 jeql 5f 1095 subl2 r2,r5 # update bytes left count 1096 movl r2,r3 # r3 = saved count 1097 movl r0,r1 1098 cmps3 # check for null 1099 tstl r2 1100 jneq 3f 1101 subl2 r3,r0 # back up r0 1102 movl r4,r1 1103 movl r3,r2 1104 movblk # copy in next piece 1105 movl r1,r4 1106 movl $(NBPG*CLSIZE),r2 # check next page 1107 tstl r5 # run out of space? 1108 jneq 1b 1109 movl $ENAMETOOLONG,r0 # set error code and return 1110 jbr 6f 11113: 1112 tstl 16(fp) # return length? 1113 beql 4f 1114 subl3 r5,12(fp),r5 # actual len = maxlen - unused pages 1115 subl2 r2,r5 # - unused on this page 1116 addl3 $1,r5,*16(fp) # + the null byte 11174: 1118 movl r4,r1 1119 subl3 r2,r3,r2 # calc char cnt 1120 subl2 r2,r0 # back up r0 1121 incl r2 # add on null byte 1122 movblk # copy last piece 1123 clrl r0 1124 ret 11255: 1126 movl $EFAULT,r0 11276: 1128 tstl 16(fp) 1129 beql 7f 1130 subl3 r5,12(fp),*16(fp) 11317: 1132 ret 1133 1134/* 1135 * Copy a null terminated string from the kernel 1136 * address space to the user address space. 1137 * 1138 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied) 1139 */ 1140ENTRY(copyoutstr, 0) 1141 movl 12(fp),r5 # r5 = max length 1142 jlss 5f 1143 movl 4(fp),r0 # r0 = kernel address 1144 movl 8(fp),r4 # r4 = user address 1145 andl3 $(NBPG*CLSIZE-1),r4,r2 # r2 = bytes on first page 1146 subl3 r2,$(NBPG*CLSIZE),r2 11471: 1148 cmpl r5,r2 # r2 = min(bytes on page, length left); 1149 jgeq 2f 1150 movl r5,r2 11512: 1152 probew $1,(r4),r2 # bytes accessible? 1153 jeql 5f 1154 subl2 r2,r5 # update bytes left count 1155 movl r2,r3 # r3 = saved count 1156 movl r0,r1 1157/* 1158 * This is a workaround for a microcode bug that causes 1159 * a trap type 9 when cmps3/movs3 touches the last byte 1160 * on a valid page immediately followed by an invalid page. 1161 */ 1162#ifdef good_cmps3 1163 cmps3 # check for null 1164 tstl r2 1165 jneq 3b 1166#else 1167 decl r2 1168 beql 9f # cannot handle case of r2 == 0! 1169 cmps3 # check for null up to last byte 11709: 1171 incl r2 1172 cmpl $1,r2 # get to last byte on page? 1173 bneq 3b 1174 tstb (r0) # last byte on page null? 1175 beql 3b 1176 incl r0 # not null, so bump pointer 1177#endif not good_cmps3 1178 subl2 r3,r0 # back up r0 1179 movl r4,r1 1180 movl r3,r2 1181 movblk # copy out next piece 1182 movl r1,r4 1183 movl $(NBPG*CLSIZE),r2 # check next page 1184 tstl r5 # run out of space? 1185 jneq 1b 1186 movl $ENAMETOOLONG,r0 # set error code and return 1187 jbr 6b 11885: 1189 clrl *$0 # this should never execute, if it does 1190 movl $EFAULT,r0 # save me a core dump (mkm - 9/87) 11916: 1192 tstl 16(fp) 1193 beql 7f 1194 subl3 r5,12(fp),*16(fp) 11957: 1196 ret 1197 1198 1199/* 1200 * Copy a null terminated string from one point to another in 1201 * the kernel address space. 1202 * 1203 * copystr(fromaddr, toaddr, maxlength, &lencopied) 1204 */ 1205ENTRY(copystr, 0) 1206 movl 12(fp),r3 # r3 = max length 1207 jlss 5b 1208 movl 4(fp),r0 # r0 = src address 1209 movl 8(fp),r4 # r4 = dest address 1210 clrl r5 # r5 = bytes left 1211 movl r3,r2 # r2 = max bytes to copy 1212 movl r0,r1 1213 cmps3 # check for null 1214 tstl r2 1215 jneq 3b 1216 subl2 r3,r0 # back up r0 1217 movl r4,r1 1218 movl r3,r2 1219 movblk # copy next piece 1220 movl $ENAMETOOLONG,r0 # set error code and return 1221 jbr 6b 1222 1223/* 1224 * Copy a block of data from the user address space into 1225 * the kernel address space. 1226 * 1227 * copyin(fromaddr, toaddr, count) 1228 */ 1229ENTRY(copyin, 0) 1230 movl 12(fp),r0 # copy length 1231 blss 9f 1232 movl 4(fp),r1 # copy user address 1233 cmpl $(CLSIZE*NBPG),r0 # probing one page or less ? 1234 bgeq 2f # yes 12351: 1236 prober $1,(r1),$(CLSIZE*NBPG) # bytes accessible ? 1237 beql 9f # no 1238 addl2 $(CLSIZE*NBPG),r1 # incr user address ptr 1239 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b) # reduce count and loop 12402: 1241 prober $1,(r1),r0 # bytes accessible ? 1242 bneq 7f # yes 1243 tstl r0 # copin 0 bytes ? 1244 bneq 9f # no, can't copyin 1245 ret # lie! 12467: 1247 MOVC3(4(fp),8(fp),12(fp)) 1248 clrl r0 1249 ret 12509: 1251 movl $EFAULT,r0 1252 ret 1253 1254/* 1255 * Copy a block of data from the kernel 1256 * address space to the user address space. 1257 * 1258 * copyout(fromaddr, toaddr, count) 1259 */ 1260ENTRY(copyout, 0) 1261 movl 12(fp),r0 # get count 1262 blss 9b 1263 movl 8(fp),r1 # get user address 1264 cmpl $(CLSIZE*NBPG),r0 # can do in one probew? 1265 bgeq 2f # yes 12661: 1267 probew $1,(r1),$(CLSIZE*NBPG) # bytes accessible? 1268 beql 9b # no 1269 addl2 $(CLSIZE*NBPG),r1 # increment user address 1270 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b) # reduce count and loop 12712: 1272 probew $1,(r1),r0 # bytes accessible? 1273 bneq 7f # yes 1274 tstl r0 # copin 0 bytes ? 1275 bneq 9b # no, can't copyin 1276 ret # lie! 12777: 1278 MOVC3(4(fp),8(fp),12(fp)) 1279 clrl r0 1280 ret 1281 1282/* 1283 * savectx is like setjmp but saves all registers. 1284 * Called before swapping out the u. area, restored by resume() 1285 * below. 1286 */ 1287ENTRY(savectx, 0) 1288 movl 4(fp),r2 1289 storer $0x1ff8,(r2); addl2 $40,r2 # r3-r12 1290 movl (fp),(r2); addl2 $4,r2 # fp 1291 movab 8(fp),(r2); addl2 $4,r2 # sp 1292 movl -8(fp),(r2) # pc 1293 clrl r0 1294 ret 1295 1296#ifdef KADB 1297/* 1298 * C library -- reset, setexit -- XXX 1299 * 1300 * reset(x) 1301 * will generate a "return" from 1302 * the last call to 1303 * setexit() 1304 * by restoring r2 - r12, fp 1305 * and doing a return. 1306 * The returned value is x; on the original 1307 * call the returned value is 0. 1308 */ 1309ENTRY(setexit, 0) 1310 movab setsav,r0 1311 storer $0x1ffc, (r0) 1312 movl (fp),44(r0) # fp 1313 moval 4(fp),48(r0) # sp 1314 movl -8(fp),52(r0) # pc 1315 clrl r0 1316 ret 1317 1318ENTRY(reset, 0) 1319 movl 4(fp),r0 # returned value 1320 movab setsav,r1 1321 loadr $0x1ffc,(r1) 1322 movl 44(r1),fp 1323 movl 48(r1),sp 1324 jmp *52(r1) 1325 1326 .data 1327 .align 2 1328setsav: .space 14*4 1329 .text 1330#endif 1331 1332 .globl _whichqs 1333 .globl _qs 1334 .globl _cnt 1335 1336 .globl _noproc 1337 .comm _noproc,4 1338 .globl _runrun 1339 .comm _runrun,4 1340/* 1341 * The following primitives use the fancy TAHOE instructions. 1342 * _whichqs tells which of the 32 queues _qs 1343 * have processes in them. setrq puts processes into queues, remrq 1344 * removes them from queues. The running process is on no queue, 1345 * other processes are on a queue related to p->p_pri, divided by 4 1346 * actually to shrink the 0-127 range of priorities into the 32 available 1347 * queues. 1348 */ 1349 1350/* 1351 * setrq(p), using fancy TAHOE instructions. 1352 * 1353 * Call should be made at spl8(), and p->p_stat should be SRUN 1354 */ 1355ENTRY(setrq, 0) 1356 movl 4(fp),r0 1357 tstl P_RLINK(r0) ## firewall: p->p_rlink must be 0 1358 beql set1 ## 1359 pushab set3 ## 1360 callf $8,_panic ## 1361set1: 1362 movzbl P_PRI(r0),r1 # put on queue which is p->p_pri / 4 1363 shar $2,r1,r1 1364 shal $1,r1,r2 1365 moval _qs[r2],r2 1366 insque (r0),*4(r2) # at end of queue 1367 shal r1,$1,r1 1368 orl2 r1,_whichqs # mark queue non-empty 1369 ret 1370 1371set3: .asciz "setrq" 1372 1373/* 1374 * remrq(p), using fancy TAHOE instructions 1375 * 1376 * Call should be made at spl8(). 1377 */ 1378ENTRY(remrq, 0) 1379 movl 4(fp),r0 1380 movzbl P_PRI(r0),r1 1381 shar $2,r1,r1 1382 bbs r1,_whichqs,rem1 1383 pushab rem3 # it wasn't recorded to be on its q 1384 callf $8,_panic 1385rem1: 1386 remque (r0) 1387 bneq rem2 # q not empty yet 1388 shal r1,$1,r1 1389 mcoml r1,r1 1390 andl2 r1,_whichqs # mark queue empty 1391rem2: 1392 clrl P_RLINK(r0) ## for firewall checking 1393 ret 1394 1395rem3: .asciz "remrq" 1396 1397/* 1398 * Masterpaddr is the p->p_addr of the running process on the master 1399 * processor. When a multiprocessor system, the slave processors will have 1400 * an array of slavepaddr's. 1401 */ 1402 .globl _masterpaddr 1403 .data 1404 .align 2 1405_masterpaddr: .long 0 1406 1407 .text 1408sw0: .asciz "swtch" 1409 1410/* 1411 * When no processes are on the runq, swtch branches to idle 1412 * to wait for something to come ready. 1413 */ 1414 .globl Idle 1415Idle: idle: 1416 movl $1,_noproc 1417 mtpr $0,$IPL # must allow interrupts here 14181: 1419 tstl _whichqs # look for non-empty queue 1420 bneq sw1 1421 brb 1b 1422 1423badsw: pushab sw0 1424 callf $8,_panic 1425 /* NOTREACHED */ 1426 1427 .align 2 1428/* 1429 * swtch(), using fancy tahoe instructions 1430 */ 1431ENTRY(swtch, 0) 1432 movl (fp),fp # prepare for rei 1433 movl (sp),4(sp) # saved pc 1434 tstl (sp)+ 1435 movpsl 4(sp) 1436 incl _cnt+V_SWTCH 1437sw1: ffs _whichqs,r0 # look for non-empty queue 1438 blss idle # if none, idle 1439 mtpr $0x18,$IPL # lock out all so _whichqs==_qs 1440 bbc r0,_whichqs,sw1 # proc moved via interrupt 1441 shal $1,r0,r1 1442 moval _qs[r1],r1 1443 movl (r1),r2 # r2 = p = highest pri process 1444 remque *(r1) 1445 bvs badsw # make sure something was there 1446 bneq sw2 1447 shal r0,$1,r1 1448 mcoml r1,r1 1449 andl2 r1,_whichqs # no more procs in this queue 1450sw2: 1451 clrl _noproc 1452 clrl _runrun 1453#ifdef notdef 1454 tstl P_WCHAN(r2) ## firewalls 1455 bneq badsw ## 1456 cmpb P_STAT(r2),$SRUN ## 1457 bneq badsw ## 1458#endif 1459 clrl P_RLINK(r2) ## 1460 movl *P_ADDR(r2),r0 1461#ifdef notdef 1462 cmpl r0,_masterpaddr # resume of current proc is easy 1463 beql res0 1464#endif 1465 movl r0,_masterpaddr 1466 shal $PGSHIFT,r0,r0 # r0 = pcbb(p) 1467 brb swresume 1468 1469/* 1470 * resume(pf) 1471 */ 1472ENTRY(resume, 0) 1473 shal $PGSHIFT,4(fp),r0 # r0 = pcbb(pf) 1474 movl (fp),fp # prepare for rei 1475 movl (sp)+,4(sp) # saved pc 1476 tstl (sp)+ 1477 movpsl 4(sp) 1478swresume: 1479 mtpr $0x18,$IPL # no interrupts, please 1480 movl _CMAP2,_u+PCB_CMAP2 # yech 1481 REST_ACC # restore original accumulator 1482 svpctx 1483 mtpr r0,$PCBB 1484 ldpctx 1485 movl _u+PCB_CMAP2,_CMAP2 # yech 1486 mtpr $_CADDR2,$TBIS 1487res0: 1488 movl _u+U_PROCP,r2 # r2 = u.u_procp 1489 tstl P_CKEY(r2) # does proc have code key? 1490 bneq 1f 1491 callf $4,_getcodekey # no, give him one 1492 movl _u+U_PROCP,r2 # r2 = u.u_procp 1493 movl r0,P_CKEY(r2) 14941: 1495 tstl P_DKEY(r2) # does proc have data key? 1496 bneq 1f 1497 callf $4,_getdatakey # no, give him one 1498 movl _u+U_PROCP,r2 # r2 = u.u_procp 1499 movl r0,P_DKEY(r2) 15001: 1501 mtpr P_CKEY(r2),$CCK # set code cache key 1502 mtpr P_DKEY(r2),$DCK # set data cache key 1503 tstl _u+PCB_SSWAP 1504 bneq res1 1505 rei 1506res1: # restore alternate saved context 1507 movl _u+PCB_SSWAP,r2 1508 clrl _u+PCB_SSWAP 1509 loadr $0x3ff8,(r2); addl2 $44,r2 # restore r3-r13 (r13=fp) 1510 movl (r2),r1; addl2 $4,r2 # fetch previous sp ... 1511 movab (sp),r0 # ... and current sp and 1512 cmpl r1,r0 # check for credibility, 1513 bgequ 1f # if further up stack ... 1514 pushab 2f; callf $8,_panic # ... panic 1515 /*NOTREACHED*/ 15161: # sp ok, complete return 1517 movl r1,sp # restore sp 1518 pushl $PSL_PRVMOD # kernel mode, ipl 0 1519 pushl (r2) # return address 1520 rei 15212: .asciz "ldctx" 1522 1523/* 1524 * {fu,su},{byte,word} 1525 */ 1526ENTRY(fuword, 0) 1527 movl 4(fp), r1 1528 prober $1,(r1),$4 # check access 1529 beql fserr # page unreadable 1530 bitl $1,r1 # check byte alignment 1531 bneq 2f # odd, do byte-word-byte 1532 bitl $2,r1 # check word alignment 1533 bneq 1f # odd, do in 2 words 1534 movl (r1),r0 # move longword 1535 ret 15361: 1537 movw (r1),r0 # move two words 1538 shal $16,r0,r0 1539 movzwl 2(r1),r1 # orw2 sign extends 1540 orl2 r1,r0 1541 ret 15422: 1543 movb (r1),r0 # move byte-word-byte 1544 shal $24,r0,r0 1545 movzwl 1(r1),r2 # orw2 sign extends 1546 shal $8,r2,r2 1547 movzbl 3(r1),r1 # orb2 sign extends 1548 orl2 r2,r1 1549 orl2 r1,r0 1550 ret 1551fserr: 1552 mnegl $1,r0 1553 ret 1554 1555ENTRY(fubyte, 0) 1556 prober $1,*4(fp),$1 1557 beql fserr 1558 movzbl *4(fp),r0 1559 ret 1560 1561ENTRY(suword, 0) 1562 movl 4(fp), r0 1563 probew $1,(r0),$4 # check access 1564 beql fserr # page unwritable 1565 bitl $1,r0 # check byte alignment 1566 bneq 1f # odd byte boundary 1567 bitl $2,r0 # check word alignment 1568 beql 2f # longword aligned 1569 movw 8(fp),(r0) # move two words 1570 movw 10(fp),2(r0) 1571 jbr 3f 15721: 1573 movb 8(fp),(r0) 1574 movb 9(fp),1(r0) 1575 movb 10(fp),2(r0) 1576 movb 11(fp),3(r0) 1577 jbr 3f 15782: 1579 movl 8(fp),(r0) 15803: 1581 clrl r0 1582 ret 1583 1584ENTRY(subyte, 0) 1585 probew $1,*4(fp),$1 1586 beql fserr 1587 movb 11(fp),*4(fp) 1588 clrl r0 1589 ret 1590 1591/* 1592 * Copy 1 relocation unit (NBPG bytes) 1593 * from user virtual address to physical address 1594 */ 1595ENTRY(copyseg, 0) 1596 orl3 $PG_V|PG_KW,8(fp),_CMAP2 1597 mtpr $_CADDR2,$TBIS # invalidate entry for copy 1598 MOVC3(4(fp),$_CADDR2,$NBPG) 1599 ret 1600 1601/* 1602 * Clear a page of memory. The page frame is specified. 1603 * 1604 * clearseg(pf); 1605 */ 1606ENTRY(clearseg, 0) 1607 orl3 $PG_V|PG_KW,4(fp),_CMAP1 # Maps to virtual addr CADDR1 1608 mtpr $_CADDR1,$TBIS 1609 movl $255,r0 # r0 = limit 1610 clrl r1 # r1 = index of cleared long 16111: 1612 clrl _CADDR1[r1] 1613 aobleq r0,r1,1b 1614 ret 1615 1616/* 1617 * Check user mode read/write access. 1618 * 1619 * useracc(addr, count, mode) 1620 * caddr_t addr; int count, mode; 1621 * mode = 0 write access 1622 * mode = 1 read access 1623 */ 1624ENTRY(useracc, 0) 1625 movl $1,r2 # r2 = 'user mode' for probew/probew 1626probes: 1627 movl 4(fp),r0 # get va 1628 movl 8(fp),r1 # count 1629 tstl 12(fp) # test for read access ? 1630 bneq userar # yes 1631 cmpl $(CLSIZE*NBPG),r1 # can we do it in one probe ? 1632 bgeq uaw2 # yes 1633uaw1: 1634 probew r2,(r0),$(CLSIZE*NBPG) 1635 beql uaerr # no access 1636 addl2 $(CLSIZE*NBPG),r0 1637 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uaw1) 1638uaw2: 1639 probew r2,(r0),r1 1640 beql uaerr 1641 movl $1,r0 1642 ret 1643userar: 1644 cmpl $(CLSIZE*NBPG),r1 1645 bgeq uar2 1646uar1: 1647 prober r2,(r0),$(CLSIZE*NBPG) 1648 beql uaerr 1649 addl2 $(CLSIZE*NBPG),r0 1650 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uar1) 1651uar2: 1652 prober r2,(r0),r1 1653 beql uaerr 1654 movl $1,r0 1655 ret 1656uaerr: 1657 clrl r0 1658 ret 1659 1660/* 1661 * Check kernel mode read/write access. 1662 * 1663 * kernacc(addr, count, mode) 1664 * caddr_t addr; int count, mode; 1665 * mode = 0 write access 1666 * mode = 1 read access 1667 */ 1668ENTRY(kernacc, 0) 1669 clrl r2 # r2 = 0 means kernel mode probe. 1670 jbr probes # Dijkstra would get gastric distress here. 1671 1672/* 1673 * addupc - increment some histogram counter 1674 * in the profiling buffer 1675 * 1676 * addupc(pc, prof, delta) 1677 * long pc; short delta; struct uprof *prof; 1678 * 1679 * struct uprof { # profile arguments 1680 * short *r_base; # buffer base 1681 * unsigned pr_size; # buffer size 1682 * unsigned pr_off; # pc offset 1683 * unsigned pr_scale; # pc scaling 1684 * } 1685 */ 1686ENTRY(addupc, 0) 1687 movl 8(fp),r2 # r2 points to structure 1688 subl3 8(r2),4(fp),r0 # r0 = PC - lowpc 1689 jlss 9f # PC < lowpc , out of range ! 1690 shrl $1,r0,r0 # the unit is words 1691 shrl $1,12(r2),r1 # ditto for scale 1692 emul r1,r0,$0,r0 1693 shrq $14,r0,r0 1694 tstl r0 # too big 1695 jneq 9f 1696 cmpl r1,4(r2) # Check buffer overflow 1697 jgequ 9f 1698 probew $1,*0(r2)[r1],$2 # counter accessible? 1699 jeql 9f 1700 shrl $1,r1,r1 # make r1 word index 1701 addw2 14(fp),*0(r2)[r1] 17029: ret 1703 1704/* 1705 * scanc(size, cp, table, mask) 1706 */ 1707ENTRY(scanc, R3|R4) 1708 movl 8(fp),r0 # r0 = cp 1709 addl3 4(fp),r0,r2 # end = &cp[size] 1710 movl 12(fp),r1 # r1 = table 1711 movb 19(fp),r4 # r4 = mask 1712 decl r0 # --cp 1713 jbr 0f # just like Fortran... 17141: # do { 1715 movzbl (r0),r3 1716 bitb r4,(r1)[r3] # if (table[*cp] & mask) 1717 jneq 2f # break; 17180: aoblss r2,r0,1b # } while (++cp < end); 17192: 1720 subl3 r0,r2,r0; ret # return (end - cp); 1721 1722/* 1723 * skpc(mask, size, cp) 1724 */ 1725ENTRY(skpc, 0) 1726 movl 12(fp),r0 # r0 = cp 1727 addl3 8(fp),r0,r1 # r1 = end = &cp[size]; 1728 movb 7(fp),r2 # r2 = mask 1729 decl r0 # --cp; 1730 jbr 0f 17311: # do 1732 cmpb (r0),r2 # if (*cp != mask) 1733 jneq 2f # break; 17340: aoblss r1,r0,1b # while (++cp < end); 17352: 1736 subl3 r0,r1,r0; ret # return (end - cp); 1737 1738/* 1739 * locc(mask, size, cp) 1740 */ 1741ENTRY(locc, 0) 1742 movl 12(fp),r0 # r0 = cp 1743 addl3 8(fp),r0,r1 # r1 = end = &cp[size] 1744 movb 7(fp),r2 # r2 = mask 1745 decl r0 # --cp; 1746 jbr 0f 17471: # do 1748 cmpb (r0),r2 # if (*cp == mask) 1749 jeql 2f # break; 17500: aoblss r1,r0,1b # while (++cp < end); 17512: 1752 subl3 r0,r1,r0; ret # return (end - cp); 1753 1754#ifdef ALIGN 1755#include "tahoe/align/align.h" 1756 1757 .globl _alignment 1758/* 1759 * There's an intimate relationship between this piece of code 1760 * and the alignment emulation code (especially the layout 1761 * of local variables in alignment.c! Don't change unless 1762 * you update both this, alignment.h and alignment.c !! 1763 */ 1764non_aligned: 1765 orb2 $EMULATEALIGN,_u+U_EOSYS 1766 incl _cnt+V_TRAP 1767 incl _cnt+V_ALIGN # count emulated alignment traps 1768 moval 4(sp),_user_psl 1769 SAVE_FPSTAT(4) # Also zeroes out ret_exception ! 1770 pushl $0 # ret_addr 1771 pushl $0 # ret_code 1772 mfpr $USP,-(sp) # user sp 1773 callf $4,_alignment # call w/o parms so regs may be modified 1774 /* 1775 * We return here after a successful emulation or an exception. 1776 * The registers have been restored and we must not alter them 1777 * before returning to the user. 1778 */ 17792: mtpr (sp)+,$USP # restore user sp 1780 tstl 8(sp) # Any exception ? 1781 bneq got_excp # Yes, reflect it back to user. 1782 moval 8(sp),sp # pop 2 zeroes pushed above 1783 REST_FPSTAT 1784 xorb2 $EMULATEALIGN,_u+U_EOSYS 1785 1786 bitl $PSL_T,4(sp) # check for trace bit set 1787 beql 9f 1788 CHECK_SFE(4) 1789 pushl $0 1790 SAVE_FPSTAT(8) 1791 TRAP(TRCTRAP) 17929: rei 1793 1794got_excp: # decode exception 1795 casel 8(sp),$ILL_ADDRMOD,$ALIGNMENT 1796 .align 1 1797L1: 1798 .word ill_addrmod-L1 1799 .word ill_access-L1 1800 .word ill_oprnd-L1 1801 .word arithmetic-L1 1802 .word alignment-L1 1803 brw alignment # default - shouldn't come here at all ! 1804 1805ill_addrmod: # No other parameters. Set up stack as 1806 moval 8(sp),sp # the HW would do it in a real case. 1807 REST_FPSTAT 1808 jbr _Xresadflt 1809ill_oprnd: 1810 moval 8(sp),sp 1811 REST_FPSTAT 1812 jbr _Xresopflt 1813alignment: 1814 moval 8(sp),sp 1815 REST_FPSTAT 1816 jbr align_excp # NB: going to _Xalignflt would cause loop 1817ill_access: 1818 /* 1819 * Must restore accumulator w/o modifying sp and w/o using 1820 * registers. Solution: copy things needed by REST_FPSTAT. 1821 */ 1822 pushl 20(sp) # The flags longword 1823 pushl 20(sp) # acc_low 1824 pushl 20(sp) # acc_high 1825 pushl 20(sp) # ret_exception ignored by REST_FPSTAT 1826 REST_FPSTAT # Back where we were with the sp ! 1827 movl (sp),16(sp) # code for illegal access 1828 movl 4(sp),20(sp) # original virtual address 1829 moval 16(sp),sp # Just like the HW would set it up 1830 jbr _Xprotflt 1831arithmetic: # same trickery as above 1832 pushl 20(sp) # The flags longword 1833 pushl 20(sp) # acc_low 1834 pushl 20(sp) # acc_high 1835 pushl 20(sp) # ret_exception ignored by REST_FPSTAT 1836 REST_FPSTAT # Back where we were with the sp ! 1837 movl (sp),20(sp) # code for arithmetic exception 1838 moval 20(sp),sp # Just like the HW would set it up 1839 jbr _Xarithtrap 1840#endif 1841