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