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