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.13 (Berkeley) 04/10/90 7 */ 8 9#include "../tahoe/mtpr.h" 10#include "../tahoe/trap.h" 11#include "../tahoe/psl.h" 12#include "../tahoe/pte.h" 13#include "../tahoe/cp.h" 14#include "../tahoe/mem.h" 15#include "../tahoe/SYS.h" 16 17#include "../tahoemath/fp.h" 18 19#include "errno.h" 20#include "syscall.h" 21#include "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 ,1000*CLSIZE ) 629#ifdef GPROF 630 ADDMAP( 600*CLSIZE ) 631#endif 632 /* 633 * Enlarge kmempt as needed for bounce buffers allocated 634 * by tahoe controllers. 635 */ 636#include "hd.h" 637#if NHD > 0 638 ADDMAP( NHDC*(MAXPHYS/NBPG+CLSIZE) ) 639#endif 640#include "dk.h" 641#if NDK > 0 642 ADDMAP( NVD*(MAXPHYS/NBPG+CLSIZE) ) 643#endif 644#include "yc.h" 645#if NYC > 0 646 ADDMAP( NCY*(MAXPHYS/NBPG+CLSIZE) ) 647#endif 648#include "mp.h" 649 ADDMAP( NMP*14 ) 650 SYSMAP(ekmempt ,kmemlimit ,0 ) 651 652 SYSMAP(VMEMbeg ,vmembeg ,0 ) 653 SYSMAP(VMEMmap ,vmem ,VBIOSIZE ) 654 SYSMAP(VMEMmap1 ,vmem1 ,0 ) 655#include "ace.h" 656#if NACE > 0 657 ADDMAP( NACE*32 ) 658#endif 659#if NHD > 0 660 ADDMAP( NHDC ) 661#endif 662#include "vx.h" 663#if NVX > 0 664 ADDMAP( NVX * 16384/NBPG ) 665#endif 666 SYSMAP(VMEMend ,vmemend ,0 ) 667 668 SYSMAP(VBmap ,vbbase ,CLSIZE ) 669#if NHD > 0 670 ADDMAP( NHDC*(MAXPHYS/NBPG+CLSIZE) ) 671#endif 672#if NDK > 0 673 ADDMAP( NVD*(MAXPHYS/NBPG+CLSIZE) ) 674#endif 675#if NYC > 0 676 ADDMAP( NCY*(MAXPHYS/NBPG+CLSIZE) ) 677#endif 678 ADDMAP( NMP*14 ) 679 SYSMAP(eVBmap ,vbend ,0 ) 680 681 SYSMAP(Usrptmap ,usrpt ,USRPTSIZE+CLSIZE ) 682eSysmap: 683 .globl _Syssize 684 .set _Syssize,(eSysmap-_Sysmap)/4 685 686 .text 687/* 688 * Initialization 689 * 690 * IPL 0x1f; MME 0; scbb, pcbb, sbr, slr, isp, ksp not set 691 */ 692 .align 2 693 .globl start 694start: 695 .word 0 696/* set system control block base and system page table params */ 697 mtpr $_scb-SYSTEM,$SCBB 698 mtpr $_Sysmap-SYSTEM,$SBR 699 mtpr $_Syssize,$SLR 700/* double map the kernel into the virtual user addresses of phys mem */ 701 mtpr $_Sysmap,$P0BR 702 mtpr $_Syssize,$P0LR 703 mtpr $_Sysmap,$P1BR # against Murphy 704 mtpr $_Syssize,$P1LR 705/* set ISP */ 706 movl $_intstack-SYSTEM+NISP*NBPG,sp # still physical 707 mtpr $_intstack+NISP*NBPG,$ISP 708/* count up memory; _physmem contains limit */ 709 clrl r7 710 shll $PGSHIFT,_physmem,r8 711 decl r8 7121: pushl $1; pushl r7; callf $12,_badaddr; tstl r0; bneq 9f 713 ACBL(r8,$64*1024,r7,1b) 7149: 715/* clear memory from kernel bss and pages for proc 0 u. and page table */ 716 movab _edata,r6; andl2 $~SYSTEM,r6 717 movab _end,r5; andl2 $~SYSTEM,r5 718#ifdef KADB 719 subl2 $4,r5 7201: clrl (r6); ACBL(r5,$4,r6,1b) # clear just bss 721 addl2 $4,r5 722 bbc $6,r11,0f # check RB_KDB 723 andl3 $~SYSTEM,r9,r5 # skip symbol & string tables 724 andl3 $~SYSTEM,r9,r6 725#endif 7260: orl3 $SYSTEM,r5,r9 # convert to virtual address 727 addl2 $NBPG-1,r9 # roundup to next page 728 addl2 $(UPAGES*NBPG)+NBPG+NBPG,r5 7291: clrl (r6); ACBL(r5,$4,r6,1b) 730/* trap(), syscall(), and fpemulate() save r0-r12 in the entry mask */ 731 orw2 $0x01fff,_trap 732 orw2 $0x01fff,_syscall 733#ifdef FPE 734 orw2 $0x01fff,_fpemulate 735#endif 736 orw2 $0x01ffc,_panic # for debugging (no r0|r1) 737 callf $4,_fixctlrmask # setup for autoconfig 738/* initialize system page table: scb and int stack writeable */ 739 clrl r2 740 movab eintstack,r1 741 andl2 $~SYSTEM,r1 742 shrl $PGSHIFT,r1,r1 # r1-page number of eintstack 743/* make 1st page processor storage read/only, 2nd read/write */ 744 orl3 $PG_V|PG_KR,r2,_Sysmap[r2]; incl r2; 745 orl3 $PG_V|PG_KW,r2,_Sysmap[r2]; incl r2; 746/* other parts of the system are read/write for kernel */ 7471: orl3 $PG_V|PG_KW,r2,_Sysmap[r2]; # data:kernel write+phys=virtual 748 aoblss r1,r2,1b 749/* make rsstk read-only as red zone for interrupt stack */ 750 andl2 $~PG_PROT,_rsstkmap 751 orl2 $PG_V|PG_KR,_rsstkmap 752/* make kernel text space read-only */ 753 movab _etext+NBPG-1,r1 754 andl2 $~SYSTEM,r1 755 shrl $PGSHIFT,r1,r1 7561: orl3 $PG_V|PG_KR,r2,_Sysmap[r2] 757 aoblss r1,r2,1b 758/* make kernel data, bss, read-write */ 759 andl3 $~SYSTEM,r9,r1 760 shrl $PGSHIFT,r1,r1 7611: orl3 $PG_V|PG_KW,r2,_Sysmap[r2] 762 aoblss r1,r2,1b 763/* go to mapped mode, have to change both pc and sp to system addresses */ 764 mtpr $1,$TBIA 765 mtpr $1,$PADC # needed by HW parity&ECC logic 766 mtpr $1,$PACC # just in case 767 mtpr $1,$MME 768 movab SYSTEM(sp),sp 769 jmp *$0f 7700: 771/* disable any interrupts */ 772 movl $0,_intenable 773/* init mem sizes */ 774 shrl $PGSHIFT,r7,_physmem 775/* setup context for proc[0] == scheduler */ 776 andl3 $~SYSTEM,r9,r6 # convert to physical 777 andl2 $~(NBPG-1),r6 # make page boundary 778/* setup page table for proc[0] */ 779 shrl $PGSHIFT,r6,r3 # r3 = btoc(r6) 780 orl3 $PG_V|PG_KW,r3,_Usrptmap # init first upt entry 781 incl r3 # r3 - next page 782 movab _usrpt,r0 # r0 - first user page 783 mtpr r0,$TBIS 784/* init p0br, p0lr */ 785 mtpr r0,$P0BR # no p0 for proc[0] 786 mtpr $0,$P0LR 787 mtpr r0,$P1BR # no p1 either 788 mtpr $0,$P1LR 789/* init p2br, p2lr */ 790 movab NBPG(r0),r0 791 movl $PPAGES-UPAGES,r1 792 mtpr r1,$P2LR 793 moval -4*PPAGES(r0),r2 794 mtpr r2,$P2BR 795/* setup mapping for UPAGES of _u */ 796 clrl r2 797 movl $SYSTEM,r1 798 addl2 $UPAGES,r3 799 jbr 2f 8001: decl r3 801 moval -NBPG(r1),r1 # r1 = virtual add of next (downward) _u page 802 subl2 $4,r0 # r0 = pte address 803 orl3 $PG_V|PG_URKW,r3,(r0) 804 mtpr r1,$TBIS 8052: aobleq $UPAGES,r2,1b 806/* initialize (slightly) the pcb */ 807 movab UPAGES*NBPG(r1),PCB_KSP(r1) # KSP starts at end of _u 808 movl r1,PCB_USP(r1) # USP starts just below _u 809 mfpr $P0BR,PCB_P0BR(r1) 810 mfpr $P0LR,PCB_P0LR(r1) 811 mfpr $P1BR,PCB_P1BR(r1) 812 mfpr $P1LR,PCB_P1LR(r1) 813 mfpr $P2BR,PCB_P2BR(r1) 814 mfpr $P2LR,PCB_P2LR(r1) 815 movl $CLSIZE,PCB_SZPT(r1) # init u.u_pcb.pcb_szpt 816 movl r9,PCB_R9(r1) # r9 obtained from boot 817 movl r10,PCB_R10(r1) # r10 obtained from boot 818 movl r11,PCB_R11(r1) # r11 obtained from CP on boot 819 movab 1f,PCB_PC(r1) # initial pc 820 clrl PCB_PSL(r1) # kernel mode, ipl=0 821 shll $PGSHIFT,r3,r3 822 mtpr r3,$PCBB # first pcbb (physical) 823/* go to kernel mode */ 824 ldpctx 825 rei # Actually next instruction: 826/* put signal trampoline code in u. area */ 8271: movab sigcode,r0 828 movab _u+PCB_SIGC,r1 829 movl $19,r2 830 movblk 831/* save boot device in global _bootdev */ 832 movl r10,_bootdev 833/* save reboot flags in global _boothowto */ 834 movl r11,_boothowto 835#ifdef KADB 836/* save end of symbol & string table in global _bootesym */ 837 subl3 $NBPG-1,r9,_bootesym 838#endif 839/* calculate firstaddr, and call main() */ 840 andl3 $~SYSTEM,r9,r0 841 shrl $PGSHIFT,r0,-(sp) 842 addl2 $UPAGES+1,(sp) # first physical unused page 843 callf $8,_main 844/* proc[1] == /etc/init now running here in kernel mode; run icode */ 845 pushl $PSL_CURMOD # User mode PSL 846 pushl $0 # PC = 0 (virtual now) 847 rei 848 849/* 850 * Mask for saving/restoring registers on entry to 851 * a user signal handler. Space for the registers 852 * is reserved in sendsig, so beware if you want 853 * to change the mask. 854 */ 855#define SIGREGS (R0|R1|R2|R3|R4|R5) 856 .align 2 857 .globl sigcode 858sigcode: 859 storer $SIGREGS,16(sp) # save volatile registers 860 calls $4*3+4,*12(sp) # params pushed by sendsig for handler 861 loadr $SIGREGS,4(sp) # restore volatile registers 862 movab 24(sp),fp # use parameter list set up in sendsig 863 kcall $SYS_sigreturn # cleanup mask and onsigstack 864 halt # sigreturn does not return! 865 866 .globl _icode 867 .globl _initflags 868 .globl _szicode 869/* 870 * Icode is copied out to process 1 to exec /etc/init. 871 * If the exec fails, process 1 exits. 872 */ 873 .align 2 874_icode: 875 /* try /sbin/init */ 876 pushab b`argv1-l0(pc) 877l0: pushab b`init1-l1(pc) 878l1: pushl $2 879 movab (sp),fp 880 kcall $SYS_execv 881 /* try /etc/init */ 882 pushab b`argv2-l2(pc) 883l2: pushab b`init2-l3(pc) 884l3: pushl $2 885 movab (sp),fp 886 kcall $SYS_execv 887 /* give up */ 888 pushl r0 889 pushl $1 890 movab (sp),fp 891 kcall $SYS_exit 892 893init1: .asciz "/sbin/init" 894init2: .asciz "/etc/init" 895 .align 2 896_initflags: 897 .long 0 898argv1: .long init1+6-_icode 899 .long _initflags-_icode 900 .long 0 901argv2: .long init2+5-_icode 902 .long _initflags-_icode 903 .long 0 904_szicode: 905 .long _szicode-_icode 906 907/* 908 * Primitives 909 */ 910 911/* 912 * badaddr(addr, len) 913 * see if access addr with a len type instruction causes a machine check 914 * len is length of access (1=byte, 2=short, 4=long) 915 * r0 = 0 means good(exists); r0 =1 means does not exist. 916 */ 917ENTRY(badaddr, R3|R4) 918 mfpr $IPL,r1 919 mtpr $HIGH,$IPL 920 movl _scb+SCB_BUSERR,r2 921 movl 4(fp),r3 922 movl 8(fp),r4 923 movab 9f,_scb+SCB_BUSERR 924 bbc $0,r4,1f; tstb (r3) 9251: bbc $1,r4,1f; tstw (r3) 9261: bbc $2,r4,1f; tstl (r3) 9271: clrl r0 9282: movl r2,_scb+SCB_BUSERR 929 mtpr r1,$IPL 930 ret 931 932/* 933 * wbadaddr(addr, len, value) 934 * see if write of value to addr with a len type instruction causes 935 * a machine check 936 * len is length of access (1=byte, 2=short, 4=long) 937 * r0 = 0 means good(exists); r0 =1 means does not exist. 938 */ 939ENTRY(wbadaddr, R3|R4) 940 mfpr $IPL,r1 941 mtpr $HIGH,$IPL 942 movl _scb+SCB_BUSERR,r2 943 movl 4(fp),r3 944 movl 8(fp),r4 945 movab 9f,_scb+SCB_BUSERR 946 bbc $0,r4,1f; movb 15(fp), (r3) 9471: bbc $1,r4,1f; movw 14(fp), (r3) 9481: bbc $2,r4,1f; movl 12(fp), (r3) 9491: movl $30000,r0 # delay for error interrupt 9501: decl r0 951 jneq 1b 9522: movl r2,_scb+SCB_BUSERR # made it w/o machine checks; r0 is 0 953 mtpr r1,$IPL 954 ret 955 956 .align 2 9579: # catch buss error (if it comes) 958 andl3 4(sp),$ERRCD,r0 959 cmpl r0,$APE 960 jneq 1f 961 halt # address parity error 9621: cmpl r0,$VBE 963 jneq 1f 964 halt # Versabus error 9651: 966 movl $1,r0 # Anything else = bad address 967 movab 8(sp),sp # discard buss error trash 968 movab 2b,(sp) # new program counter on stack. 969 rei 970 971/* 972 * badcyaddr(addr) 973 * see if access tape master controller addr causes a bus error 974 * r0 = 0: no error; r0 = 1: timeout error. 975 */ 976ENTRY(badcyaddr, 0) 977 mfpr $IPL,r1 978 mtpr $HIGH,$IPL 979 clrl r2 980 movab 2f,nofault 981 movob $-1, *4(fp) 9821: aobleq $1000, r2, 1b 983 clrl nofault # made it w/o bus error 984 clrl r0 985 jbr 3f 9862: movl $1,r0 9873: mtpr r1,$IPL 988 ret 989 990/* 991 * peek(addr) 992 * fetch word and catch any bus error 993 */ 994ENTRY(peek, 0) 995 mfpr $IPL,r1 996 mtpr $0x18,$IPL # not reentrant 997 movl 4(fp),r2 998 movab 1f,nofault 999 movw (r2),r0 1000 clrl nofault 1001 andl2 $0xffff,r0 1002 jbr 2f 10031: movl $-1,r0 # bus error 10042: mtpr r1,$IPL 1005 ret 1006 1007/* 1008 * poke(addr, val) 1009 * write word and catch any bus error 1010 */ 1011ENTRY(poke, R3) 1012 mfpr $IPL,r1 1013 mtpr $0x18,$IPL # not reentrant 1014 movl 4(fp),r2 1015 movl 8(fp),r3 1016 clrl r0 1017 movab 1f,nofault 1018 movw r3,(r2) 1019 clrl nofault 1020 jbr 2f 10211: movl $-1,r0 # bus error 10222: mtpr r1,$IPL 1023 ret 1024 1025/* 1026 * Copy a potentially overlapping block of memory. 1027 * 1028 * ovbcopy(src, dst, count) 1029 * caddr_t src, dst; unsigned count; 1030 */ 1031ENTRY(ovbcopy, R3|R4) 1032 movl 4(fp),r0 1033 movl 8(fp),r1 1034 movl 12(fp),r2 1035 cmpl r0,r1 1036 bgtru 1f # normal forward case 1037 beql 2f # equal, nothing to do 1038 addl2 r2,r0 # may be overlapping 1039 cmpl r0,r1 1040 bgtru 3f 1041 subl2 r2,r0 # normal forward case 10421: 1043 movblk 10442: 1045 ret 10463: 1047 addl2 r2,r1 # overlapping, must do backwards 1048 subl3 r0,r1,r3 1049 movl r2,r4 1050 jbr 5f 10514: 1052 subl2 r3,r0 1053 subl2 r3,r1 1054 movl r3,r2 1055 movblk 1056 subl2 r3,r0 1057 subl2 r3,r1 1058 subl2 r3,r4 10595: 1060 cmpl r4,r3 1061 jgtr 4b 1062 movl r4,r2 1063 subl2 r2,r0 1064 subl2 r2,r1 1065 movblk 1066 ret 1067 1068/* 1069 * Copy a null terminated string from the user address space into 1070 * the kernel address space. 1071 * 1072 * copyinstr(fromaddr, toaddr, maxlength, &lencopied) 1073 */ 1074ENTRY(copyinstr, 0) 1075 movl 12(fp),r5 # r5 = max length 1076 jlss 5f 1077 movl 8(fp),r4 # r4 = kernel address 1078 movl 4(fp),r0 # r0 = user address 1079 andl3 $(NBPG*CLSIZE-1),r0,r2 # r2 = bytes on first page 1080 subl3 r2,$(NBPG*CLSIZE),r2 10811: 1082 cmpl r5,r2 # r2 = min(bytes on page, length left); 1083 jgeq 2f 1084 movl r5,r2 10852: 1086 prober $1,(r0),r2 # bytes accessible? 1087 jeql 5f 1088 subl2 r2,r5 # update bytes left count 1089 movl r2,r3 # r3 = saved count 1090 movl r0,r1 1091 cmps3 # check for null 1092 tstl r2 1093 jneq 3f 1094 subl2 r3,r0 # back up r0 1095 movl r4,r1 1096 movl r3,r2 1097 movblk # copy in next piece 1098 movl r1,r4 1099 movl $(NBPG*CLSIZE),r2 # check next page 1100 tstl r5 # run out of space? 1101 jneq 1b 1102 movl $ENOENT,r0 # set error code and return 1103 jbr 6f 11043: 1105 tstl 16(fp) # return length? 1106 beql 4f 1107 subl3 r5,12(fp),r5 # actual len = maxlen - unused pages 1108 subl2 r2,r5 # - unused on this page 1109 addl3 $1,r5,*16(fp) # + the null byte 11104: 1111 movl r4,r1 1112 subl3 r2,r3,r2 # calc char cnt 1113 subl2 r2,r0 # back up r0 1114 incl r2 # add on null byte 1115 movblk # copy last piece 1116 clrl r0 1117 ret 11185: 1119 movl $EFAULT,r0 11206: 1121 tstl 16(fp) 1122 beql 7f 1123 subl3 r5,12(fp),*16(fp) 11247: 1125 ret 1126 1127/* 1128 * Copy a null terminated string from the kernel 1129 * address space to the user address space. 1130 * 1131 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied) 1132 */ 1133ENTRY(copyoutstr, 0) 1134 movl 12(fp),r5 # r5 = max length 1135 jlss 5f 1136 movl 4(fp),r0 # r0 = kernel address 1137 movl 8(fp),r4 # r4 = user address 1138 andl3 $(NBPG*CLSIZE-1),r4,r2 # r2 = bytes on first page 1139 subl3 r2,$(NBPG*CLSIZE),r2 11401: 1141 cmpl r5,r2 # r2 = min(bytes on page, length left); 1142 jgeq 2f 1143 movl r5,r2 11442: 1145 probew $1,(r4),r2 # bytes accessible? 1146 jeql 5f 1147 subl2 r2,r5 # update bytes left count 1148 movl r2,r3 # r3 = saved count 1149 movl r0,r1 1150/* 1151 * This is a workaround for a microcode bug that causes 1152 * a trap type 9 when cmps3/movs3 touches the last byte 1153 * on a valid page immediately followed by an invalid page. 1154 */ 1155#ifdef good_cmps3 1156 cmps3 # check for null 1157 tstl r2 1158 jneq 3b 1159#else 1160 decl r2 1161 beql 9f # cannot handle case of r2 == 0! 1162 cmps3 # check for null up to last byte 11639: 1164 incl r2 1165 cmpl $1,r2 # get to last byte on page? 1166 bneq 3b 1167 tstb (r0) # last byte on page null? 1168 beql 3b 1169 incl r0 # not null, so bump pointer 1170#endif not good_cmps3 1171 subl2 r3,r0 # back up r0 1172 movl r4,r1 1173 movl r3,r2 1174 movblk # copy out next piece 1175 movl r1,r4 1176 movl $(NBPG*CLSIZE),r2 # check next page 1177 tstl r5 # run out of space? 1178 jneq 1b 1179 movl $ENOENT,r0 # set error code and return 1180 jbr 6b 11815: 1182 clrl *$0 # this should never execute, if it does 1183 movl $EFAULT,r0 # save me a core dump (mkm - 9/87) 11846: 1185 tstl 16(fp) 1186 beql 7f 1187 subl3 r5,12(fp),*16(fp) 11887: 1189 ret 1190 1191 1192/* 1193 * Copy a null terminated string from one point to another in 1194 * the kernel address space. 1195 * 1196 * copystr(fromaddr, toaddr, maxlength, &lencopied) 1197 */ 1198ENTRY(copystr, 0) 1199 movl 12(fp),r3 # r3 = max length 1200 jlss 5b 1201 movl 4(fp),r0 # r0 = src address 1202 movl 8(fp),r4 # r4 = dest address 1203 clrl r5 # r5 = bytes left 1204 movl r3,r2 # r2 = max bytes to copy 1205 movl r0,r1 1206 cmps3 # check for null 1207 tstl r2 1208 jneq 3b 1209 subl2 r3,r0 # back up r0 1210 movl r4,r1 1211 movl r3,r2 1212 movblk # copy next piece 1213 movl $ENOENT,r0 # set error code and return 1214 jbr 6b 1215 1216/* 1217 * Copy a block of data from the user address space into 1218 * the kernel address space. 1219 * 1220 * copyin(fromaddr, toaddr, count) 1221 */ 1222ENTRY(copyin, 0) 1223 movl 12(fp),r0 # copy length 1224 blss 9f 1225 movl 4(fp),r1 # copy user address 1226 cmpl $(CLSIZE*NBPG),r0 # probing one page or less ? 1227 bgeq 2f # yes 12281: 1229 prober $1,(r1),$(CLSIZE*NBPG) # bytes accessible ? 1230 beql 9f # no 1231 addl2 $(CLSIZE*NBPG),r1 # incr user address ptr 1232 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b) # reduce count and loop 12332: 1234 prober $1,(r1),r0 # bytes accessible ? 1235 beql 9f # no 1236 MOVC3(4(fp),8(fp),12(fp)) 1237 clrl r0 1238 ret 12399: 1240 movl $EFAULT,r0 1241 ret 1242 1243/* 1244 * Copy a block of data from the kernel 1245 * address space to the user address space. 1246 * 1247 * copyout(fromaddr, toaddr, count) 1248 */ 1249ENTRY(copyout, 0) 1250 movl 12(fp),r0 # get count 1251 blss 9b 1252 movl 8(fp),r1 # get user address 1253 cmpl $(CLSIZE*NBPG),r0 # can do in one probew? 1254 bgeq 2f # yes 12551: 1256 probew $1,(r1),$(CLSIZE*NBPG) # bytes accessible? 1257 beql 9b # no 1258 addl2 $(CLSIZE*NBPG),r1 # increment user address 1259 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b) # reduce count and loop 12602: 1261 probew $1,(r1),r0 # bytes accessible? 1262 beql 9b # no 1263 MOVC3(4(fp),8(fp),12(fp)) 1264 clrl r0 1265 ret 1266 1267/* 1268 * savectx is like setjmp but saves all registers. 1269 * Called before swapping out the u. area, restored by resume() 1270 * below. 1271 */ 1272ENTRY(savectx, 0) 1273 movl 4(fp),r2 1274 storer $0x1ff8,(r2); addl2 $40,r2 # r3-r12 1275 movl (fp),(r2); addl2 $4,r2 # fp 1276 movab 8(fp),(r2); addl2 $4,r2 # sp 1277 movl -8(fp),(r2) # pc 1278 clrl r0 1279 ret 1280 1281#ifdef KADB 1282/* 1283 * C library -- reset, setexit -- XXX 1284 * 1285 * reset(x) 1286 * will generate a "return" from 1287 * the last call to 1288 * setexit() 1289 * by restoring r2 - r12, fp 1290 * and doing a return. 1291 * The returned value is x; on the original 1292 * call the returned value is 0. 1293 */ 1294ENTRY(setexit, 0) 1295 movab setsav,r0 1296 storer $0x1ffc, (r0) 1297 movl (fp),44(r0) # fp 1298 moval 4(fp),48(r0) # sp 1299 movl -8(fp),52(r0) # pc 1300 clrl r0 1301 ret 1302 1303ENTRY(reset, 0) 1304 movl 4(fp),r0 # returned value 1305 movab setsav,r1 1306 loadr $0x1ffc,(r1) 1307 movl 44(r1),fp 1308 movl 48(r1),sp 1309 jmp *52(r1) 1310 1311 .data 1312 .align 2 1313setsav: .space 14*4 1314 .text 1315#endif 1316 1317 .globl _whichqs 1318 .globl _qs 1319 .globl _cnt 1320 1321 .globl _noproc 1322 .comm _noproc,4 1323 .globl _runrun 1324 .comm _runrun,4 1325/* 1326 * The following primitives use the fancy TAHOE instructions. 1327 * _whichqs tells which of the 32 queues _qs 1328 * have processes in them. setrq puts processes into queues, remrq 1329 * removes them from queues. The running process is on no queue, 1330 * other processes are on a queue related to p->p_pri, divided by 4 1331 * actually to shrink the 0-127 range of priorities into the 32 available 1332 * queues. 1333 */ 1334 1335/* 1336 * setrq(p), using fancy TAHOE instructions. 1337 * 1338 * Call should be made at spl8(), and p->p_stat should be SRUN 1339 */ 1340ENTRY(setrq, 0) 1341 movl 4(fp),r0 1342 tstl P_RLINK(r0) ## firewall: p->p_rlink must be 0 1343 beql set1 ## 1344 pushab set3 ## 1345 callf $8,_panic ## 1346set1: 1347 movzbl P_PRI(r0),r1 # put on queue which is p->p_pri / 4 1348 shar $2,r1,r1 1349 shal $1,r1,r2 1350 moval _qs[r2],r2 1351 insque (r0),*4(r2) # at end of queue 1352 shal r1,$1,r1 1353 orl2 r1,_whichqs # mark queue non-empty 1354 ret 1355 1356set3: .asciz "setrq" 1357 1358/* 1359 * remrq(p), using fancy TAHOE instructions 1360 * 1361 * Call should be made at spl8(). 1362 */ 1363ENTRY(remrq, 0) 1364 movl 4(fp),r0 1365 movzbl P_PRI(r0),r1 1366 shar $2,r1,r1 1367 bbs r1,_whichqs,rem1 1368 pushab rem3 # it wasn't recorded to be on its q 1369 callf $8,_panic 1370rem1: 1371 remque (r0) 1372 bneq rem2 # q not empty yet 1373 shal r1,$1,r1 1374 mcoml r1,r1 1375 andl2 r1,_whichqs # mark queue empty 1376rem2: 1377 clrl P_RLINK(r0) ## for firewall checking 1378 ret 1379 1380rem3: .asciz "remrq" 1381 1382/* 1383 * Masterpaddr is the p->p_addr of the running process on the master 1384 * processor. When a multiprocessor system, the slave processors will have 1385 * an array of slavepaddr's. 1386 */ 1387 .globl _masterpaddr 1388 .data 1389 .align 2 1390_masterpaddr: .long 0 1391 1392 .text 1393sw0: .asciz "swtch" 1394 1395/* 1396 * When no processes are on the runq, swtch branches to idle 1397 * to wait for something to come ready. 1398 */ 1399 .globl Idle 1400Idle: idle: 1401 movl $1,_noproc 1402 mtpr $0,$IPL # must allow interrupts here 14031: 1404 tstl _whichqs # look for non-empty queue 1405 bneq sw1 1406 brb 1b 1407 1408badsw: pushab sw0 1409 callf $8,_panic 1410 /* NOTREACHED */ 1411 1412 .align 2 1413/* 1414 * swtch(), using fancy tahoe instructions 1415 */ 1416ENTRY(swtch, 0) 1417 movl (fp),fp # prepare for rei 1418 movl (sp),4(sp) # saved pc 1419 tstl (sp)+ 1420 movpsl 4(sp) 1421 incl _cnt+V_SWTCH 1422sw1: ffs _whichqs,r0 # look for non-empty queue 1423 blss idle # if none, idle 1424 mtpr $0x18,$IPL # lock out all so _whichqs==_qs 1425 bbc r0,_whichqs,sw1 # proc moved via interrupt 1426 shal $1,r0,r1 1427 moval _qs[r1],r1 1428 movl (r1),r2 # r2 = p = highest pri process 1429 remque *(r1) 1430 bvs badsw # make sure something was there 1431 bneq sw2 1432 shal r0,$1,r1 1433 mcoml r1,r1 1434 andl2 r1,_whichqs # no more procs in this queue 1435sw2: 1436 clrl _noproc 1437 clrl _runrun 1438#ifdef notdef 1439 tstl P_WCHAN(r2) ## firewalls 1440 bneq badsw ## 1441 cmpb P_STAT(r2),$SRUN ## 1442 bneq badsw ## 1443#endif 1444 clrl P_RLINK(r2) ## 1445 movl *P_ADDR(r2),r0 1446#ifdef notdef 1447 cmpl r0,_masterpaddr # resume of current proc is easy 1448 beql res0 1449#endif 1450 movl r0,_masterpaddr 1451 shal $PGSHIFT,r0,r0 # r0 = pcbb(p) 1452 brb swresume 1453 1454/* 1455 * resume(pf) 1456 */ 1457ENTRY(resume, 0) 1458 shal $PGSHIFT,4(fp),r0 # r0 = pcbb(pf) 1459 movl (fp),fp # prepare for rei 1460 movl (sp)+,4(sp) # saved pc 1461 tstl (sp)+ 1462 movpsl 4(sp) 1463swresume: 1464 mtpr $0x18,$IPL # no interrupts, please 1465 movl _CMAP2,_u+PCB_CMAP2 # yech 1466 REST_ACC # restore original accumulator 1467 svpctx 1468 mtpr r0,$PCBB 1469 ldpctx 1470 movl _u+PCB_CMAP2,_CMAP2 # yech 1471 mtpr $_CADDR2,$TBIS 1472res0: 1473 movl _u+U_PROCP,r2 # r2 = u.u_procp 1474 tstl P_CKEY(r2) # does proc have code key? 1475 bneq 1f 1476 callf $4,_getcodekey # no, give him one 1477 movl _u+U_PROCP,r2 # r2 = u.u_procp 1478 movl r0,P_CKEY(r2) 14791: 1480 tstl P_DKEY(r2) # does proc have data key? 1481 bneq 1f 1482 callf $4,_getdatakey # no, give him one 1483 movl _u+U_PROCP,r2 # r2 = u.u_procp 1484 movl r0,P_DKEY(r2) 14851: 1486 mtpr P_CKEY(r2),$CCK # set code cache key 1487 mtpr P_DKEY(r2),$DCK # set data cache key 1488 tstl _u+PCB_SSWAP 1489 bneq res1 1490 rei 1491res1: # restore alternate saved context 1492 movl _u+PCB_SSWAP,r2 1493 clrl _u+PCB_SSWAP 1494 loadr $0x3ff8,(r2); addl2 $44,r2 # restore r3-r13 (r13=fp) 1495 movl (r2),r1; addl2 $4,r2 # fetch previous sp ... 1496 movab (sp),r0 # ... and current sp and 1497 cmpl r1,r0 # check for credibility, 1498 bgequ 1f # if further up stack ... 1499 pushab 2f; callf $8,_panic # ... panic 1500 /*NOTREACHED*/ 15011: # sp ok, complete return 1502 movl r1,sp # restore sp 1503 pushl $PSL_PRVMOD # kernel mode, ipl 0 1504 pushl (r2) # return address 1505 rei 15062: .asciz "ldctx" 1507 1508/* 1509 * {fu,su},{byte,word} 1510 */ 1511ENTRY(fuword, 0) 1512 movl 4(fp), r1 1513 prober $1,(r1),$4 # check access 1514 beql fserr # page unreadable 1515 bitl $1,r1 # check byte alignment 1516 bneq 2f # odd, do byte-word-byte 1517 bitl $2,r1 # check word alignment 1518 bneq 1f # odd, do in 2 words 1519 movl (r1),r0 # move longword 1520 ret 15211: 1522 movw (r1),r0 # move two words 1523 shal $16,r0,r0 1524 movzwl 2(r1),r1 # orw2 sign extends 1525 orl2 r1,r0 1526 ret 15272: 1528 movb (r1),r0 # move byte-word-byte 1529 shal $24,r0,r0 1530 movzwl 1(r1),r2 # orw2 sign extends 1531 shal $8,r2,r2 1532 movzbl 3(r1),r1 # orb2 sign extends 1533 orl2 r2,r1 1534 orl2 r1,r0 1535 ret 1536fserr: 1537 mnegl $1,r0 1538 ret 1539 1540ENTRY(fubyte, 0) 1541 prober $1,*4(fp),$1 1542 beql fserr 1543 movzbl *4(fp),r0 1544 ret 1545 1546ENTRY(suword, 0) 1547 movl 4(fp), r0 1548 probew $1,(r0),$4 # check access 1549 beql fserr # page unwritable 1550 bitl $1,r0 # check byte alignment 1551 bneq 1f # odd byte boundary 1552 bitl $2,r0 # check word alignment 1553 beql 2f # longword aligned 1554 movw 8(fp),(r0) # move two words 1555 movw 10(fp),2(r0) 1556 jbr 3f 15571: 1558 movb 8(fp),(r0) 1559 movb 9(fp),1(r0) 1560 movb 10(fp),2(r0) 1561 movb 11(fp),3(r0) 1562 jbr 3f 15632: 1564 movl 8(fp),(r0) 15653: 1566 clrl r0 1567 ret 1568 1569ENTRY(subyte, 0) 1570 probew $1,*4(fp),$1 1571 beql fserr 1572 movb 11(fp),*4(fp) 1573 clrl r0 1574 ret 1575 1576/* 1577 * Copy 1 relocation unit (NBPG bytes) 1578 * from user virtual address to physical address 1579 */ 1580ENTRY(copyseg, 0) 1581 orl3 $PG_V|PG_KW,8(fp),_CMAP2 1582 mtpr $_CADDR2,$TBIS # invalidate entry for copy 1583 MOVC3(4(fp),$_CADDR2,$NBPG) 1584 ret 1585 1586/* 1587 * Clear a page of memory. The page frame is specified. 1588 * 1589 * clearseg(pf); 1590 */ 1591ENTRY(clearseg, 0) 1592 orl3 $PG_V|PG_KW,4(fp),_CMAP1 # Maps to virtual addr CADDR1 1593 mtpr $_CADDR1,$TBIS 1594 movl $255,r0 # r0 = limit 1595 clrl r1 # r1 = index of cleared long 15961: 1597 clrl _CADDR1[r1] 1598 aobleq r0,r1,1b 1599 ret 1600 1601/* 1602 * Check user mode read/write access. 1603 * 1604 * useracc(addr, count, mode) 1605 * caddr_t addr; int count, mode; 1606 * mode = 0 write access 1607 * mode = 1 read access 1608 */ 1609ENTRY(useracc, 0) 1610 movl $1,r2 # r2 = 'user mode' for probew/probew 1611probes: 1612 movl 4(fp),r0 # get va 1613 movl 8(fp),r1 # count 1614 tstl 12(fp) # test for read access ? 1615 bneq userar # yes 1616 cmpl $(CLSIZE*NBPG),r1 # can we do it in one probe ? 1617 bgeq uaw2 # yes 1618uaw1: 1619 probew r2,(r0),$(CLSIZE*NBPG) 1620 beql uaerr # no access 1621 addl2 $(CLSIZE*NBPG),r0 1622 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uaw1) 1623uaw2: 1624 probew r2,(r0),r1 1625 beql uaerr 1626 movl $1,r0 1627 ret 1628userar: 1629 cmpl $(CLSIZE*NBPG),r1 1630 bgeq uar2 1631uar1: 1632 prober r2,(r0),$(CLSIZE*NBPG) 1633 beql uaerr 1634 addl2 $(CLSIZE*NBPG),r0 1635 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uar1) 1636uar2: 1637 prober r2,(r0),r1 1638 beql uaerr 1639 movl $1,r0 1640 ret 1641uaerr: 1642 clrl r0 1643 ret 1644 1645/* 1646 * Check kernel mode read/write access. 1647 * 1648 * kernacc(addr, count, mode) 1649 * caddr_t addr; int count, mode; 1650 * mode = 0 write access 1651 * mode = 1 read access 1652 */ 1653ENTRY(kernacc, 0) 1654 clrl r2 # r2 = 0 means kernel mode probe. 1655 jbr probes # Dijkstra would get gastric distress here. 1656 1657/* 1658 * addupc - increment some histogram counter 1659 * in the profiling buffer 1660 * 1661 * addupc(pc, prof, delta) 1662 * long pc; short delta; struct uprof *prof; 1663 * 1664 * struct uprof { # profile arguments 1665 * short *r_base; # buffer base 1666 * unsigned pr_size; # buffer size 1667 * unsigned pr_off; # pc offset 1668 * unsigned pr_scale; # pc scaling 1669 * } 1670 */ 1671ENTRY(addupc, 0) 1672 movl 8(fp),r2 # r2 points to structure 1673 subl3 8(r2),4(fp),r0 # r0 = PC - lowpc 1674 jlss 9f # PC < lowpc , out of range ! 1675 shrl $1,r0,r0 # the unit is words 1676 shrl $1,12(r2),r1 # ditto for scale 1677 emul r1,r0,$0,r0 1678 shrq $14,r0,r0 1679 tstl r0 # too big 1680 jneq 9f 1681 cmpl r1,4(r2) # Check buffer overflow 1682 jgequ 9f 1683 probew $1,*0(r2)[r1],$2 # counter accessible? 1684 jeql 9f 1685 shrl $1,r1,r1 # make r1 word index 1686 addw2 14(fp),*0(r2)[r1] 16879: ret 1688 1689/* 1690 * scanc(size, cp, table, mask) 1691 */ 1692ENTRY(scanc, R3|R4) 1693 movl 8(fp),r0 # r0 = cp 1694 addl3 4(fp),r0,r2 # end = &cp[size] 1695 movl 12(fp),r1 # r1 = table 1696 movb 19(fp),r4 # r4 = mask 1697 decl r0 # --cp 1698 jbr 0f # just like Fortran... 16991: # do { 1700 movzbl (r0),r3 1701 bitb r4,(r1)[r3] # if (table[*cp] & mask) 1702 jneq 2f # break; 17030: aoblss r2,r0,1b # } while (++cp < end); 17042: 1705 subl3 r0,r2,r0; ret # return (end - cp); 1706 1707/* 1708 * skpc(mask, size, cp) 1709 */ 1710ENTRY(skpc, 0) 1711 movl 12(fp),r0 # r0 = cp 1712 addl3 8(fp),r0,r1 # r1 = end = &cp[size]; 1713 movb 7(fp),r2 # r2 = mask 1714 decl r0 # --cp; 1715 jbr 0f 17161: # do 1717 cmpb (r0),r2 # if (*cp != mask) 1718 jneq 2f # break; 17190: aoblss r1,r0,1b # while (++cp < end); 17202: 1721 subl3 r0,r1,r0; ret # return (end - cp); 1722 1723/* 1724 * locc(mask, size, cp) 1725 */ 1726ENTRY(locc, 0) 1727 movl 12(fp),r0 # r0 = cp 1728 addl3 8(fp),r0,r1 # r1 = end = &cp[size] 1729 movb 7(fp),r2 # r2 = mask 1730 decl r0 # --cp; 1731 jbr 0f 17321: # do 1733 cmpb (r0),r2 # if (*cp == mask) 1734 jeql 2f # break; 17350: aoblss r1,r0,1b # while (++cp < end); 17362: 1737 subl3 r0,r1,r0; ret # return (end - cp); 1738 1739#ifdef ALIGN 1740#include "../tahoealign/align.h" 1741 1742 .globl _alignment 1743/* 1744 * There's an intimate relationship between this piece of code 1745 * and the alignment emulation code (especially the layout 1746 * of local variables in alignment.c! Don't change unless 1747 * you update both this, alignment.h and alignment.c !! 1748 */ 1749non_aligned: 1750 orb2 $EMULATEALIGN,_u+U_EOSYS 1751 incl _cnt+V_TRAP 1752 incl _cnt+V_ALIGN # count emulated alignment traps 1753 moval 4(sp),_user_psl 1754 SAVE_FPSTAT(4) # Also zeroes out ret_exception ! 1755 pushl $0 # ret_addr 1756 pushl $0 # ret_code 1757 mfpr $USP,-(sp) # user sp 1758 callf $4,_alignment # call w/o parms so regs may be modified 1759 /* 1760 * We return here after a successful emulation or an exception. 1761 * The registers have been restored and we must not alter them 1762 * before returning to the user. 1763 */ 17642: mtpr (sp)+,$USP # restore user sp 1765 tstl 8(sp) # Any exception ? 1766 bneq got_excp # Yes, reflect it back to user. 1767 moval 8(sp),sp # pop 2 zeroes pushed above 1768 REST_FPSTAT 1769 xorb2 $EMULATEALIGN,_u+U_EOSYS 1770 1771 bitl $PSL_T,4(sp) # check for trace bit set 1772 beql 9f 1773 CHECK_SFE(4) 1774 pushl $0 1775 SAVE_FPSTAT(8) 1776 TRAP(TRCTRAP) 17779: rei 1778 1779got_excp: # decode exception 1780 casel 8(sp),$ILL_ADDRMOD,$ALIGNMENT 1781 .align 1 1782L1: 1783 .word ill_addrmod-L1 1784 .word ill_access-L1 1785 .word ill_oprnd-L1 1786 .word arithmetic-L1 1787 .word alignment-L1 1788 brw alignment # default - shouldn't come here at all ! 1789 1790ill_addrmod: # No other parameters. Set up stack as 1791 moval 8(sp),sp # the HW would do it in a real case. 1792 REST_FPSTAT 1793 jbr _Xresadflt 1794ill_oprnd: 1795 moval 8(sp),sp 1796 REST_FPSTAT 1797 jbr _Xresopflt 1798alignment: 1799 moval 8(sp),sp 1800 REST_FPSTAT 1801 jbr align_excp # NB: going to _Xalignflt would cause loop 1802ill_access: 1803 /* 1804 * Must restore accumulator w/o modifying sp and w/o using 1805 * registers. Solution: copy things needed by REST_FPSTAT. 1806 */ 1807 pushl 20(sp) # The flags longword 1808 pushl 20(sp) # acc_low 1809 pushl 20(sp) # acc_high 1810 pushl 20(sp) # ret_exception ignored by REST_FPSTAT 1811 REST_FPSTAT # Back where we were with the sp ! 1812 movl (sp),16(sp) # code for illegal access 1813 movl 4(sp),20(sp) # original virtual address 1814 moval 16(sp),sp # Just like the HW would set it up 1815 jbr _Xprotflt 1816arithmetic: # same trickery as above 1817 pushl 20(sp) # The flags longword 1818 pushl 20(sp) # acc_low 1819 pushl 20(sp) # acc_high 1820 pushl 20(sp) # ret_exception ignored by REST_FPSTAT 1821 REST_FPSTAT # Back where we were with the sp ! 1822 movl (sp),20(sp) # code for arithmetic exception 1823 moval 20(sp),sp # Just like the HW would set it up 1824 jbr _Xarithtrap 1825#endif 1826