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.16 (Berkeley) 12/16/90 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/* 873 * Icode is copied out to process 1 to exec /etc/init. 874 * If the exec fails, process 1 exits. 875 */ 876 .align 2 877_icode: 878 /* try /sbin/init */ 879 pushab b`argv1-l0(pc) 880l0: pushab b`init1-l1(pc) 881l1: pushl $2 882 movab (sp),fp 883 kcall $SYS_execv 884 /* try /etc/init */ 885 pushab b`argv2-l2(pc) 886l2: pushab b`init2-l3(pc) 887l3: pushl $2 888 movab (sp),fp 889 kcall $SYS_execv 890 /* give up */ 891 pushl r0 892 pushl $1 893 movab (sp),fp 894 kcall $SYS_exit 895 896init1: .asciz "/sbin/init" 897init2: .asciz "/etc/init" 898 .align 2 899_initflags: 900 .long 0 901argv1: .long init1+6-_icode 902 .long _initflags-_icode 903 .long 0 904argv2: .long init2+5-_icode 905 .long _initflags-_icode 906 .long 0 907_szicode: 908 .long _szicode-_icode 909 910/* 911 * Primitives 912 */ 913 914/* 915 * badaddr(addr, len) 916 * see if access addr with a len type instruction causes a machine check 917 * len is length of access (1=byte, 2=short, 4=long) 918 * r0 = 0 means good(exists); r0 =1 means does not exist. 919 */ 920ENTRY(badaddr, R3|R4) 921 mfpr $IPL,r1 922 mtpr $HIGH,$IPL 923 movl _scb+SCB_BUSERR,r2 924 movl 4(fp),r3 925 movl 8(fp),r4 926 movab 9f,_scb+SCB_BUSERR 927 bbc $0,r4,1f; tstb (r3) 9281: bbc $1,r4,1f; tstw (r3) 9291: bbc $2,r4,1f; tstl (r3) 9301: clrl r0 9312: movl r2,_scb+SCB_BUSERR 932 mtpr r1,$IPL 933 ret 934 935/* 936 * wbadaddr(addr, len, value) 937 * see if write of value to addr with a len type instruction causes 938 * a machine check 939 * len is length of access (1=byte, 2=short, 4=long) 940 * r0 = 0 means good(exists); r0 =1 means does not exist. 941 */ 942ENTRY(wbadaddr, R3|R4) 943 mfpr $IPL,r1 944 mtpr $HIGH,$IPL 945 movl _scb+SCB_BUSERR,r2 946 movl 4(fp),r3 947 movl 8(fp),r4 948 movab 9f,_scb+SCB_BUSERR 949 bbc $0,r4,1f; movb 15(fp), (r3) 9501: bbc $1,r4,1f; movw 14(fp), (r3) 9511: bbc $2,r4,1f; movl 12(fp), (r3) 9521: movl $30000,r0 # delay for error interrupt 9531: decl r0 954 jneq 1b 9552: movl r2,_scb+SCB_BUSERR # made it w/o machine checks; r0 is 0 956 mtpr r1,$IPL 957 ret 958 959 .align 2 9609: # catch buss error (if it comes) 961 andl3 4(sp),$ERRCD,r0 962 cmpl r0,$APE 963 jneq 1f 964 halt # address parity error 9651: cmpl r0,$VBE 966 jneq 1f 967 halt # Versabus error 9681: 969 movl $1,r0 # Anything else = bad address 970 movab 8(sp),sp # discard buss error trash 971 movab 2b,(sp) # new program counter on stack. 972 rei 973 974/* 975 * badcyaddr(addr) 976 * see if access tape master controller addr causes a bus error 977 * r0 = 0: no error; r0 = 1: timeout error. 978 */ 979ENTRY(badcyaddr, 0) 980 mfpr $IPL,r1 981 mtpr $HIGH,$IPL 982 clrl r2 983 movab 2f,nofault 984 movob $-1, *4(fp) 9851: aobleq $1000, r2, 1b 986 clrl nofault # made it w/o bus error 987 clrl r0 988 jbr 3f 9892: movl $1,r0 9903: mtpr r1,$IPL 991 ret 992 993/* 994 * peek(addr) 995 * fetch word and catch any bus error 996 */ 997ENTRY(peek, 0) 998 mfpr $IPL,r1 999 mtpr $0x18,$IPL # not reentrant 1000 movl 4(fp),r2 1001 movab 1f,nofault 1002 movw (r2),r0 1003 clrl nofault 1004 andl2 $0xffff,r0 1005 jbr 2f 10061: movl $-1,r0 # bus error 10072: mtpr r1,$IPL 1008 ret 1009 1010/* 1011 * poke(addr, val) 1012 * write word and catch any bus error 1013 */ 1014ENTRY(poke, R3) 1015 mfpr $IPL,r1 1016 mtpr $0x18,$IPL # not reentrant 1017 movl 4(fp),r2 1018 movl 8(fp),r3 1019 clrl r0 1020 movab 1f,nofault 1021 movw r3,(r2) 1022 clrl nofault 1023 jbr 2f 10241: movl $-1,r0 # bus error 10252: mtpr r1,$IPL 1026 ret 1027 1028/* 1029 * Copy a potentially overlapping block of memory. 1030 * 1031 * ovbcopy(src, dst, count) 1032 * caddr_t src, dst; unsigned count; 1033 */ 1034ENTRY(ovbcopy, R3|R4) 1035 movl 4(fp),r0 1036 movl 8(fp),r1 1037 movl 12(fp),r2 1038 cmpl r0,r1 1039 bgtru 1f # normal forward case 1040 beql 2f # equal, nothing to do 1041 addl2 r2,r0 # may be overlapping 1042 cmpl r0,r1 1043 bgtru 3f 1044 subl2 r2,r0 # normal forward case 10451: 1046 movblk 10472: 1048 ret 10493: 1050 addl2 r2,r1 # overlapping, must do backwards 1051 subl3 r0,r1,r3 1052 movl r2,r4 1053 jbr 5f 10544: 1055 subl2 r3,r0 1056 subl2 r3,r1 1057 movl r3,r2 1058 movblk 1059 subl2 r3,r0 1060 subl2 r3,r1 1061 subl2 r3,r4 10625: 1063 cmpl r4,r3 1064 jgtr 4b 1065 movl r4,r2 1066 subl2 r2,r0 1067 subl2 r2,r1 1068 movblk 1069 ret 1070 1071/* 1072 * Copy a null terminated string from the user address space into 1073 * the kernel address space. 1074 * 1075 * copyinstr(fromaddr, toaddr, maxlength, &lencopied) 1076 */ 1077ENTRY(copyinstr, 0) 1078 movl 12(fp),r5 # r5 = max length 1079 jlss 5f 1080 movl 8(fp),r4 # r4 = kernel address 1081 movl 4(fp),r0 # r0 = user address 1082 andl3 $(NBPG*CLSIZE-1),r0,r2 # r2 = bytes on first page 1083 subl3 r2,$(NBPG*CLSIZE),r2 10841: 1085 cmpl r5,r2 # r2 = min(bytes on page, length left); 1086 jgeq 2f 1087 movl r5,r2 10882: 1089 prober $1,(r0),r2 # bytes accessible? 1090 jeql 5f 1091 subl2 r2,r5 # update bytes left count 1092 movl r2,r3 # r3 = saved count 1093 movl r0,r1 1094 cmps3 # check for null 1095 tstl r2 1096 jneq 3f 1097 subl2 r3,r0 # back up r0 1098 movl r4,r1 1099 movl r3,r2 1100 movblk # copy in next piece 1101 movl r1,r4 1102 movl $(NBPG*CLSIZE),r2 # check next page 1103 tstl r5 # run out of space? 1104 jneq 1b 1105 movl $ENAMETOOLONG,r0 # set error code and return 1106 jbr 6f 11073: 1108 tstl 16(fp) # return length? 1109 beql 4f 1110 subl3 r5,12(fp),r5 # actual len = maxlen - unused pages 1111 subl2 r2,r5 # - unused on this page 1112 addl3 $1,r5,*16(fp) # + the null byte 11134: 1114 movl r4,r1 1115 subl3 r2,r3,r2 # calc char cnt 1116 subl2 r2,r0 # back up r0 1117 incl r2 # add on null byte 1118 movblk # copy last piece 1119 clrl r0 1120 ret 11215: 1122 movl $EFAULT,r0 11236: 1124 tstl 16(fp) 1125 beql 7f 1126 subl3 r5,12(fp),*16(fp) 11277: 1128 ret 1129 1130/* 1131 * Copy a null terminated string from the kernel 1132 * address space to the user address space. 1133 * 1134 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied) 1135 */ 1136ENTRY(copyoutstr, 0) 1137 movl 12(fp),r5 # r5 = max length 1138 jlss 5f 1139 movl 4(fp),r0 # r0 = kernel address 1140 movl 8(fp),r4 # r4 = user address 1141 andl3 $(NBPG*CLSIZE-1),r4,r2 # r2 = bytes on first page 1142 subl3 r2,$(NBPG*CLSIZE),r2 11431: 1144 cmpl r5,r2 # r2 = min(bytes on page, length left); 1145 jgeq 2f 1146 movl r5,r2 11472: 1148 probew $1,(r4),r2 # bytes accessible? 1149 jeql 5f 1150 subl2 r2,r5 # update bytes left count 1151 movl r2,r3 # r3 = saved count 1152 movl r0,r1 1153/* 1154 * This is a workaround for a microcode bug that causes 1155 * a trap type 9 when cmps3/movs3 touches the last byte 1156 * on a valid page immediately followed by an invalid page. 1157 */ 1158#ifdef good_cmps3 1159 cmps3 # check for null 1160 tstl r2 1161 jneq 3b 1162#else 1163 decl r2 1164 beql 9f # cannot handle case of r2 == 0! 1165 cmps3 # check for null up to last byte 11669: 1167 incl r2 1168 cmpl $1,r2 # get to last byte on page? 1169 bneq 3b 1170 tstb (r0) # last byte on page null? 1171 beql 3b 1172 incl r0 # not null, so bump pointer 1173#endif not good_cmps3 1174 subl2 r3,r0 # back up r0 1175 movl r4,r1 1176 movl r3,r2 1177 movblk # copy out next piece 1178 movl r1,r4 1179 movl $(NBPG*CLSIZE),r2 # check next page 1180 tstl r5 # run out of space? 1181 jneq 1b 1182 movl $ENAMETOOLONG,r0 # set error code and return 1183 jbr 6b 11845: 1185 clrl *$0 # this should never execute, if it does 1186 movl $EFAULT,r0 # save me a core dump (mkm - 9/87) 11876: 1188 tstl 16(fp) 1189 beql 7f 1190 subl3 r5,12(fp),*16(fp) 11917: 1192 ret 1193 1194 1195/* 1196 * Copy a null terminated string from one point to another in 1197 * the kernel address space. 1198 * 1199 * copystr(fromaddr, toaddr, maxlength, &lencopied) 1200 */ 1201ENTRY(copystr, 0) 1202 movl 12(fp),r3 # r3 = max length 1203 jlss 5b 1204 movl 4(fp),r0 # r0 = src address 1205 movl 8(fp),r4 # r4 = dest address 1206 clrl r5 # r5 = bytes left 1207 movl r3,r2 # r2 = max bytes to copy 1208 movl r0,r1 1209 cmps3 # check for null 1210 tstl r2 1211 jneq 3b 1212 subl2 r3,r0 # back up r0 1213 movl r4,r1 1214 movl r3,r2 1215 movblk # copy next piece 1216 movl $ENAMETOOLONG,r0 # set error code and return 1217 jbr 6b 1218 1219/* 1220 * Copy a block of data from the user address space into 1221 * the kernel address space. 1222 * 1223 * copyin(fromaddr, toaddr, count) 1224 */ 1225ENTRY(copyin, 0) 1226 movl 12(fp),r0 # copy length 1227 blss 9f 1228 movl 4(fp),r1 # copy user address 1229 cmpl $(CLSIZE*NBPG),r0 # probing one page or less ? 1230 bgeq 2f # yes 12311: 1232 prober $1,(r1),$(CLSIZE*NBPG) # bytes accessible ? 1233 beql 9f # no 1234 addl2 $(CLSIZE*NBPG),r1 # incr user address ptr 1235 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b) # reduce count and loop 12362: 1237 prober $1,(r1),r0 # bytes accessible ? 1238 beql 9f # no 1239 MOVC3(4(fp),8(fp),12(fp)) 1240 clrl r0 1241 ret 12429: 1243 movl $EFAULT,r0 1244 ret 1245 1246/* 1247 * Copy a block of data from the kernel 1248 * address space to the user address space. 1249 * 1250 * copyout(fromaddr, toaddr, count) 1251 */ 1252ENTRY(copyout, 0) 1253 movl 12(fp),r0 # get count 1254 blss 9b 1255 movl 8(fp),r1 # get user address 1256 cmpl $(CLSIZE*NBPG),r0 # can do in one probew? 1257 bgeq 2f # yes 12581: 1259 probew $1,(r1),$(CLSIZE*NBPG) # bytes accessible? 1260 beql 9b # no 1261 addl2 $(CLSIZE*NBPG),r1 # increment user address 1262 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b) # reduce count and loop 12632: 1264 probew $1,(r1),r0 # bytes accessible? 1265 beql 9b # no 1266 MOVC3(4(fp),8(fp),12(fp)) 1267 clrl r0 1268 ret 1269 1270/* 1271 * savectx is like setjmp but saves all registers. 1272 * Called before swapping out the u. area, restored by resume() 1273 * below. 1274 */ 1275ENTRY(savectx, 0) 1276 movl 4(fp),r2 1277 storer $0x1ff8,(r2); addl2 $40,r2 # r3-r12 1278 movl (fp),(r2); addl2 $4,r2 # fp 1279 movab 8(fp),(r2); addl2 $4,r2 # sp 1280 movl -8(fp),(r2) # pc 1281 clrl r0 1282 ret 1283 1284#ifdef KADB 1285/* 1286 * C library -- reset, setexit -- XXX 1287 * 1288 * reset(x) 1289 * will generate a "return" from 1290 * the last call to 1291 * setexit() 1292 * by restoring r2 - r12, fp 1293 * and doing a return. 1294 * The returned value is x; on the original 1295 * call the returned value is 0. 1296 */ 1297ENTRY(setexit, 0) 1298 movab setsav,r0 1299 storer $0x1ffc, (r0) 1300 movl (fp),44(r0) # fp 1301 moval 4(fp),48(r0) # sp 1302 movl -8(fp),52(r0) # pc 1303 clrl r0 1304 ret 1305 1306ENTRY(reset, 0) 1307 movl 4(fp),r0 # returned value 1308 movab setsav,r1 1309 loadr $0x1ffc,(r1) 1310 movl 44(r1),fp 1311 movl 48(r1),sp 1312 jmp *52(r1) 1313 1314 .data 1315 .align 2 1316setsav: .space 14*4 1317 .text 1318#endif 1319 1320 .globl _whichqs 1321 .globl _qs 1322 .globl _cnt 1323 1324 .globl _noproc 1325 .comm _noproc,4 1326 .globl _runrun 1327 .comm _runrun,4 1328/* 1329 * The following primitives use the fancy TAHOE instructions. 1330 * _whichqs tells which of the 32 queues _qs 1331 * have processes in them. setrq puts processes into queues, remrq 1332 * removes them from queues. The running process is on no queue, 1333 * other processes are on a queue related to p->p_pri, divided by 4 1334 * actually to shrink the 0-127 range of priorities into the 32 available 1335 * queues. 1336 */ 1337 1338/* 1339 * setrq(p), using fancy TAHOE instructions. 1340 * 1341 * Call should be made at spl8(), and p->p_stat should be SRUN 1342 */ 1343ENTRY(setrq, 0) 1344 movl 4(fp),r0 1345 tstl P_RLINK(r0) ## firewall: p->p_rlink must be 0 1346 beql set1 ## 1347 pushab set3 ## 1348 callf $8,_panic ## 1349set1: 1350 movzbl P_PRI(r0),r1 # put on queue which is p->p_pri / 4 1351 shar $2,r1,r1 1352 shal $1,r1,r2 1353 moval _qs[r2],r2 1354 insque (r0),*4(r2) # at end of queue 1355 shal r1,$1,r1 1356 orl2 r1,_whichqs # mark queue non-empty 1357 ret 1358 1359set3: .asciz "setrq" 1360 1361/* 1362 * remrq(p), using fancy TAHOE instructions 1363 * 1364 * Call should be made at spl8(). 1365 */ 1366ENTRY(remrq, 0) 1367 movl 4(fp),r0 1368 movzbl P_PRI(r0),r1 1369 shar $2,r1,r1 1370 bbs r1,_whichqs,rem1 1371 pushab rem3 # it wasn't recorded to be on its q 1372 callf $8,_panic 1373rem1: 1374 remque (r0) 1375 bneq rem2 # q not empty yet 1376 shal r1,$1,r1 1377 mcoml r1,r1 1378 andl2 r1,_whichqs # mark queue empty 1379rem2: 1380 clrl P_RLINK(r0) ## for firewall checking 1381 ret 1382 1383rem3: .asciz "remrq" 1384 1385/* 1386 * Masterpaddr is the p->p_addr of the running process on the master 1387 * processor. When a multiprocessor system, the slave processors will have 1388 * an array of slavepaddr's. 1389 */ 1390 .globl _masterpaddr 1391 .data 1392 .align 2 1393_masterpaddr: .long 0 1394 1395 .text 1396sw0: .asciz "swtch" 1397 1398/* 1399 * When no processes are on the runq, swtch branches to idle 1400 * to wait for something to come ready. 1401 */ 1402 .globl Idle 1403Idle: idle: 1404 movl $1,_noproc 1405 mtpr $0,$IPL # must allow interrupts here 14061: 1407 tstl _whichqs # look for non-empty queue 1408 bneq sw1 1409 brb 1b 1410 1411badsw: pushab sw0 1412 callf $8,_panic 1413 /* NOTREACHED */ 1414 1415 .align 2 1416/* 1417 * swtch(), using fancy tahoe instructions 1418 */ 1419ENTRY(swtch, 0) 1420 movl (fp),fp # prepare for rei 1421 movl (sp),4(sp) # saved pc 1422 tstl (sp)+ 1423 movpsl 4(sp) 1424 incl _cnt+V_SWTCH 1425sw1: ffs _whichqs,r0 # look for non-empty queue 1426 blss idle # if none, idle 1427 mtpr $0x18,$IPL # lock out all so _whichqs==_qs 1428 bbc r0,_whichqs,sw1 # proc moved via interrupt 1429 shal $1,r0,r1 1430 moval _qs[r1],r1 1431 movl (r1),r2 # r2 = p = highest pri process 1432 remque *(r1) 1433 bvs badsw # make sure something was there 1434 bneq sw2 1435 shal r0,$1,r1 1436 mcoml r1,r1 1437 andl2 r1,_whichqs # no more procs in this queue 1438sw2: 1439 clrl _noproc 1440 clrl _runrun 1441#ifdef notdef 1442 tstl P_WCHAN(r2) ## firewalls 1443 bneq badsw ## 1444 cmpb P_STAT(r2),$SRUN ## 1445 bneq badsw ## 1446#endif 1447 clrl P_RLINK(r2) ## 1448 movl *P_ADDR(r2),r0 1449#ifdef notdef 1450 cmpl r0,_masterpaddr # resume of current proc is easy 1451 beql res0 1452#endif 1453 movl r0,_masterpaddr 1454 shal $PGSHIFT,r0,r0 # r0 = pcbb(p) 1455 brb swresume 1456 1457/* 1458 * resume(pf) 1459 */ 1460ENTRY(resume, 0) 1461 shal $PGSHIFT,4(fp),r0 # r0 = pcbb(pf) 1462 movl (fp),fp # prepare for rei 1463 movl (sp)+,4(sp) # saved pc 1464 tstl (sp)+ 1465 movpsl 4(sp) 1466swresume: 1467 mtpr $0x18,$IPL # no interrupts, please 1468 movl _CMAP2,_u+PCB_CMAP2 # yech 1469 REST_ACC # restore original accumulator 1470 svpctx 1471 mtpr r0,$PCBB 1472 ldpctx 1473 movl _u+PCB_CMAP2,_CMAP2 # yech 1474 mtpr $_CADDR2,$TBIS 1475res0: 1476 movl _u+U_PROCP,r2 # r2 = u.u_procp 1477 tstl P_CKEY(r2) # does proc have code key? 1478 bneq 1f 1479 callf $4,_getcodekey # no, give him one 1480 movl _u+U_PROCP,r2 # r2 = u.u_procp 1481 movl r0,P_CKEY(r2) 14821: 1483 tstl P_DKEY(r2) # does proc have data key? 1484 bneq 1f 1485 callf $4,_getdatakey # no, give him one 1486 movl _u+U_PROCP,r2 # r2 = u.u_procp 1487 movl r0,P_DKEY(r2) 14881: 1489 mtpr P_CKEY(r2),$CCK # set code cache key 1490 mtpr P_DKEY(r2),$DCK # set data cache key 1491 tstl _u+PCB_SSWAP 1492 bneq res1 1493 rei 1494res1: # restore alternate saved context 1495 movl _u+PCB_SSWAP,r2 1496 clrl _u+PCB_SSWAP 1497 loadr $0x3ff8,(r2); addl2 $44,r2 # restore r3-r13 (r13=fp) 1498 movl (r2),r1; addl2 $4,r2 # fetch previous sp ... 1499 movab (sp),r0 # ... and current sp and 1500 cmpl r1,r0 # check for credibility, 1501 bgequ 1f # if further up stack ... 1502 pushab 2f; callf $8,_panic # ... panic 1503 /*NOTREACHED*/ 15041: # sp ok, complete return 1505 movl r1,sp # restore sp 1506 pushl $PSL_PRVMOD # kernel mode, ipl 0 1507 pushl (r2) # return address 1508 rei 15092: .asciz "ldctx" 1510 1511/* 1512 * {fu,su},{byte,word} 1513 */ 1514ENTRY(fuword, 0) 1515 movl 4(fp), r1 1516 prober $1,(r1),$4 # check access 1517 beql fserr # page unreadable 1518 bitl $1,r1 # check byte alignment 1519 bneq 2f # odd, do byte-word-byte 1520 bitl $2,r1 # check word alignment 1521 bneq 1f # odd, do in 2 words 1522 movl (r1),r0 # move longword 1523 ret 15241: 1525 movw (r1),r0 # move two words 1526 shal $16,r0,r0 1527 movzwl 2(r1),r1 # orw2 sign extends 1528 orl2 r1,r0 1529 ret 15302: 1531 movb (r1),r0 # move byte-word-byte 1532 shal $24,r0,r0 1533 movzwl 1(r1),r2 # orw2 sign extends 1534 shal $8,r2,r2 1535 movzbl 3(r1),r1 # orb2 sign extends 1536 orl2 r2,r1 1537 orl2 r1,r0 1538 ret 1539fserr: 1540 mnegl $1,r0 1541 ret 1542 1543ENTRY(fubyte, 0) 1544 prober $1,*4(fp),$1 1545 beql fserr 1546 movzbl *4(fp),r0 1547 ret 1548 1549ENTRY(suword, 0) 1550 movl 4(fp), r0 1551 probew $1,(r0),$4 # check access 1552 beql fserr # page unwritable 1553 bitl $1,r0 # check byte alignment 1554 bneq 1f # odd byte boundary 1555 bitl $2,r0 # check word alignment 1556 beql 2f # longword aligned 1557 movw 8(fp),(r0) # move two words 1558 movw 10(fp),2(r0) 1559 jbr 3f 15601: 1561 movb 8(fp),(r0) 1562 movb 9(fp),1(r0) 1563 movb 10(fp),2(r0) 1564 movb 11(fp),3(r0) 1565 jbr 3f 15662: 1567 movl 8(fp),(r0) 15683: 1569 clrl r0 1570 ret 1571 1572ENTRY(subyte, 0) 1573 probew $1,*4(fp),$1 1574 beql fserr 1575 movb 11(fp),*4(fp) 1576 clrl r0 1577 ret 1578 1579/* 1580 * Copy 1 relocation unit (NBPG bytes) 1581 * from user virtual address to physical address 1582 */ 1583ENTRY(copyseg, 0) 1584 orl3 $PG_V|PG_KW,8(fp),_CMAP2 1585 mtpr $_CADDR2,$TBIS # invalidate entry for copy 1586 MOVC3(4(fp),$_CADDR2,$NBPG) 1587 ret 1588 1589/* 1590 * Clear a page of memory. The page frame is specified. 1591 * 1592 * clearseg(pf); 1593 */ 1594ENTRY(clearseg, 0) 1595 orl3 $PG_V|PG_KW,4(fp),_CMAP1 # Maps to virtual addr CADDR1 1596 mtpr $_CADDR1,$TBIS 1597 movl $255,r0 # r0 = limit 1598 clrl r1 # r1 = index of cleared long 15991: 1600 clrl _CADDR1[r1] 1601 aobleq r0,r1,1b 1602 ret 1603 1604/* 1605 * Check user mode read/write access. 1606 * 1607 * useracc(addr, count, mode) 1608 * caddr_t addr; int count, mode; 1609 * mode = 0 write access 1610 * mode = 1 read access 1611 */ 1612ENTRY(useracc, 0) 1613 movl $1,r2 # r2 = 'user mode' for probew/probew 1614probes: 1615 movl 4(fp),r0 # get va 1616 movl 8(fp),r1 # count 1617 tstl 12(fp) # test for read access ? 1618 bneq userar # yes 1619 cmpl $(CLSIZE*NBPG),r1 # can we do it in one probe ? 1620 bgeq uaw2 # yes 1621uaw1: 1622 probew r2,(r0),$(CLSIZE*NBPG) 1623 beql uaerr # no access 1624 addl2 $(CLSIZE*NBPG),r0 1625 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uaw1) 1626uaw2: 1627 probew r2,(r0),r1 1628 beql uaerr 1629 movl $1,r0 1630 ret 1631userar: 1632 cmpl $(CLSIZE*NBPG),r1 1633 bgeq uar2 1634uar1: 1635 prober r2,(r0),$(CLSIZE*NBPG) 1636 beql uaerr 1637 addl2 $(CLSIZE*NBPG),r0 1638 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uar1) 1639uar2: 1640 prober r2,(r0),r1 1641 beql uaerr 1642 movl $1,r0 1643 ret 1644uaerr: 1645 clrl r0 1646 ret 1647 1648/* 1649 * Check kernel mode read/write access. 1650 * 1651 * kernacc(addr, count, mode) 1652 * caddr_t addr; int count, mode; 1653 * mode = 0 write access 1654 * mode = 1 read access 1655 */ 1656ENTRY(kernacc, 0) 1657 clrl r2 # r2 = 0 means kernel mode probe. 1658 jbr probes # Dijkstra would get gastric distress here. 1659 1660/* 1661 * addupc - increment some histogram counter 1662 * in the profiling buffer 1663 * 1664 * addupc(pc, prof, delta) 1665 * long pc; short delta; struct uprof *prof; 1666 * 1667 * struct uprof { # profile arguments 1668 * short *r_base; # buffer base 1669 * unsigned pr_size; # buffer size 1670 * unsigned pr_off; # pc offset 1671 * unsigned pr_scale; # pc scaling 1672 * } 1673 */ 1674ENTRY(addupc, 0) 1675 movl 8(fp),r2 # r2 points to structure 1676 subl3 8(r2),4(fp),r0 # r0 = PC - lowpc 1677 jlss 9f # PC < lowpc , out of range ! 1678 shrl $1,r0,r0 # the unit is words 1679 shrl $1,12(r2),r1 # ditto for scale 1680 emul r1,r0,$0,r0 1681 shrq $14,r0,r0 1682 tstl r0 # too big 1683 jneq 9f 1684 cmpl r1,4(r2) # Check buffer overflow 1685 jgequ 9f 1686 probew $1,*0(r2)[r1],$2 # counter accessible? 1687 jeql 9f 1688 shrl $1,r1,r1 # make r1 word index 1689 addw2 14(fp),*0(r2)[r1] 16909: ret 1691 1692/* 1693 * scanc(size, cp, table, mask) 1694 */ 1695ENTRY(scanc, R3|R4) 1696 movl 8(fp),r0 # r0 = cp 1697 addl3 4(fp),r0,r2 # end = &cp[size] 1698 movl 12(fp),r1 # r1 = table 1699 movb 19(fp),r4 # r4 = mask 1700 decl r0 # --cp 1701 jbr 0f # just like Fortran... 17021: # do { 1703 movzbl (r0),r3 1704 bitb r4,(r1)[r3] # if (table[*cp] & mask) 1705 jneq 2f # break; 17060: aoblss r2,r0,1b # } while (++cp < end); 17072: 1708 subl3 r0,r2,r0; ret # return (end - cp); 1709 1710/* 1711 * skpc(mask, size, cp) 1712 */ 1713ENTRY(skpc, 0) 1714 movl 12(fp),r0 # r0 = cp 1715 addl3 8(fp),r0,r1 # r1 = end = &cp[size]; 1716 movb 7(fp),r2 # r2 = mask 1717 decl r0 # --cp; 1718 jbr 0f 17191: # do 1720 cmpb (r0),r2 # if (*cp != mask) 1721 jneq 2f # break; 17220: aoblss r1,r0,1b # while (++cp < end); 17232: 1724 subl3 r0,r1,r0; ret # return (end - cp); 1725 1726/* 1727 * locc(mask, size, cp) 1728 */ 1729ENTRY(locc, 0) 1730 movl 12(fp),r0 # r0 = cp 1731 addl3 8(fp),r0,r1 # r1 = end = &cp[size] 1732 movb 7(fp),r2 # r2 = mask 1733 decl r0 # --cp; 1734 jbr 0f 17351: # do 1736 cmpb (r0),r2 # if (*cp == mask) 1737 jeql 2f # break; 17380: aoblss r1,r0,1b # while (++cp < end); 17392: 1740 subl3 r0,r1,r0; ret # return (end - cp); 1741 1742#ifdef ALIGN 1743#include "tahoe/align/align.h" 1744 1745 .globl _alignment 1746/* 1747 * There's an intimate relationship between this piece of code 1748 * and the alignment emulation code (especially the layout 1749 * of local variables in alignment.c! Don't change unless 1750 * you update both this, alignment.h and alignment.c !! 1751 */ 1752non_aligned: 1753 orb2 $EMULATEALIGN,_u+U_EOSYS 1754 incl _cnt+V_TRAP 1755 incl _cnt+V_ALIGN # count emulated alignment traps 1756 moval 4(sp),_user_psl 1757 SAVE_FPSTAT(4) # Also zeroes out ret_exception ! 1758 pushl $0 # ret_addr 1759 pushl $0 # ret_code 1760 mfpr $USP,-(sp) # user sp 1761 callf $4,_alignment # call w/o parms so regs may be modified 1762 /* 1763 * We return here after a successful emulation or an exception. 1764 * The registers have been restored and we must not alter them 1765 * before returning to the user. 1766 */ 17672: mtpr (sp)+,$USP # restore user sp 1768 tstl 8(sp) # Any exception ? 1769 bneq got_excp # Yes, reflect it back to user. 1770 moval 8(sp),sp # pop 2 zeroes pushed above 1771 REST_FPSTAT 1772 xorb2 $EMULATEALIGN,_u+U_EOSYS 1773 1774 bitl $PSL_T,4(sp) # check for trace bit set 1775 beql 9f 1776 CHECK_SFE(4) 1777 pushl $0 1778 SAVE_FPSTAT(8) 1779 TRAP(TRCTRAP) 17809: rei 1781 1782got_excp: # decode exception 1783 casel 8(sp),$ILL_ADDRMOD,$ALIGNMENT 1784 .align 1 1785L1: 1786 .word ill_addrmod-L1 1787 .word ill_access-L1 1788 .word ill_oprnd-L1 1789 .word arithmetic-L1 1790 .word alignment-L1 1791 brw alignment # default - shouldn't come here at all ! 1792 1793ill_addrmod: # No other parameters. Set up stack as 1794 moval 8(sp),sp # the HW would do it in a real case. 1795 REST_FPSTAT 1796 jbr _Xresadflt 1797ill_oprnd: 1798 moval 8(sp),sp 1799 REST_FPSTAT 1800 jbr _Xresopflt 1801alignment: 1802 moval 8(sp),sp 1803 REST_FPSTAT 1804 jbr align_excp # NB: going to _Xalignflt would cause loop 1805ill_access: 1806 /* 1807 * Must restore accumulator w/o modifying sp and w/o using 1808 * registers. Solution: copy things needed by REST_FPSTAT. 1809 */ 1810 pushl 20(sp) # The flags longword 1811 pushl 20(sp) # acc_low 1812 pushl 20(sp) # acc_high 1813 pushl 20(sp) # ret_exception ignored by REST_FPSTAT 1814 REST_FPSTAT # Back where we were with the sp ! 1815 movl (sp),16(sp) # code for illegal access 1816 movl 4(sp),20(sp) # original virtual address 1817 moval 16(sp),sp # Just like the HW would set it up 1818 jbr _Xprotflt 1819arithmetic: # same trickery as above 1820 pushl 20(sp) # The flags longword 1821 pushl 20(sp) # acc_low 1822 pushl 20(sp) # acc_high 1823 pushl 20(sp) # ret_exception ignored by REST_FPSTAT 1824 REST_FPSTAT # Back where we were with the sp ! 1825 movl (sp),20(sp) # code for arithmetic exception 1826 moval 20(sp),sp # Just like the HW would set it up 1827 jbr _Xarithtrap 1828#endif 1829