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 CLI /* who knows what evil the bios got up to */ 407 408 /* save the registers after the call */ 409 410 LWI(0x7bfc, rSP) 411 OPSIZE; PUSHFL 412 OPSIZE; PUSHL AX 413 414 LWI(0, rAX) 415 MOVW AX,SS 416 LWI(RMUADDR, rBP) 417 418 OPSIZE; SXW(rDI, 0, xBP) 419 OPSIZE; SXW(rSI, 4, xBP) 420 OPSIZE; SXW(rBX, 16, xBP) 421 OPSIZE; SXW(rDX, 20, xBP) 422 OPSIZE; SXW(rCX, 24, xBP) 423 OPSIZE; POPL AX 424 OPSIZE; SXW(rAX, 28, xBP) 425 426 MOVW DS, AX 427 OPSIZE; SXW(rAX, 44, xBP) 428 MOVW ES, AX 429 OPSIZE; SXW(rAX, 40, xBP) 430 431 OPSIZE; POPL AX 432 OPSIZE; SXW(rAX, 64, xBP) /* flags */ 433 434 /* re-enter protected mode and jump to 32-bit code */ 435 OPSIZE; MOVL $1, AX 436 OPSIZE; MOVL AX, CR0 437 438/* JMPFAR SELECTOR(KESEG, SELGDT, 0):$again32bit(SB) /**/ 439 OPSIZE 440 BYTE $0xEA 441 LONG $again32bit-KZERO(SB) 442 WORD $SELECTOR(KESEG, SELGDT, 0) 443 444TEXT again32bit(SB), $0 445 MOVW $SELECTOR(KDSEG, SELGDT, 0),AX 446 MOVW AX,DS 447 MOVW AX,SS 448 MOVW AX,ES 449 MOVW AX,FS 450 MOVW AX,GS 451 452 /* enable paging and jump to kzero-address code */ 453 MOVL CR0, AX 454 ORL $0x80010000, AX /* PG|WP */ 455 MOVL AX, CR0 456 LEAL again32kzero(SB), AX 457 JMP* AX 458 459TEXT again32kzero(SB), $0 460 /* breathe a sigh of relief - back in 32-bit protected mode */ 461 462 /* switch to old stack */ 463 PUSHL AX /* match popl below for 8l */ 464 MOVL $0x7BFC, SP 465 POPL SP 466 467 /* restore idt */ 468 MOVL m0idtptr(SB),IDTR 469 470 /* restore gdt */ 471 MOVL m0gdtptr(SB), GDTR 472 473 CALL restoreregs(SB) 474 RET 475 476/* 477 * BIOS32. 478 */ 479TEXT bios32call(SB), $0 480 MOVL ci+0(FP), BP 481 MOVL 0(BP), AX 482 MOVL 4(BP), BX 483 MOVL 8(BP), CX 484 MOVL 12(BP), DX 485 MOVL 16(BP), SI 486 MOVL 20(BP), DI 487 PUSHL BP 488 489 MOVL 12(SP), BP /* ptr */ 490 BYTE $0xFF; BYTE $0x5D; BYTE $0x00 /* CALL FAR 0(BP) */ 491 492 POPL BP 493 MOVL DI, 20(BP) 494 MOVL SI, 16(BP) 495 MOVL DX, 12(BP) 496 MOVL CX, 8(BP) 497 MOVL BX, 4(BP) 498 MOVL AX, 0(BP) 499 500 XORL AX, AX 501 JCC _bios32xxret 502 INCL AX 503 504_bios32xxret: 505 RET 506 507/* 508 * Port I/O. 509 * in[bsl] input a byte|short|long 510 * ins[bsl] input a string of bytes|shorts|longs 511 * out[bsl] output a byte|short|long 512 * outs[bsl] output a string of bytes|shorts|longs 513 */ 514TEXT inb(SB), $0 515 MOVL port+0(FP), DX 516 XORL AX, AX 517 INB 518 RET 519 520TEXT insb(SB), $0 521 MOVL port+0(FP), DX 522 MOVL address+4(FP), DI 523 MOVL count+8(FP), CX 524 CLD 525 REP; INSB 526 RET 527 528TEXT ins(SB), $0 529 MOVL port+0(FP), DX 530 XORL AX, AX 531 OP16; INL 532 RET 533 534TEXT inss(SB), $0 535 MOVL port+0(FP), DX 536 MOVL address+4(FP), DI 537 MOVL count+8(FP), CX 538 CLD 539 REP; OP16; INSL 540 RET 541 542TEXT inl(SB), $0 543 MOVL port+0(FP), DX 544 INL 545 RET 546 547TEXT insl(SB), $0 548 MOVL port+0(FP), DX 549 MOVL address+4(FP), DI 550 MOVL count+8(FP), CX 551 CLD 552 REP; INSL 553 RET 554 555TEXT outb(SB), $0 556 MOVL port+0(FP), DX 557 MOVL byte+4(FP), AX 558 OUTB 559 RET 560 561TEXT outsb(SB), $0 562 MOVL port+0(FP), DX 563 MOVL address+4(FP), SI 564 MOVL count+8(FP), CX 565 CLD 566 REP; OUTSB 567 RET 568 569TEXT outs(SB), $0 570 MOVL port+0(FP), DX 571 MOVL short+4(FP), AX 572 OP16; OUTL 573 RET 574 575TEXT outss(SB), $0 576 MOVL port+0(FP), DX 577 MOVL address+4(FP), SI 578 MOVL count+8(FP), CX 579 CLD 580 REP; OP16; OUTSL 581 RET 582 583TEXT outl(SB), $0 584 MOVL port+0(FP), DX 585 MOVL long+4(FP), AX 586 OUTL 587 RET 588 589TEXT outsl(SB), $0 590 MOVL port+0(FP), DX 591 MOVL address+4(FP), SI 592 MOVL count+8(FP), CX 593 CLD 594 REP; OUTSL 595 RET 596 597/* 598 * Read/write various system registers. 599 * CR4 and the 'model specific registers' should only be read/written 600 * after it has been determined the processor supports them 601 */ 602TEXT lgdt(SB), $0 /* GDTR - global descriptor table */ 603 MOVL gdtptr+0(FP), AX 604 MOVL (AX), GDTR 605 RET 606 607TEXT lidt(SB), $0 /* IDTR - interrupt descriptor table */ 608 MOVL idtptr+0(FP), AX 609 MOVL (AX), IDTR 610 RET 611 612TEXT ltr(SB), $0 /* TR - task register */ 613 MOVL tptr+0(FP), AX 614 MOVW AX, TASK 615 RET 616 617TEXT getcr0(SB), $0 /* CR0 - processor control */ 618 MOVL CR0, AX 619 RET 620 621TEXT getcr2(SB), $0 /* CR2 - page fault linear address */ 622 MOVL CR2, AX 623 RET 624 625TEXT getcr3(SB), $0 /* CR3 - page directory base */ 626 MOVL CR3, AX 627 RET 628 629TEXT putcr0(SB), $0 630 MOVL cr0+0(FP), AX 631 MOVL AX, CR0 632 RET 633 634TEXT putcr3(SB), $0 635 MOVL cr3+0(FP), AX 636 MOVL AX, CR3 637 RET 638 639TEXT getcr4(SB), $0 /* CR4 - extensions */ 640 MOVL CR4, AX 641 RET 642 643TEXT putcr4(SB), $0 644 MOVL cr4+0(FP), AX 645 MOVL AX, CR4 646 RET 647 648TEXT invlpg(SB), $0 649 /* 486+ only */ 650 MOVL va+0(FP), CX 651 INVLPG 652 RET 653 654TEXT wbinvd(SB), $0 655 WBINVD 656 RET 657 658TEXT _cycles(SB), $0 /* time stamp counter */ 659 RDTSC 660 MOVL vlong+0(FP), CX /* &vlong */ 661 MOVL AX, 0(CX) /* lo */ 662 MOVL DX, 4(CX) /* hi */ 663 RET 664 665/* 666 * stub for: 667 * time stamp counter; low-order 32 bits of 64-bit cycle counter 668 * Runs at fasthz/4 cycles per second (m->clkin>>3) 669 */ 670TEXT lcycles(SB),1,$0 671 RDTSC 672 RET 673 674TEXT rdmsr(SB), $0 /* model-specific register */ 675 MOVL index+0(FP), CX 676 RDMSR 677 MOVL vlong+4(FP), CX /* &vlong */ 678 MOVL AX, 0(CX) /* lo */ 679 MOVL DX, 4(CX) /* hi */ 680 RET 681 682TEXT wrmsr(SB), $0 683 MOVL index+0(FP), CX 684 MOVL lo+4(FP), AX 685 MOVL hi+8(FP), DX 686 WRMSR 687 RET 688 689/* 690 * Try to determine the CPU type which requires fiddling with EFLAGS. 691 * If the Id bit can be toggled then the CPUID instruction can be used 692 * to determine CPU identity and features. First have to check if it's 693 * a 386 (Ac bit can't be set). If it's not a 386 and the Id bit can't be 694 * toggled then it's an older 486 of some kind. 695 * 696 * cpuid(fun, regs[4]); 697 */ 698TEXT cpuid(SB), $0 699 MOVL $0x240000, AX 700 PUSHL AX 701 POPFL /* set Id|Ac */ 702 PUSHFL 703 POPL BX /* retrieve value */ 704 MOVL $0, AX 705 PUSHL AX 706 POPFL /* clear Id|Ac, EFLAGS initialised */ 707 PUSHFL 708 POPL AX /* retrieve value */ 709 XORL BX, AX 710 TESTL $0x040000, AX /* Ac */ 711 JZ _cpu386 /* can't set this bit on 386 */ 712 TESTL $0x200000, AX /* Id */ 713 JZ _cpu486 /* can't toggle this bit on some 486 */ 714 /* load registers */ 715 MOVL regs+4(FP), BP 716 MOVL fn+0(FP), AX /* cpuid function */ 717 MOVL 4(BP), BX 718 MOVL 8(BP), CX /* typically an index */ 719 MOVL 12(BP), DX 720 CPUID 721 JMP _cpuid 722_cpu486: 723 MOVL $0x400, AX 724 JMP _maybezapax 725_cpu386: 726 MOVL $0x300, AX 727_maybezapax: 728 CMPL fn+0(FP), $1 729 JE _zaprest 730 XORL AX, AX 731_zaprest: 732 XORL BX, BX 733 XORL CX, CX 734 XORL DX, DX 735_cpuid: 736 MOVL regs+4(FP), BP 737 MOVL AX, 0(BP) 738 MOVL BX, 4(BP) 739 MOVL CX, 8(BP) 740 MOVL DX, 12(BP) 741 RET 742 743/* 744 * Basic timing loop to determine CPU frequency. 745 */ 746TEXT aamloop(SB), $0 747 MOVL count+0(FP), CX 748_aamloop: 749 AAM 750 LOOP _aamloop 751 RET 752 753/* 754 * Floating point. 755 * Note: the encodings for the FCLEX, FINIT, FSAVE, FSTCW, FSENV and FSTSW 756 * instructions do NOT have the WAIT prefix byte (i.e. they act like their 757 * FNxxx variations) so WAIT instructions must be explicitly placed in the 758 * code as necessary. 759 */ 760#define FPOFF(l) ;\ 761 MOVL CR0, AX ;\ 762 ANDL $0xC, AX /* EM, TS */ ;\ 763 CMPL AX, $0x8 ;\ 764 JEQ l ;\ 765 WAIT ;\ 766l: ;\ 767 MOVL CR0, AX ;\ 768 ANDL $~0x4, AX /* EM=0 */ ;\ 769 ORL $0x28, AX /* NE=1, TS=1 */ ;\ 770 MOVL AX, CR0 771 772#define FPON ;\ 773 MOVL CR0, AX ;\ 774 ANDL $~0xC, AX /* EM=0, TS=0 */ ;\ 775 MOVL AX, CR0 776 777TEXT fpoff(SB), $0 /* disable */ 778 FPOFF(l1) 779 RET 780 781TEXT fpinit(SB), $0 /* enable and init */ 782 FPON 783 FINIT 784 WAIT 785 /* setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPOVFL) */ 786 /* note that low 6 bits are masks, not enables, on this chip */ 787 PUSHW $0x0232 788 FLDCW 0(SP) 789 POPW AX 790 WAIT 791 RET 792 793TEXT fpx87save(SB), $0 /* save state and disable */ 794 MOVL p+0(FP), AX 795 FSAVE 0(AX) /* no WAIT */ 796 FPOFF(l2) 797 RET 798 799TEXT fpx87restore(SB), $0 /* enable and restore state */ 800 FPON 801 MOVL p+0(FP), AX 802 FRSTOR 0(AX) 803 WAIT 804 RET 805 806TEXT fpstatus(SB), $0 /* get floating point status */ 807 FSTSW AX 808 RET 809 810TEXT fpenv(SB), $0 /* save state without waiting */ 811 MOVL p+0(FP), AX 812 FSTENV 0(AX) 813 RET 814 815TEXT fpclear(SB), $0 /* clear pending exceptions */ 816 FPON 817 FCLEX /* no WAIT */ 818 FPOFF(l3) 819 RET 820 821TEXT fpssesave0(SB), $0 /* save state and disable */ 822 MOVL p+0(FP), AX 823 FXSAVE /* no WAIT */ 824 FPOFF(l4) 825 RET 826 827TEXT fpsserestore0(SB), $0 /* enable and restore state */ 828 FPON 829 MOVL p+0(FP), AX 830 FXRSTOR 831 WAIT 832 RET 833 834/* 835 */ 836TEXT splhi(SB), $0 837shi: 838 PUSHFL 839 POPL AX 840 TESTL $0x200, AX 841 JZ alreadyhi 842 MOVL $(MACHADDR+0x04), CX /* save PC in m->splpc */ 843 MOVL (SP), BX 844 MOVL BX, (CX) 845alreadyhi: 846 CLI 847 RET 848 849TEXT spllo(SB), $0 850slo: 851 PUSHFL 852 POPL AX 853 TESTL $0x200, AX 854 JNZ alreadylo 855 MOVL $(MACHADDR+0x04), CX /* clear m->splpc */ 856 MOVL $0, (CX) 857alreadylo: 858 STI 859 RET 860 861TEXT splx(SB), $0 862 MOVL s+0(FP), AX 863 TESTL $0x200, AX 864 JNZ slo 865 JMP shi 866 867TEXT spldone(SB), $0 868 RET 869 870TEXT islo(SB), $0 871 PUSHFL 872 POPL AX 873 ANDL $0x200, AX /* interrupt enable flag */ 874 RET 875 876/* 877 * Test-And-Set 878 */ 879TEXT tas(SB), $0 880 MOVL $0xDEADDEAD, AX 881 MOVL lock+0(FP), BX 882 XCHGL AX, (BX) /* lock->key */ 883 RET 884 885TEXT _xinc(SB), $0 /* void _xinc(long*); */ 886 MOVL l+0(FP), AX 887 LOCK; INCL 0(AX) 888 RET 889 890TEXT _xdec(SB), $0 /* long _xdec(long*); */ 891 MOVL l+0(FP), BX 892 XORL AX, AX 893 LOCK; DECL 0(BX) 894 JLT _xdeclt 895 JGT _xdecgt 896 RET 897_xdecgt: 898 INCL AX 899 RET 900_xdeclt: 901 DECL AX 902 RET 903 904TEXT mb386(SB), $0 905 POPL AX /* return PC */ 906 PUSHFL 907 PUSHL CS 908 PUSHL AX 909 IRETL 910 911TEXT mb586(SB), $0 912 XORL AX, AX 913 CPUID 914 RET 915 916TEXT sfence(SB), $0 917 BYTE $0x0f 918 BYTE $0xae 919 BYTE $0xf8 920 RET 921 922TEXT lfence(SB), $0 923 BYTE $0x0f 924 BYTE $0xae 925 BYTE $0xe8 926 RET 927 928TEXT mfence(SB), $0 929 BYTE $0x0f 930 BYTE $0xae 931 BYTE $0xf0 932 RET 933 934TEXT xchgw(SB), $0 935 MOVL v+4(FP), AX 936 MOVL p+0(FP), BX 937 XCHGW AX, (BX) 938 RET 939 940TEXT cmpswap486(SB), $0 941 MOVL addr+0(FP), BX 942 MOVL old+4(FP), AX 943 MOVL new+8(FP), CX 944 LOCK 945 BYTE $0x0F; BYTE $0xB1; BYTE $0x0B /* CMPXCHGL CX, (BX) */ 946 JNZ didnt 947 MOVL $1, AX 948 RET 949didnt: 950 XORL AX,AX 951 RET 952 953TEXT mul64fract(SB), $0 954/* 955 * Multiply two 64-bit number s and keep the middle 64 bits from the 128-bit result 956 * See ../port/tod.c for motivation. 957 */ 958 MOVL r+0(FP), CX 959 XORL BX, BX /* BX = 0 */ 960 961 MOVL a+8(FP), AX 962 MULL b+16(FP) /* a1*b1 */ 963 MOVL AX, 4(CX) /* r2 = lo(a1*b1) */ 964 965 MOVL a+8(FP), AX 966 MULL b+12(FP) /* a1*b0 */ 967 MOVL AX, 0(CX) /* r1 = lo(a1*b0) */ 968 ADDL DX, 4(CX) /* r2 += hi(a1*b0) */ 969 970 MOVL a+4(FP), AX 971 MULL b+16(FP) /* a0*b1 */ 972 ADDL AX, 0(CX) /* r1 += lo(a0*b1) */ 973 ADCL DX, 4(CX) /* r2 += hi(a0*b1) + carry */ 974 975 MOVL a+4(FP), AX 976 MULL b+12(FP) /* a0*b0 */ 977 ADDL DX, 0(CX) /* r1 += hi(a0*b0) */ 978 ADCL BX, 4(CX) /* r2 += carry */ 979 RET 980 981/* 982 * label consists of a stack pointer and a PC 983 */ 984TEXT gotolabel(SB), $0 985 MOVL label+0(FP), AX 986 MOVL 0(AX), SP /* restore sp */ 987 MOVL 4(AX), AX /* put return pc on the stack */ 988 MOVL AX, 0(SP) 989 MOVL $1, AX /* return 1 */ 990 RET 991 992TEXT setlabel(SB), $0 993 MOVL label+0(FP), AX 994 MOVL SP, 0(AX) /* store sp */ 995 MOVL 0(SP), BX /* store return pc */ 996 MOVL BX, 4(AX) 997 MOVL $0, AX /* return 0 */ 998 RET 999 1000/* 1001 * Attempt at power saving. -rsc 1002 */ 1003TEXT halt(SB), $0 1004 CLI 1005 CMPL nrdy(SB), $0 1006 JEQ _nothingready 1007 STI 1008 RET 1009 1010_nothingready: 1011 STI 1012 HLT 1013 RET 1014 1015/* 1016 * Interrupt/exception handling. 1017 * Each entry in the vector table calls either _strayintr or _strayintrx depending 1018 * on whether an error code has been automatically pushed onto the stack 1019 * (_strayintrx) or not, in which case a dummy entry must be pushed before retrieving 1020 * the trap type from the vector table entry and placing it on the stack as part 1021 * of the Ureg structure. 1022 * The size of each entry in the vector table (6 bytes) is known in trapinit(). 1023 */ 1024TEXT _strayintr(SB), $0 1025 PUSHL AX /* save AX */ 1026 MOVL 4(SP), AX /* return PC from vectortable(SB) */ 1027 JMP intrcommon 1028 1029TEXT _strayintrx(SB), $0 1030 XCHGL AX, (SP) /* swap AX with vectortable CALL PC */ 1031intrcommon: 1032 PUSHL DS /* save DS */ 1033 PUSHL $(KDSEL) 1034 POPL DS /* fix up DS */ 1035 MOVBLZX (AX), AX /* trap type -> AX */ 1036 XCHGL AX, 4(SP) /* exchange trap type with saved AX */ 1037 1038 PUSHL ES /* save ES */ 1039 PUSHL $(KDSEL) 1040 POPL ES /* fix up ES */ 1041 1042 PUSHL FS /* save the rest of the Ureg struct */ 1043 PUSHL GS 1044 PUSHAL 1045 1046 PUSHL SP /* Ureg* argument to trap */ 1047 CALL trap(SB) 1048 1049TEXT forkret(SB), $0 1050 POPL AX 1051 POPAL 1052 POPL GS 1053 POPL FS 1054 POPL ES 1055 POPL DS 1056 ADDL $8, SP /* pop error code and trap type */ 1057 IRETL 1058 1059TEXT vectortable(SB), $0 1060 CALL _strayintr(SB); BYTE $0x00 /* divide error */ 1061 CALL _strayintr(SB); BYTE $0x01 /* debug exception */ 1062 CALL _strayintr(SB); BYTE $0x02 /* NMI interrupt */ 1063 CALL _strayintr(SB); BYTE $0x03 /* breakpoint */ 1064 CALL _strayintr(SB); BYTE $0x04 /* overflow */ 1065 CALL _strayintr(SB); BYTE $0x05 /* bound */ 1066 CALL _strayintr(SB); BYTE $0x06 /* invalid opcode */ 1067 CALL _strayintr(SB); BYTE $0x07 /* no coprocessor available */ 1068 CALL _strayintrx(SB); BYTE $0x08 /* double fault */ 1069 CALL _strayintr(SB); BYTE $0x09 /* coprocessor segment overflow */ 1070 CALL _strayintrx(SB); BYTE $0x0A /* invalid TSS */ 1071 CALL _strayintrx(SB); BYTE $0x0B /* segment not available */ 1072 CALL _strayintrx(SB); BYTE $0x0C /* stack exception */ 1073 CALL _strayintrx(SB); BYTE $0x0D /* general protection error */ 1074 CALL _strayintrx(SB); BYTE $0x0E /* page fault */ 1075 CALL _strayintr(SB); BYTE $0x0F /* */ 1076 CALL _strayintr(SB); BYTE $0x10 /* coprocessor error */ 1077 CALL _strayintrx(SB); BYTE $0x11 /* alignment check */ 1078 CALL _strayintr(SB); BYTE $0x12 /* machine check */ 1079 CALL _strayintr(SB); BYTE $0x13 1080 CALL _strayintr(SB); BYTE $0x14 1081 CALL _strayintr(SB); BYTE $0x15 1082 CALL _strayintr(SB); BYTE $0x16 1083 CALL _strayintr(SB); BYTE $0x17 1084 CALL _strayintr(SB); BYTE $0x18 1085 CALL _strayintr(SB); BYTE $0x19 1086 CALL _strayintr(SB); BYTE $0x1A 1087 CALL _strayintr(SB); BYTE $0x1B 1088 CALL _strayintr(SB); BYTE $0x1C 1089 CALL _strayintr(SB); BYTE $0x1D 1090 CALL _strayintr(SB); BYTE $0x1E 1091 CALL _strayintr(SB); BYTE $0x1F 1092 CALL _strayintr(SB); BYTE $0x20 /* VectorLAPIC */ 1093 CALL _strayintr(SB); BYTE $0x21 1094 CALL _strayintr(SB); BYTE $0x22 1095 CALL _strayintr(SB); BYTE $0x23 1096 CALL _strayintr(SB); BYTE $0x24 1097 CALL _strayintr(SB); BYTE $0x25 1098 CALL _strayintr(SB); BYTE $0x26 1099 CALL _strayintr(SB); BYTE $0x27 1100 CALL _strayintr(SB); BYTE $0x28 1101 CALL _strayintr(SB); BYTE $0x29 1102 CALL _strayintr(SB); BYTE $0x2A 1103 CALL _strayintr(SB); BYTE $0x2B 1104 CALL _strayintr(SB); BYTE $0x2C 1105 CALL _strayintr(SB); BYTE $0x2D 1106 CALL _strayintr(SB); BYTE $0x2E 1107 CALL _strayintr(SB); BYTE $0x2F 1108 CALL _strayintr(SB); BYTE $0x30 1109 CALL _strayintr(SB); BYTE $0x31 1110 CALL _strayintr(SB); BYTE $0x32 1111 CALL _strayintr(SB); BYTE $0x33 1112 CALL _strayintr(SB); BYTE $0x34 1113 CALL _strayintr(SB); BYTE $0x35 1114 CALL _strayintr(SB); BYTE $0x36 1115 CALL _strayintr(SB); BYTE $0x37 1116 CALL _strayintr(SB); BYTE $0x38 1117 CALL _strayintr(SB); BYTE $0x39 1118 CALL _strayintr(SB); BYTE $0x3A 1119 CALL _strayintr(SB); BYTE $0x3B 1120 CALL _strayintr(SB); BYTE $0x3C 1121 CALL _strayintr(SB); BYTE $0x3D 1122 CALL _strayintr(SB); BYTE $0x3E 1123 CALL _strayintr(SB); BYTE $0x3F 1124 CALL _syscallintr(SB); BYTE $0x40 /* VectorSYSCALL */ 1125 CALL _strayintr(SB); BYTE $0x41 1126 CALL _strayintr(SB); BYTE $0x42 1127 CALL _strayintr(SB); BYTE $0x43 1128 CALL _strayintr(SB); BYTE $0x44 1129 CALL _strayintr(SB); BYTE $0x45 1130 CALL _strayintr(SB); BYTE $0x46 1131 CALL _strayintr(SB); BYTE $0x47 1132 CALL _strayintr(SB); BYTE $0x48 1133 CALL _strayintr(SB); BYTE $0x49 1134 CALL _strayintr(SB); BYTE $0x4A 1135 CALL _strayintr(SB); BYTE $0x4B 1136 CALL _strayintr(SB); BYTE $0x4C 1137 CALL _strayintr(SB); BYTE $0x4D 1138 CALL _strayintr(SB); BYTE $0x4E 1139 CALL _strayintr(SB); BYTE $0x4F 1140 CALL _strayintr(SB); BYTE $0x50 1141 CALL _strayintr(SB); BYTE $0x51 1142 CALL _strayintr(SB); BYTE $0x52 1143 CALL _strayintr(SB); BYTE $0x53 1144 CALL _strayintr(SB); BYTE $0x54 1145 CALL _strayintr(SB); BYTE $0x55 1146 CALL _strayintr(SB); BYTE $0x56 1147 CALL _strayintr(SB); BYTE $0x57 1148 CALL _strayintr(SB); BYTE $0x58 1149 CALL _strayintr(SB); BYTE $0x59 1150 CALL _strayintr(SB); BYTE $0x5A 1151 CALL _strayintr(SB); BYTE $0x5B 1152 CALL _strayintr(SB); BYTE $0x5C 1153 CALL _strayintr(SB); BYTE $0x5D 1154 CALL _strayintr(SB); BYTE $0x5E 1155 CALL _strayintr(SB); BYTE $0x5F 1156 CALL _strayintr(SB); BYTE $0x60 1157 CALL _strayintr(SB); BYTE $0x61 1158 CALL _strayintr(SB); BYTE $0x62 1159 CALL _strayintr(SB); BYTE $0x63 1160 CALL _strayintr(SB); BYTE $0x64 1161 CALL _strayintr(SB); BYTE $0x65 1162 CALL _strayintr(SB); BYTE $0x66 1163 CALL _strayintr(SB); BYTE $0x67 1164 CALL _strayintr(SB); BYTE $0x68 1165 CALL _strayintr(SB); BYTE $0x69 1166 CALL _strayintr(SB); BYTE $0x6A 1167 CALL _strayintr(SB); BYTE $0x6B 1168 CALL _strayintr(SB); BYTE $0x6C 1169 CALL _strayintr(SB); BYTE $0x6D 1170 CALL _strayintr(SB); BYTE $0x6E 1171 CALL _strayintr(SB); BYTE $0x6F 1172 CALL _strayintr(SB); BYTE $0x70 1173 CALL _strayintr(SB); BYTE $0x71 1174 CALL _strayintr(SB); BYTE $0x72 1175 CALL _strayintr(SB); BYTE $0x73 1176 CALL _strayintr(SB); BYTE $0x74 1177 CALL _strayintr(SB); BYTE $0x75 1178 CALL _strayintr(SB); BYTE $0x76 1179 CALL _strayintr(SB); BYTE $0x77 1180 CALL _strayintr(SB); BYTE $0x78 1181 CALL _strayintr(SB); BYTE $0x79 1182 CALL _strayintr(SB); BYTE $0x7A 1183 CALL _strayintr(SB); BYTE $0x7B 1184 CALL _strayintr(SB); BYTE $0x7C 1185 CALL _strayintr(SB); BYTE $0x7D 1186 CALL _strayintr(SB); BYTE $0x7E 1187 CALL _strayintr(SB); BYTE $0x7F 1188 CALL _strayintr(SB); BYTE $0x80 /* Vector[A]PIC */ 1189 CALL _strayintr(SB); BYTE $0x81 1190 CALL _strayintr(SB); BYTE $0x82 1191 CALL _strayintr(SB); BYTE $0x83 1192 CALL _strayintr(SB); BYTE $0x84 1193 CALL _strayintr(SB); BYTE $0x85 1194 CALL _strayintr(SB); BYTE $0x86 1195 CALL _strayintr(SB); BYTE $0x87 1196 CALL _strayintr(SB); BYTE $0x88 1197 CALL _strayintr(SB); BYTE $0x89 1198 CALL _strayintr(SB); BYTE $0x8A 1199 CALL _strayintr(SB); BYTE $0x8B 1200 CALL _strayintr(SB); BYTE $0x8C 1201 CALL _strayintr(SB); BYTE $0x8D 1202 CALL _strayintr(SB); BYTE $0x8E 1203 CALL _strayintr(SB); BYTE $0x8F 1204 CALL _strayintr(SB); BYTE $0x90 1205 CALL _strayintr(SB); BYTE $0x91 1206 CALL _strayintr(SB); BYTE $0x92 1207 CALL _strayintr(SB); BYTE $0x93 1208 CALL _strayintr(SB); BYTE $0x94 1209 CALL _strayintr(SB); BYTE $0x95 1210 CALL _strayintr(SB); BYTE $0x96 1211 CALL _strayintr(SB); BYTE $0x97 1212 CALL _strayintr(SB); BYTE $0x98 1213 CALL _strayintr(SB); BYTE $0x99 1214 CALL _strayintr(SB); BYTE $0x9A 1215 CALL _strayintr(SB); BYTE $0x9B 1216 CALL _strayintr(SB); BYTE $0x9C 1217 CALL _strayintr(SB); BYTE $0x9D 1218 CALL _strayintr(SB); BYTE $0x9E 1219 CALL _strayintr(SB); BYTE $0x9F 1220 CALL _strayintr(SB); BYTE $0xA0 1221 CALL _strayintr(SB); BYTE $0xA1 1222 CALL _strayintr(SB); BYTE $0xA2 1223 CALL _strayintr(SB); BYTE $0xA3 1224 CALL _strayintr(SB); BYTE $0xA4 1225 CALL _strayintr(SB); BYTE $0xA5 1226 CALL _strayintr(SB); BYTE $0xA6 1227 CALL _strayintr(SB); BYTE $0xA7 1228 CALL _strayintr(SB); BYTE $0xA8 1229 CALL _strayintr(SB); BYTE $0xA9 1230 CALL _strayintr(SB); BYTE $0xAA 1231 CALL _strayintr(SB); BYTE $0xAB 1232 CALL _strayintr(SB); BYTE $0xAC 1233 CALL _strayintr(SB); BYTE $0xAD 1234 CALL _strayintr(SB); BYTE $0xAE 1235 CALL _strayintr(SB); BYTE $0xAF 1236 CALL _strayintr(SB); BYTE $0xB0 1237 CALL _strayintr(SB); BYTE $0xB1 1238 CALL _strayintr(SB); BYTE $0xB2 1239 CALL _strayintr(SB); BYTE $0xB3 1240 CALL _strayintr(SB); BYTE $0xB4 1241 CALL _strayintr(SB); BYTE $0xB5 1242 CALL _strayintr(SB); BYTE $0xB6 1243 CALL _strayintr(SB); BYTE $0xB7 1244 CALL _strayintr(SB); BYTE $0xB8 1245 CALL _strayintr(SB); BYTE $0xB9 1246 CALL _strayintr(SB); BYTE $0xBA 1247 CALL _strayintr(SB); BYTE $0xBB 1248 CALL _strayintr(SB); BYTE $0xBC 1249 CALL _strayintr(SB); BYTE $0xBD 1250 CALL _strayintr(SB); BYTE $0xBE 1251 CALL _strayintr(SB); BYTE $0xBF 1252 CALL _strayintr(SB); BYTE $0xC0 1253 CALL _strayintr(SB); BYTE $0xC1 1254 CALL _strayintr(SB); BYTE $0xC2 1255 CALL _strayintr(SB); BYTE $0xC3 1256 CALL _strayintr(SB); BYTE $0xC4 1257 CALL _strayintr(SB); BYTE $0xC5 1258 CALL _strayintr(SB); BYTE $0xC6 1259 CALL _strayintr(SB); BYTE $0xC7 1260 CALL _strayintr(SB); BYTE $0xC8 1261 CALL _strayintr(SB); BYTE $0xC9 1262 CALL _strayintr(SB); BYTE $0xCA 1263 CALL _strayintr(SB); BYTE $0xCB 1264 CALL _strayintr(SB); BYTE $0xCC 1265 CALL _strayintr(SB); BYTE $0xCD 1266 CALL _strayintr(SB); BYTE $0xCE 1267 CALL _strayintr(SB); BYTE $0xCF 1268 CALL _strayintr(SB); BYTE $0xD0 1269 CALL _strayintr(SB); BYTE $0xD1 1270 CALL _strayintr(SB); BYTE $0xD2 1271 CALL _strayintr(SB); BYTE $0xD3 1272 CALL _strayintr(SB); BYTE $0xD4 1273 CALL _strayintr(SB); BYTE $0xD5 1274 CALL _strayintr(SB); BYTE $0xD6 1275 CALL _strayintr(SB); BYTE $0xD7 1276 CALL _strayintr(SB); BYTE $0xD8 1277 CALL _strayintr(SB); BYTE $0xD9 1278 CALL _strayintr(SB); BYTE $0xDA 1279 CALL _strayintr(SB); BYTE $0xDB 1280 CALL _strayintr(SB); BYTE $0xDC 1281 CALL _strayintr(SB); BYTE $0xDD 1282 CALL _strayintr(SB); BYTE $0xDE 1283 CALL _strayintr(SB); BYTE $0xDF 1284 CALL _strayintr(SB); BYTE $0xE0 1285 CALL _strayintr(SB); BYTE $0xE1 1286 CALL _strayintr(SB); BYTE $0xE2 1287 CALL _strayintr(SB); BYTE $0xE3 1288 CALL _strayintr(SB); BYTE $0xE4 1289 CALL _strayintr(SB); BYTE $0xE5 1290 CALL _strayintr(SB); BYTE $0xE6 1291 CALL _strayintr(SB); BYTE $0xE7 1292 CALL _strayintr(SB); BYTE $0xE8 1293 CALL _strayintr(SB); BYTE $0xE9 1294 CALL _strayintr(SB); BYTE $0xEA 1295 CALL _strayintr(SB); BYTE $0xEB 1296 CALL _strayintr(SB); BYTE $0xEC 1297 CALL _strayintr(SB); BYTE $0xED 1298 CALL _strayintr(SB); BYTE $0xEE 1299 CALL _strayintr(SB); BYTE $0xEF 1300 CALL _strayintr(SB); BYTE $0xF0 1301 CALL _strayintr(SB); BYTE $0xF1 1302 CALL _strayintr(SB); BYTE $0xF2 1303 CALL _strayintr(SB); BYTE $0xF3 1304 CALL _strayintr(SB); BYTE $0xF4 1305 CALL _strayintr(SB); BYTE $0xF5 1306 CALL _strayintr(SB); BYTE $0xF6 1307 CALL _strayintr(SB); BYTE $0xF7 1308 CALL _strayintr(SB); BYTE $0xF8 1309 CALL _strayintr(SB); BYTE $0xF9 1310 CALL _strayintr(SB); BYTE $0xFA 1311 CALL _strayintr(SB); BYTE $0xFB 1312 CALL _strayintr(SB); BYTE $0xFC 1313 CALL _strayintr(SB); BYTE $0xFD 1314 CALL _strayintr(SB); BYTE $0xFE 1315 CALL _strayintr(SB); BYTE $0xFF 1316