1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2017 - 2022, Intel Corporation. All rights reserved.<BR>
3 ; SPDX-License-Identifier: BSD-2-Clause-Patent
7 ; ExceptionTssEntryAsm.Asm
11 ; IA32 CPU Exception Handler with Separate Stack
15 ;------------------------------------------------------------------------------
18 ; IA32 TSS Memory Layout Description
62 ; CommonExceptionHandler()
64 extern ASM_PFX(CommonExceptionHandler)
73 ; Exception handler stub table
75 AsmExceptionEntryBegin:
81 ASM_PFX(ExceptionTaskSwtichEntry%[Vector]):
83 mov eax, ASM_PFX(CommonTaskSwtichEntryPoint)
85 mov esp, eax ; Restore stack top
88 %assign Vector Vector+1
93 ; Common part of exception handler
95 global ASM_PFX(CommonTaskSwtichEntryPoint)
96 ASM_PFX(CommonTaskSwtichEntryPoint):
99 ; +---------------------+ <-- EBP - 8
101 ; +---------------------+ <-- EBP - 4
103 ; +---------------------+ <-- EBP
105 ; +---------------------+ <-- EBP + 4
107 ; +---------------------+ <-- EBP + 8
109 ; +---------------------+
112 mov ebp, esp ; Stack frame
114 ; Use CPUID to determine if FXSAVE/FXRESTOR and DE are supported
119 ; Get TSS base of interrupted task through PreviousTaskLink field in
123 mov eax, [esp + 4] ; GDT base
129 mov ecx, [eax + ebx + 2]
131 mov cl, [eax + ebx + 7]
132 ror ecx, 8 ; ecx = Current TSS base
133 push ecx ; keep it in stack for later use
135 movzx ebx, word [ecx] ; Previous Task Link
136 mov ecx, [eax + ebx + 2]
138 mov cl, [eax + ebx + 7]
139 ror ecx, 8 ; ecx = Previous TSS base
142 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
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]
158 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
159 movzx eax, word [ecx + IA32_TSS._SS]
161 movzx eax, word [ecx + IA32_TSS._CS]
163 movzx eax, word [ecx + IA32_TSS._DS]
165 movzx eax, word [ecx + IA32_TSS._ES]
167 movzx eax, word [ecx + IA32_TSS._FS]
169 movzx eax, word [ecx + IA32_TSS._GS]
173 push dword [ecx + IA32_TSS.EIP]
175 ;; UINT32 Gdtr[2], Idtr[2];
191 mov eax, ebx ; ebx still keeps selector of interrupted task
193 movzx eax, word [ecx + IA32_TSS.LDT]
197 push dword [ecx + IA32_TSS.EFLAGS]
199 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
201 push eax ; push cr4 firstly
203 mov edx, [ebp - 4] ; cpuid.edx
204 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
206 or eax, BIT9 ; Set CR4.OSFXSR
208 test edx, BIT2 ; Test for Debugging Extensions support
210 or eax, BIT3 ; Set CR4.DE
223 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
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
249 ;; UINT32 ExceptionData;
252 ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
255 ;; call into exception handler
256 mov esi, ecx ; Keep TSS base to avoid overwrite
257 mov eax, ASM_PFX(CommonExceptionHandler)
259 ;; Prepare parameter and call
261 push edx ; EFI_SYSTEM_CONTEXT
262 push dword [ebp + 4] ; EFI_EXCEPTION_TYPE (vector number)
265 ; Call External Exception Handler
268 add esp, 8 ; Restore stack before calling
269 mov ecx, esi ; Restore TSS base
271 ;; UINT32 ExceptionData;
274 ;; FX_SAVE_STATE_IA32 FxSaveState;
275 mov edx, [ebp - 4] ; cpuid.edx
276 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
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
288 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
291 add esp, 4 ; not for Cr1
295 mov dword [ecx + IA32_TSS._CR3], eax
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
306 ;; UINT32 Gdtr[2], Idtr[2];
307 ;; Best not let anyone mess with these particular registers...
311 pop dword [ecx + IA32_TSS.EIP]
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.
319 o16 mov [ecx + IA32_TSS._GS], ax
321 o16 mov [ecx + IA32_TSS._FS], ax
323 o16 mov [ecx + IA32_TSS._ES], ax
325 o16 mov [ecx + IA32_TSS._DS], ax
327 o16 mov [ecx + IA32_TSS._CS], ax
329 o16 mov [ecx + IA32_TSS._SS], ax
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]
341 ; Set single step DB# to allow debugger to able to go back to the EIP
342 ; where the exception is triggered.
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]
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
356 ;; Replace the EIP of interrupted task with stub function
357 mov eax, ASM_PFX(SingleStepStubFunction)
358 mov dword [ecx + IA32_TSS.EIP], eax
360 mov ecx, [ebp - 8] ; Get current TSS base
361 mov eax, dword [ecx + IA32_TSS._ESP] ; Return current stack top
366 global ASM_PFX(SingleStepStubFunction)
367 ASM_PFX(SingleStepStubFunction):
369 ; we need clean TS bit in CR0 to execute
370 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
375 global ASM_PFX(AsmGetTssTemplateMap)
376 ASM_PFX(AsmGetTssTemplateMap):
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