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