Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan <jeff.fan@intel.com>
		
			
				
	
	
		
			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
 |