]> xenbits.xensource.com Git - ovmf.git/commitdiff
UefiCpuPkg/CpuExceptionHandlerLib: Make runtime fixups XCODE-only
authorArd Biesheuvel <ardb@kernel.org>
Mon, 3 Apr 2023 14:29:18 +0000 (22:29 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Thu, 6 Apr 2023 06:52:55 +0000 (06:52 +0000)
The CPU exception handler library code was rewritten at some point to
populate the vector code templates with absolute references at runtime,
given that the XCODE linker does not permit absolute references in
executable code when creating PIE executables.

This is rather unfortunate, as this prevents us from using strict
permissions on the memory mappings, given that the .text section needs
to be writable at runtime for this arrangement to work.

So let's make this hack XCODE-only, by setting a preprocessor #define
from the command line when using the XCODE toolchain, and only including
the runtime fixup code when the macro is defined.

While at it, rename the Xcode5ExceptionHandlerAsm.nasm source file and
drop the Xcode5 prefix: this code is used by other toolchains too.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Ray Ni <ray.ni@intel.com>
UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm [new file with mode: 0644]
UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/Xcode5ExceptionHandlerAsm.nasm [deleted file]

index d0f82095cf926e995470a35d0616724e25621115..fdbebadab93df75618beee375c0eb9256a511a22 100644 (file)
@@ -28,7 +28,7 @@
   Ia32/ArchInterruptDefs.h\r
 \r
 [Sources.X64]\r
-  X64/Xcode5ExceptionHandlerAsm.nasm\r
+  X64/ExceptionHandlerAsm.nasm\r
   X64/ArchExceptionHandler.c\r
   X64/ArchInterruptDefs.h\r
 \r
@@ -61,3 +61,6 @@
   MemoryAllocationLib\r
   DebugLib\r
   CcExitLib\r
+\r
+[BuildOptions]\r
+  XCODE:*_*_X64_NASM_FLAGS = -D NO_ABSOLUTE_RELOCS_IN_TEXT\r
index 8f8a5dab79303f87ede512f61eb1cafdd51ee88e..27f0b96fa9e9770527d87985d4c801d2324314cc 100644 (file)
@@ -28,7 +28,7 @@
   Ia32/ArchInterruptDefs.h\r
 \r
 [Sources.X64]\r
-  X64/Xcode5ExceptionHandlerAsm.nasm\r
+  X64/ExceptionHandlerAsm.nasm\r
   X64/ArchExceptionHandler.c\r
   X64/ArchInterruptDefs.h\r
 \r
@@ -61,3 +61,5 @@
 [FeaturePcd]\r
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard                    ## CONSUMES\r
 \r
+[BuildOptions]\r
+  XCODE:*_*_X64_NASM_FLAGS = -D NO_ABSOLUTE_RELOCS_IN_TEXT\r
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
new file mode 100644 (file)
index 0000000..3d64ac9
--- /dev/null
@@ -0,0 +1,492 @@
+;------------------------------------------------------------------------------ ;\r
+; Copyright (c) 2012 - 2022, Intel Corporation. All rights reserved.<BR>\r
+; SPDX-License-Identifier: BSD-2-Clause-Patent\r
+;\r
+; Module Name:\r
+;\r
+;   ExceptionHandlerAsm.Asm\r
+;\r
+; Abstract:\r
+;\r
+;   x64 CPU Exception Handler\r
+;\r
+; Notes:\r
+;\r
+;------------------------------------------------------------------------------\r
+%include "Nasm.inc"\r
+\r
+;\r
+; Equivalent NASM structure of IA32_DESCRIPTOR\r
+;\r
+struc IA32_DESCRIPTOR\r
+  .Limit                         CTYPE_UINT16 1\r
+  .Base                          CTYPE_UINTN  1\r
+endstruc\r
+\r
+;\r
+; Equivalent NASM structure of IA32_IDT_GATE_DESCRIPTOR\r
+;\r
+struc IA32_IDT_GATE_DESCRIPTOR\r
+  .OffsetLow                     CTYPE_UINT16 1\r
+  .Selector                      CTYPE_UINT16 1\r
+  .Reserved_0                    CTYPE_UINT8 1\r
+  .GateType                      CTYPE_UINT8 1\r
+  .OffsetHigh                    CTYPE_UINT16 1\r
+  .OffsetUpper                   CTYPE_UINT32 1\r
+  .Reserved_1                    CTYPE_UINT32 1\r
+endstruc\r
+\r
+;\r
+; CommonExceptionHandler()\r
+;\r
+\r
+%define VC_EXCEPTION 29\r
+\r
+extern ASM_PFX(mErrorCodeFlag)    ; Error code flags for exceptions\r
+extern ASM_PFX(mDoFarReturnFlag)  ; Do far return flag\r
+extern ASM_PFX(CommonExceptionHandler)\r
+\r
+SECTION .data\r
+\r
+DEFAULT REL\r
+SECTION .text\r
+\r
+ALIGN   8\r
+\r
+; Generate 256 IDT vectors.\r
+AsmIdtVectorBegin:\r
+%assign Vector 0\r
+%rep  256\r
+    push    strict dword %[Vector] ; This instruction pushes sign-extended 8-byte value on stack\r
+    push    rax\r
+%ifdef NO_ABSOLUTE_RELOCS_IN_TEXT\r
+    mov     rax, strict qword 0    ; mov     rax, ASM_PFX(CommonInterruptEntry)\r
+%else\r
+    mov     rax, ASM_PFX(CommonInterruptEntry)\r
+%endif\r
+    jmp     rax\r
+%assign Vector Vector+1\r
+%endrep\r
+AsmIdtVectorEnd:\r
+\r
+HookAfterStubHeaderBegin:\r
+    push    strict dword 0      ; 0 will be fixed\r
+VectorNum:\r
+    push    rax\r
+%ifdef NO_ABSOLUTE_RELOCS_IN_TEXT\r
+    mov     rax, strict qword 0 ;     mov     rax, HookAfterStubHeaderEnd\r
+JmpAbsoluteAddress:\r
+%else\r
+    mov     rax, HookAfterStubHeaderEnd\r
+%endif\r
+    jmp     rax\r
+HookAfterStubHeaderEnd:\r
+    mov     rax, rsp\r
+    and     sp,  0xfff0        ; make sure 16-byte aligned for exception context\r
+    sub     rsp, 0x18           ; reserve room for filling exception data later\r
+    push    rcx\r
+    mov     rcx, [rax + 8]\r
+    bt      [ASM_PFX(mErrorCodeFlag)], ecx\r
+    jnc     .0\r
+    push    qword [rsp]             ; push additional rcx to make stack alignment\r
+.0:\r
+    xchg    rcx, [rsp]        ; restore rcx, save Exception Number in stack\r
+    push    qword [rax]             ; push rax into stack to keep code consistence\r
+\r
+;---------------------------------------;\r
+; CommonInterruptEntry                  ;\r
+;---------------------------------------;\r
+; The follow algorithm is used for the common interrupt routine.\r
+; Entry from each interrupt with a push eax and eax=interrupt number\r
+; Stack frame would be as follows as specified in IA32 manuals:\r
+;\r
+; +---------------------+ <-- 16-byte aligned ensured by processor\r
+; +    Old SS           +\r
+; +---------------------+\r
+; +    Old RSP          +\r
+; +---------------------+\r
+; +    RFlags           +\r
+; +---------------------+\r
+; +    CS               +\r
+; +---------------------+\r
+; +    RIP              +\r
+; +---------------------+\r
+; +    Error Code       +\r
+; +---------------------+\r
+; +   Vector Number     +\r
+; +---------------------+\r
+; +    RBP              +\r
+; +---------------------+ <-- RBP, 16-byte aligned\r
+; The follow algorithm is used for the common interrupt routine.\r
+global ASM_PFX(CommonInterruptEntry)\r
+ASM_PFX(CommonInterruptEntry):\r
+    cli\r
+    pop     rax\r
+    ;\r
+    ; All interrupt handlers are invoked through interrupt gates, so\r
+    ; IF flag automatically cleared at the entry point\r
+    ;\r
+    xchg    rcx, [rsp]      ; Save rcx into stack and save vector number into rcx\r
+    and     rcx, 0xFF\r
+    cmp     ecx, 32         ; Intel reserved vector for exceptions?\r
+    jae     NoErrorCode\r
+    bt      [ASM_PFX(mErrorCodeFlag)], ecx\r
+    jc      HasErrorCode\r
+\r
+NoErrorCode:\r
+\r
+    ;\r
+    ; Push a dummy error code on the stack\r
+    ; to maintain coherent stack map\r
+    ;\r
+    push    qword [rsp]\r
+    mov     qword [rsp + 8], 0\r
+HasErrorCode:\r
+    push    rbp\r
+    mov     rbp, rsp\r
+    push    0             ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler\r
+    push    0             ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag\r
+\r
+    ;\r
+    ; Stack:\r
+    ; +---------------------+ <-- 16-byte aligned ensured by processor\r
+    ; +    Old SS           +\r
+    ; +---------------------+\r
+    ; +    Old RSP          +\r
+    ; +---------------------+\r
+    ; +    RFlags           +\r
+    ; +---------------------+\r
+    ; +    CS               +\r
+    ; +---------------------+\r
+    ; +    RIP              +\r
+    ; +---------------------+\r
+    ; +    Error Code       +\r
+    ; +---------------------+\r
+    ; + RCX / Vector Number +\r
+    ; +---------------------+\r
+    ; +    RBP              +\r
+    ; +---------------------+ <-- RBP, 16-byte aligned\r
+    ;\r
+\r
+    ;\r
+    ; Since here the stack pointer is 16-byte aligned, so\r
+    ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64\r
+    ; is 16-byte aligned\r
+    ;\r
+\r
+;; UINT64  Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;\r
+;; UINT64  R8, R9, R10, R11, R12, R13, R14, R15;\r
+    push r15\r
+    push r14\r
+    push r13\r
+    push r12\r
+    push r11\r
+    push r10\r
+    push r9\r
+    push r8\r
+    push rax\r
+    push qword [rbp + 8]   ; RCX\r
+    push rdx\r
+    push rbx\r
+    push qword [rbp + 48]  ; RSP\r
+    push qword [rbp]       ; RBP\r
+    push rsi\r
+    push rdi\r
+\r
+;; UINT64  Gs, Fs, Es, Ds, Cs, Ss;  insure high 16 bits of each is zero\r
+    movzx   rax, word [rbp + 56]\r
+    push    rax                      ; for ss\r
+    movzx   rax, word [rbp + 32]\r
+    push    rax                      ; for cs\r
+    mov     rax, ds\r
+    push    rax\r
+    mov     rax, es\r
+    push    rax\r
+    mov     rax, fs\r
+    push    rax\r
+    mov     rax, gs\r
+    push    rax\r
+\r
+    mov     [rbp + 8], rcx               ; save vector number\r
+\r
+;; UINT64  Rip;\r
+    push    qword [rbp + 24]\r
+\r
+;; UINT64  Gdtr[2], Idtr[2];\r
+    xor     rax, rax\r
+    push    rax\r
+    push    rax\r
+    sidt    [rsp]\r
+    mov     bx, word [rsp]\r
+    mov     rax, qword [rsp + 2]\r
+    mov     qword [rsp], rax\r
+    mov     word [rsp + 8], bx\r
+\r
+    xor     rax, rax\r
+    push    rax\r
+    push    rax\r
+    sgdt    [rsp]\r
+    mov     bx, word [rsp]\r
+    mov     rax, qword [rsp + 2]\r
+    mov     qword [rsp], rax\r
+    mov     word [rsp + 8], bx\r
+\r
+;; UINT64  Ldtr, Tr;\r
+    xor     rax, rax\r
+    str     ax\r
+    push    rax\r
+    sldt    ax\r
+    push    rax\r
+\r
+;; UINT64  RFlags;\r
+    push    qword [rbp + 40]\r
+\r
+;; UINT64  Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;\r
+    mov     rax, cr8\r
+    push    rax\r
+    mov     rax, cr4\r
+    or      rax, 0x208\r
+    mov     cr4, rax\r
+    push    rax\r
+    mov     rax, cr3\r
+    push    rax\r
+    mov     rax, cr2\r
+    push    rax\r
+    xor     rax, rax\r
+    push    rax\r
+    mov     rax, cr0\r
+    push    rax\r
+\r
+;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+    cmp     qword [rbp + 8], VC_EXCEPTION\r
+    je      VcDebugRegs          ; For SEV-ES (#VC) Debug registers ignored\r
+\r
+    mov     rax, dr7\r
+    push    rax\r
+    mov     rax, dr6\r
+    push    rax\r
+    mov     rax, dr3\r
+    push    rax\r
+    mov     rax, dr2\r
+    push    rax\r
+    mov     rax, dr1\r
+    push    rax\r
+    mov     rax, dr0\r
+    push    rax\r
+    jmp     DrFinish\r
+\r
+VcDebugRegs:\r
+;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7 are skipped for #VC to avoid exception recursion\r
+    xor     rax, rax\r
+    push    rax\r
+    push    rax\r
+    push    rax\r
+    push    rax\r
+    push    rax\r
+    push    rax\r
+\r
+DrFinish:\r
+;; FX_SAVE_STATE_X64 FxSaveState;\r
+    sub rsp, 512\r
+    mov rdi, rsp\r
+    fxsave [rdi]\r
+\r
+;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear\r
+    cld\r
+\r
+;; UINT32  ExceptionData;\r
+    push    qword [rbp + 16]\r
+\r
+;; Prepare parameter and call\r
+    mov     rcx, [rbp + 8]\r
+    mov     rdx, rsp\r
+    ;\r
+    ; Per X64 calling convention, allocate maximum parameter stack space\r
+    ; and make sure RSP is 16-byte aligned\r
+    ;\r
+    sub     rsp, 4 * 8 + 8\r
+    call    ASM_PFX(CommonExceptionHandler)\r
+    add     rsp, 4 * 8 + 8\r
+\r
+    ; The follow algorithm is used for clear shadow stack token busy bit.\r
+    ; The comment is based on the sample shadow stack.\r
+    ; Shadow stack is 32 bytes aligned.\r
+    ; The sample shadow stack layout :\r
+    ; Address | Context\r
+    ;         +-------------------------+\r
+    ;  0xFB8  |   FREE                  | It is 0xFC0|0x02|(LMA & CS.L), after SAVEPREVSSP.\r
+    ;         +-------------------------+\r
+    ;  0xFC0  |  Prev SSP               |\r
+    ;         +-------------------------+\r
+    ;  0xFC8  |   RIP                   |\r
+    ;         +-------------------------+\r
+    ;  0xFD0  |   CS                    |\r
+    ;         +-------------------------+\r
+    ;  0xFD8  |  0xFD8 | BUSY           | BUSY flag cleared after CLRSSBSY\r
+    ;         +-------------------------+\r
+    ;  0xFE0  | 0xFC0|0x02|(LMA & CS.L) |\r
+    ;         +-------------------------+\r
+    ; Instructions for Intel Control Flow Enforcement Technology (CET) are supported since NASM version 2.15.01.\r
+    cmp     qword [ASM_PFX(mDoFarReturnFlag)], 0\r
+    jz      CetDone\r
+    mov     rax, cr4\r
+    and     rax, 0x800000       ; Check if CET is enabled\r
+    jz      CetDone\r
+    sub     rsp, 0x10\r
+    sidt    [rsp]\r
+    mov     rcx, qword [rsp + IA32_DESCRIPTOR.Base]; Get IDT base address\r
+    add     rsp, 0x10\r
+    mov     rax, qword [rbp + 8]; Get exception number\r
+    sal     rax, 0x04           ; Get IDT offset\r
+    add     rax, rcx            ; Get IDT gate descriptor address\r
+    mov     al, byte [rax + IA32_IDT_GATE_DESCRIPTOR.Reserved_0]\r
+    and     rax, 0x01           ; Check IST field\r
+    jz      CetDone\r
+                                ; SSP should be 0xFC0 at this point\r
+    mov     rax, 0x04           ; advance past cs:lip:prevssp;supervisor shadow stack token\r
+    incsspq rax                 ; After this SSP should be 0xFE0\r
+    saveprevssp                 ; now the shadow stack restore token will be created at 0xFB8\r
+    rdsspq  rax                 ; Read new SSP, SSP should be 0xFE8\r
+    sub     rax, 0x10\r
+    clrssbsy [rax]              ; Clear token at 0xFD8, SSP should be 0 after this\r
+    sub     rax, 0x20\r
+    rstorssp [rax]              ; Restore to token at 0xFB8, new SSP will be 0xFB8\r
+    mov     rax, 0x01           ; Pop off the new save token created\r
+    incsspq rax                 ; SSP should be 0xFC0 now\r
+CetDone:\r
+\r
+    cli\r
+;; UINT64  ExceptionData;\r
+    add     rsp, 8\r
+\r
+;; FX_SAVE_STATE_X64 FxSaveState;\r
+\r
+    mov rsi, rsp\r
+    fxrstor [rsi]\r
+    add rsp, 512\r
+\r
+;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+;; Skip restoration of DRx registers to support in-circuit emualators\r
+;; or debuggers set breakpoint in interrupt/exception context\r
+    add     rsp, 8 * 6\r
+\r
+;; UINT64  Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;\r
+    pop     rax\r
+    mov     cr0, rax\r
+    add     rsp, 8   ; not for Cr1\r
+    pop     rax\r
+    mov     cr2, rax\r
+    pop     rax\r
+    mov     cr3, rax\r
+    pop     rax\r
+    mov     cr4, rax\r
+    pop     rax\r
+    mov     cr8, rax\r
+\r
+;; UINT64  RFlags;\r
+    pop     qword [rbp + 40]\r
+\r
+;; UINT64  Ldtr, Tr;\r
+;; UINT64  Gdtr[2], Idtr[2];\r
+;; Best not let anyone mess with these particular registers...\r
+    add     rsp, 48\r
+\r
+;; UINT64  Rip;\r
+    pop     qword [rbp + 24]\r
+\r
+;; UINT64  Gs, Fs, Es, Ds, Cs, Ss;\r
+    pop     rax\r
+    ; mov     gs, rax ; not for gs\r
+    pop     rax\r
+    ; mov     fs, rax ; not for fs\r
+    ; (X64 will not use fs and gs, so we do not restore it)\r
+    pop     rax\r
+    mov     es, rax\r
+    pop     rax\r
+    mov     ds, rax\r
+    pop     qword [rbp + 32]  ; for cs\r
+    pop     qword [rbp + 56]  ; for ss\r
+\r
+;; UINT64  Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;\r
+;; UINT64  R8, R9, R10, R11, R12, R13, R14, R15;\r
+    pop     rdi\r
+    pop     rsi\r
+    add     rsp, 8               ; not for rbp\r
+    pop     qword [rbp + 48] ; for rsp\r
+    pop     rbx\r
+    pop     rdx\r
+    pop     rcx\r
+    pop     rax\r
+    pop     r8\r
+    pop     r9\r
+    pop     r10\r
+    pop     r11\r
+    pop     r12\r
+    pop     r13\r
+    pop     r14\r
+    pop     r15\r
+\r
+    mov     rsp, rbp\r
+    pop     rbp\r
+    add     rsp, 16\r
+    cmp     qword [rsp - 32], 0  ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler\r
+    jz      DoReturn\r
+    cmp     qword [rsp - 40], 1  ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag\r
+    jz      ErrorCode\r
+    jmp     qword [rsp - 32]\r
+ErrorCode:\r
+    sub     rsp, 8\r
+    jmp     qword [rsp - 24]\r
+\r
+DoReturn:\r
+    cmp     qword [ASM_PFX(mDoFarReturnFlag)], 0   ; Check if need to do far return instead of IRET\r
+    jz      DoIret\r
+    push    rax\r
+    mov     rax, rsp          ; save old RSP to rax\r
+    mov     rsp, [rsp + 0x20]\r
+    push    qword [rax + 0x10]       ; save CS in new location\r
+    push    qword [rax + 0x8]        ; save EIP in new location\r
+    push    qword [rax + 0x18]       ; save EFLAGS in new location\r
+    mov     rax, [rax]        ; restore rax\r
+    popfq                     ; restore EFLAGS\r
+    retfq\r
+DoIret:\r
+    iretq\r
+\r
+;-------------------------------------------------------------------------------------\r
+;  GetTemplateAddressMap (&AddressMap);\r
+;-------------------------------------------------------------------------------------\r
+; comments here for definition of address map\r
+global ASM_PFX(AsmGetTemplateAddressMap)\r
+ASM_PFX(AsmGetTemplateAddressMap):\r
+    lea     rax, [AsmIdtVectorBegin]\r
+    mov     qword [rcx], rax\r
+    mov     qword [rcx + 0x8],  (AsmIdtVectorEnd - AsmIdtVectorBegin) / 256\r
+    lea     rax, [HookAfterStubHeaderBegin]\r
+    mov     qword [rcx + 0x10], rax\r
+\r
+%ifdef NO_ABSOLUTE_RELOCS_IN_TEXT\r
+; Fix up CommonInterruptEntry address\r
+    lea    rax, [ASM_PFX(CommonInterruptEntry)]\r
+    lea    rcx, [AsmIdtVectorBegin]\r
+%rep  256\r
+    mov    qword [rcx + (JmpAbsoluteAddress - 8 - HookAfterStubHeaderBegin)], rax\r
+    add    rcx, (AsmIdtVectorEnd - AsmIdtVectorBegin) / 256\r
+%endrep\r
+; Fix up HookAfterStubHeaderEnd\r
+    lea    rax, [HookAfterStubHeaderEnd]\r
+    lea    rcx, [JmpAbsoluteAddress]\r
+    mov    qword [rcx - 8], rax\r
+%endif\r
+\r
+    ret\r
+\r
+;-------------------------------------------------------------------------------------\r
+;  AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);\r
+;-------------------------------------------------------------------------------------\r
+global ASM_PFX(AsmVectorNumFixup)\r
+ASM_PFX(AsmVectorNumFixup):\r
+    mov     rax, rdx\r
+    mov     [rcx + (VectorNum - 4 - HookAfterStubHeaderBegin)], al\r
+    ret\r
+\r
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/Xcode5ExceptionHandlerAsm.nasm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/Xcode5ExceptionHandlerAsm.nasm
deleted file mode 100644 (file)
index 9574785..0000000
+++ /dev/null
@@ -1,482 +0,0 @@
-;------------------------------------------------------------------------------ ;\r
-; Copyright (c) 2012 - 2022, Intel Corporation. All rights reserved.<BR>\r
-; SPDX-License-Identifier: BSD-2-Clause-Patent\r
-;\r
-; Module Name:\r
-;\r
-;   ExceptionHandlerAsm.Asm\r
-;\r
-; Abstract:\r
-;\r
-;   x64 CPU Exception Handler\r
-;\r
-; Notes:\r
-;\r
-;------------------------------------------------------------------------------\r
-%include "Nasm.inc"\r
-\r
-;\r
-; Equivalent NASM structure of IA32_DESCRIPTOR\r
-;\r
-struc IA32_DESCRIPTOR\r
-  .Limit                         CTYPE_UINT16 1\r
-  .Base                          CTYPE_UINTN  1\r
-endstruc\r
-\r
-;\r
-; Equivalent NASM structure of IA32_IDT_GATE_DESCRIPTOR\r
-;\r
-struc IA32_IDT_GATE_DESCRIPTOR\r
-  .OffsetLow                     CTYPE_UINT16 1\r
-  .Selector                      CTYPE_UINT16 1\r
-  .Reserved_0                    CTYPE_UINT8 1\r
-  .GateType                      CTYPE_UINT8 1\r
-  .OffsetHigh                    CTYPE_UINT16 1\r
-  .OffsetUpper                   CTYPE_UINT32 1\r
-  .Reserved_1                    CTYPE_UINT32 1\r
-endstruc\r
-\r
-;\r
-; CommonExceptionHandler()\r
-;\r
-\r
-%define VC_EXCEPTION 29\r
-\r
-extern ASM_PFX(mErrorCodeFlag)    ; Error code flags for exceptions\r
-extern ASM_PFX(mDoFarReturnFlag)  ; Do far return flag\r
-extern ASM_PFX(CommonExceptionHandler)\r
-\r
-SECTION .data\r
-\r
-DEFAULT REL\r
-SECTION .text\r
-\r
-ALIGN   8\r
-\r
-; Generate 256 IDT vectors.\r
-AsmIdtVectorBegin:\r
-%assign Vector 0\r
-%rep  256\r
-    push    strict dword %[Vector] ; This instruction pushes sign-extended 8-byte value on stack\r
-    push    rax\r
-    mov     rax, strict qword 0    ; mov     rax, ASM_PFX(CommonInterruptEntry)\r
-    jmp     rax\r
-%assign Vector Vector+1\r
-%endrep\r
-AsmIdtVectorEnd:\r
-\r
-HookAfterStubHeaderBegin:\r
-    push    strict dword 0      ; 0 will be fixed\r
-VectorNum:\r
-    push    rax\r
-    mov     rax, strict qword 0 ;     mov     rax, HookAfterStubHeaderEnd\r
-JmpAbsoluteAddress:\r
-    jmp     rax\r
-HookAfterStubHeaderEnd:\r
-    mov     rax, rsp\r
-    and     sp,  0xfff0        ; make sure 16-byte aligned for exception context\r
-    sub     rsp, 0x18           ; reserve room for filling exception data later\r
-    push    rcx\r
-    mov     rcx, [rax + 8]\r
-    bt      [ASM_PFX(mErrorCodeFlag)], ecx\r
-    jnc     .0\r
-    push    qword [rsp]             ; push additional rcx to make stack alignment\r
-.0:\r
-    xchg    rcx, [rsp]        ; restore rcx, save Exception Number in stack\r
-    push    qword [rax]             ; push rax into stack to keep code consistence\r
-\r
-;---------------------------------------;\r
-; CommonInterruptEntry                  ;\r
-;---------------------------------------;\r
-; The follow algorithm is used for the common interrupt routine.\r
-; Entry from each interrupt with a push eax and eax=interrupt number\r
-; Stack frame would be as follows as specified in IA32 manuals:\r
-;\r
-; +---------------------+ <-- 16-byte aligned ensured by processor\r
-; +    Old SS           +\r
-; +---------------------+\r
-; +    Old RSP          +\r
-; +---------------------+\r
-; +    RFlags           +\r
-; +---------------------+\r
-; +    CS               +\r
-; +---------------------+\r
-; +    RIP              +\r
-; +---------------------+\r
-; +    Error Code       +\r
-; +---------------------+\r
-; +   Vector Number     +\r
-; +---------------------+\r
-; +    RBP              +\r
-; +---------------------+ <-- RBP, 16-byte aligned\r
-; The follow algorithm is used for the common interrupt routine.\r
-global ASM_PFX(CommonInterruptEntry)\r
-ASM_PFX(CommonInterruptEntry):\r
-    cli\r
-    pop     rax\r
-    ;\r
-    ; All interrupt handlers are invoked through interrupt gates, so\r
-    ; IF flag automatically cleared at the entry point\r
-    ;\r
-    xchg    rcx, [rsp]      ; Save rcx into stack and save vector number into rcx\r
-    and     rcx, 0xFF\r
-    cmp     ecx, 32         ; Intel reserved vector for exceptions?\r
-    jae     NoErrorCode\r
-    bt      [ASM_PFX(mErrorCodeFlag)], ecx\r
-    jc      HasErrorCode\r
-\r
-NoErrorCode:\r
-\r
-    ;\r
-    ; Push a dummy error code on the stack\r
-    ; to maintain coherent stack map\r
-    ;\r
-    push    qword [rsp]\r
-    mov     qword [rsp + 8], 0\r
-HasErrorCode:\r
-    push    rbp\r
-    mov     rbp, rsp\r
-    push    0             ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler\r
-    push    0             ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag\r
-\r
-    ;\r
-    ; Stack:\r
-    ; +---------------------+ <-- 16-byte aligned ensured by processor\r
-    ; +    Old SS           +\r
-    ; +---------------------+\r
-    ; +    Old RSP          +\r
-    ; +---------------------+\r
-    ; +    RFlags           +\r
-    ; +---------------------+\r
-    ; +    CS               +\r
-    ; +---------------------+\r
-    ; +    RIP              +\r
-    ; +---------------------+\r
-    ; +    Error Code       +\r
-    ; +---------------------+\r
-    ; + RCX / Vector Number +\r
-    ; +---------------------+\r
-    ; +    RBP              +\r
-    ; +---------------------+ <-- RBP, 16-byte aligned\r
-    ;\r
-\r
-    ;\r
-    ; Since here the stack pointer is 16-byte aligned, so\r
-    ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64\r
-    ; is 16-byte aligned\r
-    ;\r
-\r
-;; UINT64  Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;\r
-;; UINT64  R8, R9, R10, R11, R12, R13, R14, R15;\r
-    push r15\r
-    push r14\r
-    push r13\r
-    push r12\r
-    push r11\r
-    push r10\r
-    push r9\r
-    push r8\r
-    push rax\r
-    push qword [rbp + 8]   ; RCX\r
-    push rdx\r
-    push rbx\r
-    push qword [rbp + 48]  ; RSP\r
-    push qword [rbp]       ; RBP\r
-    push rsi\r
-    push rdi\r
-\r
-;; UINT64  Gs, Fs, Es, Ds, Cs, Ss;  insure high 16 bits of each is zero\r
-    movzx   rax, word [rbp + 56]\r
-    push    rax                      ; for ss\r
-    movzx   rax, word [rbp + 32]\r
-    push    rax                      ; for cs\r
-    mov     rax, ds\r
-    push    rax\r
-    mov     rax, es\r
-    push    rax\r
-    mov     rax, fs\r
-    push    rax\r
-    mov     rax, gs\r
-    push    rax\r
-\r
-    mov     [rbp + 8], rcx               ; save vector number\r
-\r
-;; UINT64  Rip;\r
-    push    qword [rbp + 24]\r
-\r
-;; UINT64  Gdtr[2], Idtr[2];\r
-    xor     rax, rax\r
-    push    rax\r
-    push    rax\r
-    sidt    [rsp]\r
-    mov     bx, word [rsp]\r
-    mov     rax, qword [rsp + 2]\r
-    mov     qword [rsp], rax\r
-    mov     word [rsp + 8], bx\r
-\r
-    xor     rax, rax\r
-    push    rax\r
-    push    rax\r
-    sgdt    [rsp]\r
-    mov     bx, word [rsp]\r
-    mov     rax, qword [rsp + 2]\r
-    mov     qword [rsp], rax\r
-    mov     word [rsp + 8], bx\r
-\r
-;; UINT64  Ldtr, Tr;\r
-    xor     rax, rax\r
-    str     ax\r
-    push    rax\r
-    sldt    ax\r
-    push    rax\r
-\r
-;; UINT64  RFlags;\r
-    push    qword [rbp + 40]\r
-\r
-;; UINT64  Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;\r
-    mov     rax, cr8\r
-    push    rax\r
-    mov     rax, cr4\r
-    or      rax, 0x208\r
-    mov     cr4, rax\r
-    push    rax\r
-    mov     rax, cr3\r
-    push    rax\r
-    mov     rax, cr2\r
-    push    rax\r
-    xor     rax, rax\r
-    push    rax\r
-    mov     rax, cr0\r
-    push    rax\r
-\r
-;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
-    cmp     qword [rbp + 8], VC_EXCEPTION\r
-    je      VcDebugRegs          ; For SEV-ES (#VC) Debug registers ignored\r
-\r
-    mov     rax, dr7\r
-    push    rax\r
-    mov     rax, dr6\r
-    push    rax\r
-    mov     rax, dr3\r
-    push    rax\r
-    mov     rax, dr2\r
-    push    rax\r
-    mov     rax, dr1\r
-    push    rax\r
-    mov     rax, dr0\r
-    push    rax\r
-    jmp     DrFinish\r
-\r
-VcDebugRegs:\r
-;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7 are skipped for #VC to avoid exception recursion\r
-    xor     rax, rax\r
-    push    rax\r
-    push    rax\r
-    push    rax\r
-    push    rax\r
-    push    rax\r
-    push    rax\r
-\r
-DrFinish:\r
-;; FX_SAVE_STATE_X64 FxSaveState;\r
-    sub rsp, 512\r
-    mov rdi, rsp\r
-    fxsave [rdi]\r
-\r
-;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear\r
-    cld\r
-\r
-;; UINT32  ExceptionData;\r
-    push    qword [rbp + 16]\r
-\r
-;; Prepare parameter and call\r
-    mov     rcx, [rbp + 8]\r
-    mov     rdx, rsp\r
-    ;\r
-    ; Per X64 calling convention, allocate maximum parameter stack space\r
-    ; and make sure RSP is 16-byte aligned\r
-    ;\r
-    sub     rsp, 4 * 8 + 8\r
-    call    ASM_PFX(CommonExceptionHandler)\r
-    add     rsp, 4 * 8 + 8\r
-\r
-    ; The follow algorithm is used for clear shadow stack token busy bit.\r
-    ; The comment is based on the sample shadow stack.\r
-    ; Shadow stack is 32 bytes aligned.\r
-    ; The sample shadow stack layout :\r
-    ; Address | Context\r
-    ;         +-------------------------+\r
-    ;  0xFB8  |   FREE                  | It is 0xFC0|0x02|(LMA & CS.L), after SAVEPREVSSP.\r
-    ;         +-------------------------+\r
-    ;  0xFC0  |  Prev SSP               |\r
-    ;         +-------------------------+\r
-    ;  0xFC8  |   RIP                   |\r
-    ;         +-------------------------+\r
-    ;  0xFD0  |   CS                    |\r
-    ;         +-------------------------+\r
-    ;  0xFD8  |  0xFD8 | BUSY           | BUSY flag cleared after CLRSSBSY\r
-    ;         +-------------------------+\r
-    ;  0xFE0  | 0xFC0|0x02|(LMA & CS.L) |\r
-    ;         +-------------------------+\r
-    ; Instructions for Intel Control Flow Enforcement Technology (CET) are supported since NASM version 2.15.01.\r
-    cmp     qword [ASM_PFX(mDoFarReturnFlag)], 0\r
-    jz      CetDone\r
-    mov     rax, cr4\r
-    and     rax, 0x800000       ; Check if CET is enabled\r
-    jz      CetDone\r
-    sub     rsp, 0x10\r
-    sidt    [rsp]\r
-    mov     rcx, qword [rsp + IA32_DESCRIPTOR.Base]; Get IDT base address\r
-    add     rsp, 0x10\r
-    mov     rax, qword [rbp + 8]; Get exception number\r
-    sal     rax, 0x04           ; Get IDT offset\r
-    add     rax, rcx            ; Get IDT gate descriptor address\r
-    mov     al, byte [rax + IA32_IDT_GATE_DESCRIPTOR.Reserved_0]\r
-    and     rax, 0x01           ; Check IST field\r
-    jz      CetDone\r
-                                ; SSP should be 0xFC0 at this point\r
-    mov     rax, 0x04           ; advance past cs:lip:prevssp;supervisor shadow stack token\r
-    incsspq rax                 ; After this SSP should be 0xFE0\r
-    saveprevssp                 ; now the shadow stack restore token will be created at 0xFB8\r
-    rdsspq  rax                 ; Read new SSP, SSP should be 0xFE8\r
-    sub     rax, 0x10\r
-    clrssbsy [rax]              ; Clear token at 0xFD8, SSP should be 0 after this\r
-    sub     rax, 0x20\r
-    rstorssp [rax]              ; Restore to token at 0xFB8, new SSP will be 0xFB8\r
-    mov     rax, 0x01           ; Pop off the new save token created\r
-    incsspq rax                 ; SSP should be 0xFC0 now\r
-CetDone:\r
-\r
-    cli\r
-;; UINT64  ExceptionData;\r
-    add     rsp, 8\r
-\r
-;; FX_SAVE_STATE_X64 FxSaveState;\r
-\r
-    mov rsi, rsp\r
-    fxrstor [rsi]\r
-    add rsp, 512\r
-\r
-;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
-;; Skip restoration of DRx registers to support in-circuit emualators\r
-;; or debuggers set breakpoint in interrupt/exception context\r
-    add     rsp, 8 * 6\r
-\r
-;; UINT64  Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;\r
-    pop     rax\r
-    mov     cr0, rax\r
-    add     rsp, 8   ; not for Cr1\r
-    pop     rax\r
-    mov     cr2, rax\r
-    pop     rax\r
-    mov     cr3, rax\r
-    pop     rax\r
-    mov     cr4, rax\r
-    pop     rax\r
-    mov     cr8, rax\r
-\r
-;; UINT64  RFlags;\r
-    pop     qword [rbp + 40]\r
-\r
-;; UINT64  Ldtr, Tr;\r
-;; UINT64  Gdtr[2], Idtr[2];\r
-;; Best not let anyone mess with these particular registers...\r
-    add     rsp, 48\r
-\r
-;; UINT64  Rip;\r
-    pop     qword [rbp + 24]\r
-\r
-;; UINT64  Gs, Fs, Es, Ds, Cs, Ss;\r
-    pop     rax\r
-    ; mov     gs, rax ; not for gs\r
-    pop     rax\r
-    ; mov     fs, rax ; not for fs\r
-    ; (X64 will not use fs and gs, so we do not restore it)\r
-    pop     rax\r
-    mov     es, rax\r
-    pop     rax\r
-    mov     ds, rax\r
-    pop     qword [rbp + 32]  ; for cs\r
-    pop     qword [rbp + 56]  ; for ss\r
-\r
-;; UINT64  Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;\r
-;; UINT64  R8, R9, R10, R11, R12, R13, R14, R15;\r
-    pop     rdi\r
-    pop     rsi\r
-    add     rsp, 8               ; not for rbp\r
-    pop     qword [rbp + 48] ; for rsp\r
-    pop     rbx\r
-    pop     rdx\r
-    pop     rcx\r
-    pop     rax\r
-    pop     r8\r
-    pop     r9\r
-    pop     r10\r
-    pop     r11\r
-    pop     r12\r
-    pop     r13\r
-    pop     r14\r
-    pop     r15\r
-\r
-    mov     rsp, rbp\r
-    pop     rbp\r
-    add     rsp, 16\r
-    cmp     qword [rsp - 32], 0  ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler\r
-    jz      DoReturn\r
-    cmp     qword [rsp - 40], 1  ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag\r
-    jz      ErrorCode\r
-    jmp     qword [rsp - 32]\r
-ErrorCode:\r
-    sub     rsp, 8\r
-    jmp     qword [rsp - 24]\r
-\r
-DoReturn:\r
-    cmp     qword [ASM_PFX(mDoFarReturnFlag)], 0   ; Check if need to do far return instead of IRET\r
-    jz      DoIret\r
-    push    rax\r
-    mov     rax, rsp          ; save old RSP to rax\r
-    mov     rsp, [rsp + 0x20]\r
-    push    qword [rax + 0x10]       ; save CS in new location\r
-    push    qword [rax + 0x8]        ; save EIP in new location\r
-    push    qword [rax + 0x18]       ; save EFLAGS in new location\r
-    mov     rax, [rax]        ; restore rax\r
-    popfq                     ; restore EFLAGS\r
-    retfq\r
-DoIret:\r
-    iretq\r
-\r
-;-------------------------------------------------------------------------------------\r
-;  GetTemplateAddressMap (&AddressMap);\r
-;-------------------------------------------------------------------------------------\r
-; comments here for definition of address map\r
-global ASM_PFX(AsmGetTemplateAddressMap)\r
-ASM_PFX(AsmGetTemplateAddressMap):\r
-    lea     rax, [AsmIdtVectorBegin]\r
-    mov     qword [rcx], rax\r
-    mov     qword [rcx + 0x8],  (AsmIdtVectorEnd - AsmIdtVectorBegin) / 256\r
-    lea     rax, [HookAfterStubHeaderBegin]\r
-    mov     qword [rcx + 0x10], rax\r
-\r
-; Fix up CommonInterruptEntry address\r
-    lea    rax, [ASM_PFX(CommonInterruptEntry)]\r
-    lea    rcx, [AsmIdtVectorBegin]\r
-%rep  256\r
-    mov    qword [rcx + (JmpAbsoluteAddress - 8 - HookAfterStubHeaderBegin)], rax\r
-    add    rcx, (AsmIdtVectorEnd - AsmIdtVectorBegin) / 256\r
-%endrep\r
-; Fix up HookAfterStubHeaderEnd\r
-    lea    rax, [HookAfterStubHeaderEnd]\r
-    lea    rcx, [JmpAbsoluteAddress]\r
-    mov    qword [rcx - 8], rax\r
-\r
-    ret\r
-\r
-;-------------------------------------------------------------------------------------\r
-;  AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);\r
-;-------------------------------------------------------------------------------------\r
-global ASM_PFX(AsmVectorNumFixup)\r
-ASM_PFX(AsmVectorNumFixup):\r
-    mov     rax, rdx\r
-    mov     [rcx + (VectorNum - 4 - HookAfterStubHeaderBegin)], al\r
-    ret\r
-\r