]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / Ia32 / ExceptionTssEntryAsm.nasm
CommitLineData
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
20struc 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
59endstruc\r
60\r
61;\r
62; CommonExceptionHandler()\r
63;\r
64extern ASM_PFX(CommonExceptionHandler)\r
65\r
66SECTION .data\r
67\r
68SECTION .text\r
69\r
70ALIGN 8\r
71\r
72;\r
73; Exception handler stub table\r
74;\r
75AsmExceptionEntryBegin:\r
76%assign Vector 0\r
77%rep 32\r
78\r
79DoIret%[Vector]:\r
80 iretd\r
81ASM_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
90AsmExceptionEntryEnd:\r
91\r
92;\r
93; Common part of exception handler\r
94;\r
95global ASM_PFX(CommonTaskSwtichEntryPoint)\r
96ASM_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
319o16 mov [ecx + IA32_TSS._GS], ax\r
320 pop eax\r
321o16 mov [ecx + IA32_TSS._FS], ax\r
322 pop eax\r
323o16 mov [ecx + IA32_TSS._ES], ax\r
324 pop eax\r
325o16 mov [ecx + IA32_TSS._DS], ax\r
326 pop eax\r
327o16 mov [ecx + IA32_TSS._CS], ax\r
328 pop eax\r
329o16 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
366global ASM_PFX(SingleStepStubFunction)\r
367ASM_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
375global ASM_PFX(AsmGetTssTemplateMap)\r
376ASM_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