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