1#include "mem.h" 2#include "/sys/src/boot/pc/x16.h" 3#undef DELAY 4 5#define PADDR(a) ((a) & ~KZERO) 6#define KADDR(a) (KZERO|(a)) 7 8/* 9 * Some machine instructions not handled by 8[al]. 10 */ 11#define OP16 BYTE $0x66 12#define DELAY BYTE $0xEB; BYTE $0x00 /* JMP .+2 */ 13#define CPUID BYTE $0x0F; BYTE $0xA2 /* CPUID, argument in AX */ 14#define WRMSR BYTE $0x0F; BYTE $0x30 /* WRMSR, argument in AX/DX (lo/hi) */ 15#define RDTSC BYTE $0x0F; BYTE $0x31 /* RDTSC, result in AX/DX (lo/hi) */ 16#define RDMSR BYTE $0x0F; BYTE $0x32 /* RDMSR, result in AX/DX (lo/hi) */ 17#define HLT BYTE $0xF4 18#define INVLPG BYTE $0x0F; BYTE $0x01; BYTE $0x39 /* INVLPG (%ecx) */ 19#define WBINVD BYTE $0x0F; BYTE $0x09 20#define FXSAVE BYTE $0x0f; BYTE $0xae; BYTE $0x00 /* SSE FP save */ 21#define FXRSTOR BYTE $0x0f; BYTE $0xae; BYTE $0x08 /* SSE FP restore */ 22 23/* 24 * Macros for calculating offsets within the page directory base 25 * and page tables. Note that these are assembler-specific hence 26 * the '<<2'. 27 */ 28#define PDO(a) (((((a))>>22) & 0x03FF)<<2) 29#define PTO(a) (((((a))>>12) & 0x03FF)<<2) 30 31/* 32 * For backwards compatiblity with 9load - should go away when 9load is changed 33 * 9load currently sets up the mmu, however the first 16MB of memory is identity 34 * mapped, so behave as if the mmu was not setup 35 */ 36TEXT _startKADDR(SB), $0 37 MOVL $_startPADDR(SB), AX 38 ANDL $~KZERO, AX 39 JMP* AX 40 41/* 42 * Must be 4-byte aligned. 43 */ 44TEXT _multibootheader(SB), $0 45 LONG $0x1BADB002 /* magic */ 46 LONG $0x00010003 /* flags */ 47 LONG $-(0x1BADB002 + 0x00010003) /* checksum */ 48 LONG $_multibootheader-KZERO(SB) /* header_addr */ 49 LONG $_startKADDR-KZERO(SB) /* load_addr */ 50 LONG $edata-KZERO(SB) /* load_end_addr */ 51 LONG $end-KZERO(SB) /* bss_end_addr */ 52 LONG $_startKADDR-KZERO(SB) /* entry_addr */ 53 LONG $0 /* mode_type */ 54 LONG $0 /* width */ 55 LONG $0 /* height */ 56 LONG $0 /* depth */ 57 58/* 59 * In protected mode with paging turned off and segment registers setup 60 * to linear map all memory. Entered via a jump to PADDR(entry), 61 * the physical address of the virtual kernel entry point of KADDR(entry). 62 * Make the basic page tables for processor 0. Six pages are needed for 63 * the basic set: 64 * a page directory; 65 * page tables for mapping the first 8MB of physical memory to KZERO; 66 * a page for the GDT; 67 * virtual and physical pages for mapping the Mach structure. 68 * The remaining PTEs will be allocated later when memory is sized. 69 * An identity mmu map is also needed for the switch to virtual mode. 70 * This identity mapping is removed once the MMU is going and the JMP has 71 * been made to virtual memory. 72 */ 73TEXT _startPADDR(SB), $0 74 CLI /* make sure interrupts are off */ 75 76 /* set up the gdt so we have sane plan 9 style gdts. */ 77 MOVL $tgdtptr(SB), AX 78 ANDL $~KZERO, AX 79 MOVL (AX), GDTR 80 MOVW $1, AX 81 MOVW AX, MSW 82 83 /* clear prefetch queue (weird code to avoid optimizations) */ 84 DELAY 85 86 /* set segs to something sane (avoid traps later) */ 87 MOVW $(1<<3), AX 88 MOVW AX, DS 89 MOVW AX, SS 90 MOVW AX, ES 91 MOVW AX, FS 92 MOVW AX, GS 93 94/* JMP $(2<<3):$mode32bit(SB) /**/ 95 BYTE $0xEA 96 LONG $mode32bit-KZERO(SB) 97 WORD $(2<<3) 98 99/* 100 * gdt to get us to 32-bit/segmented/unpaged mode 101 */ 102TEXT tgdt(SB), $0 103 104 /* null descriptor */ 105 LONG $0 106 LONG $0 107 108 /* data segment descriptor for 4 gigabytes (PL 0) */ 109 LONG $(0xFFFF) 110 LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW) 111 112 /* exec segment descriptor for 4 gigabytes (PL 0) */ 113 LONG $(0xFFFF) 114 LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR) 115 116/* 117 * pointer to initial gdt 118 * Note the -KZERO which puts the physical address in the gdtptr. 119 * that's needed as we start executing in physical addresses. 120 */ 121TEXT tgdtptr(SB), $0 122 WORD $(3*8) 123 LONG $tgdt-KZERO(SB) 124 125TEXT m0rgdtptr(SB), $0 126 WORD $(NGDT*8-1) 127 LONG $(CPU0GDT-KZERO) 128 129TEXT m0gdtptr(SB), $0 130 WORD $(NGDT*8-1) 131 LONG $CPU0GDT 132 133TEXT m0idtptr(SB), $0 134 WORD $(256*8-1) 135 LONG $IDTADDR 136 137TEXT mode32bit(SB), $0 138 /* At this point, the GDT setup is done. */ 139 140 MOVL $PADDR(CPU0PDB), DI /* clear 4 pages for the tables etc. */ 141 XORL AX, AX 142 MOVL $(4*BY2PG), CX 143 SHRL $2, CX 144 145 CLD 146 REP; STOSL 147 148 MOVL $PADDR(CPU0PDB), AX 149 ADDL $PDO(KZERO), AX /* page directory offset for KZERO */ 150 MOVL $PADDR(CPU0PTE), (AX) /* PTE's for KZERO */ 151 MOVL $(PTEWRITE|PTEVALID), BX /* page permissions */ 152 ORL BX, (AX) 153 154 ADDL $4, AX 155 MOVL $PADDR(CPU0PTE1), (AX) /* PTE's for KZERO+4MB */ 156 MOVL $(PTEWRITE|PTEVALID), BX /* page permissions */ 157 ORL BX, (AX) 158 159 MOVL $PADDR(CPU0PTE), AX /* first page of page table */ 160 MOVL $1024, CX /* 1024 pages in 4MB */ 161_setpte: 162 MOVL BX, (AX) 163 ADDL $(1<<PGSHIFT), BX 164 ADDL $4, AX 165 LOOP _setpte 166 167 MOVL $PADDR(CPU0PTE1), AX /* second page of page table */ 168 MOVL $1024, CX /* 1024 pages in 4MB */ 169_setpte1: 170 MOVL BX, (AX) 171 ADDL $(1<<PGSHIFT), BX 172 ADDL $4, AX 173 LOOP _setpte1 174 175 MOVL $PADDR(CPU0PTE), AX 176 ADDL $PTO(MACHADDR), AX /* page table entry offset for MACHADDR */ 177 MOVL $PADDR(CPU0MACH), (AX) /* PTE for Mach */ 178 MOVL $(PTEWRITE|PTEVALID), BX /* page permissions */ 179 ORL BX, (AX) 180 181/* 182 * Now ready to use the new map. Make sure the processor options are what is wanted. 183 * It is necessary on some processors to immediately follow mode switching with a JMP instruction 184 * to clear the prefetch queues. 185 */ 186 MOVL $PADDR(CPU0PDB), CX /* load address of page directory */ 187 MOVL (PDO(KZERO))(CX), DX /* double-map KZERO at 0 */ 188 MOVL DX, (PDO(0))(CX) 189 MOVL CX, CR3 190 DELAY /* JMP .+2 */ 191 192 MOVL CR0, DX 193 ORL $0x80010000, DX /* PG|WP */ 194 ANDL $~0x6000000A, DX /* ~(CD|NW|TS|MP) */ 195 196 MOVL $_startpg(SB), AX /* this is a virtual address */ 197 MOVL DX, CR0 /* turn on paging */ 198 JMP* AX /* jump to the virtual nirvana */ 199 200/* 201 * Basic machine environment set, can clear BSS and create a stack. 202 * The stack starts at the top of the page containing the Mach structure. 203 * The x86 architecture forces the use of the same virtual address for 204 * each processor's Mach structure, so the global Mach pointer 'm' can 205 * be initialised here. 206 */ 207TEXT _startpg(SB), $0 208 MOVL $0, (PDO(0))(CX) /* undo double-map of KZERO at 0 */ 209 MOVL CX, CR3 /* load and flush the mmu */ 210 211_clearbss: 212 MOVL $edata(SB), DI 213 XORL AX, AX 214 MOVL $end(SB), CX 215 SUBL DI, CX /* end-edata bytes */ 216 SHRL $2, CX /* end-edata doublewords */ 217 218 CLD 219 REP; STOSL /* clear BSS */ 220 221 MOVL $MACHADDR, SP 222 MOVL SP, m(SB) /* initialise global Mach pointer */ 223 MOVL $0, 0(SP) /* initialise m->machno */ 224 225 226 ADDL $(MACHSIZE-4), SP /* initialise stack */ 227 228/* 229 * Need to do one final thing to ensure a clean machine environment, 230 * clear the EFLAGS register, which can only be done once there is a stack. 231 */ 232 MOVL $0, AX 233 PUSHL AX 234 POPFL 235 236 CALL main(SB) 237 238/* 239 * Park a processor. Should never fall through a return from main to here, 240 * should only be called by application processors when shutting down. 241 */ 242TEXT idle(SB), $0 243_idle: 244 STI 245 HLT 246 JMP _idle 247 248/* 249 * Save registers. 250 */ 251TEXT saveregs(SB), $0 252 /* appease 8l */ 253 SUBL $32, SP 254 POPL AX 255 POPL AX 256 POPL AX 257 POPL AX 258 POPL AX 259 POPL AX 260 POPL AX 261 POPL AX 262 263 PUSHL AX 264 PUSHL BX 265 PUSHL CX 266 PUSHL DX 267 PUSHL BP 268 PUSHL DI 269 PUSHL SI 270 PUSHFL 271 272 XCHGL 32(SP), AX /* swap return PC and saved flags */ 273 XCHGL 0(SP), AX 274 XCHGL 32(SP), AX 275 RET 276 277TEXT restoreregs(SB), $0 278 /* appease 8l */ 279 PUSHL AX 280 PUSHL AX 281 PUSHL AX 282 PUSHL AX 283 PUSHL AX 284 PUSHL AX 285 PUSHL AX 286 PUSHL AX 287 ADDL $32, SP 288 289 XCHGL 32(SP), AX /* swap return PC and saved flags */ 290 XCHGL 0(SP), AX 291 XCHGL 32(SP), AX 292 293 POPFL 294 POPL SI 295 POPL DI 296 POPL BP 297 POPL DX 298 POPL CX 299 POPL BX 300 POPL AX 301 RET 302 303/* 304 * Assumed to be in protected mode at time of call. 305 * Switch to real mode, execute an interrupt, and 306 * then switch back to protected mode. 307 * 308 * Assumes: 309 * 310 * - no device interrupts are going to come in 311 * - 0-16MB is identity mapped in page tables 312 * - realmode() has copied us down from 0x100000 to 0x8000 313 * - can use code segment 0x0800 in real mode 314 * to get at l.s code 315 * - l.s code is less than 1 page 316 */ 317#define RELOC (RMCODE-KTZERO) 318 319TEXT realmodeidtptr(SB), $0 320 WORD $(4*256-1) 321 LONG $0 322 323TEXT realmode0(SB), $0 324 CALL saveregs(SB) 325 326 /* switch to low code address */ 327 LEAL physcode-KZERO(SB), AX 328 JMP *AX 329 330TEXT physcode(SB), $0 331 332 /* switch to low stack */ 333 MOVL SP, AX 334 MOVL $0x7C00, SP 335 PUSHL AX 336 337 /* change gdt to physical pointer */ 338 MOVL m0rgdtptr-KZERO(SB), GDTR 339 340 /* load IDT with real-mode version*/ 341 MOVL realmodeidtptr-KZERO(SB), IDTR 342 343 /* edit INT $0x00 instruction below */ 344 MOVL $(RMUADDR-KZERO+48), AX /* &rmu.trap */ 345 MOVL (AX), AX 346 MOVB AX, realmodeintrinst+(-KZERO+1+RELOC)(SB) 347 348 /* disable paging */ 349 MOVL CR0, AX 350 ANDL $0x7FFFFFFF, AX 351 MOVL AX, CR0 352 /* JMP .+2 to clear prefetch queue*/ 353 BYTE $0xEB; BYTE $0x00 354 355 /* jump to 16-bit code segment */ 356/* JMPFAR SELECTOR(KESEG16, SELGDT, 0):$again16bit(SB) /**/ 357 BYTE $0xEA 358 LONG $again16bit-KZERO(SB) 359 WORD $SELECTOR(KESEG16, SELGDT, 0) 360 361TEXT again16bit(SB), $0 362 /* 363 * Now in 16-bit compatibility mode. 364 * These are 32-bit instructions being interpreted 365 * as 16-bit instructions. I'm being lazy and 366 * not using the macros because I know when 367 * the 16- and 32-bit instructions look the same 368 * or close enough. 369 */ 370 371 /* disable protected mode and jump to real mode cs */ 372 OPSIZE; MOVL CR0, AX 373 OPSIZE; XORL BX, BX 374 OPSIZE; INCL BX 375 OPSIZE; XORL BX, AX 376 OPSIZE; MOVL AX, CR0 377 378 /* JMPFAR 0x0800:now16real */ 379 BYTE $0xEA 380 WORD $now16real-KZERO(SB) 381 WORD $0x0800 382 383TEXT now16real(SB), $0 384 /* copy the registers for the bios call */ 385 LWI(0x0000, rAX) 386 MOVW AX,SS 387 LWI(RMUADDR, rBP) 388 389 /* offsets are in Ureg */ 390 LXW(44, xBP, rAX) 391 MOVW AX, DS 392 LXW(40, xBP, rAX) 393 MOVW AX, ES 394 395 OPSIZE; LXW(0, xBP, rDI) 396 OPSIZE; LXW(4, xBP, rSI) 397 OPSIZE; LXW(16, xBP, rBX) 398 OPSIZE; LXW(20, xBP, rDX) 399 OPSIZE; LXW(24, xBP, rCX) 400 OPSIZE; LXW(28, xBP, rAX) 401 402 CLC 403 404TEXT realmodeintrinst(SB), $0 405 INT $0x00 406 407 /* save the registers after the call */ 408 409 LWI(0x7bfc, rSP) 410 OPSIZE; PUSHFL 411 OPSIZE; PUSHL AX 412 413 LWI(0, rAX) 414 MOVW AX,SS 415 LWI(RMUADDR, rBP) 416 417 OPSIZE; SXW(rDI, 0, xBP) 418 OPSIZE; SXW(rSI, 4, xBP) 419 OPSIZE; SXW(rBX, 16, xBP) 420 OPSIZE; SXW(rDX, 20, xBP) 421 OPSIZE; SXW(rCX, 24, xBP) 422 OPSIZE; POPL AX 423 OPSIZE; SXW(rAX, 28, xBP) 424 425 MOVW DS, AX 426 OPSIZE; SXW(rAX, 44, xBP) 427 MOVW ES, AX 428 OPSIZE; SXW(rAX, 40, xBP) 429 430 OPSIZE; POPL AX 431 OPSIZE; SXW(rAX, 64, xBP) /* flags */ 432 433 /* re-enter protected mode and jump to 32-bit code */ 434 OPSIZE; MOVL $1, AX 435 OPSIZE; MOVL AX, CR0 436 437/* JMPFAR SELECTOR(KESEG, SELGDT, 0):$again32bit(SB) /**/ 438 OPSIZE 439 BYTE $0xEA 440 LONG $again32bit-KZERO(SB) 441 WORD $SELECTOR(KESEG, SELGDT, 0) 442 443TEXT again32bit(SB), $0 444 MOVW $SELECTOR(KDSEG, SELGDT, 0),AX 445 MOVW AX,DS 446 MOVW AX,SS 447 MOVW AX,ES 448 MOVW AX,FS 449 MOVW AX,GS 450 451 /* enable paging and jump to kzero-address code */ 452 MOVL CR0, AX 453 ORL $0x80010000, AX /* PG|WP */ 454 MOVL AX, CR0 455 LEAL again32kzero(SB), AX 456 JMP* AX 457 458TEXT again32kzero(SB), $0 459 /* breathe a sigh of relief - back in 32-bit protected mode */ 460 461 /* switch to old stack */ 462 PUSHL AX /* match popl below for 8l */ 463 MOVL $0x7BFC, SP 464 POPL SP 465 466 /* restore idt */ 467 MOVL m0idtptr(SB),IDTR 468 469 /* restore gdt */ 470 MOVL m0gdtptr(SB), GDTR 471 472 CALL restoreregs(SB) 473 RET 474 475/* 476 * BIOS32. 477 */ 478TEXT bios32call(SB), $0 479 MOVL ci+0(FP), BP 480 MOVL 0(BP), AX 481 MOVL 4(BP), BX 482 MOVL 8(BP), CX 483 MOVL 12(BP), DX 484 MOVL 16(BP), SI 485 MOVL 20(BP), DI 486 PUSHL BP 487 488 MOVL 12(SP), BP /* ptr */ 489 BYTE $0xFF; BYTE $0x5D; BYTE $0x00 /* CALL FAR 0(BP) */ 490 491 POPL BP 492 MOVL DI, 20(BP) 493 MOVL SI, 16(BP) 494 MOVL DX, 12(BP) 495 MOVL CX, 8(BP) 496 MOVL BX, 4(BP) 497 MOVL AX, 0(BP) 498 499 XORL AX, AX 500 JCC _bios32xxret 501 INCL AX 502 503_bios32xxret: 504 RET 505 506/* 507 * Port I/O. 508 * in[bsl] input a byte|short|long 509 * ins[bsl] input a string of bytes|shorts|longs 510 * out[bsl] output a byte|short|long 511 * outs[bsl] output a string of bytes|shorts|longs 512 */ 513TEXT inb(SB), $0 514 MOVL port+0(FP), DX 515 XORL AX, AX 516 INB 517 RET 518 519TEXT insb(SB), $0 520 MOVL port+0(FP), DX 521 MOVL address+4(FP), DI 522 MOVL count+8(FP), CX 523 CLD 524 REP; INSB 525 RET 526 527TEXT ins(SB), $0 528 MOVL port+0(FP), DX 529 XORL AX, AX 530 OP16; INL 531 RET 532 533TEXT inss(SB), $0 534 MOVL port+0(FP), DX 535 MOVL address+4(FP), DI 536 MOVL count+8(FP), CX 537 CLD 538 REP; OP16; INSL 539 RET 540 541TEXT inl(SB), $0 542 MOVL port+0(FP), DX 543 INL 544 RET 545 546TEXT insl(SB), $0 547 MOVL port+0(FP), DX 548 MOVL address+4(FP), DI 549 MOVL count+8(FP), CX 550 CLD 551 REP; INSL 552 RET 553 554TEXT outb(SB), $0 555 MOVL port+0(FP), DX 556 MOVL byte+4(FP), AX 557 OUTB 558 RET 559 560TEXT outsb(SB), $0 561 MOVL port+0(FP), DX 562 MOVL address+4(FP), SI 563 MOVL count+8(FP), CX 564 CLD 565 REP; OUTSB 566 RET 567 568TEXT outs(SB), $0 569 MOVL port+0(FP), DX 570 MOVL short+4(FP), AX 571 OP16; OUTL 572 RET 573 574TEXT outss(SB), $0 575 MOVL port+0(FP), DX 576 MOVL address+4(FP), SI 577 MOVL count+8(FP), CX 578 CLD 579 REP; OP16; OUTSL 580 RET 581 582TEXT outl(SB), $0 583 MOVL port+0(FP), DX 584 MOVL long+4(FP), AX 585 OUTL 586 RET 587 588TEXT outsl(SB), $0 589 MOVL port+0(FP), DX 590 MOVL address+4(FP), SI 591 MOVL count+8(FP), CX 592 CLD 593 REP; OUTSL 594 RET 595 596/* 597 * Read/write various system registers. 598 * CR4 and the 'model specific registers' should only be read/written 599 * after it has been determined the processor supports them 600 */ 601TEXT lgdt(SB), $0 /* GDTR - global descriptor table */ 602 MOVL gdtptr+0(FP), AX 603 MOVL (AX), GDTR 604 RET 605 606TEXT lidt(SB), $0 /* IDTR - interrupt descriptor table */ 607 MOVL idtptr+0(FP), AX 608 MOVL (AX), IDTR 609 RET 610 611TEXT ltr(SB), $0 /* TR - task register */ 612 MOVL tptr+0(FP), AX 613 MOVW AX, TASK 614 RET 615 616TEXT getcr0(SB), $0 /* CR0 - processor control */ 617 MOVL CR0, AX 618 RET 619 620TEXT getcr2(SB), $0 /* CR2 - page fault linear address */ 621 MOVL CR2, AX 622 RET 623 624TEXT getcr3(SB), $0 /* CR3 - page directory base */ 625 MOVL CR3, AX 626 RET 627 628TEXT putcr0(SB), $0 629 MOVL cr0+0(FP), AX 630 MOVL AX, CR0 631 RET 632 633TEXT putcr3(SB), $0 634 MOVL cr3+0(FP), AX 635 MOVL AX, CR3 636 RET 637 638TEXT getcr4(SB), $0 /* CR4 - extensions */ 639 MOVL CR4, AX 640 RET 641 642TEXT putcr4(SB), $0 643 MOVL cr4+0(FP), AX 644 MOVL AX, CR4 645 RET 646 647TEXT invlpg(SB), $0 648 /* 486+ only */ 649 MOVL va+0(FP), CX 650 INVLPG 651 RET 652 653TEXT wbinvd(SB), $0 654 WBINVD 655 RET 656 657TEXT _cycles(SB), $0 /* time stamp counter */ 658 RDTSC 659 MOVL vlong+0(FP), CX /* &vlong */ 660 MOVL AX, 0(CX) /* lo */ 661 MOVL DX, 4(CX) /* hi */ 662 RET 663 664/* 665 * stub for: 666 * time stamp counter; low-order 32 bits of 64-bit cycle counter 667 * Runs at fasthz/4 cycles per second (m->clkin>>3) 668 */ 669TEXT lcycles(SB),1,$0 670 RDTSC 671 RET 672 673TEXT rdmsr(SB), $0 /* model-specific register */ 674 MOVL index+0(FP), CX 675 RDMSR 676 MOVL vlong+4(FP), CX /* &vlong */ 677 MOVL AX, 0(CX) /* lo */ 678 MOVL DX, 4(CX) /* hi */ 679 RET 680 681TEXT wrmsr(SB), $0 682 MOVL index+0(FP), CX 683 MOVL lo+4(FP), AX 684 MOVL hi+8(FP), DX 685 WRMSR 686 RET 687 688/* 689 * Try to determine the CPU type which requires fiddling with EFLAGS. 690 * If the Id bit can be toggled then the CPUID instruction can be used 691 * to determine CPU identity and features. First have to check if it's 692 * a 386 (Ac bit can't be set). If it's not a 386 and the Id bit can't be 693 * toggled then it's an older 486 of some kind. 694 * 695 * cpuid(fun, regs[4]); 696 */ 697TEXT cpuid(SB), $0 698 MOVL $0x240000, AX 699 PUSHL AX 700 POPFL /* set Id|Ac */ 701 PUSHFL 702 POPL BX /* retrieve value */ 703 MOVL $0, AX 704 PUSHL AX 705 POPFL /* clear Id|Ac, EFLAGS initialised */ 706 PUSHFL 707 POPL AX /* retrieve value */ 708 XORL BX, AX 709 TESTL $0x040000, AX /* Ac */ 710 JZ _cpu386 /* can't set this bit on 386 */ 711 TESTL $0x200000, AX /* Id */ 712 JZ _cpu486 /* can't toggle this bit on some 486 */ 713 /* load registers */ 714 MOVL regs+4(FP), BP 715 MOVL fn+0(FP), AX /* cpuid function */ 716 MOVL 4(BP), BX 717 MOVL 8(BP), CX /* typically an index */ 718 MOVL 12(BP), DX 719 CPUID 720 JMP _cpuid 721_cpu486: 722 MOVL $0x400, AX 723 JMP _maybezapax 724_cpu386: 725 MOVL $0x300, AX 726_maybezapax: 727 CMPL fn+0(FP), $1 728 JE _zaprest 729 XORL AX, AX 730_zaprest: 731 XORL BX, BX 732 XORL CX, CX 733 XORL DX, DX 734_cpuid: 735 MOVL regs+4(FP), BP 736 MOVL AX, 0(BP) 737 MOVL BX, 4(BP) 738 MOVL CX, 8(BP) 739 MOVL DX, 12(BP) 740 RET 741 742/* 743 * Basic timing loop to determine CPU frequency. 744 */ 745TEXT aamloop(SB), $0 746 MOVL count+0(FP), CX 747_aamloop: 748 AAM 749 LOOP _aamloop 750 RET 751 752/* 753 * Floating point. 754 * Note: the encodings for the FCLEX, FINIT, FSAVE, FSTCW, FSENV and FSTSW 755 * instructions do NOT have the WAIT prefix byte (i.e. they act like their 756 * FNxxx variations) so WAIT instructions must be explicitly placed in the 757 * code as necessary. 758 */ 759#define FPOFF(l) ;\ 760 MOVL CR0, AX ;\ 761 ANDL $0xC, AX /* EM, TS */ ;\ 762 CMPL AX, $0x8 ;\ 763 JEQ l ;\ 764 WAIT ;\ 765l: ;\ 766 MOVL CR0, AX ;\ 767 ANDL $~0x4, AX /* EM=0 */ ;\ 768 ORL $0x28, AX /* NE=1, TS=1 */ ;\ 769 MOVL AX, CR0 770 771#define FPON ;\ 772 MOVL CR0, AX ;\ 773 ANDL $~0xC, AX /* EM=0, TS=0 */ ;\ 774 MOVL AX, CR0 775 776TEXT fpoff(SB), $0 /* disable */ 777 FPOFF(l1) 778 RET 779 780TEXT fpinit(SB), $0 /* enable and init */ 781 FPON 782 FINIT 783 WAIT 784 /* setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPOVFL) */ 785 /* note that low 6 bits are masks, not enables, on this chip */ 786 PUSHW $0x0232 787 FLDCW 0(SP) 788 POPW AX 789 WAIT 790 RET 791 792TEXT fpx87save(SB), $0 /* save state and disable */ 793 MOVL p+0(FP), AX 794 FSAVE 0(AX) /* no WAIT */ 795 FPOFF(l2) 796 RET 797 798TEXT fpx87restore(SB), $0 /* enable and restore state */ 799 FPON 800 MOVL p+0(FP), AX 801 FRSTOR 0(AX) 802 WAIT 803 RET 804 805TEXT fpstatus(SB), $0 /* get floating point status */ 806 FSTSW AX 807 RET 808 809TEXT fpenv(SB), $0 /* save state without waiting */ 810 MOVL p+0(FP), AX 811 FSTENV 0(AX) 812 RET 813 814TEXT fpclear(SB), $0 /* clear pending exceptions */ 815 FPON 816 FCLEX /* no WAIT */ 817 FPOFF(l3) 818 RET 819 820TEXT fpssesave0(SB), $0 /* save state and disable */ 821 MOVL p+0(FP), AX 822 FXSAVE /* no WAIT */ 823 FPOFF(l4) 824 RET 825 826TEXT fpsserestore0(SB), $0 /* enable and restore state */ 827 FPON 828 MOVL p+0(FP), AX 829 FXRSTOR 830 WAIT 831 RET 832 833/* 834 */ 835TEXT splhi(SB), $0 836shi: 837 PUSHFL 838 POPL AX 839 TESTL $0x200, AX 840 JZ alreadyhi 841 MOVL $(MACHADDR+0x04), CX /* save PC in m->splpc */ 842 MOVL (SP), BX 843 MOVL BX, (CX) 844alreadyhi: 845 CLI 846 RET 847 848TEXT spllo(SB), $0 849slo: 850 PUSHFL 851 POPL AX 852 TESTL $0x200, AX 853 JNZ alreadylo 854 MOVL $(MACHADDR+0x04), CX /* clear m->splpc */ 855 MOVL $0, (CX) 856alreadylo: 857 STI 858 RET 859 860TEXT splx(SB), $0 861 MOVL s+0(FP), AX 862 TESTL $0x200, AX 863 JNZ slo 864 JMP shi 865 866TEXT spldone(SB), $0 867 RET 868 869TEXT islo(SB), $0 870 PUSHFL 871 POPL AX 872 ANDL $0x200, AX /* interrupt enable flag */ 873 RET 874 875/* 876 * Test-And-Set 877 */ 878TEXT tas(SB), $0 879 MOVL $0xDEADDEAD, AX 880 MOVL lock+0(FP), BX 881 XCHGL AX, (BX) /* lock->key */ 882 RET 883 884TEXT _xinc(SB), $0 /* void _xinc(long*); */ 885 MOVL l+0(FP), AX 886 LOCK; INCL 0(AX) 887 RET 888 889TEXT _xdec(SB), $0 /* long _xdec(long*); */ 890 MOVL l+0(FP), BX 891 XORL AX, AX 892 LOCK; DECL 0(BX) 893 JLT _xdeclt 894 JGT _xdecgt 895 RET 896_xdecgt: 897 INCL AX 898 RET 899_xdeclt: 900 DECL AX 901 RET 902 903TEXT mb386(SB), $0 904 POPL AX /* return PC */ 905 PUSHFL 906 PUSHL CS 907 PUSHL AX 908 IRETL 909 910TEXT mb586(SB), $0 911 XORL AX, AX 912 CPUID 913 RET 914 915TEXT sfence(SB), $0 916 BYTE $0x0f 917 BYTE $0xae 918 BYTE $0xf8 919 RET 920 921TEXT lfence(SB), $0 922 BYTE $0x0f 923 BYTE $0xae 924 BYTE $0xe8 925 RET 926 927TEXT mfence(SB), $0 928 BYTE $0x0f 929 BYTE $0xae 930 BYTE $0xf0 931 RET 932 933TEXT xchgw(SB), $0 934 MOVL v+4(FP), AX 935 MOVL p+0(FP), BX 936 XCHGW AX, (BX) 937 RET 938 939TEXT cmpswap486(SB), $0 940 MOVL addr+0(FP), BX 941 MOVL old+4(FP), AX 942 MOVL new+8(FP), CX 943 LOCK 944 BYTE $0x0F; BYTE $0xB1; BYTE $0x0B /* CMPXCHGL CX, (BX) */ 945 JNZ didnt 946 MOVL $1, AX 947 RET 948didnt: 949 XORL AX,AX 950 RET 951 952TEXT mul64fract(SB), $0 953/* 954 * Multiply two 64-bit number s and keep the middle 64 bits from the 128-bit result 955 * See ../port/tod.c for motivation. 956 */ 957 MOVL r+0(FP), CX 958 XORL BX, BX /* BX = 0 */ 959 960 MOVL a+8(FP), AX 961 MULL b+16(FP) /* a1*b1 */ 962 MOVL AX, 4(CX) /* r2 = lo(a1*b1) */ 963 964 MOVL a+8(FP), AX 965 MULL b+12(FP) /* a1*b0 */ 966 MOVL AX, 0(CX) /* r1 = lo(a1*b0) */ 967 ADDL DX, 4(CX) /* r2 += hi(a1*b0) */ 968 969 MOVL a+4(FP), AX 970 MULL b+16(FP) /* a0*b1 */ 971 ADDL AX, 0(CX) /* r1 += lo(a0*b1) */ 972 ADCL DX, 4(CX) /* r2 += hi(a0*b1) + carry */ 973 974 MOVL a+4(FP), AX 975 MULL b+12(FP) /* a0*b0 */ 976 ADDL DX, 0(CX) /* r1 += hi(a0*b0) */ 977 ADCL BX, 4(CX) /* r2 += carry */ 978 RET 979 980/* 981 * label consists of a stack pointer and a PC 982 */ 983TEXT gotolabel(SB), $0 984 MOVL label+0(FP), AX 985 MOVL 0(AX), SP /* restore sp */ 986 MOVL 4(AX), AX /* put return pc on the stack */ 987 MOVL AX, 0(SP) 988 MOVL $1, AX /* return 1 */ 989 RET 990 991TEXT setlabel(SB), $0 992 MOVL label+0(FP), AX 993 MOVL SP, 0(AX) /* store sp */ 994 MOVL 0(SP), BX /* store return pc */ 995 MOVL BX, 4(AX) 996 MOVL $0, AX /* return 0 */ 997 RET 998 999/* 1000 * Attempt at power saving. -rsc 1001 */ 1002TEXT halt(SB), $0 1003 CLI 1004 CMPL nrdy(SB), $0 1005 JEQ _nothingready 1006 STI 1007 RET 1008 1009_nothingready: 1010 STI 1011 HLT 1012 RET 1013 1014/* 1015 * Interrupt/exception handling. 1016 * Each entry in the vector table calls either _strayintr or _strayintrx depending 1017 * on whether an error code has been automatically pushed onto the stack 1018 * (_strayintrx) or not, in which case a dummy entry must be pushed before retrieving 1019 * the trap type from the vector table entry and placing it on the stack as part 1020 * of the Ureg structure. 1021 * The size of each entry in the vector table (6 bytes) is known in trapinit(). 1022 */ 1023TEXT _strayintr(SB), $0 1024 PUSHL AX /* save AX */ 1025 MOVL 4(SP), AX /* return PC from vectortable(SB) */ 1026 JMP intrcommon 1027 1028TEXT _strayintrx(SB), $0 1029 XCHGL AX, (SP) /* swap AX with vectortable CALL PC */ 1030intrcommon: 1031 PUSHL DS /* save DS */ 1032 PUSHL $(KDSEL) 1033 POPL DS /* fix up DS */ 1034 MOVBLZX (AX), AX /* trap type -> AX */ 1035 XCHGL AX, 4(SP) /* exchange trap type with saved AX */ 1036 1037 PUSHL ES /* save ES */ 1038 PUSHL $(KDSEL) 1039 POPL ES /* fix up ES */ 1040 1041 PUSHL FS /* save the rest of the Ureg struct */ 1042 PUSHL GS 1043 PUSHAL 1044 1045 PUSHL SP /* Ureg* argument to trap */ 1046 CALL trap(SB) 1047 1048TEXT forkret(SB), $0 1049 POPL AX 1050 POPAL 1051 POPL GS 1052 POPL FS 1053 POPL ES 1054 POPL DS 1055 ADDL $8, SP /* pop error code and trap type */ 1056 IRETL 1057 1058TEXT vectortable(SB), $0 1059 CALL _strayintr(SB); BYTE $0x00 /* divide error */ 1060 CALL _strayintr(SB); BYTE $0x01 /* debug exception */ 1061 CALL _strayintr(SB); BYTE $0x02 /* NMI interrupt */ 1062 CALL _strayintr(SB); BYTE $0x03 /* breakpoint */ 1063 CALL _strayintr(SB); BYTE $0x04 /* overflow */ 1064 CALL _strayintr(SB); BYTE $0x05 /* bound */ 1065 CALL _strayintr(SB); BYTE $0x06 /* invalid opcode */ 1066 CALL _strayintr(SB); BYTE $0x07 /* no coprocessor available */ 1067 CALL _strayintrx(SB); BYTE $0x08 /* double fault */ 1068 CALL _strayintr(SB); BYTE $0x09 /* coprocessor segment overflow */ 1069 CALL _strayintrx(SB); BYTE $0x0A /* invalid TSS */ 1070 CALL _strayintrx(SB); BYTE $0x0B /* segment not available */ 1071 CALL _strayintrx(SB); BYTE $0x0C /* stack exception */ 1072 CALL _strayintrx(SB); BYTE $0x0D /* general protection error */ 1073 CALL _strayintrx(SB); BYTE $0x0E /* page fault */ 1074 CALL _strayintr(SB); BYTE $0x0F /* */ 1075 CALL _strayintr(SB); BYTE $0x10 /* coprocessor error */ 1076 CALL _strayintrx(SB); BYTE $0x11 /* alignment check */ 1077 CALL _strayintr(SB); BYTE $0x12 /* machine check */ 1078 CALL _strayintr(SB); BYTE $0x13 1079 CALL _strayintr(SB); BYTE $0x14 1080 CALL _strayintr(SB); BYTE $0x15 1081 CALL _strayintr(SB); BYTE $0x16 1082 CALL _strayintr(SB); BYTE $0x17 1083 CALL _strayintr(SB); BYTE $0x18 1084 CALL _strayintr(SB); BYTE $0x19 1085 CALL _strayintr(SB); BYTE $0x1A 1086 CALL _strayintr(SB); BYTE $0x1B 1087 CALL _strayintr(SB); BYTE $0x1C 1088 CALL _strayintr(SB); BYTE $0x1D 1089 CALL _strayintr(SB); BYTE $0x1E 1090 CALL _strayintr(SB); BYTE $0x1F 1091 CALL _strayintr(SB); BYTE $0x20 /* VectorLAPIC */ 1092 CALL _strayintr(SB); BYTE $0x21 1093 CALL _strayintr(SB); BYTE $0x22 1094 CALL _strayintr(SB); BYTE $0x23 1095 CALL _strayintr(SB); BYTE $0x24 1096 CALL _strayintr(SB); BYTE $0x25 1097 CALL _strayintr(SB); BYTE $0x26 1098 CALL _strayintr(SB); BYTE $0x27 1099 CALL _strayintr(SB); BYTE $0x28 1100 CALL _strayintr(SB); BYTE $0x29 1101 CALL _strayintr(SB); BYTE $0x2A 1102 CALL _strayintr(SB); BYTE $0x2B 1103 CALL _strayintr(SB); BYTE $0x2C 1104 CALL _strayintr(SB); BYTE $0x2D 1105 CALL _strayintr(SB); BYTE $0x2E 1106 CALL _strayintr(SB); BYTE $0x2F 1107 CALL _strayintr(SB); BYTE $0x30 1108 CALL _strayintr(SB); BYTE $0x31 1109 CALL _strayintr(SB); BYTE $0x32 1110 CALL _strayintr(SB); BYTE $0x33 1111 CALL _strayintr(SB); BYTE $0x34 1112 CALL _strayintr(SB); BYTE $0x35 1113 CALL _strayintr(SB); BYTE $0x36 1114 CALL _strayintr(SB); BYTE $0x37 1115 CALL _strayintr(SB); BYTE $0x38 1116 CALL _strayintr(SB); BYTE $0x39 1117 CALL _strayintr(SB); BYTE $0x3A 1118 CALL _strayintr(SB); BYTE $0x3B 1119 CALL _strayintr(SB); BYTE $0x3C 1120 CALL _strayintr(SB); BYTE $0x3D 1121 CALL _strayintr(SB); BYTE $0x3E 1122 CALL _strayintr(SB); BYTE $0x3F 1123 CALL _syscallintr(SB); BYTE $0x40 /* VectorSYSCALL */ 1124 CALL _strayintr(SB); BYTE $0x41 1125 CALL _strayintr(SB); BYTE $0x42 1126 CALL _strayintr(SB); BYTE $0x43 1127 CALL _strayintr(SB); BYTE $0x44 1128 CALL _strayintr(SB); BYTE $0x45 1129 CALL _strayintr(SB); BYTE $0x46 1130 CALL _strayintr(SB); BYTE $0x47 1131 CALL _strayintr(SB); BYTE $0x48 1132 CALL _strayintr(SB); BYTE $0x49 1133 CALL _strayintr(SB); BYTE $0x4A 1134 CALL _strayintr(SB); BYTE $0x4B 1135 CALL _strayintr(SB); BYTE $0x4C 1136 CALL _strayintr(SB); BYTE $0x4D 1137 CALL _strayintr(SB); BYTE $0x4E 1138 CALL _strayintr(SB); BYTE $0x4F 1139 CALL _strayintr(SB); BYTE $0x50 1140 CALL _strayintr(SB); BYTE $0x51 1141 CALL _strayintr(SB); BYTE $0x52 1142 CALL _strayintr(SB); BYTE $0x53 1143 CALL _strayintr(SB); BYTE $0x54 1144 CALL _strayintr(SB); BYTE $0x55 1145 CALL _strayintr(SB); BYTE $0x56 1146 CALL _strayintr(SB); BYTE $0x57 1147 CALL _strayintr(SB); BYTE $0x58 1148 CALL _strayintr(SB); BYTE $0x59 1149 CALL _strayintr(SB); BYTE $0x5A 1150 CALL _strayintr(SB); BYTE $0x5B 1151 CALL _strayintr(SB); BYTE $0x5C 1152 CALL _strayintr(SB); BYTE $0x5D 1153 CALL _strayintr(SB); BYTE $0x5E 1154 CALL _strayintr(SB); BYTE $0x5F 1155 CALL _strayintr(SB); BYTE $0x60 1156 CALL _strayintr(SB); BYTE $0x61 1157 CALL _strayintr(SB); BYTE $0x62 1158 CALL _strayintr(SB); BYTE $0x63 1159 CALL _strayintr(SB); BYTE $0x64 1160 CALL _strayintr(SB); BYTE $0x65 1161 CALL _strayintr(SB); BYTE $0x66 1162 CALL _strayintr(SB); BYTE $0x67 1163 CALL _strayintr(SB); BYTE $0x68 1164 CALL _strayintr(SB); BYTE $0x69 1165 CALL _strayintr(SB); BYTE $0x6A 1166 CALL _strayintr(SB); BYTE $0x6B 1167 CALL _strayintr(SB); BYTE $0x6C 1168 CALL _strayintr(SB); BYTE $0x6D 1169 CALL _strayintr(SB); BYTE $0x6E 1170 CALL _strayintr(SB); BYTE $0x6F 1171 CALL _strayintr(SB); BYTE $0x70 1172 CALL _strayintr(SB); BYTE $0x71 1173 CALL _strayintr(SB); BYTE $0x72 1174 CALL _strayintr(SB); BYTE $0x73 1175 CALL _strayintr(SB); BYTE $0x74 1176 CALL _strayintr(SB); BYTE $0x75 1177 CALL _strayintr(SB); BYTE $0x76 1178 CALL _strayintr(SB); BYTE $0x77 1179 CALL _strayintr(SB); BYTE $0x78 1180 CALL _strayintr(SB); BYTE $0x79 1181 CALL _strayintr(SB); BYTE $0x7A 1182 CALL _strayintr(SB); BYTE $0x7B 1183 CALL _strayintr(SB); BYTE $0x7C 1184 CALL _strayintr(SB); BYTE $0x7D 1185 CALL _strayintr(SB); BYTE $0x7E 1186 CALL _strayintr(SB); BYTE $0x7F 1187 CALL _strayintr(SB); BYTE $0x80 /* Vector[A]PIC */ 1188 CALL _strayintr(SB); BYTE $0x81 1189 CALL _strayintr(SB); BYTE $0x82 1190 CALL _strayintr(SB); BYTE $0x83 1191 CALL _strayintr(SB); BYTE $0x84 1192 CALL _strayintr(SB); BYTE $0x85 1193 CALL _strayintr(SB); BYTE $0x86 1194 CALL _strayintr(SB); BYTE $0x87 1195 CALL _strayintr(SB); BYTE $0x88 1196 CALL _strayintr(SB); BYTE $0x89 1197 CALL _strayintr(SB); BYTE $0x8A 1198 CALL _strayintr(SB); BYTE $0x8B 1199 CALL _strayintr(SB); BYTE $0x8C 1200 CALL _strayintr(SB); BYTE $0x8D 1201 CALL _strayintr(SB); BYTE $0x8E 1202 CALL _strayintr(SB); BYTE $0x8F 1203 CALL _strayintr(SB); BYTE $0x90 1204 CALL _strayintr(SB); BYTE $0x91 1205 CALL _strayintr(SB); BYTE $0x92 1206 CALL _strayintr(SB); BYTE $0x93 1207 CALL _strayintr(SB); BYTE $0x94 1208 CALL _strayintr(SB); BYTE $0x95 1209 CALL _strayintr(SB); BYTE $0x96 1210 CALL _strayintr(SB); BYTE $0x97 1211 CALL _strayintr(SB); BYTE $0x98 1212 CALL _strayintr(SB); BYTE $0x99 1213 CALL _strayintr(SB); BYTE $0x9A 1214 CALL _strayintr(SB); BYTE $0x9B 1215 CALL _strayintr(SB); BYTE $0x9C 1216 CALL _strayintr(SB); BYTE $0x9D 1217 CALL _strayintr(SB); BYTE $0x9E 1218 CALL _strayintr(SB); BYTE $0x9F 1219 CALL _strayintr(SB); BYTE $0xA0 1220 CALL _strayintr(SB); BYTE $0xA1 1221 CALL _strayintr(SB); BYTE $0xA2 1222 CALL _strayintr(SB); BYTE $0xA3 1223 CALL _strayintr(SB); BYTE $0xA4 1224 CALL _strayintr(SB); BYTE $0xA5 1225 CALL _strayintr(SB); BYTE $0xA6 1226 CALL _strayintr(SB); BYTE $0xA7 1227 CALL _strayintr(SB); BYTE $0xA8 1228 CALL _strayintr(SB); BYTE $0xA9 1229 CALL _strayintr(SB); BYTE $0xAA 1230 CALL _strayintr(SB); BYTE $0xAB 1231 CALL _strayintr(SB); BYTE $0xAC 1232 CALL _strayintr(SB); BYTE $0xAD 1233 CALL _strayintr(SB); BYTE $0xAE 1234 CALL _strayintr(SB); BYTE $0xAF 1235 CALL _strayintr(SB); BYTE $0xB0 1236 CALL _strayintr(SB); BYTE $0xB1 1237 CALL _strayintr(SB); BYTE $0xB2 1238 CALL _strayintr(SB); BYTE $0xB3 1239 CALL _strayintr(SB); BYTE $0xB4 1240 CALL _strayintr(SB); BYTE $0xB5 1241 CALL _strayintr(SB); BYTE $0xB6 1242 CALL _strayintr(SB); BYTE $0xB7 1243 CALL _strayintr(SB); BYTE $0xB8 1244 CALL _strayintr(SB); BYTE $0xB9 1245 CALL _strayintr(SB); BYTE $0xBA 1246 CALL _strayintr(SB); BYTE $0xBB 1247 CALL _strayintr(SB); BYTE $0xBC 1248 CALL _strayintr(SB); BYTE $0xBD 1249 CALL _strayintr(SB); BYTE $0xBE 1250 CALL _strayintr(SB); BYTE $0xBF 1251 CALL _strayintr(SB); BYTE $0xC0 1252 CALL _strayintr(SB); BYTE $0xC1 1253 CALL _strayintr(SB); BYTE $0xC2 1254 CALL _strayintr(SB); BYTE $0xC3 1255 CALL _strayintr(SB); BYTE $0xC4 1256 CALL _strayintr(SB); BYTE $0xC5 1257 CALL _strayintr(SB); BYTE $0xC6 1258 CALL _strayintr(SB); BYTE $0xC7 1259 CALL _strayintr(SB); BYTE $0xC8 1260 CALL _strayintr(SB); BYTE $0xC9 1261 CALL _strayintr(SB); BYTE $0xCA 1262 CALL _strayintr(SB); BYTE $0xCB 1263 CALL _strayintr(SB); BYTE $0xCC 1264 CALL _strayintr(SB); BYTE $0xCD 1265 CALL _strayintr(SB); BYTE $0xCE 1266 CALL _strayintr(SB); BYTE $0xCF 1267 CALL _strayintr(SB); BYTE $0xD0 1268 CALL _strayintr(SB); BYTE $0xD1 1269 CALL _strayintr(SB); BYTE $0xD2 1270 CALL _strayintr(SB); BYTE $0xD3 1271 CALL _strayintr(SB); BYTE $0xD4 1272 CALL _strayintr(SB); BYTE $0xD5 1273 CALL _strayintr(SB); BYTE $0xD6 1274 CALL _strayintr(SB); BYTE $0xD7 1275 CALL _strayintr(SB); BYTE $0xD8 1276 CALL _strayintr(SB); BYTE $0xD9 1277 CALL _strayintr(SB); BYTE $0xDA 1278 CALL _strayintr(SB); BYTE $0xDB 1279 CALL _strayintr(SB); BYTE $0xDC 1280 CALL _strayintr(SB); BYTE $0xDD 1281 CALL _strayintr(SB); BYTE $0xDE 1282 CALL _strayintr(SB); BYTE $0xDF 1283 CALL _strayintr(SB); BYTE $0xE0 1284 CALL _strayintr(SB); BYTE $0xE1 1285 CALL _strayintr(SB); BYTE $0xE2 1286 CALL _strayintr(SB); BYTE $0xE3 1287 CALL _strayintr(SB); BYTE $0xE4 1288 CALL _strayintr(SB); BYTE $0xE5 1289 CALL _strayintr(SB); BYTE $0xE6 1290 CALL _strayintr(SB); BYTE $0xE7 1291 CALL _strayintr(SB); BYTE $0xE8 1292 CALL _strayintr(SB); BYTE $0xE9 1293 CALL _strayintr(SB); BYTE $0xEA 1294 CALL _strayintr(SB); BYTE $0xEB 1295 CALL _strayintr(SB); BYTE $0xEC 1296 CALL _strayintr(SB); BYTE $0xED 1297 CALL _strayintr(SB); BYTE $0xEE 1298 CALL _strayintr(SB); BYTE $0xEF 1299 CALL _strayintr(SB); BYTE $0xF0 1300 CALL _strayintr(SB); BYTE $0xF1 1301 CALL _strayintr(SB); BYTE $0xF2 1302 CALL _strayintr(SB); BYTE $0xF3 1303 CALL _strayintr(SB); BYTE $0xF4 1304 CALL _strayintr(SB); BYTE $0xF5 1305 CALL _strayintr(SB); BYTE $0xF6 1306 CALL _strayintr(SB); BYTE $0xF7 1307 CALL _strayintr(SB); BYTE $0xF8 1308 CALL _strayintr(SB); BYTE $0xF9 1309 CALL _strayintr(SB); BYTE $0xFA 1310 CALL _strayintr(SB); BYTE $0xFB 1311 CALL _strayintr(SB); BYTE $0xFC 1312 CALL _strayintr(SB); BYTE $0xFD 1313 CALL _strayintr(SB); BYTE $0xFE 1314 CALL _strayintr(SB); BYTE $0xFF 1315