• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub.
3 */
4
5#include <librm.h>
6
7#define SIZEOF_I386_REGS	32
8#define SIZEOF_I386_FLAGS	4
9
10/****************************************************************************
11 * Interrupt Descriptor Table
12 ****************************************************************************
13 */
14	.section ".data16", "aw", @progbits
15	.globl idtr
16idtr:
17idt_limit:
18	.word	idt_length - 1
19idt_base:
20	.long	0
21
22/* IDT entries have the following format:
23 * offset_lo, segment selector, flags, offset_hi
24 *
25 * Since it is not possible to specify relocations in arbitrary
26 * expressions like (int_overflow & 0xffff), we initialise the
27 * IDT with entries in an incorrect format.
28 *
29 * The entries are shuffled into the correct format in init_librm().
30 */
31#define IDT_ENTRY_EMPTY(name) .word 0, 0, 0, 0
32#define IDT_ENTRY_PRESENT(name) \
33	.long	int_##name; \
34	.word	0x8e00, VIRTUAL_CS
35
36.align 16
37idt:
38	IDT_ENTRY_PRESENT(divide_error)
39	IDT_ENTRY_PRESENT(debug_trap)
40	IDT_ENTRY_EMPTY(non_maskable_interrupt)
41	IDT_ENTRY_PRESENT(breakpoint)
42	IDT_ENTRY_PRESENT(overflow)
43	IDT_ENTRY_PRESENT(bound_range_exceeded)
44	IDT_ENTRY_PRESENT(invalid_opcode)
45	IDT_ENTRY_EMPTY(device_not_available)
46	IDT_ENTRY_PRESENT(double_fault)
47	IDT_ENTRY_EMPTY(coprocessor_segment_overrun)
48	IDT_ENTRY_PRESENT(invalid_tss)
49	IDT_ENTRY_PRESENT(segment_not_present)
50	IDT_ENTRY_PRESENT(stack_segment_fault)
51	IDT_ENTRY_PRESENT(general_protection)
52	IDT_ENTRY_PRESENT(page_fault)
53idt_end:
54	.equ	idt_length, idt_end - idt
55
56/* The IDT entries are fixed up (once) in init_librm() */
57idt_fixed:
58	.byte	0
59
60/****************************************************************************
61 * idt_init (real-mode near call, 16-bit real-mode near return address)
62 *
63 * Initialise the IDT, called from init_librm.
64 *
65 * Parameters:
66 *   %eax : IDT base address
67 *
68 * Destroys %ax, %bx, and %di.
69 ****************************************************************************
70 */
71	.section ".text16", "ax", @progbits
72	.code16
73	.globl idt_init
74idt_init:
75	movl	%eax, idt_base
76	addl	$idt, idt_base
77
78	/* IDT entries are only fixed up once */
79	movb	idt_fixed, %al
80	orb	%al, %al
81	jnz	2f
82	movb	$1, idt_fixed
83
84	/* Shuffle IDT entries into the correct format */
85	movb	$(idt_length / 8), %al
86	movw	$idt, %bx
87	or	%al, %al
88	jz	2f
891:
90	movw	2(%bx), %di
91	xchg	%di, 6(%bx)
92	movw	%di, 2(%bx)
93	addw	$8, %bx
94	dec	%al
95	jnz	1b
962:
97	ret
98
99/****************************************************************************
100 * Interrupt handlers
101 ****************************************************************************
102 */
103	.section ".text", "ax", @progbits
104	.code32
105
106/* POSIX signal numbers for reporting traps to GDB */
107#define SIGILL 4
108#define SIGTRAP 5
109#define SIGBUS 7
110#define SIGFPE 8
111#define SIGSEGV 11
112#define SIGSTKFLT 16
113
114int_divide_error:
115	pushl	$SIGFPE
116	jmp	do_interrupt
117
118int_debug_trap:
119int_breakpoint:
120	pushl	$SIGTRAP
121	jmp	do_interrupt
122
123int_overflow:
124int_bound_range_exceeded:
125	pushl	$SIGSTKFLT
126	jmp	do_interrupt
127
128int_invalid_opcode:
129	pushl	$SIGILL
130	jmp	do_interrupt
131
132int_double_fault:
133	movl	$SIGBUS, (%esp)
134	jmp	do_interrupt
135
136int_invalid_tss:
137int_segment_not_present:
138int_stack_segment_fault:
139int_general_protection:
140int_page_fault:
141	movl	$SIGSEGV, (%esp)
142	jmp	do_interrupt
143
144/* When invoked, the stack contains: eflags, cs, eip, signo. */
145#define IH_OFFSET_GDB_REGS ( 0 )
146#define IH_OFFSET_GDB_EIP ( IH_OFFSET_GDB_REGS + SIZEOF_I386_REGS )
147#define IH_OFFSET_GDB_EFLAGS ( IH_OFFSET_GDB_EIP + 4 )
148#define IH_OFFSET_GDB_SEG_REGS ( IH_OFFSET_GDB_EFLAGS + SIZEOF_I386_FLAGS )
149#define IH_OFFSET_GDB_END ( IH_OFFSET_GDB_SEG_REGS + 6 * 4 )
150#define IH_OFFSET_SIGNO ( IH_OFFSET_GDB_END )
151#define IH_OFFSET_OLD_EIP ( IH_OFFSET_SIGNO + 4 )
152#define IH_OFFSET_OLD_CS ( IH_OFFSET_OLD_EIP + 4 )
153#define IH_OFFSET_OLD_EFLAGS ( IH_OFFSET_OLD_CS + 4 )
154#define IH_OFFSET_END ( IH_OFFSET_OLD_EFLAGS + 4 )
155
156/* We also access the stack whilst still storing or restoring
157 * the register snapshot.  Since ESP is in flux, we need
158 * special offsets.
159 */
160#define IH_OFFSET_FLUX_OLD_CS ( IH_OFFSET_OLD_CS - 44 )
161#define IH_OFFSET_FLUX_OLD_EFLAGS ( IH_OFFSET_OLD_EFLAGS - 40 )
162#define IH_OFFSET_FLUX_OLD_EIP ( IH_OFFSET_OLD_EIP - 36 )
163#define IH_OFFSET_FLUX_END ( IH_OFFSET_END - 20 )
164do_interrupt:
165	/* Store CPU state in GDB register snapshot */
166	pushw	$0
167	pushw	%gs
168	pushw	$0
169	pushw	%fs
170	pushw	$0
171	pushw	%es
172	pushw	$0
173	pushw	%ds
174	pushw	$0
175	pushw	%ss
176	pushw	$0
177	pushw	IH_OFFSET_FLUX_OLD_CS + 2(%esp)
178	pushl	IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
179	pushl	IH_OFFSET_FLUX_OLD_EIP(%esp)
180	pushl	%edi
181	pushl	%esi
182	pushl	%ebp
183	leal	IH_OFFSET_FLUX_END(%esp), %edi
184	pushl	%edi /* old ESP */
185	pushl	%ebx
186	pushl	%edx
187	pushl	%ecx
188	pushl	%eax
189
190	/* Call GDB stub exception handler */
191	pushl	%esp
192	pushl	(IH_OFFSET_SIGNO + 4)(%esp)
193	call	gdbmach_handler
194	addl	$8, %esp
195
196	/* Restore CPU state from GDB register snapshot */
197	popl	%eax
198	popl	%ecx
199	popl	%edx
200	popl	%ebx
201	addl	$4, %esp /* Changing ESP currently not supported */
202	popl	%ebp
203	popl	%esi
204	popl	%edi
205	popl	IH_OFFSET_FLUX_OLD_EIP(%esp)
206	popl	IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
207	popl	IH_OFFSET_FLUX_OLD_CS(%esp)
208	popl	%ss
209	popl	%ds
210	popl	%es
211	popl	%fs
212	popl	%gs
213
214	addl	$4, %esp /* drop signo */
215	iret
216