CpuExceptionHandlerLib has code that contains absolute relocations, not supported by Xcode for X64, and it then copies this code to an alternate location in memory. It is very hard to write IP relative self-modifiying code. I had to update AsmVectorNumFixup() to also patch in the absolute addressess after the code was copied. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Anderw Fish <afish@apple.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16068 6f19259b-4bc3-4df7-8a09-765794883524
390 lines
11 KiB
NASM
390 lines
11 KiB
NASM
;------------------------------------------------------------------------------ ;
|
|
; Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
|
|
; This program and the accompanying materials
|
|
; are licensed and made available under the terms and conditions of the BSD License
|
|
; which accompanies this distribution. The full text of the license may be found at
|
|
; http://opensource.org/licenses/bsd-license.php.
|
|
;
|
|
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
;
|
|
; Module Name:
|
|
;
|
|
; ExceptionHandlerAsm.Asm
|
|
;
|
|
; Abstract:
|
|
;
|
|
; x64 CPU Exception Handler
|
|
;
|
|
; Notes:
|
|
;
|
|
;------------------------------------------------------------------------------
|
|
|
|
;
|
|
; CommonExceptionHandler()
|
|
;
|
|
externdef CommonExceptionHandler:near
|
|
|
|
EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions
|
|
EXTRN mDoFarReturnFlag:QWORD ; Do far return flag
|
|
|
|
data SEGMENT
|
|
|
|
.code
|
|
|
|
ALIGN 8
|
|
|
|
AsmIdtVectorBegin:
|
|
REPEAT 32
|
|
db 6ah ; push #VectorNum
|
|
db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
|
|
push rax
|
|
mov rax, CommonInterruptEntry
|
|
jmp rax
|
|
ENDM
|
|
AsmIdtVectorEnd:
|
|
|
|
HookAfterStubHeaderBegin:
|
|
db 6ah ; push
|
|
@VectorNum:
|
|
db 0 ; 0 will be fixed
|
|
push rax
|
|
mov rax, HookAfterStubHeaderEnd
|
|
jmp rax
|
|
HookAfterStubHeaderEnd:
|
|
mov rax, rsp
|
|
and sp, 0fff0h ; make sure 16-byte aligned for exception context
|
|
sub rsp, 18h ; reserve room for filling exception data later
|
|
push rcx
|
|
mov rcx, [rax + 8]
|
|
bt mErrorCodeFlag, ecx
|
|
jnc @F
|
|
push [rsp] ; push additional rcx to make stack alignment
|
|
@@:
|
|
xchg rcx, [rsp] ; restore rcx, save Exception Number in stack
|
|
push [rax] ; push rax into stack to keep code consistence
|
|
|
|
;---------------------------------------;
|
|
; CommonInterruptEntry ;
|
|
;---------------------------------------;
|
|
; The follow algorithm is used for the common interrupt routine.
|
|
; Entry from each interrupt with a push eax and eax=interrupt number
|
|
; Stack frame would be as follows as specified in IA32 manuals:
|
|
;
|
|
; +---------------------+ <-- 16-byte aligned ensured by processor
|
|
; + Old SS +
|
|
; +---------------------+
|
|
; + Old RSP +
|
|
; +---------------------+
|
|
; + RFlags +
|
|
; +---------------------+
|
|
; + CS +
|
|
; +---------------------+
|
|
; + RIP +
|
|
; +---------------------+
|
|
; + Error Code +
|
|
; +---------------------+
|
|
; + Vector Number +
|
|
; +---------------------+
|
|
; + RBP +
|
|
; +---------------------+ <-- RBP, 16-byte aligned
|
|
; The follow algorithm is used for the common interrupt routine.
|
|
CommonInterruptEntry PROC PUBLIC
|
|
cli
|
|
pop rax
|
|
;
|
|
; All interrupt handlers are invoked through interrupt gates, so
|
|
; IF flag automatically cleared at the entry point
|
|
;
|
|
xchg rcx, [rsp] ; Save rcx into stack and save vector number into rcx
|
|
and rcx, 0FFh
|
|
cmp ecx, 32 ; Intel reserved vector for exceptions?
|
|
jae NoErrorCode
|
|
bt mErrorCodeFlag, ecx
|
|
jc @F
|
|
|
|
NoErrorCode:
|
|
|
|
;
|
|
; Push a dummy error code on the stack
|
|
; to maintain coherent stack map
|
|
;
|
|
push [rsp]
|
|
mov qword ptr [rsp + 8], 0
|
|
@@:
|
|
push rbp
|
|
mov rbp, rsp
|
|
push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
|
|
push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
|
|
|
|
;
|
|
; Stack:
|
|
; +---------------------+ <-- 16-byte aligned ensured by processor
|
|
; + Old SS +
|
|
; +---------------------+
|
|
; + Old RSP +
|
|
; +---------------------+
|
|
; + RFlags +
|
|
; +---------------------+
|
|
; + CS +
|
|
; +---------------------+
|
|
; + RIP +
|
|
; +---------------------+
|
|
; + Error Code +
|
|
; +---------------------+
|
|
; + RCX / Vector Number +
|
|
; +---------------------+
|
|
; + RBP +
|
|
; +---------------------+ <-- RBP, 16-byte aligned
|
|
;
|
|
|
|
|
|
;
|
|
; Since here the stack pointer is 16-byte aligned, so
|
|
; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
|
|
; is 16-byte aligned
|
|
;
|
|
|
|
;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
|
|
;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
|
|
push r15
|
|
push r14
|
|
push r13
|
|
push r12
|
|
push r11
|
|
push r10
|
|
push r9
|
|
push r8
|
|
push rax
|
|
push qword ptr [rbp + 8] ; RCX
|
|
push rdx
|
|
push rbx
|
|
push qword ptr [rbp + 48] ; RSP
|
|
push qword ptr [rbp] ; RBP
|
|
push rsi
|
|
push rdi
|
|
|
|
;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
|
|
movzx rax, word ptr [rbp + 56]
|
|
push rax ; for ss
|
|
movzx rax, word ptr [rbp + 32]
|
|
push rax ; for cs
|
|
mov rax, ds
|
|
push rax
|
|
mov rax, es
|
|
push rax
|
|
mov rax, fs
|
|
push rax
|
|
mov rax, gs
|
|
push rax
|
|
|
|
mov [rbp + 8], rcx ; save vector number
|
|
|
|
;; UINT64 Rip;
|
|
push qword ptr [rbp + 24]
|
|
|
|
;; UINT64 Gdtr[2], Idtr[2];
|
|
xor rax, rax
|
|
push rax
|
|
push rax
|
|
sidt [rsp]
|
|
xchg rax, [rsp + 2]
|
|
xchg rax, [rsp]
|
|
xchg rax, [rsp + 8]
|
|
|
|
xor rax, rax
|
|
push rax
|
|
push rax
|
|
sgdt [rsp]
|
|
xchg rax, [rsp + 2]
|
|
xchg rax, [rsp]
|
|
xchg rax, [rsp + 8]
|
|
|
|
;; UINT64 Ldtr, Tr;
|
|
xor rax, rax
|
|
str ax
|
|
push rax
|
|
sldt ax
|
|
push rax
|
|
|
|
;; UINT64 RFlags;
|
|
push qword ptr [rbp + 40]
|
|
|
|
;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
|
|
mov rax, cr8
|
|
push rax
|
|
mov rax, cr4
|
|
or rax, 208h
|
|
mov cr4, rax
|
|
push rax
|
|
mov rax, cr3
|
|
push rax
|
|
mov rax, cr2
|
|
push rax
|
|
xor rax, rax
|
|
push rax
|
|
mov rax, cr0
|
|
push rax
|
|
|
|
;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
|
|
mov rax, dr7
|
|
push rax
|
|
mov rax, dr6
|
|
push rax
|
|
mov rax, dr3
|
|
push rax
|
|
mov rax, dr2
|
|
push rax
|
|
mov rax, dr1
|
|
push rax
|
|
mov rax, dr0
|
|
push rax
|
|
|
|
;; FX_SAVE_STATE_X64 FxSaveState;
|
|
sub rsp, 512
|
|
mov rdi, rsp
|
|
db 0fh, 0aeh, 07h ;fxsave [rdi]
|
|
|
|
;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
|
|
cld
|
|
|
|
;; UINT32 ExceptionData;
|
|
push qword ptr [rbp + 16]
|
|
|
|
;; Prepare parameter and call
|
|
mov rcx, [rbp + 8]
|
|
mov rdx, rsp
|
|
;
|
|
; Per X64 calling convention, allocate maximum parameter stack space
|
|
; and make sure RSP is 16-byte aligned
|
|
;
|
|
sub rsp, 4 * 8 + 8
|
|
mov rax, CommonExceptionHandler
|
|
call rax
|
|
add rsp, 4 * 8 + 8
|
|
|
|
cli
|
|
;; UINT64 ExceptionData;
|
|
add rsp, 8
|
|
|
|
;; FX_SAVE_STATE_X64 FxSaveState;
|
|
|
|
mov rsi, rsp
|
|
db 0fh, 0aeh, 0Eh ; fxrstor [rsi]
|
|
add rsp, 512
|
|
|
|
;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
|
|
;; Skip restoration of DRx registers to support in-circuit emualators
|
|
;; or debuggers set breakpoint in interrupt/exception context
|
|
add rsp, 8 * 6
|
|
|
|
;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
|
|
pop rax
|
|
mov cr0, rax
|
|
add rsp, 8 ; not for Cr1
|
|
pop rax
|
|
mov cr2, rax
|
|
pop rax
|
|
mov cr3, rax
|
|
pop rax
|
|
mov cr4, rax
|
|
pop rax
|
|
mov cr8, rax
|
|
|
|
;; UINT64 RFlags;
|
|
pop qword ptr [rbp + 40]
|
|
|
|
;; UINT64 Ldtr, Tr;
|
|
;; UINT64 Gdtr[2], Idtr[2];
|
|
;; Best not let anyone mess with these particular registers...
|
|
add rsp, 48
|
|
|
|
;; UINT64 Rip;
|
|
pop qword ptr [rbp + 24]
|
|
|
|
;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
|
|
pop rax
|
|
; mov gs, rax ; not for gs
|
|
pop rax
|
|
; mov fs, rax ; not for fs
|
|
; (X64 will not use fs and gs, so we do not restore it)
|
|
pop rax
|
|
mov es, rax
|
|
pop rax
|
|
mov ds, rax
|
|
pop qword ptr [rbp + 32] ; for cs
|
|
pop qword ptr [rbp + 56] ; for ss
|
|
|
|
;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
|
|
;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
|
|
pop rdi
|
|
pop rsi
|
|
add rsp, 8 ; not for rbp
|
|
pop qword ptr [rbp + 48] ; for rsp
|
|
pop rbx
|
|
pop rdx
|
|
pop rcx
|
|
pop rax
|
|
pop r8
|
|
pop r9
|
|
pop r10
|
|
pop r11
|
|
pop r12
|
|
pop r13
|
|
pop r14
|
|
pop r15
|
|
|
|
mov rsp, rbp
|
|
pop rbp
|
|
add rsp, 16
|
|
cmp qword ptr [rsp - 32], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
|
|
jz DoReturn
|
|
cmp qword ptr [rsp - 40], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
|
|
jz ErrorCode
|
|
jmp qword ptr [rsp - 32]
|
|
ErrorCode:
|
|
sub rsp, 8
|
|
jmp qword ptr [rsp - 24]
|
|
|
|
DoReturn:
|
|
cmp mDoFarReturnFlag, 0 ; Check if need to do far return instead of IRET
|
|
jz DoIret
|
|
push rax
|
|
mov rax, rsp ; save old RSP to rax
|
|
mov rsp, [rsp + 20h]
|
|
push [rax + 10h] ; save CS in new location
|
|
push [rax + 8h] ; save EIP in new location
|
|
push [rax + 18h] ; save EFLAGS in new location
|
|
mov rax, [rax] ; restore rax
|
|
popfq ; restore EFLAGS
|
|
DB 48h ; prefix to composite "retq" with next "retf"
|
|
retf ; far return
|
|
DoIret:
|
|
iretq
|
|
|
|
CommonInterruptEntry ENDP
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
; GetTemplateAddressMap (&AddressMap);
|
|
;-------------------------------------------------------------------------------------
|
|
; comments here for definition of address map
|
|
AsmGetTemplateAddressMap PROC
|
|
mov rax, offset AsmIdtVectorBegin
|
|
mov qword ptr [rcx], rax
|
|
mov qword ptr [rcx + 8h], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
|
|
mov rax, offset HookAfterStubHeaderBegin
|
|
mov qword ptr [rcx + 10h], rax
|
|
ret
|
|
AsmGetTemplateAddressMap ENDP
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
|
|
;-------------------------------------------------------------------------------------
|
|
AsmVectorNumFixup PROC
|
|
mov rax, rdx
|
|
mov [rcx + (@VectorNum - HookAfterStubHeaderBegin)], al
|
|
ret
|
|
AsmVectorNumFixup ENDP
|
|
|
|
END
|