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