[PATCH V3 10/10] OvmfPkg: Update ResetVector to support Tdx


Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

In the previous ResetVector code there are many SEV stuff mixed in common
routines, such as SetCr3ForPageTables64. If Tdx stuff is added in this way
then it is very hard to review and maintain.

According to the suggestion (https://edk2.groups.io/g/devel/message/78151)
below changes are included in this commit:
1. AmdSev.asm is created to hold the SEV related codes
2. IntelTdx.asm is created to hold the TDX related codes
3. Transition32FlatTo64Flat in Flat32ToFlat64.asm is refactor to the
pattern described in above link.
4. SetCr3ForPageTables64 in PageTables64.asm is refactor to the pattern
described in above link.

Put all above together, the code flow is described below:

1) ResetVector/Ia16/ResetVectorVtf0.asm
In Tdx all CPUs "reset" to run on 32-bit protected mode with flat
descriptor (paging disabled). But in Non-Td guest the initial state of
CPUs is 16-bit real mode. To resolve this conflict, BITS 16/32 is used
in the very beginning of ResetVector. It will check the 32-bit protected
mode or 16-bit real mode, then jump to the corresponding entry point.

2) ReloadFlat32.asm load the GDT and set the CR0, then jump to Flat32.

3) Init32.asm is the entry point of doing the 32-bit protected mode
initialization. Here ReloadFlat32 is called. After that InitTdx is called
to do Tdx initialization if it is Tdx guests.

4) Transition32FlatTo64Flat does the transition from 32-bit to 64-bit.
The Pre/Post functions are called in turn, according to the suggestion in
above link.

After all above is successfully done, Tdx jump to SecEntry.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 21 +
OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm | 110 +----
OvmfPkg/ResetVector/Ia32/PageTables64.asm | 478 +++----------------
OvmfPkg/ResetVector/Main.asm | 14 +
OvmfPkg/ResetVector/ResetVector.nasmb | 4 +
5 files changed, 131 insertions(+), 496 deletions(-)

diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
index ac86ce69ebe8..a390ed81d021 100644
--- a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
+++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
@@ -155,10 +155,31 @@ resetVector:
;
; This is where the processor will begin execution
;
+; In IA32 we follow the standard reset vector flow. While in X64, Td guest
+; may be supported. Td guest requires the startup mode to be 32-bit
+; protected mode but the legacy VM startup mode is 16-bit real mode.
+; To make NASM generate such shared entry code that behaves correctly in
+; both 16-bit and 32-bit mode, more BITS directives are added.
+;
+%ifdef ARCH_IA32
+
nop
nop
jmp EarlyBspInitReal16

+%else
+
+ smsw ax
+ test al, 1
+ jz .Real
+BITS 32
+ jmp Main32
+BITS 16
+.Real:
+ jmp EarlyBspInitReal16
+
+%endif
+
ALIGN 16

fourGigabytes:
diff --git a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
index c6d0d898bcd1..40cf6cea55bb 100644
--- a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
+++ b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
@@ -11,107 +11,39 @@
BITS 32

;
-; Modified: EAX, ECX, EDX
+; Transition from 32 bit flat protected mode into 64 bit flag protected mode
+;
+; To handle the situations of Tdx/SEV/Legacy guests, Pre/Post routines are
+; called. For example, SevPreSetCr3ForPageTables64 check the Sev features
+; and set the EAX value. TdxPostSetCr3PageTables64 set the CR0/CR4 and adjust
+; the CR3 if GPAW is 52.
+;
+; But in Tdx guest, memory region cannot be accessed before it is accepted
+; (except the case that the memory region is initialized by host VMM before
+; the guest is launched.) So in the beginning of Pre/Post routines it would
+; check if it is Tdx guest by checking the TDX_WORK_AREA.
+;
+; Modified: EAX, EBX, ECX, EDX, ESP
;
Transition32FlatTo64Flat:

+ OneTimeCall PreSetCr3ForPageTables64Sev
+
+SetPageTables64:
OneTimeCall SetCr3ForPageTables64

- mov eax, cr4
- bts eax, 5 ; enable PAE
- mov cr4, eax
+ OneTimeCall PostSetCr3PageTables64Tdx

- mov ecx, 0xc0000080
- rdmsr
- bts eax, 8 ; set LME
- wrmsr
-
- ;
- ; SEV-ES mitigation check support
- ;
- xor ebx, ebx
-
- cmp byte[SEV_ES_WORK_AREA], 0
- jz EnablePaging
-
- ;
- ; SEV-ES is active, perform a quick sanity check against the reported
- ; encryption bit position. This is to help mitigate against attacks where
- ; the hypervisor reports an incorrect encryption bit position.
- ;
- ; This is the first step in a two step process. Before paging is enabled
- ; writes to memory are encrypted. Using the RDRAND instruction (available
- ; on all SEV capable processors), write 64-bits of random data to the
- ; SEV_ES_WORK_AREA and maintain the random data in registers (register
- ; state is protected under SEV-ES). This will be used in the second step.
- ;
-RdRand1:
- rdrand ecx
- jnc RdRand1
- mov dword[SEV_ES_WORK_AREA_RDRAND], ecx
-RdRand2:
- rdrand edx
- jnc RdRand2
- mov dword[SEV_ES_WORK_AREA_RDRAND + 4], edx
-
- ;
- ; Use EBX instead of the SEV_ES_WORK_AREA memory to determine whether to
- ; perform the second step.
- ;
- mov ebx, 1
-
-EnablePaging:
- mov eax, cr0
- bts eax, 31 ; set PG
- mov cr0, eax ; enable paging
+ OneTimeCall PostSetCr3PageTables64Sev

jmp LINEAR_CODE64_SEL:ADDR_OF(jumpTo64BitAndLandHere)
+
BITS 64
+
jumpTo64BitAndLandHere:

- ;
- ; Check if the second step of the SEV-ES mitigation is to be performed.
- ;
- test ebx, ebx
- jz InsnCompare
+ OneTimeCall PostJump64BitAndLandHereSev

- ;
- ; SEV-ES is active, perform the second step of the encryption bit postion
- ; mitigation check. The ECX and EDX register contain data from RDRAND that
- ; was stored to memory in encrypted form. If the encryption bit position is
- ; valid, the contents of ECX and EDX will match the memory location.
- ;
- cmp dword[SEV_ES_WORK_AREA_RDRAND], ecx
- jne SevEncBitHlt
- cmp dword[SEV_ES_WORK_AREA_RDRAND + 4], edx
- jne SevEncBitHlt
-
- ;
- ; If SEV or SEV-ES is active, perform a quick sanity check against
- ; the reported encryption bit position. This is to help mitigate
- ; against attacks where the hypervisor reports an incorrect encryption
- ; bit position. If SEV is not active, this check will always succeed.
- ;
- ; The cmp instruction compares the first four bytes of the cmp instruction
- ; itself (which will be read decrypted if SEV or SEV-ES is active and the
- ; encryption bit position is valid) against the immediate within the
- ; instruction (an instruction fetch is always decrypted correctly by
- ; hardware) based on RIP relative addressing.
- ;
-InsnCompare:
- cmp dword[rel InsnCompare], 0xFFF63D81
- je GoodCompare
-
- ;
- ; The hypervisor provided an incorrect encryption bit position, do not
- ; proceed.
- ;
-SevEncBitHlt:
- cli
- hlt
- jmp SevEncBitHlt
-
-GoodCompare:
debugShowPostCode POSTCODE_64BIT_MODE

OneTimeCallRet Transition32FlatTo64Flat
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index 5fae8986d9da..ac365b114ee5 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -36,198 +36,97 @@ BITS 32
%define PAGE_PDP_ATTR (PAGE_ACCESSED + \
PAGE_READ_WRITE + \
PAGE_PRESENT)
-
-;
-; SEV-ES #VC exception handler support
-;
-; #VC handler local variable locations
-;
-%define VC_CPUID_RESULT_EAX 0
-%define VC_CPUID_RESULT_EBX 4
-%define VC_CPUID_RESULT_ECX 8
-%define VC_CPUID_RESULT_EDX 12
-%define VC_GHCB_MSR_EDX 16
-%define VC_GHCB_MSR_EAX 20
-%define VC_CPUID_REQUEST_REGISTER 24
-%define VC_CPUID_FUNCTION 28
-
-; #VC handler total local variable size
-;
-%define VC_VARIABLE_SIZE 32
-
-; #VC handler GHCB CPUID request/response protocol values
-;
-%define GHCB_CPUID_REQUEST 4
-%define GHCB_CPUID_RESPONSE 5
-%define GHCB_CPUID_REGISTER_SHIFT 30
-%define CPUID_INSN_LEN 2
-
-
-; Check if Secure Encrypted Virtualization (SEV) features are enabled.
-;
-; Register usage is tight in this routine, so multiple calls for the
-; same CPUID and MSR data are performed to keep things simple.
-;
-; Modified: EAX, EBX, ECX, EDX, ESP
;
-; If SEV is enabled then EAX will be at least 32.
-; If SEV is disabled then EAX will be zero.
+; Extra page tables built by Tdx guests
;
-CheckSevFeatures:
- ; Set the first byte of the workarea to zero to communicate to the SEC
- ; phase that SEV-ES is not enabled. If SEV-ES is enabled, the CPUID
- ; instruction will trigger a #VC exception where the first byte of the
- ; workarea will be set to one or, if CPUID is not being intercepted,
- ; the MSR check below will set the first byte of the workarea to one.
- mov byte[SEV_ES_WORK_AREA], 0
+TdxBuildExtraPageTables:
+ xor eax, eax
+ mov ecx, 0x400
+tdClearTdxPageTablesMemoryLoop:
+ mov dword [ecx * 4 + TDX_PT_ADDR (0) - 4], eax
+ loop tdClearTdxPageTablesMemoryLoop

+ ;xor edx, edx
;
- ; Set up exception handlers to check for SEV-ES
- ; Load temporary RAM stack based on PCDs (see SevEsIdtVmmComm for
- ; stack usage)
- ; Establish exception handlers
- ;
- mov esp, SEV_ES_VC_TOP_OF_STACK
- mov eax, ADDR_OF(Idtr)
- lidt [cs:eax]
-
- ; Check if we have a valid (0x8000_001F) CPUID leaf
- ; CPUID raises a #VC exception if running as an SEV-ES guest
- mov eax, 0x80000000
- cpuid
-
- ; This check should fail on Intel or Non SEV AMD CPUs. In future if
- ; Intel CPUs supports this CPUID leaf then we are guranteed to have exact
- ; same bit definition.
- cmp eax, 0x8000001f
- jl NoSev
-
- ; Check for SEV memory encryption feature:
- ; CPUID Fn8000_001F[EAX] - Bit 1
- ; CPUID raises a #VC exception if running as an SEV-ES guest
- mov eax, 0x8000001f
- cpuid
- bt eax, 1
- jnc NoSev
-
- ; Check if SEV memory encryption is enabled
- ; MSR_0xC0010131 - Bit 0 (SEV enabled)
- mov ecx, 0xc0010131
- rdmsr
- bt eax, 0
- jnc NoSev
-
- ; Check for SEV-ES memory encryption feature:
- ; CPUID Fn8000_001F[EAX] - Bit 3
- ; CPUID raises a #VC exception if running as an SEV-ES guest
- mov eax, 0x8000001f
- cpuid
- bt eax, 3
- jnc GetSevEncBit
-
- ; Check if SEV-ES is enabled
- ; MSR_0xC0010131 - Bit 1 (SEV-ES enabled)
- mov ecx, 0xc0010131
- rdmsr
- bt eax, 1
- jnc GetSevEncBit
-
- ; Set the first byte of the workarea to one to communicate to the SEC
- ; phase that SEV-ES is enabled.
- mov byte[SEV_ES_WORK_AREA], 1
-
-GetSevEncBit:
- ; Get pte bit position to enable memory encryption
- ; CPUID Fn8000_001F[EBX] - Bits 5:0
+ ; Top level Page Directory Pointers (1 * 256TB entry)
;
- and ebx, 0x3f
- mov eax, ebx
-
- ; The encryption bit position is always above 31
- sub ebx, 32
- jns SevSaveMask
+ mov dword[TDX_PT_ADDR (0)], PT_ADDR (0) + PAGE_PDP_ATTR
+ ;mov dword[TDX_PT_ADDR (4)], edx

- ; Encryption bit was reported as 31 or below, enter a HLT loop
-SevEncBitLowHlt:
- cli
- hlt
- jmp SevEncBitLowHlt
+ mov byte[TDX_WORK_AREA_PGTBL_READY], 1

-SevSaveMask:
- xor edx, edx
- bts edx, ebx
+ OneTimeCallRet TdxBuildExtraPageTables

- mov dword[SEV_ES_WORK_AREA_ENC_MASK], 0
- mov dword[SEV_ES_WORK_AREA_ENC_MASK + 4], edx
- jmp SevExit
-
-NoSev:
+;
+; Ghcb page tables built by SEV
+;
+SevBuildGhcbPageTables:
;
- ; Perform an SEV-ES sanity check by seeing if a #VC exception occurred.
+ ; The initial GHCB will live at GHCB_BASE and needs to be un-encrypted.
+ ; This requires the 2MB page for this range be broken down into 512 4KB
+ ; pages. All will be marked encrypted, except for the GHCB.
;
- cmp byte[SEV_ES_WORK_AREA], 0
- jz NoSevPass
+ mov ecx, (GHCB_BASE >> 21)
+ mov eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
+ mov [ecx * 8 + PT_ADDR (0x2000)], eax

;
- ; A #VC was received, yet CPUID indicates no SEV-ES support, something
- ; isn't right.
+ ; Page Table Entries (512 * 4KB entries => 2MB)
;
-NoSevEsVcHlt:
- cli
- hlt
- jmp NoSevEsVcHlt
-
-NoSevPass:
- xor eax, eax
+ mov ecx, 512
+pageTableEntries4kLoop:
+ mov eax, ecx
+ dec eax
+ shl eax, 12
+ add eax, GHCB_BASE & 0xFFE0_0000
+ add eax, PAGE_4K_PDE_ATTR
+ mov [ecx * 8 + GHCB_PT_ADDR - 8], eax
+ mov [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx
+ loop pageTableEntries4kLoop

-SevExit:
;
- ; Clear exception handlers and stack
+ ; Clear the encryption bit from the GHCB entry
;
- push eax
- mov eax, ADDR_OF(IdtrClear)
- lidt [cs:eax]
- pop eax
- mov esp, 0
-
- OneTimeCallRet CheckSevFeatures
-
-; Check if Secure Encrypted Virtualization - Encrypted State (SEV-ES) feature
-; is enabled.
-;
-; Modified: EAX
-;
-; If SEV-ES is enabled then EAX will be non-zero.
-; If SEV-ES is disabled then EAX will be zero.
-;
-IsSevEsEnabled:
- xor eax, eax
-
- ; During CheckSevFeatures, the SEV_ES_WORK_AREA was set to 1 if
- ; SEV-ES is enabled.
- cmp byte[SEV_ES_WORK_AREA], 1
- jne SevEsDisabled
+ mov ecx, (GHCB_BASE & 0x1F_FFFF) >> 12
+ mov [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0

- mov eax, 1
+ mov ecx, GHCB_SIZE / 4
+ xor eax, eax
+clearGhcbMemoryLoop:
+ mov dword[ecx * 4 + GHCB_BASE - 4], eax
+ loop clearGhcbMemoryLoop

-SevEsDisabled:
- OneTimeCallRet IsSevEsEnabled
+ OneTimeCallRet SevBuildGhcbPageTables

;
; Modified: EAX, EBX, ECX, EDX
;
SetCr3ForPageTables64:

- OneTimeCall CheckSevFeatures
xor edx, edx
+
+CheckTdx:
+ cmp dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
+ jnz CheckSev
+
+ ;
+ ; In Td guest, BSP builds the page table and set the flag of
+ ; TDX_WORK_AREA_PGTBL_READY. APs check this flag and then set
+ ; cr3 directly.
+ ;
+ cmp byte[TDX_WORK_AREA_PGTBL_READY], 1
+ jz SetCr3
+ jmp BuildPageTables
+
+CheckSev:
test eax, eax
- jz SevNotActive
+ jz BuildPageTables

; If SEV is enabled, C-bit is always above 31
sub eax, 32
bts edx, eax

-SevNotActive:
+BuildPageTables:

;
; For OVMF, build some initial page tables at
@@ -277,44 +176,22 @@ pageTableEntriesLoop:
mov [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
loop pageTableEntriesLoop

- OneTimeCall IsSevEsEnabled
- test eax, eax
- jz SetCr3
-
;
- ; The initial GHCB will live at GHCB_BASE and needs to be un-encrypted.
- ; This requires the 2MB page for this range be broken down into 512 4KB
- ; pages. All will be marked encrypted, except for the GHCB.
+ ; If it is Td guest, TdxExtraPageTable should be initialized as well
;
- mov ecx, (GHCB_BASE >> 21)
- mov eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
- mov [ecx * 8 + PT_ADDR (0x2000)], eax
+ cmp dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
+ jnz IsSevEs

- ;
- ; Page Table Entries (512 * 4KB entries => 2MB)
- ;
- mov ecx, 512
-pageTableEntries4kLoop:
- mov eax, ecx
- dec eax
- shl eax, 12
- add eax, GHCB_BASE & 0xFFE0_0000
- add eax, PAGE_4K_PDE_ATTR
- mov [ecx * 8 + GHCB_PT_ADDR - 8], eax
- mov [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx
- loop pageTableEntries4kLoop
+ OneTimeCall TdxBuildExtraPageTables
+ jmp SetCr3

- ;
- ; Clear the encryption bit from the GHCB entry
- ;
- mov ecx, (GHCB_BASE & 0x1F_FFFF) >> 12
- mov [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0
+IsSevEs:
+ ; During CheckSevFeatures, the SEV_ES_WORK_AREA was set to 1 if
+ ; SEV-ES is enabled.
+ cmp byte[SEV_ES_WORK_AREA], 1
+ jne SetCr3

- mov ecx, GHCB_SIZE / 4
- xor eax, eax
-clearGhcbMemoryLoop:
- mov dword[ecx * 4 + GHCB_BASE - 4], eax
- loop clearGhcbMemoryLoop
+ OneTimeCall SevBuildGhcbPageTables

SetCr3:
;
@@ -325,217 +202,4 @@ SetCr3:

OneTimeCallRet SetCr3ForPageTables64

-;
-; Start of #VC exception handling routines
-;

-SevEsIdtNotCpuid:
- ;
- ; Use VMGEXIT to request termination.
- ; 1 - #VC was not for CPUID
- ;
- mov eax, 1
- jmp SevEsIdtTerminate
-
-SevEsIdtNoCpuidResponse:
- ;
- ; Use VMGEXIT to request termination.
- ; 2 - GHCB_CPUID_RESPONSE not received
- ;
- mov eax, 2
-
-SevEsIdtTerminate:
- ;
- ; Use VMGEXIT to request termination. At this point the reason code is
- ; located in EAX, so shift it left 16 bits to the proper location.
- ;
- ; EAX[11:0] => 0x100 - request termination
- ; EAX[15:12] => 0x1 - OVMF
- ; EAX[23:16] => 0xXX - REASON CODE
- ;
- shl eax, 16
- or eax, 0x1100
- xor edx, edx
- mov ecx, 0xc0010130
- wrmsr
- ;
- ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
- ; mode, so work around this by temporarily switching to 64-bit mode.
- ;
-BITS 64
- rep vmmcall
-BITS 32
-
- ;
- ; We shouldn't come back from the VMGEXIT, but if we do, just loop.
- ;
-SevEsIdtHlt:
- hlt
- jmp SevEsIdtHlt
- iret
-
- ;
- ; Total stack usage for the #VC handler is 44 bytes:
- ; - 12 bytes for the exception IRET (after popping error code)
- ; - 32 bytes for the local variables.
- ;
-SevEsIdtVmmComm:
- ;
- ; If we're here, then we are an SEV-ES guest and this
- ; was triggered by a CPUID instruction
- ;
- ; Set the first byte of the workarea to one to communicate that
- ; a #VC was taken.
- mov byte[SEV_ES_WORK_AREA], 1
-
- pop ecx ; Error code
- cmp ecx, 0x72 ; Be sure it was CPUID
- jne SevEsIdtNotCpuid
-
- ; Set up local variable room on the stack
- ; CPUID function : + 28
- ; CPUID request register : + 24
- ; GHCB MSR (EAX) : + 20
- ; GHCB MSR (EDX) : + 16
- ; CPUID result (EDX) : + 12
- ; CPUID result (ECX) : + 8
- ; CPUID result (EBX) : + 4
- ; CPUID result (EAX) : + 0
- sub esp, VC_VARIABLE_SIZE
-
- ; Save the CPUID function being requested
- mov [esp + VC_CPUID_FUNCTION], eax
-
- ; The GHCB CPUID protocol uses the following mapping to request
- ; a specific register:
- ; 0 => EAX, 1 => EBX, 2 => ECX, 3 => EDX
- ;
- ; Set EAX as the first register to request. This will also be used as a
- ; loop variable to request all register values (EAX to EDX).
- xor eax, eax
- mov [esp + VC_CPUID_REQUEST_REGISTER], eax
-
- ; Save current GHCB MSR value
- mov ecx, 0xc0010130
- rdmsr
- mov [esp + VC_GHCB_MSR_EAX], eax
- mov [esp + VC_GHCB_MSR_EDX], edx
-
-NextReg:
- ;
- ; Setup GHCB MSR
- ; GHCB_MSR[63:32] = CPUID function
- ; GHCB_MSR[31:30] = CPUID register
- ; GHCB_MSR[11:0] = CPUID request protocol
- ;
- mov eax, [esp + VC_CPUID_REQUEST_REGISTER]
- cmp eax, 4
- jge VmmDone
-
- shl eax, GHCB_CPUID_REGISTER_SHIFT
- or eax, GHCB_CPUID_REQUEST
- mov edx, [esp + VC_CPUID_FUNCTION]
- mov ecx, 0xc0010130
- wrmsr
-
- ;
- ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
- ; mode, so work around this by temporarily switching to 64-bit mode.
- ;
-BITS 64
- rep vmmcall
-BITS 32
-
- ;
- ; Read GHCB MSR
- ; GHCB_MSR[63:32] = CPUID register value
- ; GHCB_MSR[31:30] = CPUID register
- ; GHCB_MSR[11:0] = CPUID response protocol
- ;
- mov ecx, 0xc0010130
- rdmsr
- mov ecx, eax
- and ecx, 0xfff
- cmp ecx, GHCB_CPUID_RESPONSE
- jne SevEsIdtNoCpuidResponse
-
- ; Save returned value
- shr eax, GHCB_CPUID_REGISTER_SHIFT
- mov [esp + eax * 4], edx
-
- ; Next register
- inc word [esp + VC_CPUID_REQUEST_REGISTER]
-
- jmp NextReg
-
-VmmDone:
- ;
- ; At this point we have all CPUID register values. Restore the GHCB MSR,
- ; set the return register values and return.
- ;
- mov eax, [esp + VC_GHCB_MSR_EAX]
- mov edx, [esp + VC_GHCB_MSR_EDX]
- mov ecx, 0xc0010130
- wrmsr
-
- mov eax, [esp + VC_CPUID_RESULT_EAX]
- mov ebx, [esp + VC_CPUID_RESULT_EBX]
- mov ecx, [esp + VC_CPUID_RESULT_ECX]
- mov edx, [esp + VC_CPUID_RESULT_EDX]
-
- add esp, VC_VARIABLE_SIZE
-
- ; Update the EIP value to skip over the now handled CPUID instruction
- ; (the CPUID instruction has a length of 2)
- add word [esp], CPUID_INSN_LEN
- iret
-
-ALIGN 2
-
-Idtr:
- dw IDT_END - IDT_BASE - 1 ; Limit
- dd ADDR_OF(IDT_BASE) ; Base
-
-IdtrClear:
- dw 0 ; Limit
- dd 0 ; Base
-
-ALIGN 16
-
-;
-; The Interrupt Descriptor Table (IDT)
-; This will be used to determine if SEV-ES is enabled. Upon execution
-; of the CPUID instruction, a VMM Communication Exception will occur.
-; This will tell us if SEV-ES is enabled. We can use the current value
-; of the GHCB MSR to determine the SEV attributes.
-;
-IDT_BASE:
-;
-; Vectors 0 - 28 (No handlers)
-;
-%rep 29
- dw 0 ; Offset low bits 15..0
- dw 0x10 ; Selector
- db 0 ; Reserved
- db 0x8E ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
- dw 0 ; Offset high bits 31..16
-%endrep
-;
-; Vector 29 (VMM Communication Exception)
-;
- dw (ADDR_OF(SevEsIdtVmmComm) & 0xffff) ; Offset low bits 15..0
- dw 0x10 ; Selector
- db 0 ; Reserved
- db 0x8E ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
- dw (ADDR_OF(SevEsIdtVmmComm) >> 16) ; Offset high bits 31..16
-;
-; Vectors 30 - 31 (No handlers)
-;
-%rep 2
- dw 0 ; Offset low bits 15..0
- dw 0x10 ; Selector
- db 0 ; Reserved
- db 0x8E ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
- dw 0 ; Offset high bits 31..16
-%endrep
-IDT_END:
diff --git a/OvmfPkg/ResetVector/Main.asm b/OvmfPkg/ResetVector/Main.asm
index dbebfb9e5d29..0418e0294920 100644
--- a/OvmfPkg/ResetVector/Main.asm
+++ b/OvmfPkg/ResetVector/Main.asm
@@ -36,6 +36,20 @@ Main16:

BITS 32

+%ifdef ARCH_X64
+
+ jmp SearchBfv
+
+;
+; Entry point of Main32
+;
+Main32:
+
+ OneTimeCall Init32
+
+%endif
+
+SearchBfv:
;
; Search for the Boot Firmware Volume (BFV)
;
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 0ac6d7a6fd33..ade8ce6f08a5 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -132,6 +132,10 @@
%define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))

%include "X64/TdxMetadata.asm"
+ %include "Ia32/Init32.asm"
+ %include "Ia32/IntelTdx.asm"
+ %include "Ia32/AmdSev.asm"
+ %include "Ia32/ReloadFlat32.asm"

%include "Ia32/Flat32ToFlat64.asm"
%include "Ia32/PageTables64.asm"
--
2.29.2.windows.2

Join devel@edk2.groups.io to automatically receive all group messages.