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.5 (Berkeley) 09/08/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 lea sp@(16),a1 | a1 = &clockframe 475 btst #CLK_INT,CLOCK_REG | system-clock intrrupt? 476 jeq Lnottimer | no, skip hardclock 477 movb #CLK_CLR,CLOCK_REG | clear system-clock interrupt 478 tstl _clock_on | system-clock started? 479 jeq Lnottimer | no, skip hardclock 480 addql #1,_intrcnt+28 | count hardclock interrupt 481 movl a1,sp@- 482 jbsr _hardclock | hardclock(&frame) 483 addql #4,sp 484Lnottimer: 485 moveml sp@+,#0x0303 | restore scratch regs 486 addql #2,sp | pop pad word 487 addql #1,_cnt+V_INTR | chalk up another interrupt 488 jra rei | all done 489 490_lev7intr: 491 addql #1,_intrcnt+36 492 clrw sp@- | pad SR to longword 493 moveml #0xFFFF,sp@- | save registers 494 movl usp,a0 | and save 495 movl a0,sp@(60) | the user stack pointer 496 jbsr _nmihand | call handler 497 movl sp@(60),a0 | restore 498 movl a0,usp | user SP 499 moveml sp@+,#0x7FFF | and remaining registers 500 addql #6,sp | pop SSP and align word 501 jra rei | all done 502 503/* 504 * Emulation of VAX REI instruction. 505 * 506 * This code deals with checking for and servicing ASTs 507 * (profiling, scheduling) and software interrupts (network, softclock). 508 * We check for ASTs first, just like the VAX. To avoid excess overhead 509 * the T_ASTFLT handling code will also check for software interrupts so we 510 * do not have to do it here. 511 * 512 * This code is complicated by the fact that sendsig may have been called 513 * necessitating a stack cleanup. 514 */ 515 .comm _ssir,1 516 .globl _astpending 517rei: 518#ifdef DEBUG 519 tstl _panicstr | have we paniced? 520 jne Ldorte | yes, do not make matters worse 521#endif 522 tstl _astpending | AST pending? 523 jeq Lchksir | no, go check for SIR 524Lrei1: 525 btst #5,sp@ | yes, are we returning to user mode? 526 jne Lchksir | no, go check for SIR 527 clrw sp@- | pad SR to longword 528 moveml #0xFFFF,sp@- | save all registers 529 movl usp,a1 | including 530 movl a1,sp@(60) | the users SP 531 clrl sp@- | VA == none 532 clrl sp@- | code == none 533 movl #T_ASTFLT,sp@- | type == async system trap 534 jbsr _trap | go handle it 535 lea sp@(12),sp | pop value args 536 movl sp@(60),a0 | restore user SP 537 movl a0,usp | from save area 538 movw sp@(64),d0 | need to adjust stack? 539 jne Laststkadj | yes, go to it 540 moveml sp@+,#0x7FFF | no, restore most user regs 541 addql #6,sp | toss SSP and pad 542 rte | and do real RTE 543Laststkadj: 544 lea sp@(66),a1 | pointer to HW frame 545 addql #8,a1 | source pointer 546 movl a1,a0 | source 547 addw d0,a0 | + hole size = dest pointer 548 movl a1@-,a0@- | copy 549 movl a1@-,a0@- | 8 bytes 550 movl a0,sp@(60) | new SSP 551 moveml sp@+,#0x7FFF | restore user registers 552 movl sp@,sp | and our SP 553 rte | and return 554Lchksir: 555 tstb _ssir | SIR pending? 556 jeq Ldorte | no, all done 557 movl d0,sp@- | need a scratch register 558 movw sp@(4),d0 | get SR 559 andw #PSL_IPL7,d0 | mask all but IPL 560 jne Lnosir | came from interrupt, no can do 561 movl sp@+,d0 | restore scratch register 562Lgotsir: 563 movw #SPL1,sr | prevent others from servicing int 564 tstb _ssir | too late? 565 jeq Ldorte | yes, oh well... 566 clrw sp@- | pad SR to longword 567 moveml #0xFFFF,sp@- | save all registers 568 movl usp,a1 | including 569 movl a1,sp@(60) | the users SP 570 clrl sp@- | VA == none 571 clrl sp@- | code == none 572 movl #T_SSIR,sp@- | type == software interrupt 573 jbsr _trap | go handle it 574 lea sp@(12),sp | pop value args 575 movl sp@(60),a0 | restore 576 movl a0,usp | user SP 577 moveml sp@+,#0x7FFF | and all remaining registers 578 addql #6,sp | pop SSP and align word 579 rte 580Lnosir: 581 movl sp@+,d0 | restore scratch register 582Ldorte: 583 rte | real return 584 585/* 586 * Kernel access to the current processes kernel stack is via a fixed 587 * virtual address. It is at the same address as in the users VA space. 588 * Umap contains the KVA of the first of UPAGES PTEs mapping VA _kstack. 589 */ 590 .data 591 .set _kstack,KERNELSTACK | KERNELSTACK(0x3ff00000) != USRSTACK 592_Umap: .long 0 593 .globl _kstack, _Umap 594 595/* 596 * Initialization 597 * 598 * Kernel is loaded at 0. 599 * VBR contains zero from ROM. Exceptions will continue to vector 600 * through ROM until MMU is turned on at which time they will vector 601 * through our table (vectors.s). 602 */ 603 .comm _lowram,4 604 605 .text 606 .globl _edata 607 .globl _etext,_end 608 .globl start 609start: 610 movw #PSL_HIGHIPL,sr | no interrupts 611 lea tmpstk,sp | give ourselves a temporary stack 612 clrl d0 | XXXX if loader set vbr = 0 613 movc d0,vbr | XXXX please remove these 2 lines 614/* 615 * a5 contains parameters address from booter. 616 * First, we copy parameters to save area. 617 * (Now just save maxmem and so on. Not complete yet.) XXXX 618 */ 619 movl a5@(KI_MAXADDR),d0 | maxaddr 620 moveq #PGSHIFT,d1 621 lsrl d1,d0 | convert to page (click) number 622 movl d0,_maxmem | argument saved in maxmem 623 movl d0,_physmem | physmem = maxmem 624 clrl _lowram | lowram = 0 625 movl #0,a5 | kernel is loaded at 0 626 movl #CACHE_OFF,d0 627 movc d0,cacr | clear and disable on-chip cache(s) 628 629/* initialize source/destination control registers for movs */ 630 moveq #FC_USERD,d0 | user space 631 movc d0,sfc | as source 632 movc d0,dfc | and destination of transfers 633 634/* 635 * LUNA PIO initialization. 636 */ 637 movb #PIO_MODED,PIO0_CTL | read dipswitch 638 movb PIO0_B,d0 | dipsw-2 (from portB) 639 lsll #8,d0 640 movb PIO0_A,d0 | dipsw-1 (from portA) 641 movw d0,_dipswitch 642 643/* configure kernel and proc0 VA space so we can get going */ 644 .globl _Sysseg, _pmap_bootstrap, _avail_start 645 movl #_end,d5 | end of static kernel text/data 646 addl #NBPG-1,d5 647 andl #PG_FRAME,d5 | round to a page 648 movl d5,a4 | PA=VA 649 pea a5@ | firstpa 650 pea a4@ | nextpa 651 jbsr _pmap_bootstrap | bootstrap(firstpa, nextpa) 652 addql #8,sp 653 654/* 655 * Prepare to enable MMU. 656 */ 657 movl _Sysseg,a1 | system segment table addr read value (a KVA) 658 lea _protorp,a0 659 movl #0x80000202,a0@ | nolimit + share global + 4 byte PTEs 660 movl a1,a0@(4) | + segtable address 661 pmove a0@,srp | load the supervisor root pointer 662 movl #0x80000002,a0@ | reinit upper half for CRP loads 663/* we must set tt-registers here */ 664 lea _protott0,a0 665 .word 0xf010 | pmove a0@,mmutt0 666 .word 0x0800 667 lea _protott1,a0 668 .word 0xf010 | pmove a0@,mmutt1 669 .word 0x0c00 670 movl #0x82c0aa00,a2@ | value to load TC with 671 pmove a2@,tc | load it 672 673/* 674 * Should be running mapped from this point on 675 */ 676#ifdef FPCOPROC 677/* fpp check */ 678 movl a1,sp@- 679 jbsr _checkfpp | check fpp 680 frestore _fppnull | reset 681 movl sp@+,a1 682#endif 683/* select the software page size now */ 684 lea tmpstk,sp | temporary stack 685 jbsr _vm_set_page_size | select software page size 686#ifdef BOOTDEBUG 687 movl a5,sp@- | phys load address (assumes VA 0) 688 movl a4,sp@- | first available PA 689 jbsr _Opmap_bootstrap | sync up pmap module 690 addql #8,sp 691#endif 692/* set kernel stack, user SP, and initial pcb */ 693 lea _kstack,a1 | proc0 kernel stack 694 lea a1@(UPAGES*NBPG-4),sp | set kernel stack to end of area 695 movl #USRSTACK-4,a2 696 movl a2,usp | init user SP 697 movl _proc0paddr,a1 | get proc0 pcb addr 698 movl a1,_curpcb | proc0 is running 699 clrw a1@(PCB_FLAGS) | clear flags 700#ifdef FPCOPROC 701 clrl a1@(PCB_FPCTX) | ensure null FP context 702 movl a1,sp@- 703 jbsr _m68881_restore | restore it (does not kill a1) 704 addql #4,sp 705#endif 706/* flush TLB and turn on caches */ 707 jbsr _TBIA | invalidate TLB 708 movl #CACHE_ON,d0 709 movc d0,cacr | clear cache(s) 710/* final setup for C code */ 711 movw #PSL_LOWIPL,sr | lower SPL 712 movl d7,_boothowto | save reboot flags 713 movl d6,_bootdev | and boot device 714 jbsr _main | call main() 715 716/* proc[1] == init now running here; 717 * create a null exception frame and return to user mode in icode 718 */ 719 clrw sp@- | vector offset/frame type 720 clrl sp@- | return to icode location 0 721 movw #PSL_USER,sp@- | in user mode 722 rte 723 724/* 725 * Signal "trampoline" code (18 bytes). Invoked from RTE setup by sendsig(). 726 * 727 * Stack looks like: 728 * 729 * sp+0 -> signal number 730 * sp+4 signal specific code 731 * sp+8 pointer to signal context frame (scp) 732 * sp+12 address of handler 733 * sp+16 saved hardware state 734 * . 735 * . 736 * scp+0-> beginning of signal context frame 737 */ 738 .globl _sigcode, _esigcode 739 .data 740_sigcode: 741 movl sp@(12),a0 | signal handler addr (4 bytes) 742 jsr a0@ | call signal handler (2 bytes) 743 addql #4,sp | pop signo (2 bytes) 744 trap #1 | special syscall entry (2 bytes) 745 movl d0,sp@(4) | save errno (4 bytes) 746 moveq #1,d0 | syscall == exit (2 bytes) 747 trap #0 | exit(errno) (2 bytes) 748 .align 2 749_esigcode: 750 751/* 752 * Icode is copied out to process 1 to exec init. 753 * If the exec fails, process 1 exits. 754 */ 755 .globl _icode,_szicode 756 .text 757_icode: 758 clrl sp@- 759 pea pc@((argv-.)+2) 760 pea pc@((init-.)+2) 761 clrl sp@- 762 moveq #SYS_execve,d0 763 trap #0 764 moveq #SYS_exit,d0 765 trap #0 766init: 767 .asciz "/sbin/init" 768 .even 769argv: 770 .long init+6-_icode | argv[0] = "init" ("/sbin/init" + 6) 771 .long eicode-_icode | argv[1] follows icode after copyout 772 .long 0 773eicode: 774 775_szicode: 776 .long _szicode-_icode 777 778/* 779 * Primitives 780 */ 781 782#ifdef GPROF 783#define ENTRY(name) \ 784 .globl _/**/name; _/**/name: link a6,#0; jbsr mcount; unlk a6 785#define ALTENTRY(name, rname) \ 786 ENTRY(name); jra rname+12 787#else 788#define ENTRY(name) \ 789 .globl _/**/name; _/**/name: 790#define ALTENTRY(name, rname) \ 791 .globl _/**/name; _/**/name: 792#endif 793 794/* 795 * copyinstr(fromaddr, toaddr, maxlength, &lencopied) 796 * 797 * Copy a null terminated string from the user address space into 798 * the kernel address space. 799 * NOTE: maxlength must be < 64K 800 */ 801ENTRY(copyinstr) 802 movl _curpcb,a0 | current pcb 803 movl #Lcisflt1,a0@(PCB_ONFAULT) | set up to catch faults 804 movl sp@(4),a0 | a0 = fromaddr 805 movl sp@(8),a1 | a1 = toaddr 806 moveq #0,d0 807 movw sp@(14),d0 | d0 = maxlength 808 jlt Lcisflt1 | negative count, error 809 jeq Lcisdone | zero count, all done 810 subql #1,d0 | set up for dbeq 811Lcisloop: 812 movsb a0@+,d1 | grab a byte 813 nop 814 movb d1,a1@+ | copy it 815 dbeq d0,Lcisloop | if !null and more, continue 816 jne Lcisflt2 | ran out of room, error 817 moveq #0,d0 | got a null, all done 818Lcisdone: 819 tstl sp@(16) | return length desired? 820 jeq Lcisret | no, just return 821 subl sp@(4),a0 | determine how much was copied 822 movl sp@(16),a1 | return location 823 movl a0,a1@ | stash it 824Lcisret: 825 movl _curpcb,a0 | current pcb 826 clrl a0@(PCB_ONFAULT) | clear fault addr 827 rts 828Lcisflt1: 829 moveq #EFAULT,d0 | copy fault 830 jra Lcisdone 831Lcisflt2: 832 moveq #ENAMETOOLONG,d0 | ran out of space 833 jra Lcisdone 834 835/* 836 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied) 837 * 838 * Copy a null terminated string from the kernel 839 * address space to the user address space. 840 * NOTE: maxlength must be < 64K 841 */ 842ENTRY(copyoutstr) 843 movl _curpcb,a0 | current pcb 844 movl #Lcosflt1,a0@(PCB_ONFAULT) | set up to catch faults 845 movl sp@(4),a0 | a0 = fromaddr 846 movl sp@(8),a1 | a1 = toaddr 847 moveq #0,d0 848 movw sp@(14),d0 | d0 = maxlength 849 jlt Lcosflt1 | negative count, error 850 jeq Lcosdone | zero count, all done 851 subql #1,d0 | set up for dbeq 852Lcosloop: 853 movb a0@+,d1 | grab a byte 854 movsb d1,a1@+ | copy it 855 nop 856 dbeq d0,Lcosloop | if !null and more, continue 857 jne Lcosflt2 | ran out of room, error 858 moveq #0,d0 | got a null, all done 859Lcosdone: 860 tstl sp@(16) | return length desired? 861 jeq Lcosret | no, just return 862 subl sp@(4),a0 | determine how much was copied 863 movl sp@(16),a1 | return location 864 movl a0,a1@ | stash it 865Lcosret: 866 movl _curpcb,a0 | current pcb 867 clrl a0@(PCB_ONFAULT) | clear fault addr 868 rts 869Lcosflt1: 870 moveq #EFAULT,d0 | copy fault 871 jra Lcosdone 872Lcosflt2: 873 moveq #ENAMETOOLONG,d0 | ran out of space 874 jra Lcosdone 875 876/* 877 * copystr(fromaddr, toaddr, maxlength, &lencopied) 878 * 879 * Copy a null terminated string from one point to another in 880 * the kernel address space. 881 * NOTE: maxlength must be < 64K 882 */ 883ENTRY(copystr) 884 movl sp@(4),a0 | a0 = fromaddr 885 movl sp@(8),a1 | a1 = toaddr 886 moveq #0,d0 887 movw sp@(14),d0 | d0 = maxlength 888 jlt Lcsflt1 | negative count, error 889 jeq Lcsdone | zero count, all done 890 subql #1,d0 | set up for dbeq 891Lcsloop: 892 movb a0@+,a1@+ | copy a byte 893 dbeq d0,Lcsloop | if !null and more, continue 894 jne Lcsflt2 | ran out of room, error 895 moveq #0,d0 | got a null, all done 896Lcsdone: 897 tstl sp@(16) | return length desired? 898 jeq Lcsret | no, just return 899 subl sp@(4),a0 | determine how much was copied 900 movl sp@(16),a1 | return location 901 movl a0,a1@ | stash it 902Lcsret: 903 rts 904Lcsflt1: 905 moveq #EFAULT,d0 | copy fault 906 jra Lcsdone 907Lcsflt2: 908 moveq #ENAMETOOLONG,d0 | ran out of space 909 jra Lcsdone 910 911/* 912 * Copyin(from, to, len) 913 * 914 * Copy specified amount of data from user space into the kernel. 915 * NOTE: len must be < 64K 916 */ 917ENTRY(copyin) 918 movl d2,sp@- | scratch register 919 movl _curpcb,a0 | current pcb 920 movl #Lciflt,a0@(PCB_ONFAULT) | set up to catch faults 921 movl sp@(16),d2 | check count 922 jlt Lciflt | negative, error 923 jeq Lcidone | zero, done 924 movl sp@(8),a0 | src address 925 movl sp@(12),a1 | dest address 926 movl a0,d0 927 btst #0,d0 | src address odd? 928 jeq Lcieven | no, go check dest 929 movsb a0@+,d1 | yes, get a byte 930 nop 931 movb d1,a1@+ | put a byte 932 subql #1,d2 | adjust count 933 jeq Lcidone | exit if done 934Lcieven: 935 movl a1,d0 936 btst #0,d0 | dest address odd? 937 jne Lcibyte | yes, must copy by bytes 938 movl d2,d0 | no, get count 939 lsrl #2,d0 | convert to longwords 940 jeq Lcibyte | no longwords, copy bytes 941 subql #1,d0 | set up for dbf 942Lcilloop: 943 movsl a0@+,d1 | get a long 944 nop 945 movl d1,a1@+ | put a long 946 dbf d0,Lcilloop | til done 947 andl #3,d2 | what remains 948 jeq Lcidone | all done 949Lcibyte: 950 subql #1,d2 | set up for dbf 951Lcibloop: 952 movsb a0@+,d1 | get a byte 953 nop 954 movb d1,a1@+ | put a byte 955 dbf d2,Lcibloop | til done 956Lcidone: 957 moveq #0,d0 | success 958Lciexit: 959 movl _curpcb,a0 | current pcb 960 clrl a0@(PCB_ONFAULT) | clear fault catcher 961 movl sp@+,d2 | restore scratch reg 962 rts 963Lciflt: 964 moveq #EFAULT,d0 | got a fault 965 jra Lciexit 966 967/* 968 * Copyout(from, to, len) 969 * 970 * Copy specified amount of data from kernel to the user space 971 * NOTE: len must be < 64K 972 */ 973ENTRY(copyout) 974 movl d2,sp@- | scratch register 975 movl _curpcb,a0 | current pcb 976 movl #Lcoflt,a0@(PCB_ONFAULT) | catch faults 977 movl sp@(16),d2 | check count 978 jlt Lcoflt | negative, error 979 jeq Lcodone | zero, done 980 movl sp@(8),a0 | src address 981 movl sp@(12),a1 | dest address 982 movl a0,d0 983 btst #0,d0 | src address odd? 984 jeq Lcoeven | no, go check dest 985 movb a0@+,d1 | yes, get a byte 986 movsb d1,a1@+ | put a byte 987 nop 988 subql #1,d2 | adjust count 989 jeq Lcodone | exit if done 990Lcoeven: 991 movl a1,d0 992 btst #0,d0 | dest address odd? 993 jne Lcobyte | yes, must copy by bytes 994 movl d2,d0 | no, get count 995 lsrl #2,d0 | convert to longwords 996 jeq Lcobyte | no longwords, copy bytes 997 subql #1,d0 | set up for dbf 998Lcolloop: 999 movl a0@+,d1 | get a long 1000 movsl d1,a1@+ | put a long 1001 nop 1002 dbf d0,Lcolloop | til done 1003 andl #3,d2 | what remains 1004 jeq Lcodone | all done 1005Lcobyte: 1006 subql #1,d2 | set up for dbf 1007Lcobloop: 1008 movb a0@+,d1 | get a byte 1009 movsb d1,a1@+ | put a byte 1010 nop 1011 dbf d2,Lcobloop | til done 1012Lcodone: 1013 moveq #0,d0 | success 1014Lcoexit: 1015 movl _curpcb,a0 | current pcb 1016 clrl a0@(PCB_ONFAULT) | clear fault catcher 1017 movl sp@+,d2 | restore scratch reg 1018 rts 1019Lcoflt: 1020 moveq #EFAULT,d0 | got a fault 1021 jra Lcoexit 1022 1023/* 1024 * non-local gotos 1025 */ 1026ENTRY(setjmp) 1027 movl sp@(4),a0 | savearea pointer 1028 moveml #0xFCFC,a0@ | save d2-d7/a2-a7 1029 movl sp@,a0@(48) | and return address 1030 moveq #0,d0 | return 0 1031 rts 1032 1033ENTRY(qsetjmp) 1034 movl sp@(4),a0 | savearea pointer 1035 lea a0@(40),a0 | skip regs we do not save 1036 movl a6,a0@+ | save FP 1037 movl sp,a0@+ | save SP 1038 movl sp@,a0@ | and return address 1039 moveq #0,d0 | return 0 1040 rts 1041 1042ENTRY(longjmp) 1043 movl sp@(4),a0 1044 moveml a0@+,#0xFCFC 1045 movl a0@,sp@ 1046 moveq #1,d0 1047 rts 1048 1049/* 1050 * The following primitives manipulate the run queues. 1051 * _whichqs tells which of the 32 queues _qs 1052 * have processes in them. Setrq puts processes into queues, Remrq 1053 * removes them from queues. The running process is on no queue, 1054 * other processes are on a queue related to p->p_pri, divided by 4 1055 * actually to shrink the 0-127 range of priorities into the 32 available 1056 * queues. 1057 */ 1058 1059 .globl _whichqs,_qs,_cnt,_panic 1060 .globl _curproc,_want_resched 1061 1062/* 1063 * Setrq(p) 1064 * 1065 * Call should be made at spl6(), and p->p_stat should be SRUN 1066 */ 1067ENTRY(setrq) 1068 movl sp@(4),a0 1069 tstl a0@(P_RLINK) 1070 jeq Lset1 1071 movl #Lset2,sp@- 1072 jbsr _panic 1073Lset1: 1074 clrl d0 1075 movb a0@(P_PRI),d0 1076 lsrb #2,d0 1077 movl _whichqs,d1 1078 bset d0,d1 1079 movl d1,_whichqs 1080 lslb #3,d0 1081 addl #_qs,d0 1082 movl d0,a0@(P_LINK) 1083 movl d0,a1 1084 movl a1@(P_RLINK),a0@(P_RLINK) 1085 movl a0,a1@(P_RLINK) 1086 movl a0@(P_RLINK),a1 1087 movl a0,a1@(P_LINK) 1088 rts 1089 1090Lset2: 1091 .asciz "setrq" 1092 .even 1093 1094/* 1095 * Remrq(p) 1096 * 1097 * Call should be made at spl6(). 1098 */ 1099ENTRY(remrq) 1100 movl sp@(4),a0 1101 clrl d0 1102 movb a0@(P_PRI),d0 1103 lsrb #2,d0 1104 movl _whichqs,d1 1105 bclr d0,d1 1106 jne Lrem1 1107 movl #Lrem3,sp@- 1108 jbsr _panic 1109Lrem1: 1110 movl d1,_whichqs 1111 movl a0@(P_LINK),a1 1112 movl a0@(P_RLINK),a1@(P_RLINK) 1113 movl a0@(P_RLINK),a1 1114 movl a0@(P_LINK),a1@(P_LINK) 1115 movl #_qs,a1 1116 movl d0,d1 1117 lslb #3,d1 1118 addl d1,a1 1119 cmpl a1@(P_LINK),a1 1120 jeq Lrem2 1121 movl _whichqs,d1 1122 bset d0,d1 1123 movl d1,_whichqs 1124Lrem2: 1125 clrl a0@(P_RLINK) 1126 rts 1127 1128Lrem3: 1129 .asciz "remrq" 1130Lsw0: 1131 .asciz "swtch" 1132 .even 1133 1134 .globl _curpcb 1135 .globl _masterpaddr | XXX compatibility (debuggers) 1136 .data 1137_masterpaddr: | XXX compatibility (debuggers) 1138_curpcb: 1139 .long 0 1140pcbflag: 1141 .byte 0 | copy of pcb_flags low byte 1142 .align 2 1143 .comm nullpcb,SIZEOF_PCB 1144 .text 1145 1146/* 1147 * At exit of a process, do a swtch for the last time. 1148 * The mapping of the pcb at p->p_addr has already been deleted, 1149 * and the memory for the pcb+stack has been freed. 1150 * The ipl is high enough to prevent the memory from being reallocated. 1151 */ 1152ENTRY(swtch_exit) 1153 movl #nullpcb,_curpcb | save state into garbage pcb 1154 lea tmpstk,sp | goto a tmp stack 1155 jra _cpu_swtch 1156 1157/* 1158 * When no processes are on the runq, Swtch branches to idle 1159 * to wait for something to come ready. 1160 */ 1161 .globl Idle 1162Lidle: 1163 stop #PSL_LOWIPL 1164Idle: 1165idle: 1166 movw #PSL_HIGHIPL,sr 1167 tstl _whichqs 1168 jeq Lidle 1169 movw #PSL_LOWIPL,sr 1170 jra Lsw1 1171 1172Lbadsw: 1173 movl #Lsw0,sp@- 1174 jbsr _panic 1175 /*NOTREACHED*/ 1176 1177/* 1178 * cpu_swtch() 1179 * 1180 * NOTE: On the mc68851 (318/319/330) we attempt to avoid flushing the 1181 * entire ATC. The effort involved in selective flushing may not be 1182 * worth it, maybe we should just flush the whole thing? 1183 * 1184 * NOTE 2: With the new VM layout we now no longer know if an inactive 1185 * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag 1186 * bit). For now, we just always flush the full ATC. 1187 */ 1188ENTRY(cpu_swtch) 1189 movl _curpcb,a0 | current pcb 1190 movw sr,a0@(PCB_PS) | save sr before changing ipl 1191#ifdef notyet 1192 movl _curproc,sp@- | remember last proc running 1193#endif 1194 clrl _curproc 1195 addql #1,_cnt+V_SWTCH 1196 1197Lsw1: 1198 /* 1199 * Find the highest-priority queue that isn't empty, 1200 * then take the first proc from that queue. 1201 */ 1202 clrl d0 1203 lea _whichqs,a0 1204 movl a0@,d1 1205Lswchk: 1206 btst d0,d1 1207 jne Lswfnd 1208 addqb #1,d0 1209 cmpb #32,d0 1210 jne Lswchk 1211 jra idle 1212Lswfnd: 1213 movw #PSL_HIGHIPL,sr | lock out interrupts 1214 movl a0@,d1 | and check again... 1215 bclr d0,d1 1216 jeq Lsw1 | proc moved, rescan 1217 movl d1,a0@ | update whichqs 1218 moveq #1,d1 | double check for higher priority 1219 lsll d0,d1 | process (which may have snuck in 1220 subql #1,d1 | while we were finding this one) 1221 andl a0@,d1 1222 jeq Lswok | no one got in, continue 1223 movl a0@,d1 1224 bset d0,d1 | otherwise put this one back 1225 movl d1,a0@ 1226 jra Lsw1 | and rescan 1227Lswok: 1228 movl d0,d1 1229 lslb #3,d1 | convert queue number to index 1230 addl #_qs,d1 | locate queue (q) 1231 movl d1,a1 1232 cmpl a1@(P_LINK),a1 | anyone on queue? 1233 jeq Lbadsw | no, panic 1234 movl a1@(P_LINK),a0 | p = q->p_link 1235 movl a0@(P_LINK),a1@(P_LINK) | q->p_link = p->p_link 1236 movl a0@(P_LINK),a1 | q = p->p_link 1237 movl a0@(P_RLINK),a1@(P_RLINK) | q->p_rlink = p->p_rlink 1238 cmpl a0@(P_LINK),d1 | anyone left on queue? 1239 jeq Lsw2 | no, skip 1240 movl _whichqs,d1 1241 bset d0,d1 | yes, reset bit 1242 movl d1,_whichqs 1243Lsw2: 1244 movl a0,_curproc 1245 clrl _want_resched 1246#ifdef notyet 1247 movl sp@+,a1 1248 cmpl a0,a1 | switching to same proc? 1249 jeq Lswdone | yes, skip save and restore 1250#endif 1251 /* 1252 * Save state of previous process in its pcb. 1253 */ 1254 movl _curpcb,a1 1255 moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers 1256 movl usp,a2 | grab USP (a2 has been saved) 1257 movl a2,a1@(PCB_USP) | and save it 1258#ifdef FPCOPROC 1259 lea a1@(PCB_FPCTX),a2 | pointer to FP save area 1260 fsave a2@ | save FP state 1261 tstb a2@ | null state frame? 1262 jeq Lswnofpsave | yes, all done 1263 fmovem fp0-fp7,a2@(216) | save FP general registers 1264 fmovem fpcr/fpsr/fpi,a2@(312) | save FP control registers 1265Lswnofpsave: 1266#endif 1267 1268#ifdef DIAGNOSTIC 1269 tstl a0@(P_WCHAN) 1270 jne Lbadsw 1271 cmpb #SRUN,a0@(P_STAT) 1272 jne Lbadsw 1273#endif 1274 clrl a0@(P_RLINK) | clear back link 1275 movl a0@(P_ADDR),a1 | get p_addr 1276 movl a1,_curpcb 1277 movb a1@(PCB_FLAGS+1),pcbflag | copy of pcb_flags low byte 1278 1279 /* see if pmap_activate needs to be called; should remove this */ 1280 movl a0@(P_VMSPACE),a0 | vmspace = p->p_vmspace 1281#ifdef DIAGNOSTIC 1282 tstl a0 | map == VM_MAP_NULL? 1283 jeq Lbadsw | panic 1284#endif 1285 lea a0@(VM_PMAP),a0 | pmap = &vmspace.vm_pmap 1286 tstl a0@(PM_STCHG) | pmap->st_changed? 1287 jeq Lswnochg | no, skip 1288 pea a1@ | push pcb (at p_addr) 1289 pea a0@ | push pmap 1290 jbsr _pmap_activate | pmap_activate(pmap, pcb) 1291 addql #8,sp 1292 movl _curpcb,a1 | restore p_addr 1293Lswnochg: 1294 1295 movl #PGSHIFT,d1 1296 movl a1,d0 1297 lsrl d1,d0 | convert p_addr to page number 1298 lsll #2,d0 | and now to Sysmap offset 1299 addl _Sysmap,d0 | add Sysmap base to get PTE addr 1300#ifdef notdef 1301 movw #PSL_HIGHIPL,sr | go crit while changing PTEs 1302#endif 1303 lea tmpstk,sp | now goto a tmp stack for NMI 1304 movl d0,a0 | address of new context 1305 movl _Umap,a2 | address of PTEs for kstack 1306 moveq #UPAGES-1,d0 | sizeof kstack 1307Lres1: 1308 movl a0@+,d1 | get PTE 1309 andl #~PG_PROT,d1 | mask out old protection 1310 orl #PG_RW+PG_V,d1 | ensure valid and writable 1311 movl d1,a2@+ | load it up 1312 dbf d0,Lres1 | til done 1313 movl #CACHE_CLR,d0 1314 movc d0,cacr | invalidate cache(s) 1315 pflusha | flush entire TLB 1316 movl a1@(PCB_USTP),d0 | get USTP 1317 moveq #PGSHIFT,d1 1318 lsll d1,d0 | convert to addr 1319 lea _protorp,a0 | CRP prototype 1320 movl d0,a0@(4) | stash USTP 1321 pmove a0@,crp | load new user root pointer 1322 moveml a1@(PCB_REGS),#0xFCFC | and registers 1323 movl a1@(PCB_USP),a0 1324 movl a0,usp | and USP 1325#ifdef FPCOPROC 1326 lea a1@(PCB_FPCTX),a0 | pointer to FP save area 1327 tstb a0@ | null state frame? 1328 jeq Lresfprest | yes, easy 1329 fmovem a0@(312),fpcr/fpsr/fpi | restore FP control registers 1330 fmovem a0@(216),fp0-fp7 | restore FP general registers 1331Lresfprest: 1332 frestore a0@ | restore state 1333#endif 1334 movw a1@(PCB_PS),sr | no, restore PS 1335 moveq #1,d0 | return 1 (for alternate returns) 1336 rts 1337 1338/* 1339 * savectx(pcb, altreturn) 1340 * Update pcb, saving current processor state and arranging 1341 * for alternate return ala longjmp in swtch if altreturn is true. 1342 */ 1343ENTRY(savectx) 1344 movl sp@(4),a1 1345 movw sr,a1@(PCB_PS) 1346 movl usp,a0 | grab USP 1347 movl a0,a1@(PCB_USP) | and save it 1348 moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers 1349#ifdef FPCOPROC 1350 lea a1@(PCB_FPCTX),a0 | pointer to FP save area 1351 fsave a0@ | save FP state 1352 tstb a0@ | null state frame? 1353 jeq Lsvnofpsave | yes, all done 1354 fmovem fp0-fp7,a0@(216) | save FP general registers 1355 fmovem fpcr/fpsr/fpi,a0@(312) | save FP control registers 1356Lsvnofpsave: 1357#endif 1358 tstl sp@(8) | altreturn? 1359 jeq Lsavedone 1360 movl sp,d0 | relocate current sp relative to a1 1361 subl #_kstack,d0 | (sp is relative to kstack): 1362 addl d0,a1 | a1 += sp - kstack; 1363 movl sp@,a1@ | write return pc at (relocated) sp@ 1364Lsavedone: 1365 moveq #0,d0 | return 0 1366 rts 1367 1368/* 1369 * {fu,su},{byte,sword,word} 1370 */ 1371ALTENTRY(fuiword, _fuword) 1372ENTRY(fuword) 1373 movl sp@(4),a0 | address to read 1374 movl _curpcb,a1 | current pcb 1375 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1376 movsl a0@,d0 | do read from user space 1377 nop 1378 jra Lfsdone 1379 1380ENTRY(fusword) 1381 movl sp@(4),a0 1382 movl _curpcb,a1 | current pcb 1383 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1384 moveq #0,d0 1385 movsw a0@,d0 | do read from user space 1386 nop 1387 jra Lfsdone 1388 1389/* Just like fusword, but tells trap code not to page in. */ 1390ENTRY(fuswintr) 1391 movl sp@(4),a0 1392 movl _curpcb,a1 1393 movl #_fswintr,a1@(PCB_ONFAULT) 1394 moveq #0,d0 1395 movsw a0@,d0 1396 nop 1397 jra Lfsdone 1398 1399ALTENTRY(fuibyte, _fubyte) 1400ENTRY(fubyte) 1401 movl sp@(4),a0 | address to read 1402 movl _curpcb,a1 | current pcb 1403 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1404 moveq #0,d0 1405 movsb a0@,d0 | do read from user space 1406 nop 1407 jra Lfsdone 1408 1409Lfserr: 1410 moveq #-1,d0 | error indicator 1411Lfsdone: 1412 clrl a1@(PCB_ONFAULT) | clear fault address 1413 rts 1414 1415/* Just like Lfserr, but the address is different (& exported). */ 1416 .globl _fswintr 1417_fswintr: 1418 moveq #-1,d0 1419 jra Lfsdone 1420 1421 1422/* 1423 * Write a longword in user instruction space. 1424 * Largely the same as suword but with a final i-cache purge on those 1425 * machines with split caches. 1426 */ 1427ENTRY(suiword) 1428 movl sp@(4),a0 | address to write 1429 movl sp@(8),d0 | value to put there 1430 movl _curpcb,a1 | current pcb 1431 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1432 movsl d0,a0@ | do write to user space 1433 nop 1434 moveq #0,d0 | indicate no fault 1435 movl #IC_CLEAR,d1 1436 movc d1,cacr | invalidate i-cache 1437 jra Lfsdone 1438 1439ENTRY(suword) 1440 movl sp@(4),a0 | address to write 1441 movl sp@(8),d0 | value to put there 1442 movl _curpcb,a1 | current pcb 1443 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1444 movsl d0,a0@ | do write to user space 1445 nop 1446 moveq #0,d0 | indicate no fault 1447 jra Lfsdone 1448 1449ENTRY(susword) 1450 movl sp@(4),a0 | address to write 1451 movw sp@(10),d0 | value to put there 1452 movl _curpcb,a1 | current pcb 1453 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1454 movsw d0,a0@ | do write to user space 1455 nop 1456 moveq #0,d0 | indicate no fault 1457 jra Lfsdone 1458 1459ENTRY(suswintr) 1460 movl sp@(4),a0 1461 movw sp@(10),d0 1462 movl _curpcb,a1 1463 movl #_fswintr,a1@(PCB_ONFAULT) 1464 movsw d0,a0@ 1465 nop 1466 moveq #0,d0 1467 jra Lfsdone 1468 1469ALTENTRY(suibyte, _subyte) 1470ENTRY(subyte) 1471 movl sp@(4),a0 | address to write 1472 movb sp@(11),d0 | value to put there 1473 movl _curpcb,a1 | current pcb 1474 movl #Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault 1475 movsb d0,a0@ | do write to user space 1476 nop 1477 moveq #0,d0 | indicate no fault 1478 jra Lfsdone 1479 1480/* 1481 * Invalidate entire TLB. 1482 */ 1483ENTRY(TBIA) 1484__TBIA: 1485 pflusha | flush entire TLB 1486 movl #DC_CLEAR,d0 1487 movc d0,cacr | invalidate on-chip d-cache 1488 rts 1489 1490/* 1491 * Invalidate any TLB entry for given VA (TB Invalidate Single) 1492 */ 1493ENTRY(TBIS) 1494#ifdef DEBUG 1495 tstl fulltflush | being conservative? 1496 jne __TBIA | yes, flush entire TLB 1497#endif 1498 1499 movl sp@(4),a0 | get addr to flush 1500 pflush #0,#0,a0@ | flush address from both sides 1501 movl #DC_CLEAR,d0 1502 movc d0,cacr | invalidate on-chip data cache 1503 rts 1504 1505/* 1506 * Invalidate supervisor side of TLB 1507 */ 1508ENTRY(TBIAS) 1509#ifdef DEBUG 1510 tstl fulltflush | being conservative? 1511 jne __TBIA | yes, flush everything 1512#endif 1513 pflush #4,#4 | flush supervisor TLB entries 1514 movl #DC_CLEAR,d0 1515 movc d0,cacr | invalidate on-chip d-cache 1516 rts 1517 1518/* 1519 * Invalidate user side of TLB 1520 */ 1521ENTRY(TBIAU) 1522#ifdef DEBUG 1523 tstl fulltflush | being conservative? 1524 jne __TBIA | yes, flush everything 1525#endif 1526 pflush #0,#4 | flush user TLB entries 1527 movl #DC_CLEAR,d0 1528 movc d0,cacr | invalidate on-chip d-cache 1529 rts 1530 1531/* 1532 * Invalidate instruction cache 1533 */ 1534ENTRY(ICIA) 1535 movl #IC_CLEAR,d0 1536 movc d0,cacr | invalidate i-cache 1537 rts 1538 1539ENTRY(PCIA) 1540 movl #DC_CLEAR,d0 1541 movc d0,cacr | invalidate on-chip d-cache 1542 rts 1543 1544/* 1545 * Get callers current SP value. 1546 * Note that simply taking the address of a local variable in a C function 1547 * doesn't work because callee saved registers may be outside the stack frame 1548 * defined by A6 (e.g. GCC generated code). 1549 */ 1550 .globl _getsp 1551_getsp: 1552 movl sp,d0 | get current SP 1553 addql #4,d0 | compensate for return address 1554 rts 1555 1556 .globl _getsfc, _getdfc 1557_getsfc: 1558 movc sfc,d0 1559 rts 1560_getdfc: 1561 movc dfc,d0 1562 rts 1563 1564/* 1565 * Load a new user segment table pointer. 1566 */ 1567ENTRY(loadustp) 1568 movl sp@(4),d0 | new USTP 1569 moveq #PGSHIFT,d1 1570 lsll d1,d0 | convert to addr 1571 lea _protorp,a0 | CRP prototype 1572 movl d0,a0@(4) | stash USTP 1573 pmove a0@,crp | load root pointer 1574 movl #DC_CLEAR,d0 1575 movc d0,cacr | invalidate on-chip d-cache 1576 rts 1577 1578ENTRY(ploadw) 1579 movl sp@(4),a0 | address to load 1580 ploadw #1,a0@ | pre-load translation 1581 rts 1582 1583/* 1584 * Set processor priority level calls. Most are implemented with 1585 * inline asm expansions. However, spl0 requires special handling 1586 * as we need to check for our emulated software interrupts. 1587 */ 1588 1589ENTRY(spl0) 1590 moveq #0,d0 1591 movw sr,d0 | get old SR for return 1592 movw #PSL_LOWIPL,sr | restore new SR 1593 tstb _ssir | software interrupt pending? 1594 jeq Lspldone | no, all done 1595 subql #4,sp | make room for RTE frame 1596 movl sp@(4),sp@(2) | position return address 1597 clrw sp@(6) | set frame type 0 1598 movw #PSL_LOWIPL,sp@ | and new SR 1599 jra Lgotsir | go handle it 1600Lspldone: 1601 rts 1602 1603ENTRY(_insque) 1604 movw sr,d0 1605 movw #PSL_HIGHIPL,sr | atomic 1606 movl sp@(8),a0 | where to insert (after) 1607 movl sp@(4),a1 | element to insert (e) 1608 movl a0@,a1@ | e->next = after->next 1609 movl a0,a1@(4) | e->prev = after 1610 movl a1,a0@ | after->next = e 1611 movl a1@,a0 1612 movl a1,a0@(4) | e->next->prev = e 1613 movw d0,sr 1614 rts 1615 1616ENTRY(_remque) 1617 movw sr,d0 1618 movw #PSL_HIGHIPL,sr | atomic 1619 movl sp@(4),a0 | element to remove (e) 1620 movl a0@,a1 1621 movl a0@(4),a0 1622 movl a0,a1@(4) | e->next->prev = e->prev 1623 movl a1,a0@ | e->prev->next = e->next 1624 movw d0,sr 1625 rts 1626 1627/* 1628 * bzero(addr, count) 1629 */ 1630ALTENTRY(blkclr, _bzero) 1631ENTRY(bzero) 1632 movl sp@(4),a0 | address 1633 movl sp@(8),d0 | count 1634 jeq Lbzdone | if zero, nothing to do 1635 movl a0,d1 1636 btst #0,d1 | address odd? 1637 jeq Lbzeven | no, can copy words 1638 clrb a0@+ | yes, zero byte to get to even boundary 1639 subql #1,d0 | decrement count 1640 jeq Lbzdone | none left, all done 1641Lbzeven: 1642 movl d0,d1 1643 andl #31,d0 1644 lsrl #5,d1 | convert count to 8*longword count 1645 jeq Lbzbyte | no such blocks, zero byte at a time 1646Lbzloop: 1647 clrl a0@+; clrl a0@+; clrl a0@+; clrl a0@+; 1648 clrl a0@+; clrl a0@+; clrl a0@+; clrl a0@+; 1649 subql #1,d1 | one more block zeroed 1650 jne Lbzloop | more to go, do it 1651 tstl d0 | partial block left? 1652 jeq Lbzdone | no, all done 1653Lbzbyte: 1654 clrb a0@+ 1655 subql #1,d0 | one more byte cleared 1656 jne Lbzbyte | more to go, do it 1657Lbzdone: 1658 rts 1659 1660/* 1661 * strlen(str) 1662 */ 1663ENTRY(strlen) 1664 moveq #-1,d0 1665 movl sp@(4),a0 | string 1666Lslloop: 1667 addql #1,d0 | increment count 1668 tstb a0@+ | null? 1669 jne Lslloop | no, keep going 1670 rts 1671 1672/* 1673 * bcmp(s1, s2, len) 1674 * 1675 * WARNING! This guy only works with counts up to 64K 1676 */ 1677ENTRY(bcmp) 1678 movl sp@(4),a0 | string 1 1679 movl sp@(8),a1 | string 2 1680 moveq #0,d0 1681 movw sp@(14),d0 | length 1682 jeq Lcmpdone | if zero, nothing to do 1683 subqw #1,d0 | set up for DBcc loop 1684Lcmploop: 1685 cmpmb a0@+,a1@+ | equal? 1686 dbne d0,Lcmploop | yes, keep going 1687 addqw #1,d0 | +1 gives zero on match 1688Lcmpdone: 1689 rts 1690 1691/* 1692 * {ov}bcopy(from, to, len) 1693 * 1694 * Works for counts up to 128K. 1695 */ 1696ALTENTRY(ovbcopy, _bcopy) 1697ENTRY(bcopy) 1698 movl sp@(12),d0 | get count 1699 jeq Lcpyexit | if zero, return 1700 movl sp@(4),a0 | src address 1701 movl sp@(8),a1 | dest address 1702 cmpl a1,a0 | src before dest? 1703 jlt Lcpyback | yes, copy backwards (avoids overlap) 1704 movl a0,d1 1705 btst #0,d1 | src address odd? 1706 jeq Lcfeven | no, go check dest 1707 movb a0@+,a1@+ | yes, copy a byte 1708 subql #1,d0 | update count 1709 jeq Lcpyexit | exit if done 1710Lcfeven: 1711 movl a1,d1 1712 btst #0,d1 | dest address odd? 1713 jne Lcfbyte | yes, must copy by bytes 1714 movl d0,d1 | no, get count 1715 lsrl #2,d1 | convert to longwords 1716 jeq Lcfbyte | no longwords, copy bytes 1717 subql #1,d1 | set up for dbf 1718Lcflloop: 1719 movl a0@+,a1@+ | copy longwords 1720 dbf d1,Lcflloop | til done 1721 andl #3,d0 | get remaining count 1722 jeq Lcpyexit | done if none 1723Lcfbyte: 1724 subql #1,d0 | set up for dbf 1725Lcfbloop: 1726 movb a0@+,a1@+ | copy bytes 1727 dbf d0,Lcfbloop | til done 1728Lcpyexit: 1729 rts 1730Lcpyback: 1731 addl d0,a0 | add count to src 1732 addl d0,a1 | add count to dest 1733 movl a0,d1 1734 btst #0,d1 | src address odd? 1735 jeq Lcbeven | no, go check dest 1736 movb a0@-,a1@- | yes, copy a byte 1737 subql #1,d0 | update count 1738 jeq Lcpyexit | exit if done 1739Lcbeven: 1740 movl a1,d1 1741 btst #0,d1 | dest address odd? 1742 jne Lcbbyte | yes, must copy by bytes 1743 movl d0,d1 | no, get count 1744 lsrl #2,d1 | convert to longwords 1745 jeq Lcbbyte | no longwords, copy bytes 1746 subql #1,d1 | set up for dbf 1747Lcblloop: 1748 movl a0@-,a1@- | copy longwords 1749 dbf d1,Lcblloop | til done 1750 andl #3,d0 | get remaining count 1751 jeq Lcpyexit | done if none 1752Lcbbyte: 1753 subql #1,d0 | set up for dbf 1754Lcbbloop: 1755 movb a0@-,a1@- | copy bytes 1756 dbf d0,Lcbbloop | til done 1757 rts 1758 1759/* 1760 * Emulate fancy VAX string operations: 1761 * scanc(count, startc, table, mask) 1762 * skpc(mask, count, startc) 1763 * locc(mask, count, startc) 1764 */ 1765ENTRY(scanc) 1766 movl sp@(4),d0 | get length 1767 jeq Lscdone | nothing to do, return 1768 movl sp@(8),a0 | start of scan 1769 movl sp@(12),a1 | table to compare with 1770 movb sp@(19),d1 | and mask to use 1771 movw d2,sp@- | need a scratch register 1772 clrw d2 | clear it out 1773 subqw #1,d0 | adjust for dbra 1774Lscloop: 1775 movb a0@+,d2 | get character 1776 movb a1@(0,d2:w),d2 | get table entry 1777 andb d1,d2 | mask it 1778 dbne d0,Lscloop | keep going til no more or non-zero 1779 addqw #1,d0 | overshot by one 1780 movw sp@+,d2 | restore scratch 1781Lscdone: 1782 rts 1783 1784ENTRY(skpc) 1785 movl sp@(8),d0 | get length 1786 jeq Lskdone | nothing to do, return 1787 movb sp@(7),d1 | mask to use 1788 movl sp@(12),a0 | where to start 1789 subqw #1,d0 | adjust for dbcc 1790Lskloop: 1791 cmpb a0@+,d1 | compate with mask 1792 dbne d0,Lskloop | keep going til no more or zero 1793 addqw #1,d0 | overshot by one 1794Lskdone: 1795 rts 1796 1797ENTRY(locc) 1798 movl sp@(8),d0 | get length 1799 jeq Llcdone | nothing to do, return 1800 movb sp@(7),d1 | mask to use 1801 movl sp@(12),a0 | where to start 1802 subqw #1,d0 | adjust for dbcc 1803Llcloop: 1804 cmpb a0@+,d1 | compate with mask 1805 dbeq d0,Llcloop | keep going til no more or non-zero 1806 addqw #1,d0 | overshot by one 1807Llcdone: 1808 rts 1809 1810/* 1811 * Emulate VAX FFS (find first set) instruction. 1812 */ 1813ENTRY(ffs) 1814 moveq #-1,d0 1815 movl sp@(4),d1 1816 jeq Lffsdone 1817Lffsloop: 1818 addql #1,d0 1819 btst d0,d1 1820 jeq Lffsloop 1821Lffsdone: 1822 addql #1,d0 1823 rts 1824 1825#ifdef FPCOPROC 1826/* 1827 * Save and restore 68881 state. 1828 * Pretty awful looking since our assembler does not 1829 * recognize FP mnemonics. 1830 */ 1831ENTRY(m68881_save) 1832 movl sp@(4),a0 | save area pointer 1833 fsave a0@ | save state 1834 tstb a0@ | null state frame? 1835 jeq Lm68881sdone | yes, all done 1836 fmovem fp0-fp7,a0@(216) | save FP general registers 1837 fmovem fpcr/fpsr/fpi,a0@(312) | save FP control registers 1838Lm68881sdone: 1839 rts 1840 1841ENTRY(m68881_restore) 1842 movl sp@(4),a0 | save area pointer 1843 tstb a0@ | null state frame? 1844 jeq Lm68881rdone | yes, easy 1845 fmovem a0@(312),fpcr/fpsr/fpi | restore FP control registers 1846 fmovem a0@(216),fp0-fp7 | restore FP general registers 1847Lm68881rdone: 1848 frestore a0@ | restore state 1849 rts 1850 1851/* LUNA */ 1852 1853 .globl _fpp_svarea 1854 1855/* Fpp is MC68882 ? */ 1856ENTRY(is_68882) 1857 frestore _fppnull | initialize fpp 1858 movl #2,d0 1859 fmovecr #0,fp1 1860 fsinx fp1,fp2 1861 lea _fpp_svarea,a0 | save area 1862 movw sr,d1 | save status reg. 1863 movw #0x2700,sr | mask intrrupt 1864 fsave a0@ | save fpp context 1865 movw d1,sr | restore status reg. 1866 movl a0@,d1 1867 andl #0x00ff0000,d1 | check status field 1868 cmpl #0x00180000,d1 | 68881(idle)? 1869 beq _is81 1870 cmpl #0x00b40000,d1 | 68881(busy)? 1871 beq _is81 1872 cmpl #0x00380000,d1 | 68882(idle)? 1873 beq _is82 1874 cmpl #0x00d40000,d1 | 68882(busy)? 1875 beq _is82 1876 bra _is82out | default 68881 1877_is81: 1878 clrl d0 1879 bra _is82out 1880_is82: 1881 movl #1,d0 1882_is82out: 1883 frestore a0@ 1884 rts 1885 1886#ifdef OLD_LUNA 1887/* We have fpp ? */ 1888ENTRY(havefpp) 1889 movl a2,sp@- 1890 clrl d0 1891 movl vb,a2 1892 movl a2@(FLINE_VEC),a0 | save vectors 1893 movl a2@(COPRO_VEC),a1 1894 movl sp,d1 1895 movl #_fpvec,a2@(FLINE_VEC) | change vectors 1896 movl #_fpvec,a2@(COPRO_VEC) 1897 fnop | cause exception ? 1898 movl #1,d0 1899_fpvec: movl a0,a2@(FLINE_VEC) | restore vectors 1900 movl a1,a2@(COPRO_VEC) 1901 movl d1,sp 1902 movl sp@+,a2 1903 rts 1904#endif 1905#endif 1906 1907/* 1908 * Handle the nitty-gritty of rebooting the machine. 1909 * Basically we just turn off the MMU and jump to the appropriate ROM routine. 1910 * Note that we must be running in an address range that is mapped one-to-one 1911 * logical to physical so that the PC is still valid immediately after the MMU 1912 * is turned off. We have conveniently mapped the last page of physical 1913 * memory this way. 1914 */ 1915 .globl _doboot 1916_doboot: 1917 movl #0x41000004,a0 1918 movl a0@,a1 | get PROM restart entry address 1919 movl #CACHE_OFF,d0 1920 movc d0,cacr | disable on-chip cache(s) 1921 movl #_tcroff,a0 | value for pmove to TC (turn off MMU) 1922 pmove a0@,tc | disable MMU 1923 jmp a1@ | goto REBOOT 1924 1925 .data 1926 .space NBPG 1927tmpstk: 1928 .globl _protorp,_protott0,_protott1 1929_protorp: 1930 .long 0,0 | prototype root pointer 1931_protott0: 1932 .long 0x807F8543 | prototype tt0 register (for kernel) 1933_protott1: 1934 .long 0 | prototype tt0 register (for user) 1935 .globl _cold 1936_cold: 1937 .long 1 | cold start flag 1938 .globl _want_resched 1939_want_resched: 1940 .long 0 1941 .globl _proc0paddr 1942_proc0paddr: 1943 .long 0 | KVA of proc0 u-area 1944 1945 .globl _tcroff 1946_tcroff: 1947 .long 0 | TC reg. reset flag 1948 1949#ifdef FPCOPROC 1950 .globl _fppnull 1951_fppnull: 1952 .long 0 1953#endif 1954 .globl _clock_on 1955_clock_on: 1956 .long 0 | clock is enable ? 1957 .globl _dipswitch 1958_dipswitch: 1959 .word 0 | dipsw(front panel) value 1960#ifdef DEBUG 1961 .globl fulltflush, fullcflush 1962fulltflush: 1963 .long 0 1964fullcflush: 1965 .long 0 1966 .globl timebomb 1967timebomb: 1968 .long 0 1969#endif 1970/* interrupt counters */ 1971 .globl _intrcnt,_eintrcnt,_intrnames,_eintrnames 1972_intrnames: 1973 .asciz "spur" 1974 .asciz "lev1" 1975 .asciz "lev2" 1976 .asciz "lev3" 1977 .asciz "lev4" 1978 .asciz "clock" 1979 .asciz "lev7" 1980 .asciz "nmi" 1981_eintrnames: 1982 .even 1983_intrcnt: 1984 .long 0,0,0,0,0,0,0,0,0 1985_eintrcnt: 1986