1 #------------------------------------------------------------------------------
3 #* Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
4 #* This program and the accompanying materials
5 #* are licensed and made available under the terms and conditions of the BSD License
6 #* which accompanies this distribution. The full text of the license may be found at
7 #* http://opensource.org/licenses/bsd-license.php
9 #* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 #* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 #* ExceptionHandlerAsm.S
16 #* IA32 CPU Exception Handler
18 #------------------------------------------------------------------------------
24 ASM_GLOBAL ASM_PFX(CommonExceptionHandler)
25 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
26 ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
28 #EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions
29 #EXTRN ASM_PFX(mDoFarReturnFlag):DWORD # Do far return flag
34 # exception handler stub table
37 .byte 0x6a # push #VectorNum
41 .long ASM_PFX(CommonInterruptEntry)
44 .byte 0x6a # push #VectorNum
48 .long ASM_PFX(CommonInterruptEntry)
51 .byte 0x6a # push #VectorNum
55 .long ASM_PFX(CommonInterruptEntry)
58 .byte 0x6a # push #VectorNum
62 .long ASM_PFX(CommonInterruptEntry)
65 .byte 0x6a # push #VectorNum
69 .long ASM_PFX(CommonInterruptEntry)
72 .byte 0x6a # push #VectorNum
76 .long ASM_PFX(CommonInterruptEntry)
79 .byte 0x6a # push #VectorNum
83 .long ASM_PFX(CommonInterruptEntry)
86 .byte 0x6a # push #VectorNum
90 .long ASM_PFX(CommonInterruptEntry)
93 .byte 0x6a # push #VectorNum
97 .long ASM_PFX(CommonInterruptEntry)
100 .byte 0x6a # push #VectorNum
104 .long ASM_PFX(CommonInterruptEntry)
107 .byte 0x6a # push #VectorNum
111 .long ASM_PFX(CommonInterruptEntry)
114 .byte 0x6a # push #VectorNum
118 .long ASM_PFX(CommonInterruptEntry)
121 .byte 0x6a # push #VectorNum
125 .long ASM_PFX(CommonInterruptEntry)
128 .byte 0x6a # push #VectorNum
132 .long ASM_PFX(CommonInterruptEntry)
135 .byte 0x6a # push #VectorNum
139 .long ASM_PFX(CommonInterruptEntry)
142 .byte 0x6a # push #VectorNum
146 .long ASM_PFX(CommonInterruptEntry)
149 .byte 0x6a # push #VectorNum
153 .long ASM_PFX(CommonInterruptEntry)
156 .byte 0x6a # push #VectorNum
160 .long ASM_PFX(CommonInterruptEntry)
163 .byte 0x6a # push #VectorNum
167 .long ASM_PFX(CommonInterruptEntry)
170 .byte 0x6a # push #VectorNum
174 .long ASM_PFX(CommonInterruptEntry)
177 .byte 0x6a # push #VectorNum
181 .long ASM_PFX(CommonInterruptEntry)
184 .byte 0x6a # push #VectorNum
188 .long ASM_PFX(CommonInterruptEntry)
191 .byte 0x6a # push #VectorNum
195 .long ASM_PFX(CommonInterruptEntry)
198 .byte 0x6a # push #VectorNum
202 .long ASM_PFX(CommonInterruptEntry)
205 .byte 0x6a # push #VectorNum
209 .long ASM_PFX(CommonInterruptEntry)
212 .byte 0x6a # push #VectorNum
216 .long ASM_PFX(CommonInterruptEntry)
219 .byte 0x6a # push #VectorNum
223 .long ASM_PFX(CommonInterruptEntry)
226 .byte 0x6a # push #VectorNum
230 .long ASM_PFX(CommonInterruptEntry)
233 .byte 0x6a # push #VectorNum
237 .long ASM_PFX(CommonInterruptEntry)
240 .byte 0x6a # push #VectorNum
244 .long ASM_PFX(CommonInterruptEntry)
247 .byte 0x6a # push #VectorNum
251 .long ASM_PFX(CommonInterruptEntry)
254 .byte 0x6a # push #VectorNum
258 .long ASM_PFX(CommonInterruptEntry)
264 .byte 0 # 0 will be fixed
266 .byte 0xB8 # movl ASM_PFX(HookAfterStubHeaderEnd), %eax
267 .long ASM_PFX(HookAfterStubHeaderEnd)
269 ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
270 ASM_PFX(HookAfterStubHeaderEnd):
272 subl $8, %esp # reserve room for filling exception data later
274 xchgl (%esp), %ecx # get vector number
275 bt %ecx, ASM_PFX(mErrorCodeFlag)
277 pushl (%esp) # addition push if exception data needed
279 xchg (%esp), %ecx # restore ecx
282 #---------------------------------------;
283 # CommonInterruptEntry ;
284 #---------------------------------------;
285 # The follow algorithm is used for the common interrupt routine.
287 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
288 ASM_PFX(CommonInterruptEntry):
292 # All interrupt handlers are invoked through interrupt gates, so
293 # IF flag automatically cleared at the entry point
297 # Get vector number from top of stack
300 andl $0x0FF, %ecx # Vector number should be less than 256
301 cmpl $32, %ecx # Intel reserved vector for exceptions?
303 bt %ecx, ASM_PFX(mErrorCodeFlag)
310 # +---------------------+
312 # +---------------------+
314 # +---------------------+
316 # +---------------------+
318 # +---------------------+ <-- ESP
321 # ECX - Vector Number
325 # Put Vector Number on stack
330 # Put 0 (dummy) error code on stack, and restore ECX
332 xorl %ecx, %ecx # ECX = 0
335 jmp ErrorCodeAndVectorOnStack
341 # +---------------------+
343 # +---------------------+
345 # +---------------------+
347 # +---------------------+
349 # +---------------------+
351 # +---------------------+ <-- ESP
354 # ECX - Vector Number
358 # Put Vector Number on stack and restore ECX
362 ErrorCodeAndVectorOnStack:
368 # +---------------------+
370 # +---------------------+
372 # +---------------------+
374 # +---------------------+
376 # +---------------------+
378 # +---------------------+
380 # +---------------------+ <-- EBP
384 # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
387 andl $0x0fffffff0, %esp
391 pushl $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
392 pushl $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
394 #; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
405 #; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
408 movzwl 16(%ebp), %eax
423 #; UINT32 Gdtr[2], Idtr[2];
449 #; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
450 ## insure FXSAVE/FXRSTOR is enabled in CR4...
451 ## ... while we're at it, make sure DE is also enabled...
453 pushl %ebx # temporarily save value of ebx on stack
454 cpuid # use CPUID to determine if FXSAVE/FXRESTOR
455 # and DE are supported
456 popl %ebx # retore value of ebx that was overwritten
459 pushl %eax # push cr4 firstly
460 testl $BIT24, %edx # Test for FXSAVE/FXRESTOR support
462 orl $BIT9, %eax # Set CR4.OSFXSR
464 testl $BIT2, %edx # Test for Debugging Extensions support
466 orl $BIT3, %eax # Set CR4.DE
478 #; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
492 #; FX_SAVE_STATE_IA32 FxSaveState;
495 testl $BIT24, %edx # Test for FXSAVE/FXRESTOR support.
496 # edx still contains result from CPUID above
498 .byte 0x0f, 0x0ae, 0x07 #fxsave [edi]
501 #; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
504 #; UINT32 ExceptionData;
507 #; Prepare parameter and call
514 # Call External Exception Handler
516 call ASM_PFX(CommonExceptionHandler)
520 #; UINT32 ExceptionData;
523 #; FX_SAVE_STATE_IA32 FxSaveState;
526 cpuid # use CPUID to determine if FXSAVE/FXRESTOR
528 testl $BIT24, %edx # Test for FXSAVE/FXRESTOR support
530 .byte 0x0f, 0x0ae, 0x0e # fxrstor [esi]
534 #; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
535 #; Skip restoration of DRx registers to support in-circuit emualators
536 #; or debuggers set breakpoint in interrupt/exception context
539 #; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
542 addl $4, %esp # not for Cr1
554 #; UINT32 Gdtr[2], Idtr[2];
555 #; Best not let anyone mess with these particular registers...
561 #; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
562 #; NOTE - modified segment registers could hang the debugger... We
563 #; could attempt to insulate ourselves against this possibility,
564 #; but that poses risks as well.
573 #; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
576 addl $4, %esp # not for ebp
577 addl $4, %esp # not for esp
588 cmpl $0, -16(%esp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
590 cmpl $1, -20(%esp) # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
598 cmpl $0, ASM_PFX(mDoFarReturnFlag)
600 pushl 8(%esp) # save EFLAGS
602 pushl -8(%esp) # save CS in new location
603 pushl -8(%esp) # save EIP in new location
604 pushl -8(%esp) # save EFLAGS in new location
605 popfl # restore EFLAGS
612 #---------------------------------------;
613 # _AsmGetTemplateAddressMap ;
614 #---------------------------------------;
617 # AsmGetTemplateAddressMap (
618 # EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
621 # Routine Description:
623 # Return address map of interrupt handler template so that C code can generate
634 # Input: [ebp][0] = Original ebp
635 # [ebp][4] = Return address
640 #-----------------------------------------------------------------------------;
641 #-------------------------------------------------------------------------------------
642 # AsmGetAddressMap (&AddressMap);
643 #-------------------------------------------------------------------------------------
644 ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap)
645 ASM_PFX(AsmGetTemplateAddressMap):
652 movl $Exception0Handle, (%ebx)
653 movl $(Exception1Handle - Exception0Handle), 0x4(%ebx)
654 movl $(HookAfterStubBegin), 0x8(%ebx)
659 #-------------------------------------------------------------------------------------
660 # AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
661 #-------------------------------------------------------------------------------------
662 ASM_GLOBAL ASM_PFX(AsmVectorNumFixup)
663 ASM_PFX(AsmVectorNumFixup):
666 movb %al, (VectorNum - HookAfterStubBegin)(%ecx)