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