Date   

[PATCH 2/3] OvmfPkg/ResetVector: add the macro to invoke MSR protocol based VMGEXIT

Brijesh Singh
 

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

The upcoming SEV-SNP support will need to make a few additional MSR
protocol based VMGEXIT's. Add a macro that wraps the common setup and
response validation logic in one place to keep the code readable.

While at it, define SEV_STATUS_MSR that will be used to get the SEV STATUS
MSR instead of open coding it.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Suggested-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
OvmfPkg/ResetVector/Ia32/AmdSev.asm | 71 +++++++++++++++++++----------
1 file changed, 47 insertions(+), 24 deletions(-)

diff --git a/OvmfPkg/ResetVector/Ia32/AmdSev.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
index b32dd3b5d656..2c478cda314b 100644
--- a/OvmfPkg/ResetVector/Ia32/AmdSev.asm
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -36,6 +36,44 @@ BITS 32
%define CPUID_INSN_LEN 2


+%define SEV_GHCB_MSR 0xc0010130
+%define SEV_STATUS_MSR 0xc0010131
+
+; Macro is used to issue the MSR protocol based VMGEXIT. The caller is
+; responsible to populate values in the EDX:EAX registers. After the vmmcall
+; returns, it verifies that the response code matches with the expected
+; code. If it does not match then terminate the guest. The result of request
+; is returned in the EDX:EAX.
+;
+; args 1:Request code, 2: Response code
+%macro VmgExit 2
+ ;
+ ; Add request code:
+ ; GHCB_MSR[11:0] = Request code
+ or eax, %1
+
+ mov ecx, SEV_GHCB_MSR
+ 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
+
+ mov ecx, SEV_GHCB_MSR
+ rdmsr
+
+ ;
+ ; Verify the reponse code, if it does not match then request to terminate
+ ; GHCB_MSR[11:0] = Response code
+ mov ecx, eax
+ and ecx, 0xfff
+ cmp ecx, %2
+ jne SevEsUnexpectedRespTerminate
+%endmacro
+
; Check if Secure Encrypted Virtualization (SEV) features are enabled.
;
; Register usage is tight in this routine, so multiple calls for the
@@ -85,7 +123,7 @@ CheckSevFeatures:

; Check if SEV memory encryption is enabled
; MSR_0xC0010131 - Bit 0 (SEV enabled)
- mov ecx, 0xc0010131
+ mov ecx, SEV_STATUS_MSR
rdmsr
bt eax, 0
jnc NoSev
@@ -100,7 +138,7 @@ CheckSevFeatures:

; Check if SEV-ES is enabled
; MSR_0xC0010131 - Bit 1 (SEV-ES enabled)
- mov ecx, 0xc0010131
+ mov ecx, SEV_STATUS_MSR
rdmsr
bt eax, 1
jnc GetSevEncBit
@@ -197,10 +235,10 @@ SevEsIdtNotCpuid:
mov eax, 1
jmp SevEsIdtTerminate

-SevEsIdtNoCpuidResponse:
+SevEsUnexpectedRespTerminate:
;
; Use VMGEXIT to request termination.
- ; 2 - GHCB_CPUID_RESPONSE not received
+ ; 2 - Unexpected Response is received
;
mov eax, 2

@@ -216,7 +254,7 @@ SevEsIdtTerminate:
shl eax, 16
or eax, 0x1100
xor edx, edx
- mov ecx, 0xc0010130
+ mov ecx, SEV_GHCB_MSR
wrmsr
;
; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
@@ -276,7 +314,7 @@ SevEsIdtVmmComm:
mov [esp + VC_CPUID_REQUEST_REGISTER], eax

; Save current GHCB MSR value
- mov ecx, 0xc0010130
+ mov ecx, SEV_GHCB_MSR
rdmsr
mov [esp + VC_GHCB_MSR_EAX], eax
mov [esp + VC_GHCB_MSR_EDX], edx
@@ -293,31 +331,16 @@ NextReg:
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
+ VmgExit GHCB_CPUID_REQUEST, GHCB_CPUID_RESPONSE

;
- ; Read GHCB MSR
+ ; Response 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
@@ -335,7 +358,7 @@ VmmDone:
;
mov eax, [esp + VC_GHCB_MSR_EAX]
mov edx, [esp + VC_GHCB_MSR_EDX]
- mov ecx, 0xc0010130
+ mov ecx, SEV_GHCB_MSR
wrmsr

mov eax, [esp + VC_CPUID_RESULT_EAX]
--
2.17.1


[PATCH 1/3] OvmfPkg/ResetVector: move SEV specific code in a separate file

Brijesh Singh
 

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

The PageTables64.asm was created to provide routines to set the CR3
register for 64-bit paging. During the SEV support, it grew to include a
lot of the SEV stuff. Before adding more SEV features, let's move all
the SEV-specific routines into a separate file.

No functionality change intended.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Suggested-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
.../Ia32/{PageTables64.asm => AmdSev.asm} | 140 -------
OvmfPkg/ResetVector/Ia32/PageTables64.asm | 391 ------------------
OvmfPkg/ResetVector/ResetVector.nasmb | 1 +
3 files changed, 1 insertion(+), 531 deletions(-)
copy OvmfPkg/ResetVector/Ia32/{PageTables64.asm => AmdSev.asm} (71%)

diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
similarity index 71%
copy from OvmfPkg/ResetVector/Ia32/PageTables64.asm
copy to OvmfPkg/ResetVector/Ia32/AmdSev.asm
index 5fae8986d9da..b32dd3b5d656 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -10,33 +10,6 @@

BITS 32

-%define PAGE_PRESENT 0x01
-%define PAGE_READ_WRITE 0x02
-%define PAGE_USER_SUPERVISOR 0x04
-%define PAGE_WRITE_THROUGH 0x08
-%define PAGE_CACHE_DISABLE 0x010
-%define PAGE_ACCESSED 0x020
-%define PAGE_DIRTY 0x040
-%define PAGE_PAT 0x080
-%define PAGE_GLOBAL 0x0100
-%define PAGE_2M_MBO 0x080
-%define PAGE_2M_PAT 0x01000
-
-%define PAGE_4K_PDE_ATTR (PAGE_ACCESSED + \
- PAGE_DIRTY + \
- PAGE_READ_WRITE + \
- PAGE_PRESENT)
-
-%define PAGE_2M_PDE_ATTR (PAGE_2M_MBO + \
- PAGE_ACCESSED + \
- PAGE_DIRTY + \
- PAGE_READ_WRITE + \
- PAGE_PRESENT)
-
-%define PAGE_PDP_ATTR (PAGE_ACCESSED + \
- PAGE_READ_WRITE + \
- PAGE_PRESENT)
-
;
; SEV-ES #VC exception handler support
;
@@ -213,119 +186,6 @@ IsSevEsEnabled:
SevEsDisabled:
OneTimeCallRet IsSevEsEnabled

-;
-; Modified: EAX, EBX, ECX, EDX
-;
-SetCr3ForPageTables64:
-
- OneTimeCall CheckSevFeatures
- xor edx, edx
- test eax, eax
- jz SevNotActive
-
- ; If SEV is enabled, C-bit is always above 31
- sub eax, 32
- bts edx, eax
-
-SevNotActive:
-
- ;
- ; For OVMF, build some initial page tables at
- ; PcdOvmfSecPageTablesBase - (PcdOvmfSecPageTablesBase + 0x6000).
- ;
- ; This range should match with PcdOvmfSecPageTablesSize which is
- ; declared in the FDF files.
- ;
- ; At the end of PEI, the pages tables will be rebuilt into a
- ; more permanent location by DxeIpl.
- ;
-
- mov ecx, 6 * 0x1000 / 4
- xor eax, eax
-clearPageTablesMemoryLoop:
- mov dword[ecx * 4 + PT_ADDR (0) - 4], eax
- loop clearPageTablesMemoryLoop
-
- ;
- ; Top level Page Directory Pointers (1 * 512GB entry)
- ;
- mov dword[PT_ADDR (0)], PT_ADDR (0x1000) + PAGE_PDP_ATTR
- mov dword[PT_ADDR (4)], edx
-
- ;
- ; Next level Page Directory Pointers (4 * 1GB entries => 4GB)
- ;
- mov dword[PT_ADDR (0x1000)], PT_ADDR (0x2000) + PAGE_PDP_ATTR
- mov dword[PT_ADDR (0x1004)], edx
- mov dword[PT_ADDR (0x1008)], PT_ADDR (0x3000) + PAGE_PDP_ATTR
- mov dword[PT_ADDR (0x100C)], edx
- mov dword[PT_ADDR (0x1010)], PT_ADDR (0x4000) + PAGE_PDP_ATTR
- mov dword[PT_ADDR (0x1014)], edx
- mov dword[PT_ADDR (0x1018)], PT_ADDR (0x5000) + PAGE_PDP_ATTR
- mov dword[PT_ADDR (0x101C)], edx
-
- ;
- ; Page Table Entries (2048 * 2MB entries => 4GB)
- ;
- mov ecx, 0x800
-pageTableEntriesLoop:
- mov eax, ecx
- dec eax
- shl eax, 21
- add eax, PAGE_2M_PDE_ATTR
- mov [ecx * 8 + PT_ADDR (0x2000 - 8)], eax
- 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.
- ;
- mov ecx, (GHCB_BASE >> 21)
- mov eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
- mov [ecx * 8 + PT_ADDR (0x2000)], eax
-
- ;
- ; 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
-
- ;
- ; 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
-
- mov ecx, GHCB_SIZE / 4
- xor eax, eax
-clearGhcbMemoryLoop:
- mov dword[ecx * 4 + GHCB_BASE - 4], eax
- loop clearGhcbMemoryLoop
-
-SetCr3:
- ;
- ; Set CR3 now that the paging structures are available
- ;
- mov eax, PT_ADDR (0)
- mov cr3, eax
-
- OneTimeCallRet SetCr3ForPageTables64
-
-;
; Start of #VC exception handling routines
;

diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index 5fae8986d9da..eacdb69ddb9f 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -37,182 +37,6 @@ BITS 32
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.
-;
-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
-
- ;
- ; 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
- ;
- and ebx, 0x3f
- mov eax, ebx
-
- ; The encryption bit position is always above 31
- sub ebx, 32
- jns SevSaveMask
-
- ; Encryption bit was reported as 31 or below, enter a HLT loop
-SevEncBitLowHlt:
- cli
- hlt
- jmp SevEncBitLowHlt
-
-SevSaveMask:
- xor edx, edx
- bts edx, ebx
-
- mov dword[SEV_ES_WORK_AREA_ENC_MASK], 0
- mov dword[SEV_ES_WORK_AREA_ENC_MASK + 4], edx
- jmp SevExit
-
-NoSev:
- ;
- ; Perform an SEV-ES sanity check by seeing if a #VC exception occurred.
- ;
- cmp byte[SEV_ES_WORK_AREA], 0
- jz NoSevPass
-
- ;
- ; A #VC was received, yet CPUID indicates no SEV-ES support, something
- ; isn't right.
- ;
-NoSevEsVcHlt:
- cli
- hlt
- jmp NoSevEsVcHlt
-
-NoSevPass:
- xor eax, eax
-
-SevExit:
- ;
- ; Clear exception handlers and stack
- ;
- 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 eax, 1
-
-SevEsDisabled:
- OneTimeCallRet IsSevEsEnabled
-
;
; Modified: EAX, EBX, ECX, EDX
;
@@ -324,218 +148,3 @@ SetCr3:
mov cr3, eax

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/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 5fbacaed5f9d..8a3269cfc212 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -77,6 +77,7 @@
%define SEV_ES_WORK_AREA_ENC_MASK (FixedPcdGet32 (PcdSevEsWorkAreaBase) + 16)
%define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
%include "Ia32/Flat32ToFlat64.asm"
+%include "Ia32/AmdSev.asm"
%include "Ia32/PageTables64.asm"
%endif

--
2.17.1


[PATCH 0/3] Move the SEV specific changes in ResetVector in separate file

Brijesh Singh
 

The PageTable64.asm was created to build the initial page table,
but over the time it grew to include bunch of the SEV specific code
which does not directly manipulates the pagetable. Before adding more
to it, let's move all the SEV-specific routines into a separate file.

The series is taken from SNP RFCv4. And there is no functionality change
intended. Its just moving the code from one place to another.

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: Laszlo Ersek <lersek@redhat.com>

The full branch is available at:
https://github.com/AMDESE/ovmf/pull/new/refactor-reset-vector

Brijesh Singh (3):
OvmfPkg/ResetVector: move SEV specific code in a separate file
OvmfPkg/ResetVector: add the macro to invoke MSR protocol based
VMGEXIT
OvmfPkg/ResetVector: add the macro to request guest termination

.../Ia32/{PageTables64.asm => AmdSev.asm} | 292 ++++---------
OvmfPkg/ResetVector/Ia32/PageTables64.asm | 391 ------------------
OvmfPkg/ResetVector/ResetVector.nasmb | 1 +
3 files changed, 90 insertions(+), 594 deletions(-)
copy OvmfPkg/ResetVector/Ia32/{PageTables64.asm => AmdSev.asm} (67%)

--
2.17.1


Re: [RFC PATCH] OvmfPkg/OvmfXen: set PcdAcpiS3Enable at initialization

Anthony PERARD
 

On Wed, Jul 21, 2021 at 02:56:46PM +0800, Gary Lin wrote:
BTW, it seems to me that QEMU fwcfg is only used for Xen Direct Kernel
Boot. However, per xl.cfg manpage, it's possible to turn on or off S3
support by setting "acpi_s3" in xl.cfg, but PcdAcpiS3Enable wasn't set
in the current OvmfXen implementation. Just wonder how xl passes the S3
support bit to OvmfXen.
It doesn't. "acpi_s3" doesn't have any control over PcdAcpiS3Enable, and
doesn't have any control over QEMU, so QEMU would probably always say S3
is available.

What happen when "acpi_s3" is set or not is:
- the value is stored in xenstore
- hvmloader (which runs before OVMF) read the xenstore value and
adds the appropriate ACPI SSDT table to allow S3.

Cheers,

--
Anthony PERARD


Re: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector

Brijesh Singh
 

Hi Min,

This refactoring is already done by the SNP patch series.

https://edk2.groups.io/g/devel/message/77336?p=,,,20,0,0,0::Created,,posterid%3A5969970,20,2,20,83891510

It appears that you are also pulling in some of TDX logic inside the
AMDSev.asm such as

;
+PostJump64BitAndLandHereSev:
+
+ ;
+ ; If it is Tdx guest, jump to exit point directly.
+ ; This is because following code may access the memory region which has
+ ; not been accepted. It is not allowed in Tdx guests.
+ ;
+ mov eax, dword[TDX_WORK_AREA]
+ cmp eax, 0x47584454 ; 'TDXG'
+ jz GoodCompare

Why we are referring the TDX workarea inside the AmdSev.asm ?

I will take out my refactoring patch outside of the SNP series and
submit it so that you can build on top of. This will simplify review
process.

thanks

On 7/27/21 12:42 AM, Min Xu wrote:
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

AmdSev.asm includes below routines:
- CheckSevFeatures
Check if Secure Encrypted Virtualization (SEV) features are enabled.
- PreSetCr3ForPageTables64Sev
It is called before SetCr3ForPageTables64 in SEV guests.
- PostSetCr3PageTables64Sev
It is called after SetCr3PageTables64 in SEV guests.
- PostJump64BitAndLandHereSev
It is called after Jump64BitAndLandHere in SEV guests.
- #VC exception handling routines

These routines are extracted from PageTables64.asm and Flat32ToFlat64.asm
Need AMD engineers' help to review/validate the patch so that there is
no regression. Thanks in advance!

Note:
In above Pre/Post routines, dword[TDX_WORK_AREA] should be checked
to see if it is 'TDXG' (Tdx guests). This is because some memory region
for example, byte[SEV_ES_WORK_AREA] cannot be accessed in Tdx guests.
Tdx requires that any memory region to be accessed should be accepted
first or initialized by host VMM before Td guest is launched.

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/Ia32/AmdSev.asm | 526 ++++++++++++++++++++++++++++
1 file changed, 526 insertions(+)
create mode 100644 OvmfPkg/ResetVector/Ia32/AmdSev.asm

diff --git a/OvmfPkg/ResetVector/Ia32/AmdSev.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
new file mode 100644
index 000000000000..962b7e169c61
--- /dev/null
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -0,0 +1,526 @@
+;------------------------------------------------------------------------------
+; @file
+; AMD SEV routines
+;
+; Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+
+BITS 32
+;
+; 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.
+;
+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
+
+ ;
+ ; 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
+ ;
+ and ebx, 0x3f
+ mov eax, ebx
+
+ ; The encryption bit position is always above 31
+ sub ebx, 32
+ jns SevSaveMask
+
+ ; Encryption bit was reported as 31 or below, enter a HLT loop
+SevEncBitLowHlt:
+ cli
+ hlt
+ jmp SevEncBitLowHlt
+
+SevSaveMask:
+ xor edx, edx
+ bts edx, ebx
+
+ mov dword[SEV_ES_WORK_AREA_ENC_MASK], 0
+ mov dword[SEV_ES_WORK_AREA_ENC_MASK + 4], edx
+ jmp SevExit
+
+NoSev:
+ ;
+ ; Perform an SEV-ES sanity check by seeing if a #VC exception occurred.
+ ;
+ cmp byte[SEV_ES_WORK_AREA], 0
+ jz NoSevPass
+
+ ;
+ ; A #VC was received, yet CPUID indicates no SEV-ES support, something
+ ; isn't right.
+ ;
+NoSevEsVcHlt:
+ cli
+ hlt
+ jmp NoSevEsVcHlt
+
+NoSevPass:
+ xor eax, eax
+
+SevExit:
+ ;
+ ; Clear exception handlers and stack
+ ;
+ push eax
+ mov eax, ADDR_OF(IdtrClear)
+ lidt [cs:eax]
+ pop eax
+ mov esp, 0
+
+ OneTimeCallRet CheckSevFeatures
+
+;
+; Called before SetCr3ForPageTables64 in SEV guests
+;
+; Modified: EAX, EBX, ECX, EDX, ESP
+;
+PreSetCr3ForPageTables64Sev:
+ ; In Tdx TDX_WORK_AREA was set to 'TDXG'.
+ ; CheckSevFeatures cannot be called in Tdx guest because SEV_ES_WORK_AREA
+ ; cannot be accessed in this situation. Any memory region to be accessed
+ ; in Td guest should be accepted first.
+ cmp dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
+ jz ExitPreSetCr3ForPageTables64Sev
+
+ OneTimeCall CheckSevFeatures
+
+ExitPreSetCr3ForPageTables64Sev:
+ OneTimeCallRet PreSetCr3ForPageTables64Sev
+
+;
+; It is called in SEV after SetCr3PageTables64
+;
+; Modified: EAX, EBX, ECX, EDX, ESP
+;
+PostSetCr3PageTables64Sev:
+ ; In Tdx TDX_WORK_AREA was set to 'TDXG'.
+ ; CheckSevFeatures cannot be called in Tdx because SEV_ES_WORK_AREA
+ ; cannot be accessed in this situation. Any memory region to be accessed
+ ; in Td guest should be accepted first.
+ cmp dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
+ jz ExitPostSetCr3PageTables64Sev
+
+ mov eax, cr4
+ bts eax, 5 ; enable PAE
+ mov cr4, eax
+
+ 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
+
+ExitPostSetCr3PageTables64Sev:
+
+ OneTimeCallRet PostSetCr3PageTables64Sev
+
+;
+; 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:
+
+BITS 64
+
+;
+; Called after Jump64BitAndLandHere
+;
+PostJump64BitAndLandHereSev:
+
+ ;
+ ; If it is Tdx guest, jump to exit point directly.
+ ; This is because following code may access the memory region which has
+ ; not been accepted. It is not allowed in Tdx guests.
+ ;
+ mov eax, dword[TDX_WORK_AREA]
+ cmp eax, 0x47584454 ; 'TDXG'
+ jz GoodCompare
+
+ ;
+ ; Check if the second step of the SEV-ES mitigation is to be performed.
+ ;
+ test ebx, ebx
+ jz InsnCompare
+
+ ;
+ ; 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:
+ OneTimeCallRet PostJump64BitAndLandHereSev


[PATCH v1] UefiCpuPkg/CpuCacheInfoLib: Sort CpuCacheInfo array

Jason Lou
 

From: Jason <yun.lou@intel.com>

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3508

Sort the CpuCacheInfo array by the core type values from largest to
smallest.

Signed-off-by: Jason Lou <yun.lou@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
---
UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c | 67 ++++++++=
+++++++++++-
UefiCpuPkg/Include/Library/CpuCacheInfoLib.h | 3 +-
UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf | 4 +-
UefiCpuPkg/Library/CpuCacheInfoLib/InternalCpuCacheInfoLib.h | 1 +
UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf | 4 +-
5 files changed, 75 insertions(+), 4 deletions(-)

diff --git a/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c b/UefiCpu=
Pkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c
index 126ee0da86..fa4850c4fe 100644
--- a/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c
+++ b/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c
@@ -37,6 +37,69 @@ CpuCacheInfoPrintCpuCacheInfoTable (
DEBUG ((DEBUG_INFO, "+-------+------------------------------------------=
--------------------------------------------+\n"));=0D
}=0D
=0D
+/**=0D
+ Function to compare core type for use in QuickSort.=0D
+=0D
+ @param[in] Buffer1 pointer to core type poiner to compare=0D
+ @param[in] Buffer2 pointer to second core type pointer to c=
ompare=0D
+=0D
+ @retval 0 Buffer1 equal to Buffer2=0D
+ @retval 1 Buffer1 is less than Buffer2=0D
+ @retval -1 Buffer1 is greater than Buffer2=0D
+**/=0D
+INTN=0D
+EFIAPI=0D
+CpuCacheInfoCompareCoreType (=0D
+ IN CONST VOID *Buffer1,=0D
+ IN CONST VOID *Buffer2=0D
+ )=0D
+{=0D
+ if (((CPU_CACHE_INFO*)Buffer1)->CoreType =3D=3D ((CPU_CACHE_INFO*)Buffer=
2)->CoreType) {=0D
+ return 0;=0D
+ } else if (((CPU_CACHE_INFO*)Buffer1)->CoreType < ((CPU_CACHE_INFO*)Buff=
er2)->CoreType) {=0D
+ return 1;=0D
+ } else {=0D
+ return -1;=0D
+ }=0D
+}=0D
+=0D
+/**=0D
+ Sort CpuCacheInfo array by the core type values from largest to smallest=
.=0D
+=0D
+ @param[in, out] CpuCacheInfo Pointer to the CpuCacheInfo array.=0D
+ @param[in] CpuCacheInfoCount The length of CpuCacheInfo array.=0D
+=0D
+**/=0D
+VOID=0D
+CpuCacheInfoSort (=0D
+ IN OUT CPU_CACHE_INFO *CpuCacheInfo,=0D
+ IN UINTN CpuCacheInfoCount=0D
+ )=0D
+{=0D
+ UINTN Index;=0D
+ UINTN NextIndex;=0D
+ UINT32 CurrentPackage;=0D
+ UINT8 CacheInfoCountPerPackage;=0D
+=0D
+ for (Index =3D 0; Index < CpuCacheInfoCount; Index +=3D CacheInfoCountPe=
rPackage) {=0D
+ //=0D
+ // Calculate the number of CpuCacheInfo current processor has.=0D
+ //=0D
+ CurrentPackage =3D CpuCacheInfo[Index].Package;=0D
+ CacheInfoCountPerPackage =3D 1;=0D
+ for (NextIndex =3D Index + 1; NextIndex < CpuCacheInfoCount; NextIndex=
++) {=0D
+ if (CurrentPackage =3D=3D CpuCacheInfo[NextIndex].Package) {=0D
+ CacheInfoCountPerPackage++;=0D
+ }=0D
+ }=0D
+=0D
+ //=0D
+ // Sort CpuCacheInfo for current processor by the core type values fro=
m largest to smallest.=0D
+ //=0D
+ PerformQuickSort (&CpuCacheInfo[Index], CacheInfoCountPerPackage, size=
of (*CpuCacheInfo), (SORT_COMPARE) CpuCacheInfoCompareCoreType);=0D
+ }=0D
+}=0D
+=0D
/**=0D
Get the total number of package and package ID in the platform.=0D
=0D
@@ -325,6 +388,7 @@ CpuCacheInfoCollectCpuCacheInfoData (
if (*CacheInfoCount < LocalCacheInfoCount) {=0D
Status =3D EFI_BUFFER_TOO_SMALL;=0D
} else {=0D
+ CpuCacheInfoSort (LocalCacheInfo, LocalCacheInfoCount);=0D
CopyMem (CacheInfo, LocalCacheInfo, sizeof (*CacheInfo) * LocalCacheIn=
foCount);=0D
DEBUG_CODE (=0D
CpuCacheInfoPrintCpuCacheInfoTable (CacheInfo, LocalCacheInfoCount);=
=0D
@@ -340,7 +404,8 @@ CpuCacheInfoCollectCpuCacheInfoData (
}=0D
=0D
/**=0D
- Get CpuCacheInfo data array.=0D
+ Get CpuCacheInfo data array. The data array is sorted by CPU package ID =
from smallest to largest,=0D
+ by core type from largest to smallest and by cache level from smallest t=
o largest.=0D
=0D
@param[in, out] CpuCacheInfo Pointer to the CpuCacheInfo array.=0D
@param[in, out] CpuCacheInfoCount As input, point to the length of res=
ponse CpuCacheInfo array.=0D
diff --git a/UefiCpuPkg/Include/Library/CpuCacheInfoLib.h b/UefiCpuPkg/Incl=
ude/Library/CpuCacheInfoLib.h
index a66152bce0..d813f53bf7 100644
--- a/UefiCpuPkg/Include/Library/CpuCacheInfoLib.h
+++ b/UefiCpuPkg/Include/Library/CpuCacheInfoLib.h
@@ -59,7 +59,8 @@ typedef struct {
} CPU_CACHE_INFO;=0D
=0D
/**=0D
- Get CpuCacheInfo data array.=0D
+ Get CpuCacheInfo data array. The data array is sorted by CPU package ID =
from smallest to largest,=0D
+ by core type from largest to smallest and by cache level from smallest t=
o largest.=0D
=0D
@param[in, out] CpuCacheInfo Pointer to the CpuCacheInfo array.=0D
@param[in, out] CpuCacheInfoCount As input, point to the length of res=
ponse CpuCacheInfo array.=0D
diff --git a/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf b/Ue=
fiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf
index c481080e49..c3d3f1e799 100644
--- a/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf
+++ b/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf
@@ -3,7 +3,7 @@
#=0D
# Provides cache info for each package, core type, cache level and cache =
type.=0D
#=0D
-# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>=0D
+# Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>=
=0D
#=0D
# SPDX-License-Identifier: BSD-2-Clause-Patent=0D
#=0D
@@ -25,6 +25,7 @@
=0D
[Packages]=0D
MdePkg/MdePkg.dec=0D
+ MdeModulePkg/MdeModulePkg.dec=0D
UefiCpuPkg/UefiCpuPkg.dec=0D
=0D
[LibraryClasses]=0D
@@ -33,6 +34,7 @@
BaseMemoryLib=0D
MemoryAllocationLib=0D
UefiBootServicesTableLib=0D
+ SortLib=0D
=0D
[Protocols]=0D
gEfiMpServiceProtocolGuid=0D
diff --git a/UefiCpuPkg/Library/CpuCacheInfoLib/InternalCpuCacheInfoLib.h b=
/UefiCpuPkg/Library/CpuCacheInfoLib/InternalCpuCacheInfoLib.h
index b6e6ae5bc5..089d259b3f 100644
--- a/UefiCpuPkg/Library/CpuCacheInfoLib/InternalCpuCacheInfoLib.h
+++ b/UefiCpuPkg/Library/CpuCacheInfoLib/InternalCpuCacheInfoLib.h
@@ -17,6 +17,7 @@
#include <Library/DebugLib.h>=0D
#include <Library/BaseMemoryLib.h>=0D
#include <Library/MemoryAllocationLib.h>=0D
+#include <Library/SortLib.h>=0D
#include <Library/CpuCacheInfoLib.h>=0D
=0D
typedef struct {=0D
diff --git a/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf b/Ue=
fiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf
index 0c73015cac..0864497849 100644
--- a/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf
+++ b/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf
@@ -3,7 +3,7 @@
#=0D
# Provides cache info for each package, core type, cache level and cache =
type.=0D
#=0D
-# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>=0D
+# Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>=
=0D
#=0D
# SPDX-License-Identifier: BSD-2-Clause-Patent=0D
#=0D
@@ -25,6 +25,7 @@
=0D
[Packages]=0D
MdePkg/MdePkg.dec=0D
+ MdeModulePkg/MdeModulePkg.dec=0D
UefiCpuPkg/UefiCpuPkg.dec=0D
=0D
[LibraryClasses]=0D
@@ -33,6 +34,7 @@
BaseMemoryLib=0D
MemoryAllocationLib=0D
PeiServicesTablePointerLib=0D
+ SortLib=0D
=0D
[Ppis]=0D
gEdkiiPeiMpServices2PpiGuid=0D
--=20
2.28.0.windows.1


Re: [PATCH v2 0/4] ArmPlatformPkg: Add support to generate HEST ACPI table

Sami Mujawar
 

Hi Omkar,

I will pick this up for review this week.

Regards,

Sami Mujawar

On 26/07/2021, 15:52, "Omkar Kulkarni" <Omkar.Kulkarni@arm.com> wrote:

Gentle reminder to review this patch series.

Regards,
Omkar

Changes since v1:
> - Helper added for HEST ACPI table generation.
> - Rebased to the latest upstream code.
>
> Hardware Error Source Table (HEST)[1] and Software Delegated Exception
> Interface
> (SDEI)[2] ACPI tables are used to acomplish firmware first error handling.This
> patch series introduces a framework to build and install the HEST ACPI table
> dynamically.
>
> The following figure illustrates the possible usage of the dyanamic
> generation of HEST ACPI table.
>
> NS | S
> +--------------------------------------+--------------------------------------+
> | | |
> |+-------------------------------------+---------------------+ |
> || +---------------------+--------------------+| |
> || | | || |
> || +-----------+ |+------------------+ | +-----------------+|| +-------------+|
> || |HestTable | || HestErrorSource | | | HestErrorSource ||| | DMC-620
> ||
> || | DXE | || DXE | | | StandaloneMM ||| |Standalone MM||
> || +-----------+ |+------------------+ | +-----------------+|| +-------------+|
> || |GHESv2 | || |
> || +---------------------+--------------------+| |
> || +--------------------+ | | |
> || |PlatformErrorHandler| | | |
> || | DXE | | | |
> || +--------------------+ | | |
> ||FF FWK | | |
> |+-------------------------------------+---------------------+ |
> | | |
> +--------------------------------------+--------------------------------------+
> |
> Figure: Firmware First Error Handling approach.
>
> All the hardware error sources are added to HEST table as GHESv2[3] error
> source
> descriptors. The framework comprises of following DXE and MM drivers:
>
> - HestTableDxe:
> Builds HEST table header and allows appending error source descriptors to
> the
> HEST table. Also provides protocol interface to install the built HEST table.
>
> - HestErrorSourceDxe & HestErrorSourceStandaloneMM:
> These two drivers together retrieve all possible error source descriptors of
> type GHESv2 from the MM drivers implementing HEST Error Source
> Descriptor
> protocol. Once all the descriptors are collected HestErrorSourceDxe
> appends
> it to HEST table using HestTableDxe driver.
>
> - PlatformErrorHandlerDxe:
> Builds and installs SDEI ACPI table. This driver does not initialize(load)
> until HestErrorSourceDxe driver has finished appending all possible GHESv2
> error source descriptors to the HEST table. Once that is complete using the
> HestTableDxe driver it installs the HEST table.
>
> This patch series provides reference implementation for DMC-620 Dynamic
> Memory
> Controller[4] that has RAS feature enabled. This is platform code
> implemented as Standalone MM driver in edk2-platforms.
>
> References:
> [1] : ACPI 6.3, Table 18-382, Hardware Error Source Table
> [2] : SDEI Platform Design Document, revision b, 10 Appendix C, ACPI table
> definitions for SDEI
> [3] : ACPI Reference Specification 6.3, Table 18-393 GHESv2 Structure
> [4] : DMC620 Dynamic Memory Controller, revision r1p0
> [5] : UEFI Reference Specification 2.8, Appendix N - Common Platform Error
> Record
> [6] : UEFI Reference Specification 2.8, Section N.2.5 Memory Error Section
>
> Link to github branch with the patches in this series -
> https://github.com/omkkul01/edk2/tree/ras_firmware_first_edk2
>
> Omkar Anand Kulkarni (4):
> ArmPlatformPkg: Allow dynamic generation of HEST ACPI table
> ArmPlatformPkg: add definition for
> MM_HEST_ERROR_SOURCE_DESC_PROTOCOL
> ArmPlatformPkg: retreive error source descriptors from MM
> ArmPlatformPkg: Add helpers for HEST table generation
>
> ArmPlatformPkg/ArmPlatformPkg.dec | 12 +
> .../Drivers/Apei/HestDxe/HestDxe.inf | 49 +++
> .../HestMmErrorSources/HestErrorSourceDxe.inf | 44 +++
> .../HestErrorSourceStandaloneMm.inf | 51 +++
> .../HestMmErrorSourceCommon.h | 37 ++
> ArmPlatformPkg/Include/HestAcpiHeader.h | 49 +++
> .../Include/Protocol/HestErrorSourceInfo.h | 64 ++++
> ArmPlatformPkg/Include/Protocol/HestTable.h | 71 ++++
> ArmPlatformPkg/Drivers/Apei/HestDxe/HestDxe.c | 354
> ++++++++++++++++++
> .../HestMmErrorSources/HestErrorSourceDxe.c | 308 +++++++++++++++
> .../HestErrorSourceStandaloneMm.c | 312 +++++++++++++++
> 11 files changed, 1351 insertions(+)
> create mode 100644 ArmPlatformPkg/Drivers/Apei/HestDxe/HestDxe.inf
> create mode 100644
> ArmPlatformPkg/Drivers/HestMmErrorSources/HestErrorSourceDxe.inf
> create mode 100644
> ArmPlatformPkg/Drivers/HestMmErrorSources/HestErrorSourceStandalone
> Mm.inf
> create mode 100644
> ArmPlatformPkg/Drivers/HestMmErrorSources/HestMmErrorSourceCommo
> n.h
> create mode 100644 ArmPlatformPkg/Include/HestAcpiHeader.h
> create mode 100644
> ArmPlatformPkg/Include/Protocol/HestErrorSourceInfo.h
> create mode 100644 ArmPlatformPkg/Include/Protocol/HestTable.h
> create mode 100644 ArmPlatformPkg/Drivers/Apei/HestDxe/HestDxe.c
> create mode 100644
> ArmPlatformPkg/Drivers/HestMmErrorSources/HestErrorSourceDxe.c
> create mode 100644
> ArmPlatformPkg/Drivers/HestMmErrorSources/HestErrorSourceStandalone
> Mm.c
>
> --
> 2.17.1
>
>
>
> -=-=-=-=-=-=
> Groups.io Links: You receive all messages sent to this group.
> View/Reply Online (#77667): https://edk2.groups.io/g/devel/message/77667
> Mute This Topic: https://groups.io/mt/84115237/4857533
> Group Owner: devel+owner@edk2.groups.io
> Unsubscribe: https://edk2.groups.io/g/devel/unsub
> [omkar.kulkarni@arm.com]
> -=-=-=-=-=-=
>


Re: [edk2-platforms][PATCH v2 0/5] Platform/Sgi: Add platform support for firmware first error handling

Sami Mujawar
 

Hi Omkar,

I will pick this up for review this week.

Regards,

Sami Mujawar

On 26/07/2021, 15:52, "Omkar Kulkarni" <Omkar.Kulkarni@arm.com> wrote:

Gentle reminder to review this patch series.

Regards,
Omkar

Changes since v1:
> - Added Platform Error Handler DXE driver.
> - Move the ACPI header values to common DSC include file.
> - Rebased to the latest upstream code.
>
> This patch series introduces platform support for RAS using Firmware First
> error handling. Firmware first error handling on ARM Neoverse reference
> design platforms is achieved using HEST[1] and SDEI[2] ACPI tables.
>
> For doing so the Platform Error handler DXE driver is introduced. This driver
> is integral part of the firmware first error handling framework in EDK2. SDEI
> being the notification mechanism used to communicate the platform errors
> to OSPM, it builds and installs the SDEI ACPI table. Also installs the HEST table
> which is already created as part of firmware first framework in EDK2.
>
> This series does provide a reference implementation to leverage the
> firmware first framework by implementing a platform MM driver for
> Dynamic Memory Controller DMC[3] that has RAS feature enabled. This
> driver mainly handles
> following:
> - Implements the Hest Error Source Descriptor protocol introduced as part of
> firmware first framework in EDK2. Publishes the 1-bit ECC DRAM error
> sources
> as GHESv2[4] type error source descriptors.
> - For any 1-bit CE that occurs on DRAM it reads DMC error record registers
> and
> populates a error status block (CPER)[5] of Memory Type error[6].
>
> References:
> [1] : ACPI 6.3, Table 18-382, Hardware Error Source Table [2] : SDEI Platform
> Design Document, revision b, 10 Appendix C, ACPI table
> definitions for SDEI
> [3] : DMC620 Dynamic Memory Controller, revision r1p0 [4] : ACPI Reference
> Specification 6.3, Table 18-393 GHESv2 Structure [5] : UEFI Reference
> Specification 2.8, Appendix N - Common Platform Error
> Record
> [6] : UEFI Reference Specification 2.8, Section N.2.5 Memory Error Section
>
> This patch series is dependent on the edk2 patch series
> https://edk2.groups.io/g/devel/message/77667
>
> Link to github branch with the patches in this series -
> https://github.com/omkkul01/edk2-platforms/tree/ras_firware_first_edk2-
> platforms
>
> Omkar Anand Kulkarni (5):
> Platform/ARM: Add DMC-620 ECC error handling driver
> Platform/Sgi: dmc-620 firmware-first error handling
> Platform/Sgi: define memory region for GHES error status block
> Platform/Sgi: Define values for ACPI table header
> Platform/Sgi: Add platform error handling driver
>
> Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.dec | 30 ++
> Platform/ARM/SgiPkg/SgiPlatform.dec | 1 +
> Platform/ARM/SgiPkg/SgiPlatform.dsc.inc | 38 ++
> Platform/ARM/SgiPkg/SgiPlatformMm.dsc.inc | 30 ++
> Platform/ARM/SgiPkg/PlatformStandaloneMm.fdf | 6 +
> Platform/ARM/SgiPkg/SgiPlatform.fdf | 13 +
> Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.inf | 60 +++
> .../PlatformErrorHandlerDxe.inf | 51 +++
> .../Library/PlatformLib/PlatformLib.inf | 6 +
> Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.h | 175 +++++++++
> Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.c | 360
> ++++++++++++++++++
> .../Dmc620Mm/Dmc620MmErrorSourceInfo.c | 198 ++++++++++
> .../PlatformErrorHandlerDxe.c | 171 +++++++++
> .../Library/PlatformLib/PlatformLibMem.c | 13 +-
> 14 files changed, 1150 insertions(+), 2 deletions(-) create mode 100644
> Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.dec
> create mode 100644 Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.inf
> create mode 100644
> Platform/ARM/SgiPkg/Drivers/PlatformErrorHandlerDxe/PlatformErrorHandl
> erDxe.inf
> create mode 100644 Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.h
> create mode 100644 Platform/ARM/Drivers/Dmc620Mm/Dmc620Mm.c
> create mode 100644
> Platform/ARM/Drivers/Dmc620Mm/Dmc620MmErrorSourceInfo.c
> create mode 100644
> Platform/ARM/SgiPkg/Drivers/PlatformErrorHandlerDxe/PlatformErrorHandl
> erDxe.c
>
> --
> 2.17.1
>
>
>
> -=-=-=-=-=-=
> Groups.io Links: You receive all messages sent to this group.
> View/Reply Online (#77669): https://edk2.groups.io/g/devel/message/77669
> Mute This Topic: https://groups.io/mt/84115312/4857533
> Group Owner: devel+owner@edk2.groups.io
> Unsubscribe: https://edk2.groups.io/g/devel/unsub
> [omkar.kulkarni@arm.com]
> -=-=-=-=-=-=
>


Re: [edk2-test][PATCH 1/1] SctPkg: Consume MdeLibs.dsc.inc for RegisterFilterLib

G Edhaya Chandran
 

Reviewed-by: G Edhaya Chandran<edhaya.chandran@...>


Re: [PATCH V3 00/10] Add Intel TDX support in OvmfPkg/ResetVector

Min Xu
 

On July 27, 2021 3:17 PM, Yao, Jiewen wrote:
Thanks Min.
Many thanks for splitting SEV stuff to a standalone file. That is very good start.

Some other comments for your consideration:

1) There is no need to create a standalone Init32.asm and ReloadFlat32.asm.
They are only needed in TDX so far. Please keep it in TDX.
Agree. Will move them to IntelTdx.asm in the next version.

2) I do not see the absolute need to create multiple patches for
ResetVector.nasm/ResetVectorVtf0.asm to add TDX stuff one by one. That
always makes me feel you miss something in the beginning. Since all the patches
are adding TDX support, I think we can add them one time.
Agree. Will update it in next version.

3) The strategy I take to review the patch is to compare the ResetVector in
UefiCpuPkg and OvmfPkg.
If they are similar, I am at ease. If they are different, I would ask why.

For example, OVMF version Flat32ToFlat64.asm missing the
CR4/CR0/EFER_MSR handling in normal mode. I am not sure why. A potential
bug? We had better make them consistent.
They are in SEV's code. I will extract them out in the next version.

4) I can understand difference in PageTables64.asm. UefiCpuPkg uses ROM page
table, while OVMF uses runtime crated page table. That is OK.

However, it is hard for me to understand how SEV/TDX hack the build page table.

I still recommend we move SEV hook to SEV file, and TDX hook to TDX file.
If we can use below patter, that can help me a lot to understand the logic.
===============
SetCr3ForPageTables64:

xor edx, edx

PreBuildPageTableHookSev
PreBuildPageTableHookTdx

BuildPageTables:

XXXXXX

PostBuildPageTableHookSev
PostBuildPageTableHookTdx

SetCr3:
===============
Agree. Will update it in next version.

5) There are too many noise in ResetVectorVtf0.asm.
Can we move SEV and TDX related GUID definition to a standalone SevVtf0.asm
and TdxVtf0.asm?
Sure. I will do it in the next version.
Thank you very much for the comments.

Xu, Min


Re: [PATCH V3 00/10] Add Intel TDX support in OvmfPkg/ResetVector

Yao, Jiewen
 

Thanks Min.
Many thanks for splitting SEV stuff to a standalone file. That is very good start.

Some other comments for your consideration:

1) There is no need to create a standalone Init32.asm and ReloadFlat32.asm. They are only needed in TDX so far. Please keep it in TDX.

2) I do not see the absolute need to create multiple patches for ResetVector.nasm/ResetVectorVtf0.asm to add TDX stuff one by one. That always makes me feel you miss something in the beginning. Since all the patches are adding TDX support, I think we can add them one time.

3) The strategy I take to review the patch is to compare the ResetVector in UefiCpuPkg and OvmfPkg.
If they are similar, I am at ease. If they are different, I would ask why.

For example, OVMF version Flat32ToFlat64.asm missing the CR4/CR0/EFER_MSR handling in normal mode. I am not sure why. A potential bug? We had better make them consistent.

4) I can understand difference in PageTables64.asm. UefiCpuPkg uses ROM page table, while OVMF uses runtime crated page table. That is OK.

However, it is hard for me to understand how SEV/TDX hack the build page table.

I still recommend we move SEV hook to SEV file, and TDX hook to TDX file.
If we can use below patter, that can help me a lot to understand the logic.
===============
SetCr3ForPageTables64:

xor edx, edx

PreBuildPageTableHookSev
PreBuildPageTableHookTdx

BuildPageTables:

XXXXXX

PostBuildPageTableHookSev
PostBuildPageTableHookTdx

SetCr3:
===============

5) There are too many noise in ResetVectorVtf0.asm.
Can we move SEV and TDX related GUID definition to a standalone SevVtf0.asm and TdxVtf0.asm?


Thank you
Yao Jiewen

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Min Xu
Sent: Tuesday, July 27, 2021 1:42 PM
To: devel@edk2.groups.io
Cc: Xu, Min M <min.m.xu@intel.com>; Ard Biesheuvel
<ardb+tianocore@kernel.org>; Justen, Jordan L <jordan.l.justen@intel.com>;
Brijesh Singh <brijesh.singh@amd.com>; Erdem Aktas
<erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Yao,
Jiewen <jiewen.yao@intel.com>; Tom Lendacky <thomas.lendacky@amd.com>
Subject: [edk2-devel] [PATCH V3 00/10] Add Intel TDX support in
OvmfPkg/ResetVector

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

Intel's Trust Domain Extensions (Intel TDX) refers to an Intel technology
that extends Virtual Machines Extensions (VMX) and Multi-Key Total Memory
Encryption (MKTME) with a new kind of virutal machines guest called a
Trust Domain (TD). A TD is desinged to run in a CPU mode that protects the
confidentiality of TD memory contents and the TD's CPU state from other
software, including the hosting Virtual-Machine Monitor (VMM), unless
explicitly shared by the TD itself.

The patch-sets to support Intel TDX in OvmfPkg is split into several
waves. This is wave1 which adds Intel TDX support in OvmfPkg/ResetVector.
Note: TDX only works in X64.

According to the comments in https://edk2.groups.io/g/devel/message/78152
and https://edk2.groups.io/g/devel/message/78151, PageTables64.asm and
Flat32ToFlat64.asm are refined. SEV and TDX related routines are separated
to AmdSev.asm and IntelTdx.asm.

Patch 1 add the PCDs of BFV/CFV. BFV is the code part of the image. CFV is
the configuration part. BFV is measured by VMM and CFV is measured by TDVF
itself.

Patch 2 add TdxMetadata in OvmfPkg/ResetVector. It describes the
information about the image so that VMM can do the initialization and
measurement based on these information.

Patch 3 set the initial value of Td mailbox and its related macros used in
ResetVector.

Patch 4 define macro of TDX_PT_ADDR which indicates the Tdx extra page
tables.

Patch 5 is IntelTdx.asm which includes below routines used in ResetVector.
- IsTdx
- InitTdx
- PostSetCr3PageTables64Tdx

Patch 6 is AmdSev.asm which includes SEV routines. These routines are
extracted from the previous PageTables64.asm/Flat32ToFlat64.asm.

Patch 7 load the GDT and set CR0, then jump to Flat32 protected mode. This
is because GDT is not set in the initial stage of ResetVector.

Patch 8 is Init32.asm. It is the entry point of doing the 32-bit protected
mode initialization. ReloadFlat32 and InitTdx are called. In the future if
SEV has something to initialize, InitSev (for example) can be called in
turn.

Patch 9 create Main.asm in OvmfPkg/ResetVector. It is based on the
suggestion in https://edk2.groups.io/g/devel/message/78152. In this commit
it is simply copied from UefiCpuPkg. In the next commit this Main.asm is
updated to add a new Entry (Main32) to support Tdx.

In Patch 10, all above are put together. Init32.asm call ReloadFlat32
to jump to 32-bit protected mode, then InitTdx initialize TDX_WORK_AREA
to record 'TDXG' flags. After that page tables are built and set, then
jump to SecEntry.

[TDX]: https://software.intel.com/content/dam/develop/external/us/en/
documents/tdx-whitepaper-final9-17.pdf

[TDVF]: https://software.intel.com/content/dam/develop/external/us/en/
documents/tdx-virtual-firmware-design-guide-rev-1.pdf

[ReviewComment-1]: https://edk2.groups.io/g/devel/message/78151

[ReviewComment-2]: https://edk2.groups.io/g/devel/message/78152

Code is at https://github.com/mxu9/edk2/tree/tdvf_wave1.v3

v3 changes:
- Refine PageTables64.asm and Flat32ToFlat64.asm based on the review
comments in [ReviewComment-1] and [ReviewComment-2].
- SEV codes are in AmdSev.asm
- TDX codes are in IntelTdx.asm
- Main.asm is created in OvmfPkg/ResetVector. The one in
UefiCpuPkg/ResetVector/Vtf0 is not used.
- Init32.asm/ReloadFlat32.asm in UefiCpuPkg/ResetVector/Vtf0/Ia32 are
deleted. They're moved to OvmfPkg/ResetVector/Ia32.
- InitTdx.asm is renamed to InteTdx.asm

v2 changes:
- Move InitTdx.asm and ReloadFlat32.asm from UefiCpuPkg/ResetVector/Vtf0
to OvmfPkg/ResetVector. Init32.asm is created which is a null stub of
32-bit initialization. In Main32 just simply call Init32. It makes
the Main.asm in UefiCpuPkg/ResetVector clean and clear.
- Init32.asm/InitTdx.asm/ReloadFlat32.asm are created under
OvmfPkg/ResetVector/Ia32.
- Update some descriptions of the patch-sets.
- Update the REF link in cover letter.
- Add Ard Biesheuvel in Cc list.

v1: https://edk2.groups.io/g/devel/message/77675

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>

Min Xu (10):
OvmfPkg: Add Tdx BFV/CFV PCDs and PcdOvmfImageSizeInKb
OvmfPkg: Add Tdx metadata
OvmfPkg: Set TdMailbox initial value and macros
OvmfPkg: Add TDX_PT_ADDR defition in ResetVector.nasmb
OvmfPkg: Add IntelTdx.asm in ResetVector
OvmfPkg: Add AmdSev.asm in ResetVector
OvmfPkg: Add ReloadFlat32
OvmfPkg: Add Init32
OvmfPkg: Create Main.asm in ResetVector
OvmfPkg: Update ResetVector to support Tdx

OvmfPkg/OvmfPkg.dec | 13 +
OvmfPkg/OvmfPkgDefines.fdf.inc | 12 +-
OvmfPkg/OvmfPkgX64.fdf | 6 +
OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 38 ++
OvmfPkg/ResetVector/Ia32/AmdSev.asm | 526 +++++++++++++++++++
OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm | 110 +---
OvmfPkg/ResetVector/Ia32/Init32.asm | 32 ++
OvmfPkg/ResetVector/Ia32/IntelTdx.asm | 172 ++++++
OvmfPkg/ResetVector/Ia32/PageTables64.asm | 478 +++--------------
OvmfPkg/ResetVector/Ia32/ReloadFlat32.asm | 44 ++
OvmfPkg/ResetVector/Main.asm | 119 +++++
OvmfPkg/ResetVector/ResetVector.inf | 11 +-
OvmfPkg/ResetVector/ResetVector.nasmb | 66 ++-
OvmfPkg/ResetVector/X64/TdxMetadata.asm | 97 ++++
14 files changed, 1224 insertions(+), 500 deletions(-)
create mode 100644 OvmfPkg/ResetVector/Ia32/AmdSev.asm
create mode 100644 OvmfPkg/ResetVector/Ia32/Init32.asm
create mode 100644 OvmfPkg/ResetVector/Ia32/IntelTdx.asm
create mode 100644 OvmfPkg/ResetVector/Ia32/ReloadFlat32.asm
create mode 100644 OvmfPkg/ResetVector/Main.asm
create mode 100644 OvmfPkg/ResetVector/X64/TdxMetadata.asm

--
2.29.2.windows.2





Re: [edk2-test][PATCH v1 1/1] uefi-sct/SctPkg: Update page alignment calculations

G Edhaya Chandran
 

Reviewed-by: G Edhaya Chandran<edhaya.chandran@...>


[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


[PATCH V3 09/10] OvmfPkg: Create Main.asm in ResetVector

Min Xu
 

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

According to suggestion in https://edk2.groups.io/g/devel/message/78152
we drop UefiCpuPkg changes and focus on improving OvmfPkg. So Main.asm
is created in OvmfPkg/ResetVector which is simply copied from UefiCpuPkg.
In the next commit this Main.asm will be updated to add a new Entry
(Main32) to support Tdx.

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/Main.asm | 105 +++++++++++++++++++++++++++++++++++
1 file changed, 105 insertions(+)
create mode 100644 OvmfPkg/ResetVector/Main.asm

diff --git a/OvmfPkg/ResetVector/Main.asm b/OvmfPkg/ResetVector/Main.asm
new file mode 100644
index 000000000000..dbebfb9e5d29
--- /dev/null
+++ b/OvmfPkg/ResetVector/Main.asm
@@ -0,0 +1,105 @@
+;------------------------------------------------------------------------------
+; @file
+; Main routine of the pre-SEC code up through the jump into SEC
+;
+; Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+
+BITS 16
+
+;
+; Modified: EBX, ECX, EDX, EBP
+;
+; @param[in,out] RAX/EAX Initial value of the EAX register
+; (BIST: Built-in Self Test)
+; @param[in,out] DI 'BP': boot-strap processor, or
+; 'AP': application processor
+; @param[out] RBP/EBP Address of Boot Firmware Volume (BFV)
+; @param[out] DS Selector allowing flat access to all addresses
+; @param[out] ES Selector allowing flat access to all addresses
+; @param[out] FS Selector allowing flat access to all addresses
+; @param[out] GS Selector allowing flat access to all addresses
+; @param[out] SS Selector allowing flat access to all addresses
+;
+; @return None This routine jumps to SEC and does not return
+;
+Main16:
+ OneTimeCall EarlyInit16
+
+ ;
+ ; Transition the processor from 16-bit real mode to 32-bit flat mode
+ ;
+ OneTimeCall TransitionFromReal16To32BitFlat
+
+BITS 32
+
+ ;
+ ; Search for the Boot Firmware Volume (BFV)
+ ;
+ OneTimeCall Flat32SearchForBfvBase
+
+ ;
+ ; EBP - Start of BFV
+ ;
+
+ ;
+ ; Search for the SEC entry point
+ ;
+ OneTimeCall Flat32SearchForSecEntryPoint
+
+ ;
+ ; ESI - SEC Core entry point
+ ; EBP - Start of BFV
+ ;
+
+%ifdef ARCH_IA32
+
+ ;
+ ; Restore initial EAX value into the EAX register
+ ;
+ mov eax, esp
+
+ ;
+ ; Jump to the 32-bit SEC entry point
+ ;
+ jmp esi
+
+%else
+
+ ;
+ ; Transition the processor from 32-bit flat mode to 64-bit flat mode
+ ;
+ OneTimeCall Transition32FlatTo64Flat
+
+BITS 64
+
+ ;
+ ; Some values were calculated in 32-bit mode. Make sure the upper
+ ; 32-bits of 64-bit registers are zero for these values.
+ ;
+ mov rax, 0x00000000ffffffff
+ and rsi, rax
+ and rbp, rax
+ and rsp, rax
+
+ ;
+ ; RSI - SEC Core entry point
+ ; RBP - Start of BFV
+ ;
+
+ ;
+ ; Restore initial EAX value into the RAX register
+ ;
+ mov rax, rsp
+
+ ;
+ ; Jump to the 64-bit SEC entry point
+ ;
+ jmp rsi
+
+%endif
+
+
--
2.29.2.windows.2


[PATCH V3 08/10] OvmfPkg: Add Init32

Min Xu
 

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

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. In the future if SEV has
something to initialize, InitSev (for example) can be called in Init32.

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/Ia32/Init32.asm | 32 +++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 OvmfPkg/ResetVector/Ia32/Init32.asm

diff --git a/OvmfPkg/ResetVector/Ia32/Init32.asm b/OvmfPkg/ResetVector/Ia32/Init32.asm
new file mode 100644
index 000000000000..fb78f6856f0a
--- /dev/null
+++ b/OvmfPkg/ResetVector/Ia32/Init32.asm
@@ -0,0 +1,32 @@
+;------------------------------------------------------------------------------
+; @file
+; 32-bit initialization code
+;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+BITS 32
+
+;
+; Modified: EAX, EBX, ECX, EDX, EBP, EDI, ESP
+;
+Init32:
+ ;
+ ; Save EBX in EBP because EBX will be changed in ReloadFlat32
+ ;
+ mov ebp, ebx
+
+ ;
+ ; First load the GDT and jump to Flat32 mode
+ ;
+ OneTimeCall ReloadFlat32
+
+ ;
+ ; Initialization of Tdx
+ ;
+ OneTimeCall InitTdx
+
+ OneTimeCallRet Init32
+
--
2.29.2.windows.2


[PATCH V3 07/10] OvmfPkg: Add ReloadFlat32

Min Xu
 

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

Load the GDT and set the CR0, then jump to Flat 32 protected mode. After
that CR4 is set.

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/Ia32/ReloadFlat32.asm | 44 +++++++++++++++++++++++
1 file changed, 44 insertions(+)
create mode 100644 OvmfPkg/ResetVector/Ia32/ReloadFlat32.asm

diff --git a/OvmfPkg/ResetVector/Ia32/ReloadFlat32.asm b/OvmfPkg/ResetVector/Ia32/ReloadFlat32.asm
new file mode 100644
index 000000000000..cfcea06fbd11
--- /dev/null
+++ b/OvmfPkg/ResetVector/Ia32/ReloadFlat32.asm
@@ -0,0 +1,44 @@
+;------------------------------------------------------------------------------
+; @file
+; Load the GDT and set the CR0, then jump to Flat 32 protected mode.
+;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+%define SEC_DEFAULT_CR0 0x00000023
+%define SEC_DEFAULT_CR4 0x640
+
+BITS 32
+
+;
+; Modified: EAX, EBX, CR0, CR4, DS, ES, FS, GS, SS
+;
+ReloadFlat32:
+
+ cli
+ mov ebx, ADDR_OF(gdtr)
+ lgdt [ebx]
+
+ mov eax, SEC_DEFAULT_CR0
+ mov cr0, eax
+
+ jmp LINEAR_CODE_SEL:dword ADDR_OF(jumpToFlat32BitAndLandHere)
+BITS 32
+jumpToFlat32BitAndLandHere:
+
+ mov eax, SEC_DEFAULT_CR4
+ mov cr4, eax
+
+ debugShowPostCode POSTCODE_32BIT_MODE
+
+ mov ax, LINEAR_SEL
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ OneTimeCallRet ReloadFlat32
+
--
2.29.2.windows.2


[PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector

Min Xu
 

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

AmdSev.asm includes below routines:
- CheckSevFeatures
Check if Secure Encrypted Virtualization (SEV) features are enabled.
- PreSetCr3ForPageTables64Sev
It is called before SetCr3ForPageTables64 in SEV guests.
- PostSetCr3PageTables64Sev
It is called after SetCr3PageTables64 in SEV guests.
- PostJump64BitAndLandHereSev
It is called after Jump64BitAndLandHere in SEV guests.
- #VC exception handling routines

These routines are extracted from PageTables64.asm and Flat32ToFlat64.asm
Need AMD engineers' help to review/validate the patch so that there is
no regression. Thanks in advance!

Note:
In above Pre/Post routines, dword[TDX_WORK_AREA] should be checked
to see if it is 'TDXG' (Tdx guests). This is because some memory region
for example, byte[SEV_ES_WORK_AREA] cannot be accessed in Tdx guests.
Tdx requires that any memory region to be accessed should be accepted
first or initialized by host VMM before Td guest is launched.

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/Ia32/AmdSev.asm | 526 ++++++++++++++++++++++++++++
1 file changed, 526 insertions(+)
create mode 100644 OvmfPkg/ResetVector/Ia32/AmdSev.asm

diff --git a/OvmfPkg/ResetVector/Ia32/AmdSev.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
new file mode 100644
index 000000000000..962b7e169c61
--- /dev/null
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -0,0 +1,526 @@
+;------------------------------------------------------------------------------
+; @file
+; AMD SEV routines
+;
+; Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+
+BITS 32
+;
+; 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.
+;
+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
+
+ ;
+ ; 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
+ ;
+ and ebx, 0x3f
+ mov eax, ebx
+
+ ; The encryption bit position is always above 31
+ sub ebx, 32
+ jns SevSaveMask
+
+ ; Encryption bit was reported as 31 or below, enter a HLT loop
+SevEncBitLowHlt:
+ cli
+ hlt
+ jmp SevEncBitLowHlt
+
+SevSaveMask:
+ xor edx, edx
+ bts edx, ebx
+
+ mov dword[SEV_ES_WORK_AREA_ENC_MASK], 0
+ mov dword[SEV_ES_WORK_AREA_ENC_MASK + 4], edx
+ jmp SevExit
+
+NoSev:
+ ;
+ ; Perform an SEV-ES sanity check by seeing if a #VC exception occurred.
+ ;
+ cmp byte[SEV_ES_WORK_AREA], 0
+ jz NoSevPass
+
+ ;
+ ; A #VC was received, yet CPUID indicates no SEV-ES support, something
+ ; isn't right.
+ ;
+NoSevEsVcHlt:
+ cli
+ hlt
+ jmp NoSevEsVcHlt
+
+NoSevPass:
+ xor eax, eax
+
+SevExit:
+ ;
+ ; Clear exception handlers and stack
+ ;
+ push eax
+ mov eax, ADDR_OF(IdtrClear)
+ lidt [cs:eax]
+ pop eax
+ mov esp, 0
+
+ OneTimeCallRet CheckSevFeatures
+
+;
+; Called before SetCr3ForPageTables64 in SEV guests
+;
+; Modified: EAX, EBX, ECX, EDX, ESP
+;
+PreSetCr3ForPageTables64Sev:
+ ; In Tdx TDX_WORK_AREA was set to 'TDXG'.
+ ; CheckSevFeatures cannot be called in Tdx guest because SEV_ES_WORK_AREA
+ ; cannot be accessed in this situation. Any memory region to be accessed
+ ; in Td guest should be accepted first.
+ cmp dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
+ jz ExitPreSetCr3ForPageTables64Sev
+
+ OneTimeCall CheckSevFeatures
+
+ExitPreSetCr3ForPageTables64Sev:
+ OneTimeCallRet PreSetCr3ForPageTables64Sev
+
+;
+; It is called in SEV after SetCr3PageTables64
+;
+; Modified: EAX, EBX, ECX, EDX, ESP
+;
+PostSetCr3PageTables64Sev:
+ ; In Tdx TDX_WORK_AREA was set to 'TDXG'.
+ ; CheckSevFeatures cannot be called in Tdx because SEV_ES_WORK_AREA
+ ; cannot be accessed in this situation. Any memory region to be accessed
+ ; in Td guest should be accepted first.
+ cmp dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
+ jz ExitPostSetCr3PageTables64Sev
+
+ mov eax, cr4
+ bts eax, 5 ; enable PAE
+ mov cr4, eax
+
+ 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
+
+ExitPostSetCr3PageTables64Sev:
+
+ OneTimeCallRet PostSetCr3PageTables64Sev
+
+;
+; 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:
+
+BITS 64
+
+;
+; Called after Jump64BitAndLandHere
+;
+PostJump64BitAndLandHereSev:
+
+ ;
+ ; If it is Tdx guest, jump to exit point directly.
+ ; This is because following code may access the memory region which has
+ ; not been accepted. It is not allowed in Tdx guests.
+ ;
+ mov eax, dword[TDX_WORK_AREA]
+ cmp eax, 0x47584454 ; 'TDXG'
+ jz GoodCompare
+
+ ;
+ ; Check if the second step of the SEV-ES mitigation is to be performed.
+ ;
+ test ebx, ebx
+ jz InsnCompare
+
+ ;
+ ; 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:
+ OneTimeCallRet PostJump64BitAndLandHereSev
--
2.29.2.windows.2


[PATCH V3 05/10] OvmfPkg: Add IntelTdx.asm in ResetVector

Min Xu
 

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

IntelTdx.asm includes below routines used in ResetVector
- IsTdx
Check if the running system is Tdx guest.

- InitTdx
This is the initialization code for Tdx guest. It sets TDX_WORK_AREA
so that it can be used in later code. Also APs will spin to check
if the PageTable has been built by BSP. If the PageTables is ready,
APs continues.

- PostSetCr3PageTables64Tdx
It is called after SetCr3PageTables64 in Tdx guest to set CR0/CR4.
If GPAW is 52, then CR3 is adjusted as well.

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/Ia32/IntelTdx.asm | 172 ++++++++++++++++++++++++++
1 file changed, 172 insertions(+)
create mode 100644 OvmfPkg/ResetVector/Ia32/IntelTdx.asm

diff --git a/OvmfPkg/ResetVector/Ia32/IntelTdx.asm b/OvmfPkg/ResetVector/Ia32/IntelTdx.asm
new file mode 100644
index 000000000000..4a00059a47a7
--- /dev/null
+++ b/OvmfPkg/ResetVector/Ia32/IntelTdx.asm
@@ -0,0 +1,172 @@
+;------------------------------------------------------------------------------
+; @file
+; Intel TDX routines
+;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+BITS 32
+
+;
+; Check if it is Intel Tdx
+;
+; Modified: EAX, EBX, ECX, EDX
+;
+; If it is Intel Tdx, EAX is zero
+; If it is not Intel Tdx, EAX is non-zero
+;
+IsTdx:
+ ;
+ ; CPUID (0)
+ ;
+ mov eax, 0
+ cpuid
+ cmp ebx, 0x756e6547 ; "Genu"
+ jne IsNotTdx
+ cmp edx, 0x49656e69 ; "ineI"
+ jne IsNotTdx
+ cmp ecx, 0x6c65746e ; "ntel"
+ jne IsNotTdx
+
+ ;
+ ; CPUID (1)
+ ;
+ mov eax, 1
+ cpuid
+ test ecx, 0x80000000
+ jz IsNotTdx
+
+ ;
+ ; CPUID[0].EAX >= 0x21?
+ ;
+ mov eax, 0
+ cpuid
+ cmp eax, 0x21
+ jl IsNotTdx
+
+ ;
+ ; CPUID (0x21,0)
+ ;
+ mov eax, 0x21
+ mov ecx, 0
+ cpuid
+
+ cmp ebx, 0x65746E49 ; "Inte"
+ jne IsNotTdx
+ cmp edx, 0x5844546C ; "lTDX"
+ jne IsNotTdx
+ cmp ecx, 0x20202020 ; " "
+ jne IsNotTdx
+
+ mov eax, 0
+ jmp ExitIsTdx
+
+IsNotTdx:
+ mov eax, 1
+
+ExitIsTdx:
+
+ OneTimeCallRet IsTdx
+
+;
+; Initialization code if it is Tdx guest.
+; If it is Tdx guest, EBP[6:0] holds CPU supported GPAW, ESI[31:0] is the vCPU ID
+;
+; Modified: EBP
+;
+InitTdx:
+
+ ;
+ ; First check if it is Tdx
+ ;
+ OneTimeCall IsTdx
+
+ test eax, eax
+ jnz ExitInitTdx
+
+ ;
+ ; In Td guest, BSP/AP shares the same entry point
+ ; BSP builds up the page table, while APs shouldn't do the same task.
+ ; Instead, APs just leverage the page table which is built by BSP.
+ ; APs will wait until the page table is ready.
+ ; In Td guest, vCPU 0 is treated as the BSP, the others are APs.
+ ; ESI indicates the vCPU ID.
+ ;
+ cmp esi, 0
+ je TdBspEntry
+
+ApWait:
+ cmp byte[TDX_WORK_AREA_PGTBL_READY], 0
+ je ApWait
+ jmp ExitInitTdx
+
+TdBspEntry:
+ ;
+ ; It is of Tdx Guest
+ ; Save the Tdx info in TDX_WORK_AREA so that the following code can use
+ ; these information.
+ ;
+ mov dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
+
+ ;
+ ; EBP[6:0] CPU supported GPA width
+ ;
+ and ebp, 0x3f
+ cmp ebp, 52
+ jl NotPageLevel5
+ mov byte[TDX_WORK_AREA_PAGELEVEL5], 1
+
+NotPageLevel5:
+ mov DWORD[TDX_WORK_AREA_INFO], ebp
+
+ExitInitTdx:
+ OneTimeCallRet InitTdx
+
+;
+; Called after SetCr3PageTables64 in Tdx guest to set CR0/CR4.
+; If GPAW is 52, then CR3 is adjusted as well.
+;
+; Modified: EAX, EBX, CR0, CR3, CR4
+;
+PostSetCr3PageTables64Tdx:
+ ;
+ ; TDX_WORK_AREA was set in InitTdx if it is Tdx guest
+ ;
+ cmp dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
+ jnz ExitPostSetCr3PageTables64Tdx
+
+ mov eax, cr4
+ bts eax, 5 ; enable PAE
+
+ ;
+ ; byte[TDX_WORK_AREA_PAGELEVEL5] holds the indicator whether 52bit is supported.
+ ; if it is the case, need to set LA57 and use 5-level paging
+ ;
+ cmp byte[TDX_WORK_AREA_PAGELEVEL5], 0
+ jz SetCr4
+ bts eax, 12
+
+SetCr4:
+ mov cr4, eax
+ mov ebx, cr3
+
+ ;
+ ; if la57 is not set, we are ok
+ ; if using 5-level paging, adjust top-level page directory
+ ;
+ bt eax, 12
+ jnc TdxSetCr3
+ mov ebx, TDX_PT_ADDR (0)
+
+TdxSetCr3:
+ mov cr3, ebx
+
+ mov eax, cr0
+ bts eax, 31 ; set PG
+ mov cr0, eax ; enable paging
+
+ExitPostSetCr3PageTables64Tdx:
+ OneTimeCallRet PostSetCr3PageTables64Tdx
+
--
2.29.2.windows.2


[PATCH V3 04/10] OvmfPkg: Add TDX_PT_ADDR defition in ResetVector.nasmb

Min Xu
 

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

Tdx support 4-level paging or 5-level paging based on the GPAW. If
5-level page table is supported (GPAW is 52), a top level page directory
pointers (1 * 256TB entry) is generated in the memory region defined by
PcdOvmfSecPageTablesBase.

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/ResetVector.nasmb | 3 +++
1 file changed, 3 insertions(+)

diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 42b4a3791d29..0ac6d7a6fd33 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -118,6 +118,9 @@
%define TDX_WORK_AREA_PGTBL_READY (TDX_WORK_AREA + 5)
%define TDX_WORK_AREA_INITVP (TDX_WORK_AREA + 8)
%define TDX_WORK_AREA_INFO (TDX_WORK_AREA + 8 + 4)
+
+ %define TDX_PT_ADDR(Offset) (TDX_EXTRA_PAGE_TABLE_BASE + (Offset))
+
%define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))

%define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
--
2.29.2.windows.2


[PATCH V3 03/10] OvmfPkg: Set TdMailbox initial value and macros

Min Xu
 

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

In Tdx the memory region defined by PcdOvmfSecGhcbBackupBase is used as
TdMailbox. It is initialized to all-0 by host VMM. Piece of the memory
region TdMailbox[0x10, 0x20] is used as TDX_WORK_AREA. In this area a
flag 'TDXG' is set so that the following code can check if it is
Tdx guest.

So in Non-Tdx guest, this memory region should be initialized to all-0 in
the definition of MEMFD.

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/OvmfPkgX64.fdf | 6 ++++++
OvmfPkg/ResetVector/ResetVector.nasmb | 12 ++++++++++++
2 files changed, 18 insertions(+)

diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 5fa8c0895808..c587d1412803 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -87,6 +87,12 @@ gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpaceGuid.PcdSevE

0x00C000|0x001000
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
+DATA = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+}

0x010000|0x010000
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index b653fe87abd6..42b4a3791d29 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -106,6 +106,18 @@
%define TDX_EXTRA_PAGE_TABLE_BASE FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase)
%define TDX_EXTRA_PAGE_TABLE_SIZE FixedPcdGet32 (PcdOvmfSecGhcbPageTableSize)

+ ;
+ ; TdMailboxBase [0x10, 0x800] is reserved for OS.
+ ; Td guest initialize piece of this area (TdMailboxBase [0x10,0x20]) to
+ ; record the Td guest info so that this information can be used in the
+ ; following ResetVector flow.
+ ;
+ %define TD_MAILBOX_WORKAREA_OFFSET 0x10
+ %define TDX_WORK_AREA (TDX_MAILBOX_MEMORY_BASE + TD_MAILBOX_WORKAREA_OFFSET)
+ %define TDX_WORK_AREA_PAGELEVEL5 (TDX_WORK_AREA + 4)
+ %define TDX_WORK_AREA_PGTBL_READY (TDX_WORK_AREA + 5)
+ %define TDX_WORK_AREA_INITVP (TDX_WORK_AREA + 8)
+ %define TDX_WORK_AREA_INFO (TDX_WORK_AREA + 8 + 4)
%define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))

%define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
--
2.29.2.windows.2

6141 - 6160 of 84277