1 #------------------------------------------------------------------------------ ;
2 # Copyright (c) 2012 - 2013, 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.S
17 # x64 CPU Exception Handler
21 #------------------------------------------------------------------------------
25 ASM_GLOBAL ASM_PFX(CommonExceptionHandler)
26 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
27 ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
29 #EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions
30 #EXTRN ASM_PFX(mDoFarReturnFlag):QWORD # Do far return flag
34 # exception handler stub table
37 .byte 0x6a # push #VectorNum
41 .quad ASM_PFX(CommonInterruptEntry)
44 .byte 0x6a # push #VectorNum
48 .quad ASM_PFX(CommonInterruptEntry)
51 .byte 0x6a # push #VectorNum
55 .quad ASM_PFX(CommonInterruptEntry)
58 .byte 0x6a # push #VectorNum
62 .quad ASM_PFX(CommonInterruptEntry)
65 .byte 0x6a # push #VectorNum
69 .quad ASM_PFX(CommonInterruptEntry)
72 .byte 0x6a # push #VectorNum
76 .quad ASM_PFX(CommonInterruptEntry)
79 .byte 0x6a # push #VectorNum
83 .quad ASM_PFX(CommonInterruptEntry)
86 .byte 0x6a # push #VectorNum
90 .quad ASM_PFX(CommonInterruptEntry)
93 .byte 0x6a # push #VectorNum
97 .quad ASM_PFX(CommonInterruptEntry)
100 .byte 0x6a # push #VectorNum
104 .quad ASM_PFX(CommonInterruptEntry)
107 .byte 0x6a # push #VectorNum
111 .quad ASM_PFX(CommonInterruptEntry)
114 .byte 0x6a # push #VectorNum
118 .quad ASM_PFX(CommonInterruptEntry)
121 .byte 0x6a # push #VectorNum
125 .quad ASM_PFX(CommonInterruptEntry)
128 .byte 0x6a # push #VectorNum
132 .quad ASM_PFX(CommonInterruptEntry)
135 .byte 0x6a # push #VectorNum
139 .quad ASM_PFX(CommonInterruptEntry)
142 .byte 0x6a # push #VectorNum
146 .quad ASM_PFX(CommonInterruptEntry)
149 .byte 0x6a # push #VectorNum
153 .quad ASM_PFX(CommonInterruptEntry)
156 .byte 0x6a # push #VectorNum
160 .quad ASM_PFX(CommonInterruptEntry)
163 .byte 0x6a # push #VectorNum
167 .quad ASM_PFX(CommonInterruptEntry)
170 .byte 0x6a # push #VectorNum
174 .quad ASM_PFX(CommonInterruptEntry)
177 .byte 0x6a # push #VectorNum
181 .quad ASM_PFX(CommonInterruptEntry)
184 .byte 0x6a # push #VectorNum
188 .quad ASM_PFX(CommonInterruptEntry)
191 .byte 0x6a # push #VectorNum
195 .quad ASM_PFX(CommonInterruptEntry)
198 .byte 0x6a # push #VectorNum
202 .quad ASM_PFX(CommonInterruptEntry)
205 .byte 0x6a # push #VectorNum
209 .quad ASM_PFX(CommonInterruptEntry)
212 .byte 0x6a # push #VectorNum
216 .quad ASM_PFX(CommonInterruptEntry)
219 .byte 0x6a # push #VectorNum
223 .quad ASM_PFX(CommonInterruptEntry)
226 .byte 0x6a # push #VectorNum
230 .quad ASM_PFX(CommonInterruptEntry)
233 .byte 0x6a # push #VectorNum
237 .quad ASM_PFX(CommonInterruptEntry)
240 .byte 0x6a # push #VectorNum
244 .quad ASM_PFX(CommonInterruptEntry)
247 .byte 0x6a # push #VectorNum
251 .quad ASM_PFX(CommonInterruptEntry)
254 .byte 0x6a # push #VectorNum
258 .quad ASM_PFX(CommonInterruptEntry)
261 HookAfterStubHeaderBegin:
264 .byte 0 # 0 will be fixed
266 .byte 0x48, 0xB8 # movq ASM_PFX(HookAfterStubHeaderEnd), %rax
267 .quad ASM_PFX(HookAfterStubHeaderEnd)
269 ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
270 ASM_PFX(HookAfterStubHeaderEnd):
273 andl $0x0fffffff0, %esp
276 bt %ecx, ASM_PFX(mErrorCodeFlag)
278 pushq (%rsp) # push additional rcx to make stack alignment
280 xchgq (%rsp), %rcx # restore rcx, save Exception Number in stack
281 pushq (%rax) # push rax into stack to keep code consistence
283 #---------------------------------------;
284 # CommonInterruptEntry ;
285 #---------------------------------------;
286 # The follow algorithm is used for the common interrupt routine.
288 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
289 ASM_PFX(CommonInterruptEntry):
293 # All interrupt handlers are invoked through interrupt gates, so
294 # IF flag automatically cleared at the entry point
297 # Calculate vector number
299 xchgq (%rsp), %rcx # get the return address of call, actually, it is the address of vector number.
301 cmp $32, %ecx # Intel reserved vector for exceptions?
304 leaq ASM_PFX(mErrorCodeFlag)(%rip), %rax
307 jc CommonInterruptEntry_al_0000
312 # Push a dummy error code on the stack
313 # to maintain coherent stack map
317 CommonInterruptEntry_al_0000:
320 pushq $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
321 pushq $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
325 # +---------------------+ <-- 16-byte aligned ensured by processor
327 # +---------------------+
329 # +---------------------+
331 # +---------------------+
333 # +---------------------+
335 # +---------------------+
337 # +---------------------+
338 # + RCX / Vector Number +
339 # +---------------------+
341 # +---------------------+ <-- RBP, 16-byte aligned
346 # Since here the stack pointer is 16-byte aligned, so
347 # EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
351 #; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
352 #; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
370 #; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
371 movzwq 56(%rbp), %rax
373 movzwq 32(%rbp), %rax
384 movq %rcx, 8(%rbp) # save vector number
389 #; UINT64 Gdtr[2], Idtr[2];
416 #; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
432 #; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
446 #; FX_SAVE_STATE_X64 FxSaveState;
449 .byte 0x0f, 0x0ae, 0x07 #fxsave [rdi]
451 #; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
454 #; UINT32 ExceptionData;
457 #; Prepare parameter and call
461 # Per X64 calling convention, allocate maximum parameter stack space
462 # and make sure RSP is 16-byte aligned
465 call ASM_PFX(CommonExceptionHandler)
469 #; UINT64 ExceptionData;
472 #; FX_SAVE_STATE_X64 FxSaveState;
475 .byte 0x0f, 0x0ae, 0x0E # fxrstor [rsi]
478 #; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
479 #; Skip restoration of DRx registers to support in-circuit emualators
480 #; or debuggers set breakpoint in interrupt/exception context
483 #; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
486 addq $8, %rsp # not for Cr1
500 #; UINT64 Gdtr[2], Idtr[2];
501 #; Best not let anyone mess with these particular registers...
507 #; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
509 # mov %rax, %gs ; not for gs
511 # mov %rax, %fs ; not for fs
512 # (X64 will not use fs and gs, so we do not restore it)
517 popq 32(%rbp) # for cs
518 popq 56(%rbp) # for ss
520 #; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
521 #; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
524 addq $8, %rsp # not for rbp
525 popq 48(%rbp) # for rsp
542 cmpq $0, -32(%rsp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
543 jz DoReturn # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
552 cmpq $0, ASM_PFX(mDoFarReturnFlag) # Check if need to do far return instead of IRET
555 movq %rsp, %rax # save old RSP to rax
556 movq 0x20(%rsp), %rsp
557 pushq 0x10(%rax) # save CS in new location
558 pushq 0x8(%rax) # save EIP in new location
559 pushq 0x18(%rax) # save EFLAGS in new location
560 movq (%rax), %rax # restore rax
561 popfq # restore EFLAGS
562 .byte 0x48 # prefix to composite "retq" with next "retf"
568 #-------------------------------------------------------------------------------------
569 # AsmGetTemplateAddressMap (&AddressMap);
570 #-------------------------------------------------------------------------------------
571 # comments here for definition of address map
572 ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap)
573 ASM_PFX(AsmGetTemplateAddressMap):
575 movabsq $Exception0Handle, %rax
577 movq $(Exception1Handle - Exception0Handle), 0x08(%rcx)
578 movabsq $HookAfterStubHeaderBegin, %rax
579 movq %rax, 0x10(%rcx)
582 #-------------------------------------------------------------------------------------
583 # AsmVectorNumFixup (*VectorBase, VectorNum);
584 #-------------------------------------------------------------------------------------
585 ASM_GLOBAL ASM_PFX(AsmVectorNumFixup)
586 ASM_PFX(AsmVectorNumFixup):
588 movb %al, (VectorNum - HookAfterStubHeaderBegin)(%rcx)