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.3 (Berkeley) 09/24/88 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 bbc $NETISR_RAW,_netisr,1f 344 andl2 $~(1<<NETISR_RAW),_netisr 345 callf $4,_rawintr 3461: 347 incl _cnt+V_SOFT 348 POPR; REST_FPSTAT 349 rei 350 351SCBVEC(cnrint): 352 CHECK_SFE(4) 353 SAVE_FPSTAT(4); PUSHR; 354 pushl $CPCONS; callf $8,_cnrint; 355 incl _intrcnt+I_CNR 356 incl _cnt+V_INTR 357 POPR; REST_FPSTAT; 358 rei 359SCBVEC(cnxint): 360 CHECK_SFE(4) 361 SAVE_FPSTAT(4); PUSHR; 362 pushl $CPCONS; callf $8,_cnxint; 363 incl _intrcnt+I_CNX 364 incl _cnt+V_INTR 365 POPR; REST_FPSTAT; 366 rei 367SCBVEC(rmtrint): 368 CHECK_SFE(4) 369 SAVE_FPSTAT(4); PUSHR; 370 pushl $CPREMOT; callf $8,_cnrint; 371 incl _intrcnt+I_RMTR 372 incl _cnt+V_INTR 373 POPR; REST_FPSTAT; 374 rei 375SCBVEC(rmtxint): 376 CHECK_SFE(4) 377 SAVE_FPSTAT(4); PUSHR; 378 pushl $CPREMOT; callf $8,_cnxint; 379 incl _intrcnt+I_RMTX 380 incl _cnt+V_INTR 381 POPR; REST_FPSTAT; 382 rei 383 384#define PUSHPCPSL pushl 4+FPSPC+REGSPC(sp); pushl 4+FPSPC+REGSPC(sp); 385 386SCBVEC(hardclock): 387 tstl _clk_enable 388 bneq 1f 389 rei 3901: 391 CHECK_SFE(4) 392 SAVE_FPSTAT(4); PUSHR 393 PUSHPCPSL # push pc and psl 394 callf $12,_hardclock # hardclock(pc,psl) 395 incl _intrcnt+I_CLOCK 396 incl _cnt+V_INTR ## temp so not to break vmstat -= HZ 397 POPR; REST_FPSTAT 398 rei 399SCBVEC(softclock): 400 CHECK_SFE(4) 401 SAVE_FPSTAT(4); PUSHR; 402 PUSHPCPSL # push pc and psl 403 callf $12,_softclock # softclock(pc,psl) 404 incl _cnt+V_SOFT 405 POPR; REST_FPSTAT 406 rei 407 408/* 409 * Stray VERSAbus interrupt catch routines 410 */ 411 .data 412#define PJ .align 2; callf $4,_Xvstray 413 .globl _catcher 414_catcher: 415 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 416 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ 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 428 .align 2 429 .globl _cold 430_cold: .long 0x3 431 432 .text 433SCBVEC(vstray): 434 .word 0 435 bbc $0,_cold,2f # system running? 436 bbc $1,_cold,1f # doing autoconfig? 437 jbr 3f # random interrupt, ignore 4381: 439 mfpr $IPL,r12 # ...setup br and cvec 440 subl3 $_catcher+7,-8(fp),r11; shar $3,r11,r11 441 addl2 $SCB_DEVBASE,r11 442 jbr 3f 4432: 444 PUSHR 445 subl3 $_catcher+7,-8(fp),r0; shar $3,r0,r0 446 addl3 $SCB_DEVBASE,r0,-(sp); 447 mfpr $IPL,-(sp) 448 PRINTF(2, "stray intr ipl %x vec %x\n") 449 POPR 4503: moval 0f,-8(fp); ret # pop callf frame... 4510: rei # ...and return 452 453/* 454 * Trap and fault vector routines 455 */ 456#define TRAP(a) pushl $T_/**/a; jbr alltraps 457 458/* 459 * Ast delivery (profiling and/or reschedule) 460 */ 461 462SCBVEC(kspnotval): 463 CHECK_SFE(4) 464 pushl $0; 465 SAVE_FPSTAT(8) 466 TRAP(KSPNOTVAL) 467SCBVEC(privinflt): 468 CHECK_SFE(4) 469 pushl $0; 470 SAVE_FPSTAT(8) 471 TRAP(PRIVINFLT) 472SCBVEC(resopflt): 473 CHECK_SFE(4) 474 pushl $0; 475 SAVE_FPSTAT(8) 476 TRAP(RESOPFLT) 477SCBVEC(resadflt): 478 CHECK_SFE(4) 479 pushl $0; 480 SAVE_FPSTAT(8) 481 TRAP(RESADFLT) 482SCBVEC(bptflt): 483 CHECK_SFE(4) 484 pushl $0; 485 SAVE_FPSTAT(8) 486 TRAP(BPTFLT) 487SCBVEC(kdbintr): 488 CHECK_SFE(4); 489 pushl $0; 490 SAVE_FPSTAT(8); 491 TRAP(KDBTRAP); 492SCBVEC(tracep): 493 CHECK_SFE(4) 494 pushl $0; 495 SAVE_FPSTAT(8) 496 TRAP(TRCTRAP) 497SCBVEC(alignflt): 498#ifdef ALIGN 499 bitl $PSL_CURMOD,4(sp) 500 jeql align_excp # Can't emulate for kernel mode ! 501 jbr non_aligned # Only emulated for user mode. 502align_excp: 503#else 504 CHECK_SFE(4) 505#endif 506 pushl $0; 507 SAVE_FPSTAT(8) 508 TRAP(ALIGNFLT) 509SCBVEC(arithtrap): 510 CHECK_SFE(8) 511 SAVE_FPSTAT(8) 512 TRAP(ARITHTRAP) 513 514SCBVEC(protflt): 515 CHECK_SFE(12) 516 bitl $1,(sp)+ 517 jneq segflt 518 SAVE_FPSTAT(8) 519 TRAP(PROTFLT) 520segflt: 521 SAVE_FPSTAT(8) 522 TRAP(SEGFLT) 523 524SCBVEC(fpm): # Floating Point Emulation 525#ifdef FPE 526 CHECK_SFE(16) 527 SAVE_FPSTAT(16) 528 incl _cnt+V_FPE # count emulation traps 529 callf $4,_fpemulate 530 REST_FPSTAT 531#endif 532 moval 8(sp),sp # Pop operand 533 tstl (sp) # Stack= PSL, PC, return_code 534 jneq _Xarithtrap # If not OK, emulate F.P. exception 535 movab 4(sp),sp # Else remove return_code and 536 rei 537 538SCBVEC(sfexcep): 539 CHECK_SFE(4) 540 pushl $0 541 SAVE_FPSTAT(8) 542 TRAP(ASTFLT) 543 544SCBVEC(transflt): 545 CHECK_SFE(12) 546 bitl $2,(sp)+ 547 bneq tableflt 548pageflt: 549 SAVE_FPSTAT(8) 550 TRAP(PAGEFLT) 551tableflt: 552 SAVE_FPSTAT(8) 553 TRAP(TABLEFLT) 554 555#define REST_STACK movab 4(sp), sp; REST_FPSTAT; movab 4(sp), sp 556 557alltraps: 558 mfpr $USP,-(sp); 559 callf $4,_trap; 560 mtpr (sp)+,$USP 561 incl _cnt+V_TRAP 562 REST_STACK # pop type, code, and fp stuff 563 mtpr $HIGH,$IPL ## dont go to a higher IPL (GROT) 564 rei 565 566SCBVEC(syscall): 567 CHECK_SFE(8) 568 SAVE_FPSTAT(8) 569 pushl $T_SYSCALL 570 mfpr $USP,-(sp); 571 callf $4,_syscall; 572 mtpr (sp)+,$USP 573 incl _cnt+V_SYSCALL 574 REST_STACK # pop type, code, and fp stuff 575 mtpr $HIGH,$IPL ## dont go to a higher IPL (GROT) 576 rei 577 578/* 579 * System page table. 580 * 581 * Mbmap and Usrptmap are enlarged by CLSIZE entries 582 * as they are managed by resource maps starting with index 1 or CLSIZE. 583 */ 584#define vaddr(x) ((((x)-_Sysmap)/4)*NBPG+SYSTEM) 585#define SYSMAP(mname, vname, npte) \ 586_/**/mname: .globl _/**/mname; \ 587 .space (npte)*4; \ 588 .globl _/**/vname; \ 589 .set _/**/vname,vaddr(_/**/mname) 590#define ADDMAP(npte) .space (npte)*4 591 592 .data 593 .align 2 594 SYSMAP(Sysmap ,Sysbase ,SYSPTSIZE ) 595 SYSMAP(Forkmap ,forkutl ,UPAGES ) 596 SYSMAP(Xswapmap ,xswaputl ,UPAGES ) 597 SYSMAP(Xswap2map,xswap2utl ,UPAGES ) 598 SYSMAP(Swapmap ,swaputl ,UPAGES ) 599 SYSMAP(Pushmap ,pushutl ,UPAGES ) 600 SYSMAP(Vfmap ,vfutl ,UPAGES ) 601 SYSMAP(CMAP1 ,CADDR1 ,1 ) 602 SYSMAP(CMAP2 ,CADDR2 ,1 ) 603 SYSMAP(mmap ,vmmap ,1 ) 604 SYSMAP(alignmap ,alignutl ,1 ) /* XXX */ 605 SYSMAP(msgbufmap,msgbuf ,MSGBUFPTECNT ) 606 SYSMAP(Mbmap ,mbutl ,NMBCLUSTERS*MCLBYTES/NBPG+CLSIZE ) 607 SYSMAP(kmempt ,kmembase ,300*CLSIZE ) 608#ifdef GPROF 609 SYSMAP(profmap ,profbase ,600*CLSIZE ) 610#endif 611 /* 612 * Enlarge kmempt as needed for bounce buffers allocated 613 * by tahoe controllers. 614 */ 615#include "hd.h" 616#if NHD > 0 617 ADDMAP( NHDC*(MAXPHYS/NBPG+CLSIZE) ) 618#endif 619#include "dk.h" 620#if NDK > 0 621 ADDMAP( NVD*(MAXPHYS/NBPG+CLSIZE) ) 622#endif 623#include "yc.h" 624#if NYC > 0 625 ADDMAP( NCY*(MAXPHYS/NBPG+CLSIZE) ) 626#endif 627#include "mp.h" 628 ADDMAP( NMP*14 ) 629 SYSMAP(ekmempt ,kmemlimit ,0 ) 630 631 SYSMAP(VMEMbeg ,vmembeg ,0 ) 632 SYSMAP(VMEMmap ,vmem ,VBIOSIZE ) 633 SYSMAP(VMEMmap1 ,vmem1 ,0 ) 634#include "ace.h" 635 ADDMAP( NACE*32 ) 636 SYSMAP(VMEMend ,vmemend ,0 ) 637 638 SYSMAP(VBmap ,vbbase ,CLSIZE ) 639#if NHD > 0 640 ADDMAP( NHDC*(MAXPHYS/NBPG+CLSIZE) ) 641#endif 642#if NDK > 0 643 ADDMAP( NVD*(MAXPHYS/NBPG+CLSIZE) ) 644#endif 645#if NYC > 0 646 ADDMAP( NCY*(MAXPHYS/NBPG+CLSIZE) ) 647#endif 648 ADDMAP( NMP*14 ) 649 SYSMAP(eVBmap ,vbend ,0 ) 650 651 SYSMAP(Usrptmap ,usrpt ,USRPTSIZE+CLSIZE ) 652eSysmap: 653 .globl _Syssize 654 .set _Syssize,(eSysmap-_Sysmap)/4 655 656 .text 657/* 658 * Initialization 659 * 660 * IPL 0x1f; MME 0; scbb, pcbb, sbr, slr, isp, ksp not set 661 */ 662 .align 2 663 .globl start 664start: 665 .word 0 666/* set system control block base and system page table params */ 667 mtpr $_scb-SYSTEM,$SCBB 668 mtpr $_Sysmap-SYSTEM,$SBR 669 mtpr $_Syssize,$SLR 670/* double map the kernel into the virtual user addresses of phys mem */ 671 mtpr $_Sysmap,$P0BR 672 mtpr $_Syssize,$P0LR 673 mtpr $_Sysmap,$P1BR # against Murphy 674 mtpr $_Syssize,$P1LR 675/* set ISP */ 676 movl $_intstack-SYSTEM+NISP*NBPG,sp # still physical 677 mtpr $_intstack+NISP*NBPG,$ISP 678/* count up memory */ 679 clrl r7 6801: pushl $1; pushl r7; callf $12,_badaddr; tstl r0; bneq 9f 681 ACBL($MAXMEM*1024-1,$64*1024,r7,1b) 6829: 683/* clear memory from kernel bss and pages for proc 0 u. and page table */ 684 movab _edata,r6; andl2 $~SYSTEM,r6 685 movab _end,r5; andl2 $~SYSTEM,r5 686#ifdef KADB 687 subl2 $4,r5 6881: clrl (r6); ACBL(r5,$4,r6,1b) # clear just bss 689 addl2 $4,r5 690 bbc $6,r11,0f # check RB_KDB 691 andl3 $~SYSTEM,r9,r5 # skip symbol & string tables 692 andl3 $~SYSTEM,r9,r6 693#endif 6940: orl3 $SYSTEM,r5,r9 # convert to virtual address 695 addl2 $NBPG-1,r9 # roundup to next page 696 addl2 $(UPAGES*NBPG)+NBPG+NBPG,r5 6971: clrl (r6); ACBL(r5,$4,r6,1b) 698/* trap(), syscall(), and fpemulate() save r0-r12 in the entry mask */ 699 orw2 $0x01fff,_trap 700 orw2 $0x01fff,_syscall 701#ifdef FPE 702 orw2 $0x01fff,_fpemulate 703#endif 704 orw2 $0x01ffc,_panic # for debugging (no r0|r1) 705 callf $4,_fixctlrmask # setup for autoconfig 706/* initialize system page table: scb and int stack writeable */ 707 clrl r2 708 movab eintstack,r1 709 andl2 $~SYSTEM,r1 710 shrl $PGSHIFT,r1,r1 # r1-page number of eintstack 711/* make 1st page processor storage read/only, 2nd read/write */ 712 orl3 $PG_V|PG_KR,r2,_Sysmap[r2]; incl r2; 713 orl3 $PG_V|PG_KW,r2,_Sysmap[r2]; incl r2; 714/* other parts of the system are read/write for kernel */ 7151: orl3 $PG_V|PG_KW,r2,_Sysmap[r2]; # data:kernel write+phys=virtual 716 aoblss r1,r2,1b 717/* make rsstk read-only as red zone for interrupt stack */ 718 andl2 $~PG_PROT,_rsstkmap 719 orl2 $PG_V|PG_KR,_rsstkmap 720/* make kernel text space read-only */ 721 movab _etext+NBPG-1,r1 722 andl2 $~SYSTEM,r1 723 shrl $PGSHIFT,r1,r1 7241: orl3 $PG_V|PG_KR,r2,_Sysmap[r2] 725 aoblss r1,r2,1b 726/* make kernel data, bss, read-write */ 727 andl3 $~SYSTEM,r9,r1 728 shrl $PGSHIFT,r1,r1 7291: orl3 $PG_V|PG_KW,r2,_Sysmap[r2] 730 aoblss r1,r2,1b 731/* go to mapped mode, have to change both pc and sp to system addresses */ 732 mtpr $1,$TBIA 733 mtpr $1,$PADC # needed by HW parity&ECC logic 734 mtpr $1,$PACC # just in case 735 mtpr $1,$MME 736 movab SYSTEM(sp),sp 737 jmp *$0f 7380: 739/* disable any interrupts */ 740 movl $0,_intenable 741/* init mem sizes */ 742 shrl $PGSHIFT,r7,_maxmem 743 movl _maxmem,_physmem 744 movl _maxmem,_freemem 745/* setup context for proc[0] == scheduler */ 746 andl3 $~SYSTEM,r9,r6 # convert to physical 747 andl2 $~(NBPG-1),r6 # make page boundary 748/* setup page table for proc[0] */ 749 shrl $PGSHIFT,r6,r3 # r3 = btoc(r6) 750 orl3 $PG_V|PG_KW,r3,_Usrptmap # init first upt entry 751 incl r3 # r3 - next page 752 movab _usrpt,r0 # r0 - first user page 753 mtpr r0,$TBIS 754/* init p0br, p0lr */ 755 mtpr r0,$P0BR # no p0 for proc[0] 756 mtpr $0,$P0LR 757 mtpr r0,$P1BR # no p1 either 758 mtpr $0,$P1LR 759/* init p2br, p2lr */ 760 movab NBPG(r0),r0 761 movl $PPAGES-UPAGES,r1 762 mtpr r1,$P2LR 763 moval -4*PPAGES(r0),r2 764 mtpr r2,$P2BR 765/* setup mapping for UPAGES of _u */ 766 clrl r2 767 movl $SYSTEM,r1 768 addl2 $UPAGES,r3 769 jbr 2f 7701: decl r3 771 moval -NBPG(r1),r1 # r1 = virtual add of next (downward) _u page 772 subl2 $4,r0 # r0 = pte address 773 orl3 $PG_V|PG_URKW,r3,(r0) 774 mtpr r1,$TBIS 7752: aobleq $UPAGES,r2,1b 776/* initialize (slightly) the pcb */ 777 movab UPAGES*NBPG(r1),PCB_KSP(r1) # KSP starts at end of _u 778 movl r1,PCB_USP(r1) # USP starts just below _u 779 mfpr $P0BR,PCB_P0BR(r1) 780 mfpr $P0LR,PCB_P0LR(r1) 781 mfpr $P1BR,PCB_P1BR(r1) 782 mfpr $P1LR,PCB_P1LR(r1) 783 mfpr $P2BR,PCB_P2BR(r1) 784 mfpr $P2LR,PCB_P2LR(r1) 785 movl $CLSIZE,PCB_SZPT(r1) # init u.u_pcb.pcb_szpt 786 movl r9,PCB_R9(r1) # r9 obtained from boot 787 movl r10,PCB_R10(r1) # r10 obtained from boot 788 movl r11,PCB_R11(r1) # r11 obtained from CP on boot 789 movab 1f,PCB_PC(r1) # initial pc 790 clrl PCB_PSL(r1) # kernel mode, ipl=0 791 shll $PGSHIFT,r3,r3 792 mtpr r3,$PCBB # first pcbb (physical) 793/* go to kernel mode */ 794 ldpctx 795 rei # Actually next instruction: 796/* put signal trampoline code in u. area */ 7971: movab sigcode,r0 798 movab _u+PCB_SIGC,r1 799 movl $19,r2 800 movblk 801/* save boot device in global _bootdev */ 802 movl r10,_bootdev 803/* save reboot flags in global _boothowto */ 804 movl r11,_boothowto 805#ifdef KADB 806/* save end of symbol & string table in global _bootesym */ 807 subl3 $NBPG-1,r9,_bootesym 808#endif 809/* calculate firstaddr, and call main() */ 810 andl3 $~SYSTEM,r9,r0 811 shrl $PGSHIFT,r0,-(sp) 812 addl2 $UPAGES+1,(sp) # first physical unused page 813 callf $8,_main 814/* proc[1] == /etc/init now running here in kernel mode; run icode */ 815 pushl $PSL_CURMOD # User mode PSL 816 pushl $0 # PC = 0 (virtual now) 817 rei 818 819/* 820 * Mask for saving/restoring registers on entry to 821 * a user signal handler. Space for the registers 822 * is reserved in sendsig, so beware if you want 823 * to change the mask. 824 */ 825#define SIGREGS (R0|R1|R2|R3|R4|R5) 826 .align 2 827 .globl sigcode 828sigcode: 829 storer $SIGREGS,16(sp) # save volatile registers 830 calls $4*3+4,*12(sp) # params pushed by sendsig for handler 831 loadr $SIGREGS,4(sp) # restore volatile registers 832 movab 24(sp),fp # use parameter list set up in sendsig 833 kcall $SYS_sigreturn # cleanup mask and onsigstack 834 halt # sigreturn does not return! 835 836 .globl _icode 837 .globl _initflags 838 .globl _szicode 839/* 840 * Icode is copied out to process 1 to exec /etc/init. 841 * If the exec fails, process 1 exits. 842 */ 843 .align 2 844_icode: 845 pushab b`argv-l0(pc) 846l0: pushab b`init-l1(pc) 847l1: pushl $2 848 movab (sp),fp 849 kcall $SYS_execv 850 pushl r0 851 kcall $SYS_exit 852 853init: .asciz "/etc/init" 854 .align 2 855_initflags: 856 .long 0 857argv: .long init+5-_icode 858 .long _initflags-_icode 859 .long 0 860_szicode: 861 .long _szicode-_icode 862 863/* 864 * Primitives 865 */ 866 867/* 868 * badaddr(addr, len) 869 * see if access addr with a len type instruction causes a machine check 870 * len is length of access (1=byte, 2=short, 4=long) 871 * r0 = 0 means good(exists); r0 =1 means does not exist. 872 */ 873ENTRY(badaddr, R3|R4) 874 mfpr $IPL,r1 875 mtpr $HIGH,$IPL 876 movl _scb+SCB_BUSERR,r2 877 movl 4(fp),r3 878 movl 8(fp),r4 879 movab 9f,_scb+SCB_BUSERR 880 bbc $0,r4,1f; tstb (r3) 8811: bbc $1,r4,1f; tstw (r3) 8821: bbc $2,r4,1f; tstl (r3) 8831: clrl r0 8842: movl r2,_scb+SCB_BUSERR 885 mtpr r1,$IPL 886 ret 887 888 .align 2 8899: # catch buss error (if it comes) 890 andl3 4(sp),$ERRCD,r0 891 cmpl r0,$APE 892 jneq 1f 893 halt # address parity error 8941: cmpl r0,$VBE 895 jneq 1f 896 halt # Versabus error 8971: 898 movl $1,r0 # Anything else = bad address 899 movab 8(sp),sp # discard buss error trash 900 movab 2b,(sp) # new program counter on stack. 901 rei 902 903/* 904 * badcyaddr(addr) 905 * see if access tape master controller addr causes a bus error 906 * r0 = 0: no error; r0 = 1: timeout error. 907 */ 908ENTRY(badcyaddr, 0) 909 mfpr $IPL,r1 910 mtpr $HIGH,$IPL 911 clrl r2 912 movab 2f,nofault 913 movob $-1, *4(fp) 9141: aobleq $1000, r2, 1b 915 clrl nofault # made it w/o bus error 916 clrl r0 917 jbr 3f 9182: movl $1,r0 9193: mtpr r1,$IPL 920 ret 921 922/* 923 * peek(addr) 924 * fetch word and catch any bus error 925 */ 926ENTRY(peek, 0) 927 mfpr $IPL,r1 928 mtpr $0x18,$IPL # not reentrant 929 movl 4(fp),r2 930 movab 1f,nofault 931 movw (r2),r0 932 clrl nofault 933 andl2 $0xffff,r0 934 jbr 2f 9351: movl $-1,r0 # bus error 9362: mtpr r1,$IPL 937 ret 938 939/* 940 * poke(addr, val) 941 * write word and catch any bus error 942 */ 943ENTRY(poke, R3) 944 mfpr $IPL,r1 945 mtpr $0x18,$IPL # not reentrant 946 movl 4(fp),r2 947 movl 8(fp),r3 948 clrl r0 949 movab 1f,nofault 950 movw r3,(r2) 951 clrl nofault 952 jbr 2f 9531: movl $-1,r0 # bus error 9542: mtpr r1,$IPL 955 ret 956 957/* 958 * Copy a potentially overlapping block of memory. 959 * 960 * ovbcopy(src, dst, count) 961 * caddr_t src, dst; unsigned count; 962 */ 963ENTRY(ovbcopy, R3|R4) 964 movl 4(fp),r0 965 movl 8(fp),r1 966 movl 12(fp),r2 967 cmpl r0,r1 968 bgtru 1f # normal forward case 969 beql 2f # equal, nothing to do 970 addl2 r2,r0 # may be overlapping 971 cmpl r0,r1 972 bgtru 3f 973 subl2 r2,r0 # normal forward case 9741: 975 movblk 9762: 977 ret 9783: 979 addl2 r2,r1 # overlapping, must do backwards 980 subl3 r0,r1,r3 981 movl r2,r4 982 jbr 5f 9834: 984 subl2 r3,r0 985 subl2 r3,r1 986 movl r3,r2 987 movblk 988 subl2 r3,r0 989 subl2 r3,r1 990 subl2 r3,r4 9915: 992 cmpl r4,r3 993 jgtr 4b 994 movl r4,r2 995 subl2 r2,r0 996 subl2 r2,r1 997 movblk 998 ret 999 1000/* 1001 * Copy a null terminated string from the user address space into 1002 * the kernel address space. 1003 * 1004 * copyinstr(fromaddr, toaddr, maxlength, &lencopied) 1005 */ 1006ENTRY(copyinstr, 0) 1007 movl 12(fp),r5 # r5 = max length 1008 jlss 5f 1009 movl 8(fp),r4 # r4 = kernel address 1010 movl 4(fp),r0 # r0 = user address 1011 andl3 $(NBPG*CLSIZE-1),r0,r2 # r2 = bytes on first page 1012 subl3 r2,$(NBPG*CLSIZE),r2 10131: 1014 cmpl r5,r2 # r2 = min(bytes on page, length left); 1015 jgeq 2f 1016 movl r5,r2 10172: 1018 prober $1,(r0),r2 # bytes accessible? 1019 jeql 5f 1020 subl2 r2,r5 # update bytes left count 1021 movl r2,r3 # r3 = saved count 1022 movl r0,r1 1023 cmps3 # check for null 1024 tstl r2 1025 jneq 3f 1026 subl2 r3,r0 # back up r0 1027 movl r4,r1 1028 movl r3,r2 1029 movblk # copy in next piece 1030 movl r1,r4 1031 movl $(NBPG*CLSIZE),r2 # check next page 1032 tstl r5 # run out of space? 1033 jneq 1b 1034 movl $ENOENT,r0 # set error code and return 1035 jbr 6f 10363: 1037 tstl 16(fp) # return length? 1038 beql 4f 1039 subl3 r5,12(fp),r5 # actual len = maxlen - unused pages 1040 subl2 r2,r5 # - unused on this page 1041 addl3 $1,r5,*16(fp) # + the null byte 10424: 1043 movl r4,r1 1044 subl3 r2,r3,r2 # calc char cnt 1045 subl2 r2,r0 # back up r0 1046 incl r2 # add on null byte 1047 movblk # copy last piece 1048 clrl r0 1049 ret 10505: 1051 movl $EFAULT,r0 10526: 1053 tstl 16(fp) 1054 beql 7f 1055 subl3 r5,12(fp),*16(fp) 10567: 1057 ret 1058 1059/* 1060 * Copy a null terminated string from the kernel 1061 * address space to the user address space. 1062 * 1063 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied) 1064 */ 1065ENTRY(copyoutstr, 0) 1066 movl 12(fp),r5 # r5 = max length 1067 jlss 5f 1068 movl 4(fp),r0 # r0 = kernel address 1069 movl 8(fp),r4 # r4 = user address 1070 andl3 $(NBPG*CLSIZE-1),r4,r2 # r2 = bytes on first page 1071 subl3 r2,$(NBPG*CLSIZE),r2 10721: 1073 cmpl r5,r2 # r2 = min(bytes on page, length left); 1074 jgeq 2f 1075 movl r5,r2 10762: 1077 probew $1,(r4),r2 # bytes accessible? 1078 jeql 5f 1079 subl2 r2,r5 # update bytes left count 1080 movl r2,r3 # r3 = saved count 1081 movl r0,r1 1082/* 1083 * This is a workaround for a microcode bug that causes 1084 * a trap type 9 when cmps3/movs3 touches the last byte 1085 * on a valid page immediately followed by an invalid page. 1086 */ 1087#ifdef good_cmps3 1088 cmps3 # check for null 1089 tstl r2 1090 jneq 3b 1091#else 1092 decl r2 1093 beql 9f # cannot handle case of r2 == 0! 1094 cmps3 # check for null up to last byte 10959: 1096 incl r2 1097 cmpl $1,r2 # get to last byte on page? 1098 bneq 3b 1099 tstb (r0) # last byte on page null? 1100 beql 3b 1101 incl r0 # not null, so bump pointer 1102#endif not good_cmps3 1103 subl2 r3,r0 # back up r0 1104 movl r4,r1 1105 movl r3,r2 1106 movblk # copy out next piece 1107 movl r1,r4 1108 movl $(NBPG*CLSIZE),r2 # check next page 1109 tstl r5 # run out of space? 1110 jneq 1b 1111 movl $ENOENT,r0 # set error code and return 1112 jbr 6b 11135: 1114 clrl *$0 # this should never execute, if it does 1115 movl $EFAULT,r0 # save me a core dump (mkm - 9/87) 11166: 1117 tstl 16(fp) 1118 beql 7f 1119 subl3 r5,12(fp),*16(fp) 11207: 1121 ret 1122 1123 1124/* 1125 * Copy a null terminated string from one point to another in 1126 * the kernel address space. 1127 * 1128 * copystr(fromaddr, toaddr, maxlength, &lencopied) 1129 */ 1130ENTRY(copystr, 0) 1131 movl 12(fp),r3 # r3 = max length 1132 jlss 5b 1133 movl 4(fp),r0 # r0 = src address 1134 movl 8(fp),r4 # r4 = dest address 1135 clrl r5 # r5 = bytes left 1136 movl r3,r2 # r2 = max bytes to copy 1137 movl r0,r1 1138 cmps3 # check for null 1139 tstl r2 1140 jneq 3b 1141 subl2 r3,r0 # back up r0 1142 movl r4,r1 1143 movl r3,r2 1144 movblk # copy next piece 1145 movl $ENOENT,r0 # set error code and return 1146 jbr 6b 1147 1148/* 1149 * Copy a block of data from the user address space into 1150 * the kernel address space. 1151 * 1152 * copyin(fromaddr, toaddr, count) 1153 */ 1154ENTRY(copyin, 0) 1155 movl 12(fp),r0 # copy length 1156 blss 9f 1157 movl 4(fp),r1 # copy user address 1158 cmpl $(CLSIZE*NBPG),r0 # probing one page or less ? 1159 bgeq 2f # yes 11601: 1161 prober $1,(r1),$(CLSIZE*NBPG) # bytes accessible ? 1162 beql 9f # no 1163 addl2 $(CLSIZE*NBPG),r1 # incr user address ptr 1164 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b) # reduce count and loop 11652: 1166 prober $1,(r1),r0 # bytes accessible ? 1167 beql 9f # no 1168 MOVC3(4(fp),8(fp),12(fp)) 1169 clrl r0 1170 ret 11719: 1172 movl $EFAULT,r0 1173 ret 1174 1175/* 1176 * Copy a block of data from the kernel 1177 * address space to the user address space. 1178 * 1179 * copyout(fromaddr, toaddr, count) 1180 */ 1181ENTRY(copyout, 0) 1182 movl 12(fp),r0 # get count 1183 blss 9b 1184 movl 8(fp),r1 # get user address 1185 cmpl $(CLSIZE*NBPG),r0 # can do in one probew? 1186 bgeq 2f # yes 11871: 1188 probew $1,(r1),$(CLSIZE*NBPG) # bytes accessible? 1189 beql 9b # no 1190 addl2 $(CLSIZE*NBPG),r1 # increment user address 1191 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b) # reduce count and loop 11922: 1193 probew $1,(r1),r0 # bytes accessible? 1194 beql 9b # no 1195 MOVC3(4(fp),8(fp),12(fp)) 1196 clrl r0 1197 ret 1198 1199/* 1200 * non-local goto's 1201 */ 1202#ifdef notdef 1203ENTRY(setjmp, 0) 1204 movl 4(fp),r0 1205 movl (fp),(r0); addl2 $4,r0 # save fp 1206 movl -8(fp),(r0) # save pc 1207 clrl r0 1208 ret 1209#endif 1210 1211ENTRY(longjmp, 0) 1212 movl 4(fp),r0 1213 movl (r0),newfp; addl2 $4,r0 # must save parameters in memory 1214 movl (r0),newpc # as all regs may be clobbered. 12151: 1216 cmpl fp,newfp # are we there yet? 1217 bgequ 2f # yes 1218 moval 1b,-8(fp) # redirect return pc to us! 1219 ret # pop next frame 12202: 1221 beql 3f # did we miss our frame? 1222 pushab 4f # yep ?!? 1223 callf $8,_panic 12243: 1225 movl newpc,r0 # all done, just return 1226 jmp (r0) # to setjmp `ret' 1227 1228 .data 1229newpc: .space 4 1230newfp: .space 4 12314: .asciz "longjmp" 1232 .text 1233 1234/* 1235 * setjmp that saves all registers as the call frame may not 1236 * be available to recover them in the usual manner by longjmp. 1237 * Called before swapping out the u. area, restored by resume() 1238 * below. 1239 */ 1240ENTRY(savectx, 0) 1241 movl 4(fp),r2 1242 storer $0x1ff8,(r2); addl2 $40,r2 # r3-r12 1243 movl (fp),(r2); addl2 $4,r2 # fp 1244 movab 8(fp),(r2); addl2 $4,r2 # sp 1245 movl -8(fp),(r2) # pc 1246 clrl r0 1247 ret 1248 1249#ifdef KADB 1250/* 1251 * C library -- reset, setexit 1252 * 1253 * reset(x) 1254 * will generate a "return" from 1255 * the last call to 1256 * setexit() 1257 * by restoring r2 - r12, fp 1258 * and doing a return. 1259 * The returned value is x; on the original 1260 * call the returned value is 0. 1261 */ 1262ENTRY(setexit, 0) 1263 movab setsav,r0 1264 storer $0x1ffc, (r0) 1265 movl (fp),44(r0) # fp 1266 moval 4(fp),48(r0) # sp 1267 movl -8(fp),52(r0) # pc 1268 clrl r0 1269 ret 1270 1271ENTRY(reset, 0) 1272 movl 4(fp),r0 # returned value 1273 movab setsav,r1 1274 loadr $0x1ffc,(r1) 1275 movl 44(r1),fp 1276 movl 48(r1),sp 1277 jmp *52(r1) 1278 1279 .data 1280 .align 2 1281setsav: .space 14*4 1282 .text 1283#endif 1284 1285 .globl _whichqs 1286 .globl _qs 1287 .globl _cnt 1288 1289 .globl _noproc 1290 .comm _noproc,4 1291 .globl _runrun 1292 .comm _runrun,4 1293/* 1294 * The following primitives use the fancy TAHOE instructions. 1295 * _whichqs tells which of the 32 queues _qs 1296 * have processes in them. setrq puts processes into queues, remrq 1297 * removes them from queues. The running process is on no queue, 1298 * other processes are on a queue related to p->p_pri, divided by 4 1299 * actually to shrink the 0-127 range of priorities into the 32 available 1300 * queues. 1301 */ 1302 1303/* 1304 * setrq(p), using fancy TAHOE instructions. 1305 * 1306 * Call should be made at spl8(), and p->p_stat should be SRUN 1307 */ 1308ENTRY(setrq, 0) 1309 movl 4(fp),r0 1310 tstl P_RLINK(r0) ## firewall: p->p_rlink must be 0 1311 beql set1 ## 1312 pushab set3 ## 1313 callf $8,_panic ## 1314set1: 1315 movzbl P_PRI(r0),r1 # put on queue which is p->p_pri / 4 1316 shar $2,r1,r1 1317 shal $1,r1,r2 1318 moval _qs[r2],r2 1319 insque (r0),*4(r2) # at end of queue 1320 shal r1,$1,r1 1321 orl2 r1,_whichqs # mark queue non-empty 1322 ret 1323 1324set3: .asciz "setrq" 1325 1326/* 1327 * remrq(p), using fancy TAHOE instructions 1328 * 1329 * Call should be made at spl8(). 1330 */ 1331ENTRY(remrq, 0) 1332 movl 4(fp),r0 1333 movzbl P_PRI(r0),r1 1334 shar $2,r1,r1 1335 bbs r1,_whichqs,rem1 1336 pushab rem3 # it wasn't recorded to be on its q 1337 callf $8,_panic 1338rem1: 1339 remque (r0) 1340 bneq rem2 # q not empty yet 1341 shal r1,$1,r1 1342 mcoml r1,r1 1343 andl2 r1,_whichqs # mark queue empty 1344rem2: 1345 clrl P_RLINK(r0) ## for firewall checking 1346 ret 1347 1348rem3: .asciz "remrq" 1349 1350/* 1351 * Masterpaddr is the p->p_addr of the running process on the master 1352 * processor. When a multiprocessor system, the slave processors will have 1353 * an array of slavepaddr's. 1354 */ 1355 .globl _masterpaddr 1356 .data 1357 .align 2 1358_masterpaddr: .long 0 1359 1360 .text 1361sw0: .asciz "swtch" 1362 1363/* 1364 * When no processes are on the runq, swtch branches to idle 1365 * to wait for something to come ready. 1366 */ 1367 .globl Idle 1368Idle: idle: 1369 movl $1,_noproc 1370 mtpr $0,$IPL # must allow interrupts here 13711: 1372 tstl _whichqs # look for non-empty queue 1373 bneq sw1 1374 brb 1b 1375 1376badsw: pushab sw0 1377 callf $8,_panic 1378 /* NOTREACHED */ 1379 1380 .align 2 1381/* 1382 * swtch(), using fancy tahoe instructions 1383 */ 1384ENTRY(swtch, 0) 1385 movl (fp),fp # prepare for rei 1386 movl (sp),4(sp) # saved pc 1387 tstl (sp)+ 1388 movpsl 4(sp) 1389 incl _cnt+V_SWTCH 1390sw1: ffs _whichqs,r0 # look for non-empty queue 1391 blss idle # if none, idle 1392 mtpr $0x18,$IPL # lock out all so _whichqs==_qs 1393 bbc r0,_whichqs,sw1 # proc moved via interrupt 1394 shal $1,r0,r1 1395 moval _qs[r1],r1 1396 movl (r1),r2 # r2 = p = highest pri process 1397 remque *(r1) 1398 bvs badsw # make sure something was there 1399 bneq sw2 1400 shal r0,$1,r1 1401 mcoml r1,r1 1402 andl2 r1,_whichqs # no more procs in this queue 1403sw2: 1404 clrl _noproc 1405 clrl _runrun 1406#ifdef notdef 1407 tstl P_WCHAN(r2) ## firewalls 1408 bneq badsw ## 1409 cmpb P_STAT(r2),$SRUN ## 1410 bneq badsw ## 1411#endif 1412 clrl P_RLINK(r2) ## 1413 movl *P_ADDR(r2),r0 1414#ifdef notdef 1415 cmpl r0,_masterpaddr # resume of current proc is easy 1416 beql res0 1417#endif 1418 movl r0,_masterpaddr 1419 shal $PGSHIFT,r0,r0 # r0 = pcbb(p) 1420 brb swresume 1421 1422/* 1423 * resume(pf) 1424 */ 1425ENTRY(resume, 0) 1426 shal $PGSHIFT,4(fp),r0 # r0 = pcbb(pf) 1427 movl (fp),fp # prepare for rei 1428 movl (sp)+,4(sp) # saved pc 1429 tstl (sp)+ 1430 movpsl 4(sp) 1431swresume: 1432 mtpr $0x18,$IPL # no interrupts, please 1433 movl _CMAP2,_u+PCB_CMAP2 # yech 1434 REST_ACC # restore original accumulator 1435 svpctx 1436 mtpr r0,$PCBB 1437 ldpctx 1438 movl _u+PCB_CMAP2,_CMAP2 # yech 1439 mtpr $_CADDR2,$TBIS 1440res0: 1441 movl _u+U_PROCP,r2 # r2 = u.u_procp 1442 tstl P_CKEY(r2) # does proc have code key? 1443 bneq 1f 1444 callf $4,_getcodekey # no, give him one 1445 movl _u+U_PROCP,r2 # r2 = u.u_procp 1446 movl r0,P_CKEY(r2) 14471: 1448 tstl P_DKEY(r2) # does proc have data key? 1449 bneq 1f 1450 callf $4,_getdatakey # no, give him one 1451 movl _u+U_PROCP,r2 # r2 = u.u_procp 1452 movl r0,P_DKEY(r2) 14531: 1454 mtpr P_CKEY(r2),$CCK # set code cache key 1455 mtpr P_DKEY(r2),$DCK # set data cache key 1456 tstl _u+PCB_SSWAP 1457 bneq res1 1458 rei 1459res1: # longjmp to saved context 1460 movl _u+PCB_SSWAP,r2 1461 clrl _u+PCB_SSWAP 1462 loadr $0x3ff8,(r2); addl2 $44,r2 # restore r3-r13 (r13=fp) 1463 movl (r2),r1; addl2 $4,r2 # fetch previous sp ... 1464 movab (sp),r0 # ... and current sp and 1465 cmpl r1,r0 # check for credibility, 1466 bgequ 1f # if further up stack ... 1467 pushab 2f; callf $8,_panic # ... panic 1468 /*NOTREACHED*/ 14691: # sp ok, complete return 1470 movl r1,sp # restore sp 1471 pushl $PSL_PRVMOD # kernel mode, ipl 0 1472 pushl (r2) # return address 1473 rei 14742: .asciz "ldctx" 1475 1476/* 1477 * {fu,su},{byte,word} 1478 */ 1479ENTRY(fuword, 0) 1480 movl 4(fp), r1 1481 prober $1,(r1),$4 # check access 1482 beql fserr # page unreadable 1483 bitl $1,r1 # check byte alignment 1484 bneq 2f # odd, do byte-word-byte 1485 bitl $2,r1 # check word alignment 1486 bneq 1f # odd, do in 2 words 1487 movl (r1),r0 # move longword 1488 ret 14891: 1490 movw (r1),r0 # move two words 1491 shal $16,r0,r0 1492 movzwl 2(r1),r1 # orw2 sign extends 1493 orl2 r1,r0 1494 ret 14952: 1496 movb (r1),r0 # move byte-word-byte 1497 shal $24,r0,r0 1498 movzwl 1(r1),r2 # orw2 sign extends 1499 shal $8,r2,r2 1500 movzbl 3(r1),r1 # orb2 sign extends 1501 orl2 r2,r1 1502 orl2 r1,r0 1503 ret 1504fserr: 1505 mnegl $1,r0 1506 ret 1507 1508ENTRY(fubyte, 0) 1509 prober $1,*4(fp),$1 1510 beql fserr 1511 movzbl *4(fp),r0 1512 ret 1513 1514ENTRY(suword, 0) 1515 movl 4(fp), r0 1516 probew $1,(r0),$4 # check access 1517 beql fserr # page unwritable 1518 bitl $1,r0 # check byte alignment 1519 bneq 1f # odd byte boundary 1520 bitl $2,r0 # check word alignment 1521 beql 2f # longword aligned 1522 movw 8(fp),(r0) # move two words 1523 movw 10(fp),2(r0) 1524 jbr 3f 15251: 1526 movb 8(fp),(r0) 1527 movb 9(fp),1(r0) 1528 movb 10(fp),2(r0) 1529 movb 11(fp),3(r0) 1530 jbr 3f 15312: 1532 movl 8(fp),(r0) 15333: 1534 clrl r0 1535 ret 1536 1537ENTRY(subyte, 0) 1538 probew $1,*4(fp),$1 1539 beql fserr 1540 movb 11(fp),*4(fp) 1541 clrl r0 1542 ret 1543 1544/* 1545 * Copy 1 relocation unit (NBPG bytes) 1546 * from user virtual address to physical address 1547 */ 1548ENTRY(copyseg, 0) 1549 orl3 $PG_V|PG_KW,8(fp),_CMAP2 1550 mtpr $_CADDR2,$TBIS # invalidate entry for copy 1551 MOVC3(4(fp),$_CADDR2,$NBPG) 1552 ret 1553 1554/* 1555 * Clear a page of memory. The page frame is specified. 1556 * 1557 * clearseg(pf); 1558 */ 1559ENTRY(clearseg, 0) 1560 orl3 $PG_V|PG_KW,4(fp),_CMAP1 # Maps to virtual addr CADDR1 1561 mtpr $_CADDR1,$TBIS 1562 movl $255,r0 # r0 = limit 1563 clrl r1 # r1 = index of cleared long 15641: 1565 clrl _CADDR1[r1] 1566 aobleq r0,r1,1b 1567 ret 1568 1569/* 1570 * Check user mode read/write access. 1571 * 1572 * useracc(addr, count, mode) 1573 * caddr_t addr; int count, mode; 1574 * mode = 0 write access 1575 * mode = 1 read access 1576 */ 1577ENTRY(useracc, 0) 1578 movl $1,r2 # r2 = 'user mode' for probew/probew 1579probes: 1580 movl 4(fp),r0 # get va 1581 movl 8(fp),r1 # count 1582 tstl 12(fp) # test for read access ? 1583 bneq userar # yes 1584 cmpl $(CLSIZE*NBPG),r1 # can we do it in one probe ? 1585 bgeq uaw2 # yes 1586uaw1: 1587 probew r2,(r0),$(CLSIZE*NBPG) 1588 beql uaerr # no access 1589 addl2 $(CLSIZE*NBPG),r0 1590 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uaw1) 1591uaw2: 1592 probew r2,(r0),r1 1593 beql uaerr 1594 movl $1,r0 1595 ret 1596userar: 1597 cmpl $(CLSIZE*NBPG),r1 1598 bgeq uar2 1599uar1: 1600 prober r2,(r0),$(CLSIZE*NBPG) 1601 beql uaerr 1602 addl2 $(CLSIZE*NBPG),r0 1603 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uar1) 1604uar2: 1605 prober r2,(r0),r1 1606 beql uaerr 1607 movl $1,r0 1608 ret 1609uaerr: 1610 clrl r0 1611 ret 1612 1613/* 1614 * Check kernel mode read/write access. 1615 * 1616 * kernacc(addr, count, mode) 1617 * caddr_t addr; int count, mode; 1618 * mode = 0 write access 1619 * mode = 1 read access 1620 */ 1621ENTRY(kernacc, 0) 1622 clrl r2 # r2 = 0 means kernel mode probe. 1623 jbr probes # Dijkstra would get gastric distress here. 1624 1625/* 1626 * addupc - increment some histogram counter 1627 * in the profiling buffer 1628 * 1629 * addupc(pc, prof, delta) 1630 * long pc; short delta; struct uprof *prof; 1631 * 1632 * struct uprof { # profile arguments 1633 * short *r_base; # buffer base 1634 * unsigned pr_size; # buffer size 1635 * unsigned pr_off; # pc offset 1636 * unsigned pr_scale; # pc scaling 1637 * } 1638 */ 1639ENTRY(addupc, 0) 1640 movl 8(fp),r2 # r2 points to structure 1641 subl3 8(r2),4(fp),r0 # r0 = PC - lowpc 1642 jlss 9f # PC < lowpc , out of range ! 1643 shrl $1,r0,r0 # the unit is words 1644 shrl $1,12(r2),r1 # ditto for scale 1645 emul r1,r0,$0,r0 1646 shrq $14,r0,r0 1647 tstl r0 # too big 1648 jneq 9f 1649 cmpl r1,4(r2) # Check buffer overflow 1650 jgequ 9f 1651 probew $1,*0(r2)[r1],$2 # counter accessible? 1652 jeql 9f 1653 shrl $1,r1,r1 # make r1 word index 1654 addw2 14(fp),*0(r2)[r1] 16559: ret 1656 1657/* 1658 * scanc(size, cp, table, mask) 1659 */ 1660ENTRY(scanc, R3|R4) 1661 movl 8(fp),r0 # r0 = cp 1662 addl3 4(fp),r0,r2 # end = &cp[size] 1663 movl 12(fp),r1 # r1 = table 1664 movb 19(fp),r4 # r4 = mask 1665 decl r0 # --cp 1666 jbr 0f # just like Fortran... 16671: # do { 1668 movzbl (r0),r3 1669 bitb r4,(r1)[r3] # if (table[*cp] & mask) 1670 jneq 2f # break; 16710: aoblss r2,r0,1b # } while (++cp < end); 16722: 1673 subl3 r0,r2,r0; ret # return (end - cp); 1674 1675/* 1676 * skpc(mask, size, cp) 1677 */ 1678ENTRY(skpc, 0) 1679 movl 12(fp),r0 # r0 = cp 1680 addl3 8(fp),r0,r1 # r1 = end = &cp[size]; 1681 movb 7(fp),r2 # r2 = mask 1682 decl r0 # --cp; 1683 jbr 0f 16841: # do 1685 cmpb (r0),r2 # if (*cp != mask) 1686 jneq 2f # break; 16870: aoblss r1,r0,1b # while (++cp < end); 16882: 1689 subl3 r0,r1,r0; ret # return (end - cp); 1690 1691/* 1692 * locc(mask, size, cp) 1693 */ 1694ENTRY(locc, 0) 1695 movl 12(fp),r0 # r0 = cp 1696 addl3 8(fp),r0,r1 # r1 = end = &cp[size] 1697 movb 7(fp),r2 # r2 = mask 1698 decl r0 # --cp; 1699 jbr 0f 17001: # do 1701 cmpb (r0),r2 # if (*cp == mask) 1702 jeql 2f # break; 17030: aoblss r1,r0,1b # while (++cp < end); 17042: 1705 subl3 r0,r1,r0; ret # return (end - cp); 1706 1707#ifdef ALIGN 1708#include "../tahoealign/align.h" 1709 1710 .globl _alignment 1711/* 1712 * There's an intimate relationship between this piece of code 1713 * and the alignment emulation code (especially the layout 1714 * of local variables in alignment.c! Don't change unless 1715 * you update both this, alignment.h and alignment.c !! 1716 */ 1717non_aligned: 1718 orb2 $EMULATEALIGN,_u+U_EOSYS 1719 incl _cnt+V_TRAP 1720 incl _cnt+V_ALIGN # count emulated alignment traps 1721 moval 4(sp),_user_psl 1722 SAVE_FPSTAT(4) # Also zeroes out ret_exception ! 1723 pushl $0 # ret_addr 1724 pushl $0 # ret_code 1725 mfpr $USP,-(sp) # user sp 1726 callf $4,_alignment # call w/o parms so regs may be modified 1727 /* 1728 * We return here after a successful emulation or an exception. 1729 * The registers have been restored and we must not alter them 1730 * before returning to the user. 1731 */ 17322: mtpr (sp)+,$USP # restore user sp 1733 tstl 8(sp) # Any exception ? 1734 bneq got_excp # Yes, reflect it back to user. 1735 moval 8(sp),sp # pop 2 zeroes pushed above 1736 REST_FPSTAT 1737 xorb2 $EMULATEALIGN,_u+U_EOSYS 1738 1739 bitl $PSL_T,4(sp) # check for trace bit set 1740 beql 9f 1741 CHECK_SFE(4) 1742 pushl $0 1743 SAVE_FPSTAT(8) 1744 TRAP(TRCTRAP) 17459: rei 1746 1747got_excp: # decode exception 1748 casel 8(sp),$ILL_ADDRMOD,$ALIGNMENT 1749 .align 1 1750L1: 1751 .word ill_addrmod-L1 1752 .word ill_access-L1 1753 .word ill_oprnd-L1 1754 .word arithmetic-L1 1755 .word alignment-L1 1756 brw alignment # default - shouldn't come here at all ! 1757 1758ill_addrmod: # No other parameters. Set up stack as 1759 moval 8(sp),sp # the HW would do it in a real case. 1760 REST_FPSTAT 1761 jbr _Xresadflt 1762ill_oprnd: 1763 moval 8(sp),sp 1764 REST_FPSTAT 1765 jbr _Xresopflt 1766alignment: 1767 moval 8(sp),sp 1768 REST_FPSTAT 1769 jbr align_excp # NB: going to _Xalignflt would cause loop 1770ill_access: 1771 /* 1772 * Must restore accumulator w/o modifying sp and w/o using 1773 * registers. Solution: copy things needed by REST_FPSTAT. 1774 */ 1775 pushl 20(sp) # The flags longword 1776 pushl 20(sp) # acc_low 1777 pushl 20(sp) # acc_high 1778 pushl 20(sp) # ret_exception ignored by REST_FPSTAT 1779 REST_FPSTAT # Back where we were with the sp ! 1780 movl (sp),16(sp) # code for illegal access 1781 movl 4(sp),20(sp) # original virtual address 1782 moval 16(sp),sp # Just like the HW would set it up 1783 jbr _Xprotflt 1784arithmetic: # same trickery as above 1785 pushl 20(sp) # The flags longword 1786 pushl 20(sp) # acc_low 1787 pushl 20(sp) # acc_high 1788 pushl 20(sp) # ret_exception ignored by REST_FPSTAT 1789 REST_FPSTAT # Back where we were with the sp ! 1790 movl (sp),20(sp) # code for arithmetic exception 1791 moval 20(sp),sp # Just like the HW would set it up 1792 jbr _Xarithtrap 1793#endif 1794