1/* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1980, 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * %sccs.include.redist.c% 11 * 12 * from: Utah $Hdr: locore.s 1.47 89/10/08$ 13 * 14 * @(#)locore.s 7.2 (Berkeley) 05/25/90 15 */ 16 17 .text 18/* 19 * This is where we wind up if the kernel jumps to location 0. 20 * (i.e. a bogus PC) This is known to immediately follow the vector 21 * table and is hence at 0x400 (see reset vector in vectors.s). 22 */ 23 .globl _panic 24 pea Ljmp0panic 25 jbsr _panic 26 /* NOTREACHED */ 27Ljmp0panic: 28 .asciz "kernel jump to zero" 29 .even 30 31/* 32 * Do a dump. 33 * Called by auto-restart. 34 */ 35 .globl _dumpsys 36 .globl _doadump 37_doadump: 38 jbsr _dumpsys 39 jbsr _doboot 40 /*NOTREACHED*/ 41 42/* 43 * Trap/interrupt vector routines 44 */ 45 46 .globl _trap, _nofault, _longjmp 47_buserr: 48 tstl _nofault | device probe? 49 jeq _addrerr | no, handle as usual 50 movl _nofault,sp@- | yes, 51 jbsr _longjmp | longjmp(nofault) 52_addrerr: 53 clrw sp@- | pad SR to longword 54 moveml #0xFFFF,sp@- | save user registers 55 movl usp,a0 | save the user SP 56 movl a0,sp@(60) | in the savearea 57 lea sp@(64),a1 | grab base of HW berr frame 58 movw a1@(12),d0 | grab SSW for fault processing 59 btst #12,d0 | RB set? 60 jeq LbeX0 | no, test RC 61 bset #14,d0 | yes, must set FB 62 movw d0,a1@(12) | for hardware too 63LbeX0: 64 btst #13,d0 | RC set? 65 jeq LbeX1 | no, skip 66 bset #15,d0 | yes, must set FC 67 movw d0,a1@(12) | for hardware too 68LbeX1: 69 btst #8,d0 | data fault? 70 jeq Lbe0 | no, check for hard cases 71 movl a1@(18),d1 | fault address is as given in frame 72 jra Lbe10 | thats it 73Lbe0: 74 btst #4,a1@(8) | long (type B) stack frame? 75 jne Lbe4 | yes, go handle 76 movl a1@(4),d1 | no, can use save PC 77 btst #14,d0 | FB set? 78 jeq Lbe3 | no, try FC 79 addql #4,d1 | yes, adjust address 80 jra Lbe10 | done 81Lbe3: 82 btst #15,d0 | FC set? 83 jeq Lbe10 | no, done 84 addql #2,d1 | yes, adjust address 85 jra Lbe10 | done 86Lbe4: 87 movl a1@(38),d1 | long format, use stage B address 88 btst #15,d0 | FC set? 89 jeq Lbe10 | no, all done 90 subql #2,d1 | yes, adjust address 91Lbe10: 92 movl d1,sp@- | push fault VA 93 movw d0,sp@- | and SSW 94 clrw sp@- | padded to longword 95 movw a1@(8),d0 | get frame format/vector offset 96 andw #0x0FFF,d0 | clear out frame format 97 cmpw #12,d0 | address error vector? 98 jeq Lisaerr | yes, go to it 99#if defined(HP330) || defined(HP360) || defined(HP370) 100 tstl _mmutype | HP MMU? 101 jeq Lbehpmmu | yes, skip 102 movl d1,a0 | fault address 103 .long 0xf0109e11 | ptestr #1,a0@,#7 104 .long 0xf0176200 | pmove psr,sp@ 105 btst #7,sp@ | bus error bit set? 106 jeq Lismerr | no, must be MMU fault 107 clrw sp@ | yes, re-clear pad word 108 jra Lisberr | and process as normal bus error 109Lbehpmmu: 110#endif 111#if defined(HP320) || defined(HP350) 112 lea _IObase+MMUSTAT,a0 | no, get addr of MMU status 113 movl a0@,d0 | read status 114 btst #3,d0 | MMU fault? 115 jeq Lisberr | no, just a non-MMU bus error so skip 116 andl #~MMU_FAULT,a0@ | yes, clear fault bits 117 movw d0,sp@ | pass MMU stat in upper half of code 118#endif 119Lismerr: 120 movl #T_MMUFLT,sp@- | show that we are an MMU fault 121 jra Lbexit | and deal with it 122Lisaerr: 123 movl #T_ADDRERR,sp@- | mark address error 124 jra Lbexit | and deal with it 125Lisberr: 126 movl #T_BUSERR,sp@- | mark bus error 127Lbexit: 128 jbsr _trap | handle the error 129 lea sp@(12),sp | pop value args 130 movl sp@(60),a0 | restore user SP 131 movl a0,usp | from save area 132 moveml sp@+,#0x7FFF | restore most user regs 133 addql #4,sp | toss SSP 134 tstw sp@+ | do we need to clean up stack? 135 jeq rei | no, just continue 136 btst #7,sp@(6) | type 9/10/11 frame? 137 jeq rei | no, nothing to do 138 btst #5,sp@(6) | type 9? 139 jne Lbex1 | no, skip 140 movw sp@,sp@(12) | yes, push down SR 141 movl sp@(2),sp@(14) | and PC 142 clrw sp@(18) | and mark as type 0 frame 143 lea sp@(12),sp | clean the excess 144 jra rei | all done 145Lbex1: 146 btst #4,sp@(6) | type 10? 147 jne Lbex2 | no, skip 148 movw sp@,sp@(24) | yes, push down SR 149 movl sp@(2),sp@(26) | and PC 150 clrw sp@(30) | and mark as type 0 frame 151 lea sp@(24),sp | clean the excess 152 jra rei | all done 153Lbex2: 154 movw sp@,sp@(84) | type 11, push down SR 155 movl sp@(2),sp@(86) | and PC 156 clrw sp@(90) | and mark as type 0 frame 157 lea sp@(84),sp | clean the excess 158 jra rei | all done 159 160_illinst: 161 clrw sp@- 162 moveml #0xFFFF,sp@- 163 moveq #T_ILLINST,d0 164 jra _fault 165 166_zerodiv: 167 clrw sp@- 168 moveml #0xFFFF,sp@- 169 moveq #T_ZERODIV,d0 170 jra _fault 171 172_chkinst: 173 clrw sp@- 174 moveml #0xFFFF,sp@- 175 moveq #T_CHKINST,d0 176 jra _fault 177 178_trapvinst: 179 clrw sp@- 180 moveml #0xFFFF,sp@- 181 moveq #T_TRAPVINST,d0 182 jra _fault 183 184_privinst: 185 clrw sp@- 186 moveml #0xFFFF,sp@- 187 moveq #T_PRIVINST,d0 188 jra _fault 189 190_coperr: 191 clrw sp@- 192 moveml #0xFFFF,sp@- 193 moveq #T_COPERR,d0 194 jra _fault 195 196_fmterr: 197 clrw sp@- 198 moveml #0xFFFF,sp@- 199 moveq #T_FMTERR,d0 200 jra _fault 201 202_fptrap: 203#ifdef FPCOPROC 204 clrw sp@- | pad SR to longword 205 moveml #0xFFFF,sp@- | save user registers 206 movl usp,a0 | and save 207 movl a0,sp@(60) | the user stack pointer 208 clrl sp@- | no VA arg 209 lea _u+PCB_FPCTX,a0 | address of FP savearea 210 .word 0xf310 | fsave a0@ 211 tstb a0@ | null state frame? 212 jeq Lfptnull | yes, safe 213 clrw d0 | no, need to tweak BIU 214 movb a0@(1),d0 | get frame size 215 bset #3,a0@(0,d0:w) | set exc_pend bit of BIU 216Lfptnull: 217 .word 0xf227,0xa800 | fmovem fpsr,sp@- (code arg) 218 .word 0xf350 | frestore a0@ 219 movl #T_FPERR,sp@- | push type arg 220 jbsr _trap | call trap 221 lea sp@(12),sp | pop value args 222 movl sp@(60),a0 | restore 223 movl a0,usp | user SP 224 moveml sp@+,#0x7FFF | and remaining user registers 225 addql #6,sp | pop SSP and align word 226 jra rei | all done 227#else 228 jra _badtrap | treat as an unexpected trap 229#endif 230 231 .globl _fault 232_fault: 233 movl usp,a0 | get and save 234 movl a0,sp@(60) | the user stack pointer 235 clrl sp@- | no VA arg 236 clrl sp@- | or code arg 237 movl d0,sp@- | push trap type 238 jbsr _trap | handle trap 239 lea sp@(12),sp | pop value args 240 movl sp@(60),a0 | restore 241 movl a0,usp | user SP 242 moveml sp@+,#0x7FFF | restore most user regs 243 addql #6,sp | pop SP and pad word 244 jra rei | all done 245 246 .globl _straytrap 247_badtrap: 248 clrw sp@- 249 moveml #0xC0C0,sp@- 250 movw sp@(24),sp@- 251 clrw sp@- 252 jbsr _straytrap 253 addql #4,sp 254 moveml sp@+,#0x0303 255 addql #2,sp 256 jra rei 257 258 .globl _syscall 259_trap0: 260 clrw sp@- | pad SR to longword 261 moveml #0xFFFF,sp@- | save user registers 262 movl usp,a0 | save the user SP 263 movl a0,sp@(60) | in the savearea 264 movl d0,sp@- | push syscall number 265 jbsr _syscall | handle it 266 addql #4,sp | pop syscall arg 267 movl sp@(60),a0 | grab and restore 268 movl a0,usp | user SP 269 moveml sp@+,#0x7FFF | restore most registers 270 addql #6,sp | pop SSP and align word 271 jra rei | all done 272 273/* 274 * Routines for traps 1 and 2. The meaning of the two traps depends 275 * on whether we are an HPUX compatible process or a native 4.3 process. 276 * Our native 4.3 implementation uses trap 1 as sigreturn() and trap 2 277 * as a breakpoint trap. HPUX uses trap 1 for a breakpoint, so we have 278 * to make adjustments so that trap 2 is used for sigreturn. 279 */ 280_trap1: 281 btst #PCB_TRCB,_u+PCB_FLAGS+1| being traced by an HPUX process? 282 jeq sigreturn | no, trap1 is sigreturn 283 jra _trace | yes, trap1 is breakpoint 284 285_trap2: 286 btst #PCB_TRCB,_u+PCB_FLAGS+1| being traced by an HPUX process? 287 jeq _trace | no, trap2 is breakpoint 288 jra sigreturn | yes, trap2 is sigreturn 289 290/* 291 * Trap 15 is used for: 292 * - KGDB traps 293 * - trace traps for SUN binaries (not fully supported yet) 294 * We just pass it on and let trap() sort it all out 295 */ 296_trap15: 297 clrw sp@- 298 moveml #0xFFFF,sp@- 299 moveq #T_TRAP15,d0 300 jra _fault 301 302/* 303 * Hit a breakpoint (trap 1 or 2) instruction. 304 * Push the code and treat as a normal fault. 305 */ 306_trace: 307 clrw sp@- 308 moveml #0xFFFF,sp@- 309 moveq #T_TRACE,d0 310 jra _fault 311 312/* 313 * The sigreturn() syscall comes here. It requires special handling 314 * because we must open a hole in the stack to fill in the (possibly much 315 * larger) original stack frame. 316 */ 317sigreturn: 318 lea sp@(-84),sp | leave enough space for largest frame 319 movl sp@(84),sp@ | move up current 8 byte frame 320 movl sp@(88),sp@(4) 321 movw #0xFFFF,sp@- | default: must clean stack 322 moveml #0xFFFF,sp@- | save user registers 323 movl usp,a0 | save the user SP 324 movl a0,sp@(60) | in the savearea 325 movl #SYS_sigreturn,sp@- | push syscall number 326 jbsr _syscall | handle it 327 addql #4,sp | pop syscall# 328 movl sp@(60),a0 | grab and restore 329 movl a0,usp | user SP 330 lea sp@(64),a1 | pointer to HW frame 331 tstw a1@+ | do we need to clean up stack? 332 jeq Lsigr1 | no, just continue 333 movb a1@(6),d0 | grab format byte 334 lsrb #4,d0 | get rid of excess 335 cmpb #10,d0 | type 10 frame? 336 jne Lsigr2 | no, continue 337 movw #32,d1 | yes, frame size is 32 bytes 338 jra Lsigrcp | go to it 339Lsigr2: 340 cmpb #9,d0 | type 9? 341 jne Lsigr3 | no, continue 342 movw #20,d1 | yes, frame size is 20 bytes 343 jra Lsigrcp | go to it 344Lsigr3: 345 cmpb #2,d0 | type 2? 346 jne Lsigr4 | no, continue 347 movw #12,d1 | yes, frame size is 12 bytes 348 jra Lsigrcp | go to it 349Lsigr4: 350 movw #8,d1 | must be type 0/1, size is 8 bytes 351Lsigrcp: 352 lea a1@(92),a0 | destination 353 addw d1,a1 | source 354 lsrw #1,d1 | convert to word count 355 subqw #1,d1 | minus 1 for dbf 356Lsigrlp: 357 movw a1@-,a0@- | copy a word 358 dbf d1,Lsigrlp | continue 359 movl a0,a1 | new HW frame base 360Lsigr1: 361 movl a1,sp@(60) | new SP value 362 moveml sp@+,#0x7FFF | restore user registers 363 movl sp@,sp | and our SP 364 jra rei | all done 365 366/* 367 * Interrupt handlers. 368 * All DIO device interrupts are auto-vectored. Most can be configured 369 * to interrupt in the range IPL3 to IPL5. Here are our assignments: 370 * 371 * Level 0: Spurious: ignored. 372 * Level 1: HIL 373 * Level 2: 374 * Level 3: Internal HP-IB 375 * Level 4: "Fast" HP-IBs, SCSI 376 * Level 5: DMA, Ethernet, Built-in RS232 377 * Level 6: Clock 378 * Level 7: Non-maskable: parity errors, RESET key 379 */ 380 .globl _hilint, _intrhand, _hardclock, _nmihand 381 382_spurintr: 383 addql #1,_intrcnt+0 384 addql #1,_cnt+V_INTR 385 jra rei 386 387_lev1intr: 388 addql #1,_intrcnt+4 389 clrw sp@- 390 moveml #0xC0C0,sp@- 391 jbsr _hilint 392 moveml sp@+,#0x0303 393 addql #2,sp 394 addql #1,_cnt+V_INTR 395 jra rei 396 397/* check for DMA first to reduce overhead */ 398_lev5intr: 399 clrw sp@- 400 moveml #0xC0C0,sp@- 401 jbsr _dmaintr 402 tstl d0 403 jeq Lnotdma 404 addql #1,_intrcnt+24 405 moveml sp@+,#0x0303 406 addql #2,sp 407 addql #1,_cnt+V_INTR 408 jra rei 409 410_lev2intr: 411_lev3intr: 412_lev4intr: 413 clrw sp@- 414 moveml #0xC0C0,sp@- 415Lnotdma: 416 lea _intrcnt,a0 417 movw sp@(24),d0 | use vector offset 418 andw #0xfff,d0 | sans frame type 419 addql #1,a0@(-0x60,d0:w) | to increment apropos counter 420 movw sr,sp@- | push current SR value 421 clrw sp@- | padded to longword 422 jbsr _intrhand | handle interrupt 423 addql #4,sp | pop SR 424 moveml sp@+,#0x0303 425 addql #2,sp 426 addql #1,_cnt+V_INTR 427 jra rei 428 429_lev6intr: 430 clrw sp@- 431 moveml #0xC0C0,sp@- 432#ifdef DEBUG 433 .globl _panicstr, _regdump, _panic 434 tstl timebomb | set to go off? 435 jeq Lnobomb | no, skip it 436 subql #1,timebomb | decrement 437 jne Lnobomb | not ready to go off 438 moveml sp@+,#0x0303 | temporarily restore regs 439 jra Luseours | go die 440Lnobomb: 441 cmpl #_u+NBPG+NBPG,sp | our we still in stack page? 442 jcc Lstackok | yes, continue normally 443 tstl _panicstr | have we paniced? 444 jne Lstackok | yes, do not re-panic 445 moveml sp@+,#0x0303 | no, temporarily restore regs 446 cmpl #_u+NBPG+0x400,sp | our we safely in redzone? 447 jcc Luseours | yes, panic with this stack 448 lea tmpstk,sp | no, switch to tmpstk 449Luseours: 450 moveml #0xFFFF,sp@- | push all registers 451 movl sp,a0 | remember this spot 452 movl #256,sp@- | longword count 453 movl a0,sp@- | and reg pointer 454 jbsr _regdump | dump core 455 addql #8,sp | pop params 456 movl #Lstkrip,sp@- | push panic message 457 jbsr _panic | ES and D 458Lstkrip: 459 .asciz "k-stack overflow" 460 .even 461Lstackok: 462#endif 463 movb _IObase+CLKSR,d0 | read clock status 464#ifdef PROFTIMER 465 .globl _profon 466 tstb _profon | profile clock on? 467 jeq Ltimer1 | no, then must be timer1 interrupt 468 btst #2,d0 | timer3 interrupt? 469 jeq Ltimer1 | no, must be timer1 470 movb _IObase+CLKMSB3,d1 | clear timer3 interrupt 471 lea sp@(16),a1 | get pointer to PS 472#ifdef GPROF 473 .globl _profclock 474 movl d0,sp@- | save status so jsr will not clobber 475 movl a1@,sp@- | push padded PS 476 movl a1@(4),sp@- | push PC 477 jbsr _profclock | profclock(pc, ps) 478 addql #8,sp | pop params 479#else 480 btst #5,a1@(2) | saved PS in user mode? 481 jne Lttimer1 | no, go check timer1 482 tstl _u+U_PROFSCALE | process being profiled? 483 jeq Lttimer1 | no, go check timer1 484 movl d0,sp@- | save status so jsr will not clobber 485 movl #1,sp@- 486 movl #_u+U_PROF,sp@- 487 movl a1@(4),sp@- 488 jbsr _addupc | addupc(pc, &u.u_prof, 1) 489 lea sp@(12),sp | pop params 490#endif 491 addql #1,_intrcnt+32 | add another profile clock interrupt 492 movl sp@+,d0 | get saved clock status 493Lttimer1: 494 btst #0,d0 | timer1 interrupt? 495 jeq Ltimend | no, check state of kernel profiling 496Ltimer1: 497#endif 498 movb _IObase+CLKMSB1,d1 | clear timer1 interrupt 499 lea sp@(16),a1 | get pointer to PS 500 movl a1@,sp@- | push padded PS 501 movl a1@(4),sp@- | push PC 502 jbsr _hardclock | call generic clock int routine 503 addql #8,sp | pop params 504 addql #1,_intrcnt+28 | add another system clock interrupt 505#ifdef PROFTIMER 506Ltimend: 507#ifdef GPROF 508 .globl _profiling, _startprofclock 509 tstl _profiling | kernel profiling desired? 510 jne Ltimdone | no, all done 511 bset #7,_profon | mark continuous timing 512 jne Ltimdone | was already enabled, all done 513 jbsr _startprofclock | else turn it on 514Ltimdone: 515#endif 516#endif 517 moveml sp@+,#0x0303 | restore scratch regs 518 addql #2,sp | pop pad word 519 addql #1,_cnt+V_INTR | chalk up another interrupt 520 jra rei | all done 521 522_lev7intr: 523#ifdef PROFTIMER 524 addql #1,_intrcnt+36 525#else 526 addql #1,_intrcnt+32 527#endif 528 clrw sp@- | pad SR to longword 529 moveml #0xFFFF,sp@- | save registers 530 movl usp,a0 | and save 531 movl a0,sp@(60) | the user stack pointer 532 jbsr _nmihand | call handler 533 movl sp@(60),a0 | restore 534 movl a0,usp | user SP 535 moveml sp@+,#0x7FFF | and remaining registers 536 addql #6,sp | pop SSP and align word 537 jra rei | all done 538 539/* 540 * Emulation of VAX REI instruction. 541 * 542 * This code deals with checking for and servicing ASTs 543 * (profiling, scheduling) and software interrupts (network, softclock). 544 * We check for ASTs first, just like the VAX. To avoid excess overhead 545 * the T_AST handling code will also check for software interrupts so we 546 * do not have to do it here. 547 * 548 * This code is complicated by the fact that sendsig may have been called 549 * necessitating a stack cleanup. A cleanup should only be needed at this 550 * point for coprocessor mid-instruction frames (type 9), but we also test 551 * for bus error frames (type 10 and 11). 552 */ 553 .comm _ssir,1 554rei: 555#ifdef DEBUG 556 tstl _panicstr | have we paniced? 557 jne Ldorte | yes, do not make matters worse 558#endif 559 btst #PCB_ASTB,_u+PCB_FLAGS+1| AST pending? 560 jeq Lchksir | no, go check for SIR 561 btst #5,sp@ | yes, are we returning to user mode? 562 jne Lchksir | no, go check for SIR 563 clrw sp@- | pad SR to longword 564 moveml #0xFFFF,sp@- | save all registers 565 movl usp,a1 | including 566 movl a1,sp@(60) | the users SP 567 clrl sp@- | VA == none 568 clrl sp@- | code == none 569 movl #T_AST,sp@- | type == async system trap 570 jbsr _trap | go handle it 571 lea sp@(12),sp | pop value args 572 movl sp@(60),a0 | restore 573 movl a0,usp | user SP 574 moveml sp@+,#0x7FFF | and all remaining registers 575 addql #4,sp | toss SSP 576 tstw sp@+ | do we need to clean up stack? 577 jeq Ldorte | no, just continue 578 btst #7,sp@(6) | type 9/10/11 frame? 579 jeq Ldorte | no, nothing to do 580 btst #5,sp@(6) | type 9? 581 jne Last1 | no, skip 582 movw sp@,sp@(12) | yes, push down SR 583 movl sp@(2),sp@(14) | and PC 584 clrw sp@(18) | and mark as type 0 frame 585 lea sp@(12),sp | clean the excess 586 jra Ldorte | all done 587Last1: 588 btst #4,sp@(6) | type 10? 589 jne Last2 | no, skip 590 movw sp@,sp@(24) | yes, push down SR 591 movl sp@(2),sp@(26) | and PC 592 clrw sp@(30) | and mark as type 0 frame 593 lea sp@(24),sp | clean the excess 594 jra Ldorte | all done 595Last2: 596 movw sp@,sp@(84) | type 11, push down SR 597 movl sp@(2),sp@(86) | and PC 598 clrw sp@(90) | and mark as type 0 frame 599 lea sp@(84),sp | clean the excess 600 jra Ldorte | all done 601Lchksir: 602 tstb _ssir | SIR pending? 603 jeq Ldorte | no, all done 604 movl d0,sp@- | need a scratch register 605 movw sp@(4),d0 | get SR 606 andw #PSL_IPL7,d0 | mask all but IPL 607 jne Lnosir | came from interrupt, no can do 608 movl sp@+,d0 | restore scratch register 609Lgotsir: 610 movw #SPL1,sr | prevent others from servicing int 611 tstb _ssir | too late? 612 jeq Ldorte | yes, oh well... 613 clrw sp@- | pad SR to longword 614 moveml #0xFFFF,sp@- | save all registers 615 movl usp,a1 | including 616 movl a1,sp@(60) | the users SP 617 clrl sp@- | VA == none 618 clrl sp@- | code == none 619 movl #T_SSIR,sp@- | type == software interrupt 620 jbsr _trap | go handle it 621 lea sp@(12),sp | pop value args 622 movl sp@(60),a0 | restore 623 movl a0,usp | user SP 624 moveml sp@+,#0x7FFF | and all remaining registers 625 addql #6,sp | pop SSP and align word 626 rte 627Lnosir: 628 movl sp@+,d0 | restore scratch register 629Ldorte: 630 rte | real return 631 632/* 633 * System page table 634 * Mbmap, Usrptmap, and Usriomap are enlarged by CLSIZE entries 635 * as they are managed by resource maps starting with index 1 or CLSIZE. 636 * Usrptmap is allocated last so that we can also use the pad space up 637 * to eSysmap. (no point in wasting it!) 638 */ 639#define vaddr(x) x-_Sysmap/4*NBPG 640#define SYSMAP(mname,vname,size) \ 641 .globl _/**/mname,_/**/vname; \ 642_/**/mname: \ 643 .space size*4; \ 644 _/**/vname = vaddr(_/**/mname) 645#define ADDMAP(npte) .space npte*4 646 647 .data 648 SYSMAP(Sysmap ,Sysbase ,SYSPTSIZE ) 649 SYSMAP(Forkmap ,forkutl ,UPAGES ) 650 SYSMAP(Xswapmap ,xswaputl ,UPAGES ) 651 SYSMAP(Xswap2map,xswap2utl ,UPAGES ) 652 SYSMAP(Swapmap ,swaputl ,UPAGES ) 653 SYSMAP(Pushmap ,pushutl ,UPAGES ) 654 SYSMAP(Vfmap ,vfutl ,UPAGES ) 655 SYSMAP(CMAP1 ,CADDR1 ,1 ) 656 SYSMAP(CMAP2 ,CADDR2 ,1 ) 657 SYSMAP(mmap ,vmmap ,1 ) 658 SYSMAP(msgbufmap,msgbuf ,MSGBUFPTECNT ) 659 SYSMAP(Umap ,u ,UPAGES ) 660 SYSMAP(Mbmap ,mbutl ,NMBCLUSTERS*MCLBYTES/NBPG+CLSIZE ) 661 /* 662 * This is the map used by the kernel memory allocator. 663 * It is expanded as necessary by the special features 664 * that use it. 665 * 666 * XXX: NEED way to compute kmem size from maxusers, 667 * device complement 668 */ 669 SYSMAP(kmempt ,kmembase ,NKMEMCLUSTERS*CLSIZE ) 670#ifdef SYSVSHM 671 ADDMAP( SHMMAXPGS ) 672#endif 673#ifdef GPROF 674 ADDMAP( 768*1024/NBPG ) 675#endif 676 SYSMAP(ekmempt ,kmemlimit ,0 ) 677 SYSMAP(IOmap ,IObase ,IOMAPSIZE ) /* map DIO space */ 678 SYSMAP(eIOmap ,IOlimit ,0 ) 679#if defined(HP360) || defined(HP370) 680 SYSMAP(Grfmap ,grfregs ,1024 ) /* 340 @ SC132 */ 681#endif 682 SYSMAP(Usriomap ,usrio ,USRIOSIZE+CLSIZE ) /* for PHYSIO */ 683 SYSMAP(Usrptmap ,usrpt ,USRPTSIZE+CLSIZE ) 684 . = . + NBPG - 1 & -NBPG /* align to page boundry */ 685eSysmap: 686 687/* 688 * System segment table. 1 page is sufficient to map the entire 689 * 4Gb address space. (funny how that works out...) 690 */ 691 .globl _Sysseg 692_Sysseg: 693 .space NBPG 694eSysseg: 695 696 .globl _Syssize, _Usrptsize 697_Syssize = eSysmap-_Sysmap/4 698_Usrptsize = eSysmap-_Usrptmap/4 699 700/* 701 * Initialization 702 * 703 * A5 contains physical load point from boot 704 * VBR contains zero from ROM. Exceptions will continue to vector 705 * through ROM until MMU is turned on at which time they will vector 706 * through our table (vectors.s). 707 */ 708 .comm _lowram,4 709 710 .text 711 .globl _edata 712 .globl _etext,_end 713 .globl start 714start: 715 movw #PSL_HIGHIPL,sr | no interrupts 716 lea _lowram,a0 717 addl a5,a0 718 movl a5,a0@ | store start of physical memory 719 movl #CACHE_OFF,d0 720 movc d0,cacr | clear and disable on-chip cache(s) 721 722/* determine our CPU/MMU combo - check for all regardless of kernel config */ 723 movl #0x200,d0 | data freeze bit 724 movc d0,cacr | only exists on 68030 725 movc cacr,d0 | read it back 726 tstl d0 | zero? 727 jeq Lis68020 | yes, we have 68020 728 lea _mmutype,a0 | no, we have 68030 729 addl a5,a0 730 movl #-1,a0@ | set to reflect 68030 PMMU 731 lea _machineid,a0 732 addl a5,a0 733 movl #0x80,IOBASE+MMUCMD | set magic cookie 734 movl IOBASE+MMUCMD,d0 | read it back 735 btst #7,d0 | cookie still on? 736 jeq Lnot370 | no, 360 or 375 737 movl #0,IOBASE+MMUCMD | clear magic cookie 738 movl IOBASE+MMUCMD,d0 | read it back 739 btst #7,d0 | still on? 740 jeq Lisa370 | no, must be a 370 741 movl #5,a0@ | yes, must be a 340 742 jra Lstart1 743Lnot370: 744 movl #3,a0@ | type is at least a 360 745 movl #0,IOBASE+MMUCMD | clear magic cookie2 746 movl IOBASE+MMUCMD,d0 | read it back 747 btst #16,d0 | still on? 748 jeq Lstart1 | no, must be a 360 749 movl #6,a0@ | yes, must be a 345/375 750 jra Lhaspac 751Lisa370: 752 movl #4,a0@ | set to 370 753Lhaspac: 754 lea _ectype,a0 755 addl a5,a0 756 movl #-1,a0@ | also has a physical address cache 757 jra Lstart1 758Lis68020: 759 movl #1,IOBASE+MMUCMD | a 68020, write HP MMU location 760 movl IOBASE+MMUCMD,d0 | read it back 761 btst #0,d0 | non-zero? 762 jne Lishpmmu | yes, we have HP MMU 763 lea _mmutype,a0 764 addl a5,a0 765 movl #1,a0@ | no, we have PMMU 766 lea _machineid,a0 767 addl a5,a0 768 movl #1,a0@ | and 330 CPU 769 jra Lstart1 770Lishpmmu: 771 lea _ectype,a0 | 320 or 350 772 addl a5,a0 773 movl #1,a0@ | both have a virtual address cache 774 movl #0x80,IOBASE+MMUCMD | set magic cookie 775 movl IOBASE+MMUCMD,d0 | read it back 776 btst #7,d0 | cookie still on? 777 jeq Lstart1 | no, just a 320 778 lea _machineid,a0 779 addl a5,a0 780 movl #2,a0@ | yes, a 350 781 782Lstart1: 783 movl #0,IOBASE+MMUCMD | clear out MMU again 784/* initialize source/destination control registers for movs */ 785 moveq #FC_USERD,d0 | user space 786 movc d0,sfc | as source 787 movc d0,dfc | and destination of transfers 788/* initialize proc. 0 (system) page table */ 789 movl #_Sysmap,a0 | SYSPT map addr 790 addl a5,a0 | relocate 791/* text pages are read-only */ 792 clrl d0 | assume load at VA 0 793 movl a5,d1 | get load PA 794 andl #PG_FRAME,d1 | convert to a page frame 795 orl #PG_RO+PG_V,d1 | mark as valid and RO 796 movl #_etext,a1 | go til end of text 797Lispt1: 798 movl d1,a0@+ | load PTE 799 addl #NBPG,d1 | increment page frame number 800 addl #NBPG,d0 | and address counter 801 cmpl a1,d0 | done yet? 802 jcs Lispt1 | no, keep going 803/* data and bss are read/write */ 804 andl #PG_FRAME,d1 | mask out old prot bits 805 orl #PG_RW+PG_V,d1 | mark as valid and RW 806 movl #_end,a1 | go til end of data/bss 807Lispt2: 808 movl d1,a0@+ | load PTE 809 addl #NBPG,d1 | increment page frame number 810 addl #NBPG,d0 | and address counter 811 cmpl a1,d0 | done yet? 812 jcs Lispt2 | no, keep going 813/* invalidate remainder of system page table */ 814 movl #eSysmap,a1 | end of map 815 addl a5,a1 | relocate 816Lispt3: 817 movl #PG_NV,a0@+ | invalidate PTE 818 cmpl a1,a0 | done yet? 819 jcs Lispt3 | no, keep going 820/* go back and initialize IOmap */ 821 movl #_IOmap,a0 | IO map addr 822 addl a5,a0 | relocate 823 movl #_eIOmap,a1 | end of map 824 addl a5,a1 | relocate 825 movl #IOBASE,d1 | physical IO base 826 andl #PG_FRAME,d1 | mask to frame number 827 orl #PG_RW+PG_CI+PG_V,d1 | mark valid, RW and CI 828Lispt4: 829 movl d1,a0@+ | load PTE 830 addl #NBPG,d1 | increment page frame number 831 cmpl a1,a0 | done yet? 832 jcs Lispt4 | no, keep going 833/* initialize proc. 0 (system) segment table */ 834 movl #_Sysseg,a0 | segment table 835 addl a5,a0 | relocate 836 movl #eSysmap-_Sysmap/NBPG*4,a1 | bytes of PTEs for Sysmap 837 addl a0,a1 | make an end count 838 movl #_Sysmap,d1 | system PT addr 839 addl a5,d1 | relocate 840 andl #SG_FRAME,d1 | mask to frame number 841 orl #SG_RW+SG_V,d1 | mark as RW and valid 842Lispt5: 843 movl d1,a0@+ | load STE 844 addl #NBPG,d1 | increment page frame number 845 cmpl a1,a0 | done yet? 846 jcs Lispt5 | no, keep going 847/* invalidate the unused part */ 848 movl #eSysseg,a1 | end of segment table 849 addl a5,a1 | relocate 850Lispt6: 851 movl #SG_NV,a0@+ | invalidate STE 852 cmpl a1,a0 | done yet? 853 jcs Lispt6 | no, keep going 854 855/* 856 * Setup page table for process 0. 857 * 858 * We set up page table access for the kernel via Usrptmap (usrpt) 859 * and access to the u-area itself via Umap (u). First page beyond 860 * kernel BSS (d0) is used for proc0 page table. Next UPAGES pages 861 * following are for u-area. 862 */ 863 addl a5,d0 | relocate PT address 864 movl d0,d1 865 andl #PG_FRAME,d1 | mask to page frame number 866 orl #PG_RW+PG_V,d1 | RW and valid 867 movl #_Usrptmap,a1 | get PT map address 868 addl a5,a1 | relocate 869 movl d1,a1@ | validate PTE for proc0 PT 870 movl d0,a0 | base of proc0 PT 871 addl #NBPG,d0 | plus one page yields 872 movl d0,a2 | base of u-area 873/* invalidate entire page table */ 874Liudot1: 875 movl #PG_NV,a0@+ | invalidate PTE 876 cmpl a2,a0 | done yet? 877 jcs Liudot1 | no, keep going 878/* now go back and validate u-area PTEs */ 879 subl #HIGHPAGES*4,a0 | base of PTEs for u-area (p_addr) 880 movl a0,a1 881 addl #UPAGES*4,a1 | end of PTEs for u-area 882 movl d0,d1 | get base of u-area 883 andl #PG_FRAME,d1 | mask to page frame number 884 orl #PG_RW+PG_V,d1 | add valid and writable 885 movl #_Umap,a3 | address of u 886 addl a5,a3 | relocate 887Liudot2: 888 movl d1,a0@+ | validate p_addr PTE 889 movl d1,a3@+ | validate u PTE 890 addl #NBPG,d1 | to next page 891 cmpl a1,a0 | done yet? 892 jcs Liudot2 | no, keep going 893/* clear process 0 u-area */ 894 addl #NBPG*UPAGES,d0 | end of u-area 895Lclru1: 896 clrl a2@+ | clear 897 cmpl d0,a2 | done yet? 898 jcs Lclru1 | no, keep going 899 movl a2,a4 | save addr of first avail page 900 901/* 902 * Prepare to enable MMU. 903 * Since the kernel is not mapped logical == physical we must insure 904 * that when the MMU is turned on, all prefetched addresses (including 905 * the PC) are valid. In order guarentee that, we map the last page of 906 * memory logical == physical and load up that page with enough code to 907 * defeat the prefetch, then we execute the jump back to here. 908 * 909 * Is this all really necessary, or am I paranoid?? 910 */ 911 movl #_Sysseg,d1 | system segment table addr 912 addl a5,d1 | relocate 913 lea _mmutype,a0 914 addl a5,a0 915 tstl a0@ | HP MMU? 916 jeq Lhpmmu2 | yes, skip 917 lea _protorp,a0 918 addl a5,a0 919 movl #0x80000202,a0@ | nolimit + share global + 4 byte PTEs 920 movl d1,a0@(4) | + segtable address 921 .long 0xf0104800 | pmove a0@,srp 922 movl #0x80000002,a0@ | reinit upper half for CRP loads 923 jra Lstploaddone | done 924Lhpmmu2: 925 moveq #PGSHIFT,d2 926 lsrl d2,d1 | convert to page frame 927 movl d1,IOBASE+MMUSSTP | load in sysseg table register 928Lstploaddone: 929 movl #eSysseg-4,a1 | last entry in sysseg table 930 addl a5,a1 | relocate 931 movl d0,d1 | use page after proc0 u for tmp PT 932 andl #SG_FRAME,d1 | mask to page frame 933 orl #SG_RW+SG_V,d1 | mark valid and writable 934 movl d1,a1@ | load in segment table 935 movl d0,a1 | page table address 936 addl #NBPG-4,a1 | move to last entry 937 movl #MAXADDR,d1 | address of last page of memory 938 movl d1,a2 939 andl #PG_FRAME,d1 | mask to page frame 940 orl #PG_RW+PG_V,d1 | mark valid and writable 941 movl d1,a1@ | store PTE in table 942 movl #Lhighcode,a1 | addr of high code 943 addl a5,a1 | relocate 944 movl #Lehighcode,a3 | end addr 945 addl a5,a3 | relocate 946Lcodecopy: 947 movw a1@+,a2@+ | copy a word 948 cmpl a3,a1 | done yet? 949 jcs Lcodecopy | no, keep going 950 jmp MAXADDR | go for it! 951 952Lhighcode: 953 lea _mmutype,a0 954 addl a5,a0 955 tstl a0@ | HP MMU? 956 jeq Lhpmmu3 | yes, skip 957 movl #MMU_IEN+MMU_FPE,IOBASE+MMUCMD | enable 68881 and i-cache 958 movl #0x82c0aa00,a2@ | value to load TC with 959 .long 0xf0124000 | pmove a2@,tc 960 jmp Lenab1 961Lhpmmu3: 962 movl #0,IOBASE+MMUCMD | clear external cache 963 movl #MMU_ENAB,IOBASE+MMUCMD | turn on MMU 964 jmp Lenab1 | jmp to mapped code 965Lehighcode: 966 967/* 968 * Should be running mapped from this point on 969 */ 970Lenab1: 971/* while the ROM scratch page is mapped, check for internal HP-IB in SYSFLAG */ 972 btst #5,0xfffffed2 | internal HP-IB? 973 jeq Linitmem | yes, have HP-IB continue normally 974 clrl _internalhpib | no, clear associated address 975/* init mem sizes */ 976Linitmem: 977 movl #MAXADDR,d1 | last page 978 moveq #PGSHIFT,d2 979 lsrl d2,d1 | convert to page (click) number 980 movl d1,_maxmem | save as maxmem 981 movl _lowram,d0 | lowram value from ROM via boot 982 lsrl d2,d0 | convert to page number 983 subl d0,d1 | compute amount of RAM present 984 movl d1,_freemem | save as freemem 985 movl d1,_physmem | and physmem 986/* initialize (slightly) the pcb */ 987 movl #_u,a1 | proc0 u-area 988 movl a1,sp 989 addl #UPAGES*NBPG-4,sp | set kernel stack to end of u-area 990 movl #USRSTACK-4,a2 991 movl a2,usp | init user SP 992 movl #_usrpt,a1@(PCB_P0BR) | p0br: SVA of text/data user PT 993 clrl a1@(PCB_P0LR) | p0lr: 0 (does not really exist) 994 movl #_usrpt+NBPG,d0 | addr of end of PT 995 subl #P1PAGES*4,d0 | backup size of P1 region 996 movl d0,a1@(PCB_P1BR) | p1br: P1PAGES from end of PT 997 movl #P1PAGES-HIGHPAGES,a1@(PCB_P1LR) | p1lr: vax style 998 movl #CLSIZE,a1@(PCB_SZPT) | page table size 999 clrw a1@(PCB_FLAGS) | clear flags 1000#ifdef FPCOPROC 1001 clrl a1@(PCB_FPCTX) | ensure null FP context 1002 movl a1,sp@- 1003 jbsr _m68881_restore | restore it (does not kill a1) 1004 addql #4,sp 1005#endif 1006 addl #PCB_SIGC,a1 | address of proc0 sig trampoline code 1007 movl #Lsigcode,a2 | address of sig trampoline proto 1008Lsigc: 1009 movw a2@+,a1@+ | copy 1010 cmpl #Lesigcode,a2 | done yet? 1011 jcs Lsigc | no, keep going 1012/* flush TLB and turn on caches */ 1013 movl #PG_NV,eSysseg-4 | invalidate last page 1014 jbsr _TBIA | invalidate TLB 1015 movl #CACHE_ON,d0 1016 movc d0,cacr | clear cache(s) 1017 tstl _ectype 1018 jeq Lnocache0 1019 orl #MMU_CEN,_IObase+MMUCMD | turn on external cache 1020Lnocache0: 1021/* final setup for C code */ 1022 movw #PSL_LOWIPL,sr | lower SPL 1023 movl d7,_boothowto | save reboot flags 1024 movl d6,_bootdev | and boot device 1025 movl a4,d1 | addr of first available RAM 1026 moveq #PGSHIFT,d2 1027 lsrl d2,d1 | convert to click 1028 movl d1,sp@- | param to main 1029 jbsr _main | main(firstaddr) 1030 addql #4,sp 1031/* proc[1] == init now running here; 1032 * create a null exception frame and return to user mode in icode 1033 */ 1034 clrw sp@- | vector offset/frame type 1035 clrl sp@- | return to icode location 0 1036 movw #PSL_USER,sp@- | in user mode 1037 rte 1038 1039/* 1040 * Signal "trampoline" code (18 bytes). Invoked from RTE setup by sendsig(). 1041 * 1042 * Stack looks like: 1043 * 1044 * sp+0 -> signal number 1045 * sp+4 signal specific code 1046 * sp+8 pointer to signal context frame (scp) 1047 * sp+12 address of handler 1048 * sp+16 saved hardware state 1049 * . 1050 * . 1051 * scp+0-> beginning of signal context frame 1052 */ 1053Lsigcode: 1054 movl sp@(12),a0 | signal handler addr (4 bytes) 1055 jsr a0@ | call signal handler (2 bytes) 1056 addql #4,sp | pop signo (2 bytes) 1057 trap #1 | special syscall entry (2 bytes) 1058 movl d0,sp@(4) | save errno (4 bytes) 1059 moveq #1,d0 | syscall == exit (2 bytes) 1060 trap #0 | exit(errno) (2 bytes) 1061Lesigcode: 1062 1063/* 1064 * Icode is copied out to process 1 to exec init. 1065 * If the exec fails, process 1 exits. 1066 */ 1067 argv1 = argv-_icode 1068 init1 = init-_icode 1069 .globl _icode,_initflags,_szicode 1070_icode: 1071 movl #argv1,sp@- 1072 movl #init1,sp@- 1073 clrl sp@- 1074 moveq #SYS_execv,d0 1075 trap #0 1076 moveq #SYS_exit,d0 1077 trap #0 1078 1079init: 1080 .asciz "/sbin/init" 1081 .even 1082_initflags: 1083 .long 0 1084argv: 1085 .long init+6-_icode 1086 .long _initflags-_icode 1087 .long 0 1088_szicode: 1089 .long _szicode-_icode 1090 1091/* 1092 * Primitives 1093 */ 1094 1095#ifdef GPROF 1096#ifdef __GNUC__ 1097#define ENTRY(name) \ 1098 .globl _/**/name; _/**/name: link a6,#0; jbsr mcount; unlk a6 1099#define ALTENTRY(name, rname) \ 1100 ENTRY(name); jra rname+12 1101#else 1102#define ENTRY(name) \ 1103 .globl _/**/name; _/**/name: jbsr mcount 1104#define ALTENTRY(name, rname) \ 1105 ENTRY(name); jra rname+6 1106#endif 1107#else 1108#define ENTRY(name) \ 1109 .globl _/**/name; _/**/name: 1110#define ALTENTRY(name, rname) \ 1111 .globl _/**/name; _/**/name: 1112#endif 1113 1114/* 1115 * update profiling information for the user 1116 * addupc(pc, &u.u_prof, ticks) 1117 */ 1118ENTRY(addupc) 1119 movl a2,sp@- | scratch register 1120 movl sp@(12),a2 | get &u.u_prof 1121 movl sp@(8),d0 | get user pc 1122 subl a2@(8),d0 | pc -= pr->pr_off 1123 jlt Lauexit | less than 0, skip it 1124 movl a2@(12),d1 | get pr->pr_scale 1125 lsrl #1,d0 | pc /= 2 1126 lsrl #1,d1 | scale /= 2 1127 mulul d1,d0 | pc /= scale 1128 moveq #14,d1 1129 lsrl d1,d0 | pc >>= 14 1130 bclr #0,d0 | pc &= ~1 1131 cmpl a2@(4),d0 | too big for buffer? 1132 jge Lauexit | yes, screw it 1133 addl a2@,d0 | no, add base 1134 movl d0,sp@- | push address 1135 jbsr _fusword | grab old value 1136 movl sp@+,a0 | grab address back 1137 cmpl #-1,d0 | access ok 1138 jeq Lauerror | no, skip out 1139 addw sp@(18),d0 | add tick to current value 1140 movl d0,sp@- | push value 1141 movl a0,sp@- | push address 1142 jbsr _susword | write back new value 1143 addql #8,sp | pop params 1144 tstl d0 | fault? 1145 jeq Lauexit | no, all done 1146Lauerror: 1147 clrl a2@(12) | clear scale (turn off prof) 1148Lauexit: 1149 movl sp@+,a2 | restore scratch reg 1150 rts 1151 1152/* 1153 * copyinstr(fromaddr, toaddr, maxlength, &lencopied) 1154 * 1155 * Copy a null terminated string from the user address space into 1156 * the kernel address space. 1157 * NOTE: maxlength must be < 64K 1158 */ 1159ENTRY(copyinstr) 1160 movl sp@(4),a0 | a0 = fromaddr 1161 movl sp@(8),a1 | a1 = toaddr 1162 moveq #0,d0 1163 movw sp@(14),d0 | d0 = maxlength 1164 jlt Lcisflt1 | negative count, error 1165 jeq Lcisdone | zero count, all done 1166 movl #Lcisflt1,_u+PCB_ONFAULT | set up to catch faults 1167 subql #1,d0 | set up for dbeq 1168Lcisloop: 1169 movsb a0@+,d1 | grab a byte 1170 movb d1,a1@+ | copy it 1171 dbeq d0,Lcisloop | if !null and more, continue 1172 jne Lcisflt2 | ran out of room, error 1173 moveq #0,d0 | got a null, all done 1174Lcisdone: 1175 tstl sp@(16) | return length desired? 1176 jeq Lcisret | no, just return 1177 subl sp@(4),a0 | determine how much was copied 1178 movl sp@(16),a1 | return location 1179 movl a0,a1@ | stash it 1180Lcisret: 1181 clrl _u+PCB_ONFAULT | clear fault addr 1182 rts 1183Lcisflt1: 1184 moveq #EFAULT,d0 | copy fault 1185 jra Lcisdone 1186Lcisflt2: 1187 moveq #ENOENT,d0 | ran out of space 1188 jra Lcisdone 1189 1190/* 1191 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied) 1192 * 1193 * Copy a null terminated string from the kernel 1194 * address space to the user address space. 1195 * NOTE: maxlength must be < 64K 1196 */ 1197ENTRY(copyoutstr) 1198 movl sp@(4),a0 | a0 = fromaddr 1199 movl sp@(8),a1 | a1 = toaddr 1200 moveq #0,d0 1201 movw sp@(14),d0 | d0 = maxlength 1202 jlt Lcosflt1 | negative count, error 1203 jeq Lcosdone | zero count, all done 1204 movl #Lcosflt1,_u+PCB_ONFAULT| set up to catch faults 1205 subql #1,d0 | set up for dbeq 1206Lcosloop: 1207 movb a0@+,d1 | grab a byte 1208 movsb d1,a1@+ | copy it 1209 dbeq d0,Lcosloop | if !null and more, continue 1210 jne Lcosflt2 | ran out of room, error 1211 moveq #0,d0 | got a null, all done 1212Lcosdone: 1213 tstl sp@(16) | return length desired? 1214 jeq Lcosret | no, just return 1215 subl sp@(4),a0 | determine how much was copied 1216 movl sp@(16),a1 | return location 1217 movl a0,a1@ | stash it 1218Lcosret: 1219 clrl _u+PCB_ONFAULT | clear fault addr 1220 rts 1221Lcosflt1: 1222 moveq #EFAULT,d0 | copy fault 1223 jra Lcosdone 1224Lcosflt2: 1225 moveq #ENOENT,d0 | ran out of space 1226 jra Lcosdone 1227 1228/* 1229 * copystr(fromaddr, toaddr, maxlength, &lencopied) 1230 * 1231 * Copy a null terminated string from one point to another in 1232 * the kernel address space. 1233 * NOTE: maxlength must be < 64K 1234 */ 1235ENTRY(copystr) 1236 movl sp@(4),a0 | a0 = fromaddr 1237 movl sp@(8),a1 | a1 = toaddr 1238 moveq #0,d0 1239 movw sp@(14),d0 | d0 = maxlength 1240 jlt Lcsflt1 | negative count, error 1241 jeq Lcsdone | zero count, all done 1242 movl #Lcsflt1,_u+PCB_ONFAULT | set up to catch faults 1243 subql #1,d0 | set up for dbeq 1244Lcsloop: 1245 movb a0@+,a1@+ | copy a byte 1246 dbeq d0,Lcsloop | if !null and more, continue 1247 jne Lcsflt2 | ran out of room, error 1248 moveq #0,d0 | got a null, all done 1249Lcsdone: 1250 tstl sp@(16) | return length desired? 1251 jeq Lcsret | no, just return 1252 subl sp@(4),a0 | determine how much was copied 1253 movl sp@(16),a1 | return location 1254 movl a0,a1@ | stash it 1255Lcsret: 1256 clrl _u+PCB_ONFAULT | clear fault addr 1257 rts 1258Lcsflt1: 1259 moveq #EFAULT,d0 | copy fault 1260 jra Lcsdone 1261Lcsflt2: 1262 moveq #ENOENT,d0 | ran out of space 1263 jra Lcsdone 1264 1265/* 1266 * Copyin(from, to, len) 1267 * 1268 * Copy specified amount of data from user space into the kernel. 1269 * NOTE: len must be < 64K 1270 */ 1271ENTRY(copyin) 1272 movl d2,sp@- | scratch register 1273 movl #Lciflt,_u+PCB_ONFAULT | catch faults 1274 movl sp@(16),d2 | check count 1275 jlt Lciflt | negative, error 1276 jeq Lcidone | zero, done 1277 movl sp@(8),a0 | src address 1278 movl sp@(12),a1 | dest address 1279 movl a0,d0 1280 btst #0,d0 | src address odd? 1281 jeq Lcieven | no, go check dest 1282 movsb a0@+,d1 | yes, get a byte 1283 movb d1,a1@+ | put a byte 1284 subql #1,d2 | adjust count 1285 jeq Lcidone | exit if done 1286Lcieven: 1287 movl a1,d0 1288 btst #0,d0 | dest address odd? 1289 jne Lcibyte | yes, must copy by bytes 1290 movl d2,d0 | no, get count 1291 lsrl #2,d0 | convert to longwords 1292 jeq Lcibyte | no longwords, copy bytes 1293 subql #1,d0 | set up for dbf 1294Lcilloop: 1295 movsl a0@+,d1 | get a long 1296 movl d1,a1@+ | put a long 1297 dbf d0,Lcilloop | til done 1298 andl #3,d2 | what remains 1299 jeq Lcidone | all done 1300Lcibyte: 1301 subql #1,d2 | set up for dbf 1302Lcibloop: 1303 movsb a0@+,d1 | get a byte 1304 movb d1,a1@+ | put a byte 1305 dbf d2,Lcibloop | til done 1306Lcidone: 1307 moveq #0,d0 | success 1308Lciexit: 1309 clrl _u+PCB_ONFAULT | reset fault catcher 1310 movl sp@+,d2 | restore scratch reg 1311 rts 1312Lciflt: 1313 moveq #EFAULT,d0 | got a fault 1314 jra Lciexit 1315 1316/* 1317 * Copyout(from, to, len) 1318 * 1319 * Copy specified amount of data from kernel to the user space 1320 * NOTE: len must be < 64K 1321 */ 1322ENTRY(copyout) 1323 movl d2,sp@- | scratch register 1324 movl #Lcoflt,_u+PCB_ONFAULT | catch faults 1325 movl sp@(16),d2 | check count 1326 jlt Lcoflt | negative, error 1327 jeq Lcodone | zero, done 1328 movl sp@(8),a0 | src address 1329 movl sp@(12),a1 | dest address 1330 movl a0,d0 1331 btst #0,d0 | src address odd? 1332 jeq Lcoeven | no, go check dest 1333 movb a0@+,d1 | yes, get a byte 1334 movsb d1,a1@+ | put a byte 1335 subql #1,d2 | adjust count 1336 jeq Lcodone | exit if done 1337Lcoeven: 1338 movl a1,d0 1339 btst #0,d0 | dest address odd? 1340 jne Lcobyte | yes, must copy by bytes 1341 movl d2,d0 | no, get count 1342 lsrl #2,d0 | convert to longwords 1343 jeq Lcobyte | no longwords, copy bytes 1344 subql #1,d0 | set up for dbf 1345Lcolloop: 1346 movl a0@+,d1 | get a long 1347 movsl d1,a1@+ | put a long 1348 dbf d0,Lcolloop | til done 1349 andl #3,d2 | what remains 1350 jeq Lcodone | all done 1351Lcobyte: 1352 subql #1,d2 | set up for dbf 1353Lcobloop: 1354 movb a0@+,d1 | get a byte 1355 movsb d1,a1@+ | put a byte 1356 dbf d2,Lcobloop | til done 1357Lcodone: 1358 moveq #0,d0 | success 1359Lcoexit: 1360 clrl _u+PCB_ONFAULT | reset fault catcher 1361 movl sp@+,d2 | restore scratch reg 1362 rts 1363Lcoflt: 1364 moveq #EFAULT,d0 | got a fault 1365 jra Lcoexit 1366 1367/* 1368 * non-local gotos 1369 */ 1370ALTENTRY(savectx, _setjmp) 1371ENTRY(setjmp) 1372 movl sp@(4),a0 | savearea pointer 1373 moveml #0xFCFC,a0@ | save d2-d7/a2-a7 1374 movl sp@,a0@(48) | and return address 1375 moveq #0,d0 | return 0 1376 rts 1377 1378ENTRY(qsetjmp) 1379 movl sp@(4),a0 | savearea pointer 1380 lea a0@(40),a0 | skip regs we do not save 1381 movl a6,a0@+ | save FP 1382 movl sp,a0@+ | save SP 1383 movl sp@,a0@ | and return address 1384 moveq #0,d0 | return 0 1385 rts 1386 1387ENTRY(longjmp) 1388 movl sp@(4),a0 1389 moveml a0@+,#0xFCFC 1390 movl a0@,sp@ 1391 moveq #1,d0 1392 rts 1393 1394/* 1395 * The following primitives manipulate the run queues. 1396 * _whichqs tells which of the 32 queues _qs 1397 * have processes in them. Setrq puts processes into queues, Remrq 1398 * removes them from queues. The running process is on no queue, 1399 * other processes are on a queue related to p->p_pri, divided by 4 1400 * actually to shrink the 0-127 range of priorities into the 32 available 1401 * queues. 1402 */ 1403 1404 .globl _whichqs,_qs,_cnt,_panic 1405 .comm _noproc,4 1406 .comm _runrun,4 1407 1408/* 1409 * Setrq(p) 1410 * 1411 * Call should be made at spl6(), and p->p_stat should be SRUN 1412 */ 1413ENTRY(setrq) 1414 movl sp@(4),a0 1415 tstl a0@(P_RLINK) 1416 jeq Lset1 1417 movl #Lset2,sp@- 1418 jbsr _panic 1419Lset1: 1420 clrl d0 1421 movb a0@(P_PRI),d0 1422 lsrb #2,d0 1423 movl _whichqs,d1 1424 bset d0,d1 1425 movl d1,_whichqs 1426 lslb #3,d0 1427 addl #_qs,d0 1428 movl d0,a0@(P_LINK) 1429 movl d0,a1 1430 movl a1@(P_RLINK),a0@(P_RLINK) 1431 movl a0,a1@(P_RLINK) 1432 movl a0@(P_RLINK),a1 1433 movl a0,a1@(P_LINK) 1434 rts 1435 1436Lset2: 1437 .asciz "setrq" 1438 .even 1439 1440/* 1441 * Remrq(p) 1442 * 1443 * Call should be made at spl6(). 1444 */ 1445ENTRY(remrq) 1446 movl sp@(4),a0 1447 clrl d0 1448 movb a0@(P_PRI),d0 1449 lsrb #2,d0 1450 movl _whichqs,d1 1451 bclr d0,d1 1452 jne Lrem1 1453 movl #Lrem3,sp@- 1454 jbsr _panic 1455Lrem1: 1456 movl d1,_whichqs 1457 movl a0@(P_LINK),a1 1458 movl a0@(P_RLINK),a1@(P_RLINK) 1459 movl a0@(P_RLINK),a1 1460 movl a0@(P_LINK),a1@(P_LINK) 1461 movl #_qs,a1 1462 movl d0,d1 1463 lslb #3,d1 1464 addl d1,a1 1465 cmpl a1@(P_LINK),a1 1466 jeq Lrem2 1467 movl _whichqs,d1 1468 bset d0,d1 1469 movl d1,_whichqs 1470Lrem2: 1471 clrl a0@(P_RLINK) 1472 rts 1473 1474Lrem3: 1475 .asciz "remrq" 1476Lsw0: 1477 .asciz "swtch" 1478 .even 1479 1480/* 1481 * When no processes are on the runq, Swtch branches to idle 1482 * to wait for something to come ready. 1483 */ 1484 .globl Idle 1485Idle: 1486idle: 1487 movw #PSL_LOWIPL,sr 1488 tstl _whichqs 1489 jne Lsw1 1490 stop #PSL_LOWIPL 1491 jra idle 1492 1493Lbadsw: 1494 movl #Lsw0,sp@- 1495 jbsr _panic 1496 /*NOTREACHED*/ 1497 1498/* 1499 * Swtch() 1500 */ 1501ENTRY(swtch) 1502 movw sr,_u+PCB_PS 1503 movl #1,_noproc 1504 addql #1,_cnt+V_SWTCH 1505Lsw1: 1506 clrl d0 1507 movl _whichqs,d1 1508Lswchk: 1509 btst d0,d1 1510 jne Lswfnd 1511 addqb #1,d0 1512 cmpb #32,d0 1513 jne Lswchk 1514 jra idle 1515Lswfnd: 1516 movw #PSL_HIGHIPL,sr 1517 movl _whichqs,d1 1518 bclr d0,d1 1519 jeq Lsw1 1520 movl d1,_whichqs 1521 movl d0,d1 1522 lslb #3,d1 1523 addl #_qs,d1 1524 movl d1,a1 1525 cmpl a1@(P_LINK),a1 1526 jeq Lbadsw 1527 movl a1@(P_LINK),a0 1528 movl a0@(P_LINK),a1@(P_LINK) 1529 movl a0@(P_LINK),a1 1530 movl a0@(P_RLINK),a1@(P_RLINK) 1531 cmpl a0@(P_LINK),d1 1532 jeq Lsw2 1533 movl _whichqs,d1 1534 bset d0,d1 1535 movl d1,_whichqs 1536Lsw2: 1537 clrl _noproc 1538 clrl _runrun 1539 tstl a0@(P_WCHAN) 1540 jne Lbadsw 1541 cmpb #SRUN,a0@(P_STAT) 1542 jne Lbadsw 1543 clrl a0@(P_RLINK) 1544 movl a0@(P_ADDR),d0 1545 jra Lres0 1546 1547/* 1548 * Resume(p_addr) 1549 * 1550 * NOTE: on the PMMU we attempt to avoid flushing the entire TAC. 1551 * The effort involved in selective flushing may not be worth it, 1552 * maybe we should just flush the whole thing? 1553 */ 1554ENTRY(resume) 1555 movw sr,_u+PCB_PS 1556 movl sp@(4),d0 1557Lres0: 1558 lea _u,a1 | &u 1559 movl usp,a0 | grab USP 1560 movl a0,a1@(PCB_USP) | and save it 1561 moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers 1562#ifdef FPCOPROC 1563 lea a1@(PCB_FPCTX),a0 | pointer to FP save area 1564 .word 0xf310 | fsave a0@ 1565 tstb a0@ | null state frame? 1566 jeq Lresnofpsave | yes, all done 1567 .word 0xf228,0xf0ff,0x00d8 | fmovem fp0-fp7,a0@(216) 1568 .word 0xf228,0xbc00,0x0138 | fmovem fpcr/fpsr/fpiar,a0@(312) 1569Lresnofpsave: 1570#endif 1571#ifdef PROFTIMER 1572 movw #SPL6,sr | protect against clock interrupts 1573 bclr #0,_profon | clear user profiling bit, was set? 1574 jeq Lskipoff | no, clock off or doing kernel only 1575#ifdef GPROF 1576 tstb _profon | kernel profiling also enabled? 1577 jlt Lskipoff | yes, nothing more to do 1578#endif 1579 movb #0,_IObase+CLKCR2 | no, just user, select CR3 1580 movb #0,_IObase+CLKCR3 | and turn it off 1581Lskipoff: 1582#endif 1583 movl _CMAP2,a1@(PCB_CMAP2) | save temporary map PTE 1584 movw #PSL_HIGHIPL,sr | go crit while changing PTEs 1585 lea tmpstk,sp | now goto a tmp stack for NMI 1586 movl d0,a0 | address of new context 1587 lea _Umap,a1 | address of PTEs for u 1588 moveq #UPAGES-1,d0 | sizeof u 1589Lres1: 1590 movl a0@+,d1 | get PTE 1591 andl #~PG_PROT,d1 | mask out old protection 1592 orl #PG_RW+PG_V,d1 | ensure valid and writable 1593 movl d1,a1@+ | load it up 1594 dbf d0,Lres1 | til done 1595 lea _u,a1 | reload &u 1596 movl #CACHE_CLR,d0 1597 movc d0,cacr | invalidate cache(s) 1598#if defined(HP330) || defined(HP360) || defined(HP370) 1599 tstl _mmutype | HP MMU? 1600 jeq Lhpmmu4 | yes, skip 1601 jmi Lnot68851a | must flush all on 68030 MMU 1602#ifdef DEBUG 1603 tstl fullflush | 68851, conservative? 1604 jne Lnot68851a | yes, go flush all 1605#endif 1606 .long 0xf0003494 | no, pflushs #4,#4 (flush super side) 1607 jra Lres2 1608Lnot68851a: 1609 .long 0xf0002400 | pflusha 1610Lres2: 1611 movl a1@(PCB_USTP),d0 | get USTP 1612 moveq #PGSHIFT,d1 1613 lsll d1,d0 | convert to addr 1614 lea _protorp,a0 | CRP prototype 1615 movl d0,a0@(4) | stash USTP 1616 .long 0xf0104C00 | pmove a0@,crp 1617 jra Lcxswdone | thats it 1618Lhpmmu4: 1619#endif 1620#if defined(HP320) || defined(HP350) 1621 movl _IObase+MMUTBINVAL,d1 | invalidate TLB 1622 tstl _ectype | got external VAC? 1623 jle Lnocache1 | no, skip 1624 movl #_IObase+MMUCMD,a0 | addr of MMU command register 1625 andl #~MMU_CEN,a0@ | toggle cache enable 1626 orl #MMU_CEN,a0@ | to clear data cache 1627Lnocache1: 1628 movl a1@(PCB_USTP),_IObase+MMUUSTP | context switch 1629#endif 1630Lcxswdone: 1631 movl a1@(U_PROCP),a0 | u.u_procp 1632 bclr #SPTECHGB-24,a0@(P_FLAG)| clear SPTECHG bit 1633#if defined(HP330) 1634 jeq Lnot68851b | if set need to flush user TLB 1635 tstl _mmutype | 68851 PMMU? 1636 jle Lnot68851b | no, skip 1637 .long 0xf0003490 | pflushs #0,#4 1638Lnot68851b: 1639#endif 1640 movl a1@(PCB_CMAP2),_CMAP2 | reload tmp map 1641 moveml a1@(PCB_REGS),#0xFCFC | and registers 1642 movl a1@(PCB_USP),a0 1643 movl a0,usp | and USP 1644#ifdef PROFTIMER 1645 tstl a1@(U_PROFSCALE) | process being profiled? 1646 jeq Lskipon | no, do nothing 1647 orb #1,_profon | turn on user profiling bit 1648#ifdef GPROF 1649 jlt Lskipon | already profiling kernel, all done 1650#endif 1651 lea _IObase+CLKMSB3,a0 | address timer 3 counter 1652 movl _profint,d1 | profiling interval 1653 subql #1,d1 | adjusted 1654 movepw d1,a0@(0) | set interval 1655 movb #0,_IObase+CLKCR2 | select CR3 1656 movb #64,_IObase+CLKCR3 | turn it on 1657Lskipon: 1658#endif 1659#ifdef FPCOPROC 1660 lea a1@(PCB_FPCTX),a0 | pointer to FP save area 1661 tstb a0@ | null state frame? 1662 jeq Lresfprest | yes, easy 1663 .word 0xf228,0x9c00,0x0138 | fmovem a0@(312),fpcr/fpsr/fpiar 1664 .word 0xf228,0xd0ff,0x00d8 | fmovem a0@(216),fp0-fp7 1665Lresfprest: 1666 .word 0xf350 | frestore a0@ 1667#endif 1668 tstl a1@(PCB_SSWAP) | do an alternate return? 1669 jne Lres3 | yes, go reload regs 1670 movw a1@(PCB_PS),sr | no, restore PS 1671 rts 1672Lres3: 1673 movl a1@(PCB_SSWAP),a0 | addr of saved context 1674 clrl a1@(PCB_SSWAP) | clear flag 1675 moveml a0@+,#0x7CFC | restore registers 1676 movl a0@+,a1 | and SP 1677 cmpl sp,a1 | paranoia... 1678 jge Lres4 | ...must be popping, yes? 1679 lea tmpstk,sp | no! set up a legit stack 1680 movl #Lres5,sp@- | push a panic message 1681 jbsr _panic | and panic 1682 /* NOTREACHED */ 1683Lres4: 1684 movl a1,sp | restore SP 1685 movl a0@,sp@ | and PC 1686 moveq #1,d0 | arrange for non-zero return 1687 movw #PSL_LOWIPL,sr | lower SPL 1688 rts 1689 1690Lres5: 1691 .asciz "ldctx" 1692 .even 1693 1694/* 1695 * {fu,su},{byte,sword,word} 1696 */ 1697ALTENTRY(fuiword, _fuword) 1698ENTRY(fuword) 1699 movl sp@(4),d0 | address to read 1700 btst #0,d0 | is it odd? 1701 jne Lfserr | yes, a fault 1702 movl #Lfserr,_u+PCB_ONFAULT | where to return to on a fault 1703 movl d0,a0 1704 movsl a0@,d0 | do read from user space 1705 jra Lfsdone 1706 1707ENTRY(fusword) 1708 movl sp@(4),d0 1709 btst #0,d0 | is address odd? 1710 jne Lfserr | yes, a fault 1711 movl #Lfserr,_u+PCB_ONFAULT | where to return to on a fault 1712 movl d0,a0 | address to read 1713 moveq #0,d0 1714 movsw a0@,d0 | do read from user space 1715 jra Lfsdone 1716 1717ALTENTRY(fuibyte, _fubyte) 1718ENTRY(fubyte) 1719 movl #Lfserr,_u+PCB_ONFAULT | where to return to on a fault 1720 movl sp@(4),a0 | address to read 1721 moveq #0,d0 1722 movsb a0@,d0 | do read from user space 1723 jra Lfsdone 1724 1725Lfserr: 1726 moveq #-1,d0 | error indicator 1727Lfsdone: 1728 clrl _u+PCB_ONFAULT | clear fault address 1729 rts 1730 1731ALTENTRY(suiword, _suword) 1732ENTRY(suword) 1733 movl sp@(4),d0 | address to write 1734 btst #0,d0 | is it odd? 1735 jne Lfserr | yes, a fault 1736 movl #Lfserr,_u+PCB_ONFAULT | where to return to on a fault 1737 movl d0,a0 | address to write 1738 movl sp@(8),d0 | value to put there 1739 movsl d0,a0@ | do write to user space 1740 moveq #0,d0 | indicate no fault 1741 jra Lfsdone 1742 1743ENTRY(susword) 1744 movl sp@(4),d0 | address to write 1745 btst #0,d0 | is it odd? 1746 jne Lfserr | yes, a fault 1747 movl #Lfserr,_u+PCB_ONFAULT | where to return to on a fault 1748 movl d0,a0 | address to write 1749 movw sp@(10),d0 | value to put there 1750 movsw d0,a0@ | do write to user space 1751 moveq #0,d0 | indicate no fault 1752 jra Lfsdone 1753 1754ALTENTRY(suibyte, _subyte) 1755ENTRY(subyte) 1756 movl #Lfserr,_u+PCB_ONFAULT | where to return to on a fault 1757 movl sp@(4),a0 | address to write 1758 movb sp@(11),d0 | value to put there 1759 movsb d0,a0@ | do write to user space 1760 moveq #0,d0 | indicate no fault 1761 jra Lfsdone 1762 1763/* 1764 * Copy 1 relocation unit (NBPG bytes) 1765 * from user virtual address to physical address 1766 */ 1767ENTRY(copyseg) 1768 movl sp@(8),d0 | destination page number 1769 moveq #PGSHIFT,d1 1770 lsll d1,d0 | convert to address 1771 orl #PG_CI+PG_RW+PG_V,d0 | make sure valid and writable 1772 movl d0,_CMAP2 | load in page table 1773 movl #_CADDR2,sp@- | destination kernel VA 1774 jbsr _TBIS | invalidate any old mapping 1775 addql #4,sp 1776 movl #_CADDR2,a1 | destination addr 1777 movl sp@(4),a0 | source addr 1778 movl #NBPG/4-1,d0 | count 1779 movl #Lcpydone,_u+PCB_ONFAULT | where to go on a fault 1780Lcpyloop: 1781 movsl a0@+,d1 | read longword 1782 movl d1,a1@+ | write longword 1783 dbf d0,Lcpyloop | continue until done 1784Lcpydone: 1785 clrl _u+PCB_ONFAULT | clear error catch 1786 rts 1787 1788/* 1789 * zero out physical memory 1790 * specified in relocation units (NBPG bytes) 1791 */ 1792ENTRY(clearseg) 1793 movl sp@(4),d0 | destination page number 1794 moveq #PGSHIFT,d1 1795 lsll d1,d0 | convert to address 1796 orl #PG_CI+PG_RW+PG_V,d0 | make sure valid and writable 1797 movl d0,_CMAP1 | load in page map 1798 movl #_CADDR1,sp@- | destination kernel VA 1799 jbsr _TBIS | invalidate any old mapping 1800 addql #4,sp 1801 movl #_CADDR1,a1 | destination addr 1802 movl #NBPG/4-1,d0 | count 1803/* simple clear loop is fastest on 68020 */ 1804Lclrloop: 1805 clrl a1@+ | clear a longword 1806 dbf d0,Lclrloop | continue til done 1807 rts 1808 1809/* 1810 * Invalidate entire TLB. 1811 */ 1812ENTRY(TBIA) 1813__TBIA: 1814#if defined(HP330) || defined(HP360) || defined(HP370) 1815 tstl _mmutype | HP MMU? 1816 jeq Lhpmmu6 | yes, skip 1817 .long 0xf0002400 | no, pflusha 1818#if defined(HP360) || defined(HP370) 1819 jpl Lmc68851a | 68851 implies no d-cache 1820 movl #DC_CLEAR,d0 1821 movc d0,cacr | invalidate on-chip d-cache 1822Lmc68851a: 1823#endif 1824 rts 1825Lhpmmu6: 1826#endif 1827#if defined(HP320) || defined(HP350) 1828 movl _IObase+MMUTBINVAL,sp@- | do not ask me, this 1829 addql #4,sp | is how hpux does it 1830 jra __DCIA | XXX: invalidate entire cache 1831#endif 1832 rts 1833 1834/* 1835 * Invalidate any TLB entry for given VA (TB Invalidate Single) 1836 */ 1837ENTRY(TBIS) 1838#ifdef DEBUG 1839 tstl fullflush | being conservative? 1840 jne __TBIA | yes, flush entire TLB 1841#endif 1842#if defined(HP330) || defined(HP360) || defined(HP370) 1843 tstl _mmutype | HP MMU? 1844 jeq Lhpmmu5 | yes, skip 1845 movl sp@(4),a0 | get addr to flush 1846#if defined(HP360) || defined(HP370) 1847 jpl Lmc68851b | is 68851? 1848 .long 0xf0103810 | pflush #0,#0,a0@ 1849 movl #DC_CLEAR,d0 1850 movc d0,cacr | invalidate on-chip data cache 1851 rts 1852Lmc68851b: 1853#endif 1854 .long 0xf0103c10 | pflushs #0,#0,a0@ 1855 rts 1856Lhpmmu5: 1857#endif 1858#if defined(HP320) || defined(HP350) 1859 movl sp@(4),d0 | VA to invalidate 1860 bclr #0,d0 | ensure even 1861 movl d0,a0 1862 movw sr,d1 | go critical 1863 movw #PSL_HIGHIPL,sr | while in purge space 1864 moveq #FC_PURGE,d0 | change address space 1865 movc d0,dfc | for destination 1866 moveq #0,d0 | zero to invalidate? 1867 movsl d0,a0@ | hit it 1868 moveq #FC_USERD,d0 | back to old 1869 movc d0,dfc | address space 1870 movw d1,sr | restore IPL 1871#endif 1872 rts 1873 1874/* 1875 * Invalidate supervisor side of TLB 1876 */ 1877ENTRY(TBIAS) 1878#ifdef DEBUG 1879 tstl fullflush | being conservative? 1880 jne __TBIA | yes, flush everything 1881#endif 1882#if defined(HP330) || defined(HP360) || defined(HP370) 1883 tstl _mmutype | HP MMU? 1884 jeq Lhpmmu7 | yes, skip 1885#if defined(HP360) || defined(HP370) 1886 jpl Lmc68851c | 68851? 1887 .long 0xf0003094 | pflush #4,#4 1888 movl #DC_CLEAR,d0 1889 movc d0,cacr | invalidate on-chip d-cache 1890 rts 1891Lmc68851c: 1892#endif 1893 .long 0xf0003494 | pflushs #4,#4 1894 rts 1895Lhpmmu7: 1896#endif 1897#if defined(HP320) || defined(HP350) 1898 movl #0x8000,d0 | more 1899 movl d0,_IObase+MMUTBINVAL | HP magic 1900 jra __DCIS | XXX: invalidate entire sup. cache 1901#endif 1902 rts 1903 1904/* 1905 * Invalidate user side of TLB 1906 */ 1907ENTRY(TBIAU) 1908#ifdef DEBUG 1909 tstl fullflush | being conservative? 1910 jne __TBIA | yes, flush everything 1911#endif 1912#if defined(HP330) || defined(HP360) || defined(HP370) 1913 tstl _mmutype | HP MMU? 1914 jeq Lhpmmu8 | yes, skip 1915#if defined(HP360) || defined(HP370) 1916 jpl Lmc68851d | 68851? 1917 .long 0xf0003090 | pflush #0,#4 1918 movl #DC_CLEAR,d0 1919 movc d0,cacr | invalidate on-chip d-cache 1920 rts 1921Lmc68851d: 1922#endif 1923 .long 0xf0003490 | pflushs #0,#4 1924 rts 1925Lhpmmu8: 1926#endif 1927#if defined(HP320) || defined(HP350) 1928 moveq #0,d0 | more 1929 movl d0,_IObase+MMUTBINVAL | HP magic 1930 jra __DCIU | XXX: invalidate entire user cache 1931#endif 1932 rts 1933 1934/* 1935 * Invalidate instruction cache 1936 */ 1937ENTRY(ICIA) 1938 movl #IC_CLEAR,d0 1939 movc d0,cacr | invalidate i-cache 1940 rts 1941 1942/* 1943 * Invalidate data cache. 1944 * HP external cache allows for invalidation of user/supervisor portions. 1945 */ 1946ENTRY(DCIA) 1947__DCIA: 1948#if defined(HP360) || defined(HP370) 1949 movl #DC_CLEAR,d0 1950 movc d0,cacr | invalidate on-chip d-cache 1951#endif 1952#if defined(HP320) || defined(HP350) 1953 tstl _ectype | got external VAC? 1954 jle Lnocache2 | no, all done 1955 movl #_IObase+MMUCMD,a0 | MMU control reg 1956 andl #~MMU_CEN,a0@ | disable cache 1957 orl #MMU_CEN,a0@ | reenable cache 1958Lnocache2: 1959#endif 1960 rts 1961 1962ENTRY(DCIS) 1963__DCIS: 1964#if defined(HP360) || defined(HP370) 1965 movl #DC_CLEAR,d0 1966 movc d0,cacr | invalidate on-chip d-cache 1967#endif 1968#if defined(HP320) || defined(HP350) 1969 tstl _ectype | got external VAC? 1970 jle Lnocache3 | no, all done 1971 movl _IObase+MMUSSTP,d0 | read the supervisor STP 1972 movl d0,_IObase+MMUSSTP | write it back 1973Lnocache3: 1974#endif 1975 rts 1976 1977ENTRY(DCIU) 1978__DCIU: 1979#if defined(HP360) || defined(HP370) 1980 movl #DC_CLEAR,d0 1981 movc d0,cacr | invalidate on-chip d-cache 1982#endif 1983#if defined(HP320) || defined(HP350) 1984 tstl _ectype | got external VAC? 1985 jle Lnocache4 | no, all done 1986 movl _IObase+MMUUSTP,d0 | read the user STP 1987 movl d0,_IObase+MMUUSTP | write it back 1988Lnocache4: 1989#endif 1990 rts 1991 1992#if defined(HP370) 1993ENTRY(PCIA) 1994 tstl _ectype | got external PAC? 1995 jge Lnocache6 | no, all done 1996 movl #_IObase+MMUCMD,a0 | MMU control reg 1997 andl #~MMU_CEN,a0@ | disable cache 1998 orl #MMU_CEN,a0@ | reenable cache 1999Lnocache6: 2000 rts 2001#endif 2002 2003ENTRY(ecacheon) 2004 tstl _ectype 2005 jeq Lnocache7 2006 movl #_IObase+MMUCMD,a0 2007 orl #MMU_CEN,a0@ 2008Lnocache7: 2009 rts 2010 2011ENTRY(ecacheoff) 2012 tstl _ectype 2013 jeq Lnocache8 2014 movl #_IObase+MMUCMD,a0 2015 andl #~MMU_CEN,a0@ 2016Lnocache8: 2017 rts 2018 2019 .globl _getsfc, _getdfc 2020_getsfc: 2021 movc sfc,d0 2022 rts 2023_getdfc: 2024 movc dfc,d0 2025 rts 2026 2027/* 2028 * Load a new user segment table pointer. 2029 */ 2030ENTRY(loadustp) 2031#if defined(HP330) || defined(HP360) || defined(HP370) 2032 tstl _mmutype | HP MMU? 2033 jeq Lhpmmu9 | yes, skip 2034 movl sp@(4),d0 | new USTP 2035 moveq #PGSHIFT,d1 2036 lsll d1,d0 | convert to addr 2037 lea _protorp,a0 | CRP prototype 2038 movl d0,a0@(4) | stash USTP 2039 .long 0xf0104C00 | pmove a0@,crp 2040 movl #DC_CLEAR,d0 2041 movc d0,cacr | invalidate on-chip d-cache 2042 rts | since pmove flushes TLB 2043Lhpmmu9: 2044#endif 2045#if defined(HP320) || defined(HP350) 2046 movl sp@(4),_IObase+MMUUSTP | load a new USTP 2047#endif 2048 rts 2049 2050/* 2051 * Flush any hardware context associated with given USTP. 2052 * Only does something for HP330 where we must flush RPT 2053 * and ATC entries in PMMU. 2054 */ 2055ENTRY(flushustp) 2056#if defined(HP330) 2057 tstl _mmutype | 68851 PMMU? 2058 jle Lnot68851 | no, nothing to do 2059 movl sp@(4),d0 | get USTP to flush 2060 moveq #PGSHIFT,d1 2061 lsll d1,d0 | convert to address 2062 movl d0,_protorp+4 | stash USTP 2063 .long 0xf039a000,_protorp | pflushr _protorp 2064Lnot68851: 2065#endif 2066 rts 2067 2068ENTRY(ploadw) 2069#if defined(HP330) || defined(HP360) || defined(HP370) 2070 movl sp@(4),a0 | address to load 2071 .long 0xf0102011 | pload #1,a0@ 2072#endif 2073 rts 2074 2075/* 2076 * Set processor priority level calls. Most could (should) be replaced 2077 * by inline asm expansions. However, SPL0 and SPLX require special 2078 * handling. If we are returning to the base processor priority (SPL0) 2079 * we need to check for our emulated software interrupts. 2080 */ 2081 2082ENTRY(spl0) 2083 moveq #0,d0 2084 movw sr,d0 | get old SR for return 2085 movw #PSL_LOWIPL,sr | restore new SR 2086 jra Lsplsir 2087 2088ENTRY(splx) 2089 moveq #0,d0 2090 movw sr,d0 | get current SR for return 2091 movw sp@(6),d1 | get new value 2092 movw d1,sr | restore new SR 2093 andw #PSL_IPL7,d1 | mask all but PSL_IPL 2094 jne Lspldone | non-zero, all done 2095Lsplsir: 2096 tstb _ssir | software interrupt pending? 2097 jeq Lspldone | no, all done 2098 subql #4,sp | make room for RTE frame 2099 movl sp@(4),sp@(2) | position return address 2100 clrw sp@(6) | set frame type 0 2101 movw #PSL_LOWIPL,sp@ | and new SR 2102 jra Lgotsir | go handle it 2103Lspldone: 2104 rts 2105 2106ALTENTRY(splsoftclock, _spl1) 2107ALTENTRY(splnet, _spl1) 2108ENTRY(spl1) 2109 moveq #0,d0 2110 movw sr,d0 2111 movw #SPL1,sr 2112 rts 2113 2114ENTRY(spl2) 2115 moveq #0,d0 2116 movw sr,d0 2117 movw #SPL2,sr 2118 rts 2119 2120ENTRY(spl3) 2121 moveq #0,d0 2122 movw sr,d0 2123 movw #SPL3,sr 2124 rts 2125 2126ENTRY(spl4) 2127 moveq #0,d0 2128 movw sr,d0 2129 movw #SPL4,sr 2130 rts 2131 2132ALTENTRY(splimp, _spl5) 2133ALTENTRY(splbio, _spl5) 2134ALTENTRY(spltty, _spl5) 2135ENTRY(spl5) 2136 moveq #0,d0 2137 movw sr,d0 2138 movw #SPL5,sr 2139 rts 2140 2141ALTENTRY(splclock, _spl6) 2142ENTRY(spl6) 2143 moveq #0,d0 2144 movw sr,d0 2145 movw #SPL6,sr 2146 rts 2147 2148ALTENTRY(splhigh, _spl7) 2149ENTRY(spl7) 2150 moveq #0,d0 2151 movw sr,d0 2152 movw #PSL_HIGHIPL,sr 2153 rts 2154 2155#ifdef GPROF 2156/* 2157 * Special versions of splhigh and splx called by mcount(). 2158 * Note that __splx does not check for software interrupts. 2159 */ 2160 .globl __splhigh, __splx 2161__splhigh: 2162 moveq #0,d0 2163 movw sr,d0 2164 movw #PSL_HIGHIPL,sr 2165 rts 2166 2167__splx: 2168 moveq #0,d0 2169 movw sr,d0 | get current SR for return 2170 movw sp@(6),d1 | get new value 2171 movw d1,sr | restore new SR 2172 rts 2173#endif 2174 2175ENTRY(_insque) 2176 movw sr,d0 2177 movw #PSL_HIGHIPL,sr | atomic 2178 movl sp@(8),a0 | where to insert (after) 2179 movl sp@(4),a1 | element to insert (e) 2180 movl a0@,a1@ | e->next = after->next 2181 movl a0,a1@(4) | e->prev = after 2182 movl a1,a0@ | after->next = e 2183 movl a1@,a0 2184 movl a1,a0@(4) | e->next->prev = e 2185 movw d0,sr 2186 rts 2187 2188ENTRY(_remque) 2189 movw sr,d0 2190 movw #PSL_HIGHIPL,sr | atomic 2191 movl sp@(4),a0 | element to remove (e) 2192 movl a0@,a1 2193 movl a0@(4),a0 2194 movl a0,a1@(4) | e->next->prev = e->prev 2195 movl a1,a0@ | e->prev->next = e->next 2196 movw d0,sr 2197 rts 2198 2199ALTENTRY(blkclr, _bzero) 2200ENTRY(bzero) 2201 movl sp@(4),a0 2202 movl sp@(8),d0 2203 jeq 1$ 2204 movl a0,d1 2205 btst #0,d1 2206 jeq 2$ 2207 clrb a0@+ 2208 subql #1,d0 2209 jeq 1$ 22102$: 2211 movl d0,d1 2212 andl #31,d0 2213 lsrl #5,d1 2214 jeq 3$ 22154$: 2216 clrl a0@+; clrl a0@+; clrl a0@+; clrl a0@+; 2217 clrl a0@+; clrl a0@+; clrl a0@+; clrl a0@+; 2218 subql #1,d1 2219 jne 4$ 2220 tstl d0 2221 jeq 1$ 22223$: 2223 clrb a0@+ 2224 subql #1,d0 2225 jne 3$ 22261$: 2227 rts 2228 2229/* 2230 * strlen(str) 2231 */ 2232ENTRY(strlen) 2233 moveq #-1,d0 2234 movl sp@(4),a0 | string 2235Lslloop: 2236 addql #1,d0 | increment count 2237 tstb a0@+ | null? 2238 jne Lslloop | no, keep going 2239 rts 2240 2241/* 2242 * bcmp(s1, s2, len) 2243 * 2244 * WARNING! This guy only works with counts up to 64K 2245 */ 2246ENTRY(bcmp) 2247 movl sp@(4),a0 | string 1 2248 movl sp@(8),a1 | string 2 2249 moveq #0,d0 2250 movw sp@(14),d0 | length 2251 jeq Lcmpdone | if zero, nothing to do 2252 subqw #1,d0 | set up for DBcc loop 2253Lcmploop: 2254 cmpmb a0@+,a1@+ | equal? 2255 dbne d0,Lcmploop | yes, keep going 2256 addqw #1,d0 | +1 gives zero on match 2257Lcmpdone: 2258 rts 2259 2260/* 2261 * {ov}bcopy(from, to, len) 2262 * 2263 * Works for counts up to 128K. 2264 */ 2265ALTENTRY(ovbcopy, _bcopy) 2266ENTRY(bcopy) 2267 movl sp@(12),d0 | get count 2268 jeq Lcpyexit | if zero, return 2269 movl sp@(4),a0 | src address 2270 movl sp@(8),a1 | dest address 2271 cmpl a1,a0 | src before dest? 2272 jlt Lcpyback | yes, copy backwards (avoids overlap) 2273 movl a0,d1 2274 btst #0,d1 | src address odd? 2275 jeq Lcfeven | no, go check dest 2276 movb a0@+,a1@+ | yes, copy a byte 2277 subql #1,d0 | update count 2278 jeq Lcpyexit | exit if done 2279Lcfeven: 2280 movl a1,d1 2281 btst #0,d1 | dest address odd? 2282 jne Lcfbyte | yes, must copy by bytes 2283 movl d0,d1 | no, get count 2284 lsrl #2,d1 | convert to longwords 2285 jeq Lcfbyte | no longwords, copy bytes 2286 subql #1,d1 | set up for dbf 2287Lcflloop: 2288 movl a0@+,a1@+ | copy longwords 2289 dbf d1,Lcflloop | til done 2290 andl #3,d0 | get remaining count 2291 jeq Lcpyexit | done if none 2292Lcfbyte: 2293 subql #1,d0 | set up for dbf 2294Lcfbloop: 2295 movb a0@+,a1@+ | copy bytes 2296 dbf d0,Lcfbloop | til done 2297Lcpyexit: 2298 rts 2299Lcpyback: 2300 addl d0,a0 | add count to src 2301 addl d0,a1 | add count to dest 2302 movl a0,d1 2303 btst #0,d1 | src address odd? 2304 jeq Lcbeven | no, go check dest 2305 movb a0@-,a1@- | yes, copy a byte 2306 subql #1,d0 | update count 2307 jeq Lcpyexit | exit if done 2308Lcbeven: 2309 movl a1,d1 2310 btst #0,d1 | dest address odd? 2311 jne Lcbbyte | yes, must copy by bytes 2312 movl d0,d1 | no, get count 2313 lsrl #2,d1 | convert to longwords 2314 jeq Lcbbyte | no longwords, copy bytes 2315 subql #1,d1 | set up for dbf 2316Lcblloop: 2317 movl a0@-,a1@- | copy longwords 2318 dbf d1,Lcblloop | til done 2319 andl #3,d0 | get remaining count 2320 jeq Lcpyexit | done if none 2321Lcbbyte: 2322 subql #1,d0 | set up for dbf 2323Lcbbloop: 2324 movb a0@-,a1@- | copy bytes 2325 dbf d0,Lcbbloop | til done 2326 rts 2327 2328/* 2329 * Emulate fancy VAX string operations: 2330 * scanc(count, startc, table, mask) 2331 * skpc(mask, count, startc) 2332 * locc(mask, count, startc) 2333 */ 2334ENTRY(scanc) 2335 movl sp@(4),d0 | get length 2336 jeq Lscdone | nothing to do, return 2337 movl sp@(8),a0 | start of scan 2338 movl sp@(12),a1 | table to compare with 2339 movb sp@(19),d1 | and mask to use 2340 movw d2,sp@- | need a scratch register 2341 clrw d2 | clear it out 2342 subqw #1,d0 | adjust for dbra 2343Lscloop: 2344 movb a0@+,d2 | get character 2345 movb a1@(0,d2:w),d2 | get table entry 2346 andb d1,d2 | mask it 2347 dbne d0,Lscloop | keep going til no more or non-zero 2348 addqw #1,d0 | overshot by one 2349 movw sp@+,d2 | restore scratch 2350Lscdone: 2351 rts 2352 2353ENTRY(skpc) 2354 movl sp@(8),d0 | get length 2355 jeq Lskdone | nothing to do, return 2356 movb sp@(7),d1 | mask to use 2357 movl sp@(12),a0 | where to start 2358 subqw #1,d0 | adjust for dbcc 2359Lskloop: 2360 cmpb a0@+,d1 | compate with mask 2361 dbne d0,Lskloop | keep going til no more or zero 2362 addqw #1,d0 | overshot by one 2363Lskdone: 2364 rts 2365 2366ENTRY(locc) 2367 movl sp@(8),d0 | get length 2368 jeq Llcdone | nothing to do, return 2369 movb sp@(7),d1 | mask to use 2370 movl sp@(12),a0 | where to start 2371 subqw #1,d0 | adjust for dbcc 2372Llcloop: 2373 cmpb a0@+,d1 | compate with mask 2374 dbeq d0,Llcloop | keep going til no more or non-zero 2375 addqw #1,d0 | overshot by one 2376Llcdone: 2377 rts 2378 2379/* 2380 * Emulate VAX FFS (find first set) instruction. 2381 */ 2382ENTRY(ffs) 2383 moveq #-1,d0 2384 movl sp@(4),d1 2385 beq Lffsdone 2386Lffsloop: 2387 addql #1,d0 2388 btst d0,d1 2389 beq Lffsloop 2390Lffsdone: 2391 addql #1,d0 2392 rts 2393 2394#ifdef FPCOPROC 2395/* 2396 * Save and restore 68881 state. 2397 * Pretty awful looking since our assembler does not 2398 * recognize FP mnemonics. 2399 */ 2400ENTRY(m68881_save) 2401 movl sp@(4),a0 | save area pointer 2402 .word 0xf310 | fsave a0@ 2403 tstb a0@ | null state frame? 2404 jeq Lm68881sdone | yes, all done 2405 .word 0xf228,0xf0ff,0x00d8 | fmovem fp0-fp7,a0@(216) 2406 .word 0xf228,0xbc00,0x0138 | fmovem fpcr/fpsr/fpiar,a0@(312) 2407Lm68881sdone: 2408 rts 2409 2410ENTRY(m68881_restore) 2411 movl sp@(4),a0 | save area pointer 2412 tstb a0@ | null state frame? 2413 jeq Lm68881rdone | yes, easy 2414 .word 0xf228,0x9c00,0x0138 | fmovem a0@(312),fpcr/fpsr/fpiar 2415 .word 0xf228,0xd0ff,0x00d8 | fmovem a0@(216),fp0-fp7 2416Lm68881rdone: 2417 .word 0xf350 | frestore a0@ 2418 rts 2419#endif 2420 2421/* 2422 * Handle the nitty-gritty of rebooting the machine. 2423 * Basically we just turn off the MMU and jump to the appropriate ROM routine. 2424 * Note that we must be running in an address range that is mapped one-to-one 2425 * logical to physical so that the PC is still valid immediately after the MMU 2426 * is turned off. 2427 */ 2428 .globl _doboot 2429_doboot: 2430 movl #CACHE_OFF,d0 2431 movc d0,cacr | disable on-chip cache(s) 2432#if defined(HP320) || defined(HP350) || defined(HP370) 2433 tstl _ectype 2434 jeq Lnocache5 2435 andl #~MMU_CEN,_IObase+MMUCMD| disable external cache 2436Lnocache5: 2437#endif 2438/* one-to-one map the last page of memory */ 2439 movl #MAXADDR,d0 | last page of RAM used to pass params 2440 orl #PG_RW+PG_V,d0 | create a PTE 2441 movl d0,_mmap | to access that page 2442 jbsr _TBIA | invalidate TLB 2443 movl #MAXADDR,d0 | last page of RAM is also used 2444 orl #SG_RW+SG_V,d0 | as the page table for itself 2445 movl d0,eSysseg-4 | (ok since it needs only last word) 2446 movl _vmmap+NBPG-4,d2 | save old contents 2447 movl _mmap,_vmmap+NBPG-4 | store PTE in new page table 2448 jbsr _TBIA | invalidate again 2449 lea MAXADDR,a0 | can now access last page 2450 movl _boothowto,a0@+ | store howto 2451 movl _bootdev,a0@+ | and devtype 2452 lea Lbootcode,a1 | start of boot code 2453 lea Lebootcode,a3 | end of boot code 2454Lbootcopy: 2455 movw a1@+,a0@+ | copy a word 2456 cmpl a3,a1 | done yet? 2457 jcs Lbootcopy | no, keep going 2458 jmp MAXADDR+8 | jump to last page 2459 2460Lbootcode: 2461 lea MAXADDR+0x800,sp | physical SP in case of NMI 2462#if defined(HP330) || defined(HP360) || defined(HP370) 2463 tstl _mmutype | HP MMU? 2464 jeq LhpmmuB | yes, skip 2465 movl #0,a0@ | value for pmove to TC (turn off MMU) 2466 .long 0xf0104000 | pmove a0@,tc 2467 movl d2,MAXADDR+NBPG-4 | restore old high page contents 2468 jmp 0x1A4 | goto REQ_REBOOT 2469LhpmmuB: 2470#endif 2471#if defined(HP320) || defined(HP350) 2472 movl #0xFFFF0000,_IObase+MMUCMD | totally disable MMU 2473 movl d2,MAXADDR+NBPG-4 | restore old high page contents 2474 jmp 0x1A4 | goto REQ_REBOOT 2475#endif 2476Lebootcode: 2477 2478 .data 2479 .space NBPG 2480tmpstk: 2481 .globl _machineid 2482_machineid: 2483 .long 0 | default to 320 2484 .globl _mmutype,_protorp 2485_mmutype: 2486 .long 0 | default to HP MMU 2487_protorp: 2488 .long 0,0 | prototype root pointer 2489 .globl _ectype 2490_ectype: 2491 .long 0 | external cache type, default to none 2492 .globl _cold 2493_cold: 2494 .long 1 | cold start flag 2495#ifdef DEBUG 2496 .globl fullflush 2497fullflush: 2498 .long 0 2499 .globl timebomb 2500timebomb: 2501 .long 0 2502#endif 2503/* interrupt counters */ 2504 .globl _intrcnt,_eintrcnt,_intrnames,_eintrnames 2505_intrnames: 2506 .asciz "spur" 2507 .asciz "hil" 2508 .asciz "lev2" 2509 .asciz "lev3" 2510 .asciz "lev4" 2511 .asciz "lev5" 2512 .asciz "dma" 2513 .asciz "clock" 2514#ifdef PROFTIMER 2515 .asciz "pclock" 2516#endif 2517 .asciz "nmi" 2518_eintrnames: 2519 .even 2520_intrcnt: 2521#ifdef PROFTIMER 2522 .long 0,0,0,0,0,0,0,0,0,0 2523#else 2524 .long 0,0,0,0,0,0,0,0,0 2525#endif 2526_eintrcnt: 2527