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
277 movabsl ASM_PFX(mErrorCodeFlag), %eax
281 pushq (%rsp) # push additional rcx to make stack alignment
283 xchgq (%rsp), %rcx # restore rcx, save Exception Number in stack
284 pushq (%rax) # push rax into stack to keep code consistence
286 #---------------------------------------;
287 # CommonInterruptEntry ;
288 #---------------------------------------;
289 # The follow algorithm is used for the common interrupt routine.
291 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
292 ASM_PFX(CommonInterruptEntry):
296 # All interrupt handlers are invoked through interrupt gates, so
297 # IF flag automatically cleared at the entry point
300 # Calculate vector number
302 xchgq (%rsp), %rcx # get the return address of call, actually, it is the address of vector number.
304 cmp $32, %ecx # Intel reserved vector for exceptions?
307 movabsl ASM_PFX(mErrorCodeFlag), %eax
310 jc CommonInterruptEntry_al_0000
315 # Push a dummy error code on the stack
316 # to maintain coherent stack map
320 CommonInterruptEntry_al_0000:
323 pushq $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
324 pushq $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
328 # +---------------------+ <-- 16-byte aligned ensured by processor
330 # +---------------------+
332 # +---------------------+
334 # +---------------------+
336 # +---------------------+
338 # +---------------------+
340 # +---------------------+
341 # + RCX / Vector Number +
342 # +---------------------+
344 # +---------------------+ <-- RBP, 16-byte aligned
349 # Since here the stack pointer is 16-byte aligned, so
350 # EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
354 #; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
355 #; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
373 #; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
374 movzwq 56(%rbp), %rax
376 movzwq 32(%rbp), %rax
387 movq %rcx, 8(%rbp) # save vector number
392 #; UINT64 Gdtr[2], Idtr[2];
419 #; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
435 #; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
449 #; FX_SAVE_STATE_X64 FxSaveState;
452 .byte 0x0f, 0x0ae, 0x07 #fxsave [rdi]
454 #; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
457 #; UINT32 ExceptionData;
460 #; Prepare parameter and call
464 # Per X64 calling convention, allocate maximum parameter stack space
465 # and make sure RSP is 16-byte aligned
468 call ASM_PFX(CommonExceptionHandler)
472 #; UINT64 ExceptionData;
475 #; FX_SAVE_STATE_X64 FxSaveState;
478 .byte 0x0f, 0x0ae, 0x0E # fxrstor [rsi]
481 #; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
482 #; Skip restoration of DRx registers to support in-circuit emualators
483 #; or debuggers set breakpoint in interrupt/exception context
486 #; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
489 addq $8, %rsp # not for Cr1
503 #; UINT64 Gdtr[2], Idtr[2];
504 #; Best not let anyone mess with these particular registers...
510 #; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
512 # mov %rax, %gs ; not for gs
514 # mov %rax, %fs ; not for fs
515 # (X64 will not use fs and gs, so we do not restore it)
520 popq 32(%rbp) # for cs
521 popq 56(%rbp) # for ss
523 #; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
524 #; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
527 addq $8, %rsp # not for rbp
528 popq 48(%rbp) # for rsp
545 cmpq $0, -32(%rsp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
546 jz DoReturn # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
556 movabsq ASM_PFX(mDoFarReturnFlag), %rax
557 cmpq $0, %rax # Check if need to do far return instead of IRET
561 movq %rsp, %rax # save old RSP to rax
562 movq 0x20(%rsp), %rsp
563 pushq 0x10(%rax) # save CS in new location
564 pushq 0x8(%rax) # save EIP in new location
565 pushq 0x18(%rax) # save EFLAGS in new location
566 movq (%rax), %rax # restore rax
567 popfq # restore EFLAGS
568 .byte 0x48 # prefix to composite "retq" with next "retf"
574 #-------------------------------------------------------------------------------------
575 # AsmGetTemplateAddressMap (&AddressMap);
576 #-------------------------------------------------------------------------------------
577 # comments here for definition of address map
578 ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap)
579 ASM_PFX(AsmGetTemplateAddressMap):
581 movabsq $Exception0Handle, %rax
583 movq $(Exception1Handle - Exception0Handle), 0x08(%rcx)
584 movabsq $HookAfterStubHeaderBegin, %rax
585 movq %rax, 0x10(%rcx)
588 #-------------------------------------------------------------------------------------
589 # AsmVectorNumFixup (*VectorBase, VectorNum);
590 #-------------------------------------------------------------------------------------
591 ASM_GLOBAL ASM_PFX(AsmVectorNumFixup)
592 ASM_PFX(AsmVectorNumFixup):
594 movb %al, (VectorNum - HookAfterStubHeaderBegin)(%rcx)