1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2017, 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]):
82 db 0x6a ; push #VectorNum
84 mov eax, ASM_PFX(CommonTaskSwtichEntryPoint)
86 mov esp, eax ; Restore stack top
89 %assign Vector Vector+1
94 ; Common part of exception handler
96 global ASM_PFX(CommonTaskSwtichEntryPoint)
97 ASM_PFX(CommonTaskSwtichEntryPoint):
100 ; +---------------------+ <-- EBP - 8
102 ; +---------------------+ <-- EBP - 4
104 ; +---------------------+ <-- EBP
106 ; +---------------------+ <-- EBP + 4
108 ; +---------------------+ <-- EBP + 8
110 ; +---------------------+
113 mov ebp, esp ; Stack frame
115 ; Use CPUID to determine if FXSAVE/FXRESTOR and DE are supported
120 ; Get TSS base of interrupted task through PreviousTaskLink field in
124 mov eax, [esp + 4] ; GDT base
130 mov ecx, [eax + ebx + 2]
132 mov cl, [eax + ebx + 7]
133 ror ecx, 8 ; ecx = Current TSS base
134 push ecx ; keep it in stack for later use
136 movzx ebx, word [ecx] ; Previous Task Link
137 mov ecx, [eax + ebx + 2]
139 mov cl, [eax + ebx + 7]
140 ror ecx, 8 ; ecx = Previous TSS base
143 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
149 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
150 push dword [ecx + IA32_TSS._EAX]
151 push dword [ecx + IA32_TSS._ECX]
152 push dword [ecx + IA32_TSS._EDX]
153 push dword [ecx + IA32_TSS._EBX]
154 push dword [ecx + IA32_TSS._ESP]
155 push dword [ecx + IA32_TSS._EBP]
156 push dword [ecx + IA32_TSS._ESI]
157 push dword [ecx + IA32_TSS._EDI]
159 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
160 movzx eax, word [ecx + IA32_TSS._SS]
162 movzx eax, word [ecx + IA32_TSS._CS]
164 movzx eax, word [ecx + IA32_TSS._DS]
166 movzx eax, word [ecx + IA32_TSS._ES]
168 movzx eax, word [ecx + IA32_TSS._FS]
170 movzx eax, word [ecx + IA32_TSS._GS]
174 push dword [ecx + IA32_TSS.EIP]
176 ;; UINT32 Gdtr[2], Idtr[2];
192 mov eax, ebx ; ebx still keeps selector of interrupted task
194 movzx eax, word [ecx + IA32_TSS.LDT]
198 push dword [ecx + IA32_TSS.EFLAGS]
200 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
202 push eax ; push cr4 firstly
204 mov edx, [ebp - 4] ; cpuid.edx
205 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
207 or eax, BIT9 ; Set CR4.OSFXSR
209 test edx, BIT2 ; Test for Debugging Extensions support
211 or eax, BIT3 ; Set CR4.DE
224 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
238 ;; FX_SAVE_STATE_IA32 FxSaveState;
239 ;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
240 ;; when executing fxsave/fxrstor instruction
241 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support.
242 ; edx still contains result from CPUID above
247 db 0xf, 0xae, 0x7 ;fxsave [edi]
250 ;; UINT32 ExceptionData;
253 ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
256 ;; call into exception handler
257 mov esi, ecx ; Keep TSS base to avoid overwrite
258 mov eax, ASM_PFX(CommonExceptionHandler)
260 ;; Prepare parameter and call
262 push edx ; EFI_SYSTEM_CONTEXT
263 push dword [ebp + 4] ; EFI_EXCEPTION_TYPE (vector number)
266 ; Call External Exception Handler
269 add esp, 8 ; Restore stack before calling
270 mov ecx, esi ; Restore TSS base
272 ;; UINT32 ExceptionData;
275 ;; FX_SAVE_STATE_IA32 FxSaveState;
276 mov edx, [ebp - 4] ; cpuid.edx
277 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
280 db 0xf, 0xae, 0xe ; fxrstor [esi]
284 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
285 ;; Skip restoration of DRx registers to support debuggers
286 ;; that set breakpoints in interrupt/exception context
289 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
292 add esp, 4 ; not for Cr1
296 mov dword [ecx + IA32_TSS._CR3], eax
301 pop dword [ecx + IA32_TSS.EFLAGS]
302 mov ebx, dword [ecx + IA32_TSS.EFLAGS]
303 btr ebx, 9 ; Do 'cli'
304 mov dword [ecx + IA32_TSS.EFLAGS], ebx
307 ;; UINT32 Gdtr[2], Idtr[2];
308 ;; Best not let anyone mess with these particular registers...
312 pop dword [ecx + IA32_TSS.EIP]
314 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
315 ;; NOTE - modified segment registers could hang the debugger... We
316 ;; could attempt to insulate ourselves against this possibility,
317 ;; but that poses risks as well.
320 o16 mov [ecx + IA32_TSS._GS], ax
322 o16 mov [ecx + IA32_TSS._FS], ax
324 o16 mov [ecx + IA32_TSS._ES], ax
326 o16 mov [ecx + IA32_TSS._DS], ax
328 o16 mov [ecx + IA32_TSS._CS], ax
330 o16 mov [ecx + IA32_TSS._SS], ax
332 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
333 pop dword [ecx + IA32_TSS._EDI]
334 pop dword [ecx + IA32_TSS._ESI]
335 add esp, 4 ; not for ebp
336 add esp, 4 ; not for esp
337 pop dword [ecx + IA32_TSS._EBX]
338 pop dword [ecx + IA32_TSS._EDX]
339 pop dword [ecx + IA32_TSS._ECX]
340 pop dword [ecx + IA32_TSS._EAX]
342 ; Set single step DB# to allow debugger to able to go back to the EIP
343 ; where the exception is triggered.
345 ;; Create return context for iretd in stub function
346 mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
347 mov ebx, dword [ecx + IA32_TSS.EIP]
348 mov [eax - 0xc], ebx ; create EIP in old stack
349 movzx ebx, word [ecx + IA32_TSS._CS]
350 mov [eax - 0x8], ebx ; create CS in old stack
351 mov ebx, dword [ecx + IA32_TSS.EFLAGS]
353 mov [eax - 0x4], ebx ; create eflags in old stack
354 sub eax, 0xc ; minus 12 byte
355 mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer
357 ;; Replace the EIP of interrupted task with stub function
358 mov eax, ASM_PFX(SingleStepStubFunction)
359 mov dword [ecx + IA32_TSS.EIP], eax
361 mov ecx, [ebp - 8] ; Get current TSS base
362 mov eax, dword [ecx + IA32_TSS._ESP] ; Return current stack top
367 global ASM_PFX(SingleStepStubFunction)
368 ASM_PFX(SingleStepStubFunction):
370 ; we need clean TS bit in CR0 to execute
371 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
376 global ASM_PFX(AsmGetTssTemplateMap)
377 ASM_PFX(AsmGetTssTemplateMap):
382 mov ebx, dword [ebp + 0x8]
383 mov dword [ebx], ASM_PFX(ExceptionTaskSwtichEntry0)
384 mov dword [ebx + 0x4], (AsmExceptionEntryEnd - AsmExceptionEntryBegin) / 32
385 mov dword [ebx + 0x8], 0