1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2016, 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 ; ExceptionHandlerAsm.Asm
17 ; IA32 CPU Exception Handler
21 ;------------------------------------------------------------------------------
24 ; CommonExceptionHandler()
26 extern ASM_PFX(CommonExceptionHandler)
30 extern ASM_PFX(mErrorCodeFlag) ; Error code flags for exceptions
31 extern ASM_PFX(mDoFarReturnFlag) ; Do far return flag
38 ; exception handler stub table
42 db 0x6a ; push #VectorNum
43 db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
45 mov eax, ASM_PFX(CommonInterruptEntry)
53 db 0 ; 0 will be fixed
55 mov eax, HookAfterStubHeaderEnd
57 HookAfterStubHeaderEnd:
59 sub esp, 8 ; reserve room for filling exception data later
61 xchg ecx, [esp] ; get vector number
62 bt [ASM_PFX(mErrorCodeFlag)], ecx
64 push dword [esp] ; addition push if exception data needed
66 xchg ecx, [esp] ; restore ecx
69 ;----------------------------------------------------------------------------;
70 ; CommonInterruptEntry ;
71 ;----------------------------------------------------------------------------;
72 ; The follow algorithm is used for the common interrupt routine.
73 ; Entry from each interrupt with a push eax and eax=interrupt number
75 ; +---------------------+
77 ; +---------------------+
79 ; +---------------------+
81 ; +---------------------+
83 ; +---------------------+
85 ; +---------------------+
87 ; +---------------------+ <-- EBP
88 global ASM_PFX(CommonInterruptEntry)
89 ASM_PFX(CommonInterruptEntry):
93 ; All interrupt handlers are invoked through interrupt gates, so
94 ; IF flag automatically cleared at the entry point
98 ; Get vector number from top of stack
101 and ecx, 0xFF ; Vector number should be less than 256
102 cmp ecx, 32 ; Intel reserved vector for exceptions?
104 bt [ASM_PFX(mErrorCodeFlag)], ecx
111 ; +---------------------+
113 ; +---------------------+
115 ; +---------------------+
117 ; +---------------------+
119 ; +---------------------+ <-- ESP
122 ; ECX - Vector Number
126 ; Put Vector Number on stack
131 ; Put 0 (dummy) error code on stack, and restore ECX
133 xor ecx, ecx ; ECX = 0
136 jmp ErrorCodeAndVectorOnStack
142 ; +---------------------+
144 ; +---------------------+
146 ; +---------------------+
148 ; +---------------------+
150 ; +---------------------+
152 ; +---------------------+ <-- ESP
155 ; ECX - Vector Number
159 ; Put Vector Number on stack and restore ECX
163 ErrorCodeAndVectorOnStack:
169 ; +---------------------+
171 ; +---------------------+
173 ; +---------------------+
175 ; +---------------------+
177 ; +---------------------+
179 ; +---------------------+
181 ; +---------------------+ <-- EBP
185 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
192 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
193 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
195 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
200 lea ecx, [ebp + 6 * 4]
202 push dword [ebp] ; EBP
206 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
209 movzx eax, word [ebp + 4 * 4]
221 mov eax, [ebp + 3 * 4]
224 ;; UINT32 Gdtr[2], Idtr[2];
247 mov eax, [ebp + 5 * 4]
250 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
252 push ebx ; temporarily save value of ebx on stack
253 cpuid ; use CPUID to determine if FXSAVE/FXRESTOR and DE
255 pop ebx ; retore value of ebx that was overwritten by CPUID
257 push eax ; push cr4 firstly
258 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
260 or eax, BIT9 ; Set CR4.OSFXSR
262 test edx, BIT2 ; Test for Debugging Extensions support
264 or eax, BIT3 ; Set CR4.DE
276 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
290 ;; FX_SAVE_STATE_IA32 FxSaveState;
293 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support.
294 ; edx still contains result from CPUID above
296 db 0xf, 0xae, 0x7 ;fxsave [edi]
299 ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
302 ;; UINT32 ExceptionData;
303 push dword [ebp + 2 * 4]
305 ;; Prepare parameter and call
308 mov edx, dword [ebp + 1 * 4]
312 ; Call External Exception Handler
314 mov eax, ASM_PFX(CommonExceptionHandler)
319 ;; UINT32 ExceptionData;
322 ;; FX_SAVE_STATE_IA32 FxSaveState;
325 cpuid ; use CPUID to determine if FXSAVE/FXRESTOR
327 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
329 db 0xf, 0xae, 0xe ; fxrstor [esi]
333 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
334 ;; Skip restoration of DRx registers to support in-circuit emualators
335 ;; or debuggers set breakpoint in interrupt/exception context
338 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
341 add esp, 4 ; not for Cr1
350 pop dword [ebp + 5 * 4]
353 ;; UINT32 Gdtr[2], Idtr[2];
354 ;; Best not let anyone mess with these particular registers...
358 pop dword [ebp + 3 * 4]
360 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
361 ;; NOTE - modified segment registers could hang the debugger... We
362 ;; could attempt to insulate ourselves against this possibility,
363 ;; but that poses risks as well.
369 pop dword [ebp + 4 * 4]
372 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
375 add esp, 4 ; not for ebp
376 add esp, 4 ; not for esp
387 ; Enable TF bit after page fault handler runs
388 cmp dword [esp], 14 ; #PF?
390 bts dword [esp + 16], 8 ; EFLAGS
394 cmp dword [esp - 16], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
396 cmp dword [esp - 20], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
404 cmp dword [ASM_PFX(mDoFarReturnFlag)], 0 ; Check if need to do far return instead of IRET
406 push dword [esp + 8] ; save EFLAGS
408 push dword [esp - 8] ; save CS in new location
409 push dword [esp - 8] ; save EIP in new location
410 push dword [esp - 8] ; save EFLAGS in new location
411 popfd ; restore EFLAGS
417 ;---------------------------------------;
418 ; _AsmGetTemplateAddressMap ;
419 ;----------------------------------------------------------------------------;
422 ; AsmGetTemplateAddressMap (
423 ; EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
426 ; Routine Description:
428 ; Return address map of interrupt handler template so that C code can generate
439 ; Input: [ebp][0] = Original ebp
440 ; [ebp][4] = Return address
445 ;-----------------------------------------------------------------------------;
446 global ASM_PFX(AsmGetTemplateAddressMap)
447 ASM_PFX(AsmGetTemplateAddressMap):
452 mov ebx, dword [ebp + 0x8]
453 mov dword [ebx], AsmIdtVectorBegin
454 mov dword [ebx + 0x4], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
455 mov dword [ebx + 0x8], HookAfterStubBegin
461 ;-------------------------------------------------------------------------------------
462 ; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
463 ;-------------------------------------------------------------------------------------
464 global ASM_PFX(AsmVectorNumFixup)
465 ASM_PFX(AsmVectorNumFixup):
466 mov eax, dword [esp + 8]
468 mov [ecx + (VectorNum - HookAfterStubBegin)], al