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