xref: /aosp_15_r20/external/coreboot/payloads/libpayload/arch/x86/exception_asm.S (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1/*
2 *
3 * Copyright 2013 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 4
30	.global exception_stack_end
31exception_stack_end:
32	.long 0
33	.global exception_state
34exception_state:
35	.long 0
36
37/* Some temporary variables which are used while saving exception state. */
38vector:
39	.long 0
40error_code:
41	.long 0
42old_esp:
43	.long 0
44old_eax:
45	.long 0
46
47	.align 8
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:
58	movl	$0, error_code
59	movl	$\num, vector
60	jmp	exception_common
61	.endm
62
63	.macro stub_err num
64exception_stub_\num:
65	popl	error_code
66	movl	$\num, vector
67	jmp	exception_common
68	.endm
69
70	.altmacro
71	.macro	user_defined_stubs from, to
72	stub	\from
73	.if	\to-\from
74	user_defined_stubs	%(from+1),\to
75	.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:
117	/*
118	 * Save off the stack pointer and old eax value and install the
119	 * exception stack. eax points to the old stack which has the
120	 * exception ip, cs, and flags.
121	 */
122	mov	%esp, old_esp
123	addl	$12, old_esp
124	mov	%eax, old_eax
125	mov	%esp, %eax
126	mov	exception_stack_end, %esp
127
128	/*
129	 * Push values onto the top of the exception stack to form an
130	 * exception state structure.
131	 */
132	pushl	vector
133	pushl	error_code
134	pushl	%gs
135	pushl	%fs
136	pushl	%es
137	pushl	%ds
138	pushl	%ss
139	pushl	4(%eax)
140	pushl	8(%eax)
141	pushl	(%eax)
142	pushl	%edi
143	pushl	%esi
144	pushl	%ebp
145	pushl	old_esp
146	pushl	%ebx
147	pushl	%edx
148	pushl	%ecx
149	pushl	old_eax
150
151	/*
152	 * Call the C exception handler. It will find the exception state
153	 * using the exception_state global pointer. Not
154	 * passing parameters means we don't have to worry about what ABI
155	 * is being used.
156	 */
157	mov	%esp, exception_state
158	call	exception_dispatch
159
160	/*
161	 * Restore state from the exception state structure, including any
162	 * changes that might have been made.
163	 */
164	popl	old_eax
165	popl	%ecx
166	popl	%edx
167	popl	%ebx
168	popl	old_esp
169
170	mov	old_esp, %eax
171	subl	$12, %eax
172
173	popl	%ebp
174	popl	%esi
175	popl	%edi
176	popl	(%eax)
177	popl	8(%eax)
178	popl	4(%eax)
179	popl	%ss
180	popl	%ds
181	popl	%es
182	popl	%fs
183	popl	%gs
184
185	mov	%eax, %esp
186	mov	old_eax, %eax
187
188	/* Return from the exception. */
189	iretl
190
191/*
192 * We need segment selectors for the IDT, so we need to know where things are
193 * in the GDT. We set one up here which is pretty standard and largely copied
194 * from coreboot.
195 */
196	.align 8
197gdt:
198	/* selgdt 0, unused */
199	.word 0x0000, 0x0000
200	.byte 0x00, 0x00, 0x00, 0x00
201
202	/* selgdt 8, unused */
203	.word 0x0000, 0x0000
204	.byte 0x00, 0x00, 0x00, 0x00
205
206	/* selgdt 0x10, flat 4GB code segment */
207        .word 0xffff, 0x0000
208	.byte 0x00, 0x9b, 0xcf, 0x00
209
210	/* selgdt 0x18, flat 4GB data segment */
211	.word 0xffff, 0x0000
212	.byte 0x00, 0x93, 0xcf, 0x00
213gdt_end:
214
215/* GDT pointer for use with lgdt */
216gdt_ptr:
217	.word	gdt_end - gdt - 1
218	.long	gdt
219
220	/*
221	 * Record the target and construct the actual entry at init time. This
222	 * is necessary because the linker doesn't want to construct the entry
223	 * for us.
224	 */
225	.macro interrupt_gate target
226	.long \target
227	.long \target
228	.endm
229
230	.altmacro
231	.macro	user_defined_gates from, to
232	interrupt_gate	exception_stub_\from
233	.if	\to-\from
234	user_defined_gates	%(from+1),\to
235	.endif
236	.endm
237
238	.align 8
239	.global	idt
240idt:
241	interrupt_gate exception_stub_0
242	interrupt_gate exception_stub_1
243	interrupt_gate exception_stub_2
244	interrupt_gate exception_stub_3
245	interrupt_gate exception_stub_4
246	interrupt_gate exception_stub_5
247	interrupt_gate exception_stub_6
248	interrupt_gate exception_stub_7
249	interrupt_gate exception_stub_8
250	interrupt_gate exception_stub_9
251	interrupt_gate exception_stub_10
252	interrupt_gate exception_stub_11
253	interrupt_gate exception_stub_12
254	interrupt_gate exception_stub_13
255	interrupt_gate exception_stub_14
256	interrupt_gate exception_stub_15
257	interrupt_gate exception_stub_16
258	interrupt_gate exception_stub_17
259	interrupt_gate exception_stub_18
260	interrupt_gate exception_stub_19
261	interrupt_gate exception_stub_20
262	interrupt_gate exception_stub_21
263	interrupt_gate exception_stub_22
264	interrupt_gate exception_stub_23
265	interrupt_gate exception_stub_24
266	interrupt_gate exception_stub_25
267	interrupt_gate exception_stub_26
268	interrupt_gate exception_stub_27
269	interrupt_gate exception_stub_28
270	interrupt_gate exception_stub_29
271	interrupt_gate exception_stub_30
272	interrupt_gate exception_stub_31
273	user_defined_gates 32, 63
274	user_defined_gates 64, 127
275	user_defined_gates 128, 191
276	user_defined_gates 192, 255
277idt_end:
278
279/* IDT pointer for use with lidt */
280idt_ptr:
281	.word idt_end - idt - 1
282	.long idt
283
284	.global exception_init_asm
285exception_init_asm:
286	/* Save eax so we can use it as a temporary variable. */
287	pushl	%eax
288
289	/* Install the GDT. */
290	lgdt	gdt_ptr
291	/* Load the segment registers from it. */
292	ljmp	$0x10, $1f
2931:	movl	$0x18, %eax
294	movl	%eax, %ds
295	movl	%eax, %es
296	movl	%eax, %ss
297	movl	%eax, %fs
298	movl	%eax, %gs
299
300	/*
301	 * Loop over the entries which start out as two copies of the target
302	 * address. We can turn them into real interrupt gates by selectively
303	 * replacing certain bit fields.
304	 */
305	movl	$idt, %eax
3061:
307	andl	$0x0000ffff, (%eax)
308	orl	$0x00100000, (%eax)
309	andl	$0xffff0000, 4(%eax)
310	orl	$0x0000ee00, 4(%eax)
311	addl	$8, %eax
312	cmp	$idt_end, %eax
313	jne	1b
314
315	/* Install the IDT. */
316	lidt	idt_ptr
317
318	/* Restore eax and return to the caller. */
319	popl	%eax
320	ret
321