]>
Commit | Line | Data |
---|---|---|
0ff5aa9c | 1 | ;------------------------------------------------------------------------------ ;\r |
2aa107c0 | 2 | ; Copyright (c) 2017 - 2022, Intel Corporation. All rights reserved.<BR>\r |
0acd8697 | 3 | ; SPDX-License-Identifier: BSD-2-Clause-Patent\r |
0ff5aa9c JW |
4 | ;\r |
5 | ; Module Name:\r | |
6 | ;\r | |
7 | ; ExceptionTssEntryAsm.Asm\r | |
8 | ;\r | |
9 | ; Abstract:\r | |
10 | ;\r | |
11 | ; IA32 CPU Exception Handler with Separate Stack\r | |
12 | ;\r | |
13 | ; Notes:\r | |
14 | ;\r | |
15 | ;------------------------------------------------------------------------------\r | |
16 | \r | |
17 | ;\r | |
18 | ; IA32 TSS Memory Layout Description\r | |
19 | ;\r | |
20 | struc IA32_TSS\r | |
21 | resw 1\r | |
22 | resw 1\r | |
23 | .ESP0: resd 1\r | |
24 | .SS0: resw 1\r | |
25 | resw 1\r | |
26 | .ESP1: resd 1\r | |
27 | .SS1: resw 1\r | |
28 | resw 1\r | |
29 | .ESP2: resd 1\r | |
30 | .SS2: resw 1\r | |
31 | resw 1\r | |
32 | ._CR3: resd 1\r | |
33 | .EIP: resd 1\r | |
34 | .EFLAGS: resd 1\r | |
35 | ._EAX: resd 1\r | |
36 | ._ECX: resd 1\r | |
37 | ._EDX: resd 1\r | |
38 | ._EBX: resd 1\r | |
39 | ._ESP: resd 1\r | |
40 | ._EBP: resd 1\r | |
41 | ._ESI: resd 1\r | |
42 | ._EDI: resd 1\r | |
43 | ._ES: resw 1\r | |
44 | resw 1\r | |
45 | ._CS: resw 1\r | |
46 | resw 1\r | |
47 | ._SS: resw 1\r | |
48 | resw 1\r | |
49 | ._DS: resw 1\r | |
50 | resw 1\r | |
51 | ._FS: resw 1\r | |
52 | resw 1\r | |
53 | ._GS: resw 1\r | |
54 | resw 1\r | |
55 | .LDT: resw 1\r | |
56 | resw 1\r | |
57 | resw 1\r | |
58 | resw 1\r | |
59 | endstruc\r | |
60 | \r | |
61 | ;\r | |
62 | ; CommonExceptionHandler()\r | |
63 | ;\r | |
64 | extern ASM_PFX(CommonExceptionHandler)\r | |
65 | \r | |
66 | SECTION .data\r | |
67 | \r | |
68 | SECTION .text\r | |
69 | \r | |
70 | ALIGN 8\r | |
71 | \r | |
72 | ;\r | |
73 | ; Exception handler stub table\r | |
74 | ;\r | |
75 | AsmExceptionEntryBegin:\r | |
76 | %assign Vector 0\r | |
77 | %rep 32\r | |
78 | \r | |
79 | DoIret%[Vector]:\r | |
80 | iretd\r | |
81 | ASM_PFX(ExceptionTaskSwtichEntry%[Vector]):\r | |
2aa107c0 | 82 | push byte %[Vector]\r |
0ff5aa9c JW |
83 | mov eax, ASM_PFX(CommonTaskSwtichEntryPoint)\r |
84 | call eax\r | |
85 | mov esp, eax ; Restore stack top\r | |
86 | jmp DoIret%[Vector]\r | |
87 | \r | |
88 | %assign Vector Vector+1\r | |
89 | %endrep\r | |
90 | AsmExceptionEntryEnd:\r | |
91 | \r | |
92 | ;\r | |
93 | ; Common part of exception handler\r | |
94 | ;\r | |
95 | global ASM_PFX(CommonTaskSwtichEntryPoint)\r | |
96 | ASM_PFX(CommonTaskSwtichEntryPoint):\r | |
97 | ;\r | |
98 | ; Stack:\r | |
99 | ; +---------------------+ <-- EBP - 8\r | |
100 | ; + TSS Base +\r | |
101 | ; +---------------------+ <-- EBP - 4\r | |
102 | ; + CPUID.EDX +\r | |
103 | ; +---------------------+ <-- EBP\r | |
104 | ; + EIP +\r | |
105 | ; +---------------------+ <-- EBP + 4\r | |
106 | ; + Vector Number +\r | |
107 | ; +---------------------+ <-- EBP + 8\r | |
108 | ; + Error Code +\r | |
109 | ; +---------------------+\r | |
110 | ;\r | |
111 | \r | |
112 | mov ebp, esp ; Stack frame\r | |
113 | \r | |
114 | ; Use CPUID to determine if FXSAVE/FXRESTOR and DE are supported\r | |
115 | mov eax, 1\r | |
116 | cpuid\r | |
117 | push edx\r | |
118 | \r | |
119 | ; Get TSS base of interrupted task through PreviousTaskLink field in\r | |
120 | ; current TSS base\r | |
121 | sub esp, 8\r | |
122 | sgdt [esp + 2]\r | |
123 | mov eax, [esp + 4] ; GDT base\r | |
124 | add esp, 8\r | |
125 | \r | |
126 | xor ebx, ebx\r | |
127 | str bx ; Current TR\r | |
128 | \r | |
129 | mov ecx, [eax + ebx + 2]\r | |
130 | shl ecx, 8\r | |
131 | mov cl, [eax + ebx + 7]\r | |
132 | ror ecx, 8 ; ecx = Current TSS base\r | |
133 | push ecx ; keep it in stack for later use\r | |
134 | \r | |
135 | movzx ebx, word [ecx] ; Previous Task Link\r | |
136 | mov ecx, [eax + ebx + 2]\r | |
137 | shl ecx, 8\r | |
138 | mov cl, [eax + ebx + 7]\r | |
139 | ror ecx, 8 ; ecx = Previous TSS base\r | |
140 | \r | |
141 | ;\r | |
142 | ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32\r | |
143 | ; is 16-byte aligned\r | |
144 | ;\r | |
145 | and esp, 0xfffffff0\r | |
146 | sub esp, 12\r | |
147 | \r | |
148 | ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;\r | |
149 | push dword [ecx + IA32_TSS._EAX]\r | |
150 | push dword [ecx + IA32_TSS._ECX]\r | |
151 | push dword [ecx + IA32_TSS._EDX]\r | |
152 | push dword [ecx + IA32_TSS._EBX]\r | |
153 | push dword [ecx + IA32_TSS._ESP]\r | |
154 | push dword [ecx + IA32_TSS._EBP]\r | |
155 | push dword [ecx + IA32_TSS._ESI]\r | |
156 | push dword [ecx + IA32_TSS._EDI]\r | |
157 | \r | |
158 | ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;\r | |
159 | movzx eax, word [ecx + IA32_TSS._SS]\r | |
160 | push eax\r | |
161 | movzx eax, word [ecx + IA32_TSS._CS]\r | |
162 | push eax\r | |
163 | movzx eax, word [ecx + IA32_TSS._DS]\r | |
164 | push eax\r | |
165 | movzx eax, word [ecx + IA32_TSS._ES]\r | |
166 | push eax\r | |
167 | movzx eax, word [ecx + IA32_TSS._FS]\r | |
168 | push eax\r | |
169 | movzx eax, word [ecx + IA32_TSS._GS]\r | |
170 | push eax\r | |
171 | \r | |
172 | ;; UINT32 Eip;\r | |
173 | push dword [ecx + IA32_TSS.EIP]\r | |
174 | \r | |
175 | ;; UINT32 Gdtr[2], Idtr[2];\r | |
176 | sub esp, 8\r | |
177 | sidt [esp]\r | |
178 | mov eax, [esp + 2]\r | |
179 | xchg eax, [esp]\r | |
180 | and eax, 0xFFFF\r | |
181 | mov [esp+4], eax\r | |
182 | \r | |
183 | sub esp, 8\r | |
184 | sgdt [esp]\r | |
185 | mov eax, [esp + 2]\r | |
186 | xchg eax, [esp]\r | |
187 | and eax, 0xFFFF\r | |
188 | mov [esp+4], eax\r | |
189 | \r | |
190 | ;; UINT32 Ldtr, Tr;\r | |
191 | mov eax, ebx ; ebx still keeps selector of interrupted task\r | |
192 | push eax\r | |
193 | movzx eax, word [ecx + IA32_TSS.LDT]\r | |
194 | push eax\r | |
195 | \r | |
196 | ;; UINT32 EFlags;\r | |
197 | push dword [ecx + IA32_TSS.EFLAGS]\r | |
198 | \r | |
199 | ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;\r | |
200 | mov eax, cr4\r | |
201 | push eax ; push cr4 firstly\r | |
202 | \r | |
203 | mov edx, [ebp - 4] ; cpuid.edx\r | |
204 | test edx, BIT24 ; Test for FXSAVE/FXRESTOR support\r | |
205 | jz .1\r | |
206 | or eax, BIT9 ; Set CR4.OSFXSR\r | |
207 | .1:\r | |
208 | test edx, BIT2 ; Test for Debugging Extensions support\r | |
209 | jz .2\r | |
210 | or eax, BIT3 ; Set CR4.DE\r | |
211 | .2:\r | |
212 | mov cr4, eax\r | |
213 | \r | |
214 | mov eax, cr3\r | |
215 | push eax\r | |
216 | mov eax, cr2\r | |
217 | push eax\r | |
218 | xor eax, eax\r | |
219 | push eax\r | |
220 | mov eax, cr0\r | |
221 | push eax\r | |
222 | \r | |
223 | ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r | |
224 | mov eax, dr7\r | |
225 | push eax\r | |
226 | mov eax, dr6\r | |
227 | push eax\r | |
228 | mov eax, dr3\r | |
229 | push eax\r | |
230 | mov eax, dr2\r | |
231 | push eax\r | |
232 | mov eax, dr1\r | |
233 | push eax\r | |
234 | mov eax, dr0\r | |
235 | push eax\r | |
236 | \r | |
237 | ;; FX_SAVE_STATE_IA32 FxSaveState;\r | |
238 | ;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)\r | |
239 | ;; when executing fxsave/fxrstor instruction\r | |
240 | test edx, BIT24 ; Test for FXSAVE/FXRESTOR support.\r | |
241 | ; edx still contains result from CPUID above\r | |
242 | jz .3\r | |
243 | clts\r | |
244 | sub esp, 512\r | |
245 | mov edi, esp\r | |
2aa107c0 | 246 | fxsave [edi]\r |
0ff5aa9c JW |
247 | .3:\r |
248 | \r | |
249 | ;; UINT32 ExceptionData;\r | |
250 | push dword [ebp + 8]\r | |
251 | \r | |
252 | ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear\r | |
253 | cld\r | |
254 | \r | |
255 | ;; call into exception handler\r | |
256 | mov esi, ecx ; Keep TSS base to avoid overwrite\r | |
257 | mov eax, ASM_PFX(CommonExceptionHandler)\r | |
258 | \r | |
259 | ;; Prepare parameter and call\r | |
260 | mov edx, esp\r | |
261 | push edx ; EFI_SYSTEM_CONTEXT\r | |
262 | push dword [ebp + 4] ; EFI_EXCEPTION_TYPE (vector number)\r | |
263 | \r | |
264 | ;\r | |
265 | ; Call External Exception Handler\r | |
266 | ;\r | |
267 | call eax\r | |
268 | add esp, 8 ; Restore stack before calling\r | |
269 | mov ecx, esi ; Restore TSS base\r | |
270 | \r | |
271 | ;; UINT32 ExceptionData;\r | |
272 | add esp, 4\r | |
273 | \r | |
274 | ;; FX_SAVE_STATE_IA32 FxSaveState;\r | |
275 | mov edx, [ebp - 4] ; cpuid.edx\r | |
276 | test edx, BIT24 ; Test for FXSAVE/FXRESTOR support\r | |
277 | jz .4\r | |
278 | mov esi, esp\r | |
2aa107c0 | 279 | fxrstor [esi]\r |
0ff5aa9c JW |
280 | .4:\r |
281 | add esp, 512\r | |
282 | \r | |
283 | ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r | |
284 | ;; Skip restoration of DRx registers to support debuggers\r | |
285 | ;; that set breakpoints in interrupt/exception context\r | |
286 | add esp, 4 * 6\r | |
287 | \r | |
288 | ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;\r | |
289 | pop eax\r | |
290 | mov cr0, eax\r | |
291 | add esp, 4 ; not for Cr1\r | |
292 | pop eax\r | |
293 | mov cr2, eax\r | |
294 | pop eax\r | |
295 | mov dword [ecx + IA32_TSS._CR3], eax\r | |
296 | pop eax\r | |
297 | mov cr4, eax\r | |
298 | \r | |
299 | ;; UINT32 EFlags;\r | |
300 | pop dword [ecx + IA32_TSS.EFLAGS]\r | |
301 | mov ebx, dword [ecx + IA32_TSS.EFLAGS]\r | |
302 | btr ebx, 9 ; Do 'cli'\r | |
303 | mov dword [ecx + IA32_TSS.EFLAGS], ebx\r | |
304 | \r | |
305 | ;; UINT32 Ldtr, Tr;\r | |
306 | ;; UINT32 Gdtr[2], Idtr[2];\r | |
307 | ;; Best not let anyone mess with these particular registers...\r | |
308 | add esp, 24\r | |
309 | \r | |
310 | ;; UINT32 Eip;\r | |
311 | pop dword [ecx + IA32_TSS.EIP]\r | |
312 | \r | |
313 | ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;\r | |
314 | ;; NOTE - modified segment registers could hang the debugger... We\r | |
315 | ;; could attempt to insulate ourselves against this possibility,\r | |
316 | ;; but that poses risks as well.\r | |
317 | ;;\r | |
318 | pop eax\r | |
319 | o16 mov [ecx + IA32_TSS._GS], ax\r | |
320 | pop eax\r | |
321 | o16 mov [ecx + IA32_TSS._FS], ax\r | |
322 | pop eax\r | |
323 | o16 mov [ecx + IA32_TSS._ES], ax\r | |
324 | pop eax\r | |
325 | o16 mov [ecx + IA32_TSS._DS], ax\r | |
326 | pop eax\r | |
327 | o16 mov [ecx + IA32_TSS._CS], ax\r | |
328 | pop eax\r | |
329 | o16 mov [ecx + IA32_TSS._SS], ax\r | |
330 | \r | |
331 | ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;\r | |
332 | pop dword [ecx + IA32_TSS._EDI]\r | |
333 | pop dword [ecx + IA32_TSS._ESI]\r | |
334 | add esp, 4 ; not for ebp\r | |
335 | add esp, 4 ; not for esp\r | |
336 | pop dword [ecx + IA32_TSS._EBX]\r | |
337 | pop dword [ecx + IA32_TSS._EDX]\r | |
338 | pop dword [ecx + IA32_TSS._ECX]\r | |
339 | pop dword [ecx + IA32_TSS._EAX]\r | |
340 | \r | |
341 | ; Set single step DB# to allow debugger to able to go back to the EIP\r | |
342 | ; where the exception is triggered.\r | |
343 | \r | |
344 | ;; Create return context for iretd in stub function\r | |
345 | mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer\r | |
346 | mov ebx, dword [ecx + IA32_TSS.EIP]\r | |
347 | mov [eax - 0xc], ebx ; create EIP in old stack\r | |
348 | movzx ebx, word [ecx + IA32_TSS._CS]\r | |
349 | mov [eax - 0x8], ebx ; create CS in old stack\r | |
350 | mov ebx, dword [ecx + IA32_TSS.EFLAGS]\r | |
16b918bb | 351 | bts ebx, 8 ; Set TF\r |
0ff5aa9c | 352 | mov [eax - 0x4], ebx ; create eflags in old stack\r |
0ff5aa9c JW |
353 | sub eax, 0xc ; minus 12 byte\r |
354 | mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer\r | |
355 | \r | |
356 | ;; Replace the EIP of interrupted task with stub function\r | |
357 | mov eax, ASM_PFX(SingleStepStubFunction)\r | |
358 | mov dword [ecx + IA32_TSS.EIP], eax\r | |
359 | \r | |
360 | mov ecx, [ebp - 8] ; Get current TSS base\r | |
361 | mov eax, dword [ecx + IA32_TSS._ESP] ; Return current stack top\r | |
362 | mov esp, ebp\r | |
363 | \r | |
364 | ret\r | |
365 | \r | |
366 | global ASM_PFX(SingleStepStubFunction)\r | |
367 | ASM_PFX(SingleStepStubFunction):\r | |
368 | ;\r | |
369 | ; we need clean TS bit in CR0 to execute\r | |
370 | ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.\r | |
371 | ;\r | |
372 | clts\r | |
373 | iretd\r | |
374 | \r | |
375 | global ASM_PFX(AsmGetTssTemplateMap)\r | |
376 | ASM_PFX(AsmGetTssTemplateMap):\r | |
377 | push ebp ; C prolog\r | |
378 | mov ebp, esp\r | |
379 | pushad\r | |
380 | \r | |
381 | mov ebx, dword [ebp + 0x8]\r | |
382 | mov dword [ebx], ASM_PFX(ExceptionTaskSwtichEntry0)\r | |
383 | mov dword [ebx + 0x4], (AsmExceptionEntryEnd - AsmExceptionEntryBegin) / 32\r | |
384 | mov dword [ebx + 0x8], 0\r | |
385 | \r | |
386 | popad\r | |
387 | pop ebp\r | |
388 | ret\r | |
389 | \r |