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