a49492328bcc47322c4dcafca761b93bd6539ca4
[people/andreif/gpxe.git] / src / arch / i386 / core / gdbidt.S
1 /*
2  * Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub.
3  */
4
5 #include <virtaddr.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"
15         .globl idtr
16 idtr:
17 idt_limit:
18         .word   idt_length - 1
19 idt_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
37 idt:
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)
53 idt_end:
54         .equ    idt_length, idt_end - idt
55
56 /* The IDT entries are fixed up (once) in init_librm() */
57 idt_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"
72         .code16
73         .globl idt_init
74 idt_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
89 1:
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
96 2:
97         ret
98
99 /****************************************************************************
100  * Interrupt handlers
101  ****************************************************************************
102  */
103         .section ".text"
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
114 int_divide_error:
115         pushl   $SIGFPE
116         jmp     do_interrupt
117
118 int_debug_trap:
119 int_breakpoint:
120         pushl   $SIGTRAP
121         jmp     do_interrupt
122
123 int_overflow:
124 int_bound_range_exceeded:
125         pushl   $SIGSTKFLT
126         jmp     do_interrupt
127
128 int_invalid_opcode:
129         pushl   $SIGILL
130         jmp     do_interrupt
131
132 int_double_fault:
133         movl    $SIGBUS, (%esp)
134         jmp     do_interrupt
135
136 int_invalid_tss:
137 int_segment_not_present:
138 int_stack_segment_fault:
139 int_general_protection:
140 int_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 )
164 do_interrupt:
165         /* Store CPU state in GDB register snapshot */
166         pushl   %gs
167         pushl   %fs
168         pushl   %es
169         pushl   %ds
170         pushl   %ss
171         pushl   IH_OFFSET_FLUX_OLD_CS(%esp)
172         pushl   IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
173         pushl   IH_OFFSET_FLUX_OLD_EIP(%esp)
174         pushl   %edi
175         pushl   %esi
176         pushl   %ebp
177         leal    IH_OFFSET_FLUX_END(%esp), %edi
178         pushl   %edi /* old ESP */
179         pushl   %ebx
180         pushl   %edx
181         pushl   %ecx
182         pushl   %eax
183
184         /* Call GDB stub exception handler */
185         pushl   %esp
186         pushl   (IH_OFFSET_SIGNO + 4)(%esp)
187         call    gdbmach_handler
188         addl    $8, %esp
189
190         /* Restore CPU state from GDB register snapshot */
191         popl    %eax
192         popl    %ecx
193         popl    %edx
194         popl    %ebx
195         addl    $4, %esp /* Changing ESP currently not supported */
196         popl    %ebp
197         popl    %esi
198         popl    %edi
199         popl    IH_OFFSET_FLUX_OLD_EIP(%esp)
200         popl    IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
201         popl    IH_OFFSET_FLUX_OLD_CS(%esp)
202         popl    %ss
203         popl    %ds
204         popl    %es
205         popl    %fs
206         popl    %gs
207
208         addl    $4, %esp /* drop signo */
209         iret