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