blob: 6d91b937ac243f889c28aef5f7e7c3d11923e11e [file] [log] [blame]
Subrata Banikafa39102024-05-18 12:26:40 +00001/*
2 *
3 * Copyright 2024 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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 .align 16
30 .global exception_stack_end
31exception_stack_end:
32 .quad 0
33 .global exception_state
34exception_state:
35 .quad 0
36
37/* Some temporary variables which are used while saving exception state. */
38vector:
39 .quad 0
40error_code:
41 .quad 0
Subrata Banikafa39102024-05-18 12:26:40 +000042old_rax:
43 .quad 0
Subrata Banik063c5942024-06-11 14:50:50 +000044old_rcx:
45 .quad 0
Subrata Banikafa39102024-05-18 12:26:40 +000046
47 .align 16
48
49/*
50 * Each exception vector has a small stub associated with it which sets aside
51 * the error code, if any, records which vector we entered from, and calls
52 * the common exception entry point. Some exceptions have error codes and some
53 * don't, so we have a macro for each type.
54 */
55
56 .macro stub num
57exception_stub_\num:
Subrata Banik063c5942024-06-11 14:50:50 +000058 movq $0, error_code
59 movq $\num, vector
60 jmp exception_common
Subrata Banikafa39102024-05-18 12:26:40 +000061 .endm
62
63 .macro stub_err num
64exception_stub_\num:
Subrata Banik063c5942024-06-11 14:50:50 +000065 pop error_code
66 movq $\num, vector
67 jmp exception_common
Subrata Banikafa39102024-05-18 12:26:40 +000068 .endm
69
70 .altmacro
Subrata Banik063c5942024-06-11 14:50:50 +000071 .macro user_defined_stubs from, to
72 stub \from
73 .if \to-\from
74 user_defined_stubs %(from+1),\to
Subrata Banikafa39102024-05-18 12:26:40 +000075 .endif
76 .endm
77
78 stub 0
79 stub 1
80 stub 2
81 stub 3
82 stub 4
83 stub 5
84 stub 6
85 stub 7
86 stub_err 8
87 stub 9
88 stub_err 10
89 stub_err 11
90 stub_err 12
91 stub_err 13
92 stub_err 14
93 stub 15
94 stub 16
95 stub_err 17
96 stub 18
97 stub 19
98 stub 20
99 stub 21
100 stub 22
101 stub 23
102 stub 24
103 stub 25
104 stub 26
105 stub 27
106 stub 28
107 stub 29
108 stub_err 30
109 stub 31
110 /* Split the macro so we avoid a stack overflow. */
111 user_defined_stubs 32, 63
112 user_defined_stubs 64, 127
113 user_defined_stubs 128, 191
114 user_defined_stubs 192, 255
115
116exception_common:
Subrata Banik063c5942024-06-11 14:50:50 +0000117 /*
118 * At this point, on x86-64, on the stack there is:
119 * 0(%rsp) rip
120 * 8(%rsp) cs
121 * 16(%rsp) rflags
122 * 24(%rsp) rsp
123 * 32(%rsp) ss
124 *
125 * This section sets up the exception stack.
126 * It saves the old stack pointer (rsp) to preserve RIP, CS, RFLAGS and SS.
127 * Then sets up the new stack pointer to point to the exception stack area.
128 */
129 movq %rax, old_rax
130 movq %rcx, old_rcx
Subrata Banikafa39102024-05-18 12:26:40 +0000131
Subrata Banik063c5942024-06-11 14:50:50 +0000132 mov %rsp, %rax
133 movq exception_stack_end, %rsp
134 /*
135 * The `exception_state` struct is not 16-byte aligned.
136 * Push an extra 8 bytes to ensure the stack pointer
137 * is 16-byte aligned before calling exception_dispatch.
138 */
139 push $0
140
141 /*
142 * Push values onto the top of the exception stack to form an
143 * exception state structure.
144 */
145 push vector
146 push error_code
147
148 /* push of the gs, fs, es, ds, ss and cs */
149 mov %gs, %rcx
150 movl %ecx, -4(%rsp) /* gs */
151 mov %fs, %rcx
152 movl %ecx, -8(%rsp) /* fs */
153 movl $0, -12(%rsp) /* es */
154 movl $0, -16(%rsp) /* ds */
155 movq 32(%rax), %rcx
156 movl %ecx, -20(%rsp) /* ss */
157 movq 8(%rax), %rcx
158 movl %ecx, -24(%rsp) /* cs */
159 sub $24, %rsp
160
161 push 16(%rax) /* rflags */
162 push (%rax) /* rip */
163 push %r15
164 push %r14
165 push %r13
166 push %r12
167 push %r11
168 push %r10
169 push %r9
170 push %r8
171 push 24(%rax) /* rsp */
172 push %rbp
173 push %rdi
174 push %rsi
175 push %rdx
176 push old_rcx /* rcx */
177 push %rbx
178 push old_rax /* rax */
179
180 /*
181 * Call the C exception handler. It will find the exception state
182 * using the exception_state global pointer. Not
183 * passing parameters means we don't have to worry about what ABI
184 * is being used.
185 */
186 mov %rsp, exception_state
187 call exception_dispatch
188
189 /*
190 * Restore state from the exception state structure, including any
191 * changes that might have been made.
192 */
193 pop old_rax
194 pop %rbx
195 pop old_rcx
196 pop %rdx
197 pop %rsi
198 pop %rdi
199 pop %rbp
200 lea exception_stack, %rax
201 pop 24(%rax) /* rsp */
202 pop %r8
203 pop %r9
204 pop %r10
205 pop %r11
206 pop %r12
207 pop %r13
208 pop %r14
209 pop %r15
210 pop (%rax) /* rip */
211 pop 16(%rax) /* rflags */
212
213 /* pop of the gs, fs, es, ds, ss and cs */
214 movl (%rsp), %ecx
215 movq %rcx, 8(%rax) /* cs */
216 movl 4(%rsp), %ecx
217 movq %rcx, 32(%rax) /* ss */
218 movl 16(%rsp), %ecx
219 mov %rcx, %fs /* fs */
220 movl 20(%rsp), %ecx
221 mov %rcx, %gs /* gs */
222
223 mov %rax, %rsp
224 movq old_rax, %rax
225 movq old_rcx, %rcx
226
227 iretq
Subrata Banikafa39102024-05-18 12:26:40 +0000228
229/*
230 * We need segment selectors for the IDT, so we need to know where things are
231 * in the GDT. We set one up here which is pretty standard and largely copied
232 * from coreboot.
233 */
234 .align 16
235gdt:
236 /* selgdt 0, unused */
237 .word 0x0000, 0x0000
238 .byte 0x00, 0x00, 0x00, 0x00
239
240 /* selgdt 8, unused */
241 .word 0x0000, 0x0000
242 .byte 0x00, 0x00, 0x00, 0x00
243
244 /* selgdt 0x10, flat 4GB code segment */
245 .word 0xffff, 0x0000
246 .byte 0x00, 0x9b, 0xcf, 0x00
247
248 /* selgdt 0x18, flat 4GB data segment */
249 .word 0xffff, 0x0000
Subrata Banik063c5942024-06-11 14:50:50 +0000250 .byte 0x00, 0x92, 0xcf, 0x00
Subrata Banikafa39102024-05-18 12:26:40 +0000251
252 /* selgdt 0x20, flat x64 code segment */
Subrata Banik063c5942024-06-11 14:50:50 +0000253 .word 0xffff, 0x0000
254 .byte 0x00, 0x9b, 0xaf, 0x00
Subrata Banikafa39102024-05-18 12:26:40 +0000255gdt_end:
256
257/* GDT pointer for use with lgdt */
258.global gdt_ptr
259gdt_ptr:
Subrata Banik063c5942024-06-11 14:50:50 +0000260 .word gdt_end - gdt - 1
261 .quad gdt
Subrata Banikafa39102024-05-18 12:26:40 +0000262
263 /*
264 * Record the target and construct the actual entry at init time. This
265 * is necessary because the linker doesn't want to construct the entry
266 * for us.
267 */
268 .macro interrupt_gate target
Subrata Banik063c5942024-06-11 14:50:50 +0000269 .word 0 /* patchable */
270 .word 0x20 /* Target code segment selector */
271 .word 0xee00 /* Present, Type 64-bit Interrupt Gate */
272 .word 0 /* patchable */
273 .quad \target /* patchable */
Subrata Banikafa39102024-05-18 12:26:40 +0000274 .endm
275
276 .altmacro
277 .macro user_defined_gates from, to
278 interrupt_gate exception_stub_\from
279 .if \to-\from
280 user_defined_gates %(from+1),\to
281 .endif
282 .endm
283
284 .align 16
Subrata Banik063c5942024-06-11 14:50:50 +0000285 .global idt
Subrata Banikafa39102024-05-18 12:26:40 +0000286idt:
287 interrupt_gate exception_stub_0
288 interrupt_gate exception_stub_1
289 interrupt_gate exception_stub_2
290 interrupt_gate exception_stub_3
291 interrupt_gate exception_stub_4
292 interrupt_gate exception_stub_5
293 interrupt_gate exception_stub_6
294 interrupt_gate exception_stub_7
295 interrupt_gate exception_stub_8
296 interrupt_gate exception_stub_9
297 interrupt_gate exception_stub_10
298 interrupt_gate exception_stub_11
299 interrupt_gate exception_stub_12
300 interrupt_gate exception_stub_13
301 interrupt_gate exception_stub_14
302 interrupt_gate exception_stub_15
303 interrupt_gate exception_stub_16
304 interrupt_gate exception_stub_17
305 interrupt_gate exception_stub_18
306 interrupt_gate exception_stub_19
307 interrupt_gate exception_stub_20
308 interrupt_gate exception_stub_21
309 interrupt_gate exception_stub_22
310 interrupt_gate exception_stub_23
311 interrupt_gate exception_stub_24
312 interrupt_gate exception_stub_25
313 interrupt_gate exception_stub_26
314 interrupt_gate exception_stub_27
315 interrupt_gate exception_stub_28
316 interrupt_gate exception_stub_29
317 interrupt_gate exception_stub_30
318 interrupt_gate exception_stub_31
319 user_defined_gates 32, 63
320 user_defined_gates 64, 127
321 user_defined_gates 128, 191
322 user_defined_gates 192, 255
323idt_end:
324
325/* IDT pointer for use with lidt */
326idt_ptr:
327 .word idt_end - idt - 1
328 .quad idt
329
Subrata Banik063c5942024-06-11 14:50:50 +0000330.section .text.exception_init_asm
331.globl exception_init_asm
332.type exception_init_asm, @function
333
Subrata Banikafa39102024-05-18 12:26:40 +0000334exception_init_asm:
Subrata Banik063c5942024-06-11 14:50:50 +0000335 /* Set up IDT entries */
336 mov $idt, %rax
3371:
338 movq 8(%rax), %rdi
339 movw %di, (%rax) /* procedure entry point offset bits 0..15 */
340 shr $16, %rdi
341 movw %di, 6(%rax) /* procedure entry point offset bits 16..31 */
342 shr $16, %rdi
343 movl %edi, 8(%rax) /* procedure entry point offset bits 32..63 */
344 movl $0, 12(%rax) /* reserved */
345 add $16, %rax
346 cmp $idt_end, %rax
347 jne 1b
348
349 /* Load the IDT */
350 lidt idt_ptr
Subrata Banikafa39102024-05-18 12:26:40 +0000351 ret