1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
3 ; This program and the accompanying materials
4 ; are licensed and made available under the terms and conditions of the BSD License
5 ; which accompanies this distribution. The full text of the license may be found at
6 ; http://opensource.org/licenses/bsd-license.php.
8 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 ; ExceptionTssEntryAsm.Asm
17 ; IA32 CPU Exception Handler with Separate Stack
21 ;------------------------------------------------------------------------------
24 ; IA32 TSS Memory Layout Description
68 ; CommonExceptionHandler()
70 extern ASM_PFX(CommonExceptionHandler)
79 ; Exception handler stub table
81 AsmExceptionEntryBegin:
87 ASM_PFX(ExceptionTaskSwtichEntry%[Vector]):
88 db 0x6a ; push #VectorNum
90 mov eax, ASM_PFX(CommonTaskSwtichEntryPoint)
92 mov esp, eax ; Restore stack top
95 %assign Vector Vector+1
100 ; Common part of exception handler
102 global ASM_PFX(CommonTaskSwtichEntryPoint)
103 ASM_PFX(CommonTaskSwtichEntryPoint):
106 ; +---------------------+ <-- EBP - 8
108 ; +---------------------+ <-- EBP - 4
110 ; +---------------------+ <-- EBP
112 ; +---------------------+ <-- EBP + 4
114 ; +---------------------+ <-- EBP + 8
116 ; +---------------------+
119 mov ebp, esp ; Stack frame
121 ; Use CPUID to determine if FXSAVE/FXRESTOR and DE are supported
126 ; Get TSS base of interrupted task through PreviousTaskLink field in
130 mov eax, [esp + 4] ; GDT base
136 mov ecx, [eax + ebx + 2]
138 mov cl, [eax + ebx + 7]
139 ror ecx, 8 ; ecx = Current TSS base
140 push ecx ; keep it in stack for later use
142 movzx ebx, word [ecx] ; Previous Task Link
143 mov ecx, [eax + ebx + 2]
145 mov cl, [eax + ebx + 7]
146 ror ecx, 8 ; ecx = Previous TSS base
149 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
155 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
156 push dword [ecx + IA32_TSS._EAX]
157 push dword [ecx + IA32_TSS._ECX]
158 push dword [ecx + IA32_TSS._EDX]
159 push dword [ecx + IA32_TSS._EBX]
160 push dword [ecx + IA32_TSS._ESP]
161 push dword [ecx + IA32_TSS._EBP]
162 push dword [ecx + IA32_TSS._ESI]
163 push dword [ecx + IA32_TSS._EDI]
165 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
166 movzx eax, word [ecx + IA32_TSS._SS]
168 movzx eax, word [ecx + IA32_TSS._CS]
170 movzx eax, word [ecx + IA32_TSS._DS]
172 movzx eax, word [ecx + IA32_TSS._ES]
174 movzx eax, word [ecx + IA32_TSS._FS]
176 movzx eax, word [ecx + IA32_TSS._GS]
180 push dword [ecx + IA32_TSS.EIP]
182 ;; UINT32 Gdtr[2], Idtr[2];
198 mov eax, ebx ; ebx still keeps selector of interrupted task
200 movzx eax, word [ecx + IA32_TSS.LDT]
204 push dword [ecx + IA32_TSS.EFLAGS]
206 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
208 push eax ; push cr4 firstly
210 mov edx, [ebp - 4] ; cpuid.edx
211 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
213 or eax, BIT9 ; Set CR4.OSFXSR
215 test edx, BIT2 ; Test for Debugging Extensions support
217 or eax, BIT3 ; Set CR4.DE
230 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
244 ;; FX_SAVE_STATE_IA32 FxSaveState;
245 ;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
246 ;; when executing fxsave/fxrstor instruction
247 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support.
248 ; edx still contains result from CPUID above
253 db 0xf, 0xae, 0x7 ;fxsave [edi]
256 ;; UINT32 ExceptionData;
259 ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
262 ;; call into exception handler
263 mov esi, ecx ; Keep TSS base to avoid overwrite
264 mov eax, ASM_PFX(CommonExceptionHandler)
266 ;; Prepare parameter and call
268 push edx ; EFI_SYSTEM_CONTEXT
269 push dword [ebp + 4] ; EFI_EXCEPTION_TYPE (vector number)
272 ; Call External Exception Handler
275 add esp, 8 ; Restore stack before calling
276 mov ecx, esi ; Restore TSS base
278 ;; UINT32 ExceptionData;
281 ;; FX_SAVE_STATE_IA32 FxSaveState;
282 mov edx, [ebp - 4] ; cpuid.edx
283 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
286 db 0xf, 0xae, 0xe ; fxrstor [esi]
290 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
291 ;; Skip restoration of DRx registers to support debuggers
292 ;; that set breakpoints in interrupt/exception context
295 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
298 add esp, 4 ; not for Cr1
302 mov dword [ecx + IA32_TSS._CR3], eax
307 pop dword [ecx + IA32_TSS.EFLAGS]
308 mov ebx, dword [ecx + IA32_TSS.EFLAGS]
309 btr ebx, 9 ; Do 'cli'
310 mov dword [ecx + IA32_TSS.EFLAGS], ebx
313 ;; UINT32 Gdtr[2], Idtr[2];
314 ;; Best not let anyone mess with these particular registers...
318 pop dword [ecx + IA32_TSS.EIP]
320 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
321 ;; NOTE - modified segment registers could hang the debugger... We
322 ;; could attempt to insulate ourselves against this possibility,
323 ;; but that poses risks as well.
326 o16 mov [ecx + IA32_TSS._GS], ax
328 o16 mov [ecx + IA32_TSS._FS], ax
330 o16 mov [ecx + IA32_TSS._ES], ax
332 o16 mov [ecx + IA32_TSS._DS], ax
334 o16 mov [ecx + IA32_TSS._CS], ax
336 o16 mov [ecx + IA32_TSS._SS], ax
338 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
339 pop dword [ecx + IA32_TSS._EDI]
340 pop dword [ecx + IA32_TSS._ESI]
341 add esp, 4 ; not for ebp
342 add esp, 4 ; not for esp
343 pop dword [ecx + IA32_TSS._EBX]
344 pop dword [ecx + IA32_TSS._EDX]
345 pop dword [ecx + IA32_TSS._ECX]
346 pop dword [ecx + IA32_TSS._EAX]
348 ; Set single step DB# to allow debugger to able to go back to the EIP
349 ; where the exception is triggered.
351 ;; Create return context for iretd in stub function
352 mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
353 mov ebx, dword [ecx + IA32_TSS.EIP]
354 mov [eax - 0xc], ebx ; create EIP in old stack
355 movzx ebx, word [ecx + IA32_TSS._CS]
356 mov [eax - 0x8], ebx ; create CS in old stack
357 mov ebx, dword [ecx + IA32_TSS.EFLAGS]
359 mov [eax - 0x4], ebx ; create eflags in old stack
360 sub eax, 0xc ; minus 12 byte
361 mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer
363 ;; Replace the EIP of interrupted task with stub function
364 mov eax, ASM_PFX(SingleStepStubFunction)
365 mov dword [ecx + IA32_TSS.EIP], eax
367 mov ecx, [ebp - 8] ; Get current TSS base
368 mov eax, dword [ecx + IA32_TSS._ESP] ; Return current stack top
373 global ASM_PFX(SingleStepStubFunction)
374 ASM_PFX(SingleStepStubFunction):
376 ; we need clean TS bit in CR0 to execute
377 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
382 global ASM_PFX(AsmGetTssTemplateMap)
383 ASM_PFX(AsmGetTssTemplateMap):
388 mov ebx, dword [ebp + 0x8]
389 mov dword [ebx], ASM_PFX(ExceptionTaskSwtichEntry0)
390 mov dword [ebx + 0x4], (AsmExceptionEntryEnd - AsmExceptionEntryBegin) / 32
391 mov dword [ebx + 0x8], 0