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