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