xref: /openbsd/sys/arch/i386/stand/libsa/gidt.S (revision a6445c1d)
1/*	$OpenBSD: gidt.S,v 1.36 2012/10/31 13:55:58 jsing Exp $	*/
2
3/*
4 * Copyright (c) 1997 Michael Shalayeff
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30	.file "gidt.S"
31
32#include <machine/asm.h>
33#define _LOCORE
34#include <machine/trap.h>
35#include <debug_md.h>
36#undef _LOCORE
37#include <assym.h>
38
39#include "gidt.h"
40
41#ifdef GIDT_DEBUG
42#define	gidt_debug0		; \
43	mov	$0xb8000, %eax	; \
44	mov	$0x47314730, (%eax)
45#define	gidt_debug1		; \
46	mov	$(0xb8000 - LINKADDR), %eax	; \
47	mov	$0x4f314f30, (%eax)
48#define	gidt_debug2		; \
49	mov	$0xb8004, %eax	; \
50	mov	$0x47334732, (%eax)
51#define	gidt_debug3		; \
52	mov	$0xb8004, %eax	; \
53	mov	$0x4f334f32, (%eax)
54#define gidt_debug4		; \
55	movl	$0xb8008, %eax	; \
56	movl	$0x47344733, (%eax)
57#else
58#define gidt_debug0 /* gidt_debug0 */
59#define gidt_debug1 /* gidt_debug1 */
60#define gidt_debug2 /* gidt_debug2 */
61#define gidt_debug3 /* gidt_debug3 */
62#define gidt_debug4 /* gidt_debug4 */
63#endif
64
65#define prot2real						\
66	gidt_debug0;						\
67								\
68	ljmp	$S16TEXT, $1f - LINKADDR;			\
691:								\
70	.code16;						\
71	movw	$S16DATA, %ax;					\
72	movw	%ax, %ds;					\
73	movw	%ax, %es;					\
74	gidt_debug1;						\
75								\
76	movl	%cr0, %eax;	/* disable pmmm */		\
77	andl 	$~CR0_PE, %eax;					\
78	movl	%eax, %cr0;					\
79								\
80	/* reload real cs:ip */					\
81	data32 ljmp	$(LINKADDR >> 4), $1f - LINKADDR;	\
821:								\
83	movw	%cs, %ax;	/* setup: %ds, %es, %ss = %cs */ \
84	movw	%ax, %ds;					\
85	movw	%ax, %es;					\
86	xorw	%ax, %ax;					\
87	movw	%ax, %ss;					\
88								\
89	gidt_debug2;						\
90								\
91	data32 addr32 lidt (Idtr_real - LINKADDR); /* load idtr for real mode */
92
93#define real2prot						\
94	gidt_debug3;						\
95								\
96	movw	$LINKADDR >> 4, %ax;				\
97	movw	%ax, %ds;					\
98	data32 addr32 lgdt (Gdtr - LINKADDR); 	/* load the gdtr */	\
99								\
100	movl	%cr0, %eax;	/* enable pmmm */		\
101	orl	$CR0_PE, %eax;					\
102	movl	%eax, %cr0;					\
103								\
104	data32 ljmp	$S32TEXT, $1f;   /* reload %cs,flush pipeline */\
1051:								\
106	.code32;						\
107	/* reload 32bit %ds, %ss, %es */			\
108	mov	$S32DATA, %eax;					\
109	mov	%ax, %ds;					\
110	mov	%ax, %ss;					\
111	mov	%ax, %es;					\
112								\
113	gidt_debug4;						\
114								\
115	/* load idtr for debugger and DOS/BIOS iface */		\
116	lidt	Idtr;
117
118
119	.globl	_C_LABEL(BIOS_regs)
120
121	.text
122	.code32
123	.globl	_ASM_LABEL(pmm_init)
124	.globl	_C_LABEL(_rtt)
125
126ENTRY(_rtt)
127#ifdef SOFTRAID
128	call	_C_LABEL(sr_clear_keys)
129#endif
130#ifdef GIDT_DEBUG
131	movl	$0xb8000, %ebx
132	movl	$0x4f514f51, (%ebx)
133#endif
134	movw	$0x1234, %ax
135	movw	%ax, 0x472	/* warm boot */
136
137	/* Try to use the KBD to reboot system */
138	movb	$0xfe, %al
139	outb	%al, $0x64
140
141	movl	$0x5000, %ecx
1421:	inb	$0x84, %al
143	loop	1b
144
145	movb	$0xfe, %al
146	outb	%al, $0x64
147
148#ifdef GIDT_DEBUG
149	movl	$0xb8000, %ebx
150	movl	$0x07310731, (%ebx)
151#endif
152
153	/* Try to cause a triple fault... */
154	lidt	Idtr_reset
155	xorl	%eax, %eax
156	divl	%eax, %eax
157
158	/* Again... */
159	int $0x8
160
161	/* Again... */
162	movl	$0, %esp	/* segment violation */
163	ret
164
165#define IPROC(n)	X##n
166#define IEMU(n)		IPROC(emu##n)
167
168create_idt_entry:
169	movw	%ax, (%ebx)
170	movw	$S32TEXT, 2(%ebx)
171	movw	$((0x80|SDT_SYS386TGT) << 8), 4(%ebx)
172	shr	$16, %eax
173	movw	%ax, 6(%ebx)
174	addl	$8, %ebx
175	ret
176
177	.align	8, 0x90
178pmm_init:
179
180#define idte(e)	\
181	movl $IPROC(e), %eax; call create_idt_entry
182#define idtb(b)	idte(emu##b)
183
184	/* Build interrupt descriptor table. */
185	/* Maskable interrupts (32-255) */
186	movl	$idt, %ebx
187	movl	$Idtr, %eax
188	movw	$(640 - 1), (%eax)
189	movl	%ebx, 2(%eax)
190
191	/* Internal (0-31) */
192	idte(de); idte(db); idte(nmi); idte(bp); idte(of); idte(br)
193	idte(ud); idte(nm); idte(df);  idte(fo); idte(ts); idte(np)
194	idte(ss); idte(gp); idte(pf);  idte(xx); idte(mf); idte(ac)
195	idte(mc)
196	idte(xx); idte(xx); idte(xx);  idte(xx); idte(xx); idte(xx)
197	idte(xx); idte(xx); idte(xx);  idte(xx); idte(xx); idte(xx)
198	idte(xx)
199	/* BIOS entry points (32-63) */
200	idtb(0);  idtb(1);  idtb(2);  idtb(3);  idtb(4);  idtb(5)
201	idtb(6);  idtb(7);  idtb(8);  idtb(9);  idtb(10); idtb(11)
202	idtb(12); idtb(13); idtb(14); idtb(15); idtb(16); idtb(17)
203	idtb(18); idtb(19); idtb(20); idtb(21); idtb(22); idtb(23)
204	idtb(24); idtb(25); idtb(26); idtb(27); idtb(28); idtb(29)
205	idtb(30); idtb(31); idtb(32); idtb(33); idtb(34); idtb(35)
206	idtb(36); idtb(37); idtb(38); idtb(39); idtb(40); idtb(41)
207	idtb(42); idtb(43); idtb(44); idtb(45); idtb(46); idtb(47)
208	/* DOS entry points (64-80) */
209
210#undef idtb
211#undef idte
212
213	/* load idtr for interrupts */
214	lidt	Idtr
215	ret
216
217	.bss
218	.align 8, 0x90
219idt:
220	/* IDT has 80 entries at 8 bytes each. */
221	.space  640
222
223	.globl	Idtr
224Idtr:	.word	0  // 640 - 1
225	.long	0  // idt
226	.word	0
227
228	.text
229	.align	8
230	.globl	Idtr_real
231Idtr_real:
232	.word	1023
233	.long	0
234	.word	0
235
236	.align	8
237Idtr_reset:
238	.long	0, 0
239
240	.align	8
241gdt:
242		/* 0x00 : null */
243	.space	8
244		/* 0x08 : flat code */
245	.word	0xFFFF			# lolimit
246	.word	0			# lobase
247	.byte	0			# midbase
248	.byte	SDT_MEMERAC | 0 | 0x80	# RXAC, dpl = 0, present
249	.byte	0xf | 0 | 0x40 | 0x80	# hilimit, xx, 32bit, 4k granularity
250	.byte	0			# hibase
251		/* 0x10 : flat data */
252	.word	0xFFFF			# lolimit
253	.word	0			# lobase
254	.byte	0			# midbase
255	.byte	SDT_MEMRWA | 0 | 0x80	# RWA, dpl = 0, present
256	.byte	0xf | 0 | 0x40 | 0x80	# hilimit, xx, 32bit, 4k granularity
257	.byte	0			# hibase
258		/* 0x18 : 16 bit code */
259	.word	0xFFFF			# lolimit
260	.word	(LINKADDR & 0xffff)	# lobase
261	.byte	(LINKADDR >> 16) & 0xff	# midbase
262	.byte	SDT_MEMERAC | 0 | 0x80	# RXAC, dpl = 0, present
263	.byte	0x0 | 0 | 0 | 0		# hilimit, xx, 16bit, byte granularity
264	.byte	(LINKADDR >> 20) & 0xff	# hibase
265		/* 0x20 : 16 bit data */
266	.word	0xFFFF			# lolimit
267	.word	(LINKADDR & 0xffff)	# lobase
268	.byte	(LINKADDR >> 16) & 0xff	# midbase
269	.byte	SDT_MEMRWA | 0 | 0x80	# RWA, dpl = 0, present
270	.byte	0x0 | 0 | 0 | 0		# hilimit, xx, 16bit, byte granularity
271	.byte	(LINKADDR >> 20) & 0xff	# hibase
272
273.globl Gdtr
274Gdtr:	.word	. - gdt - 1
275	.long	gdt
276	.word	0
277
278#define IENTRY(name,type) \
279IPROC(name): \
280	pushl	$type ; \
281	jmp	1f
282#define IENTRY_ERR(name,err,type) \
283IPROC(name): \
284	pushl	$err ; \
285	pushl	$type ; \
286	jmp	1f
287
288IPROC(xx):
289	pushl	$1
290	pushl	$T_RESERVED
291	jmp	1f
292
293IENTRY_ERR(de,0,T_DIVIDE)	/* #DE divide by zero */
294IENTRY_ERR(db,0,T_TRCTRAP)	/* #DB debug */
295IENTRY_ERR(nmi,0,T_NMI)		/* NMI */
296IENTRY_ERR(bp,0,T_BPTFLT)	/* #BP breakpoint */
297IENTRY_ERR(of,0,T_OFLOW)	/* #OF overflow */
298IENTRY_ERR(br,0,T_BOUND)	/* #BR BOUND range exceeded */
299IENTRY_ERR(ud,0,T_PRIVINFLT)	/* #UD invalid opcode */
300IENTRY_ERR(nm,0,T_DNA)		/* #NM device not available */
301IENTRY(df,T_DOUBLEFLT)		/* #DF double fault */
302IENTRY_ERR(fo,0,T_FPOPFLT)	/* #FO coprocessor segment overrun */
303IENTRY(ts,T_TSSFLT)		/* #TS invalid TSS */
304IENTRY(np,T_SEGNPFLT)		/* #NP segment not present */
305IENTRY(ss,T_STKFLT)		/* #SS stack fault */
306IENTRY(gp,T_PROTFLT)		/* #GP general protection */
307IENTRY(pf,T_PAGEFLT)		/* #PF page fault */
308IENTRY_ERR(mf,0,T_ARITHTRAP)	/* #MF floating point error */
309IENTRY(ac,T_ALIGNFLT)		/* #AC alignment check */
310IENTRY(mc,T_MACHK)		/* #MC machine check */
311
312	.globl	alltraps
3131:	/* save on jumps */
314	jmp	alltraps
315
316#define	IEMUENT(n)	IEMU(n): pushl $n; jmp 1f
317
318IEMUENT(0);  IEMUENT(1);  IEMUENT(2);  IEMUENT(3)
319IEMUENT(4);  IEMUENT(5);  IEMUENT(6);  IEMUENT(7)
320IEMUENT(8);  IEMUENT(9);  IEMUENT(10); IEMUENT(11)
321IEMUENT(12); IEMUENT(13); IEMUENT(14); IEMUENT(15)
322IEMUENT(16); IEMUENT(17); IEMUENT(18); IEMUENT(19)
323IEMUENT(20); IEMUENT(21); IEMUENT(22); IEMUENT(23)
324IEMUENT(24); IEMUENT(25); IEMUENT(26); IEMUENT(27)
325IEMUENT(28); IEMUENT(29); IEMUENT(30); IEMUENT(31)
3261:	jmp	EMUh	/* redirect for short jumps */
327IEMUENT(32); IEMUENT(33); IEMUENT(34); IEMUENT(35)
328IEMUENT(36); IEMUENT(37); IEMUENT(38); IEMUENT(39)
329IEMUENT(40); IEMUENT(41); IEMUENT(42); IEMUENT(43)
330IEMUENT(44); IEMUENT(45); IEMUENT(46); IEMUENT(47)
3311:	jmp	EMUh
332
333/*
334 * entry point for BIOS real-mode interface
335 * all the magic for real-prot mode switching is here
336 *
337 * Note: Once in real mode access to .data or .bss should be avoided since it
338 * may not be reachable within the current segment. The following code also
339 * assumes that .text is writeable.
340 *
341 * Call:	%eax, %ecx, %edx, %ebx, %ebp, %esi, %edi, %es, %ds
342 * Return:	%eax, %edx, %ecx, %eflags (as returned from BIOS)
343 *
344 */
345	.globl	EMUh
346	.align	8, 0x90
347EMUh:
348	/* save %eax */
349	mov	%eax, 5f
350	pop	%eax
351
352	pusha
353	push	%ds
354	push	%es
355	push	%fs
356	push	%gs
357
358	/* save BIOS int vector */
359	mov	%al, intno
360
361	/* Load BIOS registers prior to switching to real mode. */
362	movl	_C_LABEL(BIOS_regs)+BIOSR_ES, %eax
363	mov	%eax, 7f
364	movl	_C_LABEL(BIOS_regs)+BIOSR_DS, %eax
365	mov	%eax, 6f
366
367	prot2real
368
369	push	%ds
370
371	# data32 movl $Leax, %eax
372	.byte	0x66, 0xb8
3737:	.long	0x90909090
374	mov	%ax, %es
375
376	# data32 movl $Leax, %eax
377	.byte	0x66, 0xb8
3786:	.long	0x90909090
379	mov	%ax, %ds
380
381	# data32 movl $Leax, %eax
382	.byte	0x66, 0xb8
3835:	.long	0x90909090
384
385	;sti
386	int	$0
387intno	= . - 1
388	;cli
389
390	pop	%ds
391
392	/* Preserve BX and ES for protected mode. */
393	addr32 movl %eax, (2f - LINKADDR)
394	movl	%ebx, %eax
395	addr32 movl %eax, (4f - LINKADDR)
396	movl	%es, %eax
397	addr32 movl %eax, (3f - LINKADDR)
398	addr32 movl (2f - LINKADDR), %eax
399
400	movb	%ah, %bh
401	lahf
402	xchgb	%ah, %bh
403
404	/* Preserve AX for protected mode. */
405	addr32 movl %eax, (2f - LINKADDR)
406
407	real2prot
408
409	# movl $Leax, %eax
410	.byte	0xb8
4114:	.long	0x90909090
412	movl	%eax, _C_LABEL(BIOS_regs)+BIOSR_BX
413
414	# movl $Leax, %eax
415	.byte	0xb8
4163:	.long	0x90909090
417	movl	%eax, _C_LABEL(BIOS_regs)+BIOSR_ES
418
419	# movl $Leax, %eax
420	.byte	0xb8
4212:	.long	0x90909090
422
423	/* pass BIOS return values back to caller */
424	movl	%eax, 0xb*4(%esp)
425	movl	%ecx, 0xa*4(%esp)
426	movl	%edx, 0x9*4(%esp)
427	movb	%bh , 0xe*4(%esp)
428
429	/* clear NT flag in eflags */
430	/* Martin Fredriksson <martin@gbg.netman.se> */
431	pushf
432	pop	%eax
433	and	$0xffffbfff, %eax
434	push	%eax
435	popf
436
437	/* save registers into save area */
438	movl	%eax, _C_LABEL(BIOS_regs)+BIOSR_AX
439	movl	%ecx, _C_LABEL(BIOS_regs)+BIOSR_CX
440	movl	%edx, _C_LABEL(BIOS_regs)+BIOSR_DX
441	movl	%ebp, _C_LABEL(BIOS_regs)+BIOSR_BP
442	movl	%esi, _C_LABEL(BIOS_regs)+BIOSR_SI
443	movl	%edi, _C_LABEL(BIOS_regs)+BIOSR_DI
444
445	pop	%gs
446	pop	%fs
447	pop	%es
448	pop	%ds
449	popa
450	iret
451
452/* Call buffer at 07c0:0000 in real mode to simulate a BIOS boot */
453ENTRY(bootbuf)
454	pop	%eax		/* Don't need return address */
455	pop	%esi		/* Buffer */
456	pop	%edx		/* Device */
457	prot2real		/* Switch */
458
459	/* Set up stack */
460	cli
461	xor	%ax, %ax
462	mov	%ax, %ss
463	mov	$0xfffc, %esp
464	sti
465
466	/* Jump to buffer */
467	ljmp	$0x0, $0x7c00
468
469	.end
470