1/* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1992 OMRON Corporation. 4 * Copyright (c) 1980, 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * the Systems Programming Group of the University of Utah Computer 9 * Science Department. 10 * 11 * %sccs.include.redist.c% 12 * 13 * from: Utah $Hdr: locore.s 1.62 92/01/20$ 14 * OMRON: $Id: locore.s,v 1.2 92/06/14 06:16:34 moti Exp $ 15 * 16 * from: hp300/hp300/locore.s 7.16 (Berkeley) 7/8/92 17 * 18 * @(#)locore.s 7.3 (Berkeley) 07/23/92 19 */ 20 21#include "assym.s" 22#include "vectors.s" 23 24 .text 25/* 26 * This is where we wind up if the kernel jumps to location 0. 27 * (i.e. a bogus PC) This is known to immediately follow the vector 28 * table and is hence at 0x400 (see reset vector in vectors.s). 29 */ 30 .globl _panic 31 pea Ljmp0panic 32 jbsr _panic 33 /* NOTREACHED */ 34Ljmp0panic: 35 .asciz "kernel jump to zero" 36 .even 37 38/* 39 * Do a dump. 40 * Called by auto-restart. 41 */ 42 .globl _dumpsys 43 .globl _doadump 44_doadump: 45 jbsr _dumpsys 46 jbsr _doboot 47 /*NOTREACHED*/ 48 49/* 50 * Trap/interrupt vector routines 51 */ 52 53 .globl _trap, _nofault, _longjmp 54_buserr: 55 tstl _nofault | device probe? 56 jeq _addrerr | no, handle as usual 57 movl _nofault,sp@- | yes, 58 jbsr _longjmp | longjmp(nofault) 59_addrerr: 60 clrw sp@- | pad SR to longword 61 moveml #0xFFFF,sp@- | save user registers 62 movl usp,a0 | save the user SP 63 movl a0,sp@(60) | in the savearea 64 lea sp@(64),a1 | grab base of HW berr frame 65 moveq #0,d0 66 movw a1@(12),d0 | grab SSW for fault processing 67 btst #12,d0 | RB set? 68 jeq LbeX0 | no, test RC 69 bset #14,d0 | yes, must set FB 70 movw d0,a1@(12) | for hardware too 71LbeX0: 72 btst #13,d0 | RC set? 73 jeq LbeX1 | no, skip 74 bset #15,d0 | yes, must set FC 75 movw d0,a1@(12) | for hardware too 76LbeX1: 77 btst #8,d0 | data fault? 78 jeq Lbe0 | no, check for hard cases 79 movl a1@(18),d1 | fault address is as given in frame 80 jra Lbe10 | thats it 81Lbe0: 82 btst #4,a1@(8) | long (type B) stack frame? 83 jne Lbe4 | yes, go handle 84 movl a1@(4),d1 | no, can use save PC 85 btst #14,d0 | FB set? 86 jeq Lbe3 | no, try FC 87 addql #4,d1 | yes, adjust address 88 jra Lbe10 | done 89Lbe3: 90 btst #15,d0 | FC set? 91 jeq Lbe10 | no, done 92 addql #2,d1 | yes, adjust address 93 jra Lbe10 | done 94Lbe4: 95 movl a1@(38),d1 | long format, use stage B address 96 btst #15,d0 | FC set? 97 jeq Lbe10 | no, all done 98 subql #2,d1 | yes, adjust address 99Lbe10: 100 movl d1,sp@- | push fault VA 101 movl d0,sp@- | and padded SSW 102 movw a1@(8),d0 | get frame format/vector offset 103 andw #0x0FFF,d0 | clear out frame format 104 cmpw #12,d0 | address error vector? 105 jeq Lisaerr | yes, go to it 106 movl d1,a0 | fault address 107 ptestr #1,a0@,#7 | do a table search 108 pmove psr,sp@ | save result 109 btst #7,sp@ | bus error bit set? 110 jeq Lismerr | no, must be MMU fault 111 clrw sp@ | yes, re-clear pad word 112 jra Lisberr | and process as normal bus error 113Lismerr: 114 movl #T_MMUFLT,sp@- | show that we are an MMU fault 115 jra Ltrapnstkadj | and deal with it 116Lisaerr: 117 movl #T_ADDRERR,sp@- | mark address error 118 jra Ltrapnstkadj | and deal with it 119Lisberr: 120 movl #T_BUSERR,sp@- | mark bus error 121Ltrapnstkadj: 122 jbsr _trap | handle the error 123 lea sp@(12),sp | pop value args 124 movl sp@(60),a0 | restore user SP 125 movl a0,usp | from save area 126 movw sp@(64),d0 | need to adjust stack? 127 jne Lstkadj | yes, go to it 128 moveml sp@+,#0x7FFF | no, restore most user regs 129 addql #6,sp | toss SSP and pad 130 jra rei | all done 131Lstkadj: 132 lea sp@(66),a1 | pointer to HW frame 133 addql #8,a1 | source pointer 134 movl a1,a0 | source 135 addw d0,a0 | + hole size = dest pointer 136 movl a1@-,a0@- | copy 137 movl a1@-,a0@- | 8 bytes 138 movl a0,sp@(60) | new SSP 139 moveml sp@+,#0x7FFF | restore user registers 140 movl sp@,sp | and our SP 141 jra rei | all done 142 143/* 144 * FP exceptions. 145 */ 146_fpfline: 147 jra _illinst 148 149_fpunsupp: 150 jra _illinst 151 152/* 153 * Handles all other FP coprocessor exceptions. 154 * Note that since some FP exceptions generate mid-instruction frames 155 * and may cause signal delivery, we need to test for stack adjustment 156 * after the trap call. 157 */ 158_fpfault: 159#ifdef FPCOPROC 160 clrw sp@- | pad SR to longword 161 moveml #0xFFFF,sp@- | save user registers 162 movl usp,a0 | and save 163 movl a0,sp@(60) | the user stack pointer 164 clrl sp@- | no VA arg 165 movl _curpcb,a0 | current pcb 166 lea a0@(PCB_FPCTX),a0 | address of FP savearea 167 fsave a0@ | save state 168 tstb a0@ | null state frame? 169 jeq Lfptnull | yes, safe 170 clrw d0 | no, need to tweak BIU 171 movb a0@(1),d0 | get frame size 172 bset #3,a0@(0,d0:w) | set exc_pend bit of BIU 173Lfptnull: 174 fmovem fpsr,sp@- | push fpsr as code argument 175 frestore a0@ | restore state 176 movl #T_FPERR,sp@- | push type arg 177 jra Ltrapnstkadj | call trap and deal with stack cleanup 178#else 179 jra _badtrap | treat as an unexpected trap 180#endif 181 182/* 183 * Coprocessor and format errors can generate mid-instruction stack 184 * frames and cause signal delivery hence we need to check for potential 185 * stack adjustment. 186 */ 187_coperr: 188 clrw sp@- 189 moveml #0xFFFF,sp@- 190 movl usp,a0 | get and save 191 movl a0,sp@(60) | the user stack pointer 192 clrl sp@- | no VA arg 193 clrl sp@- | or code arg 194 movl #T_COPERR,sp@- | push trap type 195 jra Ltrapnstkadj | call trap and deal with stack adjustments 196 197_fmterr: 198 clrw sp@- 199 moveml #0xFFFF,sp@- 200 movl usp,a0 | get and save 201 movl a0,sp@(60) | the user stack pointer 202 clrl sp@- | no VA arg 203 clrl sp@- | or code arg 204 movl #T_FMTERR,sp@- | push trap type 205 jra Ltrapnstkadj | call trap and deal with stack adjustments 206 207/* 208 * Other exceptions only cause four and six word stack frame and require 209 * no post-trap stack adjustment. 210 */ 211_illinst: 212 clrw sp@- 213 moveml #0xFFFF,sp@- 214 moveq #T_ILLINST,d0 215 jra fault 216 217_zerodiv: 218 clrw sp@- 219 moveml #0xFFFF,sp@- 220 moveq #T_ZERODIV,d0 221 jra fault 222 223_chkinst: 224 clrw sp@- 225 moveml #0xFFFF,sp@- 226 moveq #T_CHKINST,d0 227 jra fault 228 229_trapvinst: 230 clrw sp@- 231 moveml #0xFFFF,sp@- 232 moveq #T_TRAPVINST,d0 233 jra fault 234 235_privinst: 236 clrw sp@- 237 moveml #0xFFFF,sp@- 238 moveq #T_PRIVINST,d0 239 jra fault 240 241 .globl fault 242fault: 243 movl usp,a0 | get and save 244 movl a0,sp@(60) | the user stack pointer 245 clrl sp@- | no VA arg 246 clrl sp@- | or code arg 247 movl d0,sp@- | push trap type 248 jbsr _trap | handle trap 249 lea sp@(12),sp | pop value args 250 movl sp@(60),a0 | restore 251 movl a0,usp | user SP 252 moveml sp@+,#0x7FFF | restore most user regs 253 addql #6,sp | pop SP and pad word 254 jra rei | all done 255 256 .globl _straytrap 257_badtrap: 258 clrw sp@- | pad SR 259 moveml #0xC0C0,sp@- | save scratch regs 260 movw sp@(24),sp@- | push exception vector info 261 clrw sp@- 262 movl sp@(24),sp@- | and PC 263 jbsr _straytrap | report 264 addql #8,sp | pop args 265 moveml sp@+,#0x0303 | restore regs 266 addql #2,sp | pop padding 267 jra rei | all done 268 269 .globl _syscall 270_trap0: 271 clrw sp@- | pad SR to longword 272 moveml #0xFFFF,sp@- | save user registers 273 movl usp,a0 | save the user SP 274 movl a0,sp@(60) | in the savearea 275 movl d0,sp@- | push syscall number 276 jbsr _syscall | handle it 277 addql #4,sp | pop syscall arg 278 movl sp@(60),a0 | grab and restore 279 movl a0,usp | user SP 280 moveml sp@+,#0x7FFF | restore most registers 281 addql #6,sp | pop SSP and align word 282 jra rei | all done 283 284/* 285 * trap1 is sigreturn and trap2 is breakpoint. 286 */ 287_trap1: 288 jra sigreturn | trap1 is sigreturn 289 290_trap2: 291 jra _trace | trap2 is breakpoint 292 293/* 294 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD) 295 * cachectl(command, addr, length) 296 * command in d0, addr in a1, length in d1 297 */ 298 .globl _cachectl 299_trap12: 300 movl d1,sp@- | push length 301 movl a1,sp@- | push addr 302 movl d0,sp@- | push command 303 jbsr _cachectl | do it 304 lea sp@(12),sp | pop args 305 jra rei | all done 306 307/* 308 * Trap 15 is used for: 309 * - KGDB traps 310 * - trace traps for SUN binaries (not fully supported yet) 311 * We just pass it on and let trap() sort it all out 312 */ 313_trap15: 314 clrw sp@- 315 moveml #0xFFFF,sp@- 316#ifdef KGDB 317 moveq #T_TRAP15,d0 318 movl sp@(64),d1 | from user mode? 319 andl #PSL_S,d1 320 jeq fault 321 movl d0,sp@- 322 .globl _kgdb_trap_glue 323 jbsr _kgdb_trap_glue | returns if no debugger 324 addl #4,sp 325#endif 326 moveq #T_TRAP15,d0 327 jra fault 328 329/* 330 * Hit a breakpoint (trap 1 or 2) instruction. 331 * Push the code and treat as a normal fault. 332 */ 333_trace: 334 clrw sp@- 335 moveml #0xFFFF,sp@- 336#ifdef KGDB 337 moveq #T_TRACE,d0 338 movl sp@(64),d1 | from user mode? 339 andl #PSL_S,d1 340 jeq fault 341 movl d0,sp@- 342 jbsr _kgdb_trap_glue | returns if no debugger 343 addl #4,sp 344#endif 345 moveq #T_TRACE,d0 346 jra fault 347 348/* 349 * The sigreturn() syscall comes here. It requires special handling 350 * because we must open a hole in the stack to fill in the (possibly much 351 * larger) original stack frame. 352 */ 353sigreturn: 354 lea sp@(-84),sp | leave enough space for largest frame 355 movl sp@(84),sp@ | move up current 8 byte frame 356 movl sp@(88),sp@(4) 357 movw #84,sp@- | default: adjust by 84 bytes 358 moveml #0xFFFF,sp@- | save user registers 359 movl usp,a0 | save the user SP 360 movl a0,sp@(60) | in the savearea 361 movl #SYS_sigreturn,sp@- | push syscall number 362 jbsr _syscall | handle it 363 addql #4,sp | pop syscall# 364 movl sp@(60),a0 | grab and restore 365 movl a0,usp | user SP 366 lea sp@(64),a1 | pointer to HW frame 367 movw a1@+,d0 | do we need to adjust the stack? 368 jeq Lsigr1 | no, just continue 369 moveq #92,d1 | total size 370 subw d0,d1 | - hole size = frame size 371 lea a1@(92),a0 | destination 372 addw d1,a1 | source 373 lsrw #1,d1 | convert to word count 374 subqw #1,d1 | minus 1 for dbf 375Lsigrlp: 376 movw a1@-,a0@- | copy a word 377 dbf d1,Lsigrlp | continue 378 movl a0,a1 | new HW frame base 379Lsigr1: 380 movl a1,sp@(60) | new SP value 381 moveml sp@+,#0x7FFF | restore user registers 382 movl sp@,sp | and our SP 383 jra rei | all done 384 385/* 386 * Interrupt handlers. 387 * All DIO device interrupts are auto-vectored. Most can be configured 388 * to interrupt in the range IPL2 to IPL5. Here are our assignments: 389 * 390 * Level 0: Spurious: ignored. 391 * Level 1: (low XP) 392 * Level 2: SCSI 393 * Level 3: LANCE 394 * Level 4: [PC98] 395 * Level 5: Clock 396 * Level 6: RS232C 397 * Level 7: Non-maskable: parity errors, Abort SW 398 */ 399 .globl _hardclock, _nmihand 400 401_spurintr: 402 addql #1,_intrcnt+0 403 addql #1,_cnt+V_INTR 404 jra rei 405 406_lev1intr: 407 addql #1,_intrcnt+4 408 addql #1,_cnt+V_INTR 409 jra rei | XP not surpported yet XXXX 410 411_lev2intr: 412 addql #1,_intrcnt+8 413 clrw sp@- 414 moveml #0xC0C0,sp@- 415 jbsr __scintr 416 moveml sp@+,#0x0303 417 addql #2,sp 418 addql #1,_cnt+V_INTR 419 jra rei 420 421_lev3intr: 422 addql #1,_intrcnt+12 423 clrw sp@- 424 moveml #0xC0C0,sp@- 425 jbsr __leintr 426 moveml sp@+,#0x0303 427 addql #2,sp 428 addql #1,_cnt+V_INTR 429 jra rei 430 431_lev4intr: 432 addql #1,_intrcnt+16 433 addql #1,_cnt+V_INTR 434 jra rei | EX-PC not surpported yet XXXX 435 436_lev6intr: 437 addql #1,_intrcnt+24 438 clrw sp@- 439 moveml #0xC0C0,sp@- 440 jbsr _siointr 441 moveml sp@+,#0x0303 442 addql #2,sp 443 addql #1,_cnt+V_INTR 444 jra rei 445 446_lev5intr: 447 clrw sp@- 448 moveml #0xC0C0,sp@- 449#ifdef DEBUG 450 .globl _panicstr, _regdump, _panic 451 cmpl #_kstack+NBPG,sp | are we still in stack pages? 452 jcc Lstackok | yes, continue normally 453 tstl _curproc | if !curproc could have swtch_exit'ed, 454 jeq Lstackok | might be on tmpstk 455 tstl _panicstr | have we paniced? 456 jne Lstackok | yes, do not re-panic 457 lea tmpstk,sp | no, switch to tmpstk 458 moveml #0xFFFF,sp@- | push all registers 459 movl #Lstkrip,sp@- | push panic message 460 jbsr _printf | preview 461 addql #4,sp 462 movl sp,a0 | remember this spot 463 movl #256,sp@- | longword count 464 movl a0,sp@- | and reg pointer 465 jbsr _regdump | dump core 466 addql #8,sp | pop params 467 movl #Lstkrip,sp@- | push panic message 468 jbsr _panic | ES and D 469Lstkrip: 470 .asciz "k-stack overflow" 471 .even 472Lstackok: 473#endif 474 btst #CLK_INT,CLOCK_REG | check system clock-intr 475 jeq Lnottimer 476 movb #CLK_CLR,CLOCK_REG | clear system clock interrupt 477 tstl _clock_on | clock not yet started 478 jeq Lnottimer 479 lea sp@(16),a1 | get pointer to PS 480 movl a1@,sp@- | push padded PS 481 movl a1@(4),sp@- | push PC 482 jbsr _hardclock | call generic clock int routine 483 addql #8,sp | pop params 484Lnottimer: 485 addql #1,_intrcnt+28 | add another system clock interrupt 486 moveml sp@+,#0x0303 | restore scratch regs 487 addql #2,sp | pop pad word 488 addql #1,_cnt+V_INTR | chalk up another interrupt 489 jra rei | all done 490 491_lev7intr: 492 addql #1,_intrcnt+36 493 clrw sp@- | pad SR to longword 494 moveml #0xFFFF,sp@- | save registers 495 movl usp,a0 | and save 496 movl a0,sp@(60) | the user stack pointer 497 jbsr _nmihand | call handler 498 movl sp@(60),a0 | restore 499 movl a0,usp | user SP 500 moveml sp@+,#0x7FFF | and remaining registers 501 addql #6,sp | pop SSP and align word 502 jra rei | all done 503 504/* 505 * Emulation of VAX REI instruction. 506 * 507 * This code deals with checking for and servicing ASTs 508 * (profiling, scheduling) and software interrupts (network, softclock). 509 * We check for ASTs first, just like the VAX. To avoid excess overhead 510 * the T_ASTFLT handling code will also check for software interrupts so we 511 * do not have to do it here. 512 * 513 * This code is complicated by the fact that sendsig may have been called 514 * necessitating a stack cleanup. 515 */ 516 .comm _ssir,1 517 .globl _astpending 518rei: 519#ifdef DEBUG 520 tstl _panicstr | have we paniced? 521 jne Ldorte | yes, do not make matters worse 522#endif 523 tstl _astpending | AST pending? 524 jeq Lchksir | no, go check for SIR 525Lrei1: 526 btst #5,sp@ | yes, are we returning to user mode? 527 jne Lchksir | no, go check for SIR 528 clrw sp@- | pad SR to longword 529 moveml #0xFFFF,sp@- | save all registers 530 movl usp,a1 | including 531 movl a1,sp@(60) | the users SP 532 clrl sp@- | VA == none 533 clrl sp@- | code == none 534 movl #T_ASTFLT,sp@- | type == async system trap 535 jbsr _trap | go handle it 536 lea sp@(12),sp | pop value args 537 movl sp@(60),a0 | restore user SP 538 movl a0,usp | from save area 539 movw sp@(64),d0 | need to adjust stack? 540 jne Laststkadj | yes, go to it 541 moveml sp@+,#0x7FFF | no, restore most user regs 542 addql #6,sp | toss SSP and pad 543 rte | and do real RTE 544Laststkadj: 545 lea sp@(66),a1 | pointer to HW frame 546 addql #8,a1 | source pointer 547 movl a1,a0 | source 548 addw d0,a0 | + hole size = dest pointer 549 movl a1@-,a0@- | copy 550 movl a1@-,a0@- | 8 bytes 551 movl a0,sp@(60) | new SSP 552 moveml sp@+,#0x7FFF | restore user registers 553 movl sp@,sp | and our SP 554 rte | and return 555Lchksir: 556 tstb _ssir | SIR pending? 557 jeq Ldorte | no, all done 558 movl d0,sp@- | need a scratch register 559 movw sp@(4),d0 | get SR 560 andw #PSL_IPL7,d0 | mask all but IPL 561 jne Lnosir | came from interrupt, no can do 562 movl sp@+,d0 | restore scratch register 563Lgotsir: 564 movw #SPL1,sr | prevent others from servicing int 565 tstb _ssir | too late? 566 jeq Ldorte | yes, oh well... 567 clrw sp@- | pad SR to longword 568 moveml #0xFFFF,sp@- | save all registers 569 movl usp,a1 | including 570 movl a1,sp@(60) | the users SP 571 clrl sp@- | VA == none 572 clrl sp@- | code == none 573 movl #T_SSIR,sp@- | type == software interrupt 574 jbsr _trap | go handle it 575 lea sp@(12),sp | pop value args 576 movl sp@(60),a0 | restore 577 movl a0,usp | user SP 578 moveml sp@+,#0x7FFF | and all remaining registers 579 addql #6,sp | pop SSP and align word 580 rte 581Lnosir: 582 movl sp@+,d0 | restore scratch register 583Ldorte: 584 rte | real return 585 586/* 587 * Kernel access to the current processes kernel stack is via a fixed 588 * virtual address. It is at the same address as in the users VA space. 589 * Umap contains the KVA of the first of UPAGES PTEs mapping VA _kstack. 590 */ 591 .data 592 .set _kstack,KERNELSTACK | KERNELSTACK(0x3ff00000) != USRSTACK 593_Umap: .long 0 594 .globl _kstack, _Umap 595 596/* 597 * Initialization 598 * 599 * Kernel is loaded at 0. 600 * VBR contains zero from ROM. Exceptions will continue to vector 601 * through ROM until MMU is turned on at which time they will vector 602 * through our table (vectors.s). 603 */ 604 .comm _lowram,4 605 606 .text 607 .globl _edata 608 .globl _etext,_end 609 .globl start 610start: 611 movw #PSL_HIGHIPL,sr | no interrupts 612 lea tmpstk,sp | give ourselves a temporary stack 613 clrl d0 | XXXX if loader set vbr = 0 614 movc d0,vbr | XXXX please remove these 2 lines 615/* 616 * a5 contains parameters address from booter. 617 * First, we copy parameters to save area. 618 * (Now just save maxmem and so on. Not complete yet.) XXXX 619 */ 620 movl a5@(KI_MAXADDR),d0 | maxaddr 621 moveq #PGSHIFT,d1 622 lsrl d1,d0 | convert to page (click) number 623 movl d0,_maxmem | argument saved in maxmem 624 movl d0,_physmem | physmem = maxmem 625 clrl _lowram | lowram = 0 626 movl #0,a5 | kernel is loaded at 0 627 movl #CACHE_OFF,d0 628 movc d0,cacr | clear and disable on-chip cache(s) 629 630/* initialize source/destination control registers for movs */ 631 moveq #FC_USERD,d0 | user space 632 movc d0,sfc | as source 633 movc d0,dfc | and destination of transfers 634 635/* 636 * LUNA PIO initialization. 637 */ 638 movb #PIO_MODED,PIO0_CTL | read dipswitch 639 movb PIO0_B,d0 | dipsw-2 (from portB) 640 lsll #8,d0 641 movb PIO0_A,d0 | dipsw-1 (from portA) 642 movw d0,_dipswitch 643 644/* configure kernel and proc0 VA space so we can get going */ 645 .globl _Sysseg, _pmap_bootstrap, _avail_start 646 movl #_end,d5 | end of static kernel text/data 647 addl #NBPG-1,d5 648 andl #PG_FRAME,d5 | round to a page 649 movl d5,a4 | PA=VA 650 pea a5@ | firstpa 651 pea a4@ | nextpa 652 jbsr _pmap_bootstrap | bootstrap(firstpa, nextpa) 653 addql #8,sp 654 655/* 656 * Prepare to enable MMU. 657 */ 658 movl _Sysseg,a1 | system segment table addr read value (a KVA) 659 lea _protorp,a0 660 movl #0x80000202,a0@ | nolimit + share global + 4 byte PTEs 661 movl a1,a0@(4) | + segtable address 662 pmove a0@,srp | load the supervisor root pointer 663 movl #0x80000002,a0@ | reinit upper half for CRP loads 664/* we must set tt-registers here */ 665 lea _protott0,a0 666 .word 0xf010 | pmove a0@,mmutt0 667 .word 0x0800 668 lea _protott1,a0 669 .word 0xf010 | pmove a0@,mmutt1 670 .word 0x0c00 671 movl #0x82c0aa00,a2@ | value to load TC with 672 pmove a2@,tc | load it 673 674/* 675 * Should be running mapped from this point on 676 */ 677#ifdef FPCOPROC 678/* fpp check */ 679 movl a1,sp@- 680 jbsr _checkfpp | check fpp 681 frestore _fppnull | reset 682 movl sp@+,a1 683#endif 684/* select the software page size now */ 685 lea tmpstk,sp | temporary stack 686 jbsr _vm_set_page_size | select software page size 687#ifdef BOOTDEBUG 688 movl a5,sp@- | phys load address (assumes VA 0) 689 movl a4,sp@- | first available PA 690 jbsr _Opmap_bootstrap | sync up pmap module 691 addql #8,sp 692#endif 693/* set kernel stack, user SP, and initial pcb */ 694 lea _kstack,a1 | proc0 kernel stack 695 lea a1@(UPAGES*NBPG-4),sp | set kernel stack to end of area 696 movl #USRSTACK-4,a2 697 movl a2,usp | init user SP 698 movl _proc0paddr,a1 | get proc0 pcb addr 699 movl a1,_curpcb | proc0 is running 700 clrw a1@(PCB_FLAGS) | clear flags 701#ifdef FPCOPROC 702 clrl a1@(PCB_FPCTX) | ensure null FP context 703 movl a1,sp@- 704 jbsr _m68881_restore | restore it (does not kill a1) 705 addql #4,sp 706#endif 707/* flush TLB and turn on caches */ 708 jbsr _TBIA | invalidate TLB 709 movl #CACHE_ON,d0 710 movc d0,cacr | clear cache(s) 711/* final setup for C code */ 712 movw #PSL_LOWIPL,sr | lower SPL 713 movl d7,_boothowto | save reboot flags 714 movl d6,_bootdev | and boot device 715 jbsr _main | call main() 716 717/* proc[1] == init now running here; 718 * create a null exception frame and return to user mode in icode 719 */ 720 clrw sp@- | vector offset/frame type 721 clrl sp@- | return to icode location 0 722 movw #PSL_USER,sp@- | in user mode 723 rte 724 725/* 726 * Signal "trampoline" code (18 bytes). Invoked from RTE setup by sendsig(). 727 * 728 * Stack looks like: 729 * 730 * sp+0 -> signal number 731 * sp+4 signal specific code 732 * sp+8 pointer to signal context frame (scp) 733 * sp+12 address of handler 734 * sp+16 saved hardware state 735 * . 736 * . 737 * scp+0-> beginning of signal context frame 738 */ 739 .globl _sigcode, _esigcode 740 .data 741_sigcode: 742 movl sp@(12),a0 | signal handler addr (4 bytes) 743 jsr a0@ | call signal handler (2 bytes) 744 addql #4,sp | pop signo (2 bytes) 745 trap #1 | special syscall entry (2 bytes) 746 movl d0,sp@(4) | save errno (4 bytes) 747 moveq #1,d0 | syscall == exit (2 bytes) 748 trap #0 | exit(errno) (2 bytes) 749 .align 2 750_esigcode: 751 752/* 753 * Icode is copied out to process 1 to exec init. 754 * If the exec fails, process 1 exits. 755 */ 756 .globl _icode,_szicode 757 .text 758_icode: 759 clrl sp@- 760 pea pc@((argv-.)+2) 761 pea pc@((init-.)+2) 762 clrl sp@- 763 moveq #SYS_execve,d0 764 trap #0 765 moveq #SYS_exit,d0 766 trap #0 767init: 768 .asciz "/sbin/init" 769 .even 770argv: 771 .long init+6-_icode | argv[0] = "init" ("/sbin/init" + 6) 772 .long eicode-_icode | argv[1] follows icode after copyout 773 .long 0 774eicode: 775 776_szicode: 777 .long _szicode-_icode 778 779/* 780 * Primitives 781 */ 782 783#ifdef GPROF 784#define ENTRY(name) \ 785 .globl _/**/name; _/**/name: link a6,#0; jbsr mcount; unlk a6 786#define ALTENTRY(name, rname) \ 787 ENTRY(name); jra rname+12 788#else 789#define ENTRY(name) \ 790 .globl _/**/name; _/**/name: 791#define ALTENTRY(name, rname) \ 792 .globl _/**/name; _/**/name: 793#endif 794 795/* 796 * copyinstr(fromaddr, toaddr, maxlength, &lencopied) 797 * 798 * Copy a null terminated string from the user address space into 799 * the kernel address space. 800 * NOTE: maxlength must be < 64K 801 */ 802ENTRY(copyinstr) 803 movl _curpcb,a0 | current pcb 804 movl #Lcisflt1,a0@(PCB_ONFAULT) | set up to catch faults 805 movl sp@(4),a0 | a0 = fromaddr 806 movl sp@(8),a1 | a1 = toaddr 807 moveq #0,d0 808 movw sp@(14),d0 | d0 = maxlength 809 jlt Lcisflt1 | negative count, error 810 jeq Lcisdone | zero count, all done 811 subql #1,d0 | set up for dbeq 812Lcisloop: 813 movsb a0@+,d1 | grab a byte 814 nop 815 movb d1,a1@+ | copy it 816 dbeq d0,Lcisloop | if !null and more, continue 817 jne Lcisflt2 | ran out of room, error 818 moveq #0,d0 | got a null, all done 819Lcisdone: 820 tstl sp@(16) | return length desired? 821 jeq Lcisret | no, just return 822 subl sp@(4),a0 | determine how much was copied 823 movl sp@(16),a1 | return location 824 movl a0,a1@ | stash it 825Lcisret: 826 movl _curpcb,a0 | current pcb 827 clrl a0@(PCB_ONFAULT) | clear fault addr 828 rts 829Lcisflt1: 830 moveq #EFAULT,d0 | copy fault 831 jra Lcisdone 832Lcisflt2: 833 moveq #ENAMETOOLONG,d0 | ran out of space 834 jra Lcisdone 835 836/* 837 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied) 838 * 839 * Copy a null terminated string from the kernel 840 * address space to the user address space. 841 * NOTE: maxlength must be < 64K 842 */ 843ENTRY(copyoutstr) 844 movl _curpcb,a0 | current pcb 845 movl #Lcosflt1,a0@(PCB_ONFAULT) | set up to catch faults 846 movl sp@(4),a0 | a0 = fromaddr 847 movl sp@(8),a1 | a1 = toaddr 848 moveq #0,d0 849 movw sp@(14),d0 | d0 = maxlength 850 jlt Lcosflt1 | negative count, error 851 jeq Lcosdone | zero count, all done 852 subql #1,d0 | set up for dbeq 853Lcosloop: 854 movb a0@+,d1 | grab a byte 855 movsb d1,a1@+ | copy it 856 nop 857 dbeq d0,Lcosloop | if !null and more, continue 858 jne Lcosflt2 | ran out of room, error 859 moveq #0,d0 | got a null, all done 860Lcosdone: 861 tstl sp@(16) | return length desired? 862 jeq Lcosret | no, just return 863 subl sp@(4),a0 | determine how much was copied 864 movl sp@(16),a1 | return location 865 movl a0,a1@ | stash it 866Lcosret: 867 movl _curpcb,a0 | current pcb 868 clrl a0@(PCB_ONFAULT) | clear fault addr 869 rts 870Lcosflt1: 871 moveq #EFAULT,d0 | copy fault 872 jra Lcosdone 873Lcosflt2: 874 moveq #ENAMETOOLONG,d0 | ran out of space 875 jra Lcosdone 876 877/* 878 * copystr(fromaddr, toaddr, maxlength, &lencopied) 879 * 880 * Copy a null terminated string from one point to another in 881 * the kernel address space. 882 * NOTE: maxlength must be < 64K 883 */ 884ENTRY(copystr) 885 movl sp@(4),a0 | a0 = fromaddr 886 movl sp@(8),a1 | a1 = toaddr 887 moveq #0,d0 888 movw sp@(14),d0 | d0 = maxlength 889 jlt Lcsflt1 | negative count, error 890 jeq Lcsdone | zero count, all done 891 subql #1,d0 | set up for dbeq 892Lcsloop: 893 movb a0@+,a1@+ | copy a byte 894 dbeq d0,Lcsloop | if !null and more, continue 895 jne Lcsflt2 | ran out of room, error 896 moveq #0,d0 | got a null, all done 897Lcsdone: 898 tstl sp@(16) | return length desired? 899 jeq Lcsret | no, just return 900 subl sp@(4),a0 | determine how much was copied 901 movl sp@(16),a1 | return location 902 movl a0,a1@ | stash it 903Lcsret: 904 rts 905Lcsflt1: 906 moveq #EFAULT,d0 | copy fault 907 jra Lcsdone 908Lcsflt2: 909 moveq #ENAMETOOLONG,d0 | ran out of space 910 jra Lcsdone 911 912/* 913 * Copyin(from, to, len) 914 * 915 * Copy specified amount of data from user space into the kernel. 916 * NOTE: len must be < 64K 917 */ 918ENTRY(copyin) 919 movl d2,sp@- | scratch register 920 movl _curpcb,a0 | current pcb 921 movl #Lciflt,a0@(PCB_ONFAULT) | set up to catch faults 922 movl sp@(16),d2 | check count 923 jlt Lciflt | negative, error 924 jeq Lcidone | zero, done 925 movl sp@(8),a0 | src address 926 movl sp@(12),a1 | dest address 927 movl a0,d0 928 btst #0,d0 | src address odd? 929 jeq Lcieven | no, go check dest 930 movsb a0@+,d1 | yes, get a byte 931 nop 932 movb d1,a1@+ | put a byte 933 subql #1,d2 | adjust count 934 jeq Lcidone | exit if done 935Lcieven: 936 movl a1,d0 937 btst #0,d0 | dest address odd? 938 jne Lcibyte | yes, must copy by bytes 939 movl d2,d0 | no, get count 940 lsrl #2,d0 | convert to longwords 941 jeq Lcibyte | no longwords, copy bytes 942 subql #1,d0 | set up for dbf 943Lcilloop: 944 movsl a0@+,d1 | get a long 945 nop 946 movl d1,a1@+ | put a long 947 dbf d0,Lcilloop | til done 948 andl #3,d2 | what remains 949 jeq Lcidone | all done 950Lcibyte: 951 subql #1,d2 | set up for dbf 952Lcibloop: 953 movsb a0@+,d1 | get a byte 954 nop 955 movb d1,a1@+ | put a byte 956 dbf d2,Lcibloop | til done 957Lcidone: 958 moveq #0,d0 | success 959Lciexit: 960 movl _curpcb,a0 | current pcb 961 clrl a0@(PCB_ONFAULT) | clear fault catcher 962 movl sp@+,d2 | restore scratch reg 963 rts 964Lciflt: 965 moveq #EFAULT,d0 | got a fault 966 jra Lciexit 967 968/* 969 * Copyout(from, to, len) 970 * 971 * Copy specified amount of data from kernel to the user space 972 * NOTE: len must be < 64K 973 */ 974ENTRY(copyout) 975 movl d2,sp@- | scratch register 976 movl _curpcb,a0 | current pcb 977 movl #Lcoflt,a0@(PCB_ONFAULT) | catch faults 978 movl sp@(16),d2 | check count 979 jlt Lcoflt | negative, error 980 jeq Lcodone | zero, done 981 movl sp@(8),a0 | src address 982 movl sp@(12),a1 | dest address 983 movl a0,d0 984 btst #0,d0 | src address odd? 985 jeq Lcoeven | no, go check dest 986 movb a0@+,d1 | yes, get a byte 987 movsb d1,a1@+ | put a byte 988 nop 989 subql #1,d2 | adjust count 990 jeq Lcodone | exit if done 991Lcoeven: 992 movl a1,d0 993 btst #0,d0 | dest address odd? 994 jne Lcobyte | yes, must copy by bytes 995 movl d2,d0 | no, get count 996 lsrl #2,d0 | convert to longwords 997 jeq Lcobyte | no longwords, copy bytes 998 subql #1,d0 | set up for dbf 999Lcolloop: 1000 movl a0@+,d1 | get a long 1001 movsl d1,a1@+ | put a long 1002 nop 1003 dbf d0,Lcolloop | til done 1004 andl #3,d2 | what remains 1005 jeq Lcodone | all done 1006Lcobyte: 1007 subql #1,d2 | set up for dbf 1008Lcobloop: 1009 movb a0@+,d1 | get a byte 1010 movsb d1,a1@+ | put a byte 1011 nop 1012 dbf d2,Lcobloop | til done 1013Lcodone: 1014 moveq #0,d0 | success 1015Lcoexit: 1016 movl _curpcb,a0 | current pcb 1017 clrl a0@(PCB_ONFAULT) | clear fault catcher 1018 movl sp@+,d2 | restore scratch reg 1019 rts 1020Lcoflt: 1021 moveq #EFAULT,d0 | got a fault 1022 jra Lcoexit 1023 1024/* 1025 * non-local gotos 1026 */ 1027ENTRY(setjmp) 1028 movl sp@(4),a0 | savearea pointer 1029 moveml #0xFCFC,a0@ | save d2-d7/a2-a7 1030 movl sp@,a0@(48) | and return address 1031 moveq #0,d0 | return 0 1032 rts 1033 1034ENTRY(qsetjmp) 1035 movl sp@(4),a0 | savearea pointer 1036 lea a0@(40),a0 | skip regs we do not save 1037 movl a6,a0@+ | save FP 1038 movl sp,a0@+ | save SP 1039 movl sp@,a0@ | and return address 1040 moveq #0,d0 | return 0 1041 rts 1042 1043ENTRY(longjmp) 1044 movl sp@(4),a0 1045 moveml a0@+,#0xFCFC 1046 movl a0@,sp@ 1047 moveq #1,d0 1048 rts 1049 1050/* 1051 * The following primitives manipulate the run queues. 1052 * _whichqs tells which of the 32 queues _qs 1053 * have processes in them. Setrq puts processes into queues, Remrq 1054 * removes them from queues. The running process is on no queue, 1055 * other processes are on a queue related to p->p_pri, divided by 4 1056 * actually to shrink the 0-127 range of priorities into the 32 available 1057 * queues. 1058 */ 1059 1060 .globl _whichqs,_qs,_cnt,_panic 1061 .globl _curproc,_want_resched 1062 1063/* 1064 * Setrq(p) 1065 * 1066 * Call should be made at spl6(), and p->p_stat should be SRUN 1067 */ 1068ENTRY(setrq) 1069 movl sp@(4),a0 1070 tstl a0@(P_RLINK) 1071 jeq Lset1 1072 movl #Lset2,sp@- 1073 jbsr _panic 1074Lset1: 1075 clrl d0 1076 movb a0@(P_PRI),d0 1077 lsrb #2,d0 1078 movl _whichqs,d1 1079 bset d0,d1 1080 movl d1,_whichqs 1081 lslb #3,d0 1082 addl #_qs,d0 1083 movl d0,a0@(P_LINK) 1084 movl d0,a1 1085 movl a1@(P_RLINK),a0@(P_RLINK) 1086 movl a0,a1@(P_RLINK) 1087 movl a0@(P_RLINK),a1 1088 movl a0,a1@(P_LINK) 1089 rts 1090 1091Lset2: 1092 .asciz "setrq" 1093 .even 1094 1095/* 1096 * Remrq(p) 1097 * 1098 * Call should be made at spl6(). 1099 */ 1100ENTRY(remrq) 1101 movl sp@(4),a0 1102 clrl d0 1103 movb a0@(P_PRI),d0 1104 lsrb #2,d0 1105 movl _whichqs,d1 1106 bclr d0,d1 1107 jne Lrem1 1108 movl #Lrem3,sp@- 1109 jbsr _panic 1110Lrem1: 1111 movl d1,_whichqs 1112 movl a0@(P_LINK),a1 1113 movl a0@(P_RLINK),a1@(P_RLINK) 1114 movl a0@(P_RLINK),a1 1115 movl a0@(P_LINK),a1@(P_LINK) 1116 movl #_qs,a1 1117 movl d0,d1 1118 lslb #3,d1 1119 addl d1,a1 1120 cmpl a1@(P_LINK),a1 1121 jeq Lrem2 1122 movl _whichqs,d1 1123 bset d0,d1 1124 movl d1,_whichqs 1125Lrem2: 1126 clrl a0@(P_RLINK) 1127 rts 1128 1129Lrem3: 1130 .asciz "remrq" 1131Lsw0: 1132 .asciz "swtch" 1133 .even 1134 1135 .globl _curpcb 1136 .globl _masterpaddr | XXX compatibility (debuggers) 1137 .data 1138_masterpaddr: | XXX compatibility (debuggers) 1139_curpcb: 1140 .long 0 1141pcbflag: 1142 .byte 0 | copy of pcb_flags low byte 1143 .align 2 1144 .comm nullpcb,SIZEOF_PCB 1145 .text 1146 1147/* 1148 * At exit of a process, do a swtch for the last time. 1149 * The mapping of the pcb at p->p_addr has already been deleted, 1150 * and the memory for the pcb+stack has been freed. 1151 * The ipl is high enough to prevent the memory from being reallocated. 1152 */ 1153ENTRY(swtch_exit) 1154 movl #nullpcb,_curpcb | save state into garbage pcb 1155 lea tmpstk,sp | goto a tmp stack 1156 jra _cpu_swtch 1157 1158/* 1159 * When no processes are on the runq, Swtch branches to idle 1160 * to wait for something to come ready. 1161 */ 1162 .globl Idle 1163Lidle: 1164 stop #PSL_LOWIPL 1165Idle: 1166idle: 1167 movw #PSL_HIGHIPL,sr 1168 tstl _whichqs 1169 jeq Lidle 1170 movw #PSL_LOWIPL,sr 1171 jra Lsw1 1172 1173Lbadsw: 1174 movl #Lsw0,sp@- 1175 jbsr _panic 1176 /*NOTREACHED*/ 1177 1178/* 1179 * cpu_swtch() 1180 * 1181 * NOTE: On the mc68851 (318/319/330) we attempt to avoid flushing the 1182 * entire ATC. The effort involved in selective flushing may not be 1183 * worth it, maybe we should just flush the whole thing? 1184 * 1185 * NOTE 2: With the new VM layout we now no longer know if an inactive 1186 * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag 1187 * bit). For now, we just always flush the full ATC. 1188 */ 1189ENTRY(cpu_swtch) 1190 movl _curpcb,a0 | current pcb 1191 movw sr,a0@(PCB_PS) | save sr before changing ipl 1192#ifdef notyet 1193 movl _curproc,sp@- | remember last proc running 1194#endif 1195 clrl _curproc 1196 addql #1,_cnt+V_SWTCH 1197 1198Lsw1: 1199 /* 1200 * Find the highest-priority queue that isn't empty, 1201 * then take the first proc from that queue. 1202 */ 1203 clrl d0 1204 lea _whichqs,a0 1205 movl a0@,d1 1206Lswchk: 1207 btst d0,d1 1208 jne Lswfnd 1209 addqb #1,d0 1210 cmpb #32,d0 1211 jne Lswchk 1212 jra idle 1213Lswfnd: 1214 movw #PSL_HIGHIPL,sr | lock out interrupts 1215 movl a0@,d1 | and check again... 1216 bclr d0,d1 1217 jeq Lsw1 | proc moved, rescan 1218 movl d1,a0@ | update whichqs 1219 moveq #1,d1 | double check for higher priority 1220 lsll d0,d1 | process (which may have snuck in 1221 subql #1,d1 | while we were finding this one) 1222 andl a0@,d1 1223 jeq Lswok | no one got in, continue 1224 movl a0@,d1 1225 bset d0,d1 | otherwise put this one back 1226 movl d1,a0@ 1227 jra Lsw1 | and rescan 1228Lswok: 1229 movl d0,d1 1230 lslb #3,d1 | convert queue number to index 1231 addl #_qs,d1 | locate queue (q) 1232 movl d1,a1 1233 cmpl a1@(P_LINK),a1 | anyone on queue? 1234 jeq Lbadsw | no, panic 1235 movl a1@(P_LINK),a0 | p = q->p_link 1236 movl a0@(P_LINK),a1@(P_LINK) | q->p_link = p->p_link 1237 movl a0@(P_LINK),a1 | q = p->p_link 1238 movl a0@(P_RLINK),a1@(P_RLINK) | q->p_rlink = p->p_rlink 1239 cmpl a0@(P_LINK),d1 | anyone left on queue? 1240 jeq Lsw2 | no, skip 1241 movl _whichqs,d1 1242 bset d0,d1 | yes, reset bit 1243 movl d1,_whichqs 1244Lsw2: 1245 movl a0,_curproc 1246 clrl _want_resched 1247#ifdef notyet 1248 movl sp@+,a1 1249 cmpl a0,a1 | switching to same proc? 1250 jeq Lswdone | yes, skip save and restore 1251#endif 1252 /* 1253 * Save state of previous process in its pcb. 1254 */ 1255 movl _curpcb,a1 1256 moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers 1257 movl usp,a2 | grab USP (a2 has been saved) 1258 movl a2,a1@(PCB_USP) | and save it 1259#ifdef FPCOPROC 1260 lea a1@(PCB_FPCTX),a2 | pointer to FP save area 1261 fsave a2@ | save FP state 1262 tstb a2@ | null state frame? 1263 jeq Lswnofpsave | yes, all done 1264 fmovem fp0-fp7,a2@(216) | save FP general registers 1265 fmovem fpcr/fpsr/fpi,a2@(312) | save FP control registers 1266Lswnofpsave: 1267#endif 1268 1269#ifdef DIAGNOSTIC 1270 tstl a0@(P_WCHAN) 1271 jne Lbadsw 1272 cmpb #SRUN,a0@(P_STAT) 1273 jne Lbadsw 1274#endif 1275 clrl a0@(P_RLINK) | clear back link 1276 movl a0@(P_ADDR),a1 | get p_addr 1277 movl a1,_curpcb 1278 movb a1@(PCB_FLAGS+1),pcbflag | copy of pcb_flags low byte 1279 1280 /* see if pmap_activate needs to be called; should remove this */ 1281 movl a0@(P_VMSPACE),a0 | vmspace = p->p_vmspace 1282#ifdef DIAGNOSTIC 1283 tstl a0 | map == VM_MAP_NULL? 1284 jeq Lbadsw | panic 1285#endif 1286 lea a0@(VM_PMAP),a0 | pmap = &vmspace.vm_pmap 1287 tstl a0@(PM_STCHG) | pmap->st_changed? 1288 jeq Lswnochg | no, skip 1289 pea a1@ | push pcb (at p_addr) 1290 pea a0@ | push pmap 1291 jbsr _pmap_activate | pmap_activate(pmap, pcb) 1292 addql #8,sp 1293 movl _curpcb,a1 | restore p_addr 1294Lswnochg: 1295 1296 movl #PGSHIFT,d1 1297 movl a1,d0 1298 lsrl d1,d0 | convert p_addr to page number 1299 lsll #2,d0 | and now to Sysmap offset 1300 addl _Sysmap,d0 | add Sysmap base to get PTE addr 1301#ifdef notdef 1302 movw #PSL_HIGHIPL,sr | go crit while changing PTEs 1303#endif 1304 lea tmpstk,sp | now goto a tmp stack for NMI 1305 movl d0,a0 | address of new context 1306 movl _Umap,a2 | address of PTEs for kstack 1307 moveq #UPAGES-1,d0 | sizeof kstack 1308Lres1: 1309 movl a0@+,d1 | get PTE 1310 andl #~PG_PROT,d1 | mask out old protection 1311 orl #PG_RW+PG_V,d1 | ensure valid and writable 1312 movl d1,a2@+ | load it up 1313 dbf d0,Lres1 | til done 1314 movl #CACHE_CLR,d0 1315 movc d0,cacr | invalidate cache(s) 1316 pflusha | flush entire TLB 1317 movl a1@(PCB_USTP),d0 | get USTP 1318 moveq #PGSHIFT,d1 1319 lsll d1,d0 | convert to addr 1320 lea _protorp,a0 | CRP prototype 1321 movl d0,a0@(4) | stash USTP 1322 pmove a0@,crp | load new user root pointer 1323 moveml a1@(PCB_REGS),#0xFCFC | and registers 1324 movl a1@(PCB_USP),a0 1325 movl a0,usp | and USP 1326#ifdef FPCOPROC 1327 lea a1@(PCB_FPCTX),a0 | pointer to FP save area 1328 tstb a0@ | null state frame? 1329 jeq Lresfprest | yes, easy 1330 fmovem a0@(312),fpcr/fpsr/fpi | restore FP control registers 1331 fmovem a0@(216),fp0-fp7 | restore FP general registers 1332Lresfprest: 1333 frestore a0@ | restore state 1334#endif 1335 movw a1@(PCB_PS),sr | no, restore PS 1336 moveq #1,d0 | return 1 (for alternate returns) 1337 rts 1338 1339/* 1340 * savectx(pcb, altreturn) 1341 * Update pcb, saving current processor state and arranging 1342 * for alternate return ala longjmp in swtch if altreturn is true. 1343 */ 1344ENTRY(savectx) 1345 movl sp@(4),a1 1346 movw sr,a1@(PCB_PS) 1347 movl usp,a0 | grab USP 1348 movl a0,a1@(PCB_USP) | and save it 1349 moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers 1350#ifdef FPCOPROC 1351 lea a1@(PCB_FPCTX),a0 | pointer to FP save area 1352 fsave a0@ | save FP state 1353 tstb a0@ | null state frame? 1354 jeq Lsvnofpsave | yes, all done 1355 fmovem fp0-fp7,a0@(216) | save FP general registers 1356 fmovem fpcr/fpsr/fpi,a0@(312) | save FP control registers 1357Lsvnofpsave: 1358#endif 1359 tstl sp@(8) | altreturn? 1360 jeq Lsavedone 1361 movl sp,d0 | relocate current sp relative to a1 1362 subl #_kstack,d0 | (sp is relative to kstack): 1363 addl d0,a1 | a1 += sp - kstack; 1364 movl sp@,a1@ | write return pc at (relocated) sp@ 1365Lsavedone: 1366 moveq #0,d0 | return 0 1367 rts 1368 1369/* 1370 * {fu,su},{byte,sword,word} 1371 */ 1372ALTENTRY(fuiword, _fuword) 1373ENTRY(fuword) 1374 movl sp@(4),a0 | address to read 1375 movl _curpcb,a1 | current pcb 1376 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1377 movsl a0@,d0 | do read from user space 1378 nop 1379 jra Lfsdone 1380 1381ENTRY(fusword) 1382 movl sp@(4),a0 1383 movl _curpcb,a1 | current pcb 1384 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1385 moveq #0,d0 1386 movsw a0@,d0 | do read from user space 1387 nop 1388 jra Lfsdone 1389 1390/* Just like fusword, but tells trap code not to page in. */ 1391ENTRY(fuswintr) 1392 movl sp@(4),a0 1393 movl _curpcb,a1 1394 movl #_fswintr,a1@(PCB_ONFAULT) 1395 moveq #0,d0 1396 movsw a0@,d0 1397 nop 1398 jra Lfsdone 1399 1400ALTENTRY(fuibyte, _fubyte) 1401ENTRY(fubyte) 1402 movl sp@(4),a0 | address to read 1403 movl _curpcb,a1 | current pcb 1404 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1405 moveq #0,d0 1406 movsb a0@,d0 | do read from user space 1407 nop 1408 jra Lfsdone 1409 1410Lfserr: 1411 moveq #-1,d0 | error indicator 1412Lfsdone: 1413 clrl a1@(PCB_ONFAULT) | clear fault address 1414 rts 1415 1416/* Just like Lfserr, but the address is different (& exported). */ 1417 .globl _fswintr 1418_fswintr: 1419 moveq #-1,d0 1420 jra Lfsdone 1421 1422 1423/* 1424 * Write a longword in user instruction space. 1425 * Largely the same as suword but with a final i-cache purge on those 1426 * machines with split caches. 1427 */ 1428ENTRY(suiword) 1429 movl sp@(4),a0 | address to write 1430 movl sp@(8),d0 | value to put there 1431 movl _curpcb,a1 | current pcb 1432 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1433 movsl d0,a0@ | do write to user space 1434 nop 1435 moveq #0,d0 | indicate no fault 1436 movl #IC_CLEAR,d1 1437 movc d1,cacr | invalidate i-cache 1438 jra Lfsdone 1439 1440ENTRY(suword) 1441 movl sp@(4),a0 | address to write 1442 movl sp@(8),d0 | value to put there 1443 movl _curpcb,a1 | current pcb 1444 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1445 movsl d0,a0@ | do write to user space 1446 nop 1447 moveq #0,d0 | indicate no fault 1448 jra Lfsdone 1449 1450ENTRY(susword) 1451 movl sp@(4),a0 | address to write 1452 movw sp@(10),d0 | value to put there 1453 movl _curpcb,a1 | current pcb 1454 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1455 movsw d0,a0@ | do write to user space 1456 nop 1457 moveq #0,d0 | indicate no fault 1458 jra Lfsdone 1459 1460ENTRY(suswintr) 1461 movl sp@(4),a0 1462 movw sp@(10),d0 1463 movl _curpcb,a1 1464 movl #_fswintr,a1@(PCB_ONFAULT) 1465 movsw d0,a0@ 1466 nop 1467 moveq #0,d0 1468 jra Lfsdone 1469 1470ALTENTRY(suibyte, _subyte) 1471ENTRY(subyte) 1472 movl sp@(4),a0 | address to write 1473 movb sp@(11),d0 | value to put there 1474 movl _curpcb,a1 | current pcb 1475 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1476 movsb d0,a0@ | do write to user space 1477 nop 1478 moveq #0,d0 | indicate no fault 1479 jra Lfsdone 1480 1481/* 1482 * Invalidate entire TLB. 1483 */ 1484ENTRY(TBIA) 1485__TBIA: 1486 pflusha | flush entire TLB 1487 movl #DC_CLEAR,d0 1488 movc d0,cacr | invalidate on-chip d-cache 1489 rts 1490 1491/* 1492 * Invalidate any TLB entry for given VA (TB Invalidate Single) 1493 */ 1494ENTRY(TBIS) 1495#ifdef DEBUG 1496 tstl fulltflush | being conservative? 1497 jne __TBIA | yes, flush entire TLB 1498#endif 1499 1500 movl sp@(4),a0 | get addr to flush 1501 pflush #0,#0,a0@ | flush address from both sides 1502 movl #DC_CLEAR,d0 1503 movc d0,cacr | invalidate on-chip data cache 1504 rts 1505 1506/* 1507 * Invalidate supervisor side of TLB 1508 */ 1509ENTRY(TBIAS) 1510#ifdef DEBUG 1511 tstl fulltflush | being conservative? 1512 jne __TBIA | yes, flush everything 1513#endif 1514 pflush #4,#4 | flush supervisor TLB entries 1515 movl #DC_CLEAR,d0 1516 movc d0,cacr | invalidate on-chip d-cache 1517 rts 1518 1519/* 1520 * Invalidate user side of TLB 1521 */ 1522ENTRY(TBIAU) 1523#ifdef DEBUG 1524 tstl fulltflush | being conservative? 1525 jne __TBIA | yes, flush everything 1526#endif 1527 pflush #0,#4 | flush user TLB entries 1528 movl #DC_CLEAR,d0 1529 movc d0,cacr | invalidate on-chip d-cache 1530 rts 1531 1532/* 1533 * Invalidate instruction cache 1534 */ 1535ENTRY(ICIA) 1536 movl #IC_CLEAR,d0 1537 movc d0,cacr | invalidate i-cache 1538 rts 1539 1540ENTRY(PCIA) 1541 movl #DC_CLEAR,d0 1542 movc d0,cacr | invalidate on-chip d-cache 1543 rts 1544 1545/* 1546 * Get callers current SP value. 1547 * Note that simply taking the address of a local variable in a C function 1548 * doesn't work because callee saved registers may be outside the stack frame 1549 * defined by A6 (e.g. GCC generated code). 1550 */ 1551 .globl _getsp 1552_getsp: 1553 movl sp,d0 | get current SP 1554 addql #4,d0 | compensate for return address 1555 rts 1556 1557 .globl _getsfc, _getdfc 1558_getsfc: 1559 movc sfc,d0 1560 rts 1561_getdfc: 1562 movc dfc,d0 1563 rts 1564 1565/* 1566 * Load a new user segment table pointer. 1567 */ 1568ENTRY(loadustp) 1569 movl sp@(4),d0 | new USTP 1570 moveq #PGSHIFT,d1 1571 lsll d1,d0 | convert to addr 1572 lea _protorp,a0 | CRP prototype 1573 movl d0,a0@(4) | stash USTP 1574 pmove a0@,crp | load root pointer 1575 movl #DC_CLEAR,d0 1576 movc d0,cacr | invalidate on-chip d-cache 1577 rts 1578 1579ENTRY(ploadw) 1580 movl sp@(4),a0 | address to load 1581 ploadw #1,a0@ | pre-load translation 1582 rts 1583 1584/* 1585 * Set processor priority level calls. Most are implemented with 1586 * inline asm expansions. However, spl0 requires special handling 1587 * as we need to check for our emulated software interrupts. 1588 */ 1589 1590ENTRY(spl0) 1591 moveq #0,d0 1592 movw sr,d0 | get old SR for return 1593 movw #PSL_LOWIPL,sr | restore new SR 1594 tstb _ssir | software interrupt pending? 1595 jeq Lspldone | no, all done 1596 subql #4,sp | make room for RTE frame 1597 movl sp@(4),sp@(2) | position return address 1598 clrw sp@(6) | set frame type 0 1599 movw #PSL_LOWIPL,sp@ | and new SR 1600 jra Lgotsir | go handle it 1601Lspldone: 1602 rts 1603 1604ENTRY(_insque) 1605 movw sr,d0 1606 movw #PSL_HIGHIPL,sr | atomic 1607 movl sp@(8),a0 | where to insert (after) 1608 movl sp@(4),a1 | element to insert (e) 1609 movl a0@,a1@ | e->next = after->next 1610 movl a0,a1@(4) | e->prev = after 1611 movl a1,a0@ | after->next = e 1612 movl a1@,a0 1613 movl a1,a0@(4) | e->next->prev = e 1614 movw d0,sr 1615 rts 1616 1617ENTRY(_remque) 1618 movw sr,d0 1619 movw #PSL_HIGHIPL,sr | atomic 1620 movl sp@(4),a0 | element to remove (e) 1621 movl a0@,a1 1622 movl a0@(4),a0 1623 movl a0,a1@(4) | e->next->prev = e->prev 1624 movl a1,a0@ | e->prev->next = e->next 1625 movw d0,sr 1626 rts 1627 1628/* 1629 * bzero(addr, count) 1630 */ 1631ALTENTRY(blkclr, _bzero) 1632ENTRY(bzero) 1633 movl sp@(4),a0 | address 1634 movl sp@(8),d0 | count 1635 jeq Lbzdone | if zero, nothing to do 1636 movl a0,d1 1637 btst #0,d1 | address odd? 1638 jeq Lbzeven | no, can copy words 1639 clrb a0@+ | yes, zero byte to get to even boundary 1640 subql #1,d0 | decrement count 1641 jeq Lbzdone | none left, all done 1642Lbzeven: 1643 movl d0,d1 1644 andl #31,d0 1645 lsrl #5,d1 | convert count to 8*longword count 1646 jeq Lbzbyte | no such blocks, zero byte at a time 1647Lbzloop: 1648 clrl a0@+; clrl a0@+; clrl a0@+; clrl a0@+; 1649 clrl a0@+; clrl a0@+; clrl a0@+; clrl a0@+; 1650 subql #1,d1 | one more block zeroed 1651 jne Lbzloop | more to go, do it 1652 tstl d0 | partial block left? 1653 jeq Lbzdone | no, all done 1654Lbzbyte: 1655 clrb a0@+ 1656 subql #1,d0 | one more byte cleared 1657 jne Lbzbyte | more to go, do it 1658Lbzdone: 1659 rts 1660 1661/* 1662 * strlen(str) 1663 */ 1664ENTRY(strlen) 1665 moveq #-1,d0 1666 movl sp@(4),a0 | string 1667Lslloop: 1668 addql #1,d0 | increment count 1669 tstb a0@+ | null? 1670 jne Lslloop | no, keep going 1671 rts 1672 1673/* 1674 * bcmp(s1, s2, len) 1675 * 1676 * WARNING! This guy only works with counts up to 64K 1677 */ 1678ENTRY(bcmp) 1679 movl sp@(4),a0 | string 1 1680 movl sp@(8),a1 | string 2 1681 moveq #0,d0 1682 movw sp@(14),d0 | length 1683 jeq Lcmpdone | if zero, nothing to do 1684 subqw #1,d0 | set up for DBcc loop 1685Lcmploop: 1686 cmpmb a0@+,a1@+ | equal? 1687 dbne d0,Lcmploop | yes, keep going 1688 addqw #1,d0 | +1 gives zero on match 1689Lcmpdone: 1690 rts 1691 1692/* 1693 * {ov}bcopy(from, to, len) 1694 * 1695 * Works for counts up to 128K. 1696 */ 1697ALTENTRY(ovbcopy, _bcopy) 1698ENTRY(bcopy) 1699 movl sp@(12),d0 | get count 1700 jeq Lcpyexit | if zero, return 1701 movl sp@(4),a0 | src address 1702 movl sp@(8),a1 | dest address 1703 cmpl a1,a0 | src before dest? 1704 jlt Lcpyback | yes, copy backwards (avoids overlap) 1705 movl a0,d1 1706 btst #0,d1 | src address odd? 1707 jeq Lcfeven | no, go check dest 1708 movb a0@+,a1@+ | yes, copy a byte 1709 subql #1,d0 | update count 1710 jeq Lcpyexit | exit if done 1711Lcfeven: 1712 movl a1,d1 1713 btst #0,d1 | dest address odd? 1714 jne Lcfbyte | yes, must copy by bytes 1715 movl d0,d1 | no, get count 1716 lsrl #2,d1 | convert to longwords 1717 jeq Lcfbyte | no longwords, copy bytes 1718 subql #1,d1 | set up for dbf 1719Lcflloop: 1720 movl a0@+,a1@+ | copy longwords 1721 dbf d1,Lcflloop | til done 1722 andl #3,d0 | get remaining count 1723 jeq Lcpyexit | done if none 1724Lcfbyte: 1725 subql #1,d0 | set up for dbf 1726Lcfbloop: 1727 movb a0@+,a1@+ | copy bytes 1728 dbf d0,Lcfbloop | til done 1729Lcpyexit: 1730 rts 1731Lcpyback: 1732 addl d0,a0 | add count to src 1733 addl d0,a1 | add count to dest 1734 movl a0,d1 1735 btst #0,d1 | src address odd? 1736 jeq Lcbeven | no, go check dest 1737 movb a0@-,a1@- | yes, copy a byte 1738 subql #1,d0 | update count 1739 jeq Lcpyexit | exit if done 1740Lcbeven: 1741 movl a1,d1 1742 btst #0,d1 | dest address odd? 1743 jne Lcbbyte | yes, must copy by bytes 1744 movl d0,d1 | no, get count 1745 lsrl #2,d1 | convert to longwords 1746 jeq Lcbbyte | no longwords, copy bytes 1747 subql #1,d1 | set up for dbf 1748Lcblloop: 1749 movl a0@-,a1@- | copy longwords 1750 dbf d1,Lcblloop | til done 1751 andl #3,d0 | get remaining count 1752 jeq Lcpyexit | done if none 1753Lcbbyte: 1754 subql #1,d0 | set up for dbf 1755Lcbbloop: 1756 movb a0@-,a1@- | copy bytes 1757 dbf d0,Lcbbloop | til done 1758 rts 1759 1760/* 1761 * Emulate fancy VAX string operations: 1762 * scanc(count, startc, table, mask) 1763 * skpc(mask, count, startc) 1764 * locc(mask, count, startc) 1765 */ 1766ENTRY(scanc) 1767 movl sp@(4),d0 | get length 1768 jeq Lscdone | nothing to do, return 1769 movl sp@(8),a0 | start of scan 1770 movl sp@(12),a1 | table to compare with 1771 movb sp@(19),d1 | and mask to use 1772 movw d2,sp@- | need a scratch register 1773 clrw d2 | clear it out 1774 subqw #1,d0 | adjust for dbra 1775Lscloop: 1776 movb a0@+,d2 | get character 1777 movb a1@(0,d2:w),d2 | get table entry 1778 andb d1,d2 | mask it 1779 dbne d0,Lscloop | keep going til no more or non-zero 1780 addqw #1,d0 | overshot by one 1781 movw sp@+,d2 | restore scratch 1782Lscdone: 1783 rts 1784 1785ENTRY(skpc) 1786 movl sp@(8),d0 | get length 1787 jeq Lskdone | nothing to do, return 1788 movb sp@(7),d1 | mask to use 1789 movl sp@(12),a0 | where to start 1790 subqw #1,d0 | adjust for dbcc 1791Lskloop: 1792 cmpb a0@+,d1 | compate with mask 1793 dbne d0,Lskloop | keep going til no more or zero 1794 addqw #1,d0 | overshot by one 1795Lskdone: 1796 rts 1797 1798ENTRY(locc) 1799 movl sp@(8),d0 | get length 1800 jeq Llcdone | nothing to do, return 1801 movb sp@(7),d1 | mask to use 1802 movl sp@(12),a0 | where to start 1803 subqw #1,d0 | adjust for dbcc 1804Llcloop: 1805 cmpb a0@+,d1 | compate with mask 1806 dbeq d0,Llcloop | keep going til no more or non-zero 1807 addqw #1,d0 | overshot by one 1808Llcdone: 1809 rts 1810 1811/* 1812 * Emulate VAX FFS (find first set) instruction. 1813 */ 1814ENTRY(ffs) 1815 moveq #-1,d0 1816 movl sp@(4),d1 1817 jeq Lffsdone 1818Lffsloop: 1819 addql #1,d0 1820 btst d0,d1 1821 jeq Lffsloop 1822Lffsdone: 1823 addql #1,d0 1824 rts 1825 1826#ifdef FPCOPROC 1827/* 1828 * Save and restore 68881 state. 1829 * Pretty awful looking since our assembler does not 1830 * recognize FP mnemonics. 1831 */ 1832ENTRY(m68881_save) 1833 movl sp@(4),a0 | save area pointer 1834 fsave a0@ | save state 1835 tstb a0@ | null state frame? 1836 jeq Lm68881sdone | yes, all done 1837 fmovem fp0-fp7,a0@(216) | save FP general registers 1838 fmovem fpcr/fpsr/fpi,a0@(312) | save FP control registers 1839Lm68881sdone: 1840 rts 1841 1842ENTRY(m68881_restore) 1843 movl sp@(4),a0 | save area pointer 1844 tstb a0@ | null state frame? 1845 jeq Lm68881rdone | yes, easy 1846 fmovem a0@(312),fpcr/fpsr/fpi | restore FP control registers 1847 fmovem a0@(216),fp0-fp7 | restore FP general registers 1848Lm68881rdone: 1849 frestore a0@ | restore state 1850 rts 1851 1852/* LUNA */ 1853 1854 .globl _fpp_svarea 1855 1856/* Fpp is MC68882 ? */ 1857ENTRY(is_68882) 1858 frestore _fppnull | initialize fpp 1859 movl #2,d0 1860 fmovecr #0,fp1 1861 fsinx fp1,fp2 1862 lea _fpp_svarea,a0 | save area 1863 movw sr,d1 | save status reg. 1864 movw #0x2700,sr | mask intrrupt 1865 fsave a0@ | save fpp context 1866 movw d1,sr | restore status reg. 1867 movl a0@,d1 1868 andl #0x00ff0000,d1 | check status field 1869 cmpl #0x00180000,d1 | 68881(idle)? 1870 beq _is81 1871 cmpl #0x00b40000,d1 | 68881(busy)? 1872 beq _is81 1873 cmpl #0x00380000,d1 | 68882(idle)? 1874 beq _is82 1875 cmpl #0x00d40000,d1 | 68882(busy)? 1876 beq _is82 1877 bra _is82out | default 68881 1878_is81: 1879 clrl d0 1880 bra _is82out 1881_is82: 1882 movl #1,d0 1883_is82out: 1884 frestore a0@ 1885 rts 1886 1887#ifdef OLD_LUNA 1888/* We have fpp ? */ 1889ENTRY(havefpp) 1890 movl a2,sp@- 1891 clrl d0 1892 movl vb,a2 1893 movl a2@(FLINE_VEC),a0 | save vectors 1894 movl a2@(COPRO_VEC),a1 1895 movl sp,d1 1896 movl #_fpvec,a2@(FLINE_VEC) | change vectors 1897 movl #_fpvec,a2@(COPRO_VEC) 1898 fnop | cause exception ? 1899 movl #1,d0 1900_fpvec: movl a0,a2@(FLINE_VEC) | restore vectors 1901 movl a1,a2@(COPRO_VEC) 1902 movl d1,sp 1903 movl sp@+,a2 1904 rts 1905#endif 1906#endif 1907 1908/* 1909 * Handle the nitty-gritty of rebooting the machine. 1910 * Basically we just turn off the MMU and jump to the appropriate ROM routine. 1911 * Note that we must be running in an address range that is mapped one-to-one 1912 * logical to physical so that the PC is still valid immediately after the MMU 1913 * is turned off. We have conveniently mapped the last page of physical 1914 * memory this way. 1915 */ 1916 .globl _doboot 1917_doboot: 1918 movl #0x41000004,a0 1919 movl a0@,a1 | get PROM restart entry address 1920 movl #CACHE_OFF,d0 1921 movc d0,cacr | disable on-chip cache(s) 1922 movl #_tcroff,a0 | value for pmove to TC (turn off MMU) 1923 pmove a0@,tc | disable MMU 1924 jmp a1@ | goto REBOOT 1925 1926 .data 1927 .space NBPG 1928tmpstk: 1929 .globl _protorp,_protott0,_protott1 1930_protorp: 1931 .long 0,0 | prototype root pointer 1932_protott0: 1933 .long 0x807F8543 | prototype tt0 register (for kernel) 1934_protott1: 1935 .long 0 | prototype tt0 register (for user) 1936 .globl _cold 1937_cold: 1938 .long 1 | cold start flag 1939 .globl _want_resched 1940_want_resched: 1941 .long 0 1942 .globl _proc0paddr 1943_proc0paddr: 1944 .long 0 | KVA of proc0 u-area 1945 1946 .globl _tcroff 1947_tcroff: 1948 .long 0 | TC reg. reset flag 1949 1950#ifdef FPCOPROC 1951 .globl _fppnull 1952_fppnull: 1953 .long 0 1954#endif 1955 .globl _clock_on 1956_clock_on: 1957 .long 0 | clock is enable ? 1958 .globl _dipswitch 1959_dipswitch: 1960 .word 0 | dipsw(front panel) value 1961#ifdef DEBUG 1962 .globl fulltflush, fullcflush 1963fulltflush: 1964 .long 0 1965fullcflush: 1966 .long 0 1967 .globl timebomb 1968timebomb: 1969 .long 0 1970#endif 1971/* interrupt counters */ 1972 .globl _intrcnt,_eintrcnt,_intrnames,_eintrnames 1973_intrnames: 1974 .asciz "spur" 1975 .asciz "lev1" 1976 .asciz "lev2" 1977 .asciz "lev3" 1978 .asciz "lev4" 1979 .asciz "clock" 1980 .asciz "lev7" 1981 .asciz "nmi" 1982_eintrnames: 1983 .even 1984_intrcnt: 1985 .long 0,0,0,0,0,0,0,0,0 1986_eintrcnt: 1987