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 fpon(SB), $0 /* enable */ 778 FPON 779 RET 780 781TEXT fpoff(SB), $0 /* disable */ 782 FPOFF(l1) 783 RET 784 785TEXT fpinit(SB), $0 /* enable and init */ 786 FPON 787 FINIT 788 WAIT 789 /* setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPOVFL) */ 790 /* note that low 6 bits are masks, not enables, on this chip */ 791 PUSHW $0x0232 792 FLDCW 0(SP) 793 POPW AX 794 WAIT 795 RET 796 797TEXT fpx87save(SB), $0 /* save state and disable */ 798 MOVL p+0(FP), AX 799 FSAVE 0(AX) /* no WAIT */ 800 FPOFF(l2) 801 RET 802 803TEXT fpx87restore(SB), $0 /* enable and restore state */ 804 FPON 805 MOVL p+0(FP), AX 806 FRSTOR 0(AX) 807 WAIT 808 RET 809 810TEXT fpstatus(SB), $0 /* get floating point status */ 811 FSTSW AX 812 RET 813 814TEXT fpenv(SB), $0 /* save state without waiting */ 815 MOVL p+0(FP), AX 816 FSTENV 0(AX) /* also masks FP exceptions */ 817 RET 818 819TEXT fpclear(SB), $0 /* clear pending exceptions */ 820 FPON 821 FCLEX /* no WAIT */ 822 FPOFF(l3) 823 RET 824 825TEXT fpssesave0(SB), $0 /* save state and disable */ 826 MOVL p+0(FP), AX 827 FXSAVE /* no WAIT */ 828 FPOFF(l4) 829 RET 830 831TEXT fpsserestore0(SB), $0 /* enable and restore state */ 832 FPON 833 MOVL p+0(FP), AX 834 FXRSTOR 835 WAIT 836 RET 837 838/* 839 */ 840TEXT splhi(SB), $0 841shi: 842 PUSHFL 843 POPL AX 844 TESTL $0x200, AX 845 JZ alreadyhi 846 MOVL $(MACHADDR+0x04), CX /* save PC in m->splpc */ 847 MOVL (SP), BX 848 MOVL BX, (CX) 849alreadyhi: 850 CLI 851 RET 852 853TEXT spllo(SB), $0 854slo: 855 PUSHFL 856 POPL AX 857 TESTL $0x200, AX 858 JNZ alreadylo 859 MOVL $(MACHADDR+0x04), CX /* clear m->splpc */ 860 MOVL $0, (CX) 861alreadylo: 862 STI 863 RET 864 865TEXT splx(SB), $0 866 MOVL s+0(FP), AX 867 TESTL $0x200, AX 868 JNZ slo 869 JMP shi 870 871TEXT spldone(SB), $0 872 RET 873 874TEXT islo(SB), $0 875 PUSHFL 876 POPL AX 877 ANDL $0x200, AX /* interrupt enable flag */ 878 RET 879 880/* 881 * Test-And-Set 882 */ 883TEXT tas(SB), $0 884 MOVL $0xDEADDEAD, AX 885 MOVL lock+0(FP), BX 886 XCHGL AX, (BX) /* lock->key */ 887 RET 888 889TEXT _xinc(SB), $0 /* void _xinc(long*); */ 890 MOVL l+0(FP), AX 891 LOCK; INCL 0(AX) 892 RET 893 894TEXT _xdec(SB), $0 /* long _xdec(long*); */ 895 MOVL l+0(FP), BX 896 XORL AX, AX 897 LOCK; DECL 0(BX) 898 JLT _xdeclt 899 JGT _xdecgt 900 RET 901_xdecgt: 902 INCL AX 903 RET 904_xdeclt: 905 DECL AX 906 RET 907 908TEXT mb386(SB), $0 909 POPL AX /* return PC */ 910 PUSHFL 911 PUSHL CS 912 PUSHL AX 913 IRETL 914 915TEXT mb586(SB), $0 916 XORL AX, AX 917 CPUID 918 RET 919 920TEXT sfence(SB), $0 921 BYTE $0x0f 922 BYTE $0xae 923 BYTE $0xf8 924 RET 925 926TEXT lfence(SB), $0 927 BYTE $0x0f 928 BYTE $0xae 929 BYTE $0xe8 930 RET 931 932TEXT mfence(SB), $0 933 BYTE $0x0f 934 BYTE $0xae 935 BYTE $0xf0 936 RET 937 938TEXT xchgw(SB), $0 939 MOVL v+4(FP), AX 940 MOVL p+0(FP), BX 941 XCHGW AX, (BX) 942 RET 943 944TEXT cmpswap486(SB), $0 945 MOVL addr+0(FP), BX 946 MOVL old+4(FP), AX 947 MOVL new+8(FP), CX 948 LOCK 949 BYTE $0x0F; BYTE $0xB1; BYTE $0x0B /* CMPXCHGL CX, (BX) */ 950 JNZ didnt 951 MOVL $1, AX 952 RET 953didnt: 954 XORL AX,AX 955 RET 956 957TEXT mul64fract(SB), $0 958/* 959 * Multiply two 64-bit number s and keep the middle 64 bits from the 128-bit result 960 * See ../port/tod.c for motivation. 961 */ 962 MOVL r+0(FP), CX 963 XORL BX, BX /* BX = 0 */ 964 965 MOVL a+8(FP), AX 966 MULL b+16(FP) /* a1*b1 */ 967 MOVL AX, 4(CX) /* r2 = lo(a1*b1) */ 968 969 MOVL a+8(FP), AX 970 MULL b+12(FP) /* a1*b0 */ 971 MOVL AX, 0(CX) /* r1 = lo(a1*b0) */ 972 ADDL DX, 4(CX) /* r2 += hi(a1*b0) */ 973 974 MOVL a+4(FP), AX 975 MULL b+16(FP) /* a0*b1 */ 976 ADDL AX, 0(CX) /* r1 += lo(a0*b1) */ 977 ADCL DX, 4(CX) /* r2 += hi(a0*b1) + carry */ 978 979 MOVL a+4(FP), AX 980 MULL b+12(FP) /* a0*b0 */ 981 ADDL DX, 0(CX) /* r1 += hi(a0*b0) */ 982 ADCL BX, 4(CX) /* r2 += carry */ 983 RET 984 985/* 986 * label consists of a stack pointer and a PC 987 */ 988TEXT gotolabel(SB), $0 989 MOVL label+0(FP), AX 990 MOVL 0(AX), SP /* restore sp */ 991 MOVL 4(AX), AX /* put return pc on the stack */ 992 MOVL AX, 0(SP) 993 MOVL $1, AX /* return 1 */ 994 RET 995 996TEXT setlabel(SB), $0 997 MOVL label+0(FP), AX 998 MOVL SP, 0(AX) /* store sp */ 999 MOVL 0(SP), BX /* store return pc */ 1000 MOVL BX, 4(AX) 1001 MOVL $0, AX /* return 0 */ 1002 RET 1003 1004/* 1005 * Attempt at power saving. -rsc 1006 */ 1007TEXT halt(SB), $0 1008 CLI 1009 CMPL nrdy(SB), $0 1010 JEQ _nothingready 1011 STI 1012 RET 1013 1014_nothingready: 1015 STI 1016 HLT 1017 RET 1018 1019/* 1020 * Interrupt/exception handling. 1021 * Each entry in the vector table calls either _strayintr or _strayintrx depending 1022 * on whether an error code has been automatically pushed onto the stack 1023 * (_strayintrx) or not, in which case a dummy entry must be pushed before retrieving 1024 * the trap type from the vector table entry and placing it on the stack as part 1025 * of the Ureg structure. 1026 * The size of each entry in the vector table (6 bytes) is known in trapinit(). 1027 */ 1028TEXT _strayintr(SB), $0 1029 PUSHL AX /* save AX */ 1030 MOVL 4(SP), AX /* return PC from vectortable(SB) */ 1031 JMP intrcommon 1032 1033TEXT _strayintrx(SB), $0 1034 XCHGL AX, (SP) /* swap AX with vectortable CALL PC */ 1035intrcommon: 1036 PUSHL DS /* save DS */ 1037 PUSHL $(KDSEL) 1038 POPL DS /* fix up DS */ 1039 MOVBLZX (AX), AX /* trap type -> AX */ 1040 XCHGL AX, 4(SP) /* exchange trap type with saved AX */ 1041 1042 PUSHL ES /* save ES */ 1043 PUSHL $(KDSEL) 1044 POPL ES /* fix up ES */ 1045 1046 PUSHL FS /* save the rest of the Ureg struct */ 1047 PUSHL GS 1048 PUSHAL 1049 1050 PUSHL SP /* Ureg* argument to trap */ 1051 CALL trap(SB) 1052 1053TEXT forkret(SB), $0 1054 POPL AX 1055 POPAL 1056 POPL GS 1057 POPL FS 1058 POPL ES 1059 POPL DS 1060 ADDL $8, SP /* pop error code and trap type */ 1061 IRETL 1062 1063TEXT vectortable(SB), $0 1064 CALL _strayintr(SB); BYTE $0x00 /* divide error */ 1065 CALL _strayintr(SB); BYTE $0x01 /* debug exception */ 1066 CALL _strayintr(SB); BYTE $0x02 /* NMI interrupt */ 1067 CALL _strayintr(SB); BYTE $0x03 /* breakpoint */ 1068 CALL _strayintr(SB); BYTE $0x04 /* overflow */ 1069 CALL _strayintr(SB); BYTE $0x05 /* bound */ 1070 CALL _strayintr(SB); BYTE $0x06 /* invalid opcode */ 1071 CALL _strayintr(SB); BYTE $0x07 /* no coprocessor available */ 1072 CALL _strayintrx(SB); BYTE $0x08 /* double fault */ 1073 CALL _strayintr(SB); BYTE $0x09 /* coprocessor segment overflow */ 1074 CALL _strayintrx(SB); BYTE $0x0A /* invalid TSS */ 1075 CALL _strayintrx(SB); BYTE $0x0B /* segment not available */ 1076 CALL _strayintrx(SB); BYTE $0x0C /* stack exception */ 1077 CALL _strayintrx(SB); BYTE $0x0D /* general protection error */ 1078 CALL _strayintrx(SB); BYTE $0x0E /* page fault */ 1079 CALL _strayintr(SB); BYTE $0x0F /* */ 1080 CALL _strayintr(SB); BYTE $0x10 /* coprocessor error */ 1081 CALL _strayintrx(SB); BYTE $0x11 /* alignment check */ 1082 CALL _strayintr(SB); BYTE $0x12 /* machine check */ 1083 CALL _strayintr(SB); BYTE $0x13 1084 CALL _strayintr(SB); BYTE $0x14 1085 CALL _strayintr(SB); BYTE $0x15 1086 CALL _strayintr(SB); BYTE $0x16 1087 CALL _strayintr(SB); BYTE $0x17 1088 CALL _strayintr(SB); BYTE $0x18 1089 CALL _strayintr(SB); BYTE $0x19 1090 CALL _strayintr(SB); BYTE $0x1A 1091 CALL _strayintr(SB); BYTE $0x1B 1092 CALL _strayintr(SB); BYTE $0x1C 1093 CALL _strayintr(SB); BYTE $0x1D 1094 CALL _strayintr(SB); BYTE $0x1E 1095 CALL _strayintr(SB); BYTE $0x1F 1096 CALL _strayintr(SB); BYTE $0x20 /* VectorLAPIC */ 1097 CALL _strayintr(SB); BYTE $0x21 1098 CALL _strayintr(SB); BYTE $0x22 1099 CALL _strayintr(SB); BYTE $0x23 1100 CALL _strayintr(SB); BYTE $0x24 1101 CALL _strayintr(SB); BYTE $0x25 1102 CALL _strayintr(SB); BYTE $0x26 1103 CALL _strayintr(SB); BYTE $0x27 1104 CALL _strayintr(SB); BYTE $0x28 1105 CALL _strayintr(SB); BYTE $0x29 1106 CALL _strayintr(SB); BYTE $0x2A 1107 CALL _strayintr(SB); BYTE $0x2B 1108 CALL _strayintr(SB); BYTE $0x2C 1109 CALL _strayintr(SB); BYTE $0x2D 1110 CALL _strayintr(SB); BYTE $0x2E 1111 CALL _strayintr(SB); BYTE $0x2F 1112 CALL _strayintr(SB); BYTE $0x30 1113 CALL _strayintr(SB); BYTE $0x31 1114 CALL _strayintr(SB); BYTE $0x32 1115 CALL _strayintr(SB); BYTE $0x33 1116 CALL _strayintr(SB); BYTE $0x34 1117 CALL _strayintr(SB); BYTE $0x35 1118 CALL _strayintr(SB); BYTE $0x36 1119 CALL _strayintr(SB); BYTE $0x37 1120 CALL _strayintr(SB); BYTE $0x38 1121 CALL _strayintr(SB); BYTE $0x39 1122 CALL _strayintr(SB); BYTE $0x3A 1123 CALL _strayintr(SB); BYTE $0x3B 1124 CALL _strayintr(SB); BYTE $0x3C 1125 CALL _strayintr(SB); BYTE $0x3D 1126 CALL _strayintr(SB); BYTE $0x3E 1127 CALL _strayintr(SB); BYTE $0x3F 1128 CALL _syscallintr(SB); BYTE $0x40 /* VectorSYSCALL */ 1129 CALL _strayintr(SB); BYTE $0x41 1130 CALL _strayintr(SB); BYTE $0x42 1131 CALL _strayintr(SB); BYTE $0x43 1132 CALL _strayintr(SB); BYTE $0x44 1133 CALL _strayintr(SB); BYTE $0x45 1134 CALL _strayintr(SB); BYTE $0x46 1135 CALL _strayintr(SB); BYTE $0x47 1136 CALL _strayintr(SB); BYTE $0x48 1137 CALL _strayintr(SB); BYTE $0x49 1138 CALL _strayintr(SB); BYTE $0x4A 1139 CALL _strayintr(SB); BYTE $0x4B 1140 CALL _strayintr(SB); BYTE $0x4C 1141 CALL _strayintr(SB); BYTE $0x4D 1142 CALL _strayintr(SB); BYTE $0x4E 1143 CALL _strayintr(SB); BYTE $0x4F 1144 CALL _strayintr(SB); BYTE $0x50 1145 CALL _strayintr(SB); BYTE $0x51 1146 CALL _strayintr(SB); BYTE $0x52 1147 CALL _strayintr(SB); BYTE $0x53 1148 CALL _strayintr(SB); BYTE $0x54 1149 CALL _strayintr(SB); BYTE $0x55 1150 CALL _strayintr(SB); BYTE $0x56 1151 CALL _strayintr(SB); BYTE $0x57 1152 CALL _strayintr(SB); BYTE $0x58 1153 CALL _strayintr(SB); BYTE $0x59 1154 CALL _strayintr(SB); BYTE $0x5A 1155 CALL _strayintr(SB); BYTE $0x5B 1156 CALL _strayintr(SB); BYTE $0x5C 1157 CALL _strayintr(SB); BYTE $0x5D 1158 CALL _strayintr(SB); BYTE $0x5E 1159 CALL _strayintr(SB); BYTE $0x5F 1160 CALL _strayintr(SB); BYTE $0x60 1161 CALL _strayintr(SB); BYTE $0x61 1162 CALL _strayintr(SB); BYTE $0x62 1163 CALL _strayintr(SB); BYTE $0x63 1164 CALL _strayintr(SB); BYTE $0x64 1165 CALL _strayintr(SB); BYTE $0x65 1166 CALL _strayintr(SB); BYTE $0x66 1167 CALL _strayintr(SB); BYTE $0x67 1168 CALL _strayintr(SB); BYTE $0x68 1169 CALL _strayintr(SB); BYTE $0x69 1170 CALL _strayintr(SB); BYTE $0x6A 1171 CALL _strayintr(SB); BYTE $0x6B 1172 CALL _strayintr(SB); BYTE $0x6C 1173 CALL _strayintr(SB); BYTE $0x6D 1174 CALL _strayintr(SB); BYTE $0x6E 1175 CALL _strayintr(SB); BYTE $0x6F 1176 CALL _strayintr(SB); BYTE $0x70 1177 CALL _strayintr(SB); BYTE $0x71 1178 CALL _strayintr(SB); BYTE $0x72 1179 CALL _strayintr(SB); BYTE $0x73 1180 CALL _strayintr(SB); BYTE $0x74 1181 CALL _strayintr(SB); BYTE $0x75 1182 CALL _strayintr(SB); BYTE $0x76 1183 CALL _strayintr(SB); BYTE $0x77 1184 CALL _strayintr(SB); BYTE $0x78 1185 CALL _strayintr(SB); BYTE $0x79 1186 CALL _strayintr(SB); BYTE $0x7A 1187 CALL _strayintr(SB); BYTE $0x7B 1188 CALL _strayintr(SB); BYTE $0x7C 1189 CALL _strayintr(SB); BYTE $0x7D 1190 CALL _strayintr(SB); BYTE $0x7E 1191 CALL _strayintr(SB); BYTE $0x7F 1192 CALL _strayintr(SB); BYTE $0x80 /* Vector[A]PIC */ 1193 CALL _strayintr(SB); BYTE $0x81 1194 CALL _strayintr(SB); BYTE $0x82 1195 CALL _strayintr(SB); BYTE $0x83 1196 CALL _strayintr(SB); BYTE $0x84 1197 CALL _strayintr(SB); BYTE $0x85 1198 CALL _strayintr(SB); BYTE $0x86 1199 CALL _strayintr(SB); BYTE $0x87 1200 CALL _strayintr(SB); BYTE $0x88 1201 CALL _strayintr(SB); BYTE $0x89 1202 CALL _strayintr(SB); BYTE $0x8A 1203 CALL _strayintr(SB); BYTE $0x8B 1204 CALL _strayintr(SB); BYTE $0x8C 1205 CALL _strayintr(SB); BYTE $0x8D 1206 CALL _strayintr(SB); BYTE $0x8E 1207 CALL _strayintr(SB); BYTE $0x8F 1208 CALL _strayintr(SB); BYTE $0x90 1209 CALL _strayintr(SB); BYTE $0x91 1210 CALL _strayintr(SB); BYTE $0x92 1211 CALL _strayintr(SB); BYTE $0x93 1212 CALL _strayintr(SB); BYTE $0x94 1213 CALL _strayintr(SB); BYTE $0x95 1214 CALL _strayintr(SB); BYTE $0x96 1215 CALL _strayintr(SB); BYTE $0x97 1216 CALL _strayintr(SB); BYTE $0x98 1217 CALL _strayintr(SB); BYTE $0x99 1218 CALL _strayintr(SB); BYTE $0x9A 1219 CALL _strayintr(SB); BYTE $0x9B 1220 CALL _strayintr(SB); BYTE $0x9C 1221 CALL _strayintr(SB); BYTE $0x9D 1222 CALL _strayintr(SB); BYTE $0x9E 1223 CALL _strayintr(SB); BYTE $0x9F 1224 CALL _strayintr(SB); BYTE $0xA0 1225 CALL _strayintr(SB); BYTE $0xA1 1226 CALL _strayintr(SB); BYTE $0xA2 1227 CALL _strayintr(SB); BYTE $0xA3 1228 CALL _strayintr(SB); BYTE $0xA4 1229 CALL _strayintr(SB); BYTE $0xA5 1230 CALL _strayintr(SB); BYTE $0xA6 1231 CALL _strayintr(SB); BYTE $0xA7 1232 CALL _strayintr(SB); BYTE $0xA8 1233 CALL _strayintr(SB); BYTE $0xA9 1234 CALL _strayintr(SB); BYTE $0xAA 1235 CALL _strayintr(SB); BYTE $0xAB 1236 CALL _strayintr(SB); BYTE $0xAC 1237 CALL _strayintr(SB); BYTE $0xAD 1238 CALL _strayintr(SB); BYTE $0xAE 1239 CALL _strayintr(SB); BYTE $0xAF 1240 CALL _strayintr(SB); BYTE $0xB0 1241 CALL _strayintr(SB); BYTE $0xB1 1242 CALL _strayintr(SB); BYTE $0xB2 1243 CALL _strayintr(SB); BYTE $0xB3 1244 CALL _strayintr(SB); BYTE $0xB4 1245 CALL _strayintr(SB); BYTE $0xB5 1246 CALL _strayintr(SB); BYTE $0xB6 1247 CALL _strayintr(SB); BYTE $0xB7 1248 CALL _strayintr(SB); BYTE $0xB8 1249 CALL _strayintr(SB); BYTE $0xB9 1250 CALL _strayintr(SB); BYTE $0xBA 1251 CALL _strayintr(SB); BYTE $0xBB 1252 CALL _strayintr(SB); BYTE $0xBC 1253 CALL _strayintr(SB); BYTE $0xBD 1254 CALL _strayintr(SB); BYTE $0xBE 1255 CALL _strayintr(SB); BYTE $0xBF 1256 CALL _strayintr(SB); BYTE $0xC0 1257 CALL _strayintr(SB); BYTE $0xC1 1258 CALL _strayintr(SB); BYTE $0xC2 1259 CALL _strayintr(SB); BYTE $0xC3 1260 CALL _strayintr(SB); BYTE $0xC4 1261 CALL _strayintr(SB); BYTE $0xC5 1262 CALL _strayintr(SB); BYTE $0xC6 1263 CALL _strayintr(SB); BYTE $0xC7 1264 CALL _strayintr(SB); BYTE $0xC8 1265 CALL _strayintr(SB); BYTE $0xC9 1266 CALL _strayintr(SB); BYTE $0xCA 1267 CALL _strayintr(SB); BYTE $0xCB 1268 CALL _strayintr(SB); BYTE $0xCC 1269 CALL _strayintr(SB); BYTE $0xCD 1270 CALL _strayintr(SB); BYTE $0xCE 1271 CALL _strayintr(SB); BYTE $0xCF 1272 CALL _strayintr(SB); BYTE $0xD0 1273 CALL _strayintr(SB); BYTE $0xD1 1274 CALL _strayintr(SB); BYTE $0xD2 1275 CALL _strayintr(SB); BYTE $0xD3 1276 CALL _strayintr(SB); BYTE $0xD4 1277 CALL _strayintr(SB); BYTE $0xD5 1278 CALL _strayintr(SB); BYTE $0xD6 1279 CALL _strayintr(SB); BYTE $0xD7 1280 CALL _strayintr(SB); BYTE $0xD8 1281 CALL _strayintr(SB); BYTE $0xD9 1282 CALL _strayintr(SB); BYTE $0xDA 1283 CALL _strayintr(SB); BYTE $0xDB 1284 CALL _strayintr(SB); BYTE $0xDC 1285 CALL _strayintr(SB); BYTE $0xDD 1286 CALL _strayintr(SB); BYTE $0xDE 1287 CALL _strayintr(SB); BYTE $0xDF 1288 CALL _strayintr(SB); BYTE $0xE0 1289 CALL _strayintr(SB); BYTE $0xE1 1290 CALL _strayintr(SB); BYTE $0xE2 1291 CALL _strayintr(SB); BYTE $0xE3 1292 CALL _strayintr(SB); BYTE $0xE4 1293 CALL _strayintr(SB); BYTE $0xE5 1294 CALL _strayintr(SB); BYTE $0xE6 1295 CALL _strayintr(SB); BYTE $0xE7 1296 CALL _strayintr(SB); BYTE $0xE8 1297 CALL _strayintr(SB); BYTE $0xE9 1298 CALL _strayintr(SB); BYTE $0xEA 1299 CALL _strayintr(SB); BYTE $0xEB 1300 CALL _strayintr(SB); BYTE $0xEC 1301 CALL _strayintr(SB); BYTE $0xED 1302 CALL _strayintr(SB); BYTE $0xEE 1303 CALL _strayintr(SB); BYTE $0xEF 1304 CALL _strayintr(SB); BYTE $0xF0 1305 CALL _strayintr(SB); BYTE $0xF1 1306 CALL _strayintr(SB); BYTE $0xF2 1307 CALL _strayintr(SB); BYTE $0xF3 1308 CALL _strayintr(SB); BYTE $0xF4 1309 CALL _strayintr(SB); BYTE $0xF5 1310 CALL _strayintr(SB); BYTE $0xF6 1311 CALL _strayintr(SB); BYTE $0xF7 1312 CALL _strayintr(SB); BYTE $0xF8 1313 CALL _strayintr(SB); BYTE $0xF9 1314 CALL _strayintr(SB); BYTE $0xFA 1315 CALL _strayintr(SB); BYTE $0xFB 1316 CALL _strayintr(SB); BYTE $0xFC 1317 CALL _strayintr(SB); BYTE $0xFD 1318 CALL _strayintr(SB); BYTE $0xFE 1319 CALL _strayintr(SB); BYTE $0xFF 1320