* [PATCH V7 01/37] MdePkg: Add Tdx.h
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 02/37] MdePkg: Introduce basic Tdx functions in BaseLib Min Xu
` (36 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Gerd Hoffmann,
Jiewen Yao
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
Tdx.h includes the Intel Trust Domain Extension definitions.
Detailed information can be found in below document:
https://software.intel.com/content/dam/develop/external/us/en/
documents/tdx-module-1eas-v0.85.039.pdf
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
MdePkg/Include/IndustryStandard/Tdx.h | 203 ++++++++++++++++++++++++++
1 file changed, 203 insertions(+)
create mode 100644 MdePkg/Include/IndustryStandard/Tdx.h
diff --git a/MdePkg/Include/IndustryStandard/Tdx.h b/MdePkg/Include/IndustryStandard/Tdx.h
new file mode 100644
index 000000000000..81df1361842b
--- /dev/null
+++ b/MdePkg/Include/IndustryStandard/Tdx.h
@@ -0,0 +1,203 @@
+/** @file
+ Intel Trust Domain Extension definitions
+ Detailed information is in below document:
+ https://software.intel.com/content/dam/develop/external/us/en/documents
+ /tdx-module-1eas-v0.85.039.pdf
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MDE_PKG_TDX_H_
+#define MDE_PKG_TDX_H_
+
+#define EXIT_REASON_EXTERNAL_INTERRUPT 1
+#define EXIT_REASON_TRIPLE_FAULT 2
+
+#define EXIT_REASON_PENDING_INTERRUPT 7
+#define EXIT_REASON_NMI_WINDOW 8
+#define EXIT_REASON_TASK_SWITCH 9
+#define EXIT_REASON_CPUID 10
+#define EXIT_REASON_HLT 12
+#define EXIT_REASON_INVD 13
+#define EXIT_REASON_INVLPG 14
+#define EXIT_REASON_RDPMC 15
+#define EXIT_REASON_RDTSC 16
+#define EXIT_REASON_VMCALL 18
+#define EXIT_REASON_VMCLEAR 19
+#define EXIT_REASON_VMLAUNCH 20
+#define EXIT_REASON_VMPTRLD 21
+#define EXIT_REASON_VMPTRST 22
+#define EXIT_REASON_VMREAD 23
+#define EXIT_REASON_VMRESUME 24
+#define EXIT_REASON_VMWRITE 25
+#define EXIT_REASON_VMOFF 26
+#define EXIT_REASON_VMON 27
+#define EXIT_REASON_CR_ACCESS 28
+#define EXIT_REASON_DR_ACCESS 29
+#define EXIT_REASON_IO_INSTRUCTION 30
+#define EXIT_REASON_MSR_READ 31
+#define EXIT_REASON_MSR_WRITE 32
+#define EXIT_REASON_INVALID_STATE 33
+#define EXIT_REASON_MSR_LOAD_FAIL 34
+#define EXIT_REASON_MWAIT_INSTRUCTION 36
+#define EXIT_REASON_MONITOR_TRAP_FLAG 37
+#define EXIT_REASON_MONITOR_INSTRUCTION 39
+#define EXIT_REASON_PAUSE_INSTRUCTION 40
+#define EXIT_REASON_MCE_DURING_VMENTRY 41
+#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
+#define EXIT_REASON_APIC_ACCESS 44
+#define EXIT_REASON_EOI_INDUCED 45
+#define EXIT_REASON_GDTR_IDTR 46
+#define EXIT_REASON_LDTR_TR 47
+#define EXIT_REASON_EPT_VIOLATION 48
+#define EXIT_REASON_EPT_MISCONFIG 49
+#define EXIT_REASON_INVEPT 50
+#define EXIT_REASON_RDTSCP 51
+#define EXIT_REASON_PREEMPTION_TIMER 52
+#define EXIT_REASON_INVVPID 53
+#define EXIT_REASON_WBINVD 54
+#define EXIT_REASON_XSETBV 55
+#define EXIT_REASON_APIC_WRITE 56
+#define EXIT_REASON_RDRAND 57
+#define EXIT_REASON_INVPCID 58
+#define EXIT_REASON_VMFUNC 59
+#define EXIT_REASON_ENCLS 60
+#define EXIT_REASON_RDSEED 61
+#define EXIT_REASON_PML_FULL 62
+#define EXIT_REASON_XSAVES 63
+#define EXIT_REASON_XRSTORS 64
+
+// TDCALL API Function Completion Status Codes
+#define TDX_EXIT_REASON_SUCCESS 0x0000000000000000
+#define TDX_EXIT_REASON_PAGE_ALREADY_ACCEPTED 0x00000B0A00000000
+#define TDX_EXIT_REASON_PAGE_SIZE_MISMATCH 0xC0000B0B00000000
+#define TDX_EXIT_REASON_OPERAND_INVALID 0xC000010000000000
+#define TDX_EXIT_REASON_OPERAND_BUSY 0x8000020000000000
+
+// TDCALL [TDG.MEM.PAGE.ACCEPT] page size
+#define TDCALL_ACCEPT_PAGE_SIZE_4K 0
+#define TDCALL_ACCEPT_PAGE_SIZE_2M 1
+#define TDCALL_ACCEPT_PAGE_SIZE_1G 2
+
+#define TDCALL_TDVMCALL 0
+#define TDCALL_TDINFO 1
+#define TDCALL_TDEXTENDRTMR 2
+#define TDCALL_TDGETVEINFO 3
+#define TDCALL_TDREPORT 4
+#define TDCALL_TDSETCPUIDVE 5
+#define TDCALL_TDACCEPTPAGE 6
+
+#define TDVMCALL_CPUID 0x0000a
+#define TDVMCALL_HALT 0x0000c
+#define TDVMCALL_IO 0x0001e
+#define TDVMCALL_RDMSR 0x0001f
+#define TDVMCALL_WRMSR 0x00020
+#define TDVMCALL_MMIO 0x00030
+#define TDVMCALL_PCONFIG 0x00041
+
+#define TDVMCALL_GET_TDVMCALL_INFO 0x10000
+#define TDVMCALL_MAPGPA 0x10001
+#define TDVMCALL_GET_QUOTE 0x10002
+#define TDVMCALL_REPORT_FATAL_ERR 0x10003
+#define TDVMCALL_SETUP_EVENT_NOTIFY 0x10004
+
+#pragma pack(1)
+typedef struct {
+ UINT64 Data[6];
+} TDCALL_GENERIC_RETURN_DATA;
+
+typedef struct {
+ UINT64 Gpaw;
+ UINT64 Attributes;
+ UINT32 MaxVcpus;
+ UINT32 NumVcpus;
+ UINT64 Resv[3];
+} TDCALL_INFO_RETURN_DATA;
+
+typedef union {
+ UINT64 Val;
+ struct {
+ UINT32 Size : 3;
+ UINT32 Direction : 1;
+ UINT32 String : 1;
+ UINT32 Rep : 1;
+ UINT32 Encoding : 1;
+ UINT32 Resv : 9;
+ UINT32 Port : 16;
+ UINT32 Resv2;
+ } Io;
+} VMX_EXIT_QUALIFICATION;
+
+typedef struct {
+ UINT32 ExitReason;
+ UINT32 Resv;
+ VMX_EXIT_QUALIFICATION ExitQualification;
+ UINT64 GuestLA;
+ UINT64 GuestPA;
+ UINT32 ExitInstructionLength;
+ UINT32 ExitInstructionInfo;
+ UINT32 Resv1;
+} TDCALL_VEINFO_RETURN_DATA;
+
+typedef union {
+ TDCALL_GENERIC_RETURN_DATA Generic;
+ TDCALL_INFO_RETURN_DATA TdInfo;
+ TDCALL_VEINFO_RETURN_DATA VeInfo;
+} TD_RETURN_DATA;
+
+/* data structure used in TDREPORT_STRUCT */
+typedef struct {
+ UINT8 Type;
+ UINT8 Subtype;
+ UINT8 Version;
+ UINT8 Rsvd;
+} TD_REPORT_TYPE;
+
+typedef struct {
+ TD_REPORT_TYPE ReportType;
+ UINT8 Rsvd1[12];
+ UINT8 CpuSvn[16];
+ UINT8 TeeTcbInfoHash[48];
+ UINT8 TeeInfoHash[48];
+ UINT8 ReportData[64];
+ UINT8 Rsvd2[32];
+ UINT8 Mac[32];
+} REPORTMACSTRUCT;
+
+typedef struct {
+ UINT8 Seam[2];
+ UINT8 Rsvd[14];
+} TEE_TCB_SVN;
+
+typedef struct {
+ UINT8 Valid[8];
+ TEE_TCB_SVN TeeTcbSvn;
+ UINT8 Mrseam[48];
+ UINT8 Mrsignerseam[48];
+ UINT8 Attributes[8];
+ UINT8 Rsvd[111];
+} TEE_TCB_INFO;
+
+typedef struct {
+ UINT8 Attributes[8];
+ UINT8 Xfam[8];
+ UINT8 Mrtd[48];
+ UINT8 Mrconfigid[48];
+ UINT8 Mrowner[48];
+ UINT8 Mrownerconfig[48];
+ UINT8 Rtmrs[4][48];
+ UINT8 Rsvd[112];
+} TDINFO;
+
+typedef struct {
+ REPORTMACSTRUCT ReportMacStruct;
+ TEE_TCB_INFO TeeTcbInfo;
+ UINT8 Rsvd[17];
+ TDINFO Tdinfo;
+} TDREPORT_STRUCT;
+
+#pragma pack()
+
+#endif
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 02/37] MdePkg: Introduce basic Tdx functions in BaseLib
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
2022-02-28 7:20 ` [PATCH V7 01/37] MdePkg: Add Tdx.h Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 03/37] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
` (35 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky,
Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
Introduce basic Tdx functions in BaseLib:
- TdCall ()
- TdVmCall ()
- TdIsEnabled ()
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
MdePkg/Include/Library/BaseLib.h | 62 ++++++++++
MdePkg/Library/BaseLib/BaseLib.inf | 11 ++
MdePkg/Library/BaseLib/IntelTdxNull.c | 83 +++++++++++++
MdePkg/Library/BaseLib/X64/TdCall.nasm | 85 +++++++++++++
MdePkg/Library/BaseLib/X64/TdProbe.c | 62 ++++++++++
MdePkg/Library/BaseLib/X64/TdVmcall.nasm | 145 +++++++++++++++++++++++
6 files changed, 448 insertions(+)
create mode 100644 MdePkg/Library/BaseLib/IntelTdxNull.c
create mode 100644 MdePkg/Library/BaseLib/X64/TdCall.nasm
create mode 100644 MdePkg/Library/BaseLib/X64/TdProbe.c
create mode 100644 MdePkg/Library/BaseLib/X64/TdVmcall.nasm
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 6aa0d972186e..bd762843198f 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -4759,6 +4759,68 @@ SpeculationBarrier (
VOID
);
+/**
+ The TDCALL instruction causes a VM exit to the Intel TDX module. It is
+ used to call guest-side Intel TDX functions, either local or a TD exit
+ to the host VMM, as selected by Leaf.
+
+ @param[in] Leaf Leaf number of TDCALL instruction
+ @param[in] Arg1 Arg1
+ @param[in] Arg2 Arg2
+ @param[in] Arg3 Arg3
+ @param[in,out] Results Returned result of the Leaf function
+
+ @return EFI_SUCCESS
+ @return Other See individual leaf functions
+**/
+UINTN
+EFIAPI
+TdCall (
+ IN UINT64 Leaf,
+ IN UINT64 Arg1,
+ IN UINT64 Arg2,
+ IN UINT64 Arg3,
+ IN OUT VOID *Results
+ );
+
+/**
+ TDVMALL is a leaf function 0 for TDCALL. It helps invoke services from the
+ host VMM to pass/receive information.
+
+ @param[in] Leaf Number of sub-functions
+ @param[in] Arg1 Arg1
+ @param[in] Arg2 Arg2
+ @param[in] Arg3 Arg3
+ @param[in] Arg4 Arg4
+ @param[in,out] Results Returned result of the sub-function
+
+ @return EFI_SUCCESS
+ @return Other See individual sub-functions
+
+**/
+UINTN
+EFIAPI
+TdVmCall (
+ IN UINT64 Leaf,
+ IN UINT64 Arg1,
+ IN UINT64 Arg2,
+ IN UINT64 Arg3,
+ IN UINT64 Arg4,
+ IN OUT VOID *Results
+ );
+
+/**
+ Probe if TD is enabled.
+
+ @return TRUE TD is enabled.
+ @return FALSE TD is not enabled.
+**/
+BOOLEAN
+EFIAPI
+TdIsEnabled (
+ VOID
+ );
+
#if defined (MDE_CPU_X64)
//
// The page size for the PVALIDATE instruction
diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index cebda3b210c1..1185f13204df 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -210,6 +210,7 @@
X86RdRand.c
X86PatchInstruction.c
X86SpeculationBarrier.c
+ IntelTdxNull.c
[Sources.X64]
X64/Thunk16.nasm
@@ -293,6 +294,9 @@
X64/ReadCr0.nasm| MSFT
X64/ReadEflags.nasm| MSFT
+ X64/TdCall.nasm
+ X64/TdVmcall.nasm
+ X64/TdProbe.c
X64/Non-existing.c
Math64.c
@@ -333,6 +337,7 @@
Ebc/SpeculationBarrier.c
Unaligned.c
Math64.c
+ IntelTdxNull.c
[Sources.ARM]
Arm/InternalSwitchStack.c
@@ -370,6 +375,8 @@
Arm/MemoryFence.S | GCC
Arm/SpeculationBarrier.S | GCC
+ IntelTdxNull.c
+
[Sources.AARCH64]
Arm/InternalSwitchStack.c
Arm/Unaligned.c
@@ -393,6 +400,8 @@
AArch64/CpuBreakpoint.asm | MSFT
AArch64/SpeculationBarrier.asm | MSFT
+ IntelTdxNull.c
+
[Sources.RISCV64]
Math64.c
Unaligned.c
@@ -409,6 +418,8 @@
RiscV64/RiscVInterrupt.S | GCC
RiscV64/FlushCache.S | GCC
+ IntelTdxNull.c
+
[Packages]
MdePkg/MdePkg.dec
diff --git a/MdePkg/Library/BaseLib/IntelTdxNull.c b/MdePkg/Library/BaseLib/IntelTdxNull.c
new file mode 100644
index 000000000000..ec95470bd43e
--- /dev/null
+++ b/MdePkg/Library/BaseLib/IntelTdxNull.c
@@ -0,0 +1,83 @@
+/** @file
+
+ Null stub of TdxLib
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Uefi/UefiBaseType.h>
+
+/**
+ The TDCALL instruction causes a VM exit to the Intel TDX module. It is
+ used to call guest-side Intel TDX functions, either local or a TD exit
+ to the host VMM, as selected by Leaf.
+ Leaf functions are described at <https://software.intel.com/content/
+ www/us/en/develop/articles/intel-trust-domain-extensions.html>
+
+ @param[in] Leaf Leaf number of TDCALL instruction
+ @param[in] Arg1 Arg1
+ @param[in] Arg2 Arg2
+ @param[in] Arg3 Arg3
+ @param[in,out] Results Returned result of the Leaf function
+
+ @return EFI_SUCCESS
+ @return Other See individual leaf functions
+**/
+UINTN
+EFIAPI
+TdCall (
+ IN UINT64 Leaf,
+ IN UINT64 Arg1,
+ IN UINT64 Arg2,
+ IN UINT64 Arg3,
+ IN OUT VOID *Results
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ TDVMALL is a leaf function 0 for TDCALL. It helps invoke services from the
+ host VMM to pass/receive information.
+
+ @param[in] Leaf Number of sub-functions
+ @param[in] Arg1 Arg1
+ @param[in] Arg2 Arg2
+ @param[in] Arg3 Arg3
+ @param[in] Arg4 Arg4
+ @param[in,out] Results Returned result of the sub-function
+
+ @return EFI_SUCCESS
+ @return Other See individual sub-functions
+
+**/
+UINTN
+EFIAPI
+TdVmCall (
+ IN UINT64 Leaf,
+ IN UINT64 Arg1,
+ IN UINT64 Arg2,
+ IN UINT64 Arg3,
+ IN UINT64 Arg4,
+ IN OUT VOID *Results
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Probe if TD is enabled.
+
+ @return TRUE TD is enabled.
+ @return FALSE TD is not enabled.
+**/
+BOOLEAN
+EFIAPI
+TdIsEnabled (
+ )
+{
+ return FALSE;
+}
diff --git a/MdePkg/Library/BaseLib/X64/TdCall.nasm b/MdePkg/Library/BaseLib/X64/TdCall.nasm
new file mode 100644
index 000000000000..e8a094b0eb3f
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/TdCall.nasm
@@ -0,0 +1,85 @@
+;------------------------------------------------------------------------------
+;*
+;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+%macro tdcall 0
+ db 0x66,0x0f,0x01,0xcc
+%endmacro
+
+%macro tdcall_push_regs 0
+ push rbp
+ mov rbp, rsp
+ push r15
+ push r14
+ push r13
+ push r12
+ push rbx
+ push rsi
+ push rdi
+%endmacro
+
+%macro tdcall_pop_regs 0
+ pop rdi
+ pop rsi
+ pop rbx
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+ pop rbp
+%endmacro
+
+%define number_of_regs_pushed 8
+%define number_of_parameters 4
+
+;
+; Keep these in sync for push_regs/pop_regs, code below
+; uses them to find 5th or greater parameters
+;
+%define first_variable_on_stack_offset \
+ ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8)
+%define second_variable_on_stack_offset \
+ ((first_variable_on_stack_offset) + 8)
+
+; TdCall (
+; UINT64 Leaf, // Rcx
+; UINT64 P1, // Rdx
+; UINT64 P2, // R8
+; UINT64 P3, // R9
+; UINT64 Results, // rsp + 0x28
+; )
+global ASM_PFX(TdCall)
+ASM_PFX(TdCall):
+ tdcall_push_regs
+
+ mov rax, rcx
+ mov rcx, rdx
+ mov rdx, r8
+ mov r8, r9
+
+ tdcall
+
+ ; exit if tdcall reports failure.
+ test rax, rax
+ jnz .exit
+
+ ; test if caller wanted results
+ mov r12, [rsp + first_variable_on_stack_offset ]
+ test r12, r12
+ jz .exit
+ mov [r12 + 0 ], rcx
+ mov [r12 + 8 ], rdx
+ mov [r12 + 16], r8
+ mov [r12 + 24], r9
+ mov [r12 + 32], r10
+ mov [r12 + 40], r11
+.exit:
+ tdcall_pop_regs
+ ret
diff --git a/MdePkg/Library/BaseLib/X64/TdProbe.c b/MdePkg/Library/BaseLib/X64/TdProbe.c
new file mode 100644
index 000000000000..a1cf02717bf2
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/TdProbe.c
@@ -0,0 +1,62 @@
+/** @file
+
+ Copyright (c) 2020-2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Register/Intel/Cpuid.h>
+
+/**
+ Probe if TD is enabled.
+
+ @return TRUE TD is enabled.
+ @return FALSE TD is not enabled.
+**/
+BOOLEAN
+EFIAPI
+TdIsEnabled (
+ )
+{
+ UINT32 Eax;
+ UINT32 Ebx;
+ UINT32 Ecx;
+ UINT32 Edx;
+ UINT32 LargestEax;
+ BOOLEAN TdEnabled;
+
+ TdEnabled = FALSE;
+
+ do {
+ AsmCpuid (CPUID_SIGNATURE, &LargestEax, &Ebx, &Ecx, &Edx);
+
+ if ( (Ebx != CPUID_SIGNATURE_GENUINE_INTEL_EBX)
+ || (Edx != CPUID_SIGNATURE_GENUINE_INTEL_EDX)
+ || (Ecx != CPUID_SIGNATURE_GENUINE_INTEL_ECX))
+ {
+ break;
+ }
+
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &Ecx, NULL);
+ if ((Ecx & BIT31) == 0) {
+ break;
+ }
+
+ if (LargestEax < 0x21) {
+ break;
+ }
+
+ AsmCpuidEx (0x21, 0, &Eax, &Ebx, &Ecx, &Edx);
+ if ( (Ebx != SIGNATURE_32 ('I', 'n', 't', 'e'))
+ || (Edx != SIGNATURE_32 ('l', 'T', 'D', 'X'))
+ || (Ecx != SIGNATURE_32 (' ', ' ', ' ', ' ')))
+ {
+ break;
+ }
+
+ TdEnabled = TRUE;
+ } while (FALSE);
+
+ return TdEnabled;
+}
diff --git a/MdePkg/Library/BaseLib/X64/TdVmcall.nasm b/MdePkg/Library/BaseLib/X64/TdVmcall.nasm
new file mode 100644
index 000000000000..5ecc10b17193
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/TdVmcall.nasm
@@ -0,0 +1,145 @@
+;------------------------------------------------------------------------------
+;*
+;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+%define TDVMCALL_EXPOSE_REGS_MASK 0xffec
+%define TDVMCALL 0x0
+
+%macro tdcall 0
+ db 0x66,0x0f,0x01,0xcc
+%endmacro
+
+%macro tdcall_push_regs 0
+ push rbp
+ mov rbp, rsp
+ push r15
+ push r14
+ push r13
+ push r12
+ push rbx
+ push rsi
+ push rdi
+%endmacro
+
+%macro tdcall_pop_regs 0
+ pop rdi
+ pop rsi
+ pop rbx
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+ pop rbp
+%endmacro
+
+%define number_of_regs_pushed 8
+%define number_of_parameters 4
+
+;
+; Keep these in sync for push_regs/pop_regs, code below
+; uses them to find 5th or greater parameters
+;
+%define first_variable_on_stack_offset \
+ ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8)
+%define second_variable_on_stack_offset \
+ ((first_variable_on_stack_offset) + 8)
+
+%macro tdcall_regs_preamble 2
+ mov rax, %1
+
+ xor rcx, rcx
+ mov ecx, %2
+
+ ; R10 = 0 (standard TDVMCALL)
+
+ xor r10d, r10d
+
+ ; Zero out unused (for standard TDVMCALL) registers to avoid leaking
+ ; secrets to the VMM.
+
+ xor ebx, ebx
+ xor esi, esi
+ xor edi, edi
+
+ xor edx, edx
+ xor ebp, ebp
+ xor r8d, r8d
+ xor r9d, r9d
+%endmacro
+
+%macro tdcall_regs_postamble 0
+ xor ebx, ebx
+ xor esi, esi
+ xor edi, edi
+
+ xor ecx, ecx
+ xor edx, edx
+ xor r8d, r8d
+ xor r9d, r9d
+ xor r10d, r10d
+ xor r11d, r11d
+%endmacro
+
+;------------------------------------------------------------------------------
+; 0 => RAX = TDCALL leaf
+; M => RCX = TDVMCALL register behavior
+; 1 => R10 = standard vs. vendor
+; RDI => R11 = TDVMCALL function / nr
+; RSI = R12 = p1
+; RDX => R13 = p2
+; RCX => R14 = p3
+; R8 => R15 = p4
+
+; UINT64
+; EFIAPI
+; TdVmCall (
+; UINT64 Leaf, // Rcx
+; UINT64 P1, // Rdx
+; UINT64 P2, // R8
+; UINT64 P3, // R9
+; UINT64 P4, // rsp + 0x28
+; UINT64 *Val // rsp + 0x30
+; )
+global ASM_PFX(TdVmCall)
+ASM_PFX(TdVmCall):
+ tdcall_push_regs
+
+ mov r11, rcx
+ mov r12, rdx
+ mov r13, r8
+ mov r14, r9
+ mov r15, [rsp + first_variable_on_stack_offset ]
+
+ tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK
+
+ tdcall
+
+ ; ignore return dataif TDCALL reports failure.
+ test rax, rax
+ jnz .no_return_data
+
+ ; Propagate TDVMCALL success/failure to return value.
+ mov rax, r10
+
+ ; Retrieve the Val pointer.
+ mov r9, [rsp + second_variable_on_stack_offset ]
+ test r9, r9
+ jz .no_return_data
+
+ ; On success, propagate TDVMCALL output value to output param
+ test rax, rax
+ jnz .no_return_data
+ mov [r9], r11
+.no_return_data:
+ tdcall_regs_postamble
+
+ tdcall_pop_regs
+
+ ret
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 03/37] MdePkg: Add TdxLib to wrap Tdx operations
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
2022-02-28 7:20 ` [PATCH V7 01/37] MdePkg: Add Tdx.h Min Xu
2022-02-28 7:20 ` [PATCH V7 02/37] MdePkg: Introduce basic Tdx functions in BaseLib Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 04/37] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception Min Xu
` (34 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky,
Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
TdxLib is created with functions to perform the related Tdx operation.
This includes functions for:
- TdAcceptPages : Accept pending private pages and initialize the pages
to all-0 using the TD ephemeral private key.
- TdExtendRtmr : Extend measurement to one of the RTMR registers.
- TdSharedPageMask: Get the Td guest shared page mask which indicates it
is a Shared or Private page.
- TdMaxVCpuNum : Get the maximum number of virtual CPUs.
- TdVCpuNum : Get the number of virtual CPUs.
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
MdePkg/Include/Library/TdxLib.h | 97 +++++++++++++++
MdePkg/Library/TdxLib/AcceptPages.c | 180 ++++++++++++++++++++++++++++
MdePkg/Library/TdxLib/Rtmr.c | 83 +++++++++++++
MdePkg/Library/TdxLib/TdInfo.c | 114 ++++++++++++++++++
MdePkg/Library/TdxLib/TdxLib.inf | 37 ++++++
MdePkg/Library/TdxLib/TdxLibNull.c | 107 +++++++++++++++++
MdePkg/MdePkg.dec | 3 +
MdePkg/MdePkg.dsc | 1 +
8 files changed, 622 insertions(+)
create mode 100644 MdePkg/Include/Library/TdxLib.h
create mode 100644 MdePkg/Library/TdxLib/AcceptPages.c
create mode 100644 MdePkg/Library/TdxLib/Rtmr.c
create mode 100644 MdePkg/Library/TdxLib/TdInfo.c
create mode 100644 MdePkg/Library/TdxLib/TdxLib.inf
create mode 100644 MdePkg/Library/TdxLib/TdxLibNull.c
diff --git a/MdePkg/Include/Library/TdxLib.h b/MdePkg/Include/Library/TdxLib.h
new file mode 100644
index 000000000000..86539460c9f9
--- /dev/null
+++ b/MdePkg/Include/Library/TdxLib.h
@@ -0,0 +1,97 @@
+/** @file
+ TdxLib definitions
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TDX_LIB_H_
+#define TDX_LIB_H_
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Protocol/DebugSupport.h>
+
+/**
+ This function accepts a pending private page, and initialize the page to
+ all-0 using the TD ephemeral private key.
+
+ @param[in] StartAddress Guest physical address of the private page
+ to accept. [63:52] and [11:0] must be 0.
+ @param[in] NumberOfPages Number of the pages to be accepted.
+ @param[in] PageSize GPA page size. Accept 2M/4K page size.
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+TdAcceptPages (
+ IN UINT64 StartAddress,
+ IN UINT64 NumberOfPages,
+ IN UINT32 PageSize
+ );
+
+/**
+ This function extends one of the RTMR measurement register
+ in TDCS with the provided extension data in memory.
+ RTMR extending supports SHA384 which length is 48 bytes.
+
+ @param[in] Data Point to the data to be extended
+ @param[in] DataLen Length of the data. Must be 48
+ @param[in] Index RTMR index
+
+ @return EFI_SUCCESS
+ @return EFI_INVALID_PARAMETER
+ @return EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+TdExtendRtmr (
+ IN UINT32 *Data,
+ IN UINT32 DataLen,
+ IN UINT8 Index
+ );
+
+/**
+ This function gets the Td guest shared page mask.
+
+ The guest indicates if a page is shared using the Guest Physical Address
+ (GPA) Shared (S) bit. If the GPA Width(GPAW) is 48, the S-bit is bit-47.
+ If the GPAW is 52, the S-bit is bit-51.
+
+ @return Shared page bit mask
+**/
+UINT64
+EFIAPI
+TdSharedPageMask (
+ VOID
+ );
+
+/**
+ This function gets the maximum number of Virtual CPUs that are usable for
+ Td Guest.
+
+ @return maximum Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdMaxVCpuNum (
+ VOID
+ );
+
+/**
+ This function gets the number of Virtual CPUs that are usable for Td
+ Guest.
+
+ @return Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdVCpuNum (
+ VOID
+ );
+
+#endif
diff --git a/MdePkg/Library/TdxLib/AcceptPages.c b/MdePkg/Library/TdxLib/AcceptPages.c
new file mode 100644
index 000000000000..651d47a8d8a1
--- /dev/null
+++ b/MdePkg/Library/TdxLib/AcceptPages.c
@@ -0,0 +1,180 @@
+/** @file
+
+ Unaccepted memory is a special type of private memory. In Td guest
+ TDCALL [TDG.MEM.PAGE.ACCEPT] is invoked to accept the unaccepted
+ memory before use it.
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
+#include <Library/BaseMemoryLib.h>
+
+UINT64 mNumberOfDuplicatedAcceptedPages;
+
+#define TDX_ACCEPTPAGE_MAX_RETRIED 3
+
+// PageSize is mapped to PageLevel like below:
+// 4KB - 0, 2MB - 1
+UINT32 mTdxAcceptPageLevelMap[2] = {
+ SIZE_4KB,
+ SIZE_2MB
+};
+
+#define INVALID_ACCEPT_PAGELEVEL ARRAY_SIZE(mTdxAcceptPageLevelMap)
+
+/**
+ This function gets the PageLevel according to the input page size.
+
+ @param[in] PageSize Page size
+
+ @return UINT32 The mapped page level
+**/
+UINT32
+GetGpaPageLevel (
+ UINT32 PageSize
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < ARRAY_SIZE (mTdxAcceptPageLevelMap); Index++) {
+ if (mTdxAcceptPageLevelMap[Index] == PageSize) {
+ break;
+ }
+ }
+
+ return Index;
+}
+
+/**
+ This function accept a pending private page, and initialize the page to
+ all-0 using the TD ephemeral private key.
+
+ Sometimes TDCALL [TDG.MEM.PAGE.ACCEPT] may return
+ TDX_EXIT_REASON_PAGE_SIZE_MISMATCH. It indicates the input PageLevel is
+ not workable. In this case we need to try to fallback to a smaller
+ PageLevel if possible.
+
+ @param[in] StartAddress Guest physical address of the private
+ page to accept. [63:52] and [11:0] must be 0.
+ @param[in] NumberOfPages Number of the pages to be accepted.
+ @param[in] PageSize GPA page size. Only accept 2M/4K size.
+
+ @return EFI_SUCCESS Accept successfully
+ @return others Indicate other errors
+**/
+EFI_STATUS
+EFIAPI
+TdAcceptPages (
+ IN UINT64 StartAddress,
+ IN UINT64 NumberOfPages,
+ IN UINT32 PageSize
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Address;
+ UINT64 TdxStatus;
+ UINT64 Index;
+ UINT32 GpaPageLevel;
+ UINT32 PageSize2;
+ UINTN Retried;
+
+ Retried = 0;
+
+ if ((StartAddress & ~0xFFFFFFFFFF000ULL) != 0) {
+ ASSERT (FALSE);
+ DEBUG ((DEBUG_ERROR, "Accept page address(0x%llx) is not valid. [63:52] and [11:0] must be 0\n", StartAddress));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Address = StartAddress;
+
+ GpaPageLevel = GetGpaPageLevel (PageSize);
+ if (GpaPageLevel == INVALID_ACCEPT_PAGELEVEL) {
+ ASSERT (FALSE);
+ DEBUG ((DEBUG_ERROR, "Accept page size must be 4K/2M. Invalid page size - 0x%llx\n", PageSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < NumberOfPages; Index++) {
+ Retried = 0;
+
+DoAcceptPage:
+ TdxStatus = TdCall (TDCALL_TDACCEPTPAGE, Address | GpaPageLevel, 0, 0, 0);
+ if (TdxStatus != TDX_EXIT_REASON_SUCCESS) {
+ if ((TdxStatus & ~0xFFFFULL) == TDX_EXIT_REASON_PAGE_ALREADY_ACCEPTED) {
+ //
+ // Already accepted
+ //
+ mNumberOfDuplicatedAcceptedPages++;
+ DEBUG ((DEBUG_WARN, "Page at Address (0x%llx) has already been accepted. - %d\n", Address, mNumberOfDuplicatedAcceptedPages));
+ } else if ((TdxStatus & ~0xFFFFULL) == TDX_EXIT_REASON_PAGE_SIZE_MISMATCH) {
+ //
+ // GpaPageLevel is mismatch, fall back to a smaller GpaPageLevel if possible
+ //
+ DEBUG ((DEBUG_VERBOSE, "Address %llx cannot be accepted in PageLevel of %d\n", Address, GpaPageLevel));
+
+ if (GpaPageLevel == 0) {
+ //
+ // Cannot fall back to smaller page level
+ //
+ DEBUG ((DEBUG_ERROR, "AcceptPage cannot fallback from PageLevel %d\n", GpaPageLevel));
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ } else {
+ //
+ // Fall back to a smaller page size
+ //
+ PageSize2 = mTdxAcceptPageLevelMap[GpaPageLevel - 1];
+ Status = TdAcceptPages (Address, 512, PageSize2);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ } else if ((TdxStatus & ~0xFFFFULL) == TDX_EXIT_REASON_OPERAND_BUSY) {
+ //
+ // Concurrent TDG.MEM.PAGE.ACCEPT is using the same Secure EPT entry
+ // So try it again. There is a max retried count. If Retried exceeds the max count,
+ // report the error and quit.
+ //
+ Retried += 1;
+ if (Retried > TDX_ACCEPTPAGE_MAX_RETRIED) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "Address %llx (%d) failed to be accepted because of OPERAND_BUSY. Retried %d time.\n",
+ Address,
+ Index,
+ Retried
+ ));
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ } else {
+ goto DoAcceptPage;
+ }
+ } else {
+ //
+ // Other errors
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "Address %llx (%d) failed to be accepted. Error = 0x%llx\n",
+ Address,
+ Index,
+ TdxStatus
+ ));
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+ }
+
+ Address += PageSize;
+ }
+
+ return Status;
+}
diff --git a/MdePkg/Library/TdxLib/Rtmr.c b/MdePkg/Library/TdxLib/Rtmr.c
new file mode 100644
index 000000000000..bdc91b3ebe6a
--- /dev/null
+++ b/MdePkg/Library/TdxLib/Rtmr.c
@@ -0,0 +1,83 @@
+/** @file
+
+ Extends one of the RTMR measurement registers in TDCS with the provided
+ extension data in memory.
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TdxLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <IndustryStandard/Tpm20.h>
+#include <IndustryStandard/Tdx.h>
+
+#define RTMR_COUNT 4
+#define TD_EXTEND_BUFFER_LEN (64 + 48)
+
+UINT8 mExtendBuffer[TD_EXTEND_BUFFER_LEN];
+
+/**
+ This function extends one of the RTMR measurement register
+ in TDCS with the provided extension data in memory.
+ RTMR extending supports SHA384 which length is 48 bytes.
+
+ @param[in] Data Point to the data to be extended
+ @param[in] DataLen Length of the data. Must be 48
+ @param[in] Index RTMR index
+
+ @return EFI_SUCCESS
+ @return EFI_INVALID_PARAMETER
+ @return EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+TdExtendRtmr (
+ IN UINT32 *Data,
+ IN UINT32 DataLen,
+ IN UINT8 Index
+ )
+{
+ EFI_STATUS Status;
+ UINT64 TdCallStatus;
+ UINT8 *ExtendBuffer;
+
+ Status = EFI_SUCCESS;
+
+ ASSERT (Data != NULL);
+ ASSERT (DataLen == SHA384_DIGEST_SIZE);
+ ASSERT (Index >= 0 && Index < RTMR_COUNT);
+
+ if ((Data == NULL) || (DataLen != SHA384_DIGEST_SIZE) || (Index >= RTMR_COUNT)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // TD.RTMR.EXTEND requires 64B-aligned guest physical address of
+ // 48B-extension data. We use ALIGN_POINTER(Pointer, 64) to get
+ // the 64B-aligned guest physical address.
+ ExtendBuffer = ALIGN_POINTER (mExtendBuffer, 64);
+ ASSERT (((UINTN)ExtendBuffer & 0x3f) == 0);
+
+ ZeroMem (ExtendBuffer, SHA384_DIGEST_SIZE);
+ CopyMem (ExtendBuffer, Data, SHA384_DIGEST_SIZE);
+
+ TdCallStatus = TdCall (TDCALL_TDEXTENDRTMR, (UINT64)(UINTN)ExtendBuffer, Index, 0, 0);
+
+ if (TdCallStatus == TDX_EXIT_REASON_SUCCESS) {
+ Status = EFI_SUCCESS;
+ } else if (TdCallStatus == TDX_EXIT_REASON_OPERAND_INVALID) {
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "Error returned from TdExtendRtmr call - 0x%lx\n", TdCallStatus));
+ }
+
+ return Status;
+}
diff --git a/MdePkg/Library/TdxLib/TdInfo.c b/MdePkg/Library/TdxLib/TdInfo.c
new file mode 100644
index 000000000000..a40a15116f30
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdInfo.c
@@ -0,0 +1,114 @@
+/** @file
+
+ Fetch the Tdx info.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
+#include <Library/BaseMemoryLib.h>
+
+UINT64 mTdSharedPageMask = 0;
+UINT32 mTdMaxVCpuNum = 0;
+UINT32 mTdVCpuNum = 0;
+BOOLEAN mTdDataReturned = FALSE;
+
+/**
+ This function call TDCALL_TDINFO to get the TD_RETURN_DATA.
+ If the TDCALL is successful, populate below variables:
+ - mTdSharedPageMask
+ - mTdMaxVCpunum
+ - mTdVCpuNum
+ - mTdDataReturned
+
+ @return TRUE The TDCALL is successful and above variables are populated.
+ @return FALSE The TDCALL is failed. Above variables are not set.
+**/
+BOOLEAN
+GetTdInfo (
+ VOID
+ )
+{
+ UINT64 Status;
+ TD_RETURN_DATA TdReturnData;
+ UINT8 Gpaw;
+
+ Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+ if (Status == TDX_EXIT_REASON_SUCCESS) {
+ Gpaw = (UINT8)(TdReturnData.TdInfo.Gpaw & 0x3f);
+ mTdSharedPageMask = 1ULL << (Gpaw - 1);
+ mTdMaxVCpuNum = TdReturnData.TdInfo.MaxVcpus;
+ mTdVCpuNum = TdReturnData.TdInfo.NumVcpus;
+ mTdDataReturned = TRUE;
+ } else {
+ DEBUG ((DEBUG_ERROR, "Failed call TDCALL_TDINFO. %llx\n", Status));
+ mTdDataReturned = FALSE;
+ }
+
+ return mTdDataReturned;
+}
+
+/**
+ This function gets the Td guest shared page mask.
+
+ The guest indicates if a page is shared using the Guest Physical Address
+ (GPA) Shared (S) bit. If the GPA Width(GPAW) is 48, the S-bit is bit-47.
+ If the GPAW is 52, the S-bit is bit-51.
+
+ @return Shared page bit mask
+**/
+UINT64
+EFIAPI
+TdSharedPageMask (
+ VOID
+ )
+{
+ if (mTdDataReturned) {
+ return mTdSharedPageMask;
+ }
+
+ return GetTdInfo () ? mTdSharedPageMask : 0;
+}
+
+/**
+ This function gets the maximum number of Virtual CPUs that are usable for
+ Td Guest.
+
+ @return maximum Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdMaxVCpuNum (
+ VOID
+ )
+{
+ if (mTdDataReturned) {
+ return mTdMaxVCpuNum;
+ }
+
+ return GetTdInfo () ? mTdMaxVCpuNum : 0;
+}
+
+/**
+ This function gets the number of Virtual CPUs that are usable for Td
+ Guest.
+
+ @return Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdVCpuNum (
+ VOID
+ )
+{
+ if (mTdDataReturned) {
+ return mTdVCpuNum;
+ }
+
+ return GetTdInfo () ? mTdVCpuNum : 0;
+}
diff --git a/MdePkg/Library/TdxLib/TdxLib.inf b/MdePkg/Library/TdxLib/TdxLib.inf
new file mode 100644
index 000000000000..442e63d079da
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdxLib.inf
@@ -0,0 +1,37 @@
+## @file
+# Tdx library
+#
+# Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TdxLib
+ FILE_GUID = 032A8E0D-0C27-40C0-9CAA-23B731C1B223
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TdxLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.IA32]
+ TdxLibNull.c
+
+[Sources.X64]
+ AcceptPages.c
+ Rtmr.c
+ TdInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
diff --git a/MdePkg/Library/TdxLib/TdxLibNull.c b/MdePkg/Library/TdxLib/TdxLibNull.c
new file mode 100644
index 000000000000..83ab929b4a3b
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdxLibNull.c
@@ -0,0 +1,107 @@
+/** @file
+
+ Null stub of TdxLib
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TdxLib.h>
+
+/**
+ This function accepts a pending private page, and initialize the page to
+ all-0 using the TD ephemeral private key.
+
+ @param[in] StartAddress Guest physical address of the private page
+ to accept.
+ @param[in] NumberOfPages Number of the pages to be accepted.
+ @param[in] PageSize GPA page size. Accept 1G/2M/4K page size.
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+TdAcceptPages (
+ IN UINT64 StartAddress,
+ IN UINT64 NumberOfPages,
+ IN UINT32 PageSize
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This function extends one of the RTMR measurement register
+ in TDCS with the provided extension data in memory.
+ RTMR extending supports SHA384 which length is 48 bytes.
+
+ @param[in] Data Point to the data to be extended
+ @param[in] DataLen Length of the data. Must be 48
+ @param[in] Index RTMR index
+
+ @return EFI_SUCCESS
+ @return EFI_INVALID_PARAMETER
+ @return EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+TdExtendRtmr (
+ IN UINT32 *Data,
+ IN UINT32 DataLen,
+ IN UINT8 Index
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This function gets the Td guest shared page mask.
+
+ The guest indicates if a page is shared using the Guest Physical Address
+ (GPA) Shared (S) bit. If the GPA Width(GPAW) is 48, the S-bit is bit-47.
+ If the GPAW is 52, the S-bit is bit-51.
+
+ @return Shared page bit mask
+**/
+UINT64
+EFIAPI
+TdSharedPageMask (
+ VOID
+ )
+{
+ return 0;
+}
+
+/**
+ This function gets the maximum number of Virtual CPUs that are usable for
+ Td Guest.
+
+ @return maximum Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdMaxVCpuNum (
+ VOID
+ )
+{
+ return 0;
+}
+
+/**
+ This function gets the number of Virtual CPUs that are usable for Td
+ Guest.
+
+ @return Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdVCpuNum (
+ VOID
+ )
+{
+ return 0;
+}
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index 59b405928bf8..1934c9840423 100644
--- a/MdePkg/MdePkg.dec
+++ b/MdePkg/MdePkg.dec
@@ -296,6 +296,9 @@
## @libraryclass Provides services to log the SMI handler registration.
SmiHandlerProfileLib|Include/Library/SmiHandlerProfileLib.h
+ ## @libraryclass Provides function to support TDX processing.
+ TdxLib|Include/Library/TdxLib.h
+
[Guids]
#
# GUID defined in UEFI2.1/UEFI2.0/EFI1.1
diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc
index a94959169b2f..d6a7af412be7 100644
--- a/MdePkg/MdePkg.dsc
+++ b/MdePkg/MdePkg.dsc
@@ -175,6 +175,7 @@
MdePkg/Library/SmiHandlerProfileLibNull/SmiHandlerProfileLibNull.inf
MdePkg/Library/MmServicesTableLib/MmServicesTableLib.inf
MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf
+ MdePkg/Library/TdxLib/TdxLib.inf
[Components.EBC]
MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 04/37] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (2 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 03/37] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-03-15 7:15 ` [edk2-devel] [PATCH V7 04/37] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception #ve Ni, Ray
2022-02-28 7:20 ` [PATCH V7 05/37] OvmfPkg: Extend VmgExitLib to handle #VE exception Min Xu
` (33 subsequent siblings)
37 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
VmgExitLib performs the necessary processing to handle a #VC exception.
VmgExitLibNull is a NULL instance of VmgExitLib which provides a
default limited interface. In this commit VmgExitLibNull is extended to
handle a #VE exception with a default limited interface. A full feature
version of #VE handler will be created later.
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>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
UefiCpuPkg/Include/Library/VmgExitLib.h | 28 ++++++++++++++
.../Library/VmgExitLibNull/VmTdExitNull.c | 38 +++++++++++++++++++
.../Library/VmgExitLibNull/VmgExitLibNull.inf | 1 +
3 files changed, 67 insertions(+)
create mode 100644 UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c
diff --git a/UefiCpuPkg/Include/Library/VmgExitLib.h b/UefiCpuPkg/Include/Library/VmgExitLib.h
index ebda1c3d907c..f9f911099a7b 100644
--- a/UefiCpuPkg/Include/Library/VmgExitLib.h
+++ b/UefiCpuPkg/Include/Library/VmgExitLib.h
@@ -15,6 +15,8 @@
#include <Protocol/DebugSupport.h>
#include <Register/Amd/Ghcb.h>
+#define VE_EXCEPTION 20
+
/**
Perform VMGEXIT.
@@ -142,4 +144,30 @@ VmgExitHandleVc (
IN OUT EFI_SYSTEM_CONTEXT SystemContext
);
+/**
+ Handle a #VE exception.
+
+ Performs the necessary processing to handle a #VE exception.
+
+ The base library function returns an error equal to VE_EXCEPTION,
+ to be propagated to the standard exception handling stack.
+
+ @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set
+ as value to use on error.
+ @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT
+
+ @retval EFI_SUCCESS Exception handled
+ @retval EFI_UNSUPPORTED #VE not supported, (new) exception value to
+ propagate provided
+ @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to
+ propagate provided
+
+**/
+EFI_STATUS
+EFIAPI
+VmTdExitHandleVe (
+ IN OUT EFI_EXCEPTION_TYPE *ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ );
+
#endif
diff --git a/UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c b/UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c
new file mode 100644
index 000000000000..6a4e8087cb89
--- /dev/null
+++ b/UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c
@@ -0,0 +1,38 @@
+/** @file
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Base.h>
+#include <Uefi.h>
+#include <Library/VmgExitLib.h>
+
+/**
+ Handle a #VE exception.
+
+ Performs the necessary processing to handle a #VE exception.
+
+ @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set
+ as value to use on error.
+ @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT
+
+ @retval EFI_SUCCESS Exception handled
+ @retval EFI_UNSUPPORTED #VE not supported, (new) exception value to
+ propagate provided
+ @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to
+ propagate provided
+
+**/
+EFI_STATUS
+EFIAPI
+VmTdExitHandleVe (
+ IN OUT EFI_EXCEPTION_TYPE *ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ *ExceptionType = VE_EXCEPTION;
+
+ return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf b/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
index d8770a21c355..4aab601939ff 100644
--- a/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+++ b/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
@@ -17,6 +17,7 @@
[Sources.common]
VmgExitLibNull.c
+ VmTdExitNull.c
[Packages]
MdePkg/MdePkg.dec
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 05/37] OvmfPkg: Extend VmgExitLib to handle #VE exception
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (3 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 04/37] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 06/37] UefiCpuPkg/CpuExceptionHandler: Add base support for the " Min Xu
` (32 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jiewen Yao, Jordan Justen, Brijesh Singh,
Erdem Aktas, James Bottomley, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
The base VmgExitLib library provides a default limited interface to
handle #VE exception. To provide full support, the OVMF version of
VmgExitLib is extended to provide full support of #VE handler.
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf | 3 +-
OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h | 32 +
.../Library/VmgExitLib/VmTdExitVeHandler.c | 559 ++++++++++++++++++
OvmfPkg/Library/VmgExitLib/VmgExitLib.inf | 2 +
.../Library/VmgExitLib/X64/TdVmcallCpuid.nasm | 146 +++++
5 files changed, 741 insertions(+), 1 deletion(-)
create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
create mode 100644 OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm
diff --git a/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
index 78207fa0f9c9..f9bd4974f6dc 100644
--- a/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
+++ b/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
@@ -25,6 +25,8 @@
VmgExitVcHandler.c
VmgExitVcHandler.h
SecVmgExitVcHandler.c
+ VmTdExitVeHandler.c
+ X64/TdVmcallCpuid.nasm
[Packages]
MdePkg/MdePkg.dec
@@ -44,4 +46,3 @@
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
-
diff --git a/OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h b/OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
new file mode 100644
index 000000000000..7eacd0872f46
--- /dev/null
+++ b/OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
@@ -0,0 +1,32 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef VMTD_EXIT_HANDLER_H_
+#define VMTD_EXIT_HANDLER_H_
+
+#include <Base.h>
+#include <Uefi.h>
+
+/**
+ This function enable the TD guest to request the VMM to emulate CPUID
+ operation, especially for non-architectural, CPUID leaves.
+
+ @param[in] Eax Main leaf of the CPUID
+ @param[in] Ecx Sub-leaf of the CPUID
+ @param[out] Results Returned result of CPUID operation
+
+ @return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+TdVmCallCpuid (
+ IN UINT64 Eax,
+ IN UINT64 Ecx,
+ OUT VOID *Results
+ );
+
+#endif
diff --git a/OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c b/OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
new file mode 100644
index 000000000000..b73e877c093b
--- /dev/null
+++ b/OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
@@ -0,0 +1,559 @@
+/** @file
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "VmTdExitHandler.h"
+#include <Library/VmgExitLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <IndustryStandard/InstructionParsing.h>
+
+typedef union {
+ struct {
+ UINT32 Eax;
+ UINT32 Edx;
+ } Regs;
+ UINT64 Val;
+} MSR_DATA;
+
+typedef union {
+ UINT8 Val;
+ struct {
+ UINT8 B : 1;
+ UINT8 X : 1;
+ UINT8 R : 1;
+ UINT8 W : 1;
+ } Bits;
+} REX;
+
+typedef union {
+ UINT8 Val;
+ struct {
+ UINT8 Rm : 3;
+ UINT8 Reg : 3;
+ UINT8 Mod : 2;
+ } Bits;
+} MODRM;
+
+typedef struct {
+ UINT64 Regs[4];
+} CPUID_DATA;
+
+/**
+ Handle an CPUID event.
+
+ Use the TDVMCALL instruction to handle cpuid #ve
+
+ @param[in, out] Regs x64 processor context
+ @param[in] Veinfo VE Info
+
+ @retval 0 Event handled successfully
+ @return New exception value to propagate
+**/
+STATIC
+UINT64
+EFIAPI
+CpuIdExit (
+ IN EFI_SYSTEM_CONTEXT_X64 *Regs,
+ IN TDCALL_VEINFO_RETURN_DATA *Veinfo
+ )
+{
+ CPUID_DATA CpuIdData;
+ UINT64 Status;
+
+ Status = TdVmCallCpuid (Regs->Rax, Regs->Rcx, &CpuIdData);
+
+ if (Status == 0) {
+ Regs->Rax = CpuIdData.Regs[0];
+ Regs->Rbx = CpuIdData.Regs[1];
+ Regs->Rcx = CpuIdData.Regs[2];
+ Regs->Rdx = CpuIdData.Regs[3];
+ }
+
+ return Status;
+}
+
+/**
+ Handle an IO event.
+
+ Use the TDVMCALL instruction to handle either an IO read or an IO write.
+
+ @param[in, out] Regs x64 processor context
+ @param[in] Veinfo VE Info
+
+ @retval 0 Event handled successfully
+ @return New exception value to propagate
+**/
+STATIC
+UINT64
+EFIAPI
+IoExit (
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
+ IN TDCALL_VEINFO_RETURN_DATA *Veinfo
+ )
+{
+ BOOLEAN Write;
+ UINTN Size;
+ UINTN Port;
+ UINT64 Val;
+ UINT64 RepCnt;
+ UINT64 Status;
+
+ Val = 0;
+ Write = Veinfo->ExitQualification.Io.Direction ? FALSE : TRUE;
+ Size = Veinfo->ExitQualification.Io.Size + 1;
+ Port = Veinfo->ExitQualification.Io.Port;
+
+ if (Veinfo->ExitQualification.Io.String) {
+ //
+ // If REP is set, get rep-cnt from Rcx
+ //
+ RepCnt = Veinfo->ExitQualification.Io.Rep ? Regs->Rcx : 1;
+
+ while (RepCnt) {
+ Val = 0;
+ if (Write == TRUE) {
+ CopyMem (&Val, (VOID *)Regs->Rsi, Size);
+ Regs->Rsi += Size;
+ }
+
+ Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val));
+ if (Status != 0) {
+ break;
+ }
+
+ if (Write == FALSE) {
+ CopyMem ((VOID *)Regs->Rdi, &Val, Size);
+ Regs->Rdi += Size;
+ }
+
+ if (Veinfo->ExitQualification.Io.Rep) {
+ Regs->Rcx -= 1;
+ }
+
+ RepCnt -= 1;
+ }
+ } else {
+ if (Write == TRUE) {
+ CopyMem (&Val, (VOID *)&Regs->Rax, Size);
+ }
+
+ Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val));
+ if ((Status == 0) && (Write == FALSE)) {
+ CopyMem ((VOID *)&Regs->Rax, &Val, Size);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Handle an READ MSR event.
+
+ Use the TDVMCALL instruction to handle msr read
+
+ @param[in, out] Regs x64 processor context
+ @param[in] Veinfo VE Info
+
+ @retval 0 Event handled successfully
+ @return New exception value to propagate
+**/
+STATIC
+UINT64
+ReadMsrExit (
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
+ IN TDCALL_VEINFO_RETURN_DATA *Veinfo
+ )
+{
+ MSR_DATA Data;
+ UINT64 Status;
+
+ Status = TdVmCall (EXIT_REASON_MSR_READ, Regs->Rcx, 0, 0, 0, &Data);
+ if (Status == 0) {
+ Regs->Rax = Data.Regs.Eax;
+ Regs->Rdx = Data.Regs.Edx;
+ }
+
+ return Status;
+}
+
+/**
+ Handle an WRITE MSR event.
+
+ Use the TDVMCALL instruction to handle msr write
+
+ @param[in, out] Regs x64 processor context
+ @param[in] Veinfo VE Info
+
+ @retval 0 Event handled successfully
+ @return New exception value to propagate
+**/
+STATIC
+UINT64
+WriteMsrExit (
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
+ IN TDCALL_VEINFO_RETURN_DATA *Veinfo
+ )
+{
+ UINT64 Status;
+ MSR_DATA Data;
+
+ Data.Regs.Eax = (UINT32)Regs->Rax;
+ Data.Regs.Edx = (UINT32)Regs->Rdx;
+
+ Status = TdVmCall (EXIT_REASON_MSR_WRITE, Regs->Rcx, Data.Val, 0, 0, NULL);
+
+ return Status;
+}
+
+STATIC
+VOID
+EFIAPI
+TdxDecodeInstruction (
+ IN UINT8 *Rip
+ )
+{
+ UINTN i;
+
+ DEBUG ((DEBUG_INFO, "TDX: #TD[EPT] instruction (%p):", Rip));
+ for (i = 0; i < 15; i++) {
+ DEBUG ((DEBUG_INFO, "%02x:", Rip[i]));
+ }
+
+ DEBUG ((DEBUG_INFO, "\n"));
+}
+
+#define TDX_DECODER_BUG_ON(x) \
+ if ((x)) { \
+ TdxDecodeInstruction(Rip); \
+ TdVmCall(TDVMCALL_HALT, 0, 0, 0, 0, 0); \
+ }
+
+STATIC
+UINT64 *
+EFIAPI
+GetRegFromContext (
+ IN EFI_SYSTEM_CONTEXT_X64 *Regs,
+ IN UINTN RegIndex
+ )
+{
+ switch (RegIndex) {
+ case 0: return &Regs->Rax;
+ break;
+ case 1: return &Regs->Rcx;
+ break;
+ case 2: return &Regs->Rdx;
+ break;
+ case 3: return &Regs->Rbx;
+ break;
+ case 4: return &Regs->Rsp;
+ break;
+ case 5: return &Regs->Rbp;
+ break;
+ case 6: return &Regs->Rsi;
+ break;
+ case 7: return &Regs->Rdi;
+ break;
+ case 8: return &Regs->R8;
+ break;
+ case 9: return &Regs->R9;
+ break;
+ case 10: return &Regs->R10;
+ break;
+ case 11: return &Regs->R11;
+ break;
+ case 12: return &Regs->R12;
+ break;
+ case 13: return &Regs->R13;
+ break;
+ case 14: return &Regs->R14;
+ break;
+ case 15: return &Regs->R15;
+ break;
+ }
+
+ return NULL;
+}
+
+/**
+ Handle an MMIO event.
+
+ Use the TDVMCALL instruction to handle either an mmio read or an mmio write.
+
+ @param[in, out] Regs x64 processor context
+ @param[in] Veinfo VE Info
+
+ @retval 0 Event handled successfully
+ @return New exception value to propagate
+**/
+STATIC
+INTN
+EFIAPI
+MmioExit (
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
+ IN TDCALL_VEINFO_RETURN_DATA *Veinfo
+ )
+{
+ UINT64 Status;
+ UINT32 MmioSize;
+ UINT32 RegSize;
+ UINT8 OpCode;
+ BOOLEAN SeenRex;
+ UINT64 *Reg;
+ UINT8 *Rip;
+ UINT64 Val;
+ UINT32 OpSize;
+ MODRM ModRm;
+ REX Rex;
+
+ Rip = (UINT8 *)Regs->Rip;
+ Val = 0;
+ Rex.Val = 0;
+ SeenRex = FALSE;
+
+ //
+ // Default to 32bit transfer
+ //
+ OpSize = 4;
+
+ do {
+ OpCode = *Rip++;
+ if (OpCode == 0x66) {
+ OpSize = 2;
+ } else if ((OpCode == 0x64) || (OpCode == 0x65) || (OpCode == 0x67)) {
+ continue;
+ } else if ((OpCode >= 0x40) && (OpCode <= 0x4f)) {
+ SeenRex = TRUE;
+ Rex.Val = OpCode;
+ } else {
+ break;
+ }
+ } while (TRUE);
+
+ //
+ // We need to have at least 2 more bytes for this instruction
+ //
+ TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 13);
+
+ OpCode = *Rip++;
+ //
+ // Two-byte opecode, get next byte
+ //
+ if (OpCode == 0x0F) {
+ OpCode = *Rip++;
+ }
+
+ switch (OpCode) {
+ case 0x88:
+ case 0x8A:
+ case 0xB6:
+ MmioSize = 1;
+ break;
+ case 0xB7:
+ MmioSize = 2;
+ break;
+ default:
+ MmioSize = Rex.Bits.W ? 8 : OpSize;
+ break;
+ }
+
+ /* Punt on AH/BH/CH/DH unless it shows up. */
+ ModRm.Val = *Rip++;
+ TDX_DECODER_BUG_ON (MmioSize == 1 && ModRm.Bits.Reg > 4 && !SeenRex && OpCode != 0xB6);
+ Reg = GetRegFromContext (Regs, ModRm.Bits.Reg | ((int)Rex.Bits.R << 3));
+ TDX_DECODER_BUG_ON (!Reg);
+
+ if (ModRm.Bits.Rm == 4) {
+ ++Rip; /* SIB byte */
+ }
+
+ if ((ModRm.Bits.Mod == 2) || ((ModRm.Bits.Mod == 0) && (ModRm.Bits.Rm == 5))) {
+ Rip += 4; /* DISP32 */
+ } else if (ModRm.Bits.Mod == 1) {
+ ++Rip; /* DISP8 */
+ }
+
+ switch (OpCode) {
+ case 0x88:
+ case 0x89:
+ CopyMem ((void *)&Val, Reg, MmioSize);
+ Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0);
+ break;
+ case 0xC7:
+ CopyMem ((void *)&Val, Rip, OpSize);
+ Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0);
+ Rip += OpSize;
+ default:
+ //
+ // 32-bit write registers are zero extended to the full register
+ // Hence 'MOVZX r[32/64], r/m16' is
+ // hardcoded to reg size 8, and the straight MOV case has a reg
+ // size of 8 in the 32-bit read case.
+ //
+ switch (OpCode) {
+ case 0xB6:
+ RegSize = Rex.Bits.W ? 8 : OpSize;
+ break;
+ case 0xB7:
+ RegSize = 8;
+ break;
+ default:
+ RegSize = MmioSize == 4 ? 8 : MmioSize;
+ break;
+ }
+
+ Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 0, Veinfo->GuestPA, 0, &Val);
+ if (Status == 0) {
+ ZeroMem (Reg, RegSize);
+ CopyMem (Reg, (void *)&Val, MmioSize);
+ }
+ }
+
+ if (Status == 0) {
+ TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 15);
+
+ //
+ // We change instruction length to reflect true size so handler can
+ // bump rip
+ //
+ Veinfo->ExitInstructionLength = (UINT32)((UINT64)Rip - Regs->Rip);
+ }
+
+ return Status;
+}
+
+/**
+ Handle a #VE exception.
+
+ Performs the necessary processing to handle a #VE exception.
+
+ @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set
+ as value to use on error.
+ @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT
+
+ @retval EFI_SUCCESS Exception handled
+ @retval EFI_UNSUPPORTED #VE not supported, (new) exception value to
+ propagate provided
+ @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to
+ propagate provided
+
+**/
+EFI_STATUS
+EFIAPI
+VmTdExitHandleVe (
+ IN OUT EFI_EXCEPTION_TYPE *ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINT64 Status;
+ TD_RETURN_DATA ReturnData;
+ EFI_SYSTEM_CONTEXT_X64 *Regs;
+
+ Regs = SystemContext.SystemContextX64;
+ Status = TdCall (TDCALL_TDGETVEINFO, 0, 0, 0, &ReturnData);
+ ASSERT (Status == 0);
+ if (Status != 0) {
+ DEBUG ((DEBUG_ERROR, "#VE happened. TDGETVEINFO failed with Status = 0x%llx\n", Status));
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+
+ switch (ReturnData.VeInfo.ExitReason) {
+ case EXIT_REASON_CPUID:
+ Status = CpuIdExit (Regs, &ReturnData.VeInfo);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "CPUID #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",
+ ReturnData.VeInfo.ExitReason,
+ ReturnData.VeInfo.ExitQualification.Val
+ ));
+ break;
+
+ case EXIT_REASON_HLT:
+ Status = TdVmCall (EXIT_REASON_HLT, 0, 0, 0, 0, 0);
+ break;
+
+ case EXIT_REASON_IO_INSTRUCTION:
+ Status = IoExit (Regs, &ReturnData.VeInfo);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "IO_Instruction #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",
+ ReturnData.VeInfo.ExitReason,
+ ReturnData.VeInfo.ExitQualification.Val
+ ));
+ break;
+
+ case EXIT_REASON_MSR_READ:
+ Status = ReadMsrExit (Regs, &ReturnData.VeInfo);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "RDMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n",
+ ReturnData.VeInfo.ExitReason,
+ ReturnData.VeInfo.ExitQualification.Val,
+ Regs->Rcx,
+ Status
+ ));
+ break;
+
+ case EXIT_REASON_MSR_WRITE:
+ Status = WriteMsrExit (Regs, &ReturnData.VeInfo);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "WRMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n",
+ ReturnData.VeInfo.ExitReason,
+ ReturnData.VeInfo.ExitQualification.Val,
+ Regs->Rcx,
+ Status
+ ));
+ break;
+
+ case EXIT_REASON_EPT_VIOLATION:
+ Status = MmioExit (Regs, &ReturnData.VeInfo);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "MMIO #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",
+ ReturnData.VeInfo.ExitReason,
+ ReturnData.VeInfo.ExitQualification.Val
+ ));
+ break;
+
+ case EXIT_REASON_VMCALL:
+ case EXIT_REASON_MWAIT_INSTRUCTION:
+ case EXIT_REASON_MONITOR_INSTRUCTION:
+ case EXIT_REASON_WBINVD:
+ case EXIT_REASON_RDPMC:
+ /* Handle as nops. */
+ break;
+
+ default:
+ DEBUG ((
+ DEBUG_ERROR,
+ "Unsupported #VE happened, ExitReason is %d, ExitQualification = 0x%x.\n",
+ ReturnData.VeInfo.ExitReason,
+ ReturnData.VeInfo.ExitQualification.Val
+ ));
+
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+ }
+
+ if (Status) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "#VE Error (0x%llx) returned from host, ExitReason is %d, ExitQualification = 0x%x.\n",
+ Status,
+ ReturnData.VeInfo.ExitReason,
+ ReturnData.VeInfo.ExitQualification.Val
+ ));
+
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+
+ SystemContext.SystemContextX64->Rip += ReturnData.VeInfo.ExitInstructionLength;
+ return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
index 7963670e7d30..255b0c1a2f7f 100644
--- a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
+++ b/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
@@ -25,6 +25,8 @@
VmgExitVcHandler.c
VmgExitVcHandler.h
PeiDxeVmgExitVcHandler.c
+ VmTdExitVeHandler.c
+ X64/TdVmcallCpuid.nasm
[Packages]
MdePkg/MdePkg.dec
diff --git a/OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm b/OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm
new file mode 100644
index 000000000000..fa86440904fe
--- /dev/null
+++ b/OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm
@@ -0,0 +1,146 @@
+;------------------------------------------------------------------------------
+;*
+;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+%define TDVMCALL_EXPOSE_REGS_MASK 0xffec
+%define TDVMCALL 0x0
+%define EXIT_REASON_CPUID 0xa
+
+%macro tdcall 0
+ db 0x66,0x0f,0x01,0xcc
+%endmacro
+
+%macro tdcall_push_regs 0
+ push rbp
+ mov rbp, rsp
+ push r15
+ push r14
+ push r13
+ push r12
+ push rbx
+ push rsi
+ push rdi
+%endmacro
+
+%macro tdcall_pop_regs 0
+ pop rdi
+ pop rsi
+ pop rbx
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+ pop rbp
+%endmacro
+
+%define number_of_regs_pushed 8
+%define number_of_parameters 4
+
+;
+; Keep these in sync for push_regs/pop_regs, code below
+; uses them to find 5th or greater parameters
+;
+%define first_variable_on_stack_offset \
+ ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8)
+%define second_variable_on_stack_offset \
+ ((first_variable_on_stack_offset) + 8)
+
+%macro tdcall_regs_preamble 2
+ mov rax, %1
+
+ xor rcx, rcx
+ mov ecx, %2
+
+ ; R10 = 0 (standard TDVMCALL)
+
+ xor r10d, r10d
+
+ ; Zero out unused (for standard TDVMCALL) registers to avoid leaking
+ ; secrets to the VMM.
+
+ xor ebx, ebx
+ xor esi, esi
+ xor edi, edi
+
+ xor edx, edx
+ xor ebp, ebp
+ xor r8d, r8d
+ xor r9d, r9d
+ xor r14, r14
+ xor r15, r15
+%endmacro
+
+%macro tdcall_regs_postamble 0
+ xor ebx, ebx
+ xor esi, esi
+ xor edi, edi
+
+ xor ecx, ecx
+ xor edx, edx
+ xor r8d, r8d
+ xor r9d, r9d
+ xor r10d, r10d
+ xor r11d, r11d
+%endmacro
+
+;------------------------------------------------------------------------------
+; 0 => RAX = TDCALL leaf / TDVMCALL
+; M => RCX = TDVMCALL register behavior
+; 0xa => R11 = TDVMCALL function / CPUID
+; RCX => R12 = p1
+; RDX => R13 = p2
+;
+; UINT64
+; EFIAPI
+; TdVmCallCpuid (
+; UINT64 EaxIn, // Rcx
+; UINT64 EcxIn, // Rdx
+; UINT64 *Results // R8
+; )
+global ASM_PFX(TdVmCallCpuid)
+ASM_PFX(TdVmCallCpuid):
+ tdcall_push_regs
+
+ mov r11, EXIT_REASON_CPUID
+ mov r12, rcx
+ mov r13, rdx
+
+ ; Save *results pointers
+ push r8
+
+ tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK
+
+ tdcall
+
+ ; ignore return data if TDCALL reports failure.
+ test rax, rax
+ jnz .no_return_data
+
+ ; Propagate TDVMCALL success/failure to return value.
+ mov rax, r10
+ test rax, rax
+ jnz .no_return_data
+
+ ; Retrieve *Results
+ pop r8
+ test r8, r8
+ jz .no_return_data
+ ; Caller pass in buffer so store results r12-r15 contains eax-edx
+ mov [r8 + 0], r12
+ mov [r8 + 8], r13
+ mov [r8 + 16], r14
+ mov [r8 + 24], r15
+
+.no_return_data:
+ tdcall_regs_postamble
+
+ tdcall_pop_regs
+
+ ret
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 06/37] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (4 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 05/37] OvmfPkg: Extend VmgExitLib to handle #VE exception Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-03-15 7:17 ` [edk2-devel] [PATCH V7 06/37] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception #ve Ni, Ray
2022-02-28 7:20 ` [PATCH V7 07/37] MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic Min Xu
` (31 subsequent siblings)
37 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
Add base support to handle #VE exceptions. Update the common exception
handlers to invoke the VmTdExitHandleVe () function of the VmgExitLib
library when a #VE is encountered. A non-zero return code will propagate
to the targeted exception handler.
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>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
.../PeiDxeSmmCpuException.c | 17 +++++++++++++++++
.../SecPeiCpuException.c | 18 ++++++++++++++++++
2 files changed, 35 insertions(+)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
index 762ea2460f91..4fa3f8202a33 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
@@ -45,6 +45,23 @@ CommonExceptionHandlerWorker (
}
}
+ if (ExceptionType == VE_EXCEPTION) {
+ EFI_STATUS Status;
+ //
+ // #VE needs to be handled immediately upon enabling exception handling
+ // and therefore can't use the RegisterCpuInterruptHandler() interface.
+ //
+ // Handle the #VE:
+ // On EFI_SUCCESS - Exception has been handled, return
+ // On other - ExceptionType contains (possibly new) exception
+ // value
+ //
+ Status = VmTdExitHandleVe (&ExceptionType, SystemContext);
+ if (!EFI_ERROR (Status)) {
+ return;
+ }
+ }
+
ExceptionHandlerContext = (EXCEPTION_HANDLER_CONTEXT *)(UINTN)(SystemContext.SystemContextIa32);
ReservedVectors = ExceptionHandlerData->ReservedVectors;
ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
index c614d5b0b6f1..148d89011721 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
@@ -43,6 +43,24 @@ CommonExceptionHandler (
}
}
+ if (ExceptionType == VE_EXCEPTION) {
+ EFI_STATUS Status;
+ //
+ // #VE needs to be handled immediately upon enabling exception handling
+ // and therefore can't use the RegisterCpuInterruptHandler() interface
+ // (which isn't supported under Sec and Pei anyway).
+ //
+ // Handle the #VE:
+ // On EFI_SUCCESS - Exception has been handled, return
+ // On other - ExceptionType contains (possibly new) exception
+ // value
+ //
+ Status = VmTdExitHandleVe (&ExceptionType, SystemContext);
+ if (!EFI_ERROR (Status)) {
+ return;
+ }
+ }
+
//
// Initialize the serial port before dumping.
//
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 06/37] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception #ve
2022-02-28 7:20 ` [PATCH V7 06/37] UefiCpuPkg/CpuExceptionHandler: Add base support for the " Min Xu
@ 2022-03-15 7:17 ` Ni, Ray
2022-03-15 7:37 ` Min Xu
0 siblings, 1 reply; 72+ messages in thread
From: Ni, Ray @ 2022-03-15 7:17 UTC (permalink / raw)
To: Min Xu, devel
[-- Attachment #1: Type: text/plain, Size: 125 bytes --]
Reviewed-by: Ray Ni <ray.ni@intel.com>
Min, any reason that you don't change to switch-case for VC/VE handling together?
[-- Attachment #2: Type: text/html, Size: 191 bytes --]
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 06/37] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception #ve
2022-03-15 7:17 ` [edk2-devel] [PATCH V7 06/37] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception #ve Ni, Ray
@ 2022-03-15 7:37 ` Min Xu
0 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-03-15 7:37 UTC (permalink / raw)
To: Ni, Ray, devel@edk2.groups.io
[-- Attachment #1: Type: text/plain, Size: 572 bytes --]
Oh, I can refactor the code in PeiDxeSmmCpuException.c and SecPeiCpuException.c with switch-case for VC/VE handling together. It will be updated in the next version.
From: Ni, Ray <ray.ni@intel.com>
Sent: Tuesday, March 15, 2022 3:17 PM
To: Xu, Min M <min.m.xu@intel.com>; devel@edk2.groups.io
Subject: Re: [edk2-devel] [PATCH V7 06/37] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception #ve
Reviewed-by: Ray Ni ray.ni@intel.com<mailto:ray.ni@intel.com>
Min, any reason that you don't change to switch-case for VC/VE handling together?
[-- Attachment #2: Type: text/html, Size: 2668 bytes --]
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH V7 07/37] MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (5 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 06/37] UefiCpuPkg/CpuExceptionHandler: Add base support for the " Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 08/37] MdePkg: Support mmio " Min Xu
` (30 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
Intel TDX architecture does not prescribe a specific software convention
to perform I/O from the guest TD. Guest TD providers have many choices to
provide I/O to the guest. The common I/O models are emulated devices,
para-virtualized devices, SRIOV devices and Direct Device assignments.
TDVF chooses para-virtualized I/O (Choice-A) which use the TDG.VP.VMCALL
function to invoke the funtions provided by the host VMM to perform I/O.
Another choice (Choice-B) is the emulation performed by the #VE handler.
There are 2 benefits of para-virtualized I/O:
1. Performance.
VMEXIT/VMENTRY is skipped so that the performance is better than #VE
handler.
2. De-couple with #VE handler.
Choice-B depends on the #VE handler which means I/O is not available
until #VE handler is installed. For example, in PEI phase #VE handler
is installed in CpuMpPei, while communication with Qemu (via I/O port)
happen earlier than it.
IoLibInternalTdx.c provides the helper functions for Tdx guest.
IoLibInternalTdxNull.c provides the null version of the helper functions.
It is included in the Non-X64 IoLib so that the build will not be broken.
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@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>
---
.../BaseIoLibIntrinsicSev.inf | 2 +
.../BaseIoLibIntrinsic/IoLibInternalTdx.c | 675 ++++++++++++++++++
.../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 497 +++++++++++++
MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h | 410 +++++++++++
4 files changed, 1584 insertions(+)
create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
index 34f9d1d1062f..336d79736d9a 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
@@ -51,3 +51,5 @@
BaseLib
RegisterFilterLib
+[LibraryClasses.X64]
+ TdxLib
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
new file mode 100644
index 000000000000..368eea49116a
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
@@ -0,0 +1,675 @@
+/** @file
+ TDX I/O Library routines.
+
+ Copyright (c) 2020-2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "BaseIoLibIntrinsicInternal.h"
+#include <Include/IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
+#include <Library/BaseLib.h>
+#include <Register/Intel/Cpuid.h>
+#include <Base.h>
+#include "IoLibTdx.h"
+
+// Size of TDVMCALL Access, including IO and MMIO
+#define TDVMCALL_ACCESS_SIZE_1 1
+#define TDVMCALL_ACCESS_SIZE_2 2
+#define TDVMCALL_ACCESS_SIZE_4 4
+#define TDVMCALL_ACCESS_SIZE_8 8
+
+// Direction of TDVMCALL Access, including IO and MMIO
+#define TDVMCALL_ACCESS_READ 0
+#define TDVMCALL_ACCESS_WRITE 1
+
+BOOLEAN mTdxEnabled = FALSE;
+BOOLEAN mTdxProbed = FALSE;
+
+/**
+ Check if it is Tdx guest.
+
+ @return TRUE It is Tdx guest
+ @return FALSE It is not Tdx guest
+
+**/
+BOOLEAN
+EFIAPI
+IsTdxGuest (
+ VOID
+ )
+{
+ if (mTdxProbed) {
+ return mTdxEnabled;
+ }
+
+ mTdxEnabled = TdIsEnabled ();
+ mTdxProbed = TRUE;
+
+ return mTdxEnabled;
+}
+
+/**
+ Reads an 8-bit I/O port.
+
+ TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdIoRead8 (
+ IN UINTN Port
+ )
+{
+ UINT64 Status;
+ UINT64 Val;
+
+ Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_READ, Port, 0, &Val);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+
+ return (UINT8)Val;
+}
+
+/**
+ Reads a 16-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdIoRead16 (
+ IN UINTN Port
+ )
+{
+ UINT64 Status;
+ UINT64 Val;
+
+ ASSERT ((Port & 1) == 0);
+
+ Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_READ, Port, 0, &Val);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+
+ return (UINT16)Val;
+}
+
+/**
+ Reads a 32-bit I/O port.
+
+ TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdIoRead32 (
+ IN UINTN Port
+ )
+{
+ UINT64 Status;
+ UINT64 Val;
+
+ ASSERT ((Port & 3) == 0);
+
+ Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_READ, Port, 0, &Val);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+
+ return (UINT32)Val;
+}
+
+/**
+ Writes an 8-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT8
+EFIAPI
+TdIoWrite8 (
+ IN UINTN Port,
+ IN UINT8 Value
+ )
+{
+ UINT64 Status;
+ UINT64 Val;
+
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_WRITE, Port, Val, 0);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+
+ return Value;
+}
+
+/**
+ Writes a 16-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT16
+EFIAPI
+TdIoWrite16 (
+ IN UINTN Port,
+ IN UINT16 Value
+ )
+{
+ UINT64 Status;
+ UINT64 Val;
+
+ ASSERT ((Port & 1) == 0);
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_WRITE, Port, Val, 0);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+
+ return Value;
+}
+
+/**
+ Writes a 32-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT32
+EFIAPI
+TdIoWrite32 (
+ IN UINTN Port,
+ IN UINT32 Value
+ )
+{
+ UINT64 Status;
+ UINT64 Val;
+
+ ASSERT ((Port & 3) == 0);
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_WRITE, Port, Val, 0);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+
+ return Value;
+}
+
+/**
+ Reads an 8-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdMmioRead8 (
+ IN UINTN Address
+ )
+{
+ UINT64 Value;
+ UINT64 Status;
+
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_READ, Address | TdSharedPageMask (), 0, &Value);
+ if (Status != 0) {
+ Value = *(volatile UINT64 *)Address;
+ }
+
+ return (UINT8)Value;
+}
+
+/**
+ Writes an 8-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read write registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT8
+EFIAPI
+TdMmioWrite8 (
+ IN UINTN Address,
+ IN UINT8 Value
+ )
+{
+ UINT64 Val;
+ UINT64 Status;
+
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_WRITE, Address | TdSharedPageMask (), Val, 0);
+ if (Status != 0) {
+ *(volatile UINT8 *)Address = Value;
+ }
+
+ return Value;
+}
+
+/**
+ Reads a 16-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdMmioRead16 (
+ IN UINTN Address
+ )
+{
+ UINT64 Value;
+ UINT64 Status;
+
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_READ, Address | TdSharedPageMask (), 0, &Value);
+ if (Status != 0) {
+ Value = *(volatile UINT64 *)Address;
+ }
+
+ return (UINT16)Value;
+}
+
+/**
+ Writes a 16-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT16
+EFIAPI
+TdMmioWrite16 (
+ IN UINTN Address,
+ IN UINT16 Value
+ )
+{
+ UINT64 Val;
+ UINT64 Status;
+
+ ASSERT ((Address & 1) == 0);
+
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_WRITE, Address | TdSharedPageMask (), Val, 0);
+ if (Status != 0) {
+ *(volatile UINT16 *)Address = Value;
+ }
+
+ return Value;
+}
+
+/**
+ Reads a 32-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdMmioRead32 (
+ IN UINTN Address
+ )
+{
+ UINT64 Value;
+ UINT64 Status;
+
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_READ, Address | TdSharedPageMask (), 0, &Value);
+ if (Status != 0) {
+ Value = *(volatile UINT64 *)Address;
+ }
+
+ return (UINT32)Value;
+}
+
+/**
+ Writes a 32-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT32
+EFIAPI
+TdMmioWrite32 (
+ IN UINTN Address,
+ IN UINT32 Value
+ )
+{
+ UINT64 Val;
+ UINT64 Status;
+
+ ASSERT ((Address & 3) == 0);
+
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_WRITE, Address | TdSharedPageMask (), Val, 0);
+ if (Status != 0) {
+ *(volatile UINT32 *)Address = Value;
+ }
+
+ return Value;
+}
+
+/**
+ Reads a 64-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT64
+EFIAPI
+TdMmioRead64 (
+ IN UINTN Address
+ )
+{
+ UINT64 Value;
+ UINT64 Status;
+
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_READ, Address | TdSharedPageMask (), 0, &Value);
+ if (Status != 0) {
+ Value = *(volatile UINT64 *)Address;
+ }
+
+ return Value;
+}
+
+/**
+ Writes a 64-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+**/
+UINT64
+EFIAPI
+TdMmioWrite64 (
+ IN UINTN Address,
+ IN UINT64 Value
+ )
+{
+ UINT64 Status;
+ UINT64 Val;
+
+ ASSERT ((Address & 7) == 0);
+
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_WRITE, Address | TdSharedPageMask (), Val, 0);
+ if (Status != 0) {
+ *(volatile UINT64 *)Address = Value;
+ }
+
+ return Value;
+}
+
+/**
+ Reads an 8-bit I/O port fifo into a block of memory.
+
+ Reads the 8-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoRead8 is invoked to read the I/O port fifo.
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ UINT8 *Buf8;
+ UINTN Index;
+
+ Buf8 = (UINT8 *)Buffer;
+ for (Index = 0; Index < Count; Index++) {
+ Buf8[Index] = TdIoRead8 (Port);
+ }
+}
+
+/**
+ Writes a block of memory into an 8-bit I/O port fifo.
+
+ Writes the 8-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoWrite8 is invoked to write data to the I/O port.
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ UINT8 *Buf8;
+ UINTN Index;
+
+ Buf8 = (UINT8 *)Buffer;
+ for (Index = 0; Index < Count; Index++) {
+ TdIoWrite8 (Port, Buf8[Index]);
+ }
+}
+
+/**
+ Reads a 16-bit I/O port fifo into a block of memory.
+
+ Reads the 16-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoRead16 is invoked to read data from the I/O port.
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ UINT16 *Buf16;
+ UINTN Index;
+
+ Buf16 = (UINT16 *)Buffer;
+ for (Index = 0; Index < Count; Index++) {
+ Buf16[Index] = TdIoRead16 (Port);
+ }
+}
+
+/**
+ Writes a block of memory into a 16-bit I/O port fifo.
+
+ Writes the 16-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoWrite16 is invoked to write data to the I/O port.
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ UINT16 *Buf16;
+ UINTN Index;
+
+ Buf16 = (UINT16 *)Buffer;
+ for (Index = 0; Index < Count; Index++) {
+ TdIoWrite16 (Port, Buf16[Index]);
+ }
+}
+
+/**
+ Reads a 32-bit I/O port fifo into a block of memory.
+
+ Reads the 32-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoRead32 is invoked to read data from the I/O port.
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ UINT32 *Buf32;
+ UINTN Index;
+
+ Buf32 = (UINT32 *)Buffer;
+ for (Index = 0; Index < Count; Index++) {
+ Buf32[Index] = TdIoRead32 (Port);
+ }
+}
+
+/**
+ Writes a block of memory into a 32-bit I/O port fifo.
+
+ Writes the 32-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoWrite32 is invoked to write data to the I/O port.
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ UINT32 *Buf32;
+ UINTN Index;
+
+ Buf32 = (UINT32 *)Buffer;
+ for (Index = 0; Index < Count; Index++) {
+ TdIoWrite32 (Port, Buf32[Index]);
+ }
+}
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
new file mode 100644
index 000000000000..7262704d6b14
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
@@ -0,0 +1,497 @@
+/** @file
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"
+
+/**
+ Check if it is Tdx guest.
+
+ @return TRUE It is Tdx guest
+ @return FALSE It is not Tdx guest
+
+**/
+BOOLEAN
+EFIAPI
+IsTdxGuest (
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ Reads an 8-bit I/O port.
+
+ TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdIoRead8 (
+ IN UINTN Port
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Reads a 16-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdIoRead16 (
+ IN UINTN Port
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Reads a 32-bit I/O port.
+
+ TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdIoRead32 (
+ IN UINTN Port
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Writes an 8-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT8
+EFIAPI
+TdIoWrite8 (
+ IN UINTN Port,
+ IN UINT8 Value
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Writes a 16-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT16
+EFIAPI
+TdIoWrite16 (
+ IN UINTN Port,
+ IN UINT16 Value
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Writes a 32-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT32
+EFIAPI
+TdIoWrite32 (
+ IN UINTN Port,
+ IN UINT32 Value
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Reads an 8-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdMmioRead8 (
+ IN UINTN Address
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Writes an 8-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read write registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT8
+EFIAPI
+TdMmioWrite8 (
+ IN UINTN Address,
+ IN UINT8 Val
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Reads a 16-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdMmioRead16 (
+ IN UINTN Address
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Writes a 16-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT16
+EFIAPI
+TdMmioWrite16 (
+ IN UINTN Address,
+ IN UINT16 Val
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Reads a 32-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdMmioRead32 (
+ IN UINTN Address
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Writes a 32-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT32
+EFIAPI
+TdMmioWrite32 (
+ IN UINTN Address,
+ IN UINT32 Val
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Reads a 64-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT64
+EFIAPI
+TdMmioRead64 (
+ IN UINTN Address
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Writes a 64-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+**/
+UINT64
+EFIAPI
+TdMmioWrite64 (
+ IN UINTN Address,
+ IN UINT64 Value
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Reads an 8-bit I/O port fifo into a block of memory.
+
+ Reads the 8-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoRead8 is invoked to read the I/O port fifo.
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Writes a block of memory into an 8-bit I/O port fifo.
+
+ Writes the 8-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoWrite8 is invoked to write data to the I/O port.
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Reads a 16-bit I/O port fifo into a block of memory.
+
+ Reads the 16-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoRead16 is invoked to read data from the I/O port.
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Writes a block of memory into a 16-bit I/O port fifo.
+
+ Writes the 16-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoWrite16 is invoked to write data to the I/O port.
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Reads a 32-bit I/O port fifo into a block of memory.
+
+ Reads the 32-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoRead32 is invoked to read data from the I/O port.
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Writes a block of memory into a 32-bit I/O port fifo.
+
+ Writes the 32-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoWrite32 is invoked to write data to the I/O port.
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ ASSERT (FALSE);
+}
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
new file mode 100644
index 000000000000..ab2fa771f6c8
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
@@ -0,0 +1,410 @@
+/** @file
+ Header file for Tdx IO library.
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef IOLIB_TDX_H_
+#define IOLIB_TDX_H_
+
+/**
+ Check if it is Tdx guest.
+
+ @return TRUE It is Tdx guest
+ @return FALSE It is not Tdx guest
+
+**/
+BOOLEAN
+EFIAPI
+IsTdxGuest (
+ VOID
+ );
+
+/**
+ Reads an 8-bit I/O port.
+
+ TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdIoRead8 (
+ IN UINTN Port
+ );
+
+/**
+ Reads a 16-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdIoRead16 (
+ IN UINTN Port
+ );
+
+/**
+ Reads a 32-bit I/O port.
+
+ TDVMCALL_IO is invoked to read I/O port.
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdIoRead32 (
+ IN UINTN Port
+ );
+
+/**
+ Writes an 8-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT8
+EFIAPI
+TdIoWrite8 (
+ IN UINTN Port,
+ IN UINT8 Value
+ );
+
+/**
+ Writes a 16-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT16
+EFIAPI
+TdIoWrite16 (
+ IN UINTN Port,
+ IN UINT16 Value
+ );
+
+/**
+ Writes a 32-bit I/O port.
+
+ TDVMCALL_IO is invoked to write I/O port.
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+UINT32
+EFIAPI
+TdIoWrite32 (
+ IN UINTN Port,
+ IN UINT32 Value
+ );
+
+/**
+ Reads an 8-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdMmioRead8 (
+ IN UINTN Address
+ );
+
+/**
+ Writes an 8-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read write registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT8
+EFIAPI
+TdMmioWrite8 (
+ IN UINTN Address,
+ IN UINT8 Val
+ );
+
+/**
+ Reads a 16-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdMmioRead16 (
+ IN UINTN Address
+ );
+
+/**
+ Writes a 16-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT16
+EFIAPI
+TdMmioWrite16 (
+ IN UINTN Address,
+ IN UINT16 Val
+ );
+
+/**
+ Reads a 32-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdMmioRead32 (
+ IN UINTN Address
+ );
+
+/**
+ Writes a 32-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+ @return Value.
+
+**/
+UINT32
+EFIAPI
+TdMmioWrite32 (
+ IN UINTN Address,
+ IN UINT32 Val
+ );
+
+/**
+ Reads a 64-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to read MMIO registers.
+
+ @param Address The MMIO register to read.
+
+ @return The value read.
+
+**/
+UINT64
+EFIAPI
+TdMmioRead64 (
+ IN UINTN Address
+ );
+
+/**
+ Writes a 64-bit MMIO register.
+
+ TDVMCALL_MMIO is invoked to write MMIO registers.
+
+ @param Address The MMIO register to write.
+ @param Value The value to write to the MMIO register.
+
+**/
+UINT64
+EFIAPI
+TdMmioWrite64 (
+ IN UINTN Address,
+ IN UINT64 Value
+ );
+
+/**
+ Reads an 8-bit I/O port fifo into a block of memory in Tdx.
+
+ Reads the 8-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a block of memory into an 8-bit I/O port fifo in Tdx.
+
+ Writes the 8-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+/**
+ Reads a 16-bit I/O port fifo into a block of memory in Tdx.
+
+ Reads the 16-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a block of memory into a 16-bit I/O port fifo in Tdx.
+
+ Writes the 16-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+/**
+ Reads a 32-bit I/O port fifo into a block of memory in Tdx.
+
+ Reads the 32-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a block of memory into a 32-bit I/O port fifo in Tdx.
+
+ Writes the 32-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+#endif
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 08/37] MdePkg: Support mmio for Tdx guest in BaseIoLibIntrinsic
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (6 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 07/37] MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 09/37] MdePkg: Support IoFifo " Min Xu
` (29 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky,
Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
TDVF access MMIO with TDG.VP.VMCALL to invoke VMM provided emulation
functions. If the access to MMIO fails, it fall backs to the direct
access.
BaseIoLibIntrinsic.inf is the IoLib used by other packages. It will
not support I/O in Td guest. But some files are shared between
BaseIoLibIntrinsic and BaseIoLibIntrinsicSev (IoLib.c is the example). So
IoLibInternalTdxNull.c (which holds the null stub of the Td I/O routines)
is included in BaseIoLibIntrinsic.inf. BaseIoLibIntrinsic.inf doesn't
import TdxLib so that the Pkgs which include BaseIoLibIntrinsic.inf
need not include TdxLib.
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
.../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf | 2 +
.../BaseIoLibIntrinsicSev.inf | 3 +
MdePkg/Library/BaseIoLibIntrinsic/IoLib.c | 81 +++++++++++++++++--
3 files changed, 78 insertions(+), 8 deletions(-)
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
index 97eeada0656e..27b15d9ae256 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
@@ -34,6 +34,8 @@
IoLibMmioBuffer.c
BaseIoLibIntrinsicInternal.h
IoHighLevel.c
+ IoLibInternalTdxNull.c
+ IoLibTdx.h
[Sources.IA32]
IoLibGcc.c | GCC
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
index 336d79736d9a..a74e54bee8b5 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
@@ -30,17 +30,20 @@
IoLibMmioBuffer.c
BaseIoLibIntrinsicInternal.h
IoHighLevel.c
+ IoLibTdx.h
[Sources.IA32]
IoLibGcc.c | GCC
IoLibMsc.c | MSFT
IoLib.c
+ IoLibInternalTdxNull.c
Ia32/IoFifoSev.nasm
[Sources.X64]
IoLibGcc.c | GCC
IoLibMsc.c | MSFT
IoLib.c
+ IoLibInternalTdx.c
X64/IoFifoSev.nasm
[Packages]
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c
index 9d42e21a691c..5bd02b56a1fa 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c
@@ -7,6 +7,7 @@
**/
#include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"
/**
Reads a 64-bit I/O port.
@@ -69,6 +70,8 @@ IoWrite64 (
If 8-bit MMIO register operations are not supported, then ASSERT().
+ For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
@param Address The MMIO register to read.
@return The value read.
@@ -86,7 +89,13 @@ MmioRead8 (
Flag = FilterBeforeMmIoRead (FilterWidth8, Address, &Value);
if (Flag) {
MemoryFence ();
- Value = *(volatile UINT8 *)Address;
+
+ if (IsTdxGuest ()) {
+ Value = TdMmioRead8 (Address);
+ } else {
+ Value = *(volatile UINT8 *)Address;
+ }
+
MemoryFence ();
}
@@ -104,6 +113,8 @@ MmioRead8 (
If 8-bit MMIO register operations are not supported, then ASSERT().
+ For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
@param Address The MMIO register to write.
@param Value The value to write to the MMIO register.
@@ -122,7 +133,13 @@ MmioWrite8 (
Flag = FilterBeforeMmIoWrite (FilterWidth8, Address, &Value);
if (Flag) {
MemoryFence ();
- *(volatile UINT8 *)Address = Value;
+
+ if (IsTdxGuest ()) {
+ TdMmioWrite8 (Address, Value);
+ } else {
+ *(volatile UINT8 *)Address = Value;
+ }
+
MemoryFence ();
}
@@ -141,6 +158,8 @@ MmioWrite8 (
If 16-bit MMIO register operations are not supported, then ASSERT().
If Address is not aligned on a 16-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
@param Address The MMIO register to read.
@return The value read.
@@ -159,7 +178,13 @@ MmioRead16 (
Flag = FilterBeforeMmIoRead (FilterWidth16, Address, &Value);
if (Flag) {
MemoryFence ();
- Value = *(volatile UINT16 *)Address;
+
+ if (IsTdxGuest ()) {
+ Value = TdMmioRead16 (Address);
+ } else {
+ Value = *(volatile UINT16 *)Address;
+ }
+
MemoryFence ();
}
@@ -178,6 +203,8 @@ MmioRead16 (
If 16-bit MMIO register operations are not supported, then ASSERT().
If Address is not aligned on a 16-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
@param Address The MMIO register to write.
@param Value The value to write to the MMIO register.
@@ -198,7 +225,13 @@ MmioWrite16 (
Flag = FilterBeforeMmIoWrite (FilterWidth16, Address, &Value);
if (Flag) {
MemoryFence ();
- *(volatile UINT16 *)Address = Value;
+
+ if (IsTdxGuest ()) {
+ TdMmioWrite16 (Address, Value);
+ } else {
+ *(volatile UINT16 *)Address = Value;
+ }
+
MemoryFence ();
}
@@ -217,6 +250,8 @@ MmioWrite16 (
If 32-bit MMIO register operations are not supported, then ASSERT().
If Address is not aligned on a 32-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
@param Address The MMIO register to read.
@return The value read.
@@ -236,7 +271,13 @@ MmioRead32 (
Flag = FilterBeforeMmIoRead (FilterWidth32, Address, &Value);
if (Flag) {
MemoryFence ();
- Value = *(volatile UINT32 *)Address;
+
+ if (IsTdxGuest ()) {
+ Value = TdMmioRead32 (Address);
+ } else {
+ Value = *(volatile UINT32 *)Address;
+ }
+
MemoryFence ();
}
@@ -255,6 +296,8 @@ MmioRead32 (
If 32-bit MMIO register operations are not supported, then ASSERT().
If Address is not aligned on a 32-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
@param Address The MMIO register to write.
@param Value The value to write to the MMIO register.
@@ -275,7 +318,13 @@ MmioWrite32 (
Flag = FilterBeforeMmIoWrite (FilterWidth32, Address, &Value);
if (Flag) {
MemoryFence ();
- *(volatile UINT32 *)Address = Value;
+
+ if (IsTdxGuest ()) {
+ TdMmioWrite32 (Address, Value);
+ } else {
+ *(volatile UINT32 *)Address = Value;
+ }
+
MemoryFence ();
}
@@ -294,6 +343,8 @@ MmioWrite32 (
If 64-bit MMIO register operations are not supported, then ASSERT().
If Address is not aligned on a 64-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
@param Address The MMIO register to read.
@return The value read.
@@ -313,7 +364,13 @@ MmioRead64 (
Flag = FilterBeforeMmIoRead (FilterWidth64, Address, &Value);
if (Flag) {
MemoryFence ();
- Value = *(volatile UINT64 *)Address;
+
+ if (IsTdxGuest ()) {
+ Value = TdMmioRead64 (Address);
+ } else {
+ Value = *(volatile UINT64 *)Address;
+ }
+
MemoryFence ();
}
@@ -332,6 +389,8 @@ MmioRead64 (
If 64-bit MMIO register operations are not supported, then ASSERT().
If Address is not aligned on a 64-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
@param Address The MMIO register to write.
@param Value The value to write to the MMIO register.
@@ -350,7 +409,13 @@ MmioWrite64 (
Flag = FilterBeforeMmIoWrite (FilterWidth64, Address, &Value);
if (Flag) {
MemoryFence ();
- *(volatile UINT64 *)Address = Value;
+
+ if (IsTdxGuest ()) {
+ TdMmioWrite64 (Address, Value);
+ } else {
+ *(volatile UINT64 *)Address = Value;
+ }
+
MemoryFence ();
}
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 09/37] MdePkg: Support IoFifo for Tdx guest in BaseIoLibIntrinsic
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (7 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 08/37] MdePkg: Support mmio " Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 10/37] MdePkg: Support IoRead/IoWrite " Min Xu
` (28 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky,
Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
Previously IoFifo functions are in X64/IoFifoSev.nasm which supports
both SEV guest and Legacy guest. IoLibFifo.c is introduced to support
SEV/TDX/Legacy guest in one binary. It checks the guest type in runtime
and call corresponding functions then.
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
.../BaseIoLibIntrinsicSev.inf | 2 +
MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c | 216 ++++++++++++++++++
MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h | 166 ++++++++++++++
.../BaseIoLibIntrinsic/X64/IoFifoSev.nasm | 34 +--
4 files changed, 401 insertions(+), 17 deletions(-)
create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
index a74e54bee8b5..7fe1c60f046e 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
@@ -31,6 +31,7 @@
BaseIoLibIntrinsicInternal.h
IoHighLevel.c
IoLibTdx.h
+ IoLibSev.h
[Sources.IA32]
IoLibGcc.c | GCC
@@ -44,6 +45,7 @@
IoLibMsc.c | MSFT
IoLib.c
IoLibInternalTdx.c
+ IoLibFifo.c
X64/IoFifoSev.nasm
[Packages]
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
new file mode 100644
index 000000000000..08761a15a86c
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
@@ -0,0 +1,216 @@
+/** @file
+ IoFifo read/write routines.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibSev.h"
+#include "IoLibTdx.h"
+#include <Library/TdxLib.h>
+
+/**
+ Reads an 8-bit I/O port fifo into a block of memory.
+
+ Reads the 8-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoRead8 is invoked to read the I/O port fifo.
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+IoReadFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ if (IsTdxGuest ()) {
+ TdIoReadFifo8 (Port, Count, Buffer);
+ } else {
+ SevIoReadFifo8 (Port, Count, Buffer);
+ }
+}
+
+/**
+ Writes a block of memory into an 8-bit I/O port fifo.
+
+ Writes the 8-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoWrite8 is invoked to write data to the I/O port.
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+IoWriteFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ if (IsTdxGuest ()) {
+ TdIoWriteFifo8 (Port, Count, Buffer);
+ } else {
+ SevIoWriteFifo8 (Port, Count, Buffer);
+ }
+}
+
+/**
+ Reads a 16-bit I/O port fifo into a block of memory.
+
+ Reads the 16-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoRead16 is invoked to read data from the I/O port.
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+IoReadFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ if (IsTdxGuest ()) {
+ TdIoReadFifo16 (Port, Count, Buffer);
+ } else {
+ SevIoReadFifo16 (Port, Count, Buffer);
+ }
+}
+
+/**
+ Writes a block of memory into a 16-bit I/O port fifo.
+
+ Writes the 16-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoWrite16 is invoked to write data to the I/O port.
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+IoWriteFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ if (IsTdxGuest ()) {
+ TdIoWriteFifo16 (Port, Count, Buffer);
+ } else {
+ SevIoWriteFifo16 (Port, Count, Buffer);
+ }
+}
+
+/**
+ Reads a 32-bit I/O port fifo into a block of memory.
+
+ Reads the 32-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoRead32 is invoked to read data from the I/O port.
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+IoReadFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ if (IsTdxGuest ()) {
+ TdIoReadFifo32 (Port, Count, Buffer);
+ } else {
+ SevIoReadFifo32 (Port, Count, Buffer);
+ }
+}
+
+/**
+ Writes a block of memory into a 32-bit I/O port fifo.
+
+ Writes the 32-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoWrite32 is invoked to write data to the I/O port.
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+IoWriteFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ if (IsTdxGuest ()) {
+ TdIoWriteFifo32 (Port, Count, Buffer);
+ } else {
+ SevIoWriteFifo32 (Port, Count, Buffer);
+ }
+}
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h b/MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h
new file mode 100644
index 000000000000..6d7cafcff27a
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h
@@ -0,0 +1,166 @@
+/** @file
+ Header file for SEV IO library.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef IOLIB_SEV_H_
+#define IOLIB_SEV_H_
+
+#include <Base.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+/**
+ Reads an 8-bit I/O port fifo into a block of memory.
+
+ Reads the 8-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+SevIoReadFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a block of memory into an 8-bit I/O port fifo.
+
+ Writes the 8-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+SevIoWriteFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+/**
+ Reads an 8-bit I/O port fifo into a block of memory.
+
+ Reads the 8-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+SevIoReadFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a block of memory into an 8-bit I/O port fifo.
+
+ Writes the 8-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+SevIoWriteFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+/**
+ Reads an 8-bit I/O port fifo into a block of memory.
+
+ Reads the 8-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+SevIoReadFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a block of memory into an 8-bit I/O port fifo.
+
+ Writes the 8-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+SevIoWriteFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+#endif
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm b/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
index 106f8881c55c..d02286b4d518 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
+++ b/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
@@ -67,14 +67,14 @@ ASM_PFX(SevNoRepIo):
;------------------------------------------------------------------------------
; VOID
; EFIAPI
-; IoReadFifo8 (
+; SevIoReadFifo8 (
; IN UINTN Port, // rcx
; IN UINTN Size, // rdx
; OUT VOID *Buffer // r8
; );
;------------------------------------------------------------------------------
-global ASM_PFX(IoReadFifo8)
-ASM_PFX(IoReadFifo8):
+global ASM_PFX(SevIoReadFifo8)
+ASM_PFX(SevIoReadFifo8):
xchg rcx, rdx
xchg rdi, r8 ; rdi: buffer address; r8: save rdi
@@ -103,14 +103,14 @@ ASM_PFX(IoReadFifo8):
;------------------------------------------------------------------------------
; VOID
; EFIAPI
-; IoReadFifo16 (
+; SevIoReadFifo16 (
; IN UINTN Port, // rcx
; IN UINTN Size, // rdx
; OUT VOID *Buffer // r8
; );
;------------------------------------------------------------------------------
-global ASM_PFX(IoReadFifo16)
-ASM_PFX(IoReadFifo16):
+global ASM_PFX(SevIoReadFifo16)
+ASM_PFX(SevIoReadFifo16):
xchg rcx, rdx
xchg rdi, r8 ; rdi: buffer address; r8: save rdi
@@ -139,14 +139,14 @@ ASM_PFX(IoReadFifo16):
;------------------------------------------------------------------------------
; VOID
; EFIAPI
-; IoReadFifo32 (
+; SevIoReadFifo32 (
; IN UINTN Port, // rcx
; IN UINTN Size, // rdx
; OUT VOID *Buffer // r8
; );
;------------------------------------------------------------------------------
-global ASM_PFX(IoReadFifo32)
-ASM_PFX(IoReadFifo32):
+global ASM_PFX(SevIoReadFifo32)
+ASM_PFX(SevIoReadFifo32):
xchg rcx, rdx
xchg rdi, r8 ; rdi: buffer address; r8: save rdi
@@ -181,8 +181,8 @@ ASM_PFX(IoReadFifo32):
; IN VOID *Buffer // r8
; );
;------------------------------------------------------------------------------
-global ASM_PFX(IoWriteFifo8)
-ASM_PFX(IoWriteFifo8):
+global ASM_PFX(SevIoWriteFifo8)
+ASM_PFX(SevIoWriteFifo8):
xchg rcx, rdx
xchg rsi, r8 ; rsi: buffer address; r8: save rsi
@@ -211,14 +211,14 @@ ASM_PFX(IoWriteFifo8):
;------------------------------------------------------------------------------
; VOID
; EFIAPI
-; IoWriteFifo16 (
+; SevIoWriteFifo16 (
; IN UINTN Port, // rcx
; IN UINTN Size, // rdx
; IN VOID *Buffer // r8
; );
;------------------------------------------------------------------------------
-global ASM_PFX(IoWriteFifo16)
-ASM_PFX(IoWriteFifo16):
+global ASM_PFX(SevIoWriteFifo16)
+ASM_PFX(SevIoWriteFifo16):
xchg rcx, rdx
xchg rsi, r8 ; rsi: buffer address; r8: save rsi
@@ -247,14 +247,14 @@ ASM_PFX(IoWriteFifo16):
;------------------------------------------------------------------------------
; VOID
; EFIAPI
-; IoWriteFifo32 (
+; SevIoWriteFifo32 (
; IN UINTN Port, // rcx
; IN UINTN Size, // rdx
; IN VOID *Buffer // r8
; );
;------------------------------------------------------------------------------
-global ASM_PFX(IoWriteFifo32)
-ASM_PFX(IoWriteFifo32):
+global ASM_PFX(SevIoWriteFifo32)
+ASM_PFX(SevIoWriteFifo32):
xchg rcx, rdx
xchg rsi, r8 ; rsi: buffer address; r8: save rsi
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 10/37] MdePkg: Support IoRead/IoWrite for Tdx guest in BaseIoLibIntrinsic
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (8 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 09/37] MdePkg: Support IoFifo " Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 11/37] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
` (27 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky,
Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
This commit supports IoRead/IoWrite for SEV/TDX/Legacy guest in one
binary. It checks the guest type in runtime and then call corresponding
functions.
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c | 51 ++++++++++++--
MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c | 73 +++++++++++++++-----
2 files changed, 99 insertions(+), 25 deletions(-)
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
index 5c791289c469..05a739085967 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
@@ -16,6 +16,7 @@
**/
#include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"
/**
Reads an 8-bit I/O port.
@@ -24,7 +25,9 @@
This function must guarantee that all I/O read and write operations are
serialized.
- If 8-bit I/O port operations are not supported, then ASSERT().
+ If 8-bit I/O port operations are not supported, then ASSERT()
+
+ For Td guest TDVMCALL_IO is invoked to read I/O port.
@param Port The I/O port to read.
@@ -42,7 +45,11 @@ IoRead8 (
Flag = FilterBeforeIoRead (FilterWidth8, Port, &Data);
if (Flag) {
- __asm__ __volatile__ ("inb %w1,%b0" : "=a" (Data) : "d" ((UINT16)Port));
+ if (IsTdxGuest ()) {
+ Data = TdIoRead8 (Port);
+ } else {
+ __asm__ __volatile__ ("inb %w1,%b0" : "=a" (Data) : "d" ((UINT16)Port));
+ }
}
FilterAfterIoRead (FilterWidth8, Port, &Data);
@@ -59,6 +66,8 @@ IoRead8 (
If 8-bit I/O port operations are not supported, then ASSERT().
+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
@param Port The I/O port to write.
@param Value The value to write to the I/O port.
@@ -76,7 +85,11 @@ IoWrite8 (
Flag = FilterBeforeIoWrite (FilterWidth8, Port, &Value);
if (Flag) {
- __asm__ __volatile__ ("outb %b0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ if (IsTdxGuest ()) {
+ TdIoWrite8 (Port, Value);
+ } else {
+ __asm__ __volatile__ ("outb %b0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ }
}
FilterAfterIoWrite (FilterWidth8, Port, &Value);
@@ -94,6 +107,8 @@ IoWrite8 (
If 16-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 16-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
@param Port The I/O port to read.
@return The value read.
@@ -112,7 +127,11 @@ IoRead16 (
Flag = FilterBeforeIoRead (FilterWidth16, Port, &Data);
if (Flag) {
- __asm__ __volatile__ ("inw %w1,%w0" : "=a" (Data) : "d" ((UINT16)Port));
+ if (IsTdxGuest ()) {
+ Data = TdIoRead16 (Port);
+ } else {
+ __asm__ __volatile__ ("inw %w1,%w0" : "=a" (Data) : "d" ((UINT16)Port));
+ }
}
FilterAfterIoRead (FilterWidth16, Port, &Data);
@@ -130,6 +149,8 @@ IoRead16 (
If 16-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 16-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
@param Port The I/O port to write.
@param Value The value to write to the I/O port.
@@ -149,7 +170,11 @@ IoWrite16 (
Flag = FilterBeforeIoWrite (FilterWidth16, Port, &Value);
if (Flag) {
- __asm__ __volatile__ ("outw %w0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ if (IsTdxGuest ()) {
+ TdIoWrite16 (Port, Value);
+ } else {
+ __asm__ __volatile__ ("outw %w0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ }
}
FilterAfterIoWrite (FilterWidth16, Port, &Value);
@@ -167,6 +192,8 @@ IoWrite16 (
If 32-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 32-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
@param Port The I/O port to read.
@return The value read.
@@ -185,7 +212,11 @@ IoRead32 (
Flag = FilterBeforeIoRead (FilterWidth32, Port, &Data);
if (Flag) {
- __asm__ __volatile__ ("inl %w1,%0" : "=a" (Data) : "d" ((UINT16)Port));
+ if (IsTdxGuest ()) {
+ Data = TdIoRead32 (Port);
+ } else {
+ __asm__ __volatile__ ("inl %w1,%0" : "=a" (Data) : "d" ((UINT16)Port));
+ }
}
FilterAfterIoRead (FilterWidth32, Port, &Data);
@@ -203,6 +234,8 @@ IoRead32 (
If 32-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 32-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
@param Port The I/O port to write.
@param Value The value to write to the I/O port.
@@ -222,7 +255,11 @@ IoWrite32 (
Flag = FilterBeforeIoWrite (FilterWidth32, Port, &Value);
if (Flag) {
- __asm__ __volatile__ ("outl %0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ if (IsTdxGuest ()) {
+ TdIoWrite32 (Port, Value);
+ } else {
+ __asm__ __volatile__ ("outl %0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ }
}
FilterAfterIoWrite (FilterWidth32, Port, &Value);
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
index 9f225a6b5d39..f1b7d51a7245 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
@@ -14,6 +14,7 @@
**/
#include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"
//
// Microsoft Visual Studio 7.1 Function Prototypes for I/O Intrinsics.
@@ -82,6 +83,8 @@ _ReadWriteBarrier (
If 8-bit I/O port operations are not supported, then ASSERT().
+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
@param Port The I/O port to read.
@return The value read.
@@ -98,9 +101,13 @@ IoRead8 (
Flag = FilterBeforeIoRead (FilterWidth8, Port, &Value);
if (Flag) {
- _ReadWriteBarrier ();
- Value = (UINT8)_inp ((UINT16)Port);
- _ReadWriteBarrier ();
+ if (IsTdxGuest ()) {
+ Value = TdIoRead8 (Port);
+ } else {
+ _ReadWriteBarrier ();
+ Value = (UINT8)_inp ((UINT16)Port);
+ _ReadWriteBarrier ();
+ }
}
FilterAfterIoRead (FilterWidth8, Port, &Value);
@@ -117,6 +124,8 @@ IoRead8 (
If 8-bit I/O port operations are not supported, then ASSERT().
+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
@param Port The I/O port to write.
@param Value The value to write to the I/O port.
@@ -134,9 +143,13 @@ IoWrite8 (
Flag = FilterBeforeIoWrite (FilterWidth8, Port, &Value);
if (Flag) {
- _ReadWriteBarrier ();
- (UINT8)_outp ((UINT16)Port, Value);
- _ReadWriteBarrier ();
+ if (IsTdxGuest ()) {
+ TdIoWrite8 (Port, Value);
+ } else {
+ _ReadWriteBarrier ();
+ (UINT8)_outp ((UINT16)Port, Value);
+ _ReadWriteBarrier ();
+ }
}
FilterAfterIoWrite (FilterWidth8, Port, &Value);
@@ -154,6 +167,8 @@ IoWrite8 (
If 16-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 16-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
@param Port The I/O port to read.
@return The value read.
@@ -172,9 +187,13 @@ IoRead16 (
Flag = FilterBeforeIoRead (FilterWidth16, Port, &Value);
if (Flag) {
- _ReadWriteBarrier ();
- Value = _inpw ((UINT16)Port);
- _ReadWriteBarrier ();
+ if (IsTdxGuest ()) {
+ Value = TdIoRead16 (Port);
+ } else {
+ _ReadWriteBarrier ();
+ Value = _inpw ((UINT16)Port);
+ _ReadWriteBarrier ();
+ }
}
FilterBeforeIoRead (FilterWidth16, Port, &Value);
@@ -192,6 +211,8 @@ IoRead16 (
If 16-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 16-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
@param Port The I/O port to write.
@param Value The value to write to the I/O port.
@@ -211,9 +232,13 @@ IoWrite16 (
Flag = FilterBeforeIoWrite (FilterWidth16, Port, &Value);
if (Flag) {
- _ReadWriteBarrier ();
- _outpw ((UINT16)Port, Value);
- _ReadWriteBarrier ();
+ if (IsTdxGuest ()) {
+ TdIoWrite16 (Port, Value);
+ } else {
+ _ReadWriteBarrier ();
+ _outpw ((UINT16)Port, Value);
+ _ReadWriteBarrier ();
+ }
}
FilterAfterIoWrite (FilterWidth16, Port, &Value);
@@ -231,6 +256,8 @@ IoWrite16 (
If 32-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 32-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
@param Port The I/O port to read.
@return The value read.
@@ -249,9 +276,13 @@ IoRead32 (
Flag = FilterBeforeIoRead (FilterWidth32, Port, &Value);
if (Flag) {
- _ReadWriteBarrier ();
- Value = _inpd ((UINT16)Port);
- _ReadWriteBarrier ();
+ if (IsTdxGuest ()) {
+ Value = TdIoRead32 (Port);
+ } else {
+ _ReadWriteBarrier ();
+ Value = _inpd ((UINT16)Port);
+ _ReadWriteBarrier ();
+ }
}
FilterAfterIoRead (FilterWidth32, Port, &Value);
@@ -269,6 +300,8 @@ IoRead32 (
If 32-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 32-bit boundary, then ASSERT().
+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
@param Port The I/O port to write.
@param Value The value to write to the I/O port.
@@ -288,9 +321,13 @@ IoWrite32 (
Flag = FilterBeforeIoWrite (FilterWidth32, Port, &Value);
if (Flag) {
- _ReadWriteBarrier ();
- _outpd ((UINT16)Port, Value);
- _ReadWriteBarrier ();
+ if (IsTdxGuest ()) {
+ TdIoWrite32 (Port, Value);
+ } else {
+ _ReadWriteBarrier ();
+ _outpd ((UINT16)Port, Value);
+ _ReadWriteBarrier ();
+ }
}
FilterAfterIoWrite (FilterWidth32, Port, &Value);
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 11/37] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (9 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 10/37] MdePkg: Support IoRead/IoWrite " Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-03-15 7:44 ` [edk2-devel] " Ni, Ray
2022-02-28 7:20 ` [PATCH V7 12/37] MdePkg: Add macro to check SEV / TDX guest Min Xu
` (26 subsequent siblings)
37 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Eric Dong, Ray Ni, Rahul Kumar, Brijesh Singh,
Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky,
Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
MSR is accessed in BaseXApicX2ApicLib. In TDX some MSRs are accessed
directly from/to CPU. Some should be accessed via explicit requests
from the host VMM using TDCALL(TDG.VP.VMCALL). This is done by the
help of TdxLib.
Please refer to [TDX] Section 18.1
TDX: https://software.intel.com/content/dam/develop/external/us/en/
documents/tdx-module-1.0-public-spec-v0.931.pdf
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
.../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c | 160 +++++++++++++++++-
1 file changed, 152 insertions(+), 8 deletions(-)
diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
index aaa42ff8450b..2d17177df12b 100644
--- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
+++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
@@ -23,11 +23,155 @@
#include <Library/TimerLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiCpuLib.h>
+#include <IndustryStandard/Tdx.h>
//
// Library internal functions
//
+/**
+ Some MSRs in TDX are accessed via TdCall.
+ Some are directly read/write from/to CPU.
+
+ @param MsrIndex Index of the MSR
+ @retval TRUE MSR accessed via TdCall.
+ @retval FALSE MSR accessed not via TdCall.
+
+**/
+BOOLEAN
+AccessMsrTdxCall (
+ IN UINT32 MsrIndex
+ )
+{
+ if (!TdIsEnabled ()) {
+ return FALSE;
+ }
+
+ switch (MsrIndex) {
+ case MSR_IA32_X2APIC_TPR:
+ case MSR_IA32_X2APIC_PPR:
+ case MSR_IA32_X2APIC_EOI:
+ case MSR_IA32_X2APIC_ISR0:
+ case MSR_IA32_X2APIC_ISR1:
+ case MSR_IA32_X2APIC_ISR2:
+ case MSR_IA32_X2APIC_ISR3:
+ case MSR_IA32_X2APIC_ISR4:
+ case MSR_IA32_X2APIC_ISR5:
+ case MSR_IA32_X2APIC_ISR6:
+ case MSR_IA32_X2APIC_ISR7:
+ case MSR_IA32_X2APIC_TMR0:
+ case MSR_IA32_X2APIC_TMR1:
+ case MSR_IA32_X2APIC_TMR2:
+ case MSR_IA32_X2APIC_TMR3:
+ case MSR_IA32_X2APIC_TMR4:
+ case MSR_IA32_X2APIC_TMR5:
+ case MSR_IA32_X2APIC_TMR6:
+ case MSR_IA32_X2APIC_TMR7:
+ case MSR_IA32_X2APIC_IRR0:
+ case MSR_IA32_X2APIC_IRR1:
+ case MSR_IA32_X2APIC_IRR2:
+ case MSR_IA32_X2APIC_IRR3:
+ case MSR_IA32_X2APIC_IRR4:
+ case MSR_IA32_X2APIC_IRR5:
+ case MSR_IA32_X2APIC_IRR6:
+ case MSR_IA32_X2APIC_IRR7:
+ return FALSE;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+/**
+ Read MSR value.
+
+ @param MsrIndex Index of the MSR to read
+ @retval 64-bit Value of MSR.
+
+**/
+UINT64
+LocalApicReadMsrReg64 (
+ IN UINT32 MsrIndex
+ )
+{
+ UINT64 Val;
+ UINT64 Status;
+
+ if (AccessMsrTdxCall (MsrIndex)) {
+ Status = TdVmCall (TDVMCALL_RDMSR, (UINT64)MsrIndex, 0, 0, 0, &Val);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+ } else {
+ Val = AsmReadMsr64 (MsrIndex);
+ }
+
+ return Val;
+}
+
+/**
+ Write to MSR.
+
+ @param MsrIndex Index of the MSR to write to
+ @param Value Value to be written to the MSR
+
+ @return Value
+
+**/
+UINT64
+LocalApicWriteMsrReg64 (
+ IN UINT32 MsrIndex,
+ IN UINT64 Value
+ )
+{
+ UINT64 Status;
+
+ if (AccessMsrTdxCall (MsrIndex)) {
+ Status = TdVmCall (TDVMCALL_WRMSR, (UINT64)MsrIndex, Value, 0, 0, 0);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+ } else {
+ AsmWriteMsr64 (MsrIndex, Value);
+ }
+
+ return Value;
+}
+
+/**
+ Read MSR value.
+
+ @param MsrIndex Index of the MSR to read
+ @retval 32-bit Value of MSR.
+
+**/
+UINT32
+LocalApicReadMsrReg32 (
+ IN UINT32 MsrIndex
+ )
+{
+ return (UINT32)LocalApicReadMsrReg64 (MsrIndex);
+}
+
+/**
+ Write to MSR.
+
+ @param MsrIndex Index of the MSR to write to
+ @param Value Value to be written to the MSR
+
+ @return Value
+
+**/
+UINT32
+LocalApicWriteMsrReg32 (
+ IN UINT32 MsrIndex,
+ IN UINT32 Value
+ )
+{
+ return (UINT32)LocalApicWriteMsrReg64 (MsrIndex, Value);
+}
+
/**
Determine if the CPU supports the Local APIC Base Address MSR.
@@ -78,7 +222,7 @@ GetLocalApicBaseAddress (
return PcdGet32 (PcdCpuLocalApicBaseAddress);
}
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);
return (UINTN)(LShiftU64 ((UINT64)ApicBaseMsr.Bits.ApicBaseHi, 32)) +
(((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);
@@ -109,12 +253,12 @@ SetLocalApicBaseAddress (
return;
}
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);
ApicBaseMsr.Bits.ApicBase = (UINT32)(BaseAddress >> 12);
ApicBaseMsr.Bits.ApicBaseHi = (UINT32)(RShiftU64 ((UINT64)BaseAddress, 32));
- AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+ LocalApicWriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
}
/**
@@ -154,7 +298,7 @@ ReadLocalApicReg (
ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
- return AsmReadMsr32 (MsrIndex);
+ return LocalApicReadMsrReg32 (MsrIndex);
}
}
@@ -203,7 +347,7 @@ WriteLocalApicReg (
// Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.
//
MemoryFence ();
- AsmWriteMsr32 (MsrIndex, Value);
+ LocalApicWriteMsrReg32 (MsrIndex, Value);
}
}
@@ -309,7 +453,7 @@ GetApicMode (
return LOCAL_APIC_MODE_XAPIC;
}
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);
//
// Local APIC should have been enabled
//
@@ -354,9 +498,9 @@ SetApicMode (
case LOCAL_APIC_MODE_XAPIC:
break;
case LOCAL_APIC_MODE_X2APIC:
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);
ApicBaseMsr.Bits.EXTD = 1;
- AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+ LocalApicWriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
break;
default:
ASSERT (FALSE);
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 12/37] MdePkg: Add macro to check SEV / TDX guest
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (10 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 11/37] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 13/37] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
` (25 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Michael Roth, Ray Ni, Rahul Kumar, Eric Dong,
James Bottomley, Jiewen Yao, Tom Lendacky, Jordan Justen,
Ard Biesheuvel, Erdem Aktas, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
Add macros CC_GUEST_IS_SEV / CC_GUEST_IS_TDX to check SEV / TDX guest.
Cc: Michael Roth <michael.roth@amd.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
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: Erdem Aktas <erdemaktas@google.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
MdePkg/Include/ConfidentialComputingGuestAttr.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/MdePkg/Include/ConfidentialComputingGuestAttr.h b/MdePkg/Include/ConfidentialComputingGuestAttr.h
index 6a1301801519..dd2541c6dcdf 100644
--- a/MdePkg/Include/ConfidentialComputingGuestAttr.h
+++ b/MdePkg/Include/ConfidentialComputingGuestAttr.h
@@ -22,4 +22,7 @@ typedef enum {
CCAttrIntelTdx = 0x200,
} CONFIDENTIAL_COMPUTING_GUEST_ATTR;
+#define CC_GUEST_IS_TDX(x) ((x) == CCAttrIntelTdx)
+#define CC_GUEST_IS_SEV(x) ((x) == CCAttrAmdSev || (x) == CCAttrAmdSevEs || (x) == CCAttrAmdSevSnp)
+
#endif
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 13/37] UefiCpuPkg: Enable Tdx support in MpInitLib
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (11 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 12/37] MdePkg: Add macro to check SEV / TDX guest Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 14/37] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
` (24 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
In TDVF BSP and APs are simplified. BSP is the vCPU-0, while the others
are treated as APs.
So MP intialization is rather simple. The processor info is retrieved by
TDCALL, ApWorker is not supported, BSP is always the working processor,
while the APs are just in a wait-for-precedure state.
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>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 3 +
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 15 +-
UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h | 71 ++++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.c | 27 ++++
UefiCpuPkg/Library/MpInitLib/MpLibTdx.c | 128 ++++++++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c | 73 ++++++++++
UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 3 +
7 files changed, 319 insertions(+), 1 deletion(-)
create mode 100644 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index e1cd0b350008..159b4d16ed0e 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -24,10 +24,12 @@
[Sources.IA32]
Ia32/AmdSev.c
Ia32/MpFuncs.nasm
+ MpLibTdxNull.c
[Sources.X64]
X64/AmdSev.c
X64/MpFuncs.nasm
+ MpLibTdx.c
[Sources.common]
AmdSev.c
@@ -36,6 +38,7 @@
MpLib.c
MpLib.h
Microcode.c
+ MpIntelTdx.h
[Packages]
MdePkg/MdePkg.dec
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 60d14a5a0e10..237cad8c5fd6 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -7,6 +7,7 @@
**/
#include "MpLib.h"
+#include "MpIntelTdx.h"
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
@@ -15,8 +16,8 @@
#include <Library/VmgExitLib.h>
#include <Register/Amd/Fam17Msr.h>
#include <Register/Amd/Ghcb.h>
-
#include <Protocol/Timer.h>
+#include <ConfidentialComputingGuestAttr.h>
#define AP_SAFE_STACK_SIZE 128
@@ -824,6 +825,10 @@ MpInitLibStartupThisAP (
{
EFI_STATUS Status;
+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return EFI_UNSUPPORTED;
+ }
+
//
// temporarily stop checkAllApsStatus for avoid resource dead-lock.
//
@@ -880,6 +885,10 @@ MpInitLibSwitchBSP (
EFI_TIMER_ARCH_PROTOCOL *Timer;
UINT64 TimerPeriod;
+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return EFI_UNSUPPORTED;
+ }
+
TimerPeriod = 0;
//
// Locate Timer Arch Protocol
@@ -953,6 +962,10 @@ MpInitLibEnableDisableAP (
EFI_STATUS Status;
BOOLEAN TempStopCheckState;
+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return EFI_UNSUPPORTED;
+ }
+
TempStopCheckState = FALSE;
//
// temporarily stop checkAllAPsStatus for initialize parameters.
diff --git a/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h b/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
new file mode 100644
index 000000000000..b2136f466ce6
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
@@ -0,0 +1,71 @@
+/** @file
+ Intel Tdx header file.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MP_INTEL_TDX_H_
+#define MP_INTEL_TDX_H_
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Protocol/MpService.h>
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+ @param[out] HealthData Return processor health data.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetProcessorInfo (
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
+ OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
+ );
+
+/**
+ Retrieves the number of logical processor in the platform and the number of
+ those logical processors that are enabled on this boot. This service may only
+ be called from the BSP.
+
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including the BSP
+ and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
+ processors that exist in system, including
+ the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
+ is NULL.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetNumberOfProcessors (
+ OUT UINTN *NumberOfProcessors, OPTIONAL
+ OUT UINTN *NumberOfEnabledProcessors OPTIONAL
+ );
+
+#endif
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 4a73787ee43a..de2ed8e6c294 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -9,9 +9,11 @@
**/
#include "MpLib.h"
+#include "MpIntelTdx.h"
#include <Library/VmgExitLib.h>
#include <Register/Amd/Fam17Msr.h>
#include <Register/Amd/Ghcb.h>
+#include <ConfidentialComputingGuestAttr.h>
EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
@@ -1803,6 +1805,10 @@ MpInitLibInitialize (
UINTN BackupBufferAddr;
UINTN ApIdtBase;
+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return EFI_SUCCESS;
+ }
+
OldCpuMpData = GetCpuMpDataFromGuidedHob ();
if (OldCpuMpData == NULL) {
MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
@@ -2073,6 +2079,10 @@ MpInitLibGetProcessorInfo (
CPU_INFO_IN_HOB *CpuInfoInHob;
UINTN OriginalProcessorNumber;
+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return TdxMpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, HealthData);
+ }
+
CpuMpData = GetCpuMpData ();
CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
@@ -2307,6 +2317,10 @@ EnableDisableApWorker (
CPU_MP_DATA *CpuMpData;
UINTN CallerNumber;
+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return EFI_UNSUPPORTED;
+ }
+
CpuMpData = GetCpuMpData ();
//
@@ -2367,6 +2381,11 @@ MpInitLibWhoAmI (
return EFI_INVALID_PARAMETER;
}
+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ *ProcessorNumber = 0;
+ return EFI_SUCCESS;
+ }
+
CpuMpData = GetCpuMpData ();
return GetProcessorNumber (CpuMpData, ProcessorNumber);
@@ -2405,6 +2424,10 @@ MpInitLibGetNumberOfProcessors (
UINTN EnabledProcessorNumber;
UINTN Index;
+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return TdxMpInitLibGetNumberOfProcessors (NumberOfProcessors, NumberOfEnabledProcessors);
+ }
+
CpuMpData = GetCpuMpData ();
if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
@@ -2490,6 +2513,10 @@ StartupAllCPUsWorker (
BOOLEAN HasEnabledAp;
CPU_STATE ApState;
+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return EFI_SUCCESS;
+ }
+
CpuMpData = GetCpuMpData ();
if (FailedCpuList != NULL) {
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c b/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
new file mode 100644
index 000000000000..d31d043b20b7
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
@@ -0,0 +1,128 @@
+/** @file
+ CPU MP Initialize Library common functions.
+
+ Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+#include "MpIntelTdx.h"
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/Tdx.h>
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+ @param[out] HealthData Return processor health data.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetProcessorInfo (
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
+ OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TD_RETURN_DATA TdReturnData;
+
+ if (ProcessorInfoBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+ ASSERT (Status == EFI_SUCCESS);
+
+ if (ProcessorNumber >= TdReturnData.TdInfo.NumVcpus) {
+ return EFI_NOT_FOUND;
+ }
+
+ ProcessorInfoBuffer->ProcessorId = ProcessorNumber;
+ ProcessorInfoBuffer->StatusFlag = 0;
+ if (ProcessorNumber == 0) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
+ }
+
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
+
+ //
+ // Get processor location information
+ //
+ GetProcessorLocationByApicId (
+ (UINT32)ProcessorNumber,
+ &ProcessorInfoBuffer->Location.Package,
+ &ProcessorInfoBuffer->Location.Core,
+ &ProcessorInfoBuffer->Location.Thread
+ );
+
+ if (HealthData != NULL) {
+ HealthData->Uint32 = 0;
+ }
+
+ return Status;
+}
+
+/**
+ Retrieves the number of logical processor in the platform and the number of
+ those logical processors that are enabled on this boot. This service may only
+ be called from the BSP.
+
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including the BSP
+ and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
+ processors that exist in system, including
+ the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
+ is NULL.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetNumberOfProcessors (
+ OUT UINTN *NumberOfProcessors, OPTIONAL
+ OUT UINTN *NumberOfEnabledProcessors OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TD_RETURN_DATA TdReturnData;
+
+ if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+ ASSERT (Status == EFI_SUCCESS);
+
+ if (NumberOfProcessors != NULL) {
+ *NumberOfProcessors = TdReturnData.TdInfo.NumVcpus;
+ }
+
+ if (NumberOfEnabledProcessors != NULL) {
+ *NumberOfEnabledProcessors = TdReturnData.TdInfo.MaxVcpus;
+ }
+
+ return Status;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
new file mode 100644
index 000000000000..2849e13f2aaa
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
@@ -0,0 +1,73 @@
+/** @file
+ CPU MP Initialize Library common functions.
+
+ Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+#include "MpIntelTdx.h"
+#include <Library/DebugLib.h>
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+ @param[out] HealthData Return processor health data.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetProcessorInfo (
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
+ OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Retrieves the number of logical processor in the platform and the number of
+ those logical processors that are enabled on this boot. This service may only
+ be called from the BSP.
+
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including the BSP
+ and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
+ processors that exist in system, including
+ the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
+ is NULL.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetNumberOfProcessors (
+ OUT UINTN *NumberOfProcessors, OPTIONAL
+ OUT UINTN *NumberOfEnabledProcessors OPTIONAL
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 5facf4db9499..894be0f8daab 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -24,10 +24,12 @@
[Sources.IA32]
Ia32/AmdSev.c
Ia32/MpFuncs.nasm
+ MpLibTdxNull.c
[Sources.X64]
X64/AmdSev.c
X64/MpFuncs.nasm
+ MpLibTdx.c
[Sources.common]
AmdSev.c
@@ -36,6 +38,7 @@
MpLib.c
MpLib.h
Microcode.c
+ MpIntelTdx.h
[Packages]
MdePkg/MdePkg.dec
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 14/37] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (12 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 13/37] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 15/37] OvmfPkg: Add TdxMailboxLib Min Xu
` (23 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
IntelTdx.h defines the defition used by TDX in OvmfPkg:
- Mailbox related defitions,such as the data structure, command code,
AP relocation defitions.
See Table 5.44 Multiprocessor Wakeup Mailbox Structure in below link.
https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/
ACPI_Software_Programming_Model.html#multiprocessor-wakeup-structure
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Include/IndustryStandard/IntelTdx.h | 67 +++++++++++++++++++++
1 file changed, 67 insertions(+)
create mode 100644 OvmfPkg/Include/IndustryStandard/IntelTdx.h
diff --git a/OvmfPkg/Include/IndustryStandard/IntelTdx.h b/OvmfPkg/Include/IndustryStandard/IntelTdx.h
new file mode 100644
index 000000000000..cc849be2fb59
--- /dev/null
+++ b/OvmfPkg/Include/IndustryStandard/IntelTdx.h
@@ -0,0 +1,67 @@
+/** @file
+ Defines the defitions used by TDX in OvmfPkg.
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef OVMF_INTEL_TDX_H_
+#define OVMF_INTEL_TDX_H_
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Uefi/UefiSpec.h>
+#include <Uefi/UefiBaseType.h>
+
+#define MP_CPU_PROTECTED_MODE_MAILBOX_APICID_INVALID 0xFFFFFFFF
+#define MP_CPU_PROTECTED_MODE_MAILBOX_APICID_BROADCAST 0xFFFFFFFE
+
+typedef enum {
+ MpProtectedModeWakeupCommandNoop = 0,
+ MpProtectedModeWakeupCommandWakeup = 1,
+ MpProtectedModeWakeupCommandSleep = 2,
+ MpProtectedModeWakeupCommandAcceptPages = 3,
+} MP_CPU_PROTECTED_MODE_WAKEUP_CMD;
+
+#pragma pack(1)
+
+//
+// Describes the CPU MAILBOX control structure use to
+// wakeup cpus spinning in long mode
+//
+typedef struct {
+ UINT16 Command;
+ UINT16 Resv;
+ UINT32 ApicId;
+ UINT64 WakeUpVector;
+ UINT8 ResvForOs[2032];
+ //
+ // Arguments available for wakeup code
+ //
+ UINT64 WakeUpArgs1;
+ UINT64 WakeUpArgs2;
+ UINT64 WakeUpArgs3;
+ UINT64 WakeUpArgs4;
+ UINT8 Pad1[0xe0];
+ UINT64 NumCpusArriving;
+ UINT8 Pad2[0xf8];
+ UINT64 NumCpusExiting;
+ UINT32 Tallies[256];
+ UINT8 Errors[256];
+ UINT8 Pad3[0xf8];
+} MP_WAKEUP_MAILBOX;
+
+//
+// AP relocation code information including code address and size,
+// this structure will be shared be C code and assembly code.
+// It is natural aligned by design.
+//
+typedef struct {
+ UINT8 *RelocateApLoopFuncAddress;
+ UINTN RelocateApLoopFuncSize;
+} MP_RELOCATION_MAP;
+
+#pragma pack()
+
+#endif
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 15/37] OvmfPkg: Add TdxMailboxLib
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (13 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 14/37] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 16/37] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h Min Xu
` (22 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
In Tdx BSP may issues commands to APs for some task, for example, to
accept pages paralelly. BSP also need to wait until all the APs have
done the task. TdxMailboxLib wraps these common funtions for BSP.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Include/Library/TdxMailboxLib.h | 76 ++++++++++
OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c | 140 ++++++++++++++++++
.../Library/TdxMailboxLib/TdxMailboxLib.inf | 52 +++++++
.../Library/TdxMailboxLib/TdxMailboxNull.c | 85 +++++++++++
OvmfPkg/OvmfPkg.dec | 4 +
5 files changed, 357 insertions(+)
create mode 100644 OvmfPkg/Include/Library/TdxMailboxLib.h
create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c
diff --git a/OvmfPkg/Include/Library/TdxMailboxLib.h b/OvmfPkg/Include/Library/TdxMailboxLib.h
new file mode 100644
index 000000000000..166cab43bc02
--- /dev/null
+++ b/OvmfPkg/Include/Library/TdxMailboxLib.h
@@ -0,0 +1,76 @@
+/** @file
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TDX_MAILBOX_LIB_H_
+#define TDX_MAILBOX_LIB_H_
+
+#include <Library/BaseLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Uefi/UefiSpec.h>
+#include <Pi/PiPeiCis.h>
+#include <Library/DebugLib.h>
+#include <Protocol/DebugSupport.h>
+
+/**
+ This function will be called by BSP to get the CPU number.
+
+ @retval CPU number
+**/
+UINT32
+EFIAPI
+GetCpusNum (
+ VOID
+ );
+
+/**
+ Get the address of Td mailbox.
+**/
+volatile VOID *
+EFIAPI
+GetTdxMailBox (
+ VOID
+ );
+
+/**
+ This function will be called by BSP to wakeup APs the are spinning on mailbox
+ in protected mode
+
+ @param[in] Command Command to send APs
+ @param[in] WakeupVector If used, address for APs to start executing
+ @param[in] WakeArgsX Args to pass to APs for excuting commands
+**/
+VOID
+EFIAPI
+MpSendWakeupCommand (
+ IN UINT16 Command,
+ IN UINT64 WakeupVector,
+ IN UINT64 WakeupArgs1,
+ IN UINT64 WakeupArgs2,
+ IN UINT64 WakeupArgs3,
+ IN UINT64 WakeupArgs4
+ );
+
+/**
+ BSP wait until all the APs arriving. It means the task triggered by BSP is started.
+**/
+VOID
+EFIAPI
+MpSerializeStart (
+ VOID
+ );
+
+/**
+ BSP wait until all the APs arriving. It means the task triggered by BSP is ended.
+**/
+VOID
+EFIAPI
+MpSerializeEnd (
+ VOID
+ );
+
+#endif
diff --git a/OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c b/OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
new file mode 100644
index 000000000000..13612dc141e3
--- /dev/null
+++ b/OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
@@ -0,0 +1,140 @@
+/** @file
+
+ Copyright (c) 2008, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiCpuLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/TdxLib.h>
+#include <IndustryStandard/IntelTdx.h>
+#include <IndustryStandard/Tdx.h>
+#include <Library/TdxMailboxLib.h>
+
+volatile VOID *mMailBox = NULL;
+UINT32 mNumOfCpus = 0;
+
+/**
+ This function will be called by BSP to get the CPU number.
+
+ @retval CPU number
+**/
+UINT32
+EFIAPI
+GetCpusNum (
+ VOID
+ )
+{
+ if (mNumOfCpus == 0) {
+ mNumOfCpus = TdVCpuNum ();
+ }
+
+ return mNumOfCpus;
+}
+
+/**
+ Get the address of Td mailbox.
+**/
+volatile VOID *
+EFIAPI
+GetTdxMailBox (
+ VOID
+ )
+{
+ if (mMailBox == NULL) {
+ mMailBox = (VOID *)(UINTN)PcdGet32 (PcdOvmfSecGhcbBackupBase);
+ }
+
+ return mMailBox;
+}
+
+/**
+ This function will be called by BSP to wakeup APs the are spinning on mailbox
+ in protected mode
+
+ @param[in] Command Command to send APs
+ @param[in] WakeupVector If used, address for APs to start executing
+ @param[in] WakeArgsX Args to pass to APs for excuting commands
+**/
+VOID
+EFIAPI
+MpSendWakeupCommand (
+ IN UINT16 Command,
+ IN UINT64 WakeupVector,
+ IN UINT64 WakeupArgs1,
+ IN UINT64 WakeupArgs2,
+ IN UINT64 WakeupArgs3,
+ IN UINT64 WakeupArgs4
+ )
+{
+ volatile MP_WAKEUP_MAILBOX *MailBox;
+
+ MailBox = (volatile MP_WAKEUP_MAILBOX *)GetTdxMailBox ();
+ MailBox->ApicId = MP_CPU_PROTECTED_MODE_MAILBOX_APICID_INVALID;
+ MailBox->WakeUpVector = 0;
+ MailBox->Command = MpProtectedModeWakeupCommandNoop;
+ MailBox->ApicId = MP_CPU_PROTECTED_MODE_MAILBOX_APICID_BROADCAST;
+ MailBox->WakeUpVector = WakeupVector;
+ MailBox->WakeUpArgs1 = WakeupArgs1;
+ MailBox->WakeUpArgs2 = WakeupArgs2;
+ MailBox->WakeUpArgs3 = WakeupArgs3;
+ MailBox->WakeUpArgs4 = WakeupArgs4;
+ AsmCpuid (0x01, NULL, NULL, NULL, NULL);
+ MailBox->Command = Command;
+ AsmCpuid (0x01, NULL, NULL, NULL, NULL);
+ return;
+}
+
+/**
+ BSP wait until all the APs arriving. It means the task triggered by BSP is started.
+**/
+VOID
+EFIAPI
+MpSerializeStart (
+ VOID
+ )
+{
+ volatile MP_WAKEUP_MAILBOX *MailBox;
+ UINT32 NumOfCpus;
+
+ NumOfCpus = GetCpusNum ();
+ MailBox = (volatile MP_WAKEUP_MAILBOX *)GetTdxMailBox ();
+
+ DEBUG ((DEBUG_VERBOSE, "Waiting for APs to arriving. NumOfCpus=%d, MailBox=%p\n", NumOfCpus, MailBox));
+ while (MailBox->NumCpusArriving != (NumOfCpus -1)) {
+ CpuPause ();
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "Releasing APs\n"));
+ MailBox->NumCpusExiting = NumOfCpus;
+ InterlockedIncrement ((UINT32 *)&MailBox->NumCpusArriving);
+}
+
+/**
+ BSP wait until all the APs arriving. It means the task triggered by BSP is ended.
+**/
+VOID
+EFIAPI
+MpSerializeEnd (
+ VOID
+ )
+{
+ volatile MP_WAKEUP_MAILBOX *MailBox;
+
+ MailBox = (volatile MP_WAKEUP_MAILBOX *)GetTdxMailBox ();
+ DEBUG ((DEBUG_VERBOSE, "Waiting for APs to finish\n"));
+ while (MailBox->NumCpusExiting != 1 ) {
+ CpuPause ();
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "Restarting APs\n"));
+ MailBox->Command = MpProtectedModeWakeupCommandNoop;
+ MailBox->NumCpusArriving = 0;
+ InterlockedDecrement ((UINT32 *)&MailBox->NumCpusExiting);
+}
diff --git a/OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf b/OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
new file mode 100644
index 000000000000..3cf3690a16c7
--- /dev/null
+++ b/OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
@@ -0,0 +1,52 @@
+#/** @file
+#
+# TBD
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2008, Apple Inc. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TdxMailboxLib
+ FILE_GUID = 2F81A9BA-748E-4519-BB11-A63A039D561E
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TdxMailboxLib
+
+#
+# VALID_ARCHITECTURES = X64 IA32
+#
+
+[Sources.IA32]
+ TdxMailboxNull.c
+
+[Sources.X64]
+ TdxMailbox.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ PcdLib
+ UefiCpuLib
+ DebugAgentLib
+ IoLib
+ SynchronizationLib
+ MemoryAllocationLib
+
+[Guids]
+
+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
diff --git a/OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c b/OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c
new file mode 100644
index 000000000000..35b070361eb1
--- /dev/null
+++ b/OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c
@@ -0,0 +1,85 @@
+/** @file
+
+ Copyright (c) 2008, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/TdxMailboxLib.h>
+
+/**
+ This function will be called by BSP to get the CPU number.
+
+ @retval CPU number
+**/
+UINT32
+EFIAPI
+GetCpusNum (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Get the address of Td mailbox.
+**/
+volatile VOID *
+EFIAPI
+GetTdxMailBox (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+ return (volatile VOID *)NULL;
+}
+
+/**
+ This function will be called by BSP to wakeup APs the are spinning on mailbox
+ in protected mode
+
+ @param[in] Command Command to send APs
+ @param[in] WakeupVector If used, address for APs to start executing
+ @param[in] WakeArgsX Args to pass to APs for excuting commands
+**/
+VOID
+EFIAPI
+MpSendWakeupCommand (
+ IN UINT16 Command,
+ IN UINT64 WakeupVector,
+ IN UINT64 WakeupArgs1,
+ IN UINT64 WakeupArgs2,
+ IN UINT64 WakeupArgs3,
+ IN UINT64 WakeupArgs4
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ BSP wait until all the APs arriving. It means the task triggered by BSP is started.
+**/
+VOID
+EFIAPI
+MpSerializeStart (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ BSP wait until all the APs arriving. It means the task triggered by BSP is ended.
+**/
+VOID
+EFIAPI
+MpSerializeEnd (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+}
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 7aa94ca02863..d373b5d6042e 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -109,6 +109,10 @@
#
XenPlatformLib|Include/Library/XenPlatformLib.h
+ ## @libraryclass TdxMailboxLib
+ #
+ TdxMailboxLib|Include/Library/TdxMailboxLib.h
+
[Guids]
gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}}
gEfiXenInfoGuid = {0xd3b46f3b, 0xd441, 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}}
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 16/37] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (14 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 15/37] OvmfPkg: Add TdxMailboxLib Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 17/37] OvmfPkg: Create initial version of PlatformInitLib Min Xu
` (21 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
EFI_RESOURCE_ATTRIBUTE_ENCRYPTED is Physical memory encrypted attribute.
It indicates the memory uses platform encrpytion capabilities for
protection. If this bit is clear, the memory does not use platform
encryption protection.
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>
---
MdePkg/Include/Pi/PiHob.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/MdePkg/Include/Pi/PiHob.h b/MdePkg/Include/Pi/PiHob.h
index e9f0ab4309d1..5bb7fc843112 100644
--- a/MdePkg/Include/Pi/PiHob.h
+++ b/MdePkg/Include/Pi/PiHob.h
@@ -296,6 +296,14 @@ typedef UINT32 EFI_RESOURCE_ATTRIBUTE_TYPE;
//
#define EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE 0x02000000
+//
+// Physical memory encrypted attribute. This
+// memory uses platform encrpytion capabilities for
+// protection. If this bit is clear, the memory does
+// not use platform encryption protection
+//
+#define EFI_RESOURCE_ATTRIBUTE_ENCRYPTED 0x04000000
+
///
/// Describes the resource properties of all fixed,
/// nonrelocatable resource ranges found on the processor
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 17/37] OvmfPkg: Create initial version of PlatformInitLib
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (15 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 16/37] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-03-01 12:32 ` Gerd Hoffmann
2022-02-28 7:20 ` [PATCH V7 18/37] OvmfPkg/PlatformInitLib: Add hob functions Min Xu
` (20 subsequent siblings)
37 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
There are 3 variants of PlatformPei in OvmfPkg:
- OvmfPkg/PlatformPei
- OvmfPkg/XenPlatformPei
- OvmfPkg/Bhyve/PlatformPei/PlatformPei.inf
These PlatformPeis can share many common codes, such as
Cmos / Hob / Memory / Platform related functions. This commit
(and its following several patches) are to create a PlatformInitLib
which wraps the common code called in above PlatformPeis.
Considering this PlatformInitLib will be used in SEC phase, global
variables and dynamic PCDs will be avoided. This lib will not handle
the situation of SMM / S3 either.
In this initial version of PlatformInitLib, below Cmos related functions
are introduced:
- PlatformCmosRead8
- PlatformCmosWrite8
- PlatformDebugDumpCmos
They correspond to the functions in OvmfPkg/PlatformPei:
- CmosRead8
- CmosWrite8
- DebugDumpCmos
EFI_HOB_PLATFORM_INFO is also defined in this patch which is used to
pass the platform information in Hob to Dxe phase.
After PlatformInitLib is created, OvmfPkg/PlatformPei is refactored
with this library.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/AmdSev/AmdSevX64.dsc | 1 +
OvmfPkg/CloudHv/CloudHvX64.dsc | 1 +
.../Library/PlatformInitLib.h} | 32 +++++++++++++----
.../PlatformInitLib}/Cmos.c | 32 +++++++++++++++--
.../PlatformInitLib/PlatformInitLib.inf | 36 +++++++++++++++++++
OvmfPkg/Microvm/MicrovmX64.dsc | 1 +
OvmfPkg/OvmfPkg.dec | 4 +++
OvmfPkg/OvmfPkgIa32.dsc | 1 +
OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
OvmfPkg/OvmfPkgX64.dsc | 1 +
OvmfPkg/PlatformPei/MemDetect.c | 8 ++---
OvmfPkg/PlatformPei/Platform.c | 29 +++------------
OvmfPkg/PlatformPei/PlatformPei.inf | 3 +-
13 files changed, 109 insertions(+), 41 deletions(-)
rename OvmfPkg/{PlatformPei/Cmos.h => Include/Library/PlatformInitLib.h} (55%)
rename OvmfPkg/{PlatformPei => Library/PlatformInitLib}/Cmos.c (61%)
create mode 100644 OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index fd56176796d5..785049c88962 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -280,6 +280,7 @@
!include OvmfPkg/OvmfTpmLibsPeim.dsc.inc
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+ PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
[LibraryClasses.common.DXE_CORE]
HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
diff --git a/OvmfPkg/CloudHv/CloudHvX64.dsc b/OvmfPkg/CloudHv/CloudHvX64.dsc
index 3172100310b1..e821a72f000c 100644
--- a/OvmfPkg/CloudHv/CloudHvX64.dsc
+++ b/OvmfPkg/CloudHv/CloudHvX64.dsc
@@ -307,6 +307,7 @@
!include OvmfPkg/OvmfTpmLibsPeim.dsc.inc
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+ PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
[LibraryClasses.common.DXE_CORE]
HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
diff --git a/OvmfPkg/PlatformPei/Cmos.h b/OvmfPkg/Include/Library/PlatformInitLib.h
similarity index 55%
rename from OvmfPkg/PlatformPei/Cmos.h
rename to OvmfPkg/Include/Library/PlatformInitLib.h
index 2b3124d7ba36..af75559e66fa 100644
--- a/OvmfPkg/PlatformPei/Cmos.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -1,13 +1,22 @@
/** @file
- PC/AT CMOS access routines
+ PlatformInitLib header file.
- Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
-#ifndef __CMOS_H__
-#define __CMOS_H__
+#ifndef PLATFORM_INIT_LIB_H_
+#define PLATFORM_INIT_LIB_H_
+
+#include <PiPei.h>
+
+#pragma pack(1)
+typedef struct {
+ EFI_HOB_GUID_TYPE GuidHeader;
+ UINT16 HostBridgePciDevId;
+} EFI_HOB_PLATFORM_INFO;
+#pragma pack()
/**
Reads 8-bits of CMOS data.
@@ -22,7 +31,7 @@
**/
UINT8
EFIAPI
-CmosRead8 (
+PlatformCmosRead8 (
IN UINTN Index
);
@@ -40,9 +49,18 @@ CmosRead8 (
**/
UINT8
EFIAPI
-CmosWrite8 (
+PlatformCmosWrite8 (
IN UINTN Index,
IN UINT8 Value
);
-#endif
+/**
+ Dump the CMOS content
+ */
+VOID
+EFIAPI
+PlatformDebugDumpCmos (
+ VOID
+ );
+
+#endif // PLATFORM_INIT_LIB_H_
diff --git a/OvmfPkg/PlatformPei/Cmos.c b/OvmfPkg/Library/PlatformInitLib/Cmos.c
similarity index 61%
rename from OvmfPkg/PlatformPei/Cmos.c
rename to OvmfPkg/Library/PlatformInitLib/Cmos.c
index a01b3866bee4..977aa97aea8c 100644
--- a/OvmfPkg/PlatformPei/Cmos.c
+++ b/OvmfPkg/Library/PlatformInitLib/Cmos.c
@@ -6,7 +6,8 @@
**/
-#include "Cmos.h"
+#include <Library/PlatformInitLib.h>
+#include <Library/DebugLib.h>
#include "Library/IoLib.h"
/**
@@ -22,7 +23,7 @@
**/
UINT8
EFIAPI
-CmosRead8 (
+PlatformCmosRead8 (
IN UINTN Index
)
{
@@ -44,7 +45,7 @@ CmosRead8 (
**/
UINT8
EFIAPI
-CmosWrite8 (
+PlatformCmosWrite8 (
IN UINTN Index,
IN UINT8 Value
)
@@ -53,3 +54,28 @@ CmosWrite8 (
IoWrite8 (0x71, Value);
return Value;
}
+
+/**
+ Dump the CMOS content
+ */
+VOID
+EFIAPI
+PlatformDebugDumpCmos (
+ VOID
+ )
+{
+ UINT32 Loop;
+
+ DEBUG ((DEBUG_INFO, "CMOS:\n"));
+
+ for (Loop = 0; Loop < 0x80; Loop++) {
+ if ((Loop % 0x10) == 0) {
+ DEBUG ((DEBUG_INFO, "%02x:", Loop));
+ }
+
+ DEBUG ((DEBUG_INFO, " %02x", PlatformCmosRead8 (Loop)));
+ if ((Loop % 0x10) == 0xf) {
+ DEBUG ((DEBUG_INFO, "\n"));
+ }
+ }
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
new file mode 100644
index 000000000000..4ea2da86274f
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -0,0 +1,36 @@
+## @file
+# Platform Initialization Lib
+#
+# This module provides platform specific function to detect boot mode.
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformInitLib
+ FILE_GUID = 89f886b0-7109-46e1-9d28-503ad4ab6ee0
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformInitLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ Cmos.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ IoLib
diff --git a/OvmfPkg/Microvm/MicrovmX64.dsc b/OvmfPkg/Microvm/MicrovmX64.dsc
index 1ea43443ae97..27005eec89f2 100644
--- a/OvmfPkg/Microvm/MicrovmX64.dsc
+++ b/OvmfPkg/Microvm/MicrovmX64.dsc
@@ -300,6 +300,7 @@
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+ PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
[LibraryClasses.common.DXE_CORE]
HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index d373b5d6042e..61635c73c761 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -113,6 +113,10 @@
#
TdxMailboxLib|Include/Library/TdxMailboxLib.h
+ ## @libraryclass PlatformInitLib
+ #
+ PlatformInitLib|Include/Library/PlatformInitLib.h
+
[Guids]
gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}}
gEfiXenInfoGuid = {0xd3b46f3b, 0xd441, 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}}
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 85abed24c1a7..8f02dca63869 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -300,6 +300,7 @@
QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
+ PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
!include OvmfPkg/OvmfTpmLibsPeim.dsc.inc
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index a9c1daecc1a8..c58ef8494470 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -304,6 +304,7 @@
QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
+ PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
!include OvmfPkg/OvmfTpmLibsPeim.dsc.inc
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 718399299f57..227b9845619f 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -305,6 +305,7 @@
QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
+ PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
!include OvmfPkg/OvmfTpmLibsPeim.dsc.inc
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index 1bcb5a08bca6..d118dba2f214 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -36,9 +36,9 @@ Module Name:
#include <Library/MtrrLib.h>
#include <Library/QemuFwCfgLib.h>
#include <Library/QemuFwCfgSimpleParserLib.h>
+#include <Library/PlatformInitLib.h>
#include "Platform.h"
-#include "Cmos.h"
UINT8 mPhysMemAddressWidth;
@@ -339,8 +339,8 @@ GetSystemMemorySizeBelow4gb (
// into the calculation to get the total memory size.
//
- Cmos0x34 = (UINT8)CmosRead8 (0x34);
- Cmos0x35 = (UINT8)CmosRead8 (0x35);
+ Cmos0x34 = (UINT8)PlatformCmosRead8 (0x34);
+ Cmos0x35 = (UINT8)PlatformCmosRead8 (0x35);
return (UINT32)(((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);
}
@@ -363,7 +363,7 @@ GetSystemMemorySizeAbove4gb (
Size = 0;
for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {
- Size = (UINT32)(Size << 8) + (UINT32)CmosRead8 (CmosIndex);
+ Size = (UINT32)(Size << 8) + (UINT32)PlatformCmosRead8 (CmosIndex);
}
return LShiftU64 (Size, 16);
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index d0323c645162..594891786440 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -36,10 +36,10 @@
#include <IndustryStandard/Pci22.h>
#include <IndustryStandard/Q35MchIch9.h>
#include <IndustryStandard/QemuCpuHotplug.h>
+#include <Library/PlatformInitLib.h>
#include <OvmfPlatforms.h>
#include "Platform.h"
-#include "Cmos.h"
EFI_PEI_PPI_DESCRIPTOR mPpiBootMode[] = {
{
@@ -505,11 +505,11 @@ BootModeInitialization (
{
EFI_STATUS Status;
- if (CmosRead8 (0xF) == 0xFE) {
+ if (PlatformCmosRead8 (0xF) == 0xFE) {
mBootMode = BOOT_ON_S3_RESUME;
}
- CmosWrite8 (0xF, 0x00);
+ PlatformCmosWrite8 (0xF, 0x00);
Status = PeiServicesSetBootMode (mBootMode);
ASSERT_EFI_ERROR (Status);
@@ -546,27 +546,6 @@ ReserveEmuVariableNvStore (
ASSERT_RETURN_ERROR (PcdStatus);
}
-VOID
-DebugDumpCmos (
- VOID
- )
-{
- UINT32 Loop;
-
- DEBUG ((DEBUG_INFO, "CMOS:\n"));
-
- for (Loop = 0; Loop < 0x80; Loop++) {
- if ((Loop % 0x10) == 0) {
- DEBUG ((DEBUG_INFO, "%02x:", Loop));
- }
-
- DEBUG ((DEBUG_INFO, " %02x", CmosRead8 (Loop)));
- if ((Loop % 0x10) == 0xf) {
- DEBUG ((DEBUG_INFO, "\n"));
- }
- }
-}
-
VOID
S3Verification (
VOID
@@ -810,7 +789,7 @@ InitializePlatform (
DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
- DebugDumpCmos ();
+ PlatformDebugDumpCmos ();
if (QemuFwCfgS3Enabled ()) {
DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 8ef404168c45..65e417b2f254 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -25,8 +25,6 @@
[Sources]
AmdSev.c
ClearCache.c
- Cmos.c
- Cmos.h
FeatureControl.c
Fv.c
MemDetect.c
@@ -64,6 +62,7 @@
MemEncryptSevLib
PcdLib
VmgExitLib
+ PlatformInitLib
[Pcd]
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* Re: [PATCH V7 17/37] OvmfPkg: Create initial version of PlatformInitLib
2022-02-28 7:20 ` [PATCH V7 17/37] OvmfPkg: Create initial version of PlatformInitLib Min Xu
@ 2022-03-01 12:32 ` Gerd Hoffmann
0 siblings, 0 replies; 72+ messages in thread
From: Gerd Hoffmann @ 2022-03-01 12:32 UTC (permalink / raw)
To: Min Xu
Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky
On Mon, Feb 28, 2022 at 03:20:49PM +0800, Min Xu wrote:
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
>
> There are 3 variants of PlatformPei in OvmfPkg:
> - OvmfPkg/PlatformPei
> - OvmfPkg/XenPlatformPei
> - OvmfPkg/Bhyve/PlatformPei/PlatformPei.inf
> These PlatformPeis can share many common codes, such as
> Cmos / Hob / Memory / Platform related functions. This commit
> (and its following several patches) are to create a PlatformInitLib
> which wraps the common code called in above PlatformPeis.
>
> Considering this PlatformInitLib will be used in SEC phase, global
> variables and dynamic PCDs will be avoided. This lib will not handle
> the situation of SMM / S3 either.
>
> In this initial version of PlatformInitLib, below Cmos related functions
> are introduced:
> - PlatformCmosRead8
> - PlatformCmosWrite8
> - PlatformDebugDumpCmos
>
> They correspond to the functions in OvmfPkg/PlatformPei:
> - CmosRead8
> - CmosWrite8
> - DebugDumpCmos
>
> EFI_HOB_PLATFORM_INFO is also defined in this patch which is used to
> pass the platform information in Hob to Dxe phase.
>
> After PlatformInitLib is created, OvmfPkg/PlatformPei is refactored
> with this library.
>
> 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>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH V7 18/37] OvmfPkg/PlatformInitLib: Add hob functions
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (16 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 17/37] OvmfPkg: Create initial version of PlatformInitLib Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-03-01 12:33 ` Gerd Hoffmann
2022-02-28 7:20 ` [PATCH V7 19/37] OvmfPkg/PlatformInitLib: Add memory functions Min Xu
` (19 subsequent siblings)
37 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
In this patch of PlatformInitLib, below hob functions are introduced:
- PlatformAddIoMemoryBaseSizeHob
- PlatformAddIoMemoryRangeHob
- PlatformAddMemoryBaseSizeHob
- PlatformAddMemoryRangeHob
- PlatformAddReservedMemoryBaseSizeHob
They correspond the below functions in OvmfPkg/PlatformPei:
- AddIoMemoryBaseSizeHob
- AddIoMemoryRangeHob
- AddMemoryBaseSizeHob
- AddMemoryRangeHob
- AddReservedMemoryBaseSizeHob
After above hob functions are introduced in PlatformInitLib,
OvmfPkg/PlatformPei is refactored with this library.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Include/Library/PlatformInitLib.h | 36 ++++++
OvmfPkg/Library/PlatformInitLib/Platform.c | 106 ++++++++++++++++++
.../PlatformInitLib/PlatformInitLib.inf | 2 +
OvmfPkg/PlatformPei/MemDetect.c | 20 ++--
OvmfPkg/PlatformPei/Platform.c | 101 ++---------------
OvmfPkg/PlatformPei/Platform.h | 31 -----
6 files changed, 165 insertions(+), 131 deletions(-)
create mode 100644 OvmfPkg/Library/PlatformInitLib/Platform.c
diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
index af75559e66fa..bc540f549d60 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -63,4 +63,40 @@ PlatformDebugDumpCmos (
VOID
);
+VOID
+EFIAPI
+PlatformAddIoMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize
+ );
+
+VOID
+EFIAPI
+PlatformAddIoMemoryRangeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN EFI_PHYSICAL_ADDRESS MemoryLimit
+ );
+
+VOID
+EFIAPI
+PlatformAddMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize
+ );
+
+VOID
+EFIAPI
+PlatformAddMemoryRangeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN EFI_PHYSICAL_ADDRESS MemoryLimit
+ );
+
+VOID
+EFIAPI
+PlatformAddReservedMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize,
+ IN BOOLEAN Cacheable
+ );
+
#endif // PLATFORM_INIT_LIB_H_
diff --git a/OvmfPkg/Library/PlatformInitLib/Platform.c b/OvmfPkg/Library/PlatformInitLib/Platform.c
new file mode 100644
index 000000000000..e41f230ff563
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/Platform.c
@@ -0,0 +1,106 @@
+/**@file
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include <PiPei.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PlatformInitLib.h>
+
+VOID
+EFIAPI
+PlatformAddIoMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize
+ )
+{
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_MEMORY_MAPPED_IO,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
+ MemoryBase,
+ MemorySize
+ );
+}
+
+VOID
+EFIAPI
+PlatformAddReservedMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize,
+ IN BOOLEAN Cacheable
+ )
+{
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_MEMORY_RESERVED,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ (Cacheable ?
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :
+ 0
+ ) |
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
+ MemoryBase,
+ MemorySize
+ );
+}
+
+VOID
+EFIAPI
+PlatformAddIoMemoryRangeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN EFI_PHYSICAL_ADDRESS MemoryLimit
+ )
+{
+ PlatformAddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
+}
+
+VOID
+EFIAPI
+PlatformAddMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize
+ )
+{
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
+ MemoryBase,
+ MemorySize
+ );
+}
+
+VOID
+EFIAPI
+PlatformAddMemoryRangeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN EFI_PHYSICAL_ADDRESS MemoryLimit
+ )
+{
+ PlatformAddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
index 4ea2da86274f..21813458cb59 100644
--- a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -24,6 +24,7 @@
[Sources]
Cmos.c
+ Platform.c
[Packages]
MdeModulePkg/MdeModulePkg.dec
@@ -34,3 +35,4 @@
BaseLib
DebugLib
IoLib
+ HobLib
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index d118dba2f214..d19a344d18b8 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -274,10 +274,10 @@ ScanOrAdd64BitE820Ram (
End = (E820Entry.BaseAddr + E820Entry.Length) &
~(UINT64)EFI_PAGE_MASK;
if (Base < End) {
- AddMemoryRangeHob (Base, End);
+ PlatformAddMemoryRangeHob (Base, End);
DEBUG ((
DEBUG_VERBOSE,
- "%a: AddMemoryRangeHob [0x%Lx, 0x%Lx)\n",
+ "%a: PlatformAddMemoryRangeHob [0x%Lx, 0x%Lx)\n",
__FUNCTION__,
Base,
End
@@ -743,8 +743,8 @@ QemuInitializeRamBelow1gb (
)
{
if (FeaturePcdGet (PcdSmmSmramRequire) && mQ35SmramAtDefaultSmbase) {
- AddMemoryRangeHob (0, SMM_DEFAULT_SMBASE);
- AddReservedMemoryBaseSizeHob (
+ PlatformAddMemoryRangeHob (0, SMM_DEFAULT_SMBASE);
+ PlatformAddReservedMemoryBaseSizeHob (
SMM_DEFAULT_SMBASE,
MCH_DEFAULT_SMBASE_SIZE,
TRUE /* Cacheable */
@@ -753,12 +753,12 @@ QemuInitializeRamBelow1gb (
SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE < BASE_512KB + BASE_128KB,
"end of SMRAM at default SMBASE ends at, or exceeds, 640KB"
);
- AddMemoryRangeHob (
+ PlatformAddMemoryRangeHob (
SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE,
BASE_512KB + BASE_128KB
);
} else {
- AddMemoryRangeHob (0, BASE_512KB + BASE_128KB);
+ PlatformAddMemoryRangeHob (0, BASE_512KB + BASE_128KB);
}
}
@@ -816,14 +816,14 @@ QemuInitializeRam (
UINT32 TsegSize;
TsegSize = mQ35TsegMbytes * SIZE_1MB;
- AddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);
- AddReservedMemoryBaseSizeHob (
+ PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);
+ PlatformAddReservedMemoryBaseSizeHob (
LowerMemorySize - TsegSize,
TsegSize,
TRUE
);
} else {
- AddMemoryRangeHob (BASE_1MB, LowerMemorySize);
+ PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize);
}
//
@@ -835,7 +835,7 @@ QemuInitializeRam (
if (EFI_ERROR (Status)) {
UpperMemorySize = GetSystemMemorySizeAbove4gb ();
if (UpperMemorySize != 0) {
- AddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);
+ PlatformAddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);
}
}
}
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 594891786440..62480c3c40e5 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -57,85 +57,6 @@ BOOLEAN mS3Supported = FALSE;
UINT32 mMaxCpuCount;
-VOID
-AddIoMemoryBaseSizeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- UINT64 MemorySize
- )
-{
- BuildResourceDescriptorHob (
- EFI_RESOURCE_MEMORY_MAPPED_IO,
- EFI_RESOURCE_ATTRIBUTE_PRESENT |
- EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
- EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
- EFI_RESOURCE_ATTRIBUTE_TESTED,
- MemoryBase,
- MemorySize
- );
-}
-
-VOID
-AddReservedMemoryBaseSizeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- UINT64 MemorySize,
- BOOLEAN Cacheable
- )
-{
- BuildResourceDescriptorHob (
- EFI_RESOURCE_MEMORY_RESERVED,
- EFI_RESOURCE_ATTRIBUTE_PRESENT |
- EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
- EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
- (Cacheable ?
- EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
- EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
- EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :
- 0
- ) |
- EFI_RESOURCE_ATTRIBUTE_TESTED,
- MemoryBase,
- MemorySize
- );
-}
-
-VOID
-AddIoMemoryRangeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- EFI_PHYSICAL_ADDRESS MemoryLimit
- )
-{
- AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
-}
-
-VOID
-AddMemoryBaseSizeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- UINT64 MemorySize
- )
-{
- BuildResourceDescriptorHob (
- EFI_RESOURCE_SYSTEM_MEMORY,
- EFI_RESOURCE_ATTRIBUTE_PRESENT |
- EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
- EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
- EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
- EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
- EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
- EFI_RESOURCE_ATTRIBUTE_TESTED,
- MemoryBase,
- MemorySize
- );
-}
-
-VOID
-AddMemoryRangeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- EFI_PHYSICAL_ADDRESS MemoryLimit
- )
-{
- AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
-}
-
VOID
MemMapInitialization (
VOID
@@ -155,12 +76,12 @@ MemMapInitialization (
//
// Video memory + Legacy BIOS region
//
- AddIoMemoryRangeHob (0x0A0000, BASE_1MB);
+ PlatformAddIoMemoryRangeHob (0x0A0000, BASE_1MB);
if (mHostBridgeDevId == 0xffff /* microvm */) {
- AddIoMemoryBaseSizeHob (MICROVM_GED_MMIO_BASE, SIZE_4KB);
- AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); /* ioapic #1 */
- AddIoMemoryBaseSizeHob (0xFEC10000, SIZE_4KB); /* ioapic #2 */
+ PlatformAddIoMemoryBaseSizeHob (MICROVM_GED_MMIO_BASE, SIZE_4KB);
+ PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); /* ioapic #1 */
+ PlatformAddIoMemoryBaseSizeHob (0xFEC10000, SIZE_4KB); /* ioapic #2 */
return;
}
@@ -194,20 +115,20 @@ MemMapInitialization (
// 0xFEE00000 LAPIC 1 MB
//
PciSize = 0xFC000000 - PciBase;
- AddIoMemoryBaseSizeHob (PciBase, PciSize);
+ PlatformAddIoMemoryBaseSizeHob (PciBase, PciSize);
PcdStatus = PcdSet64S (PcdPciMmio32Base, PciBase);
ASSERT_RETURN_ERROR (PcdStatus);
PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize);
ASSERT_RETURN_ERROR (PcdStatus);
- AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
- AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
+ PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
+ PlatformAddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
- AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
+ PlatformAddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
//
// Note: there should be an
//
- // AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
+ // PlatformAddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
//
// call below, just like the one above for RCBA. However, Linux insists
// that the MMCONFIG area be marked in the E820 or UEFI memory map as
@@ -225,7 +146,7 @@ MemMapInitialization (
// is most definitely not RAM; so, as an exception, cover it with
// uncacheable reserved memory right here.
//
- AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
+ PlatformAddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
BuildMemoryAllocationHob (
PciExBarBase,
SIZE_256MB,
@@ -233,7 +154,7 @@ MemMapInitialization (
);
}
- AddIoMemoryBaseSizeHob (PcdGet32 (PcdCpuLocalApicBaseAddress), SIZE_1MB);
+ PlatformAddIoMemoryBaseSizeHob (PcdGet32 (PcdCpuLocalApicBaseAddress), SIZE_1MB);
//
// On Q35, the IO Port space is available for PCI resource allocations from
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index 24e4da4e1d93..f193ff736549 100644
--- a/OvmfPkg/PlatformPei/Platform.h
+++ b/OvmfPkg/PlatformPei/Platform.h
@@ -11,37 +11,6 @@
#include <IndustryStandard/E820.h>
-VOID
-AddIoMemoryBaseSizeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- UINT64 MemorySize
- );
-
-VOID
-AddIoMemoryRangeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- EFI_PHYSICAL_ADDRESS MemoryLimit
- );
-
-VOID
-AddMemoryBaseSizeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- UINT64 MemorySize
- );
-
-VOID
-AddMemoryRangeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- EFI_PHYSICAL_ADDRESS MemoryLimit
- );
-
-VOID
-AddReservedMemoryBaseSizeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- UINT64 MemorySize,
- BOOLEAN Cacheable
- );
-
VOID
AddressWidthInitialization (
VOID
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* Re: [PATCH V7 18/37] OvmfPkg/PlatformInitLib: Add hob functions
2022-02-28 7:20 ` [PATCH V7 18/37] OvmfPkg/PlatformInitLib: Add hob functions Min Xu
@ 2022-03-01 12:33 ` Gerd Hoffmann
0 siblings, 0 replies; 72+ messages in thread
From: Gerd Hoffmann @ 2022-03-01 12:33 UTC (permalink / raw)
To: Min Xu
Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky
On Mon, Feb 28, 2022 at 03:20:50PM +0800, Min Xu wrote:
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
>
> In this patch of PlatformInitLib, below hob functions are introduced:
> - PlatformAddIoMemoryBaseSizeHob
> - PlatformAddIoMemoryRangeHob
> - PlatformAddMemoryBaseSizeHob
> - PlatformAddMemoryRangeHob
> - PlatformAddReservedMemoryBaseSizeHob
>
> They correspond the below functions in OvmfPkg/PlatformPei:
> - AddIoMemoryBaseSizeHob
> - AddIoMemoryRangeHob
> - AddMemoryBaseSizeHob
> - AddMemoryRangeHob
> - AddReservedMemoryBaseSizeHob
>
> After above hob functions are introduced in PlatformInitLib,
> OvmfPkg/PlatformPei is refactored with this library.
>
> 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>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH V7 19/37] OvmfPkg/PlatformInitLib: Add memory functions
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (17 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 18/37] OvmfPkg/PlatformInitLib: Add hob functions Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-03-01 13:09 ` Gerd Hoffmann
2022-02-28 7:20 ` [PATCH V7 20/37] OvmfPkg/PlatformInitLib: Add platform functions Min Xu
` (18 subsequent siblings)
37 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
Below functions are introduced in PlatformInitLib:
- PlatformGetFirstNonAddress
- PlatformAddressWidthInitialization
- PlatformGetSystemMemorySizeBelow4gb
- PlatformQemuUc32BaseInitialization
- PlatformInitializeRamRegions
They correspond to the below functions in OvmfPkg/PlatformPei:
- GetFirstNonAddress
- AddressWidthInitialization
- GetSystemMemorySizeBelow4gb
- QemuUc32BaseInitialization
- InitializeRamRegions
After that OvmfPkg/PlatformPei is refactored with this library.
Note: PlatformInitLib will not determine whether SMM or S3 is supported
or not. Instead the caller of these functions should input SMM / S3
support as the IN parameter by themselves. This is to reduce the
complexity of PlatformInitLib. Another reason is that some PCDs cannot
be declared as FixedAtBuild while PlatformInitLib is designed to be used
in both SEC and PEI phase.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Include/Library/PlatformInitLib.h | 78 ++
OvmfPkg/Library/PlatformInitLib/MemDetect.c | 694 ++++++++++++++++++
.../PlatformInitLib/PlatformInitLib.inf | 16 +
OvmfPkg/PlatformPei/MemDetect.c | 654 +----------------
OvmfPkg/PlatformPei/Platform.c | 9 +-
OvmfPkg/PlatformPei/Platform.h | 5 -
6 files changed, 822 insertions(+), 634 deletions(-)
create mode 100644 OvmfPkg/Library/PlatformInitLib/MemDetect.c
diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
index bc540f549d60..df2646880909 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -63,6 +63,84 @@ PlatformDebugDumpCmos (
VOID
);
+/**
+ * Return the highest address that DXE could possibly use, plus one.
+ *
+ * @param Pci64Base The 64-bit PCI host aperture base address.
+ * @param Pci64Size The 64-bit PCI host aperture size.
+ * @param DefaultPciMmio64Size The default 64-bit PCI host aperture size.
+ *
+ * @return The highest address that DXE could possibly use, plus one.
+ */
+UINT64
+EFIAPI
+PlatformGetFirstNonAddress (
+ OUT UINT64 *Pci64Base,
+ OUT UINT64 *Pci64Size,
+ IN UINT64 DefaultPciMmio64Size
+ );
+
+/**
+ * Initialize the PhysMemAddressWidth variable, based on guest RAM size.
+ *
+ * @param FirstNonAddress The highest address that DXE could possibly use, plus one.
+ *
+ * @return The physical memory address width based on the guest RAM size.
+ */
+UINT8
+EFIAPI
+PlatformAddressWidthInitialization (
+ IN UINT64 FirstNonAddress
+ );
+
+/**
+ * Get the memory size below 4GB.
+ *
+ * @return UINT32 The lower memory size.
+ */
+UINT32
+EFIAPI
+PlatformGetSystemMemorySizeBelow4gb (
+ VOID
+ );
+
+/**
+ * Initializatoin of Qemu UC32Base.
+ *
+ * @param HostBridgeDevId The host bridge Dev Id.
+ * @param LowerMemorySize The lower memory size (under 4G).
+ * @return UINT32 The Qemu UC32 base address.
+ */
+UINT32
+EFIAPI
+PlatformQemuUc32BaseInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT32 LowerMemorySize
+ );
+
+/**
+ Publish system RAM and reserve memory regions.
+
+ @param Uc32Base
+ @param HostBridgeDevId
+ @param SmmSmramRequire
+ @param BootMode
+ @param S3Supported
+ @param LowerMemorySize
+ @param Q35TsegMbytes
+**/
+VOID
+EFIAPI
+PlatformInitializeRamRegions (
+ IN UINT32 Uc32Base,
+ IN UINT16 HostBridgeDevId,
+ IN BOOLEAN SmmSmramRequire,
+ IN EFI_BOOT_MODE BootMode,
+ IN BOOLEAN S3Supported,
+ IN UINT32 LowerMemorySize,
+ IN UINT16 Q35TsegMbytes
+ );
+
VOID
EFIAPI
PlatformAddIoMemoryBaseSizeHob (
diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
new file mode 100644
index 000000000000..5a9cb6e638ed
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
@@ -0,0 +1,694 @@
+/**@file
+ Memory Detection for Virtual Machines.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Module Name:
+
+ MemDetect.c
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include <IndustryStandard/E820.h>
+#include <IndustryStandard/I440FxPiix4.h>
+#include <IndustryStandard/Q35MchIch9.h>
+#include <IndustryStandard/CloudHv.h>
+#include <PiPei.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/ResourcePublicationLib.h>
+#include <Library/MtrrLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/QemuFwCfgSimpleParserLib.h>
+
+#include <Library/PlatformInitLib.h>
+
+/**
+ * Initializatoin of Qemu UC32Base.
+ *
+ * @param HostBridgeDevId The host bridge Dev Id.
+ * @param LowerMemorySize The lower memory size (under 4G).
+ * @return UINT32 The Qemu UC32 base address.
+ */
+UINT32
+EFIAPI
+PlatformQemuUc32BaseInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT32 LowerMemorySize
+ )
+{
+ UINT32 Uc32Size;
+ UINT32 Uc32Base;
+
+ if (HostBridgeDevId == 0xffff /* microvm */) {
+ return 0;
+ }
+
+ if (HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+ //
+ // On q35, the 32-bit area that we'll mark as UC, through variable MTRRs,
+ // starts at PcdPciExpressBaseAddress. The platform DSC is responsible for
+ // setting PcdPciExpressBaseAddress such that describing the
+ // [PcdPciExpressBaseAddress, 4GB) range require a very small number of
+ // variable MTRRs (preferably 1 or 2).
+ //
+
+ ASSERT (FixedPcdGet64 (PcdPciExpressBaseAddress) <= MAX_UINT32);
+ Uc32Base = (UINT32)FixedPcdGet64 (PcdPciExpressBaseAddress);
+ return Uc32Base;
+ }
+
+ if (HostBridgeDevId == CLOUDHV_DEVICE_ID) {
+ Uc32Base = CLOUDHV_MMIO_HOLE_ADDRESS;
+ return Uc32Base;
+ }
+
+ ASSERT (HostBridgeDevId == INTEL_82441_DEVICE_ID);
+ //
+ // On i440fx, start with the [LowerMemorySize, 4GB) range. Make sure one
+ // variable MTRR suffices by truncating the size to a whole power of two,
+ // while keeping the end affixed to 4GB. This will round the base up.
+ //
+ Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize));
+ Uc32Base = (UINT32)(SIZE_4GB - Uc32Size);
+ //
+ // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.
+ // Therefore mQemuUc32Base is at least 2GB.
+ //
+ ASSERT (Uc32Base >= BASE_2GB);
+
+ if (Uc32Base != LowerMemorySize) {
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: rounded UC32 base from 0x%x up to 0x%x, for "
+ "an UC32 size of 0x%x\n",
+ __FUNCTION__,
+ LowerMemorySize,
+ Uc32Base,
+ Uc32Size
+ ));
+ }
+
+ return Uc32Base;
+}
+
+/**
+ Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map that start outside
+ of the 32-bit address range.
+
+ Find the highest exclusive >=4GB RAM address, or produce memory resource
+ descriptor HOBs for RAM entries that start at or above 4GB.
+
+ @param[out] MaxAddress If MaxAddress is NULL, then ScanOrAdd64BitE820Ram()
+ produces memory resource descriptor HOBs for RAM
+ entries that start at or above 4GB.
+
+ Otherwise, MaxAddress holds the highest exclusive
+ >=4GB RAM address on output. If QEMU's fw_cfg E820
+ RAM map contains no RAM entry that starts outside of
+ the 32-bit address range, then MaxAddress is exactly
+ 4GB on output.
+
+ @retval EFI_SUCCESS The fw_cfg E820 RAM map was found and processed.
+
+ @retval EFI_PROTOCOL_ERROR The RAM map was found, but its size wasn't a
+ whole multiple of sizeof(EFI_E820_ENTRY64). No
+ RAM entry was processed.
+
+ @return Error codes from QemuFwCfgFindFile(). No RAM
+ entry was processed.
+**/
+EFI_STATUS
+ScanOrAdd64BitE820Ram (
+ IN BOOLEAN AddHighHob,
+ OUT UINT64 *LowMemory OPTIONAL,
+ OUT UINT64 *MaxAddress OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ FIRMWARE_CONFIG_ITEM FwCfgItem;
+ UINTN FwCfgSize;
+ EFI_E820_ENTRY64 E820Entry;
+ UINTN Processed;
+
+ Status = QemuFwCfgFindFile ("etc/e820", &FwCfgItem, &FwCfgSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (FwCfgSize % sizeof E820Entry != 0) {
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ if (LowMemory != NULL) {
+ *LowMemory = 0;
+ }
+
+ if (MaxAddress != NULL) {
+ *MaxAddress = BASE_4GB;
+ }
+
+ QemuFwCfgSelectItem (FwCfgItem);
+ for (Processed = 0; Processed < FwCfgSize; Processed += sizeof E820Entry) {
+ QemuFwCfgReadBytes (sizeof E820Entry, &E820Entry);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: Base=0x%Lx Length=0x%Lx Type=%u\n",
+ __FUNCTION__,
+ E820Entry.BaseAddr,
+ E820Entry.Length,
+ E820Entry.Type
+ ));
+ if (E820Entry.Type == EfiAcpiAddressRangeMemory) {
+ if (AddHighHob && (E820Entry.BaseAddr >= BASE_4GB)) {
+ UINT64 Base;
+ UINT64 End;
+
+ //
+ // Round up the start address, and round down the end address.
+ //
+ Base = ALIGN_VALUE (E820Entry.BaseAddr, (UINT64)EFI_PAGE_SIZE);
+ End = (E820Entry.BaseAddr + E820Entry.Length) &
+ ~(UINT64)EFI_PAGE_MASK;
+ if (Base < End) {
+ PlatformAddMemoryRangeHob (Base, End);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: PlatformAddMemoryRangeHob [0x%Lx, 0x%Lx)\n",
+ __FUNCTION__,
+ Base,
+ End
+ ));
+ }
+ }
+
+ if (MaxAddress || LowMemory) {
+ UINT64 Candidate;
+
+ Candidate = E820Entry.BaseAddr + E820Entry.Length;
+ if (MaxAddress && (Candidate > *MaxAddress)) {
+ *MaxAddress = Candidate;
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: MaxAddress=0x%Lx\n",
+ __FUNCTION__,
+ *MaxAddress
+ ));
+ }
+
+ if (LowMemory && (Candidate > *LowMemory) && (Candidate < BASE_4GB)) {
+ *LowMemory = Candidate;
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: LowMemory=0x%Lx\n",
+ __FUNCTION__,
+ *LowMemory
+ ));
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * Get the memory size below 4GB.
+ *
+ * @return UINT32 The lower memory size.
+ */
+UINT32
+EFIAPI
+PlatformGetSystemMemorySizeBelow4gb (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 LowerMemorySize = 0;
+ UINT8 Cmos0x34;
+ UINT8 Cmos0x35;
+
+ Status = ScanOrAdd64BitE820Ram (FALSE, &LowerMemorySize, NULL);
+ if ((Status == EFI_SUCCESS) && (LowerMemorySize > 0)) {
+ return (UINT32)LowerMemorySize;
+ }
+
+ //
+ // CMOS 0x34/0x35 specifies the system memory above 16 MB.
+ // * CMOS(0x35) is the high byte
+ // * CMOS(0x34) is the low byte
+ // * The size is specified in 64kb chunks
+ // * Since this is memory above 16MB, the 16MB must be added
+ // into the calculation to get the total memory size.
+ //
+
+ Cmos0x34 = (UINT8)PlatformCmosRead8 (0x34);
+ Cmos0x35 = (UINT8)PlatformCmosRead8 (0x35);
+
+ return (UINT32)(((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);
+}
+
+UINT64
+GetSystemMemorySizeAbove4gb (
+ )
+{
+ UINT32 Size;
+ UINTN CmosIndex;
+
+ //
+ // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
+ // * CMOS(0x5d) is the most significant size byte
+ // * CMOS(0x5c) is the middle size byte
+ // * CMOS(0x5b) is the least significant size byte
+ // * The size is specified in 64kb chunks
+ //
+
+ Size = 0;
+ for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {
+ Size = (UINT32)(Size << 8) + (UINT32)PlatformCmosRead8 (CmosIndex);
+ }
+
+ return LShiftU64 (Size, 16);
+}
+
+/**
+ * Return the highest address that DXE could possibly use, plus one.
+ *
+ * @param Pci64Base The 64-bit PCI host aperture base address.
+ * @param Pci64Size The 64-bit PCI host aperture size.
+ * @param DefaultPciMmio64Size The default 64-bit PCI host aperture size.
+ *
+ * @return UINT64 The highest address that DXE could possibly use, plus one.
+ */
+UINT64
+EFIAPI
+PlatformGetFirstNonAddress (
+ OUT UINT64 *Pci64Base,
+ OUT UINT64 *Pci64Size,
+ IN UINT64 DefaultPciMmio64Size
+ )
+{
+ UINT64 FirstNonAddress;
+ UINT32 FwCfgPciMmio64Mb;
+ EFI_STATUS Status;
+ FIRMWARE_CONFIG_ITEM FwCfgItem;
+ UINTN FwCfgSize;
+ UINT64 HotPlugMemoryEnd;
+
+ //
+ // set FirstNonAddress to suppress incorrect compiler/analyzer warnings
+ //
+ FirstNonAddress = 0;
+
+ //
+ // If QEMU presents an E820 map, then get the highest exclusive >=4GB RAM
+ // address from it. This can express an address >= 4GB+1TB.
+ //
+ // Otherwise, get the flat size of the memory above 4GB from the CMOS (which
+ // can only express a size smaller than 1TB), and add it to 4GB.
+ //
+ Status = ScanOrAdd64BitE820Ram (FALSE, NULL, &FirstNonAddress);
+ if (EFI_ERROR (Status)) {
+ FirstNonAddress = BASE_4GB + GetSystemMemorySizeAbove4gb ();
+ }
+
+ //
+ // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO
+ // resources to 32-bit anyway. See DegradeResource() in
+ // "PciResourceSupport.c".
+ //
+ #ifdef MDE_CPU_IA32
+ if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ return FirstNonAddress;
+ }
+
+ #endif
+
+ //
+ // Otherwise, in order to calculate the highest address plus one, we must
+ // consider the 64-bit PCI host aperture too. Fetch the default size.
+ //
+ *Pci64Size = DefaultPciMmio64Size;
+
+ //
+ // See if the user specified the number of megabytes for the 64-bit PCI host
+ // aperture. Accept an aperture size up to 16TB.
+ //
+ // As signaled by the "X-" prefix, this knob is experimental, and might go
+ // away at any time.
+ //
+ Status = QemuFwCfgParseUint32 (
+ "opt/ovmf/X-PciMmio64Mb",
+ FALSE,
+ &FwCfgPciMmio64Mb
+ );
+ switch (Status) {
+ case EFI_UNSUPPORTED:
+ case EFI_NOT_FOUND:
+ break;
+ case EFI_SUCCESS:
+ if (FwCfgPciMmio64Mb <= 0x1000000) {
+ *Pci64Size = LShiftU64 (FwCfgPciMmio64Mb, 20);
+ break;
+ }
+
+ //
+ // fall through
+ //
+ default:
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: ignoring malformed 64-bit PCI host aperture size from fw_cfg\n",
+ __FUNCTION__
+ ));
+ break;
+ }
+
+ if (*Pci64Size == 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: disabling 64-bit PCI host aperture\n",
+ __FUNCTION__
+ ));
+
+ //
+ // There's nothing more to do; the amount of memory above 4GB fully
+ // determines the highest address plus one. The memory hotplug area (see
+ // below) plays no role for the firmware in this case.
+ //
+ return FirstNonAddress;
+ }
+
+ //
+ // The "etc/reserved-memory-end" fw_cfg file, when present, contains an
+ // absolute, exclusive end address for the memory hotplug area. This area
+ // starts right at the end of the memory above 4GB. The 64-bit PCI host
+ // aperture must be placed above it.
+ //
+ Status = QemuFwCfgFindFile (
+ "etc/reserved-memory-end",
+ &FwCfgItem,
+ &FwCfgSize
+ );
+ if (!EFI_ERROR (Status) && (FwCfgSize == sizeof HotPlugMemoryEnd)) {
+ QemuFwCfgSelectItem (FwCfgItem);
+ QemuFwCfgReadBytes (FwCfgSize, &HotPlugMemoryEnd);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: HotPlugMemoryEnd=0x%Lx\n",
+ __FUNCTION__,
+ HotPlugMemoryEnd
+ ));
+
+ ASSERT (HotPlugMemoryEnd >= FirstNonAddress);
+ FirstNonAddress = HotPlugMemoryEnd;
+ }
+
+ //
+ // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so
+ // that the host can map it with 1GB hugepages. Follow suit.
+ //
+ *Pci64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);
+ *Pci64Size = ALIGN_VALUE (*Pci64Size, (UINT64)SIZE_1GB);
+
+ //
+ // The 64-bit PCI host aperture should also be "naturally" aligned. The
+ // alignment is determined by rounding the size of the aperture down to the
+ // next smaller or equal power of two. That is, align the aperture by the
+ // largest BAR size that can fit into it.
+ //
+ *Pci64Base = ALIGN_VALUE (*Pci64Base, GetPowerOfTwo64 (*Pci64Size));
+
+ //
+ // The useful address space ends with the 64-bit PCI host aperture.
+ //
+ FirstNonAddress = *Pci64Base + *Pci64Size;
+ return FirstNonAddress;
+}
+
+/**
+ * Initialize the PhysMemAddressWidth variable, based on guest RAM size.
+ *
+ * @param FirstNonAddress The highest address that DXE could possibly use, plus one.
+ *
+ * @return The physical memory address width based on the guest RAM size.
+ */
+UINT8
+EFIAPI
+PlatformAddressWidthInitialization (
+ IN UINT64 FirstNonAddress
+ )
+{
+ UINT8 PhysMemAddressWidth;
+
+ //
+ // As guest-physical memory size grows, the permanent PEI RAM requirements
+ // are dominated by the identity-mapping page tables built by the DXE IPL.
+ // The DXL IPL keys off of the physical address bits advertized in the CPU
+ // HOB. To conserve memory, we calculate the minimum address width here.
+ //
+ PhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
+
+ //
+ // If FirstNonAddress is not an integral power of two, then we need an
+ // additional bit.
+ //
+ if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {
+ ++PhysMemAddressWidth;
+ }
+
+ //
+ // The minimum address width is 36 (covers up to and excluding 64 GB, which
+ // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
+ // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We
+ // can simply assert that here, since 48 bits are good enough for 256 TB.
+ //
+ if (PhysMemAddressWidth <= 36) {
+ PhysMemAddressWidth = 36;
+ }
+
+ ASSERT (PhysMemAddressWidth <= 48);
+
+ return PhysMemAddressWidth;
+}
+
+VOID
+PlatformQemuInitializeRamBelow1gb (
+ VOID
+ )
+{
+ PlatformAddMemoryRangeHob (0, BASE_512KB + BASE_128KB);
+}
+
+/**
+ Peform Memory Detection for QEMU / KVM
+
+**/
+VOID
+QemuInitializeRam (
+ UINT32 Uc32Base,
+ UINT16 HostBridgeDevId,
+ EFI_BOOT_MODE BootMode,
+ BOOLEAN SmmSmramRequire,
+ UINT32 LowerMemorySize,
+ UINT16 Q35TsegMbytes
+ )
+{
+ UINT64 UpperMemorySize;
+ MTRR_SETTINGS MtrrSettings;
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "%a called\n", __FUNCTION__));
+
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ //
+ // Create the following memory HOB as an exception on the S3 boot path.
+ //
+ // Normally we'd create memory HOBs only on the normal boot path. However,
+ // CpuMpPei specifically needs such a low-memory HOB on the S3 path as
+ // well, for "borrowing" a subset of it temporarily, for the AP startup
+ // vector.
+ //
+ // CpuMpPei saves the original contents of the borrowed area in permanent
+ // PEI RAM, in a backup buffer allocated with the normal PEI services.
+ // CpuMpPei restores the original contents ("returns" the borrowed area) at
+ // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before
+ // transferring control to the OS's wakeup vector in the FACS.
+ //
+ // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to
+ // restore the original contents. Furthermore, we expect all such PEIMs
+ // (CpuMpPei included) to claim the borrowed areas by producing memory
+ // allocation HOBs, and to honor preexistent memory allocation HOBs when
+ // looking for an area to borrow.
+ //
+ PlatformQemuInitializeRamBelow1gb ();
+ } else {
+ //
+ // Create memory HOBs
+ //
+ PlatformQemuInitializeRamBelow1gb ();
+
+ if (SmmSmramRequire) {
+ UINT32 TsegSize;
+
+ TsegSize = Q35TsegMbytes * SIZE_1MB;
+ PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);
+ PlatformAddReservedMemoryBaseSizeHob (
+ LowerMemorySize - TsegSize,
+ TsegSize,
+ TRUE
+ );
+ } else {
+ PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize);
+ }
+
+ //
+ // If QEMU presents an E820 map, then create memory HOBs for the >=4GB RAM
+ // entries. Otherwise, create a single memory HOB with the flat >=4GB
+ // memory size read from the CMOS.
+ //
+ Status = ScanOrAdd64BitE820Ram (TRUE, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ UpperMemorySize = GetSystemMemorySizeAbove4gb ();
+ if (UpperMemorySize != 0) {
+ PlatformAddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);
+ }
+ }
+ }
+
+ //
+ // We'd like to keep the following ranges uncached:
+ // - [640 KB, 1 MB)
+ // - [LowerMemorySize, 4 GB)
+ //
+ // Everything else should be WB. Unfortunately, programming the inverse (ie.
+ // keeping the default UC, and configuring the complement set of the above as
+ // WB) is not reliable in general, because the end of the upper RAM can have
+ // practically any alignment, and we may not have enough variable MTRRs to
+ // cover it exactly.
+ //
+ if (IsMtrrSupported () && (HostBridgeDevId != CLOUDHV_DEVICE_ID)) {
+ MtrrGetAllMtrrs (&MtrrSettings);
+
+ //
+ // MTRRs disabled, fixed MTRRs disabled, default type is uncached
+ //
+ ASSERT ((MtrrSettings.MtrrDefType & BIT11) == 0);
+ ASSERT ((MtrrSettings.MtrrDefType & BIT10) == 0);
+ ASSERT ((MtrrSettings.MtrrDefType & 0xFF) == 0);
+
+ //
+ // flip default type to writeback
+ //
+ SetMem (&MtrrSettings.Fixed, sizeof MtrrSettings.Fixed, 0x06);
+ ZeroMem (&MtrrSettings.Variables, sizeof MtrrSettings.Variables);
+ MtrrSettings.MtrrDefType |= BIT11 | BIT10 | 6;
+ MtrrSetAllMtrrs (&MtrrSettings);
+
+ //
+ // Set memory range from 640KB to 1MB to uncacheable
+ //
+ Status = MtrrSetMemoryAttribute (
+ BASE_512KB + BASE_128KB,
+ BASE_1MB - (BASE_512KB + BASE_128KB),
+ CacheUncacheable
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI
+ // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable.
+ //
+ Status = MtrrSetMemoryAttribute (
+ Uc32Base,
+ SIZE_4GB - Uc32Base,
+ CacheUncacheable
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Publish system RAM and reserve memory regions
+
+**/
+VOID
+EFIAPI
+PlatformInitializeRamRegions (
+ IN UINT32 Uc32Base,
+ IN UINT16 HostBridgeDevId,
+ IN BOOLEAN SmmSmramRequire,
+ IN EFI_BOOT_MODE BootMode,
+ IN BOOLEAN S3Supported,
+ IN UINT32 LowerMemorySize,
+ IN UINT16 Q35TsegMbytes
+ )
+{
+ QemuInitializeRam (
+ Uc32Base,
+ HostBridgeDevId,
+ BootMode,
+ SmmSmramRequire,
+ LowerMemorySize,
+ Q35TsegMbytes
+ );
+
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ if (!SmmSmramRequire) {
+ //
+ // Reserve the lock box storage area
+ //
+ // Since this memory range will be used on S3 resume, it must be
+ // reserved as ACPI NVS.
+ //
+ // If S3 is unsupported, then various drivers might still write to the
+ // LockBox area. We ought to prevent DXE from serving allocation requests
+ // such that they would overlap the LockBox storage.
+ //
+ ZeroMem (
+ (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfLockBoxStorageBase),
+ (UINTN)FixedPcdGet32 (PcdOvmfLockBoxStorageSize)
+ );
+ BuildMemoryAllocationHob (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfLockBoxStorageBase),
+ (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfLockBoxStorageSize),
+ S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
+ );
+ }
+
+ #ifdef MDE_CPU_X64
+ if (FixedPcdGet32 (PcdOvmfWorkAreaSize) != 0) {
+ //
+ // Reserve the work area.
+ //
+ // Since this memory range will be used by the Reset Vector on S3
+ // resume, it must be reserved as ACPI NVS.
+ //
+ // If S3 is unsupported, then various drivers might still write to the
+ // work area. We ought to prevent DXE from serving allocation requests
+ // such that they would overlap the work area.
+ //
+ BuildMemoryAllocationHob (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaBase),
+ (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaSize),
+ EfiBootServicesData
+ );
+ }
+
+ #endif
+ }
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
index 21813458cb59..6ba1e59246d1 100644
--- a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -24,15 +24,31 @@
[Sources]
Cmos.c
+ MemDetect.c
Platform.c
[Packages]
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
OvmfPkg/OvmfPkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
[LibraryClasses]
BaseLib
DebugLib
IoLib
HobLib
+ QemuFwCfgLib
+ QemuFwCfgSimpleParserLib
+ MtrrLib
+ PcdLib
+
+[FixedPcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index d19a344d18b8..9b62625f9d91 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -50,6 +50,7 @@ STATIC UINT16 mQ35TsegMbytes;
BOOLEAN mQ35SmramAtDefaultSmbase;
UINT32 mQemuUc32Base;
+UINT32 mLowerMemorySize = 0;
VOID
Q35TsegMbytesInitialization (
@@ -140,406 +141,11 @@ QemuUc32BaseInitialization (
VOID
)
{
- UINT32 LowerMemorySize;
- UINT32 Uc32Size;
-
if (mHostBridgeDevId == 0xffff /* microvm */) {
return;
}
- if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
- //
- // On q35, the 32-bit area that we'll mark as UC, through variable MTRRs,
- // starts at PcdPciExpressBaseAddress. The platform DSC is responsible for
- // setting PcdPciExpressBaseAddress such that describing the
- // [PcdPciExpressBaseAddress, 4GB) range require a very small number of
- // variable MTRRs (preferably 1 or 2).
- //
- ASSERT (FixedPcdGet64 (PcdPciExpressBaseAddress) <= MAX_UINT32);
- mQemuUc32Base = (UINT32)FixedPcdGet64 (PcdPciExpressBaseAddress);
- return;
- }
-
- if (mHostBridgeDevId == CLOUDHV_DEVICE_ID) {
- Uc32Size = CLOUDHV_MMIO_HOLE_SIZE;
- mQemuUc32Base = CLOUDHV_MMIO_HOLE_ADDRESS;
- return;
- }
-
- ASSERT (mHostBridgeDevId == INTEL_82441_DEVICE_ID);
- //
- // On i440fx, start with the [LowerMemorySize, 4GB) range. Make sure one
- // variable MTRR suffices by truncating the size to a whole power of two,
- // while keeping the end affixed to 4GB. This will round the base up.
- //
- LowerMemorySize = GetSystemMemorySizeBelow4gb ();
- Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize));
- mQemuUc32Base = (UINT32)(SIZE_4GB - Uc32Size);
- //
- // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.
- // Therefore mQemuUc32Base is at least 2GB.
- //
- ASSERT (mQemuUc32Base >= BASE_2GB);
-
- if (mQemuUc32Base != LowerMemorySize) {
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: rounded UC32 base from 0x%x up to 0x%x, for "
- "an UC32 size of 0x%x\n",
- __FUNCTION__,
- LowerMemorySize,
- mQemuUc32Base,
- Uc32Size
- ));
- }
-}
-
-/**
- Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map that start outside
- of the 32-bit address range.
-
- Find the highest exclusive >=4GB RAM address, or produce memory resource
- descriptor HOBs for RAM entries that start at or above 4GB.
-
- @param[out] MaxAddress If MaxAddress is NULL, then ScanOrAdd64BitE820Ram()
- produces memory resource descriptor HOBs for RAM
- entries that start at or above 4GB.
-
- Otherwise, MaxAddress holds the highest exclusive
- >=4GB RAM address on output. If QEMU's fw_cfg E820
- RAM map contains no RAM entry that starts outside of
- the 32-bit address range, then MaxAddress is exactly
- 4GB on output.
-
- @retval EFI_SUCCESS The fw_cfg E820 RAM map was found and processed.
-
- @retval EFI_PROTOCOL_ERROR The RAM map was found, but its size wasn't a
- whole multiple of sizeof(EFI_E820_ENTRY64). No
- RAM entry was processed.
-
- @return Error codes from QemuFwCfgFindFile(). No RAM
- entry was processed.
-**/
-STATIC
-EFI_STATUS
-ScanOrAdd64BitE820Ram (
- IN BOOLEAN AddHighHob,
- OUT UINT64 *LowMemory OPTIONAL,
- OUT UINT64 *MaxAddress OPTIONAL
- )
-{
- EFI_STATUS Status;
- FIRMWARE_CONFIG_ITEM FwCfgItem;
- UINTN FwCfgSize;
- EFI_E820_ENTRY64 E820Entry;
- UINTN Processed;
-
- Status = QemuFwCfgFindFile ("etc/e820", &FwCfgItem, &FwCfgSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (FwCfgSize % sizeof E820Entry != 0) {
- return EFI_PROTOCOL_ERROR;
- }
-
- if (LowMemory != NULL) {
- *LowMemory = 0;
- }
-
- if (MaxAddress != NULL) {
- *MaxAddress = BASE_4GB;
- }
-
- QemuFwCfgSelectItem (FwCfgItem);
- for (Processed = 0; Processed < FwCfgSize; Processed += sizeof E820Entry) {
- QemuFwCfgReadBytes (sizeof E820Entry, &E820Entry);
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: Base=0x%Lx Length=0x%Lx Type=%u\n",
- __FUNCTION__,
- E820Entry.BaseAddr,
- E820Entry.Length,
- E820Entry.Type
- ));
- if (E820Entry.Type == EfiAcpiAddressRangeMemory) {
- if (AddHighHob && (E820Entry.BaseAddr >= BASE_4GB)) {
- UINT64 Base;
- UINT64 End;
-
- //
- // Round up the start address, and round down the end address.
- //
- Base = ALIGN_VALUE (E820Entry.BaseAddr, (UINT64)EFI_PAGE_SIZE);
- End = (E820Entry.BaseAddr + E820Entry.Length) &
- ~(UINT64)EFI_PAGE_MASK;
- if (Base < End) {
- PlatformAddMemoryRangeHob (Base, End);
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: PlatformAddMemoryRangeHob [0x%Lx, 0x%Lx)\n",
- __FUNCTION__,
- Base,
- End
- ));
- }
- }
-
- if (MaxAddress || LowMemory) {
- UINT64 Candidate;
-
- Candidate = E820Entry.BaseAddr + E820Entry.Length;
- if (MaxAddress && (Candidate > *MaxAddress)) {
- *MaxAddress = Candidate;
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: MaxAddress=0x%Lx\n",
- __FUNCTION__,
- *MaxAddress
- ));
- }
-
- if (LowMemory && (Candidate > *LowMemory) && (Candidate < BASE_4GB)) {
- *LowMemory = Candidate;
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: LowMemory=0x%Lx\n",
- __FUNCTION__,
- *LowMemory
- ));
- }
- }
- }
- }
-
- return EFI_SUCCESS;
-}
-
-UINT32
-GetSystemMemorySizeBelow4gb (
- VOID
- )
-{
- EFI_STATUS Status;
- UINT64 LowerMemorySize = 0;
- UINT8 Cmos0x34;
- UINT8 Cmos0x35;
-
- Status = ScanOrAdd64BitE820Ram (FALSE, &LowerMemorySize, NULL);
- if ((Status == EFI_SUCCESS) && (LowerMemorySize > 0)) {
- return (UINT32)LowerMemorySize;
- }
-
- //
- // CMOS 0x34/0x35 specifies the system memory above 16 MB.
- // * CMOS(0x35) is the high byte
- // * CMOS(0x34) is the low byte
- // * The size is specified in 64kb chunks
- // * Since this is memory above 16MB, the 16MB must be added
- // into the calculation to get the total memory size.
- //
-
- Cmos0x34 = (UINT8)PlatformCmosRead8 (0x34);
- Cmos0x35 = (UINT8)PlatformCmosRead8 (0x35);
-
- return (UINT32)(((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);
-}
-
-STATIC
-UINT64
-GetSystemMemorySizeAbove4gb (
- )
-{
- UINT32 Size;
- UINTN CmosIndex;
-
- //
- // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
- // * CMOS(0x5d) is the most significant size byte
- // * CMOS(0x5c) is the middle size byte
- // * CMOS(0x5b) is the least significant size byte
- // * The size is specified in 64kb chunks
- //
-
- Size = 0;
- for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {
- Size = (UINT32)(Size << 8) + (UINT32)PlatformCmosRead8 (CmosIndex);
- }
-
- return LShiftU64 (Size, 16);
-}
-
-/**
- Return the highest address that DXE could possibly use, plus one.
-**/
-STATIC
-UINT64
-GetFirstNonAddress (
- VOID
- )
-{
- UINT64 FirstNonAddress;
- UINT64 Pci64Base, Pci64Size;
- UINT32 FwCfgPciMmio64Mb;
- EFI_STATUS Status;
- FIRMWARE_CONFIG_ITEM FwCfgItem;
- UINTN FwCfgSize;
- UINT64 HotPlugMemoryEnd;
- RETURN_STATUS PcdStatus;
-
- //
- // set FirstNonAddress to suppress incorrect compiler/analyzer warnings
- //
- FirstNonAddress = 0;
-
- //
- // If QEMU presents an E820 map, then get the highest exclusive >=4GB RAM
- // address from it. This can express an address >= 4GB+1TB.
- //
- // Otherwise, get the flat size of the memory above 4GB from the CMOS (which
- // can only express a size smaller than 1TB), and add it to 4GB.
- //
- Status = ScanOrAdd64BitE820Ram (FALSE, NULL, &FirstNonAddress);
- if (EFI_ERROR (Status)) {
- FirstNonAddress = BASE_4GB + GetSystemMemorySizeAbove4gb ();
- }
-
- //
- // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO
- // resources to 32-bit anyway. See DegradeResource() in
- // "PciResourceSupport.c".
- //
- #ifdef MDE_CPU_IA32
- if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
- return FirstNonAddress;
- }
-
- #endif
-
- //
- // Otherwise, in order to calculate the highest address plus one, we must
- // consider the 64-bit PCI host aperture too. Fetch the default size.
- //
- Pci64Size = PcdGet64 (PcdPciMmio64Size);
-
- //
- // See if the user specified the number of megabytes for the 64-bit PCI host
- // aperture. Accept an aperture size up to 16TB.
- //
- // As signaled by the "X-" prefix, this knob is experimental, and might go
- // away at any time.
- //
- Status = QemuFwCfgParseUint32 (
- "opt/ovmf/X-PciMmio64Mb",
- FALSE,
- &FwCfgPciMmio64Mb
- );
- switch (Status) {
- case EFI_UNSUPPORTED:
- case EFI_NOT_FOUND:
- break;
- case EFI_SUCCESS:
- if (FwCfgPciMmio64Mb <= 0x1000000) {
- Pci64Size = LShiftU64 (FwCfgPciMmio64Mb, 20);
- break;
- }
-
- //
- // fall through
- //
- default:
- DEBUG ((
- DEBUG_WARN,
- "%a: ignoring malformed 64-bit PCI host aperture size from fw_cfg\n",
- __FUNCTION__
- ));
- break;
- }
-
- if (Pci64Size == 0) {
- if (mBootMode != BOOT_ON_S3_RESUME) {
- DEBUG ((
- DEBUG_INFO,
- "%a: disabling 64-bit PCI host aperture\n",
- __FUNCTION__
- ));
- PcdStatus = PcdSet64S (PcdPciMmio64Size, 0);
- ASSERT_RETURN_ERROR (PcdStatus);
- }
-
- //
- // There's nothing more to do; the amount of memory above 4GB fully
- // determines the highest address plus one. The memory hotplug area (see
- // below) plays no role for the firmware in this case.
- //
- return FirstNonAddress;
- }
-
- //
- // The "etc/reserved-memory-end" fw_cfg file, when present, contains an
- // absolute, exclusive end address for the memory hotplug area. This area
- // starts right at the end of the memory above 4GB. The 64-bit PCI host
- // aperture must be placed above it.
- //
- Status = QemuFwCfgFindFile (
- "etc/reserved-memory-end",
- &FwCfgItem,
- &FwCfgSize
- );
- if (!EFI_ERROR (Status) && (FwCfgSize == sizeof HotPlugMemoryEnd)) {
- QemuFwCfgSelectItem (FwCfgItem);
- QemuFwCfgReadBytes (FwCfgSize, &HotPlugMemoryEnd);
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: HotPlugMemoryEnd=0x%Lx\n",
- __FUNCTION__,
- HotPlugMemoryEnd
- ));
-
- ASSERT (HotPlugMemoryEnd >= FirstNonAddress);
- FirstNonAddress = HotPlugMemoryEnd;
- }
-
- //
- // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so
- // that the host can map it with 1GB hugepages. Follow suit.
- //
- Pci64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);
- Pci64Size = ALIGN_VALUE (Pci64Size, (UINT64)SIZE_1GB);
-
- //
- // The 64-bit PCI host aperture should also be "naturally" aligned. The
- // alignment is determined by rounding the size of the aperture down to the
- // next smaller or equal power of two. That is, align the aperture by the
- // largest BAR size that can fit into it.
- //
- Pci64Base = ALIGN_VALUE (Pci64Base, GetPowerOfTwo64 (Pci64Size));
-
- if (mBootMode != BOOT_ON_S3_RESUME) {
- //
- // The core PciHostBridgeDxe driver will automatically add this range to
- // the GCD memory space map through our PciHostBridgeLib instance; here we
- // only need to set the PCDs.
- //
- PcdStatus = PcdSet64S (PcdPciMmio64Base, Pci64Base);
- ASSERT_RETURN_ERROR (PcdStatus);
- PcdStatus = PcdSet64S (PcdPciMmio64Size, Pci64Size);
- ASSERT_RETURN_ERROR (PcdStatus);
-
- DEBUG ((
- DEBUG_INFO,
- "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",
- __FUNCTION__,
- Pci64Base,
- Pci64Size
- ));
- }
-
- //
- // The useful address space ends with the 64-bit PCI host aperture.
- //
- FirstNonAddress = Pci64Base + Pci64Size;
- return FirstNonAddress;
+ mQemuUc32Base = PlatformQemuUc32BaseInitialization (mHostBridgeDevId, mLowerMemorySize);
}
/**
@@ -550,36 +156,19 @@ AddressWidthInitialization (
VOID
)
{
- UINT64 FirstNonAddress;
-
- //
- // As guest-physical memory size grows, the permanent PEI RAM requirements
- // are dominated by the identity-mapping page tables built by the DXE IPL.
- // The DXL IPL keys off of the physical address bits advertized in the CPU
- // HOB. To conserve memory, we calculate the minimum address width here.
- //
- FirstNonAddress = GetFirstNonAddress ();
- mPhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
-
- //
- // If FirstNonAddress is not an integral power of two, then we need an
- // additional bit.
- //
- if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {
- ++mPhysMemAddressWidth;
- }
-
- //
- // The minimum address width is 36 (covers up to and excluding 64 GB, which
- // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
- // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We
- // can simply assert that here, since 48 bits are good enough for 256 TB.
- //
- if (mPhysMemAddressWidth <= 36) {
- mPhysMemAddressWidth = 36;
- }
-
- ASSERT (mPhysMemAddressWidth <= 48);
+ UINT64 Pci64Base;
+ UINT64 Pci64Size;
+ UINT64 FirstNonAddress;
+ RETURN_STATUS PcdStatus;
+
+ Pci64Base = 0;
+ Pci64Size = 0;
+ FirstNonAddress = PlatformGetFirstNonAddress (&Pci64Base, &Pci64Size, PcdGet64 (PcdPciMmio64Size));
+ mPhysMemAddressWidth = PlatformAddressWidthInitialization (FirstNonAddress);
+ PcdStatus = PcdSet64S (PcdPciMmio64Base, Pci64Base);
+ ASSERT_RETURN_ERROR (PcdStatus);
+ PcdStatus = PcdSet64S (PcdPciMmio64Size, Pci64Size);
+ ASSERT_RETURN_ERROR (PcdStatus);
}
/**
@@ -664,7 +253,7 @@ PublishPeiMemory (
UINT32 LowerMemorySize;
UINT32 PeiMemoryCap;
- LowerMemorySize = GetSystemMemorySizeBelow4gb ();
+ LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb ();
if (FeaturePcdGet (PcdSmmSmramRequire)) {
//
// TSEG is chipped from the end of low RAM
@@ -736,162 +325,6 @@ PublishPeiMemory (
return Status;
}
-STATIC
-VOID
-QemuInitializeRamBelow1gb (
- VOID
- )
-{
- if (FeaturePcdGet (PcdSmmSmramRequire) && mQ35SmramAtDefaultSmbase) {
- PlatformAddMemoryRangeHob (0, SMM_DEFAULT_SMBASE);
- PlatformAddReservedMemoryBaseSizeHob (
- SMM_DEFAULT_SMBASE,
- MCH_DEFAULT_SMBASE_SIZE,
- TRUE /* Cacheable */
- );
- STATIC_ASSERT (
- SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE < BASE_512KB + BASE_128KB,
- "end of SMRAM at default SMBASE ends at, or exceeds, 640KB"
- );
- PlatformAddMemoryRangeHob (
- SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE,
- BASE_512KB + BASE_128KB
- );
- } else {
- PlatformAddMemoryRangeHob (0, BASE_512KB + BASE_128KB);
- }
-}
-
-/**
- Peform Memory Detection for QEMU / KVM
-
-**/
-STATIC
-VOID
-QemuInitializeRam (
- VOID
- )
-{
- UINT64 LowerMemorySize;
- UINT64 UpperMemorySize;
- MTRR_SETTINGS MtrrSettings;
- EFI_STATUS Status;
-
- DEBUG ((DEBUG_INFO, "%a called\n", __FUNCTION__));
-
- //
- // Determine total memory size available
- //
- LowerMemorySize = GetSystemMemorySizeBelow4gb ();
-
- if (mBootMode == BOOT_ON_S3_RESUME) {
- //
- // Create the following memory HOB as an exception on the S3 boot path.
- //
- // Normally we'd create memory HOBs only on the normal boot path. However,
- // CpuMpPei specifically needs such a low-memory HOB on the S3 path as
- // well, for "borrowing" a subset of it temporarily, for the AP startup
- // vector.
- //
- // CpuMpPei saves the original contents of the borrowed area in permanent
- // PEI RAM, in a backup buffer allocated with the normal PEI services.
- // CpuMpPei restores the original contents ("returns" the borrowed area) at
- // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before
- // transferring control to the OS's wakeup vector in the FACS.
- //
- // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to
- // restore the original contents. Furthermore, we expect all such PEIMs
- // (CpuMpPei included) to claim the borrowed areas by producing memory
- // allocation HOBs, and to honor preexistent memory allocation HOBs when
- // looking for an area to borrow.
- //
- QemuInitializeRamBelow1gb ();
- } else {
- //
- // Create memory HOBs
- //
- QemuInitializeRamBelow1gb ();
-
- if (FeaturePcdGet (PcdSmmSmramRequire)) {
- UINT32 TsegSize;
-
- TsegSize = mQ35TsegMbytes * SIZE_1MB;
- PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);
- PlatformAddReservedMemoryBaseSizeHob (
- LowerMemorySize - TsegSize,
- TsegSize,
- TRUE
- );
- } else {
- PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize);
- }
-
- //
- // If QEMU presents an E820 map, then create memory HOBs for the >=4GB RAM
- // entries. Otherwise, create a single memory HOB with the flat >=4GB
- // memory size read from the CMOS.
- //
- Status = ScanOrAdd64BitE820Ram (TRUE, NULL, NULL);
- if (EFI_ERROR (Status)) {
- UpperMemorySize = GetSystemMemorySizeAbove4gb ();
- if (UpperMemorySize != 0) {
- PlatformAddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);
- }
- }
- }
-
- //
- // We'd like to keep the following ranges uncached:
- // - [640 KB, 1 MB)
- // - [LowerMemorySize, 4 GB)
- //
- // Everything else should be WB. Unfortunately, programming the inverse (ie.
- // keeping the default UC, and configuring the complement set of the above as
- // WB) is not reliable in general, because the end of the upper RAM can have
- // practically any alignment, and we may not have enough variable MTRRs to
- // cover it exactly.
- //
- if (IsMtrrSupported () && (mHostBridgeDevId != CLOUDHV_DEVICE_ID)) {
- MtrrGetAllMtrrs (&MtrrSettings);
-
- //
- // MTRRs disabled, fixed MTRRs disabled, default type is uncached
- //
- ASSERT ((MtrrSettings.MtrrDefType & BIT11) == 0);
- ASSERT ((MtrrSettings.MtrrDefType & BIT10) == 0);
- ASSERT ((MtrrSettings.MtrrDefType & 0xFF) == 0);
-
- //
- // flip default type to writeback
- //
- SetMem (&MtrrSettings.Fixed, sizeof MtrrSettings.Fixed, 0x06);
- ZeroMem (&MtrrSettings.Variables, sizeof MtrrSettings.Variables);
- MtrrSettings.MtrrDefType |= BIT11 | BIT10 | 6;
- MtrrSetAllMtrrs (&MtrrSettings);
-
- //
- // Set memory range from 640KB to 1MB to uncacheable
- //
- Status = MtrrSetMemoryAttribute (
- BASE_512KB + BASE_128KB,
- BASE_1MB - (BASE_512KB + BASE_128KB),
- CacheUncacheable
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI
- // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable.
- //
- Status = MtrrSetMemoryAttribute (
- mQemuUc32Base,
- SIZE_4GB - mQemuUc32Base,
- CacheUncacheable
- );
- ASSERT_EFI_ERROR (Status);
- }
-}
-
/**
Publish system RAM and reserve memory regions
@@ -901,7 +334,15 @@ InitializeRamRegions (
VOID
)
{
- QemuInitializeRam ();
+ PlatformInitializeRamRegions (
+ mQemuUc32Base,
+ mHostBridgeDevId,
+ FeaturePcdGet (PcdSmmSmramRequire),
+ mBootMode,
+ mS3Supported,
+ mLowerMemorySize,
+ mQ35TsegMbytes
+ );
SevInitializeRam ();
@@ -979,28 +420,6 @@ InitializeRamRegions (
}
if (mBootMode != BOOT_ON_S3_RESUME) {
- if (!FeaturePcdGet (PcdSmmSmramRequire)) {
- //
- // Reserve the lock box storage area
- //
- // Since this memory range will be used on S3 resume, it must be
- // reserved as ACPI NVS.
- //
- // If S3 is unsupported, then various drivers might still write to the
- // LockBox area. We ought to prevent DXE from serving allocation requests
- // such that they would overlap the LockBox storage.
- //
- ZeroMem (
- (VOID *)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageBase),
- (UINTN)PcdGet32 (PcdOvmfLockBoxStorageSize)
- );
- BuildMemoryAllocationHob (
- (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageBase),
- (UINT64)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageSize),
- mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
- );
- }
-
if (FeaturePcdGet (PcdSmmSmramRequire)) {
UINT32 TsegSize;
@@ -1010,7 +429,7 @@ InitializeRamRegions (
//
TsegSize = mQ35TsegMbytes * SIZE_1MB;
BuildMemoryAllocationHob (
- GetSystemMemorySizeBelow4gb () - TsegSize,
+ PlatformGetSystemMemorySizeBelow4gb () - TsegSize,
TsegSize,
EfiReservedMemoryType
);
@@ -1026,26 +445,5 @@ InitializeRamRegions (
);
}
}
-
- #ifdef MDE_CPU_X64
- if (FixedPcdGet32 (PcdOvmfWorkAreaSize) != 0) {
- //
- // Reserve the work area.
- //
- // Since this memory range will be used by the Reset Vector on S3
- // resume, it must be reserved as ACPI NVS.
- //
- // If S3 is unsupported, then various drivers might still write to the
- // work area. We ought to prevent DXE from serving allocation requests
- // such that they would overlap the work area.
- //
- BuildMemoryAllocationHob (
- (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaBase),
- (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaSize),
- mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
- );
- }
-
- #endif
}
}
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 62480c3c40e5..7e98f97c8480 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -57,6 +57,8 @@ BOOLEAN mS3Supported = FALSE;
UINT32 mMaxCpuCount;
+extern UINT32 mLowerMemorySize;
+
VOID
MemMapInitialization (
VOID
@@ -85,7 +87,7 @@ MemMapInitialization (
return;
}
- TopOfLowRam = GetSystemMemorySizeBelow4gb ();
+ TopOfLowRam = PlatformGetSystemMemorySizeBelow4gb ();
PciExBarBase = 0;
if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
//
@@ -736,6 +738,11 @@ InitializePlatform (
Q35SmramAtDefaultSmbaseInitialization ();
}
+ //
+ // Fetch the lower memory size (Below 4G)
+ //
+ mLowerMemorySize = PlatformGetSystemMemorySizeBelow4gb ();
+
PublishPeiMemory ();
QemuUc32BaseInitialization ();
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index f193ff736549..64af9cde1002 100644
--- a/OvmfPkg/PlatformPei/Platform.h
+++ b/OvmfPkg/PlatformPei/Platform.h
@@ -31,11 +31,6 @@ PublishPeiMemory (
VOID
);
-UINT32
-GetSystemMemorySizeBelow4gb (
- VOID
- );
-
VOID
QemuUc32BaseInitialization (
VOID
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* Re: [PATCH V7 19/37] OvmfPkg/PlatformInitLib: Add memory functions
2022-02-28 7:20 ` [PATCH V7 19/37] OvmfPkg/PlatformInitLib: Add memory functions Min Xu
@ 2022-03-01 13:09 ` Gerd Hoffmann
2022-03-02 1:05 ` Min Xu
0 siblings, 1 reply; 72+ messages in thread
From: Gerd Hoffmann @ 2022-03-01 13:09 UTC (permalink / raw)
To: Min Xu
Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky
On Mon, Feb 28, 2022 at 03:20:51PM +0800, Min Xu wrote:
> Below functions are introduced in PlatformInitLib:
> - PlatformGetFirstNonAddress
> - PlatformAddressWidthInitialization
> - PlatformGetSystemMemorySizeBelow4gb
> - PlatformQemuUc32BaseInitialization
> - PlatformInitializeRamRegions
>
> They correspond to the below functions in OvmfPkg/PlatformPei:
> - GetFirstNonAddress
> - AddressWidthInitialization
> - GetSystemMemorySizeBelow4gb
> - QemuUc32BaseInitialization
> - InitializeRamRegions
>
> After that OvmfPkg/PlatformPei is refactored with this library.
>
> Note: PlatformInitLib will not determine whether SMM or S3 is supported
> or not. Instead the caller of these functions should input SMM / S3
> support as the IN parameter by themselves. This is to reduce the
> complexity of PlatformInitLib. Another reason is that some PCDs cannot
> be declared as FixedAtBuild while PlatformInitLib is designed to be used
> in both SEC and PEI phase.
Hmm. Unlike patches 17+18 which are pure code motion (except the
function renaming but that doesn't change the workflow) this patch
mixes code changes and code moving which makes it hard to review.
It should be splitted into one (or more) patches changing the functions
as needed (and keeping the code in PlatformPei), and one patch moving
things over to PlatformInitLib without functional changes.
> +PlatformGetFirstNonAddress (
> + OUT UINT64 *Pci64Base,
> + OUT UINT64 *Pci64Size,
> + IN UINT64 DefaultPciMmio64Size
> + )
> +VOID
> +QemuInitializeRam (
> + UINT32 Uc32Base,
> + UINT16 HostBridgeDevId,
> + EFI_BOOT_MODE BootMode,
> + BOOLEAN SmmSmramRequire,
> + UINT32 LowerMemorySize,
> + UINT16 Q35TsegMbytes
> + )
> +VOID
> +EFIAPI
> +PlatformInitializeRamRegions (
> + IN UINT32 Uc32Base,
> + IN UINT16 HostBridgeDevId,
> + IN BOOLEAN SmmSmramRequire,
> + IN EFI_BOOT_MODE BootMode,
> + IN BOOLEAN S3Supported,
> + IN UINT32 LowerMemorySize,
> + IN UINT16 Q35TsegMbytes
> + )
I think we should add all those parameters to the PLATFORM_INFO struct,
then simply pass around a pointer to that struct instead of having tons
of parameters for each function.
Due to this patch needing an update anyway it might be easier to do it
right away instead of an incremental cleanup after merging this series.
> @@ -85,7 +87,7 @@ MemMapInitialization (
> return;
> }
>
> - TopOfLowRam = GetSystemMemorySizeBelow4gb ();
> + TopOfLowRam = PlatformGetSystemMemorySizeBelow4gb ();
> PciExBarBase = 0;
> if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
> //
> @@ -736,6 +738,11 @@ InitializePlatform (
> Q35SmramAtDefaultSmbaseInitialization ();
> }
>
> + //
> + // Fetch the lower memory size (Below 4G)
> + //
> + mLowerMemorySize = PlatformGetSystemMemorySizeBelow4gb ();
Can't you just use TopOfLowRam here?
take care,
Gerd
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH V7 19/37] OvmfPkg/PlatformInitLib: Add memory functions
2022-03-01 13:09 ` Gerd Hoffmann
@ 2022-03-02 1:05 ` Min Xu
2022-03-02 6:56 ` [edk2-devel] " Gerd Hoffmann
0 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-03-02 1:05 UTC (permalink / raw)
To: Gerd Hoffmann
Cc: devel@edk2.groups.io, Ard Biesheuvel, Justen, Jordan L,
Brijesh Singh, Aktas, Erdem, James Bottomley, Yao, Jiewen,
Tom Lendacky
On March 1, 2022 9:10 PM, Gerd Hoffmann wrote:
> On Mon, Feb 28, 2022 at 03:20:51PM +0800, Min Xu wrote:
> > Below functions are introduced in PlatformInitLib:
> > - PlatformGetFirstNonAddress
> > - PlatformAddressWidthInitialization
> > - PlatformGetSystemMemorySizeBelow4gb
> > - PlatformQemuUc32BaseInitialization
> > - PlatformInitializeRamRegions
> >
> > They correspond to the below functions in OvmfPkg/PlatformPei:
> > - GetFirstNonAddress
> > - AddressWidthInitialization
> > - GetSystemMemorySizeBelow4gb
> > - QemuUc32BaseInitialization
> > - InitializeRamRegions
> >
> > After that OvmfPkg/PlatformPei is refactored with this library.
> >
> > Note: PlatformInitLib will not determine whether SMM or S3 is
> > supported or not. Instead the caller of these functions should input
> > SMM / S3 support as the IN parameter by themselves. This is to reduce
> > the complexity of PlatformInitLib. Another reason is that some PCDs
> > cannot be declared as FixedAtBuild while PlatformInitLib is designed
> > to be used in both SEC and PEI phase.
>
> Hmm. Unlike patches 17+18 which are pure code motion (except the
> function renaming but that doesn't change the workflow) this patch mixes
> code changes and code moving which makes it hard to review.
>
> It should be splitted into one (or more) patches changing the functions as
> needed (and keeping the code in PlatformPei), and one patch moving things
> over to PlatformInitLib without functional changes.
Ok. Looks like #21 & #22 in tdvf_wave2.v6?
https://github.com/mxu9/edk2/commit/ef0615ca5665b2058e4352a322dfa74d258f9f31
https://github.com/mxu9/edk2/commit/25f356a0bf7ee347be30e270aeffe6cbd8e0b464
>
> > +PlatformGetFirstNonAddress (
> > + OUT UINT64 *Pci64Base,
> > + OUT UINT64 *Pci64Size,
> > + IN UINT64 DefaultPciMmio64Size
> > + )
>
> > +VOID
> > +QemuInitializeRam (
> > + UINT32 Uc32Base,
> > + UINT16 HostBridgeDevId,
> > + EFI_BOOT_MODE BootMode,
> > + BOOLEAN SmmSmramRequire,
> > + UINT32 LowerMemorySize,
> > + UINT16 Q35TsegMbytes
> > + )
>
> > +VOID
> > +EFIAPI
> > +PlatformInitializeRamRegions (
> > + IN UINT32 Uc32Base,
> > + IN UINT16 HostBridgeDevId,
> > + IN BOOLEAN SmmSmramRequire,
> > + IN EFI_BOOT_MODE BootMode,
> > + IN BOOLEAN S3Supported,
> > + IN UINT32 LowerMemorySize,
> > + IN UINT16 Q35TsegMbytes
> > + )
>
> I think we should add all those parameters to the PLATFORM_INFO struct,
> then simply pass around a pointer to that struct instead of having tons of
> parameters for each function.
Ok. It will be updated in the next version.
>
> Due to this patch needing an update anyway it might be easier to do it right
> away instead of an incremental cleanup after merging this series.
>
> > @@ -85,7 +87,7 @@ MemMapInitialization (
> > return;
> > }
> >
> > - TopOfLowRam = GetSystemMemorySizeBelow4gb ();
> > + TopOfLowRam = PlatformGetSystemMemorySizeBelow4gb ();
This is in function MemMapInitialization().
> > PciExBarBase = 0;
> > if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
> > //
> > @@ -736,6 +738,11 @@ InitializePlatform (
> > Q35SmramAtDefaultSmbaseInitialization ();
> > }
> >
> > + //
> > + // Fetch the lower memory size (Below 4G) // mLowerMemorySize =
> > + PlatformGetSystemMemorySizeBelow4gb ();
This is in function InitializePlatform().
>
> Can't you just use TopOfLowRam here?
TopOfLowRam is a local variable in function MemMapInitialization(). It cannot be used in function InitialziePlatform().
Thanks
Min
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 19/37] OvmfPkg/PlatformInitLib: Add memory functions
2022-03-02 1:05 ` Min Xu
@ 2022-03-02 6:56 ` Gerd Hoffmann
2022-03-08 2:39 ` Min Xu
0 siblings, 1 reply; 72+ messages in thread
From: Gerd Hoffmann @ 2022-03-02 6:56 UTC (permalink / raw)
To: devel, min.m.xu
Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Aktas, Erdem,
James Bottomley, Yao, Jiewen, Tom Lendacky
Hi,
> > Hmm. Unlike patches 17+18 which are pure code motion (except the
> > function renaming but that doesn't change the workflow) this patch mixes
> > code changes and code moving which makes it hard to review.
> >
> > It should be splitted into one (or more) patches changing the functions as
> > needed (and keeping the code in PlatformPei), and one patch moving things
> > over to PlatformInitLib without functional changes.
> Ok. Looks like #21 & #22 in tdvf_wave2.v6?
> https://github.com/mxu9/edk2/commit/ef0615ca5665b2058e4352a322dfa74d258f9f31
> https://github.com/mxu9/edk2/commit/25f356a0bf7ee347be30e270aeffe6cbd8e0b464
No. The idea is to changes to the code in PlatformPei with small &
one-patch-per-update patches, which allow easy review. Also helps
debugging in case something go wrong, when bisecting found the broken
patch it's *much* easier to find the actual bug when the patch is small.
Rough plan:
(1) a patch allocating PLATFORM_INFO struct in PlatformPei.
(2) one or more patches moving global variables into PLATFORM_INFO
struct.
(3) one or more patches restructing functions. Stuff like like
splitting functions which set PCDs into two, one for
PlatformInitLib and one for PlatformPei.
Final step is a pure move from PlatformPei to PlatformInitLib without
changing code.
> > > + // Fetch the lower memory size (Below 4G) // mLowerMemorySize =
> > > + PlatformGetSystemMemorySizeBelow4gb ();
> This is in function InitializePlatform().
> >
> > Can't you just use TopOfLowRam here?
> TopOfLowRam is a local variable in function MemMapInitialization(). It cannot be used in function InitialziePlatform().
Ah, didn't notice it is another function. High time to introduce
PLATFORM_INFO->TopOfLowRam ;)
take care,
Gerd
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 19/37] OvmfPkg/PlatformInitLib: Add memory functions
2022-03-02 6:56 ` [edk2-devel] " Gerd Hoffmann
@ 2022-03-08 2:39 ` Min Xu
0 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-03-08 2:39 UTC (permalink / raw)
To: Gerd Hoffmann, devel@edk2.groups.io
Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Aktas, Erdem,
James Bottomley, Yao, Jiewen, Tom Lendacky
On March 2, 2022 2:57 PM, Gerd Hoffmann wrote:
> Hi,
>
> > > Hmm. Unlike patches 17+18 which are pure code motion (except the
> > > function renaming but that doesn't change the workflow) this patch
> > > mixes code changes and code moving which makes it hard to review.
> > >
> > > It should be splitted into one (or more) patches changing the
> > > functions as needed (and keeping the code in PlatformPei), and one
> > > patch moving things over to PlatformInitLib without functional changes.
> > Ok. Looks like #21 & #22 in tdvf_wave2.v6?
> >
> https://github.com/mxu9/edk2/commit/ef0615ca5665b2058e4352a322dfa74
> d25
> > 8f9f31
> >
> https://github.com/mxu9/edk2/commit/25f356a0bf7ee347be30e270aeffe6cb
> d8
> > e0b464
>
> No. The idea is to changes to the code in PlatformPei with small & one-patch-
> per-update patches, which allow easy review. Also helps debugging in case
> something go wrong, when bisecting found the broken patch it's *much*
> easier to find the actual bug when the patch is small.
>
> Rough plan:
>
> (1) a patch allocating PLATFORM_INFO struct in PlatformPei.
> (2) one or more patches moving global variables into PLATFORM_INFO
> struct.
> (3) one or more patches restructing functions. Stuff like like
> splitting functions which set PCDs into two, one for
> PlatformInitLib and one for PlatformPei.
>
> Final step is a pure move from PlatformPei to PlatformInitLib without changing
> code.
>
Thanks for the suggestion. I have created a separated patch-set for PlatformInitLib.
https://edk2.groups.io/g/devel/message/87327
Thanks
Min
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH V7 20/37] OvmfPkg/PlatformInitLib: Add platform functions
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (18 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 19/37] OvmfPkg/PlatformInitLib: Add memory functions Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 21/37] OvmfPkg: Update PlatformInitLib to process Tdx hoblist Min Xu
` (17 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
Below platform functions are introducted in PlatformInitLib:
- PlatformMaxCpuCountInitialization
- PlatformMemMapInitialization
- PlatformNoexecDxeInitialization
- PlatformMiscInitialization
They correspond to the below functions in OvmfPkg/PlatformPei:
- MaxCpuCountInitialization
- MemMapInitialization
- MiscInitialization
- NoexecDxeInitialization
QueryHostBridgeDid is a newly added function.
After that OvmfPkg/PlatformPei is refactored with this library.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Include/Library/PlatformInitLib.h | 75 +++
OvmfPkg/Library/PlatformInitLib/Platform.c | 491 ++++++++++++++++++
.../PlatformInitLib/PlatformInitLib.inf | 29 ++
OvmfPkg/PlatformPei/Platform.c | 391 ++------------
4 files changed, 628 insertions(+), 358 deletions(-)
diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
index df2646880909..dd108b3a4339 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -118,6 +118,81 @@ PlatformQemuUc32BaseInitialization (
IN UINT32 LowerMemorySize
);
+/**
+ * Query Host Bridge Dev Id.
+ *
+ * @return Host Bridge Dev Id.
+ */
+UINT16
+EFIAPI
+PlatformQueryHostBridgeDid (
+ VOID
+ );
+
+/**
+ Fetch the boot CPU count and the possible CPU count from QEMU.
+
+ @param HostBridgeDevId The Host bridge Dev Id.
+ @param DefaultMaxCpuCount The default max cpu count.
+ @param MaxCpuCount The pointer to the returned max cpu count.
+ @param BootCpuCount The pointer to the returned boot cpu count.
+**/
+VOID
+EFIAPI
+PlatformMaxCpuCountInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT32 DefaultMaxCpuCount,
+ OUT UINT32 *MaxCpuCount,
+ OUT UINT16 *BootCpuCount
+ );
+
+/**
+ * Initialize the Memory Map IO hobs.
+ *
+ * @param HostBridgeDevId The host bridge Dev Id.
+ * @param Uc32Base The Qemu Uc32Base address.
+ * @param PciBase The pointer to the Pci base address.
+ * @param PciSize The pointer to the Pci base size.
+ * @param PciIoBase The pointer to the Pci Io base address.
+ * @param PciIoSize The pointer to the Pci Io size.
+ */
+VOID
+EFIAPI
+PlatformMemMapInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT32 Uc32Base,
+ OUT UINT32 *PciBase,
+ OUT UINT32 *PciSize,
+ OUT UINT64 *PciIoBase,
+ OUT UINT64 *PciIoSize
+ );
+
+/**
+ * Fetch "opt/ovmf/PcdSetNxForStack" from QEMU
+ *
+ * @param Setting The pointer to the setting of "/opt/ovmf/PcdSetNxForStack".
+ * @return EFI_SUCCESS Successfully fetch the settings.
+ */
+EFI_STATUS
+EFIAPI
+PlatformNoexecDxeInitialization (
+ OUT BOOLEAN *Setting
+ );
+
+/**
+ * Misc initialization, such as Disable A20 Mask, Build CPU Hob,
+ * PM settings, Set PCI Express Register Range Base Address.
+ *
+ * @param HostBridgeDevId The host bridge Dev id.
+ * @param PhysMemAddressWidth The physical memory address width.
+ */
+VOID
+EFIAPI
+PlatformMiscInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT8 PhysMemAddressWidth
+ );
+
/**
Publish system RAM and reserve memory regions.
diff --git a/OvmfPkg/Library/PlatformInitLib/Platform.c b/OvmfPkg/Library/PlatformInitLib/Platform.c
index e41f230ff563..308a64f6558b 100644
--- a/OvmfPkg/Library/PlatformInitLib/Platform.c
+++ b/OvmfPkg/Library/PlatformInitLib/Platform.c
@@ -19,6 +19,21 @@
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/QemuFwCfgS3Lib.h>
+#include <Library/QemuFwCfgSimpleParserLib.h>
+#include <Library/ResourcePublicationLib.h>
+#include <Ppi/MasterBootMode.h>
+#include <IndustryStandard/I440FxPiix4.h>
+#include <IndustryStandard/Microvm.h>
+#include <IndustryStandard/Pci22.h>
+#include <IndustryStandard/Q35MchIch9.h>
+#include <IndustryStandard/QemuCpuHotplug.h>
+#include <OvmfPlatforms.h>
#include <Library/PlatformInitLib.h>
VOID
@@ -104,3 +119,479 @@ PlatformAddMemoryRangeHob (
{
PlatformAddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
}
+
+/**
+ * Initialize the Memory Map IO hobs.
+ *
+ * @param HostBridgeDevId The host bridge Dev Id.
+ * @param Uc32Base The Qemu Uc32Base address.
+ * @param PciBase The pointer to the Pci base address.
+ * @param PciSize The pointer to the Pci base size.
+ * @param PciIoBase The pointer to the Pci Io base address.
+ * @param PciIoSize The pointer to the Pci Io size.
+ */
+VOID
+EFIAPI
+PlatformMemMapInitialization (
+ UINT16 HostBridgeDevId,
+ UINT32 Uc32Base,
+ UINT32 *PciBase,
+ UINT32 *PciSize,
+ UINT64 *PciIoBase,
+ UINT64 *PciIoSize
+ )
+{
+ UINT32 TopOfLowRam;
+ UINT64 PciExBarBase;
+
+ *PciIoBase = 0xC000;
+ *PciIoSize = 0x4000;
+ *PciBase = 0;
+ *PciSize = 0;
+
+ //
+ // Video memory + Legacy BIOS region
+ //
+ PlatformAddIoMemoryRangeHob (0x0A0000, BASE_1MB);
+
+ if (HostBridgeDevId == 0xffff /* microvm */) {
+ PlatformAddIoMemoryBaseSizeHob (MICROVM_GED_MMIO_BASE, SIZE_4KB);
+ PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); /* ioapic #1 */
+ PlatformAddIoMemoryBaseSizeHob (0xFEC10000, SIZE_4KB); /* ioapic #2 */
+ return;
+ }
+
+ TopOfLowRam = PlatformGetSystemMemorySizeBelow4gb ();
+ PciExBarBase = 0;
+ if (HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+ //
+ // The MMCONFIG area is expected to fall between the top of low RAM and
+ // the base of the 32-bit PCI host aperture.
+ //
+ PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);
+ ASSERT (TopOfLowRam <= PciExBarBase);
+ ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);
+ *PciBase = (UINT32)(PciExBarBase + SIZE_256MB);
+ } else {
+ ASSERT (TopOfLowRam <= Uc32Base);
+ *PciBase = Uc32Base;
+ }
+
+ //
+ // address purpose size
+ // ------------ -------- -------------------------
+ // max(top, 2g) PCI MMIO 0xFC000000 - max(top, 2g)
+ // 0xFC000000 gap 44 MB
+ // 0xFEC00000 IO-APIC 4 KB
+ // 0xFEC01000 gap 1020 KB
+ // 0xFED00000 HPET 1 KB
+ // 0xFED00400 gap 111 KB
+ // 0xFED1C000 gap (PIIX4) / RCRB (ICH9) 16 KB
+ // 0xFED20000 gap 896 KB
+ // 0xFEE00000 LAPIC 1 MB
+ //
+ *PciSize = 0xFC000000 - *PciBase;
+ PlatformAddIoMemoryBaseSizeHob (*PciBase, *PciSize);
+
+ PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
+ PlatformAddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
+ if (HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+ PlatformAddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
+ //
+ // Note: there should be an
+ //
+ // AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
+ //
+ // call below, just like the one above for RCBA. However, Linux insists
+ // that the MMCONFIG area be marked in the E820 or UEFI memory map as
+ // "reserved memory" -- Linux does not content itself with a simple gap
+ // in the memory map wherever the MCFG ACPI table points to.
+ //
+ // This appears to be a safety measure. The PCI Firmware Specification
+ // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can
+ // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory
+ // [...]". (Emphasis added here.)
+ //
+ // Normally we add memory resource descriptor HOBs in
+ // QemuInitializeRam(), and pre-allocate from those with memory
+ // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area
+ // is most definitely not RAM; so, as an exception, cover it with
+ // uncacheable reserved memory right here.
+ //
+ PlatformAddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
+ BuildMemoryAllocationHob (
+ PciExBarBase,
+ SIZE_256MB,
+ EfiReservedMemoryType
+ );
+ }
+
+ PlatformAddIoMemoryBaseSizeHob (FixedPcdGet32 (PcdCpuLocalApicBaseAddress), SIZE_1MB);
+
+ //
+ // On Q35, the IO Port space is available for PCI resource allocations from
+ // 0x6000 up.
+ //
+ if (HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+ *PciIoBase = 0x6000;
+ *PciIoSize = 0xA000;
+ ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < *PciIoBase);
+ }
+
+ //
+ // Add PCI IO Port space available for PCI resource allocations.
+ //
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_IO,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
+ *PciIoBase,
+ *PciIoSize
+ );
+}
+
+/**
+ * Fetch "opt/ovmf/PcdSetNxForStack" from QEMU
+ *
+ * @param Setting The pointer to the setting of "/opt/ovmf/PcdSetNxForStack".
+ * @return EFI_SUCCESS Successfully fetch the settings.
+ */
+EFI_STATUS
+EFIAPI
+PlatformNoexecDxeInitialization (
+ OUT BOOLEAN *Setting
+ )
+{
+ return QemuFwCfgParseBool ("opt/ovmf/PcdSetNxForStack", Setting);
+}
+
+VOID
+PciExBarInitialization (
+ VOID
+ )
+{
+ union {
+ UINT64 Uint64;
+ UINT32 Uint32[2];
+ } PciExBarBase;
+
+ //
+ // We only support the 256MB size for the MMCONFIG area:
+ // 256 buses * 32 devices * 8 functions * 4096 bytes config space.
+ //
+ // The masks used below enforce the Q35 requirements that the MMCONFIG area
+ // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.
+ //
+ // Note that (b) also ensures that the minimum address width we have
+ // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice
+ // for DXE's page tables to cover the MMCONFIG area.
+ //
+ PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);
+ ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);
+ ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);
+
+ //
+ // Clear the PCIEXBAREN bit first, before programming the high register.
+ //
+ PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);
+
+ //
+ // Program the high register. Then program the low register, setting the
+ // MMCONFIG area size and enabling decoding at once.
+ //
+ PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);
+ PciWrite32 (
+ DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),
+ PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN
+ );
+}
+
+/**
+ * Misc initialization, such as Disable A20 Mask, Build CPU Hob,
+ * PM settings, Set PCI Express Register Range Base Address.
+ *
+ * @param HostBridgeDevId The host bridge Dev id.
+ * @param PhysMemAddressWidth The physical memory address width.
+ */
+VOID
+EFIAPI
+PlatformMiscInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT8 PhysMemAddressWidth
+ )
+{
+ UINTN PmCmd;
+ UINTN Pmba;
+ UINT32 PmbaAndVal;
+ UINT32 PmbaOrVal;
+ UINTN AcpiCtlReg;
+ UINT8 AcpiEnBit;
+
+ //
+ // Disable A20 Mask
+ //
+ IoOr8 (0x92, BIT1);
+
+ //
+ // Build the CPU HOB with guest RAM size dependent address width and 16-bits
+ // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during
+ // S3 resume as well, so we build it unconditionally.)
+ //
+ BuildCpuHob (PhysMemAddressWidth, 16);
+
+ //
+ // Determine platform type and save Host Bridge DID to PCD
+ //
+ switch (HostBridgeDevId) {
+ case INTEL_82441_DEVICE_ID:
+ PmCmd = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);
+ Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
+ PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;
+ PmbaOrVal = PIIX4_PMBA_VALUE;
+ AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);
+ AcpiEnBit = PIIX4_PMREGMISC_PMIOSE;
+ break;
+ case INTEL_Q35_MCH_DEVICE_ID:
+ PmCmd = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);
+ Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
+ PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;
+ PmbaOrVal = ICH9_PMBASE_VALUE;
+ AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);
+ AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN;
+ break;
+ default:
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Unknown Host Bridge Device ID: 0x%04x\n",
+ __FUNCTION__,
+ HostBridgeDevId
+ ));
+ ASSERT (FALSE);
+ return;
+ }
+
+ //
+ // If the appropriate IOspace enable bit is set, assume the ACPI PMBA has
+ // been configured and skip the setup here. This matches the logic in
+ // AcpiTimerLibConstructor ().
+ //
+ if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
+ //
+ // The PEI phase should be exited with fully accessibe ACPI PM IO space:
+ // 1. set PMBA
+ //
+ PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);
+
+ //
+ // 2. set PCICMD/IOSE
+ //
+ PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);
+
+ //
+ // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)
+ //
+ PciOr8 (AcpiCtlReg, AcpiEnBit);
+ }
+
+ if (HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+ //
+ // Set Root Complex Register Block BAR
+ //
+ PciWrite32 (
+ POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
+ ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
+ );
+
+ //
+ // Set PCI Express Register Range Base Address
+ //
+ PciExBarInitialization ();
+ }
+}
+
+/**
+ Fetch the boot CPU count and the possible CPU count from QEMU.
+
+ @param HostBridgeDevId The Host bridge Dev Id.
+ @param DefaultMaxCpuCount The default max cpu count.
+ @param MaxCpuCount The pointer to the returned max cpu count.
+ @param BootCpuCount The pointer to the returned boot cpu count.
+**/
+VOID
+EFIAPI
+PlatformMaxCpuCountInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT32 DefaultMaxCpuCount,
+ OUT UINT32 *MaxCpuCount,
+ OUT UINT16 *BootCpuCount
+ )
+{
+ //
+ // Try to fetch the boot CPU count.
+ //
+ QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
+ *BootCpuCount = QemuFwCfgRead16 ();
+ if (*BootCpuCount == 0) {
+ //
+ // QEMU doesn't report the boot CPU count. (BootCpuCount == 0) will let
+ // MpInitLib count APs up to (PcdCpuMaxLogicalProcessorNumber - 1), or
+ // until PcdCpuApInitTimeOutInMicroSeconds elapses (whichever is reached
+ // first).
+ //
+ DEBUG ((DEBUG_WARN, "%a: boot CPU count unavailable\n", __FUNCTION__));
+ *MaxCpuCount = DefaultMaxCpuCount;
+ } else {
+ //
+ // We will expose BootCpuCount to MpInitLib. MpInitLib will count APs up to
+ // (BootCpuCount - 1) precisely, regardless of timeout.
+ //
+ // Now try to fetch the possible CPU count.
+ //
+ UINTN CpuHpBase;
+ UINT32 CmdData2;
+
+ CpuHpBase = ((HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) ?
+ ICH9_CPU_HOTPLUG_BASE : PIIX4_CPU_HOTPLUG_BASE);
+
+ //
+ // If only legacy mode is available in the CPU hotplug register block, or
+ // the register block is completely missing, then the writes below are
+ // no-ops.
+ //
+ // 1. Switch the hotplug register block to modern mode.
+ //
+ IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0);
+ //
+ // 2. Select a valid CPU for deterministic reading of
+ // QEMU_CPUHP_R_CMD_DATA2.
+ //
+ // CPU#0 is always valid; it is the always present and non-removable
+ // BSP.
+ //
+ IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0);
+ //
+ // 3. Send a command after which QEMU_CPUHP_R_CMD_DATA2 is specified to
+ // read as zero, and which does not invalidate the selector. (The
+ // selector may change, but it must not become invalid.)
+ //
+ // Send QEMU_CPUHP_CMD_GET_PENDING, as it will prove useful later.
+ //
+ IoWrite8 (CpuHpBase + QEMU_CPUHP_W_CMD, QEMU_CPUHP_CMD_GET_PENDING);
+ //
+ // 4. Read QEMU_CPUHP_R_CMD_DATA2.
+ //
+ // If the register block is entirely missing, then this is an unassigned
+ // IO read, returning all-bits-one.
+ //
+ // If only legacy mode is available, then bit#0 stands for CPU#0 in the
+ // "CPU present bitmap". CPU#0 is always present.
+ //
+ // Otherwise, QEMU_CPUHP_R_CMD_DATA2 is either still reserved (returning
+ // all-bits-zero), or it is specified to read as zero after the above
+ // steps. Both cases confirm modern mode.
+ //
+ CmdData2 = IoRead32 (CpuHpBase + QEMU_CPUHP_R_CMD_DATA2);
+ DEBUG ((DEBUG_VERBOSE, "%a: CmdData2=0x%x\n", __FUNCTION__, CmdData2));
+ if (CmdData2 != 0) {
+ //
+ // QEMU doesn't support the modern CPU hotplug interface. Assume that the
+ // possible CPU count equals the boot CPU count (precluding hotplug).
+ //
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: modern CPU hotplug interface unavailable\n",
+ __FUNCTION__
+ ));
+ *MaxCpuCount = *BootCpuCount;
+ } else {
+ //
+ // Grab the possible CPU count from the modern CPU hotplug interface.
+ //
+ UINT32 Present, Possible, Selected;
+
+ Present = 0;
+ Possible = 0;
+
+ //
+ // We've sent QEMU_CPUHP_CMD_GET_PENDING last; this ensures
+ // QEMU_CPUHP_RW_CMD_DATA can now be read usefully. However,
+ // QEMU_CPUHP_CMD_GET_PENDING may have selected a CPU with actual pending
+ // hotplug events; therefore, select CPU#0 forcibly.
+ //
+ IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible);
+
+ do {
+ UINT8 CpuStatus;
+
+ //
+ // Read the status of the currently selected CPU. This will help with a
+ // sanity check against "BootCpuCount".
+ //
+ CpuStatus = IoRead8 (CpuHpBase + QEMU_CPUHP_R_CPU_STAT);
+ if ((CpuStatus & QEMU_CPUHP_STAT_ENABLED) != 0) {
+ ++Present;
+ }
+
+ //
+ // Attempt to select the next CPU.
+ //
+ ++Possible;
+ IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible);
+ //
+ // If the selection is successful, then the following read will return
+ // the selector (which we know is positive at this point). Otherwise,
+ // the read will return 0.
+ //
+ Selected = IoRead32 (CpuHpBase + QEMU_CPUHP_RW_CMD_DATA);
+ ASSERT (Selected == Possible || Selected == 0);
+ } while (Selected > 0);
+
+ //
+ // Sanity check: fw_cfg and the modern CPU hotplug interface should
+ // return the same boot CPU count.
+ //
+ if (*BootCpuCount != Present) {
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: QEMU v2.7 reset bug: BootCpuCount=%d "
+ "Present=%u\n",
+ __FUNCTION__,
+ *BootCpuCount,
+ Present
+ ));
+ //
+ // The handling of QemuFwCfgItemSmpCpuCount, across CPU hotplug plus
+ // platform reset (including S3), was corrected in QEMU commit
+ // e3cadac073a9 ("pc: fix FW_CFG_NB_CPUS to account for -device added
+ // CPUs", 2016-11-16), part of release v2.8.0.
+ //
+ *BootCpuCount = (UINT16)Present;
+ }
+
+ *MaxCpuCount = Possible;
+ }
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: BootCpuCount=%d MaxCpuCount=%u\n",
+ __FUNCTION__,
+ *BootCpuCount,
+ *MaxCpuCount
+ ));
+ ASSERT (*BootCpuCount <= *MaxCpuCount);
+}
+
+/**
+ * Query Host Bridge Dev Id.
+ *
+ * @return Host Bridge Dev Id.
+ */
+UINT16
+EFIAPI
+PlatformQueryHostBridgeDid (
+ VOID
+ )
+{
+ return PciRead16 (OVMF_HOSTBRIDGE_DID);
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
index 6ba1e59246d1..a42b54805ba6 100644
--- a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -28,6 +28,7 @@
Platform.c
[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
OvmfPkg/OvmfPkg.dec
@@ -42,6 +43,7 @@
QemuFwCfgSimpleParserLib
MtrrLib
PcdLib
+ PciLib
[FixedPcd]
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
@@ -50,5 +52,32 @@
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
+
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
+
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
+
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
+
[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 7e98f97c8480..5f175bf7014d 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -67,117 +67,19 @@ MemMapInitialization (
UINT64 PciIoBase;
UINT64 PciIoSize;
RETURN_STATUS PcdStatus;
- UINT32 TopOfLowRam;
- UINT64 PciExBarBase;
UINT32 PciBase;
UINT32 PciSize;
- PciIoBase = 0xC000;
- PciIoSize = 0x4000;
-
- //
- // Video memory + Legacy BIOS region
- //
- PlatformAddIoMemoryRangeHob (0x0A0000, BASE_1MB);
-
+ PlatformMemMapInitialization (mHostBridgeDevId, mQemuUc32Base, &PciBase, &PciSize, &PciIoBase, &PciIoSize);
if (mHostBridgeDevId == 0xffff /* microvm */) {
- PlatformAddIoMemoryBaseSizeHob (MICROVM_GED_MMIO_BASE, SIZE_4KB);
- PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); /* ioapic #1 */
- PlatformAddIoMemoryBaseSizeHob (0xFEC10000, SIZE_4KB); /* ioapic #2 */
return;
}
- TopOfLowRam = PlatformGetSystemMemorySizeBelow4gb ();
- PciExBarBase = 0;
- if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
- //
- // The MMCONFIG area is expected to fall between the top of low RAM and
- // the base of the 32-bit PCI host aperture.
- //
- PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);
- ASSERT (TopOfLowRam <= PciExBarBase);
- ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);
- PciBase = (UINT32)(PciExBarBase + SIZE_256MB);
- } else {
- ASSERT (TopOfLowRam <= mQemuUc32Base);
- PciBase = mQemuUc32Base;
- }
-
- //
- // address purpose size
- // ------------ -------- -------------------------
- // max(top, 2g) PCI MMIO 0xFC000000 - max(top, 2g)
- // 0xFC000000 gap 44 MB
- // 0xFEC00000 IO-APIC 4 KB
- // 0xFEC01000 gap 1020 KB
- // 0xFED00000 HPET 1 KB
- // 0xFED00400 gap 111 KB
- // 0xFED1C000 gap (PIIX4) / RCRB (ICH9) 16 KB
- // 0xFED20000 gap 896 KB
- // 0xFEE00000 LAPIC 1 MB
- //
- PciSize = 0xFC000000 - PciBase;
- PlatformAddIoMemoryBaseSizeHob (PciBase, PciSize);
PcdStatus = PcdSet64S (PcdPciMmio32Base, PciBase);
ASSERT_RETURN_ERROR (PcdStatus);
PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize);
ASSERT_RETURN_ERROR (PcdStatus);
- PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
- PlatformAddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
- if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
- PlatformAddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
- //
- // Note: there should be an
- //
- // PlatformAddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
- //
- // call below, just like the one above for RCBA. However, Linux insists
- // that the MMCONFIG area be marked in the E820 or UEFI memory map as
- // "reserved memory" -- Linux does not content itself with a simple gap
- // in the memory map wherever the MCFG ACPI table points to.
- //
- // This appears to be a safety measure. The PCI Firmware Specification
- // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can
- // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory
- // [...]". (Emphasis added here.)
- //
- // Normally we add memory resource descriptor HOBs in
- // QemuInitializeRam(), and pre-allocate from those with memory
- // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area
- // is most definitely not RAM; so, as an exception, cover it with
- // uncacheable reserved memory right here.
- //
- PlatformAddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
- BuildMemoryAllocationHob (
- PciExBarBase,
- SIZE_256MB,
- EfiReservedMemoryType
- );
- }
-
- PlatformAddIoMemoryBaseSizeHob (PcdGet32 (PcdCpuLocalApicBaseAddress), SIZE_1MB);
-
- //
- // On Q35, the IO Port space is available for PCI resource allocations from
- // 0x6000 up.
- //
- if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
- PciIoBase = 0x6000;
- PciIoSize = 0xA000;
- ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < PciIoBase);
- }
-
- //
- // Add PCI IO Port space available for PCI resource allocations.
- //
- BuildResourceDescriptorHob (
- EFI_RESOURCE_IO,
- EFI_RESOURCE_ATTRIBUTE_PRESENT |
- EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
- PciIoBase,
- PciIoSize
- );
PcdStatus = PcdSet64S (PcdPciIoBase, PciIoBase);
ASSERT_RETURN_ERROR (PcdStatus);
PcdStatus = PcdSet64S (PcdPciIoSize, PciIoSize);
@@ -204,47 +106,6 @@ NoexecDxeInitialization (
UPDATE_BOOLEAN_PCD_FROM_FW_CFG (PcdSetNxForStack);
}
-VOID
-PciExBarInitialization (
- VOID
- )
-{
- union {
- UINT64 Uint64;
- UINT32 Uint32[2];
- } PciExBarBase;
-
- //
- // We only support the 256MB size for the MMCONFIG area:
- // 256 buses * 32 devices * 8 functions * 4096 bytes config space.
- //
- // The masks used below enforce the Q35 requirements that the MMCONFIG area
- // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.
- //
- // Note that (b) also ensures that the minimum address width we have
- // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice
- // for DXE's page tables to cover the MMCONFIG area.
- //
- PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);
- ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);
- ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);
-
- //
- // Clear the PCIEXBAREN bit first, before programming the high register.
- //
- PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);
-
- //
- // Program the high register. Then program the low register, setting the
- // MMCONFIG area size and enabling decoding at once.
- //
- PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);
- PciWrite32 (
- DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),
- PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN
- );
-}
-
static const UINT8 EmptyFdt[] = {
0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x48,
0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x48,
@@ -306,19 +167,23 @@ MicrovmInitialization (
*FdtHobData = (UINTN)NewBase;
}
+/**
+ * Misc initialization for Microvm and Cloud-Hypervisor
+ *
+ * @return VOID
+ */
VOID
-MiscInitialization (
+MiscInitialization2 (
VOID
)
{
- UINTN PmCmd;
- UINTN Pmba;
- UINT32 PmbaAndVal;
- UINT32 PmbaOrVal;
- UINTN AcpiCtlReg;
- UINT8 AcpiEnBit;
RETURN_STATUS PcdStatus;
+ if ((mHostBridgeDevId != 0xffff) && (mHostBridgeDevId != CLOUDHV_DEVICE_ID)) {
+ ASSERT (FALSE);
+ return;
+ }
+
//
// Disable A20 Mask
//
@@ -331,26 +196,7 @@ MiscInitialization (
//
BuildCpuHob (mPhysMemAddressWidth, 16);
- //
- // Determine platform type and save Host Bridge DID to PCD
- //
switch (mHostBridgeDevId) {
- case INTEL_82441_DEVICE_ID:
- PmCmd = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);
- Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
- PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;
- PmbaOrVal = PIIX4_PMBA_VALUE;
- AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);
- AcpiEnBit = PIIX4_PMREGMISC_PMIOSE;
- break;
- case INTEL_Q35_MCH_DEVICE_ID:
- PmCmd = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);
- Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
- PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;
- PmbaOrVal = ICH9_PMBASE_VALUE;
- AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);
- AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN;
- break;
case 0xffff: /* microvm */
DEBUG ((DEBUG_INFO, "%a: microvm\n", __FUNCTION__));
MicrovmInitialization ();
@@ -378,47 +224,24 @@ MiscInitialization (
ASSERT (FALSE);
return;
}
+}
+
+VOID
+MiscInitialization (
+ VOID
+ )
+{
+ RETURN_STATUS PcdStatus;
+
+ if ((mHostBridgeDevId == 0xffff) || (mHostBridgeDevId == CLOUDHV_DEVICE_ID)) {
+ MiscInitialization2 ();
+ return;
+ }
+
+ PlatformMiscInitialization (mHostBridgeDevId, mPhysMemAddressWidth);
PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);
ASSERT_RETURN_ERROR (PcdStatus);
-
- //
- // If the appropriate IOspace enable bit is set, assume the ACPI PMBA has
- // been configured and skip the setup here. This matches the logic in
- // AcpiTimerLibConstructor ().
- //
- if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
- //
- // The PEI phase should be exited with fully accessibe ACPI PM IO space:
- // 1. set PMBA
- //
- PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);
-
- //
- // 2. set PCICMD/IOSE
- //
- PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);
-
- //
- // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)
- //
- PciOr8 (AcpiCtlReg, AcpiEnBit);
- }
-
- if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
- //
- // Set Root Complex Register Block BAR
- //
- PciWrite32 (
- POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
- ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
- );
-
- //
- // Set PCI Express Register Range Base Address
- //
- PciExBarInitialization ();
- }
}
VOID
@@ -531,160 +354,12 @@ MaxCpuCountInitialization (
UINT16 BootCpuCount;
RETURN_STATUS PcdStatus;
- //
- // Try to fetch the boot CPU count.
- //
- QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
- BootCpuCount = QemuFwCfgRead16 ();
- if (BootCpuCount == 0) {
- //
- // QEMU doesn't report the boot CPU count. (BootCpuCount == 0) will let
- // MpInitLib count APs up to (PcdCpuMaxLogicalProcessorNumber - 1), or
- // until PcdCpuApInitTimeOutInMicroSeconds elapses (whichever is reached
- // first).
- //
- DEBUG ((DEBUG_WARN, "%a: boot CPU count unavailable\n", __FUNCTION__));
- mMaxCpuCount = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
- } else {
- //
- // We will expose BootCpuCount to MpInitLib. MpInitLib will count APs up to
- // (BootCpuCount - 1) precisely, regardless of timeout.
- //
- // Now try to fetch the possible CPU count.
- //
- UINTN CpuHpBase;
- UINT32 CmdData2;
-
- CpuHpBase = ((mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) ?
- ICH9_CPU_HOTPLUG_BASE : PIIX4_CPU_HOTPLUG_BASE);
-
- //
- // If only legacy mode is available in the CPU hotplug register block, or
- // the register block is completely missing, then the writes below are
- // no-ops.
- //
- // 1. Switch the hotplug register block to modern mode.
- //
- IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0);
- //
- // 2. Select a valid CPU for deterministic reading of
- // QEMU_CPUHP_R_CMD_DATA2.
- //
- // CPU#0 is always valid; it is the always present and non-removable
- // BSP.
- //
- IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0);
- //
- // 3. Send a command after which QEMU_CPUHP_R_CMD_DATA2 is specified to
- // read as zero, and which does not invalidate the selector. (The
- // selector may change, but it must not become invalid.)
- //
- // Send QEMU_CPUHP_CMD_GET_PENDING, as it will prove useful later.
- //
- IoWrite8 (CpuHpBase + QEMU_CPUHP_W_CMD, QEMU_CPUHP_CMD_GET_PENDING);
- //
- // 4. Read QEMU_CPUHP_R_CMD_DATA2.
- //
- // If the register block is entirely missing, then this is an unassigned
- // IO read, returning all-bits-one.
- //
- // If only legacy mode is available, then bit#0 stands for CPU#0 in the
- // "CPU present bitmap". CPU#0 is always present.
- //
- // Otherwise, QEMU_CPUHP_R_CMD_DATA2 is either still reserved (returning
- // all-bits-zero), or it is specified to read as zero after the above
- // steps. Both cases confirm modern mode.
- //
- CmdData2 = IoRead32 (CpuHpBase + QEMU_CPUHP_R_CMD_DATA2);
- DEBUG ((DEBUG_VERBOSE, "%a: CmdData2=0x%x\n", __FUNCTION__, CmdData2));
- if (CmdData2 != 0) {
- //
- // QEMU doesn't support the modern CPU hotplug interface. Assume that the
- // possible CPU count equals the boot CPU count (precluding hotplug).
- //
- DEBUG ((
- DEBUG_WARN,
- "%a: modern CPU hotplug interface unavailable\n",
- __FUNCTION__
- ));
- mMaxCpuCount = BootCpuCount;
- } else {
- //
- // Grab the possible CPU count from the modern CPU hotplug interface.
- //
- UINT32 Present, Possible, Selected;
-
- Present = 0;
- Possible = 0;
-
- //
- // We've sent QEMU_CPUHP_CMD_GET_PENDING last; this ensures
- // QEMU_CPUHP_RW_CMD_DATA can now be read usefully. However,
- // QEMU_CPUHP_CMD_GET_PENDING may have selected a CPU with actual pending
- // hotplug events; therefore, select CPU#0 forcibly.
- //
- IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible);
-
- do {
- UINT8 CpuStatus;
-
- //
- // Read the status of the currently selected CPU. This will help with a
- // sanity check against "BootCpuCount".
- //
- CpuStatus = IoRead8 (CpuHpBase + QEMU_CPUHP_R_CPU_STAT);
- if ((CpuStatus & QEMU_CPUHP_STAT_ENABLED) != 0) {
- ++Present;
- }
-
- //
- // Attempt to select the next CPU.
- //
- ++Possible;
- IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible);
- //
- // If the selection is successful, then the following read will return
- // the selector (which we know is positive at this point). Otherwise,
- // the read will return 0.
- //
- Selected = IoRead32 (CpuHpBase + QEMU_CPUHP_RW_CMD_DATA);
- ASSERT (Selected == Possible || Selected == 0);
- } while (Selected > 0);
-
- //
- // Sanity check: fw_cfg and the modern CPU hotplug interface should
- // return the same boot CPU count.
- //
- if (BootCpuCount != Present) {
- DEBUG ((
- DEBUG_WARN,
- "%a: QEMU v2.7 reset bug: BootCpuCount=%d "
- "Present=%u\n",
- __FUNCTION__,
- BootCpuCount,
- Present
- ));
- //
- // The handling of QemuFwCfgItemSmpCpuCount, across CPU hotplug plus
- // platform reset (including S3), was corrected in QEMU commit
- // e3cadac073a9 ("pc: fix FW_CFG_NB_CPUS to account for -device added
- // CPUs", 2016-11-16), part of release v2.8.0.
- //
- BootCpuCount = (UINT16)Present;
- }
-
- mMaxCpuCount = Possible;
- }
- }
-
- DEBUG ((
- DEBUG_INFO,
- "%a: BootCpuCount=%d mMaxCpuCount=%u\n",
- __FUNCTION__,
- BootCpuCount,
- mMaxCpuCount
- ));
- ASSERT (BootCpuCount <= mMaxCpuCount);
+ PlatformMaxCpuCountInitialization (
+ mHostBridgeDevId,
+ PcdGet32 (PcdCpuMaxLogicalProcessorNumber),
+ &mMaxCpuCount,
+ &BootCpuCount
+ );
PcdStatus = PcdSet32S (PcdCpuBootLogicalProcessorNumber, BootCpuCount);
ASSERT_RETURN_ERROR (PcdStatus);
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 21/37] OvmfPkg: Update PlatformInitLib to process Tdx hoblist
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (19 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 20/37] OvmfPkg/PlatformInitLib: Add platform functions Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 22/37] OvmfPkg/Sec: Declare local variable as volatile in SecCoreStartupWithStack Min Xu
` (16 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
When host VMM create the Td guest, the system memory informations are
stored in TdHob, which is a memory region described in Tdx metadata.
The system memory region in TdHob should be accepted before it can be
accessed. So the newly added function (ProcessTdxHobList) is to process
the TdHobList to accept the memory. Because TdHobList is provided by
host VMM which is not trusted, so its content should be checked before
it is consumed by TDVF.
Because ProcessTdxHobList is to be called in SEC phase, so
PlatformInitLib.inf is updated to support SEC.
Note: In this patch it is BSP which accepts the pages. So there maybe
boot performance issue. There are some mitigations to this issue, such
as lazy accept, 2M accept page size, etc. We will re-visit here in the
future.
PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports
4K and 2M accept page size. The default value is 2M.
Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList
just returns EFI_UNSUPPORTED.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Include/Library/PlatformInitLib.h | 17 +
OvmfPkg/Library/PlatformInitLib/IntelTdx.c | 504 ++++++++++++++++++
.../Library/PlatformInitLib/IntelTdxNull.c | 30 ++
.../PlatformInitLib/PlatformInitLib.inf | 13 +-
OvmfPkg/OvmfPkg.dec | 3 +
5 files changed, 566 insertions(+), 1 deletion(-)
create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdx.c
create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
index dd108b3a4339..538fd7aee48c 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -252,4 +252,21 @@ PlatformAddReservedMemoryBaseSizeHob (
IN BOOLEAN Cacheable
);
+/**
+ In Tdx guest, some information need to be passed from host VMM to guest
+ firmware. For example, the memory resource, etc. These information are
+ prepared by host VMM and put in HobList which is described in TdxMetadata.
+
+ Information in HobList is treated as external input. From the security
+ perspective before it is consumed, it should be validated.
+
+ @retval EFI_SUCCESS Successfully process the hoblist
+ @retval Others Other error as indicated
+**/
+EFI_STATUS
+EFIAPI
+ProcessTdxHobList (
+ VOID
+ );
+
#endif // PLATFORM_INIT_LIB_H_
diff --git a/OvmfPkg/Library/PlatformInitLib/IntelTdx.c b/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
new file mode 100644
index 000000000000..1ee24dfe754d
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
@@ -0,0 +1,504 @@
+/** @file
+ Initialize Intel TDX support.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <IndustryStandard/IntelTdx.h>
+#include <IndustryStandard/QemuFwCfg.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/TdxLib.h>
+#include <Library/SynchronizationLib.h>
+#include <WorkArea.h>
+#include <ConfidentialComputingGuestAttr.h>
+
+#define ALIGNED_2MB_MASK 0x1fffff
+
+/**
+ This function will be called to accept pages. Only BSP accepts pages.
+
+ TDCALL(ACCEPT_PAGE) supports the accept page size of 4k and 2M. To
+ simplify the implementation, the Memory to be accpeted is splitted
+ into 3 parts:
+ ----------------- <-- StartAddress1 (not 2M aligned)
+ | part 1 | Length1 < 2M
+ |---------------| <-- StartAddress2 (2M aligned)
+ | | Length2 = Integer multiples of 2M
+ | part 2 |
+ | |
+ |---------------| <-- StartAddress3
+ | part 3 | Length3 < 2M
+ |---------------|
+
+ @param[in] PhysicalAddress Start physical adress
+ @param[in] PhysicalEnd End physical address
+
+ @retval EFI_SUCCESS Accept memory successfully
+ @retval Others Other errors as indicated
+**/
+EFI_STATUS
+EFIAPI
+BspAcceptMemoryResourceRange (
+ IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
+ IN EFI_PHYSICAL_ADDRESS PhysicalEnd
+ )
+{
+ EFI_STATUS Status;
+ UINT32 AcceptPageSize;
+ UINT64 StartAddress1;
+ UINT64 StartAddress2;
+ UINT64 StartAddress3;
+ UINT64 TotalLength;
+ UINT64 Length1;
+ UINT64 Length2;
+ UINT64 Length3;
+ UINT64 Pages;
+
+ AcceptPageSize = FixedPcdGet32 (PcdTdxAcceptPageSize);
+ TotalLength = PhysicalEnd - PhysicalAddress;
+ StartAddress1 = 0;
+ StartAddress2 = 0;
+ StartAddress3 = 0;
+ Length1 = 0;
+ Length2 = 0;
+ Length3 = 0;
+
+ if (TotalLength == 0) {
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((DEBUG_INFO, "TdAccept: 0x%llx - 0x%llx\n", PhysicalAddress, TotalLength));
+
+ if (ALIGN_VALUE (PhysicalAddress, SIZE_2MB) != PhysicalAddress) {
+ StartAddress1 = PhysicalAddress;
+ Length1 = ALIGN_VALUE (PhysicalAddress, SIZE_2MB) - PhysicalAddress;
+ if (Length1 >= TotalLength) {
+ Length1 = TotalLength;
+ }
+
+ PhysicalAddress += Length1;
+ TotalLength -= Length1;
+ }
+
+ if (TotalLength > SIZE_2MB) {
+ StartAddress2 = PhysicalAddress;
+ Length2 = TotalLength & ~(UINT64)ALIGNED_2MB_MASK;
+ PhysicalAddress += Length2;
+ TotalLength -= Length2;
+ }
+
+ if (TotalLength) {
+ StartAddress3 = PhysicalAddress;
+ Length3 = TotalLength;
+ }
+
+ DEBUG ((DEBUG_INFO, " Part1: 0x%llx - 0x%llx\n", StartAddress1, Length1));
+ DEBUG ((DEBUG_INFO, " Part2: 0x%llx - 0x%llx\n", StartAddress2, Length2));
+ DEBUG ((DEBUG_INFO, " Part3: 0x%llx - 0x%llx\n", StartAddress3, Length3));
+ DEBUG ((DEBUG_INFO, " Page : 0x%x\n", AcceptPageSize));
+
+ Status = EFI_SUCCESS;
+ if (Length1 > 0) {
+ Pages = Length1 / SIZE_4KB;
+ Status = TdAcceptPages (StartAddress1, Pages, SIZE_4KB);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (Length2 > 0) {
+ Pages = Length2 / AcceptPageSize;
+ Status = TdAcceptPages (StartAddress2, Pages, AcceptPageSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (Length3 > 0) {
+ Pages = Length3 / SIZE_4KB;
+ Status = TdAcceptPages (StartAddress3, Pages, SIZE_4KB);
+ ASSERT (!EFI_ERROR (Status));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Check the value whether in the valid list.
+
+ @param[in] Value A value
+ @param[in] ValidList A pointer to valid list
+ @param[in] ValidListLength Length of valid list
+
+ @retval TRUE The value is in valid list.
+ @retval FALSE The value is not in valid list.
+
+**/
+BOOLEAN
+EFIAPI
+IsInValidList (
+ IN UINT32 Value,
+ IN UINT32 *ValidList,
+ IN UINT32 ValidListLength
+ )
+{
+ UINT32 index;
+
+ if (ValidList == NULL) {
+ return FALSE;
+ }
+
+ for (index = 0; index < ValidListLength; index++) {
+ if (ValidList[index] == Value) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Check the integrity of VMM Hob List.
+
+ @param[in] VmmHobList A pointer to Hob List
+
+ @retval TRUE The Hob List is valid.
+ @retval FALSE The Hob List is invalid.
+
+**/
+BOOLEAN
+EFIAPI
+ValidateHobList (
+ IN CONST VOID *VmmHobList
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ UINT32 EFI_BOOT_MODE_LIST[12] = {
+ BOOT_WITH_FULL_CONFIGURATION,
+ BOOT_WITH_MINIMAL_CONFIGURATION,
+ BOOT_ASSUMING_NO_CONFIGURATION_CHANGES,
+ BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS,
+ BOOT_WITH_DEFAULT_SETTINGS,
+ BOOT_ON_S4_RESUME,
+ BOOT_ON_S5_RESUME,
+ BOOT_WITH_MFG_MODE_SETTINGS,
+ BOOT_ON_S2_RESUME,
+ BOOT_ON_S3_RESUME,
+ BOOT_ON_FLASH_UPDATE,
+ BOOT_IN_RECOVERY_MODE
+ };
+
+ UINT32 EFI_RESOURCE_TYPE_LIST[8] = {
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ EFI_RESOURCE_MEMORY_MAPPED_IO,
+ EFI_RESOURCE_IO,
+ EFI_RESOURCE_FIRMWARE_DEVICE,
+ EFI_RESOURCE_MEMORY_MAPPED_IO_PORT,
+ EFI_RESOURCE_MEMORY_RESERVED,
+ EFI_RESOURCE_IO_RESERVED,
+ EFI_RESOURCE_MAX_MEMORY_TYPE
+ };
+
+ if (VmmHobList == NULL) {
+ DEBUG ((DEBUG_ERROR, "HOB: HOB data pointer is NULL\n"));
+ return FALSE;
+ }
+
+ Hob.Raw = (UINT8 *)VmmHobList;
+
+ //
+ // Parse the HOB list until end of list or matching type is found.
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->Reserved != (UINT32)0) {
+ DEBUG ((DEBUG_ERROR, "HOB: Hob header Reserved filed should be zero\n"));
+ return FALSE;
+ }
+
+ if (Hob.Header->HobLength == 0) {
+ DEBUG ((DEBUG_ERROR, "HOB: Hob header LEANGTH should not be zero\n"));
+ return FALSE;
+ }
+
+ switch (Hob.Header->HobType) {
+ case EFI_HOB_TYPE_HANDOFF:
+ if (Hob.Header->HobLength != sizeof (EFI_HOB_HANDOFF_INFO_TABLE)) {
+ DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_HANDOFF));
+ return FALSE;
+ }
+
+ if (IsInValidList (Hob.HandoffInformationTable->BootMode, EFI_BOOT_MODE_LIST, 12) == FALSE) {
+ DEBUG ((DEBUG_ERROR, "HOB: Unknow HandoffInformationTable BootMode type. Type: 0x%08x\n", Hob.HandoffInformationTable->BootMode));
+ return FALSE;
+ }
+
+ if ((Hob.HandoffInformationTable->EfiFreeMemoryTop % 4096) != 0) {
+ DEBUG ((DEBUG_ERROR, "HOB: HandoffInformationTable EfiFreeMemoryTop address must be 4-KB aligned to meet page restrictions of UEFI.\
+ Address: 0x%016lx\n", Hob.HandoffInformationTable->EfiFreeMemoryTop));
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
+ if (Hob.Header->HobLength != sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)) {
+ DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_RESOURCE_DESCRIPTOR));
+ return FALSE;
+ }
+
+ if (IsInValidList (Hob.ResourceDescriptor->ResourceType, EFI_RESOURCE_TYPE_LIST, 8) == FALSE) {
+ DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceType type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceType));
+ return FALSE;
+ }
+
+ if ((Hob.ResourceDescriptor->ResourceAttribute & (~(EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_TESTED |
+ EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
+ EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED |
+ EFI_RESOURCE_ATTRIBUTE_PERSISTENT |
+ EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC |
+ EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC |
+ EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 |
+ EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_16_BIT_IO |
+ EFI_RESOURCE_ATTRIBUTE_32_BIT_IO |
+ EFI_RESOURCE_ATTRIBUTE_64_BIT_IO |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED |
+ EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE |
+ EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE |
+ EFI_RESOURCE_ATTRIBUTE_PERSISTABLE |
+ EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED |
+ EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE |
+ EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE |
+ EFI_RESOURCE_ATTRIBUTE_ENCRYPTED))) != 0)
+ {
+ DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceAttribute type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceAttribute));
+ return FALSE;
+ }
+
+ break;
+
+ // EFI_HOB_GUID_TYPE is variable length data, so skip check
+ case EFI_HOB_TYPE_GUID_EXTENSION:
+ break;
+
+ case EFI_HOB_TYPE_FV:
+ if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME)) {
+ DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV));
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_HOB_TYPE_FV2:
+ if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME2)) {
+ DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV2));
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_HOB_TYPE_FV3:
+ if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME3)) {
+ DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV3));
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_HOB_TYPE_CPU:
+ if (Hob.Header->HobLength != sizeof (EFI_HOB_CPU)) {
+ DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_CPU));
+ return FALSE;
+ }
+
+ for (UINT32 index = 0; index < 6; index++) {
+ if (Hob.Cpu->Reserved[index] != 0) {
+ DEBUG ((DEBUG_ERROR, "HOB: Cpu Reserved field will always be set to zero.\n"));
+ return FALSE;
+ }
+ }
+
+ break;
+
+ default:
+ DEBUG ((DEBUG_ERROR, "HOB: Hob type is not know. Type: 0x%04x\n", Hob.Header->HobType));
+ return FALSE;
+ }
+
+ // Get next HOB
+ Hob.Raw = (UINT8 *)(Hob.Raw + Hob.Header->HobLength);
+ }
+
+ return TRUE;
+}
+
+/**
+ Processing the incoming HobList for the TDX
+
+ Firmware must parse list, and accept the pages of memory before their can be
+ use by the guest.
+
+ @param[in] VmmHobList The Hoblist pass the firmware
+
+ @retval EFI_SUCCESS Process the HobList successfully
+ @retval Others Other errors as indicated
+
+**/
+EFI_STATUS
+EFIAPI
+ProcessHobList (
+ IN CONST VOID *VmmHobList
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PHYSICAL_ADDRESS PhysicalEnd;
+
+ Status = EFI_SUCCESS;
+ ASSERT (VmmHobList != NULL);
+ Hob.Raw = (UINT8 *)VmmHobList;
+
+ //
+ // Parse the HOB list until end of list or matching type is found.
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ DEBUG ((DEBUG_INFO, "\nResourceType: 0x%x\n", Hob.ResourceDescriptor->ResourceType));
+
+ if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
+ DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescriptor->ResourceAttribute));
+ DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", Hob.ResourceDescriptor->PhysicalStart));
+ DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", Hob.ResourceDescriptor->ResourceLength));
+ DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owner));
+
+ PhysicalEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
+
+ Status = BspAcceptMemoryResourceRange (
+ Hob.ResourceDescriptor->PhysicalStart,
+ PhysicalEnd
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+
+ return Status;
+}
+
+/**
+ In Tdx guest, some information need to be passed from host VMM to guest
+ firmware. For example, the memory resource, etc. These information are
+ prepared by host VMM and put in HobList which is described in TdxMetadata.
+
+ Information in HobList is treated as external input. From the security
+ perspective before it is consumed, it should be validated.
+
+ @retval EFI_SUCCESS Successfully process the hoblist
+ @retval Others Other error as indicated
+**/
+EFI_STATUS
+EFIAPI
+ProcessTdxHobList (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *TdHob;
+ TD_RETURN_DATA TdReturnData;
+
+ TdHob = (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase);
+ Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "Intel Tdx Started with (GPAW: %d, Cpus: %d)\n",
+ TdReturnData.TdInfo.Gpaw,
+ TdReturnData.TdInfo.NumVcpus
+ ));
+
+ //
+ // Validate HobList
+ //
+ if (ValidateHobList (TdHob) == FALSE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Process Hoblist to accept memory
+ //
+ Status = ProcessHobList (TdHob);
+
+ return Status;
+}
+
+/**
+ Transfer the incoming HobList for the TD to the final HobList for Dxe.
+ The Hobs transferred in this function are ResourceDescriptor hob and
+ MemoryAllocation hob.
+
+ @param[in] VmmHobList The Hoblist pass the firmware
+
+**/
+VOID
+EFIAPI
+TransferTdxHobList (
+ VOID
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+
+ //
+ // PcdOvmfSecGhcbBase is used as the TD_HOB in Tdx guest.
+ //
+ Hob.Raw = (UINT8 *)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase);
+ while (!END_OF_HOB_LIST (Hob)) {
+ switch (Hob.Header->HobType) {
+ case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
+ BuildResourceDescriptorHob (
+ Hob.ResourceDescriptor->ResourceType,
+ Hob.ResourceDescriptor->ResourceAttribute,
+ Hob.ResourceDescriptor->PhysicalStart,
+ Hob.ResourceDescriptor->ResourceLength
+ );
+ break;
+ case EFI_HOB_TYPE_MEMORY_ALLOCATION:
+ BuildMemoryAllocationHob (
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,
+ Hob.MemoryAllocation->AllocDescriptor.MemoryLength,
+ Hob.MemoryAllocation->AllocDescriptor.MemoryType
+ );
+ break;
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c b/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
new file mode 100644
index 000000000000..af90e0866e89
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
@@ -0,0 +1,30 @@
+/** @file
+ Initialize Intel TDX support.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+/**
+ In Tdx guest, some information need to be passed from host VMM to guest
+ firmware. For example, the memory resource, etc. These information are
+ prepared by host VMM and put in HobList which is described in TdxMetadata.
+
+ Information in HobList is treated as external input. From the security
+ perspective before it is consumed, it should be validated.
+
+ @retval EFI_SUCCESS Successfully process the hoblist
+ @retval Others Other error as indicated
+**/
+EFI_STATUS
+EFIAPI
+ProcessTdxHobList (
+ VOID
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
index a42b54805ba6..264250e56b5c 100644
--- a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -14,7 +14,7 @@
FILE_GUID = 89f886b0-7109-46e1-9d28-503ad4ab6ee0
MODULE_TYPE = BASE
VERSION_STRING = 1.0
- LIBRARY_CLASS = PlatformInitLib|PEIM
+ LIBRARY_CLASS = PlatformInitLib|SEC PEIM
#
# The following information is for reference only and not required by the build tools.
@@ -27,6 +27,12 @@
MemDetect.c
Platform.c
+[Sources.IA32]
+ IntelTdxNull.c
+
+[Sources.X64]
+ IntelTdx.c
+
[Packages]
EmbeddedPkg/EmbeddedPkg.dec
MdeModulePkg/MdeModulePkg.dec
@@ -45,6 +51,9 @@
PcdLib
PciLib
+[LibraryClasses.X64]
+ TdxLib
+
[FixedPcd]
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
@@ -79,5 +88,7 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize
+
[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 61635c73c761..f3d06411b51b 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -377,6 +377,9 @@
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecValidatedStart|0|UINT32|0x62
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecValidatedEnd|0|UINT32|0x63
+ ## The Tdx accept page size. 0x1000(4k),0x200000(2M)
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize|0x200000|UINT32|0x65
+
[PcdsDynamic, PcdsDynamicEx]
gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 22/37] OvmfPkg/Sec: Declare local variable as volatile in SecCoreStartupWithStack
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (20 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 21/37] OvmfPkg: Update PlatformInitLib to process Tdx hoblist Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 23/37] OvmfPkg: Update Sec to support Tdx Min Xu
` (15 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
Declare the local variables in SecCoreStartupWithStack that actually
move the data elements as volatile to prevent the optimizer from
replacing this function with the intrinsic memcpy().
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Sec/SecMain.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 2c5561661ef3..02520e25ab9a 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -757,12 +757,17 @@ SecCoreStartupWithStack (
//
IdtTableInStack.PeiService = NULL;
for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index++) {
- UINT8 *Src;
- UINT8 *Dst;
- UINTN Byte;
+ //
+ // Declare the local variables that actually move the data elements as
+ // volatile to prevent the optimizer from replacing this function with
+ // the intrinsic memcpy()
+ //
+ CONST UINT8 *Src;
+ volatile UINT8 *Dst;
+ UINTN Byte;
- Src = (UINT8 *)&mIdtEntryTemplate;
- Dst = (UINT8 *)&IdtTableInStack.IdtTable[Index];
+ Src = (CONST UINT8 *)&mIdtEntryTemplate;
+ Dst = (volatile UINT8 *)&IdtTableInStack.IdtTable[Index];
for (Byte = 0; Byte < sizeof (mIdtEntryTemplate); Byte++) {
Dst[Byte] = Src[Byte];
}
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 23/37] OvmfPkg: Update Sec to support Tdx
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (21 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 22/37] OvmfPkg/Sec: Declare local variable as volatile in SecCoreStartupWithStack Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-03-01 13:11 ` Gerd Hoffmann
2022-02-28 7:20 ` [PATCH V7 24/37] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
` (14 subsequent siblings)
37 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
There are below major changes in this commit.
1. SecEntry.nasm
In TDX BSP and APs goes to the same entry point in SecEntry.nasm.
BSP initialize the temporary stack and then jumps to SecMain, just as
legacy Ovmf does.
APs spin in a modified mailbox loop using initial mailbox structure.
Its structure defition is in OvmfPkg/Include/IndustryStandard/IntelTdx.h.
APs wait for command to see if the command is for me. If so execute the
command.
2. Sec/SecMain.c
When host VMM create the Td guest, the system memory informations are
stored in TdHob, which is a memory region described in Tdx metadata.
The system memory region in TdHob should be accepted before it can be
accessed. So the major task of this patch is to process the TdHobList
to accept the memory. After that TDVF follow the standard OVMF flow
and jump to PEI phase.
PcdUse1GPageTable is set to FALSE by default in OvmfPkgX64.dsc. It gives
no chance for Intel TDX to support 1G page table. To support 1G page
table this PCD is set to TRUE in OvmfPkgX64.dsc.
TDX_GUEST_SUPPORTED is defined in OvmfPkgX64.dsc. This macro wraps the
Tdx specific code.
TDX only works on X64, so the code is only valid in X64 arch.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/AmdSev/AmdSevX64.dsc | 1 +
OvmfPkg/Bhyve/BhyveX64.dsc | 1 +
OvmfPkg/CloudHv/CloudHvX64.dsc | 1 +
OvmfPkg/Include/TdxCommondefs.inc | 51 +++++++++++++++++++
OvmfPkg/Microvm/MicrovmX64.dsc | 1 +
OvmfPkg/OvmfPkgIa32X64.dsc | 2 +
OvmfPkg/OvmfPkgX64.dsc | 14 ++++++
OvmfPkg/OvmfXen.dsc | 1 +
OvmfPkg/Sec/SecMain.c | 29 ++++++++++-
OvmfPkg/Sec/SecMain.inf | 3 ++
OvmfPkg/Sec/X64/SecEntry.nasm | 82 +++++++++++++++++++++++++++++++
11 files changed, 184 insertions(+), 2 deletions(-)
create mode 100644 OvmfPkg/Include/TdxCommondefs.inc
diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index 785049c88962..c173a72134f4 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -208,6 +208,7 @@
[LibraryClasses.common]
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
+ TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
[LibraryClasses.common.SEC]
TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc
index 5fa08bebd73c..656e407473bb 100644
--- a/OvmfPkg/Bhyve/BhyveX64.dsc
+++ b/OvmfPkg/Bhyve/BhyveX64.dsc
@@ -228,6 +228,7 @@
[LibraryClasses.common]
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+ TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
[LibraryClasses.common.SEC]
!ifdef $(DEBUG_ON_SERIAL_PORT)
diff --git a/OvmfPkg/CloudHv/CloudHvX64.dsc b/OvmfPkg/CloudHv/CloudHvX64.dsc
index e821a72f000c..d5259dedfef6 100644
--- a/OvmfPkg/CloudHv/CloudHvX64.dsc
+++ b/OvmfPkg/CloudHv/CloudHvX64.dsc
@@ -237,6 +237,7 @@
[LibraryClasses.common]
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
+ TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
[LibraryClasses.common.SEC]
TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
diff --git a/OvmfPkg/Include/TdxCommondefs.inc b/OvmfPkg/Include/TdxCommondefs.inc
new file mode 100644
index 000000000000..970eac96592a
--- /dev/null
+++ b/OvmfPkg/Include/TdxCommondefs.inc
@@ -0,0 +1,51 @@
+;------------------------------------------------------------------------------
+; @file
+; TDX Common defitions used by the APs in mailbox
+;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+CommandOffset equ 00h
+ApicidOffset equ 04h
+WakeupVectorOffset equ 08h
+OSArgsOffset equ 10h
+FirmwareArgsOffset equ 800h
+WakeupArgsRelocatedMailBox equ 800h
+AcceptPageArgsPhysicalStart equ 800h
+AcceptPageArgsPhysicalEnd equ 808h
+AcceptPageArgsChunkSize equ 810h
+AcceptPageArgsPageSize equ 818h
+CpuArrivalOffset equ 900h
+CpusExitingOffset equ 0a00h
+TalliesOffset equ 0a08h
+ErrorsOffset equ 0e08h
+
+SIZE_4KB equ 1000h
+SIZE_2MB equ 200000h
+SIZE_1GB equ 40000000h
+
+PAGE_ACCEPT_LEVEL_4K equ 0
+PAGE_ACCEPT_LEVEL_2M equ 1
+PAGE_ACCEPT_LEVEL_1G equ 2
+
+TDX_PAGE_ALREADY_ACCEPTED equ 0x00000b0a
+TDX_PAGE_SIZE_MISMATCH equ 0xc0000b0b
+
+; Errors of APs in Mailbox
+ERROR_NON equ 0
+ERROR_INVALID_ACCEPT_PAGE_SIZE equ 1
+ERROR_ACCEPT_PAGE_ERROR equ 2
+ERROR_INVALID_FALLBACK_PAGE_LEVEL equ 3
+
+MpProtectedModeWakeupCommandNoop equ 0
+MpProtectedModeWakeupCommandWakeup equ 1
+MpProtectedModeWakeupCommandSleep equ 2
+MpProtectedModeWakeupCommandAcceptPages equ 3
+
+MailboxApicIdInvalid equ 0xffffffff
+MailboxApicidBroadcast equ 0xfffffffe
+
+%define TDCALL_TDINFO 0x1
+%define TDCALL_TDACCEPTPAGE 0x6
diff --git a/OvmfPkg/Microvm/MicrovmX64.dsc b/OvmfPkg/Microvm/MicrovmX64.dsc
index 27005eec89f2..0eac0c02c630 100644
--- a/OvmfPkg/Microvm/MicrovmX64.dsc
+++ b/OvmfPkg/Microvm/MicrovmX64.dsc
@@ -232,6 +232,7 @@
PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf
VirtioMmioDeviceLib|OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf
+ TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
[LibraryClasses.common.SEC]
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSecLib.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index c58ef8494470..98a6748c62dd 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -238,6 +238,8 @@
[LibraryClasses.common]
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+ TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
+ TdxMailboxLib|OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
[LibraryClasses.common.SEC]
TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 227b9845619f..2df5b2999610 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -93,6 +93,13 @@
INTEL:*_*_*_CC_FLAGS = /D DISABLE_NEW_DEPRECATED_INTERFACES
GCC:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
+ #
+ # Add TDX_GUEST_SUPPORTED
+ #
+ MSFT:*_*_*_CC_FLAGS = /D TDX_GUEST_SUPPORTED
+ INTEL:*_*_*_CC_FLAGS = /D TDX_GUEST_SUPPORTED
+ GCC:*_*_*_CC_FLAGS = -D TDX_GUEST_SUPPORTED
+
!include NetworkPkg/NetworkBuildOptions.dsc.inc
[BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER]
@@ -238,6 +245,8 @@
[LibraryClasses.common]
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
+ TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
+ TdxMailboxLib|OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
[LibraryClasses.common.SEC]
TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
@@ -558,6 +567,10 @@
gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|0x100
gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData|0x100
+ #
+ # TDX need 1G PageTable support
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable|TRUE
+
#
# Network Pcds
#
@@ -669,6 +682,7 @@
OvmfPkg/Sec/SecMain.inf {
<LibraryClasses>
NULL|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
+ NULL|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
}
#
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index efa97f09f32b..aa27e2256ae9 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -227,6 +227,7 @@
[LibraryClasses.common]
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+ TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
[LibraryClasses.common.SEC]
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSecLib.inf
diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 02520e25ab9a..ca9717a7b526 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -26,9 +26,8 @@
#include <Library/ExtractGuidedSectionLib.h>
#include <Library/LocalApicLib.h>
#include <Library/CpuExceptionHandlerLib.h>
-
#include <Ppi/TemporaryRamSupport.h>
-
+#include <Library/PlatformInitLib.h>
#include "AmdSev.h"
#define SEC_IDT_ENTRY_COUNT 34
@@ -738,6 +737,20 @@ SecCoreStartupWithStack (
UINT32 Index;
volatile UINT8 *Table;
+ #if defined (TDX_GUEST_SUPPORTED)
+ if (TdIsEnabled ()) {
+ //
+ // For Td guests, the memory map info is in TdHobLib. It should be processed
+ // first so that the memory is accepted. Otherwise access to the unaccepted
+ // memory will trigger tripple fault.
+ //
+ if (ProcessTdxHobList () != EFI_SUCCESS) {
+ CpuDeadLoop ();
+ }
+ }
+
+ #endif
+
//
// To ensure SMM can't be compromised on S3 resume, we must force re-init of
// the BaseExtractGuidedSectionLib. Since this is before library contructors
@@ -756,6 +769,7 @@ SecCoreStartupWithStack (
// we use a loop rather than CopyMem.
//
IdtTableInStack.PeiService = NULL;
+
for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index++) {
//
// Declare the local variables that actually move the data elements as
@@ -813,6 +827,17 @@ SecCoreStartupWithStack (
AsmEnableCache ();
}
+ #if defined (TDX_GUEST_SUPPORTED)
+ if (TdIsEnabled ()) {
+ //
+ // InitializeCpuExceptionHandlers () should be called in Td guests so that
+ // #VE exceptions can be handled correctly.
+ //
+ InitializeCpuExceptionHandlers (NULL);
+ }
+
+ #endif
+
DEBUG ((
DEBUG_INFO,
"SecCoreStartupWithStack(0x%x, 0x%x)\n",
diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
index 95cf0025e100..4b5b089ccd69 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -77,6 +77,9 @@
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecValidatedStart
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecValidatedEnd
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
[FeaturePcd]
gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
diff --git a/OvmfPkg/Sec/X64/SecEntry.nasm b/OvmfPkg/Sec/X64/SecEntry.nasm
index 1cc680a70716..4528fec309a0 100644
--- a/OvmfPkg/Sec/X64/SecEntry.nasm
+++ b/OvmfPkg/Sec/X64/SecEntry.nasm
@@ -10,12 +10,17 @@
;------------------------------------------------------------------------------
#include <Base.h>
+%include "TdxCommondefs.inc"
DEFAULT REL
SECTION .text
extern ASM_PFX(SecCoreStartupWithStack)
+%macro tdcall 0
+ db 0x66, 0x0f, 0x01, 0xcc
+%endmacro
+
;
; SecCore Entry Point
;
@@ -35,6 +40,32 @@ extern ASM_PFX(SecCoreStartupWithStack)
global ASM_PFX(_ModuleEntryPoint)
ASM_PFX(_ModuleEntryPoint):
+ ;
+ ; Guest type is stored in OVMF_WORK_AREA
+ ;
+ %define OVMF_WORK_AREA FixedPcdGet32 (PcdOvmfWorkAreaBase)
+ %define VM_GUEST_TYPE_TDX 2
+ mov eax, OVMF_WORK_AREA
+ cmp byte[eax], VM_GUEST_TYPE_TDX
+ jne InitStack
+
+ mov rax, TDCALL_TDINFO
+ tdcall
+
+ ;
+ ; R8 [31:0] NUM_VCPUS
+ ; [63:32] MAX_VCPUS
+ ; R9 [31:0] VCPU_INDEX
+ ; Td Guest set the VCPU0 as the BSP, others are the APs
+ ; APs jump to spinloop and get released by DXE's MpInitLib
+ ;
+ mov rax, r9
+ and rax, 0xffff
+ test rax, rax
+ jne ParkAp
+
+InitStack:
+
;
; Fill the temporary RAM with the initial stack value.
; The loop below will seed the heap as well, but that's harmless.
@@ -67,3 +98,54 @@ ASM_PFX(_ModuleEntryPoint):
sub rsp, 0x20
call ASM_PFX(SecCoreStartupWithStack)
+ ;
+ ; Note: BSP never gets here. APs will be unblocked by DXE
+ ;
+ ; R8 [31:0] NUM_VCPUS
+ ; [63:32] MAX_VCPUS
+ ; R9 [31:0] VCPU_INDEX
+ ;
+ParkAp:
+
+ mov rbp, r9
+
+.do_wait_loop:
+ mov rsp, FixedPcdGet32 (PcdOvmfSecGhcbBackupBase)
+
+ ;
+ ; register itself in [rsp + CpuArrivalOffset]
+ ;
+ mov rax, 1
+ lock xadd dword [rsp + CpuArrivalOffset], eax
+ inc eax
+
+.check_arrival_cnt:
+ cmp eax, r8d
+ je .check_command
+ mov eax, dword[rsp + CpuArrivalOffset]
+ jmp .check_arrival_cnt
+
+.check_command:
+ mov eax, dword[rsp + CommandOffset]
+ cmp eax, MpProtectedModeWakeupCommandNoop
+ je .check_command
+
+ cmp eax, MpProtectedModeWakeupCommandWakeup
+ je .do_wakeup
+
+ ; Don't support this command, so ignore
+ jmp .check_command
+
+.do_wakeup:
+ ;
+ ; BSP sets these variables before unblocking APs
+ ; RAX: WakeupVectorOffset
+ ; RBX: Relocated mailbox address
+ ; RBP: vCpuId
+ ;
+ mov rax, 0
+ mov eax, dword[rsp + WakeupVectorOffset]
+ mov rbx, [rsp + WakeupArgsRelocatedMailBox]
+ nop
+ jmp rax
+ jmp $
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* Re: [PATCH V7 23/37] OvmfPkg: Update Sec to support Tdx
2022-02-28 7:20 ` [PATCH V7 23/37] OvmfPkg: Update Sec to support Tdx Min Xu
@ 2022-03-01 13:11 ` Gerd Hoffmann
0 siblings, 0 replies; 72+ messages in thread
From: Gerd Hoffmann @ 2022-03-01 13:11 UTC (permalink / raw)
To: Min Xu
Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky
On Mon, Feb 28, 2022 at 03:20:55PM +0800, Min Xu wrote:
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
>
> There are below major changes in this commit.
>
> 1. SecEntry.nasm
> In TDX BSP and APs goes to the same entry point in SecEntry.nasm.
>
> BSP initialize the temporary stack and then jumps to SecMain, just as
> legacy Ovmf does.
>
> APs spin in a modified mailbox loop using initial mailbox structure.
> Its structure defition is in OvmfPkg/Include/IndustryStandard/IntelTdx.h.
> APs wait for command to see if the command is for me. If so execute the
> command.
>
> 2. Sec/SecMain.c
> When host VMM create the Td guest, the system memory informations are
> stored in TdHob, which is a memory region described in Tdx metadata.
> The system memory region in TdHob should be accepted before it can be
> accessed. So the major task of this patch is to process the TdHobList
> to accept the memory. After that TDVF follow the standard OVMF flow
> and jump to PEI phase.
>
> PcdUse1GPageTable is set to FALSE by default in OvmfPkgX64.dsc. It gives
> no chance for Intel TDX to support 1G page table. To support 1G page
> table this PCD is set to TRUE in OvmfPkgX64.dsc.
>
> TDX_GUEST_SUPPORTED is defined in OvmfPkgX64.dsc. This macro wraps the
> Tdx specific code.
>
> TDX only works on X64, so the code is only valid in X64 arch.
>
> 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>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH V7 24/37] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (22 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 23/37] OvmfPkg: Update Sec to support Tdx Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-02-28 7:20 ` [PATCH V7 25/37] MdeModulePkg: EFER should not be changed in TDX Min Xu
` (13 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
If TDX is enabled then we do not support DMA operation in PEI phase.
This is mainly because DMA in TDX guest requires using bounce buffer
(which need to allocate dynamic memory and allocating a PAGE size'd
buffer can be challenge in PEI phase).
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
.../QemuFwCfgLib/QemuFwCfgLibInternal.h | 11 +++++++
OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c | 32 +++++++++++++++++++
.../Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf | 2 ++
3 files changed, 45 insertions(+)
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
index 0b77cad1c030..6f7beb6ac1c7 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
@@ -59,4 +59,15 @@ InternalQemuFwCfgDmaBytes (
IN UINT32 Control
);
+/**
+ Check if it is Tdx guest
+
+ @retval TRUE It is Tdx guest
+ @retval FALSE It is not Tdx guest
+**/
+BOOLEAN
+QemuFwCfgIsTdxGuest (
+ VOID
+ );
+
#endif
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
index f696fb7cacaa..b8230613dcea 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
@@ -14,12 +14,30 @@
#include <Library/DebugLib.h>
#include <Library/QemuFwCfgLib.h>
#include <Library/MemEncryptSevLib.h>
+#include <WorkArea.h>
#include "QemuFwCfgLibInternal.h"
STATIC BOOLEAN mQemuFwCfgSupported = FALSE;
STATIC BOOLEAN mQemuFwCfgDmaSupported;
+/**
+ Check if it is Tdx guest
+
+ @retval TRUE It is Tdx guest
+ @retval FALSE It is not Tdx guest
+**/
+BOOLEAN
+QemuFwCfgIsTdxGuest (
+ VOID
+ )
+{
+ CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER *CcWorkAreaHeader;
+
+ CcWorkAreaHeader = (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER *)FixedPcdGet32 (PcdOvmfWorkAreaBase);
+ return (CcWorkAreaHeader != NULL && CcWorkAreaHeader->GuestType == GUEST_TYPE_INTEL_TDX);
+}
+
/**
Returns a boolean indicating if the firmware configuration interface
is available or not.
@@ -81,6 +99,14 @@ QemuFwCfgInitialize (
//
if (MemEncryptSevIsEnabled ()) {
DEBUG ((DEBUG_INFO, "SEV: QemuFwCfg fallback to IO Port interface.\n"));
+ } else if (QemuFwCfgIsTdxGuest ()) {
+ //
+ // If TDX is enabled then we do not support DMA operations in PEI phase.
+ // This is mainly because DMA in TDX guest requires using bounce buffer
+ // (which need to allocate dynamic memory and allocating a PAGE size'd
+ // buffer can be challenge in PEI phase)
+ //
+ DEBUG ((DEBUG_INFO, "TDX: QemuFwCfg fallback to IO Port interface.\n"));
} else {
mQemuFwCfgDmaSupported = TRUE;
DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n"));
@@ -163,6 +189,12 @@ InternalQemuFwCfgDmaBytes (
//
ASSERT (!MemEncryptSevIsEnabled ());
+ //
+ // TDX does not support DMA operations in PEI stage, we should
+ // not have reached here.
+ //
+ ASSERT (!QemuFwCfgIsTdxGuest ());
+
Access.Control = SwapBytes32 (Control);
Access.Length = SwapBytes32 (Size);
Access.Address = SwapBytes64 ((UINTN)Buffer);
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
index 9f9af7d03201..3910511880c9 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
@@ -43,3 +43,5 @@
MemoryAllocationLib
MemEncryptSevLib
+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 25/37] MdeModulePkg: EFER should not be changed in TDX
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (23 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 24/37] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-03-03 3:11 ` Wang, Jian J
2022-02-28 7:20 ` [PATCH V7 26/37] MdeModulePkg: Add PcdTdxSharedBitMask Min Xu
` (12 subsequent siblings)
37 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Jian J Wang, Hao A Wu, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
In TDX IA32_ERER is RO to host VMM. It could not be changed.
PcdIa32EferChangeAllowed is added in MdeModulePkg.dec and it is
to be set to FALSE in Tdx guest.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 1 +
MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 7 +++++++
MdeModulePkg/MdeModulePkg.dec | 5 +++++
3 files changed, 13 insertions(+)
diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
index 19b8a4c8aefa..106b679b6bd0 100644
--- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
+++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
@@ -117,6 +117,7 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdUse5LevelPageTable ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed ## CONSUMES
[Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMETIMES_CONSUMES
diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
index 0700f310b203..5c647c74e773 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
@@ -159,6 +159,13 @@ IsEnableNonExecNeeded (
return FALSE;
}
+ //
+ // Intel TDX sets this flag to FALSE.
+ //
+ if (!PcdGetBool (PcdIa32EferChangeAllowed)) {
+ return FALSE;
+ }
+
//
// XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
// Features controlled by Following PCDs need this feature to be enabled.
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 463e889e9a68..453f2a74b11d 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -2138,6 +2138,11 @@
# @Prompt GHCB Pool Size
gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0|UINT64|0x00030008
+ ## This dynamic PCD indicates if IA32_EFER can be changed. The default value is TRUE but in
+ # Intel TDX change of IA32_EFER is not allowed.
+ # @Prompt The flag which indicates if IA32_EFER is allowed to be changed.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed|TRUE|BOOLEAN|0x00030009
+
[PcdsDynamicEx]
## This dynamic PCD enables the default variable setting.
# Its value is the default store ID value. The default value is zero as Standard default.
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* Re: [PATCH V7 25/37] MdeModulePkg: EFER should not be changed in TDX
2022-02-28 7:20 ` [PATCH V7 25/37] MdeModulePkg: EFER should not be changed in TDX Min Xu
@ 2022-03-03 3:11 ` Wang, Jian J
2022-03-04 0:18 ` Min Xu
0 siblings, 1 reply; 72+ messages in thread
From: Wang, Jian J @ 2022-03-03 3:11 UTC (permalink / raw)
To: Xu, Min M, devel@edk2.groups.io
Cc: Wu, Hao A, Brijesh Singh, Aktas, Erdem, James Bottomley,
Yao, Jiewen, Tom Lendacky, Gerd Hoffmann
Hi Min,
I think the PCD should not be dynamic. Dynamic PCD is used for those features
which can be changed at boot time. But, for Intel processor, it should always
stay as FALSE. So there's no need to make it dynamic. FixedAtBuild should be fine.
Regards,
Jian
> -----Original Message-----
> From: Xu, Min M <min.m.xu@intel.com>
> Sent: Monday, February 28, 2022 3:21 PM
> To: devel@edk2.groups.io
> Cc: Xu, Min M <min.m.xu@intel.com>; Wang, Jian J <jian.j.wang@intel.com>;
> Wu, Hao A <hao.a.wu@intel.com>; Brijesh Singh <brijesh.singh@amd.com>;
> Aktas, Erdem <erdemaktas@google.com>; James Bottomley
> <jejb@linux.ibm.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky
> <thomas.lendacky@amd.com>; Gerd Hoffmann <kraxel@redhat.com>
> Subject: [PATCH V7 25/37] MdeModulePkg: EFER should not be changed in TDX
>
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
>
> In TDX IA32_ERER is RO to host VMM. It could not be changed.
> PcdIa32EferChangeAllowed is added in MdeModulePkg.dec and it is
> to be set to FALSE in Tdx guest.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Hao A Wu <hao.a.wu@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>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Acked-by: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>
> ---
> MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 1 +
> MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 7 +++++++
> MdeModulePkg/MdeModulePkg.dec | 5 +++++
> 3 files changed, 13 insertions(+)
>
> diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> index 19b8a4c8aefa..106b679b6bd0 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> @@ -117,6 +117,7 @@
> gEfiMdeModulePkgTokenSpaceGuid.PcdUse5LevelPageTable ##
> SOMETIMES_CONSUMES
> gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ##
> CONSUMES
> gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize ##
> CONSUMES
> + gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed ##
> CONSUMES
>
> [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
> gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ##
> SOMETIMES_CONSUMES
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> index 0700f310b203..5c647c74e773 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> @@ -159,6 +159,13 @@ IsEnableNonExecNeeded (
> return FALSE;
> }
>
> + //
> + // Intel TDX sets this flag to FALSE.
> + //
> + if (!PcdGetBool (PcdIa32EferChangeAllowed)) {
> + return FALSE;
> + }
> +
> //
> // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
> // Features controlled by Following PCDs need this feature to be enabled.
> diff --git a/MdeModulePkg/MdeModulePkg.dec
> b/MdeModulePkg/MdeModulePkg.dec
> index 463e889e9a68..453f2a74b11d 100644
> --- a/MdeModulePkg/MdeModulePkg.dec
> +++ b/MdeModulePkg/MdeModulePkg.dec
> @@ -2138,6 +2138,11 @@
> # @Prompt GHCB Pool Size
> gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0|UINT64|0x00030008
>
> + ## This dynamic PCD indicates if IA32_EFER can be changed. The default value
> is TRUE but in
> + # Intel TDX change of IA32_EFER is not allowed.
> + # @Prompt The flag which indicates if IA32_EFER is allowed to be changed.
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed|TRUE|BOOLEA
> N|0x00030009
> +
> [PcdsDynamicEx]
> ## This dynamic PCD enables the default variable setting.
> # Its value is the default store ID value. The default value is zero as Standard
> default.
> --
> 2.29.2.windows.2
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH V7 25/37] MdeModulePkg: EFER should not be changed in TDX
2022-03-03 3:11 ` Wang, Jian J
@ 2022-03-04 0:18 ` Min Xu
2022-03-04 1:36 ` Wang, Jian J
0 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-03-04 0:18 UTC (permalink / raw)
To: Wang, Jian J, devel@edk2.groups.io
Cc: Wu, Hao A, Brijesh Singh, Aktas, Erdem, James Bottomley,
Yao, Jiewen, Tom Lendacky, Gerd Hoffmann
On March 3, 2022 11:12 AM, Wang Jian wrote:
>
> Hi Min,
>
> I think the PCD should not be dynamic. Dynamic PCD is used for those
> features which can be changed at boot time. But, for Intel processor, it
> should always stay as FALSE. So there's no need to make it dynamic.
> FixedAtBuild should be fine.
>
I realize this PCD is not necessary. According to [TDX] Sec 10.1.5, IA32_EFER.NXE is initialized to 1. So in the function EnableExecuteDisableBit @ MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c, we can check if BIT11 is set before calling AsmWriteMsr64. It looks like:
VOID EnableExecuteDisableBit ( VOID )
{
UINT64 MsrRegisters;
MsrRegisters = AsmReadMsr64 (0xC0000080);
if ((MsrRegisters & BIT11) == 0) {
MsrRegisters |= BIT11;
AsmWriteMsr64 (0xC0000080, MsrRegisters);
}
}
[TDX] https://www.intel.com/content/dam/develop/external/us/en/documents/tdx-module-1.0-public-spec-v0.931.pdf
Thanks
Min
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH V7 25/37] MdeModulePkg: EFER should not be changed in TDX
2022-03-04 0:18 ` Min Xu
@ 2022-03-04 1:36 ` Wang, Jian J
0 siblings, 0 replies; 72+ messages in thread
From: Wang, Jian J @ 2022-03-04 1:36 UTC (permalink / raw)
To: Xu, Min M, devel@edk2.groups.io
Cc: Wu, Hao A, Brijesh Singh, Aktas, Erdem, James Bottomley,
Yao, Jiewen, Tom Lendacky, Gerd Hoffmann
Ok for me.
Regards,
Jian
> -----Original Message-----
> From: Xu, Min M <min.m.xu@intel.com>
> Sent: Friday, March 04, 2022 8:19 AM
> To: Wang, Jian J <jian.j.wang@intel.com>; devel@edk2.groups.io
> Cc: Wu, Hao A <hao.a.wu@intel.com>; Brijesh Singh <brijesh.singh@amd.com>;
> Aktas, Erdem <erdemaktas@google.com>; James Bottomley
> <jejb@linux.ibm.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky
> <thomas.lendacky@amd.com>; Gerd Hoffmann <kraxel@redhat.com>
> Subject: RE: [PATCH V7 25/37] MdeModulePkg: EFER should not be changed in
> TDX
>
> On March 3, 2022 11:12 AM, Wang Jian wrote:
> >
> > Hi Min,
> >
> > I think the PCD should not be dynamic. Dynamic PCD is used for those
> > features which can be changed at boot time. But, for Intel processor, it
> > should always stay as FALSE. So there's no need to make it dynamic.
> > FixedAtBuild should be fine.
> >
> I realize this PCD is not necessary. According to [TDX] Sec 10.1.5,
> IA32_EFER.NXE is initialized to 1. So in the function EnableExecuteDisableBit @
> MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c, we can check if BIT11
> is set before calling AsmWriteMsr64. It looks like:
> VOID EnableExecuteDisableBit ( VOID )
> {
> UINT64 MsrRegisters;
>
> MsrRegisters = AsmReadMsr64 (0xC0000080);
> if ((MsrRegisters & BIT11) == 0) {
> MsrRegisters |= BIT11;
> AsmWriteMsr64 (0xC0000080, MsrRegisters);
> }
> }
>
> [TDX]
> https://www.intel.com/content/dam/develop/external/us/en/documents/tdx-
> module-1.0-public-spec-v0.931.pdf
>
> Thanks
> Min
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH V7 26/37] MdeModulePkg: Add PcdTdxSharedBitMask
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (24 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 25/37] MdeModulePkg: EFER should not be changed in TDX Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-03-03 3:27 ` Wang, Jian J
2022-02-28 7:20 ` [PATCH V7 27/37] UefiCpuPkg: Update AddressEncMask in CpuPageTable Min Xu
` (11 subsequent siblings)
37 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Jian J Wang, Hao A Wu, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
Guest Physical Address (GPA) space in Td guest is divided into private
and shared sub-spaces, determined by the SHARED bit of GPA. This PCD
holds the shared bit mask. Its default value is 0 and it will be set
in PlatformPei driver if it is of Td guest.
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
MdeModulePkg/MdeModulePkg.dec | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 453f2a74b11d..e90a7f38708c 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -2143,6 +2143,10 @@
# @Prompt The flag which indicates if IA32_EFER is allowed to be changed.
gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed|TRUE|BOOLEAN|0x00030009
+ ## This PCD holds the shared bit mask for page table entries when Tdx is enabled.
+ # @Prompt The shared bit mask when Intel Tdx is enabled.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask|0x0|UINT64|0x0003000a
+
[PcdsDynamicEx]
## This dynamic PCD enables the default variable setting.
# Its value is the default store ID value. The default value is zero as Standard default.
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* Re: [PATCH V7 26/37] MdeModulePkg: Add PcdTdxSharedBitMask
2022-02-28 7:20 ` [PATCH V7 26/37] MdeModulePkg: Add PcdTdxSharedBitMask Min Xu
@ 2022-03-03 3:27 ` Wang, Jian J
2022-03-04 1:34 ` Min Xu
0 siblings, 1 reply; 72+ messages in thread
From: Wang, Jian J @ 2022-03-03 3:27 UTC (permalink / raw)
To: Xu, Min M, devel@edk2.groups.io
Cc: Wu, Hao A, Brijesh Singh, Aktas, Erdem, James Bottomley,
Yao, Jiewen, Tom Lendacky, Gerd Hoffmann
Hi Min,
Similar to patch 25, I don't see the needs to make this PCD dynamic only.
Do you have any strong reasons? If not sure, maybe it'd be better to put
it under following section.
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
Regards,
Jian
> -----Original Message-----
> From: Xu, Min M <min.m.xu@intel.com>
> Sent: Monday, February 28, 2022 3:21 PM
> To: devel@edk2.groups.io
> Cc: Xu, Min M <min.m.xu@intel.com>; Wang, Jian J <jian.j.wang@intel.com>;
> Wu, Hao A <hao.a.wu@intel.com>; Brijesh Singh <brijesh.singh@amd.com>;
> Aktas, Erdem <erdemaktas@google.com>; James Bottomley
> <jejb@linux.ibm.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky
> <thomas.lendacky@amd.com>; Gerd Hoffmann <kraxel@redhat.com>
> Subject: [PATCH V7 26/37] MdeModulePkg: Add PcdTdxSharedBitMask
>
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
>
> Guest Physical Address (GPA) space in Td guest is divided into private
> and shared sub-spaces, determined by the SHARED bit of GPA. This PCD
> holds the shared bit mask. Its default value is 0 and it will be set
> in PlatformPei driver if it is of Td guest.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Hao A Wu <hao.a.wu@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>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Acked-by: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>
> ---
> MdeModulePkg/MdeModulePkg.dec | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/MdeModulePkg/MdeModulePkg.dec
> b/MdeModulePkg/MdeModulePkg.dec
> index 453f2a74b11d..e90a7f38708c 100644
> --- a/MdeModulePkg/MdeModulePkg.dec
> +++ b/MdeModulePkg/MdeModulePkg.dec
> @@ -2143,6 +2143,10 @@
> # @Prompt The flag which indicates if IA32_EFER is allowed to be changed.
>
> gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed|TRUE|BOOLEA
> N|0x00030009
>
> + ## This PCD holds the shared bit mask for page table entries when Tdx is
> enabled.
> + # @Prompt The shared bit mask when Intel Tdx is enabled.
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask|0x0|UINT64|0x000
> 3000a
> +
> [PcdsDynamicEx]
> ## This dynamic PCD enables the default variable setting.
> # Its value is the default store ID value. The default value is zero as Standard
> default.
> --
> 2.29.2.windows.2
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH V7 26/37] MdeModulePkg: Add PcdTdxSharedBitMask
2022-03-03 3:27 ` Wang, Jian J
@ 2022-03-04 1:34 ` Min Xu
0 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-03-04 1:34 UTC (permalink / raw)
To: Wang, Jian J, devel@edk2.groups.io
Cc: Wu, Hao A, Brijesh Singh, Aktas, Erdem, James Bottomley,
Yao, Jiewen, Tom Lendacky, Gerd Hoffmann
On March 3, 2022 11:27 AM, Wang, Jian wrote:
> Hi Min,
>
> Similar to patch 25, I don't see the needs to make this PCD dynamic only.
> Do you have any strong reasons? If not sure, maybe it'd be better to put it
> under following section.
>
> [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
>
Thanks for reminder. It will be updated in the next version.
Thanks
Min
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH V7 27/37] UefiCpuPkg: Update AddressEncMask in CpuPageTable
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (25 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 26/37] MdeModulePkg: Add PcdTdxSharedBitMask Min Xu
@ 2022-02-28 7:20 ` Min Xu
2022-03-15 8:03 ` [edk2-devel] " Ni, Ray
2022-02-28 7:21 ` [PATCH V7 28/37] OvmfPkg: Update PlatformInitLib for Tdx guest to publish ram regions Min Xu
` (10 subsequent siblings)
37 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:20 UTC (permalink / raw)
To: devel
Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
MMIO region in Tdx guest is set with PcdTdxSharedBitMask in TdxDxe's
entry point. In SEV guest the page table entries is set with
PcdPteMemoryEncryptionAddressOrMask when creating 1:1 identity table.
So the AddressEncMask in GetPageTableEntry (@CpuPageTable.c) is either
PcdPteMemoryEncryptionAddressOrMask (in SEV guest), or
PcdTdxSharedBitMask (in TDX guest), or all-0 (in Legacy guest).
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>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
UefiCpuPkg/CpuDxe/CpuDxe.inf | 1 +
UefiCpuPkg/CpuDxe/CpuPageTable.c | 4 ++++
2 files changed, 5 insertions(+)
diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf
index d87fe503d152..235241899222 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.inf
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf
@@ -80,6 +80,7 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask ## CONSUMES
[Depex]
TRUE
diff --git a/UefiCpuPkg/CpuDxe/CpuPageTable.c b/UefiCpuPkg/CpuDxe/CpuPageTable.c
index d9e65ab4b22a..28982936fade 100644
--- a/UefiCpuPkg/CpuDxe/CpuPageTable.c
+++ b/UefiCpuPkg/CpuDxe/CpuPageTable.c
@@ -307,6 +307,9 @@ GetPageTableEntry (
// Make sure AddressEncMask is contained to smallest supported address field.
//
AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+ if (AddressEncMask == 0) {
+ AddressEncMask = PcdGet64 (PcdTdxSharedBitMask) & PAGING_1G_ADDRESS_MASK_64;
+ }
if (PagingContext->MachineType == IMAGE_FILE_MACHINE_X64) {
if ((PagingContext->ContextData.X64.Attributes & PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_5_LEVEL) != 0) {
@@ -357,6 +360,7 @@ GetPageTableEntry (
// 4k
L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+
if ((L1PageTable[Index1] == 0) && (Address != 0)) {
*PageAttribute = PageNone;
return NULL;
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 27/37] UefiCpuPkg: Update AddressEncMask in CpuPageTable
2022-02-28 7:20 ` [PATCH V7 27/37] UefiCpuPkg: Update AddressEncMask in CpuPageTable Min Xu
@ 2022-03-15 8:03 ` Ni, Ray
2022-03-16 5:35 ` Min Xu
0 siblings, 1 reply; 72+ messages in thread
From: Ni, Ray @ 2022-03-15 8:03 UTC (permalink / raw)
To: Min Xu, devel
[-- Attachment #1: Type: text/plain, Size: 190 bytes --]
Can you please remove the empty line added in GetPageTableEntry()? Can you please check whether it can pass uncrustify check?
With that addressed, Reviewed-by: Ray Ni <ray.ni@intel.com>
[-- Attachment #2: Type: text/html, Size: 256 bytes --]
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 27/37] UefiCpuPkg: Update AddressEncMask in CpuPageTable
2022-03-15 8:03 ` [edk2-devel] " Ni, Ray
@ 2022-03-16 5:35 ` Min Xu
0 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-03-16 5:35 UTC (permalink / raw)
To: Ni, Ray, devel@edk2.groups.io
[-- Attachment #1: Type: text/plain, Size: 523 bytes --]
Sure. The empty line will be removed in the next version in the next version.
From: Ni, Ray <ray.ni@intel.com>
Sent: Tuesday, March 15, 2022 4:03 PM
To: Xu, Min M <min.m.xu@intel.com>; devel@edk2.groups.io
Subject: Re: [edk2-devel] [PATCH V7 27/37] UefiCpuPkg: Update AddressEncMask in CpuPageTable
Can you please remove the empty line added in GetPageTableEntry()? Can you please check whether it can pass uncrustify check?
With that addressed, Reviewed-by: Ray Ni ray.ni@intel.com<mailto:ray.ni@intel.com>
[-- Attachment #2: Type: text/html, Size: 2631 bytes --]
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH V7 28/37] OvmfPkg: Update PlatformInitLib for Tdx guest to publish ram regions
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (26 preceding siblings ...)
2022-02-28 7:20 ` [PATCH V7 27/37] UefiCpuPkg: Update AddressEncMask in CpuPageTable Min Xu
@ 2022-02-28 7:21 ` Min Xu
2022-03-01 13:12 ` Gerd Hoffmann
2022-02-28 7:21 ` [PATCH V7 29/37] OvmfPkg: Update PlatformPei to support Tdx guest Min Xu
` (9 subsequent siblings)
37 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:21 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
In Tdx guest, the system memory is passed in TdHob by host VMM. So
the major task of PlatformTdxPublishRamRegions is to walk thru the
TdHob list and transfer the ResourceDescriptorHob and MemoryAllocationHob
to the hobs in DXE phase.
MemoryAllocationHob should also be created for Mailbox and Ovmf work area.
Another update is in PlatformAddressWidthInitialization. The physical
address width that Tdx guest supports is either 48 or 52.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Include/Library/PlatformInitLib.h | 14 ++++++
OvmfPkg/Library/PlatformInitLib/IntelTdx.c | 49 +++++++++++++++++++
.../Library/PlatformInitLib/IntelTdxNull.c | 16 ++++++
OvmfPkg/Library/PlatformInitLib/MemDetect.c | 13 +++++
4 files changed, 92 insertions(+)
diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
index 538fd7aee48c..6a88a9b4a69c 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -269,4 +269,18 @@ ProcessTdxHobList (
VOID
);
+/**
+ In Tdx guest, the system memory is passed in TdHob by host VMM. So
+ the major task of PlatformTdxPublishRamRegions is to walk thru the
+ TdHob list and transfer the ResourceDescriptorHob and MemoryAllocationHob
+ to the hobs in DXE phase.
+
+ MemoryAllocationHob should also be created for Mailbox and Ovmf work area.
+**/
+VOID
+EFIAPI
+PlatformTdxPublishRamRegions (
+ VOID
+ );
+
#endif // PLATFORM_INIT_LIB_H_
diff --git a/OvmfPkg/Library/PlatformInitLib/IntelTdx.c b/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
index 1ee24dfe754d..e9243cfa7e37 100644
--- a/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
+++ b/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
@@ -502,3 +502,52 @@ TransferTdxHobList (
Hob.Raw = GET_NEXT_HOB (Hob);
}
}
+
+/**
+ In Tdx guest, the system memory is passed in TdHob by host VMM. So
+ the major task of PlatformTdxPublishRamRegions is to walk thru the
+ TdHob list and transfer the ResourceDescriptorHob and MemoryAllocationHob
+ to the hobs in DXE phase.
+
+ MemoryAllocationHob should also be created for Mailbox and Ovmf work area.
+**/
+VOID
+EFIAPI
+PlatformTdxPublishRamRegions (
+ VOID
+ )
+{
+ if (!TdIsEnabled ()) {
+ return;
+ }
+
+ TransferTdxHobList ();
+
+ //
+ // The memory region defined by PcdOvmfSecGhcbBackupBase is pre-allocated by
+ // host VMM and used as the td mailbox at the beginning of system boot.
+ //
+ BuildMemoryAllocationHob (
+ FixedPcdGet32 (PcdOvmfSecGhcbBackupBase),
+ FixedPcdGet32 (PcdOvmfSecGhcbBackupSize),
+ EfiACPIMemoryNVS
+ );
+
+ if (FixedPcdGet32 (PcdOvmfWorkAreaSize) != 0) {
+ //
+ // Reserve the work area.
+ //
+ // Since this memory range will be used by the Reset Vector on S3
+ // resume, it must be reserved as ACPI NVS.
+ //
+ // If S3 is unsupported, then various drivers might still write to the
+ // work area. We ought to prevent DXE from serving allocation requests
+ // such that they would overlap the work area.
+ //
+ BuildMemoryAllocationHob (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaBase),
+ (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaSize),
+ EfiBootServicesData
+ );
+ }
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c b/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
index af90e0866e89..3ebe582af8de 100644
--- a/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
+++ b/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
@@ -28,3 +28,19 @@ ProcessTdxHobList (
{
return EFI_UNSUPPORTED;
}
+
+/**
+ In Tdx guest, the system memory is passed in TdHob by host VMM. So
+ the major task of PlatformTdxPublishRamRegions is to walk thru the
+ TdHob list and transfer the ResourceDescriptorHob and MemoryAllocationHob
+ to the hobs in DXE phase.
+
+ MemoryAllocationHob should also be created for Mailbox and Ovmf work area.
+**/
+VOID
+EFIAPI
+PlatformTdxPublishRamRegions (
+ VOID
+ )
+{
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
index 5a9cb6e638ed..af4c851d479d 100644
--- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c
+++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
@@ -34,6 +34,7 @@ Module Name:
#include <Library/MtrrLib.h>
#include <Library/QemuFwCfgLib.h>
#include <Library/QemuFwCfgSimpleParserLib.h>
+#include <Library/TdxLib.h>
#include <Library/PlatformInitLib.h>
@@ -481,7 +482,19 @@ PlatformAddressWidthInitialization (
PhysMemAddressWidth = 36;
}
+ #if defined (MDE_CPU_X64)
+ if (TdIsEnabled ()) {
+ if (TdSharedPageMask () == (1ULL << 47)) {
+ PhysMemAddressWidth = 48;
+ } else {
+ PhysMemAddressWidth = 52;
+ }
+ }
+
+ ASSERT (PhysMemAddressWidth <= 52);
+ #else
ASSERT (PhysMemAddressWidth <= 48);
+ #endif
return PhysMemAddressWidth;
}
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* Re: [PATCH V7 28/37] OvmfPkg: Update PlatformInitLib for Tdx guest to publish ram regions
2022-02-28 7:21 ` [PATCH V7 28/37] OvmfPkg: Update PlatformInitLib for Tdx guest to publish ram regions Min Xu
@ 2022-03-01 13:12 ` Gerd Hoffmann
0 siblings, 0 replies; 72+ messages in thread
From: Gerd Hoffmann @ 2022-03-01 13:12 UTC (permalink / raw)
To: Min Xu
Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky
On Mon, Feb 28, 2022 at 03:21:00PM +0800, Min Xu wrote:
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
>
> In Tdx guest, the system memory is passed in TdHob by host VMM. So
> the major task of PlatformTdxPublishRamRegions is to walk thru the
> TdHob list and transfer the ResourceDescriptorHob and MemoryAllocationHob
> to the hobs in DXE phase.
>
> MemoryAllocationHob should also be created for Mailbox and Ovmf work area.
>
> Another update is in PlatformAddressWidthInitialization. The physical
> address width that Tdx guest supports is either 48 or 52.
>
> 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>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH V7 29/37] OvmfPkg: Update PlatformPei to support Tdx guest
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (27 preceding siblings ...)
2022-02-28 7:21 ` [PATCH V7 28/37] OvmfPkg: Update PlatformInitLib for Tdx guest to publish ram regions Min Xu
@ 2022-02-28 7:21 ` Min Xu
2022-03-01 13:13 ` Gerd Hoffmann
2022-02-28 7:21 ` [PATCH V7 30/37] OvmfPkg: Update AcpiPlatformDxe to alter MADT table Min Xu
` (8 subsequent siblings)
37 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:21 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
OvmfPkg/PlatformPei is updated to support Tdx guest. There are below
major changes.
- Set Tdx related PCDs
- Publish Tdx RamRegions
In this patch there is another new function BuildPlatformInfoHob ().
This function builds EFI_HOB_PLATFORM_INFO which contains the
HostBridgeDevId. The hob is built in both Td guest and Non-Td guest.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/OvmfPkg.dec | 1 +
OvmfPkg/PlatformPei/FeatureControl.c | 7 +++-
OvmfPkg/PlatformPei/IntelTdx.c | 54 ++++++++++++++++++++++++++++
OvmfPkg/PlatformPei/MemDetect.c | 13 +++++--
OvmfPkg/PlatformPei/Platform.c | 18 ++++++++++
OvmfPkg/PlatformPei/Platform.h | 19 ++++++++++
OvmfPkg/PlatformPei/PlatformPei.inf | 4 +++
7 files changed, 113 insertions(+), 3 deletions(-)
create mode 100644 OvmfPkg/PlatformPei/IntelTdx.c
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index f3d06411b51b..746050d64ba7 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -133,6 +133,7 @@
gGrubFileGuid = {0xb5ae312c, 0xbc8a, 0x43b1, {0x9c, 0x62, 0xeb, 0xb8, 0x26, 0xdd, 0x5d, 0x07}}
gConfidentialComputingSecretGuid = {0xadf956ad, 0xe98c, 0x484c, {0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47}}
gConfidentialComputingSevSnpBlobGuid = {0x067b1f5f, 0xcf26, 0x44c5, {0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42}}
+ gUefiOvmfPkgPlatformInfoGuid = {0xdec9b486, 0x1f16, 0x47c7, {0x8f, 0x68, 0xdf, 0x1a, 0x41, 0x88, 0x8b, 0xa5}}
[Ppis]
# PPI whose presence in the PPI database signals that the TPM base address
diff --git a/OvmfPkg/PlatformPei/FeatureControl.c b/OvmfPkg/PlatformPei/FeatureControl.c
index 9af58c2655f8..5864ee0c214d 100644
--- a/OvmfPkg/PlatformPei/FeatureControl.c
+++ b/OvmfPkg/PlatformPei/FeatureControl.c
@@ -12,6 +12,7 @@
#include <Library/QemuFwCfgLib.h>
#include <Ppi/MpServices.h>
#include <Register/ArchitecturalMsr.h>
+#include <IndustryStandard/Tdx.h>
#include "Platform.h"
@@ -37,7 +38,11 @@ WriteFeatureControl (
IN OUT VOID *WorkSpace
)
{
- AsmWriteMsr64 (MSR_IA32_FEATURE_CONTROL, mFeatureControlValue);
+ if (TdIsEnabled ()) {
+ TdVmCall (TDVMCALL_WRMSR, (UINT64)MSR_IA32_FEATURE_CONTROL, mFeatureControlValue, 0, 0, 0);
+ } else {
+ AsmWriteMsr64 (MSR_IA32_FEATURE_CONTROL, mFeatureControlValue);
+ }
}
/**
diff --git a/OvmfPkg/PlatformPei/IntelTdx.c b/OvmfPkg/PlatformPei/IntelTdx.c
new file mode 100644
index 000000000000..dabb35dadeff
--- /dev/null
+++ b/OvmfPkg/PlatformPei/IntelTdx.c
@@ -0,0 +1,54 @@
+/** @file
+ Initialize Intel TDX support.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <IndustryStandard/QemuFwCfg.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/TdxLib.h>
+#include <Library/PlatformInitLib.h>
+#include <WorkArea.h>
+#include <ConfidentialComputingGuestAttr.h>
+#include "Platform.h"
+
+/**
+ This Function checks if TDX is available, if present then it sets
+ the dynamic PCDs for Tdx guest.
+ **/
+VOID
+IntelTdxInitialize (
+ VOID
+ )
+{
+ #ifdef MDE_CPU_X64
+ RETURN_STATUS PcdStatus;
+
+ if (!TdIsEnabled ()) {
+ return;
+ }
+
+ PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, CCAttrIntelTdx);
+ ASSERT_RETURN_ERROR (PcdStatus);
+
+ PcdStatus = PcdSetBoolS (PcdIa32EferChangeAllowed, FALSE);
+ ASSERT_RETURN_ERROR (PcdStatus);
+
+ PcdStatus = PcdSet64S (PcdTdxSharedBitMask, TdSharedPageMask ());
+ ASSERT_RETURN_ERROR (PcdStatus);
+
+ PcdStatus = PcdSetBoolS (PcdSetNxForStack, TRUE);
+ ASSERT_RETURN_ERROR (PcdStatus);
+ #endif
+}
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index 9b62625f9d91..b610885d6f31 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -37,7 +37,6 @@ Module Name:
#include <Library/QemuFwCfgLib.h>
#include <Library/QemuFwCfgSimpleParserLib.h>
#include <Library/PlatformInitLib.h>
-
#include "Platform.h"
UINT8 mPhysMemAddressWidth;
@@ -219,7 +218,12 @@ GetPeiMemoryCap (
PdpEntries = 1 << (mPhysMemAddressWidth - 30);
ASSERT (PdpEntries <= 0x200);
} else {
- Pml4Entries = 1 << (mPhysMemAddressWidth - 39);
+ if (mPhysMemAddressWidth > 48) {
+ Pml4Entries = 0x200;
+ } else {
+ Pml4Entries = 1 << (mPhysMemAddressWidth - 39);
+ }
+
ASSERT (Pml4Entries <= 0x200);
PdpEntries = 512;
}
@@ -334,6 +338,11 @@ InitializeRamRegions (
VOID
)
{
+ if (TdIsEnabled ()) {
+ PlatformTdxPublishRamRegions ();
+ return;
+ }
+
PlatformInitializeRamRegions (
mQemuUc32Base,
mHostBridgeDevId,
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 5f175bf7014d..bf144e1a62b6 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -367,6 +367,22 @@ MaxCpuCountInitialization (
ASSERT_RETURN_ERROR (PcdStatus);
}
+/**
+ * @brief Builds PlatformInfo Hob
+ */
+VOID
+BuildPlatformInfoHob (
+ VOID
+ )
+{
+ EFI_HOB_PLATFORM_INFO PlatformInfoHob;
+
+ ZeroMem (&PlatformInfoHob, sizeof (PlatformInfoHob));
+ PlatformInfoHob.HostBridgePciDevId = mHostBridgeDevId;
+
+ BuildGuidDataHob (&gUefiOvmfPkgPlatformInfoGuid, &PlatformInfoHob, sizeof (EFI_HOB_PLATFORM_INFO));
+}
+
/**
Perform Platform PEI initialization.
@@ -437,8 +453,10 @@ InitializePlatform (
InstallClearCacheCallback ();
AmdSevInitialize ();
+ IntelTdxInitialize ();
MiscInitialization ();
InstallFeatureControlCallback ();
+ BuildPlatformInfoHob ();
return EFI_SUCCESS;
}
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index 64af9cde1002..7105d4288062 100644
--- a/OvmfPkg/PlatformPei/Platform.h
+++ b/OvmfPkg/PlatformPei/Platform.h
@@ -10,6 +10,7 @@
#define _PLATFORM_PEI_H_INCLUDED_
#include <IndustryStandard/E820.h>
+#include <IndustryStandard/IntelTdx.h>
VOID
AddressWidthInitialization (
@@ -66,6 +67,24 @@ AmdSevInitialize (
VOID
);
+/**
+ This Function checks if TDX is available, if present then it sets
+ the dynamic PCDs for Tdx guest. It also builds Guid hob which contains
+ the Host Bridge DevId.
+ **/
+VOID
+IntelTdxInitialize (
+ VOID
+ );
+
+/**
+ * @brief Builds PlatformInfo Hob
+ */
+VOID
+BuildPlatformInfoHob (
+ VOID
+ );
+
extern EFI_BOOT_MODE mBootMode;
VOID
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 65e417b2f254..bd99f944f050 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -31,6 +31,7 @@
MemTypeInfo.c
Platform.c
Platform.h
+ IntelTdx.c
[Packages]
EmbeddedPkg/EmbeddedPkg.dec
@@ -43,6 +44,7 @@
[Guids]
gEfiMemoryTypeInformationGuid
gFdtHobGuid
+ gUefiOvmfPkgPlatformInfoGuid
[LibraryClasses]
BaseLib
@@ -109,6 +111,8 @@
gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled
gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr
gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures
+ gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask
[FixedPcd]
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* Re: [PATCH V7 29/37] OvmfPkg: Update PlatformPei to support Tdx guest
2022-02-28 7:21 ` [PATCH V7 29/37] OvmfPkg: Update PlatformPei to support Tdx guest Min Xu
@ 2022-03-01 13:13 ` Gerd Hoffmann
0 siblings, 0 replies; 72+ messages in thread
From: Gerd Hoffmann @ 2022-03-01 13:13 UTC (permalink / raw)
To: Min Xu
Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky
On Mon, Feb 28, 2022 at 03:21:01PM +0800, Min Xu wrote:
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
>
> OvmfPkg/PlatformPei is updated to support Tdx guest. There are below
> major changes.
> - Set Tdx related PCDs
> - Publish Tdx RamRegions
>
> In this patch there is another new function BuildPlatformInfoHob ().
> This function builds EFI_HOB_PLATFORM_INFO which contains the
> HostBridgeDevId. The hob is built in both Td guest and Non-Td guest.
>
> 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>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH V7 30/37] OvmfPkg: Update AcpiPlatformDxe to alter MADT table
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (28 preceding siblings ...)
2022-02-28 7:21 ` [PATCH V7 29/37] OvmfPkg: Update PlatformPei to support Tdx guest Min Xu
@ 2022-02-28 7:21 ` Min Xu
2022-02-28 7:21 ` [PATCH V7 31/37] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library Min Xu
` (7 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:21 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
In TDX the guest firmware is designed to publish a multiprocessor-wakeup
structure to let the guest-bootstrap processor wake up guest-application
processors with a mailbox. The mailbox is memory that the guest firmware
can reserve so each guest virtual processor can have the guest OS send
a message to them. The address of the mailbox is recorded in the MADT
table. See [ACPI].
To maintain the simplicity of the AcpiPlatformDxe, the MADT ACPI table
will be altered in another driver (TdxDxe) by installing a protocol
to notify that the ACPI table provided by Qemu is ready. Then in TdxDxe
a notification functioin will be called to alter the MADT table to recorded
the mailbox address.
The protocol is gQemuAcpiTableNotifyProtocolGuid.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf | 1 +
OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c | 14 +++++++++-
.../Include/Protocol/QemuAcpiTableNotify.h | 27 +++++++++++++++++++
3 files changed, 41 insertions(+), 1 deletion(-)
create mode 100644 OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h
diff --git a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
index b36b8413e007..e839e37e935b 100644
--- a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
+++ b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
@@ -49,6 +49,7 @@
[Protocols]
gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiPciIoProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
+ gQemuAcpiTableNotifyProtocolGuid # PROTOCOL PRODUCES
[Guids]
gRootBridgesConnectedEventGroupGuid
diff --git a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
index b885965a601e..c8dee17c13e6 100644
--- a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
+++ b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
@@ -19,7 +19,10 @@
#include <Library/QemuFwCfgS3Lib.h> // QemuFwCfgS3Enabled()
#include <Library/UefiBootServicesTableLib.h> // gBS
+#include <Protocol/QemuAcpiTableNotify.h>
#include "AcpiPlatform.h"
+EFI_HANDLE mQemuAcpiHandle = NULL;
+QEMU_ACPI_TABLE_NOTIFY_PROTOCOL mAcpiNotifyProtocol;
//
// The user structure for the ordered collection that will track the fw_cfg
@@ -1273,7 +1276,16 @@ UninstallAcpiTables:
AcpiProtocol->UninstallAcpiTable (AcpiProtocol, InstalledKey[Installed]);
}
} else {
- DEBUG ((DEBUG_INFO, "%a: installed %d tables\n", __FUNCTION__, Installed));
+ //
+ // Install a protocol to notify that the ACPI table provided by Qemu is
+ // ready.
+ //
+ gBS->InstallProtocolInterface (
+ &mQemuAcpiHandle,
+ &gQemuAcpiTableNotifyProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mAcpiNotifyProtocol
+ );
}
for (SeenPointerEntry = OrderedCollectionMin (SeenPointers);
diff --git a/OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h b/OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h
new file mode 100644
index 000000000000..a3dd2fc1dc91
--- /dev/null
+++ b/OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h
@@ -0,0 +1,27 @@
+/** @file
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef QEMU_ACPI_TABLE_NOTIFY_H_
+#define QEMU_ACPI_TABLE_NOTIFY_H_
+
+#define QEMU_ACPI_TABLE_NOTIFY_GUID \
+ { 0x928939b2, 0x4235, 0x462f, { 0x95, 0x80, 0xf6, 0xa2, 0xb2, 0xc2, 0x1a, 0x4f } };
+
+///
+/// Forward declaration
+///
+typedef struct _QEMU_ACPI_TABLE_NOTIFY_PROTOCOL QEMU_ACPI_TABLE_NOTIFY_PROTOCOL;
+
+///
+/// Protocol structure
+///
+struct _QEMU_ACPI_TABLE_NOTIFY_PROTOCOL {
+ UINT8 Notify;
+};
+
+extern EFI_GUID gQemuAcpiTableNotifyProtocolGuid;
+
+#endif
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 31/37] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (29 preceding siblings ...)
2022-02-28 7:21 ` [PATCH V7 30/37] OvmfPkg: Update AcpiPlatformDxe to alter MADT table Min Xu
@ 2022-02-28 7:21 ` Min Xu
2022-02-28 7:21 ` [PATCH V7 32/37] OvmfPkg: Add TdxDxe driver Min Xu
` (6 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:21 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
Add Intel Tdx helper library. The library provides the routines to:
- set or clear Shared bit for a given memory region.
- query whether TDX is enabled.
Please be noted, there a lot of duplicated codes for Page Table
operations. These codes should be moved to a common library
(PageTablesLib) so that it is more friendly for review and maintain.
There is a new feature requirement
https://bugzilla.tianocore.org/show_bug.cgi?id=847 which is to
implement the library. After the lib is introduced, BaseMemEncryptTdxLib
will be refactored.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Include/Library/MemEncryptTdxLib.h | 81 ++
.../BaseMemEncryptTdxLib.inf | 44 +
.../BaseMemEncryptTdxLibNull.inf | 35 +
.../BaseMemoryEncryptionNull.c | 90 ++
.../BaseMemEncryptTdxLib/MemoryEncryption.c | 948 ++++++++++++++++++
.../BaseMemEncryptTdxLib/VirtualMemory.h | 181 ++++
OvmfPkg/OvmfPkg.dec | 4 +
OvmfPkg/OvmfPkgIa32.dsc | 1 +
OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
9 files changed, 1385 insertions(+)
create mode 100644 OvmfPkg/Include/Library/MemEncryptTdxLib.h
create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h
diff --git a/OvmfPkg/Include/Library/MemEncryptTdxLib.h b/OvmfPkg/Include/Library/MemEncryptTdxLib.h
new file mode 100644
index 000000000000..2350dd47bc30
--- /dev/null
+++ b/OvmfPkg/Include/Library/MemEncryptTdxLib.h
@@ -0,0 +1,81 @@
+/** @file
+
+ Define Memory Encrypted Virtualization base library helper function
+
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MEM_ENCRYPT_TDX_LIB_H_
+#define MEM_ENCRYPT_TDX_LIB_H_
+
+#include <Base.h>
+
+/**
+ Returns boolean to indicate whether to indicate which, if any, memory encryption is enabled
+
+ @param[in] Type Bitmask of encryption technologies to check is enabled
+
+ @retval TRUE The encryption type(s) are enabled
+ @retval FALSE The encryption type(s) are not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptTdxIsEnabled (
+ VOID
+ );
+
+/**
+ This function clears memory encryption bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+
+ @retval RETURN_SUCCESS The attributes were cleared for the
+ memory region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Clearing the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxSetPageSharedBit (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages
+ );
+
+/**
+ This function sets memory encryption bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+
+ @retval RETURN_SUCCESS The attributes were set for the memory
+ region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Setting the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxClearPageSharedBit (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages
+ );
+
+#endif // _MEM_ENCRYPT_TDX_LIB_H_
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
new file mode 100644
index 000000000000..a8abfec12fa3
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
@@ -0,0 +1,44 @@
+## @file
+# Library for TDX Memory Encryption
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = MemEncryptTdxLib
+ FILE_GUID = 7E6651B2-B775-4593-A410-FC05B8C61993
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MemEncryptTdxLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[Sources]
+ VirtualMemory.h
+ MemoryEncryption.c
+
+[LibraryClasses]
+ BaseLib
+ CacheMaintenanceLib
+ CpuLib
+ DebugLib
+ MemoryAllocationLib
+ PcdLib
+ TdxLib
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
new file mode 100644
index 000000000000..a050edb5b734
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
@@ -0,0 +1,35 @@
+## @file
+# Library for Memory Encryption
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2017 Advanced Micro Devices. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = MemEncryptTdxLibNull
+ FILE_GUID = 3C69C4CA-DE46-44D7-8AA5-6EE51A4E3EA7
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MemEncryptTdxLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES = X64 IA32
+#
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[Sources]
+ BaseMemoryEncryptionNull.c
+
+[LibraryClasses]
+ BaseLib
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
new file mode 100644
index 000000000000..137d4674d499
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
@@ -0,0 +1,90 @@
+/** @file
+
+ Virtual Memory Management Services to set or clear the memory encryption
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+
+**/
+
+#include <Uefi.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseLib.h>
+#include <Library/MemEncryptTdxLib.h>
+
+/**
+ Returns boolean to indicate whether to indicate which, if any, memory encryption is enabled
+
+ @param[in] Type Bitmask of encryption technologies to check is enabled
+
+ @retval TRUE The encryption type(s) are enabled
+ @retval FALSE The encryption type(s) are not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptTdxIsEnabled (
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ This function clears memory encryption bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+
+ @retval RETURN_SUCCESS The attributes were cleared for the
+ memory region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Clearing the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxSetPageSharedBit (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This function sets memory encryption bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+
+ @retval RETURN_SUCCESS The attributes were set for the memory
+ region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Setting the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxClearPageSharedBit (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c b/OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
new file mode 100644
index 000000000000..9d11c6e4df72
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
@@ -0,0 +1,948 @@
+/** @file
+
+ Virtual Memory Management Services to set or clear the memory encryption.
+
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+
+ Note:
+ There a lot of duplicated codes for Page Table operations. These
+ codes should be moved to a common library (PageTablesLib) so that it is
+ more friendly for review and maintain. There is a new feature requirement
+ https://bugzilla.tianocore.org/show_bug.cgi?id=847 which is to implement
+ the library. After the lib is introduced, this file will be refactored.
+
+**/
+
+#include <Uefi.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/CpuLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemEncryptTdxLib.h>
+#include "VirtualMemory.h"
+#include <IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
+#include <ConfidentialComputingGuestAttr.h>
+
+typedef enum {
+ SetSharedBit,
+ ClearSharedBit
+} TDX_PAGETABLE_MODE;
+
+STATIC PAGE_TABLE_POOL *mPageTablePool = NULL;
+
+/**
+ Returns boolean to indicate whether to indicate which, if any, memory encryption is enabled
+
+ @param[in] Type Bitmask of encryption technologies to check is enabled
+
+ @retval TRUE The encryption type(s) are enabled
+ @retval FALSE The encryption type(s) are not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptTdxIsEnabled (
+ VOID
+ )
+{
+ return CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr));
+}
+
+/**
+ Get the memory encryption mask
+
+ @param[out] EncryptionMask contains the pte mask.
+
+**/
+STATIC
+UINT64
+GetMemEncryptionAddressMask (
+ VOID
+ )
+{
+ return TdSharedPageMask ();
+}
+
+/**
+ Initialize a buffer pool for page table use only.
+
+ To reduce the potential split operation on page table, the pages reserved for
+ page table should be allocated in the times of PAGE_TABLE_POOL_UNIT_PAGES and
+ at the boundary of PAGE_TABLE_POOL_ALIGNMENT. So the page pool is always
+ initialized with number of pages greater than or equal to the given
+ PoolPages.
+
+ Once the pages in the pool are used up, this method should be called again to
+ reserve at least another PAGE_TABLE_POOL_UNIT_PAGES. Usually this won't
+ happen often in practice.
+
+ @param[in] PoolPages The least page number of the pool to be created.
+
+ @retval TRUE The pool is initialized successfully.
+ @retval FALSE The memory is out of resource.
+**/
+STATIC
+BOOLEAN
+InitializePageTablePool (
+ IN UINTN PoolPages
+ )
+{
+ VOID *Buffer;
+
+ //
+ // Always reserve at least PAGE_TABLE_POOL_UNIT_PAGES, including one page for
+ // header.
+ //
+ PoolPages += 1; // Add one page for header.
+ PoolPages = ((PoolPages - 1) / PAGE_TABLE_POOL_UNIT_PAGES + 1) *
+ PAGE_TABLE_POOL_UNIT_PAGES;
+ Buffer = AllocateAlignedPages (PoolPages, PAGE_TABLE_POOL_ALIGNMENT);
+ if (Buffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "ERROR: Out of aligned pages\r\n"));
+ return FALSE;
+ }
+
+ //
+ // Link all pools into a list for easier track later.
+ //
+ if (mPageTablePool == NULL) {
+ mPageTablePool = Buffer;
+ mPageTablePool->NextPool = mPageTablePool;
+ } else {
+ ((PAGE_TABLE_POOL *)Buffer)->NextPool = mPageTablePool->NextPool;
+ mPageTablePool->NextPool = Buffer;
+ mPageTablePool = Buffer;
+ }
+
+ //
+ // Reserve one page for pool header.
+ //
+ mPageTablePool->FreePages = PoolPages - 1;
+ mPageTablePool->Offset = EFI_PAGES_TO_SIZE (1);
+
+ return TRUE;
+}
+
+/**
+ This API provides a way to allocate memory for page table.
+
+ This API can be called more than once to allocate memory for page tables.
+
+ Allocates the number of 4KB pages and returns a pointer to the allocated
+ buffer. The buffer returned is aligned on a 4KB boundary.
+
+ If Pages is 0, then NULL is returned.
+ If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+STATIC
+VOID *
+EFIAPI
+AllocatePageTableMemory (
+ IN UINTN Pages
+ )
+{
+ VOID *Buffer;
+
+ if (Pages == 0) {
+ return NULL;
+ }
+
+ //
+ // Renew the pool if necessary.
+ //
+ if ((mPageTablePool == NULL) ||
+ (Pages > mPageTablePool->FreePages))
+ {
+ if (!InitializePageTablePool (Pages)) {
+ return NULL;
+ }
+ }
+
+ Buffer = (UINT8 *)mPageTablePool + mPageTablePool->Offset;
+
+ mPageTablePool->Offset += EFI_PAGES_TO_SIZE (Pages);
+ mPageTablePool->FreePages -= Pages;
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a:%a: Buffer=0x%Lx Pages=%ld\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ Buffer,
+ Pages
+ ));
+
+ return Buffer;
+}
+
+/**
+ Split 2M page to 4K.
+
+ @param[in] PhysicalAddress Start physical address the 2M page
+ covered.
+ @param[in, out] PageEntry2M Pointer to 2M page entry.
+ @param[in] StackBase Stack base address.
+ @param[in] StackSize Stack size.
+
+**/
+STATIC
+VOID
+Split2MPageTo4K (
+ IN PHYSICAL_ADDRESS PhysicalAddress,
+ IN OUT UINT64 *PageEntry2M,
+ IN PHYSICAL_ADDRESS StackBase,
+ IN UINTN StackSize,
+ IN UINT64 AddressEncMask
+ )
+{
+ PHYSICAL_ADDRESS PhysicalAddress4K;
+ UINTN IndexOfPageTableEntries;
+ PAGE_TABLE_4K_ENTRY *PageTableEntry, *PageTableEntry1;
+
+ PageTableEntry = AllocatePageTableMemory (1);
+
+ PageTableEntry1 = PageTableEntry;
+
+ if (PageTableEntry == NULL) {
+ ASSERT (FALSE);
+ return;
+ }
+
+ PhysicalAddress4K = PhysicalAddress;
+ for (IndexOfPageTableEntries = 0;
+ IndexOfPageTableEntries < 512;
+ (IndexOfPageTableEntries++,
+ PageTableEntry++,
+ PhysicalAddress4K += SIZE_4KB))
+ {
+ //
+ // Fill in the Page Table entries
+ //
+ PageTableEntry->Uint64 = (UINT64)PhysicalAddress4K | AddressEncMask;
+ PageTableEntry->Bits.ReadWrite = 1;
+ PageTableEntry->Bits.Present = 1;
+ if ((PhysicalAddress4K >= StackBase) &&
+ (PhysicalAddress4K < StackBase + StackSize))
+ {
+ //
+ // Set Nx bit for stack.
+ //
+ PageTableEntry->Bits.Nx = 1;
+ }
+ }
+
+ //
+ // Fill in 2M page entry.
+ //
+ *PageEntry2M = ((UINT64)(UINTN)PageTableEntry1 |
+ IA32_PG_P | IA32_PG_RW | AddressEncMask);
+}
+
+/**
+ Set one page of page table pool memory to be read-only.
+
+ @param[in] PageTableBase Base address of page table (CR3).
+ @param[in] Address Start address of a page to be set as read-only.
+ @param[in] Level4Paging Level 4 paging flag.
+
+**/
+STATIC
+VOID
+SetPageTablePoolReadOnly (
+ IN UINTN PageTableBase,
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN BOOLEAN Level4Paging
+ )
+{
+ UINTN Index;
+ UINTN EntryIndex;
+ UINT64 AddressEncMask;
+ UINT64 ActiveAddressEncMask;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ UINT64 *PageTable;
+ UINT64 *NewPageTable;
+ UINT64 PageAttr;
+ UINT64 LevelSize[5];
+ UINT64 LevelMask[5];
+ UINTN LevelShift[5];
+ UINTN Level;
+ UINT64 PoolUnitSize;
+
+ if (PageTableBase == 0) {
+ ASSERT (FALSE);
+ return;
+ }
+
+ //
+ // Since the page table is always from page table pool, which is always
+ // located at the boundary of PcdPageTablePoolAlignment, we just need to
+ // set the whole pool unit to be read-only.
+ //
+ Address = Address & PAGE_TABLE_POOL_ALIGN_MASK;
+
+ LevelShift[1] = PAGING_L1_ADDRESS_SHIFT;
+ LevelShift[2] = PAGING_L2_ADDRESS_SHIFT;
+ LevelShift[3] = PAGING_L3_ADDRESS_SHIFT;
+ LevelShift[4] = PAGING_L4_ADDRESS_SHIFT;
+
+ LevelMask[1] = PAGING_4K_ADDRESS_MASK_64;
+ LevelMask[2] = PAGING_2M_ADDRESS_MASK_64;
+ LevelMask[3] = PAGING_1G_ADDRESS_MASK_64;
+ LevelMask[4] = PAGING_1G_ADDRESS_MASK_64;
+
+ LevelSize[1] = SIZE_4KB;
+ LevelSize[2] = SIZE_2MB;
+ LevelSize[3] = SIZE_1GB;
+ LevelSize[4] = SIZE_512GB;
+
+ AddressEncMask = GetMemEncryptionAddressMask () &
+ PAGING_1G_ADDRESS_MASK_64;
+ PageTable = (UINT64 *)(UINTN)PageTableBase;
+ PoolUnitSize = PAGE_TABLE_POOL_UNIT_SIZE;
+
+ for (Level = (Level4Paging) ? 4 : 3; Level > 0; --Level) {
+ Index = ((UINTN)RShiftU64 (Address, LevelShift[Level]));
+ Index &= PAGING_PAE_INDEX_MASK;
+
+ PageAttr = PageTable[Index];
+ ActiveAddressEncMask = GetMemEncryptionAddressMask () & PageAttr;
+
+ if ((PageAttr & IA32_PG_PS) == 0) {
+ //
+ // Go to next level of table.
+ //
+ PageTable = (UINT64 *)(UINTN)(PageAttr & ~AddressEncMask &
+ PAGING_4K_ADDRESS_MASK_64);
+ continue;
+ }
+
+ if (PoolUnitSize >= LevelSize[Level]) {
+ //
+ // Clear R/W bit if current page granularity is not larger than pool unit
+ // size.
+ //
+ if ((PageAttr & IA32_PG_RW) != 0) {
+ while (PoolUnitSize > 0) {
+ //
+ // PAGE_TABLE_POOL_UNIT_SIZE and PAGE_TABLE_POOL_ALIGNMENT are fit in
+ // one page (2MB). Then we don't need to update attributes for pages
+ // crossing page directory. ASSERT below is for that purpose.
+ //
+ ASSERT (Index < EFI_PAGE_SIZE/sizeof (UINT64));
+
+ PageTable[Index] &= ~(UINT64)IA32_PG_RW;
+ PoolUnitSize -= LevelSize[Level];
+
+ ++Index;
+ }
+ }
+
+ break;
+ } else {
+ //
+ // The smaller granularity of page must be needed.
+ //
+ ASSERT (Level > 1);
+
+ NewPageTable = AllocatePageTableMemory (1);
+ if (NewPageTable == NULL) {
+ ASSERT (FALSE);
+ return;
+ }
+
+ PhysicalAddress = PageAttr & LevelMask[Level];
+ for (EntryIndex = 0;
+ EntryIndex < EFI_PAGE_SIZE/sizeof (UINT64);
+ ++EntryIndex)
+ {
+ NewPageTable[EntryIndex] = PhysicalAddress | ActiveAddressEncMask |
+ IA32_PG_P | IA32_PG_RW;
+ if (Level > 2) {
+ NewPageTable[EntryIndex] |= IA32_PG_PS;
+ }
+
+ PhysicalAddress += LevelSize[Level - 1];
+ }
+
+ PageTable[Index] = (UINT64)(UINTN)NewPageTable | ActiveAddressEncMask |
+ IA32_PG_P | IA32_PG_RW;
+ PageTable = NewPageTable;
+ }
+ }
+}
+
+/**
+ Prevent the memory pages used for page table from been overwritten.
+
+ @param[in] PageTableBase Base address of page table (CR3).
+ @param[in] Level4Paging Level 4 paging flag.
+
+**/
+STATIC
+VOID
+EnablePageTableProtection (
+ IN UINTN PageTableBase,
+ IN BOOLEAN Level4Paging
+ )
+{
+ PAGE_TABLE_POOL *HeadPool;
+ PAGE_TABLE_POOL *Pool;
+ UINT64 PoolSize;
+ EFI_PHYSICAL_ADDRESS Address;
+
+ if (mPageTablePool == NULL) {
+ return;
+ }
+
+ //
+ // SetPageTablePoolReadOnly might update mPageTablePool. It's safer to
+ // remember original one in advance.
+ //
+ HeadPool = mPageTablePool;
+ Pool = HeadPool;
+ do {
+ Address = (EFI_PHYSICAL_ADDRESS)(UINTN)Pool;
+ PoolSize = Pool->Offset + EFI_PAGES_TO_SIZE (Pool->FreePages);
+
+ //
+ // The size of one pool must be multiple of PAGE_TABLE_POOL_UNIT_SIZE,
+ // which is one of page size of the processor (2MB by default). Let's apply
+ // the protection to them one by one.
+ //
+ while (PoolSize > 0) {
+ SetPageTablePoolReadOnly (PageTableBase, Address, Level4Paging);
+ Address += PAGE_TABLE_POOL_UNIT_SIZE;
+ PoolSize -= PAGE_TABLE_POOL_UNIT_SIZE;
+ }
+
+ Pool = Pool->NextPool;
+ } while (Pool != HeadPool);
+}
+
+/**
+ Split 1G page to 2M.
+
+ @param[in] PhysicalAddress Start physical address the 1G page
+ covered.
+ @param[in, out] PageEntry1G Pointer to 1G page entry.
+ @param[in] StackBase Stack base address.
+ @param[in] StackSize Stack size.
+
+**/
+STATIC
+VOID
+Split1GPageTo2M (
+ IN PHYSICAL_ADDRESS PhysicalAddress,
+ IN OUT UINT64 *PageEntry1G,
+ IN PHYSICAL_ADDRESS StackBase,
+ IN UINTN StackSize
+ )
+{
+ PHYSICAL_ADDRESS PhysicalAddress2M;
+ UINTN IndexOfPageDirectoryEntries;
+ PAGE_TABLE_ENTRY *PageDirectoryEntry;
+ UINT64 AddressEncMask;
+ UINT64 ActiveAddressEncMask;
+
+ PageDirectoryEntry = AllocatePageTableMemory (1);
+ if (PageDirectoryEntry == NULL) {
+ return;
+ }
+
+ AddressEncMask = GetMemEncryptionAddressMask ();
+ ASSERT (PageDirectoryEntry != NULL);
+
+ ActiveAddressEncMask = *PageEntry1G & AddressEncMask;
+ //
+ // Fill in 1G page entry.
+ //
+ *PageEntry1G = ((UINT64)(UINTN)PageDirectoryEntry |
+ IA32_PG_P | IA32_PG_RW | ActiveAddressEncMask);
+
+ PhysicalAddress2M = PhysicalAddress;
+ for (IndexOfPageDirectoryEntries = 0;
+ IndexOfPageDirectoryEntries < 512;
+ (IndexOfPageDirectoryEntries++,
+ PageDirectoryEntry++,
+ PhysicalAddress2M += SIZE_2MB))
+ {
+ if ((PhysicalAddress2M < StackBase + StackSize) &&
+ ((PhysicalAddress2M + SIZE_2MB) > StackBase))
+ {
+ //
+ // Need to split this 2M page that covers stack range.
+ //
+ Split2MPageTo4K (
+ PhysicalAddress2M,
+ (UINT64 *)PageDirectoryEntry,
+ StackBase,
+ StackSize,
+ ActiveAddressEncMask
+ );
+ } else {
+ //
+ // Fill in the Page Directory entries
+ //
+ PageDirectoryEntry->Uint64 = (UINT64)PhysicalAddress2M | ActiveAddressEncMask;
+ PageDirectoryEntry->Bits.ReadWrite = 1;
+ PageDirectoryEntry->Bits.Present = 1;
+ PageDirectoryEntry->Bits.MustBe1 = 1;
+ }
+ }
+}
+
+/**
+ Set or Clear the memory shared bit
+
+ @param[in] PagetablePoint Page table entry pointer (PTE).
+ @param[in] Mode Set or Clear shared bit
+
+**/
+STATIC VOID
+SetOrClearSharedBit (
+ IN OUT UINT64 *PageTablePointer,
+ IN TDX_PAGETABLE_MODE Mode,
+ IN PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINT64 Length
+ )
+{
+ UINT64 AddressEncMask;
+ UINT64 Status;
+
+ AddressEncMask = GetMemEncryptionAddressMask ();
+
+ //
+ // Set or clear page table entry. Also, set shared bit in physical address, before calling MapGPA
+ //
+ if (Mode == SetSharedBit) {
+ *PageTablePointer |= AddressEncMask;
+ PhysicalAddress |= AddressEncMask;
+ } else {
+ *PageTablePointer &= ~AddressEncMask;
+ PhysicalAddress &= ~AddressEncMask;
+ }
+
+ Status = TdVmCall (TDVMCALL_MAPGPA, PhysicalAddress, Length, 0, 0, NULL);
+
+ //
+ // If changing shared to private, must accept-page again
+ //
+ if (Mode == ClearSharedBit) {
+ TdAcceptPages (PhysicalAddress, Length / EFI_PAGE_SIZE, EFI_PAGE_SIZE);
+ }
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a:%a: pte=0x%Lx AddressEncMask=0x%Lx Mode=0x%x MapGPA Status=0x%x\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ *PageTablePointer,
+ AddressEncMask,
+ Mode,
+ Status
+ ));
+}
+
+/**
+ Check the WP status in CR0 register. This bit is used to lock or unlock write
+ access to pages marked as read-only.
+
+ @retval TRUE Write protection is enabled.
+ @retval FALSE Write protection is disabled.
+**/
+STATIC
+BOOLEAN
+IsReadOnlyPageWriteProtected (
+ VOID
+ )
+{
+ return ((AsmReadCr0 () & BIT16) != 0);
+}
+
+/**
+ Disable Write Protect on pages marked as read-only.
+**/
+STATIC
+VOID
+DisableReadOnlyPageWriteProtect (
+ VOID
+ )
+{
+ AsmWriteCr0 (AsmReadCr0 () & ~BIT16);
+}
+
+/**
+ Enable Write Protect on pages marked as read-only.
+**/
+VOID
+EnableReadOnlyPageWriteProtect (
+ VOID
+ )
+{
+ AsmWriteCr0 (AsmReadCr0 () | BIT16);
+}
+
+/**
+ This function either sets or clears memory encryption for the memory
+ region specified by PhysicalAddress and Length from the current page table
+ context.
+
+ The function iterates through the PhysicalAddress one page at a time, and set
+ or clears the memory encryption in the page table. If it encounters
+ that a given physical address range is part of large page then it attempts to
+ change the attribute at one go (based on size), otherwise it splits the
+ large pages into smaller (e.g 2M page into 4K pages) and then try to set or
+ clear the shared bit on the smallest page size.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] PhysicalAddress The physical address that is the start
+ address of a memory region.
+ @param[in] Length The length of memory region
+ @param[in] Mode Set or Clear mode
+
+ @retval RETURN_SUCCESS The attributes were cleared for the
+ memory region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Setting the memory encyrption attribute
+ is not supported
+**/
+STATIC
+RETURN_STATUS
+EFIAPI
+SetMemorySharedOrPrivate (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINTN Length,
+ IN TDX_PAGETABLE_MODE Mode
+ )
+{
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageUpperDirectoryPointerEntry;
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
+ PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;
+ PAGE_TABLE_ENTRY *PageDirectory2MEntry;
+ PAGE_TABLE_4K_ENTRY *PageTableEntry;
+ UINT64 PgTableMask;
+ UINT64 AddressEncMask;
+ UINT64 ActiveEncMask;
+ BOOLEAN IsWpEnabled;
+ RETURN_STATUS Status;
+ IA32_CR4 Cr4;
+ BOOLEAN Page5LevelSupport;
+
+ //
+ // Set PageMapLevel4Entry to suppress incorrect compiler/analyzer warnings.
+ //
+ PageMapLevel4Entry = NULL;
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx Mode=%a\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ Cr3BaseAddress,
+ PhysicalAddress,
+ (UINT64)Length,
+ (Mode == SetSharedBit) ? "Shared" : "Private"
+ ));
+
+ //
+ // Check if we have a valid memory encryption mask
+ //
+ AddressEncMask = GetMemEncryptionAddressMask ();
+
+ PgTableMask = AddressEncMask | EFI_PAGE_MASK;
+
+ if (Length == 0) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure that the page table is changeable.
+ //
+ IsWpEnabled = IsReadOnlyPageWriteProtected ();
+ if (IsWpEnabled) {
+ DisableReadOnlyPageWriteProtect ();
+ }
+
+ //
+ // If Cr3BaseAddress is not specified then read the current CR3
+ //
+ if (Cr3BaseAddress == 0) {
+ Cr3BaseAddress = AsmReadCr3 ();
+ }
+
+ //
+ // CPU will already have LA57 enabled so just check CR4
+ //
+ Cr4.UintN = AsmReadCr4 ();
+
+ Page5LevelSupport = (Cr4.Bits.LA57 ? TRUE : FALSE);
+ //
+ // If 5-level pages, adjust Cr3BaseAddress to point to first 4-level page directory,
+ // we will only have 1
+ //
+ if (Page5LevelSupport) {
+ Cr3BaseAddress = *(UINT64 *)Cr3BaseAddress & ~PgTableMask;
+ }
+
+ Status = EFI_SUCCESS;
+
+ while (Length) {
+ PageMapLevel4Entry = (VOID *)(Cr3BaseAddress & ~PgTableMask);
+ PageMapLevel4Entry += PML4_OFFSET (PhysicalAddress);
+ if (!PageMapLevel4Entry->Bits.Present) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a:%a: bad PML4 for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+ Status = RETURN_NO_MAPPING;
+ goto Done;
+ }
+
+ PageDirectory1GEntry = (VOID *)(
+ (PageMapLevel4Entry->Bits.PageTableBaseAddress <<
+ 12) & ~PgTableMask
+ );
+ PageDirectory1GEntry += PDP_OFFSET (PhysicalAddress);
+ if (!PageDirectory1GEntry->Bits.Present) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a:%a: bad PDPE for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+ Status = RETURN_NO_MAPPING;
+ goto Done;
+ }
+
+ //
+ // If the MustBe1 bit is not 1, it's not actually a 1GB entry
+ //
+ if (PageDirectory1GEntry->Bits.MustBe1) {
+ //
+ // Valid 1GB page
+ // If we have at least 1GB to go, we can just update this entry
+ //
+ if (!(PhysicalAddress & (BIT30 - 1)) && (Length >= BIT30)) {
+ SetOrClearSharedBit (&PageDirectory1GEntry->Uint64, Mode, PhysicalAddress, BIT30);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a:%a: updated 1GB entry for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+ PhysicalAddress += BIT30;
+ Length -= BIT30;
+ } else {
+ //
+ // We must split the page
+ //
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a:%a: splitting 1GB page for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+ Split1GPageTo2M (
+ (UINT64)PageDirectory1GEntry->Bits.PageTableBaseAddress << 30,
+ (UINT64 *)PageDirectory1GEntry,
+ 0,
+ 0
+ );
+ continue;
+ }
+ } else {
+ //
+ // Actually a PDP
+ //
+ PageUpperDirectoryPointerEntry =
+ (PAGE_MAP_AND_DIRECTORY_POINTER *)PageDirectory1GEntry;
+ PageDirectory2MEntry =
+ (VOID *)(
+ (PageUpperDirectoryPointerEntry->Bits.PageTableBaseAddress <<
+ 12) & ~PgTableMask
+ );
+ PageDirectory2MEntry += PDE_OFFSET (PhysicalAddress);
+ if (!PageDirectory2MEntry->Bits.Present) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a:%a: bad PDE for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+ Status = RETURN_NO_MAPPING;
+ goto Done;
+ }
+
+ //
+ // If the MustBe1 bit is not a 1, it's not a 2MB entry
+ //
+ if (PageDirectory2MEntry->Bits.MustBe1) {
+ //
+ // Valid 2MB page
+ // If we have at least 2MB left to go, we can just update this entry
+ //
+ if (!(PhysicalAddress & (BIT21-1)) && (Length >= BIT21)) {
+ SetOrClearSharedBit (&PageDirectory2MEntry->Uint64, Mode, PhysicalAddress, BIT21);
+ PhysicalAddress += BIT21;
+ Length -= BIT21;
+ } else {
+ //
+ // We must split up this page into 4K pages
+ //
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a:%a: splitting 2MB page for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+
+ ActiveEncMask = PageDirectory2MEntry->Uint64 & AddressEncMask;
+
+ Split2MPageTo4K (
+ (UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress << 21,
+ (UINT64 *)PageDirectory2MEntry,
+ 0,
+ 0,
+ ActiveEncMask
+ );
+ continue;
+ }
+ } else {
+ PageDirectoryPointerEntry =
+ (PAGE_MAP_AND_DIRECTORY_POINTER *)PageDirectory2MEntry;
+ PageTableEntry =
+ (VOID *)(
+ (PageDirectoryPointerEntry->Bits.PageTableBaseAddress <<
+ 12) & ~PgTableMask
+ );
+ PageTableEntry += PTE_OFFSET (PhysicalAddress);
+ if (!PageTableEntry->Bits.Present) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a:%a: bad PTE for Physical=0x%Lx\n",
+ gEfiCallerBaseName,
+ __FUNCTION__,
+ PhysicalAddress
+ ));
+ Status = RETURN_NO_MAPPING;
+ goto Done;
+ }
+
+ SetOrClearSharedBit (&PageTableEntry->Uint64, Mode, PhysicalAddress, EFI_PAGE_SIZE);
+ PhysicalAddress += EFI_PAGE_SIZE;
+ Length -= EFI_PAGE_SIZE;
+ }
+ }
+ }
+
+ //
+ // Protect the page table by marking the memory used for page table to be
+ // read-only.
+ //
+ if (IsWpEnabled) {
+ EnablePageTableProtection ((UINTN)PageMapLevel4Entry, TRUE);
+ }
+
+ //
+ // Flush TLB
+ //
+ CpuFlushTlb ();
+
+Done:
+ //
+ // Restore page table write protection, if any.
+ //
+ if (IsWpEnabled) {
+ EnableReadOnlyPageWriteProtect ();
+ }
+
+ return Status;
+}
+
+/**
+ This function clears memory shared bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+
+ @retval RETURN_SUCCESS The attributes were cleared for the
+ memory region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Clearing the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxSetPageSharedBit (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages
+ )
+{
+ return SetMemorySharedOrPrivate (
+ Cr3BaseAddress,
+ BaseAddress,
+ EFI_PAGES_TO_SIZE (NumPages),
+ SetSharedBit
+ );
+}
+
+/**
+ This function sets memory shared bit for the memory region specified by
+ BaseAddress and NumPages from the current page table context.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory region.
+ @param[in] NumPages The number of pages from start memory
+ region.
+
+ @retval RETURN_SUCCESS The attributes were set for the memory
+ region.
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.
+ @retval RETURN_UNSUPPORTED Setting the memory encryption attribute
+ is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxClearPageSharedBit (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN NumPages
+ )
+{
+ return SetMemorySharedOrPrivate (
+ Cr3BaseAddress,
+ BaseAddress,
+ EFI_PAGES_TO_SIZE (NumPages),
+ ClearSharedBit
+ );
+}
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h b/OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h
new file mode 100644
index 000000000000..e9403798d98d
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h
@@ -0,0 +1,181 @@
+/** @file
+
+ Virtual Memory Management Services to set or clear the memory encryption bit
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
+
+**/
+
+#ifndef TDX_VIRTUAL_MEMORY_
+#define TDX_VIRTUAL_MEMORY_
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Uefi.h>
+
+#define SYS_CODE64_SEL 0x38
+
+#pragma pack(1)
+
+//
+// Page-Map Level-4 Offset (PML4) and
+// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
+//
+
+typedef union {
+ struct {
+ UINT64 Present : 1; // 0 = Not present in memory,
+ // 1 = Present in memory
+ UINT64 ReadWrite : 1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor : 1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough : 1; // 0 = Write-Back caching,
+ // 1 = Write-Through caching
+ UINT64 CacheDisabled : 1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed : 1; // 0 = Not accessed,
+ // 1 = Accessed (set by CPU)
+ UINT64 Reserved : 1; // Reserved
+ UINT64 MustBeZero : 2; // Must Be Zero
+ UINT64 Available : 3; // Available for use by system software
+ UINT64 PageTableBaseAddress : 40; // Page Table Base Address
+ UINT64 AvabilableHigh : 11; // Available for use by system software
+ UINT64 Nx : 1; // No Execute bit
+ } Bits;
+ UINT64 Uint64;
+} PAGE_MAP_AND_DIRECTORY_POINTER;
+
+//
+// Page Table Entry 4KB
+//
+typedef union {
+ struct {
+ UINT64 Present : 1; // 0 = Not present in memory,
+ // 1 = Present in memory
+ UINT64 ReadWrite : 1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor : 1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough : 1; // 0 = Write-Back caching,
+ // 1 = Write-Through caching
+ UINT64 CacheDisabled : 1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed : 1; // 0 = Not accessed,
+ // 1 = Accessed (set by CPU)
+ UINT64 Dirty : 1; // 0 = Not Dirty, 1 = written by
+ // processor on access to page
+ UINT64 PAT : 1; //
+ UINT64 Global : 1; // 0 = Not global page, 1 = global page
+ // TLB not cleared on CR3 write
+ UINT64 Available : 3; // Available for use by system software
+ UINT64 PageTableBaseAddress : 40; // Page Table Base Address
+ UINT64 AvabilableHigh : 11; // Available for use by system software
+ UINT64 Nx : 1; // 0 = Execute Code,
+ // 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_4K_ENTRY;
+
+//
+// Page Table Entry 2MB
+//
+typedef union {
+ struct {
+ UINT64 Present : 1; // 0 = Not present in memory,
+ // 1 = Present in memory
+ UINT64 ReadWrite : 1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor : 1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough : 1; // 0 = Write-Back caching,
+ // 1=Write-Through caching
+ UINT64 CacheDisabled : 1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed : 1; // 0 = Not accessed,
+ // 1 = Accessed (set by CPU)
+ UINT64 Dirty : 1; // 0 = Not Dirty, 1 = written by
+ // processor on access to page
+ UINT64 MustBe1 : 1; // Must be 1
+ UINT64 Global : 1; // 0 = Not global page, 1 = global page
+ // TLB not cleared on CR3 write
+ UINT64 Available : 3; // Available for use by system software
+ UINT64 PAT : 1; //
+ UINT64 MustBeZero : 8; // Must be zero;
+ UINT64 PageTableBaseAddress : 31; // Page Table Base Address
+ UINT64 AvabilableHigh : 11; // Available for use by system software
+ UINT64 Nx : 1; // 0 = Execute Code,
+ // 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_ENTRY;
+
+//
+// Page Table Entry 1GB
+//
+typedef union {
+ struct {
+ UINT64 Present : 1; // 0 = Not present in memory,
+ // 1 = Present in memory
+ UINT64 ReadWrite : 1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor : 1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough : 1; // 0 = Write-Back caching,
+ // 1 = Write-Through caching
+ UINT64 CacheDisabled : 1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed : 1; // 0 = Not accessed,
+ // 1 = Accessed (set by CPU)
+ UINT64 Dirty : 1; // 0 = Not Dirty, 1 = written by
+ // processor on access to page
+ UINT64 MustBe1 : 1; // Must be 1
+ UINT64 Global : 1; // 0 = Not global page, 1 = global page
+ // TLB not cleared on CR3 write
+ UINT64 Available : 3; // Available for use by system software
+ UINT64 PAT : 1; //
+ UINT64 MustBeZero : 17; // Must be zero;
+ UINT64 PageTableBaseAddress : 22; // Page Table Base Address
+ UINT64 AvabilableHigh : 11; // Available for use by system software
+ UINT64 Nx : 1; // 0 = Execute Code,
+ // 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} PAGE_TABLE_1G_ENTRY;
+
+#pragma pack()
+
+#define IA32_PG_P BIT0
+#define IA32_PG_RW BIT1
+#define IA32_PG_PS BIT7
+
+#define PAGING_PAE_INDEX_MASK 0x1FF
+
+#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
+#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
+#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
+
+#define PAGING_L1_ADDRESS_SHIFT 12
+#define PAGING_L2_ADDRESS_SHIFT 21
+#define PAGING_L3_ADDRESS_SHIFT 30
+#define PAGING_L4_ADDRESS_SHIFT 39
+
+#define PAGING_PML4E_NUMBER 4
+
+#define PAGETABLE_ENTRY_MASK ((1UL << 9) - 1)
+#define PML4_OFFSET(x) ( (x >> 39) & PAGETABLE_ENTRY_MASK)
+#define PDP_OFFSET(x) ( (x >> 30) & PAGETABLE_ENTRY_MASK)
+#define PDE_OFFSET(x) ( (x >> 21) & PAGETABLE_ENTRY_MASK)
+#define PTE_OFFSET(x) ( (x >> 12) & PAGETABLE_ENTRY_MASK)
+#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
+
+#define PAGE_TABLE_POOL_ALIGNMENT BASE_2MB
+#define PAGE_TABLE_POOL_UNIT_SIZE SIZE_2MB
+#define PAGE_TABLE_POOL_UNIT_PAGES \
+ EFI_SIZE_TO_PAGES (PAGE_TABLE_POOL_UNIT_SIZE)
+#define PAGE_TABLE_POOL_ALIGN_MASK \
+ (~(EFI_PHYSICAL_ADDRESS)(PAGE_TABLE_POOL_ALIGNMENT - 1))
+
+typedef struct {
+ VOID *NextPool;
+ UINTN Offset;
+ UINTN FreePages;
+} PAGE_TABLE_POOL;
+
+#endif
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 746050d64ba7..72db336e321e 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -34,6 +34,10 @@
# Virtualization (SEV) guests.
MemEncryptSevLib|Include/Library/MemEncryptSevLib.h
+ ## @libraryclass Declares helper functions for TDX guests.
+ #
+ MemEncryptTdxLib|Include/Library/MemEncryptTdxLib.h
+
## @libraryclass Save and restore variables using a file
#
NvVarsFileLib|Include/Library/NvVarsFileLib.h
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 8f02dca63869..625cb06119cd 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -176,6 +176,7 @@
VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
+ MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 98a6748c62dd..734cce4f3a94 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -180,6 +180,7 @@
VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
+ MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 32/37] OvmfPkg: Add TdxDxe driver
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (30 preceding siblings ...)
2022-02-28 7:21 ` [PATCH V7 31/37] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library Min Xu
@ 2022-02-28 7:21 ` Min Xu
2022-02-28 7:21 ` [PATCH V7 33/37] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe Min Xu
` (5 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:21 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
TdxDxe driver is dispatched early in DXE, due to being list in APRIORI.
This module is responsible for below features:
- Sets max logical cpus based on TDINFO
- Sets PCI PCDs based on resource hobs
- Set shared bit in MMIO region
- Relocate Td mailbox and set its address in MADT table.
1. Set shared bit in MMIO region
Qemu allows a ROM device to set to ROMD mode (default) or MMIO mode.
When it is in ROMD mode, the device is mapped to guest memory and
satisfies read access directly.
In EDK2 Option ROM is treated as MMIO region. So Tdx guest access
Option ROM via TDVMCALL(MMIO). But as explained above, since Qemu set
the Option ROM to ROMD mode, the call of TDVMCALL(MMIO) always return
INVALID_OPERAND. Tdvf then falls back to direct access. This requires
to set the shared bit to corresponding PageTable entry. Otherwise it
triggers GP fault.
TdxDxe's entry point is the right place to set the shared bit in MMIO
region because Option ROM has not been discoverd yet.
2. Relocate Td mailbox and set the new address in MADT Mutiprocessor
Wakeup Table.
In TDX the guest firmware is designed to publish a multiprocessor-wakeup
structure to let the guest-bootstrap processor wake up guest-application
processors with a mailbox. The mailbox is memory that the guest firmware
can reserve so each guest virtual processor can have the guest OS send
a message to them. The address of the mailbox is recorded in the MADT
table. See [ACPI].
TdxDxe registers for protocol notification
(gQemuAcpiTableNotifyProtocolGuid) to call the AlterAcpiTable(), in
which MADT table is altered by the above Mailbox address. The protocol
will be installed in AcpiPlatformDxe when the MADT table provided by
Qemu is ready. This is to maintain the simplicity of the AcpiPlatformDxe.
AlterAcpiTable is the registered function which traverses the ACPI
table list to find the original MADT from Qemu. After the new MADT is
configured and installed, the original one will be uninstalled.
[ACPI] https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model
/ACPI_Software_Programming_Model.html#multiprocessor-wakeup-structure
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/OvmfPkg.dec | 1 +
OvmfPkg/OvmfPkgX64.dsc | 2 +
OvmfPkg/OvmfPkgX64.fdf | 3 +
OvmfPkg/TdxDxe/TdxAcpiTable.c | 213 ++++++++++++++++++++++++
OvmfPkg/TdxDxe/TdxAcpiTable.h | 60 +++++++
OvmfPkg/TdxDxe/TdxDxe.c | 261 ++++++++++++++++++++++++++++++
OvmfPkg/TdxDxe/TdxDxe.inf | 64 ++++++++
OvmfPkg/TdxDxe/X64/ApRunLoop.nasm | 90 +++++++++++
8 files changed, 694 insertions(+)
create mode 100644 OvmfPkg/TdxDxe/TdxAcpiTable.c
create mode 100644 OvmfPkg/TdxDxe/TdxAcpiTable.h
create mode 100644 OvmfPkg/TdxDxe/TdxDxe.c
create mode 100644 OvmfPkg/TdxDxe/TdxDxe.inf
create mode 100644 OvmfPkg/TdxDxe/X64/ApRunLoop.nasm
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 72db336e321e..a8adbe0e6ed8 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -162,6 +162,7 @@
gEfiLegacyInterruptProtocolGuid = {0x31ce593d, 0x108a, 0x485d, {0xad, 0xb2, 0x78, 0xf2, 0x1f, 0x29, 0x66, 0xbe}}
gEfiVgaMiniPortProtocolGuid = {0xc7735a2f, 0x88f5, 0x4882, {0xae, 0x63, 0xfa, 0xac, 0x8c, 0x8b, 0x86, 0xb3}}
gOvmfLoadedX86LinuxKernelProtocolGuid = {0xa3edc05d, 0xb618, 0x4ff6, {0x95, 0x52, 0x76, 0xd7, 0x88, 0x63, 0x43, 0xc8}}
+ gQemuAcpiTableNotifyProtocolGuid = {0x928939b2, 0x4235, 0x462f, {0x95, 0x80, 0xf6, 0xa2, 0xb2, 0xc2, 0x1a, 0x4f}}
[PcdsFixedAtBuild]
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase|0x0|UINT32|0
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 2df5b2999610..f1cb9ebafb69 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -953,6 +953,8 @@
}
OvmfPkg/IoMmuDxe/IoMmuDxe.inf
+ OvmfPkg/TdxDxe/TdxDxe.inf
+
!if $(SMM_REQUIRE) == TRUE
OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index ba7f26d01dc4..d7c18bbc6ec1 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -214,6 +214,7 @@ READ_LOCK_STATUS = TRUE
APRIORI DXE {
INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
+ INF OvmfPkg/TdxDxe/TdxDxe.inf
INF OvmfPkg/AmdSevDxe/AmdSevDxe.inf
!if $(SMM_REQUIRE) == FALSE
INF OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
@@ -318,6 +319,8 @@ INF ShellPkg/Application/Shell/Shell.inf
INF MdeModulePkg/Logo/LogoDxe.inf
+INF OvmfPkg/TdxDxe/TdxDxe.inf
+
#
# Network modules
#
diff --git a/OvmfPkg/TdxDxe/TdxAcpiTable.c b/OvmfPkg/TdxDxe/TdxAcpiTable.c
new file mode 100644
index 000000000000..8a1abe8b1d89
--- /dev/null
+++ b/OvmfPkg/TdxDxe/TdxAcpiTable.c
@@ -0,0 +1,213 @@
+/** @file
+ OVMF ACPI QEMU support
+
+ Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
+
+ Copyright (C) 2012-2014, Red Hat, Inc.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/OrderedCollectionLib.h>
+#include <Library/TdxLib.h>
+#include <IndustryStandard/Acpi.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
+#include <Protocol/AcpiTable.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/TdxMailboxLib.h>
+#include <Protocol/Cpu.h>
+#include <Uefi.h>
+#include <TdxAcpiTable.h>
+
+/**
+ At the beginning of system boot, a 4K-aligned, 4K-size memory (Td mailbox) is
+ pre-allocated by host VMM. BSP & APs do the page accept together in that memory
+ region.
+
+ After that TDVF is designed to relocate the mailbox to a 4K-aligned, 4K-size
+ memory block which is allocated in the ACPI Nvs memory. APs are waken up and
+ spin around the relocated mailbox for further command.
+
+ @return EFI_PHYSICAL_ADDRESS Address of the relocated mailbox
+**/
+EFI_PHYSICAL_ADDRESS
+EFIAPI
+RelocateMailbox (
+ VOID
+ )
+{
+ EFI_PHYSICAL_ADDRESS Address;
+ VOID *ApLoopFunc;
+ UINT32 RelocationPages;
+ MP_RELOCATION_MAP RelocationMap;
+ MP_WAKEUP_MAILBOX *RelocatedMailBox;
+ EFI_STATUS Status;
+
+ Address = 0;
+ ApLoopFunc = NULL;
+ ZeroMem (&RelocationMap, sizeof (RelocationMap));
+
+ //
+ // Get information needed to setup aps running in their
+ // run loop in allocated acpi reserved memory
+ // Add another page for mailbox
+ //
+ AsmGetRelocationMap (&RelocationMap);
+ if ((RelocationMap.RelocateApLoopFuncAddress == 0) || (RelocationMap.RelocateApLoopFuncSize == 0)) {
+ DEBUG ((DEBUG_ERROR, "Failed to get the RelocationMap.\n"));
+ return 0;
+ }
+
+ RelocationPages = EFI_SIZE_TO_PAGES ((UINT32)RelocationMap.RelocateApLoopFuncSize) + 1;
+
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiACPIMemoryNVS, RelocationPages, &Address);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to allocate pages for MailboxRelocation. %r\n", Status));
+ return 0;
+ }
+
+ ZeroMem ((VOID *)Address, EFI_PAGES_TO_SIZE (RelocationPages));
+
+ ApLoopFunc = (VOID *)((UINTN)Address + EFI_PAGE_SIZE);
+
+ CopyMem (
+ ApLoopFunc,
+ RelocationMap.RelocateApLoopFuncAddress,
+ RelocationMap.RelocateApLoopFuncSize
+ );
+
+ DEBUG ((
+ DEBUG_INFO,
+ "Ap Relocation: mailbox %llx, loop %p\n",
+ Address,
+ ApLoopFunc
+ ));
+
+ //
+ // Initialize mailbox
+ //
+ RelocatedMailBox = (MP_WAKEUP_MAILBOX *)Address;
+ RelocatedMailBox->Command = MpProtectedModeWakeupCommandNoop;
+ RelocatedMailBox->ApicId = MP_CPU_PROTECTED_MODE_MAILBOX_APICID_INVALID;
+ RelocatedMailBox->WakeUpVector = 0;
+
+ //
+ // Wakup APs and have been move to the finalized run loop
+ // They will spin until guest OS wakes them
+ //
+ MpSerializeStart ();
+
+ MpSendWakeupCommand (
+ MpProtectedModeWakeupCommandWakeup,
+ (UINT64)ApLoopFunc,
+ (UINT64)RelocatedMailBox,
+ 0,
+ 0,
+ 0
+ );
+
+ return Address;
+}
+
+/**
+ Alter the MADT when ACPI Table from QEMU is available.
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+**/
+VOID
+EFIAPI
+AlterAcpiTable (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_ACPI_SDT_HEADER *Table;
+ EFI_ACPI_TABLE_VERSION Version;
+ UINTN OriginalTableKey;
+ UINTN NewTableKey;
+ UINT8 *NewMadtTable;
+ UINTN NewMadtTableLength;
+ EFI_PHYSICAL_ADDRESS RelocateMailboxAddress;
+ EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE *MadtMpWk;
+ EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *MadtHeader;
+
+ Index = 0;
+ NewMadtTable = NULL;
+ MadtHeader = NULL;
+
+ Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (void **)&AcpiSdtProtocol);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Unable to locate ACPI SDT protocol.\n"));
+ return;
+ }
+
+ RelocateMailboxAddress = RelocateMailbox ();
+ if (RelocateMailboxAddress == 0) {
+ ASSERT (FALSE);
+ DEBUG ((DEBUG_ERROR, "Failed to relocate Td mailbox\n"));
+ return;
+ }
+
+ do {
+ Status = AcpiSdtProtocol->GetAcpiTable (Index, &Table, &Version, &OriginalTableKey);
+
+ if (!EFI_ERROR (Status) && (Table->Signature == EFI_ACPI_1_0_APIC_SIGNATURE)) {
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (void **)&AcpiTableProtocol);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Unable to locate ACPI Table protocol.\n"));
+ break;
+ }
+
+ NewMadtTableLength = Table->Length + sizeof (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE);
+ NewMadtTable = AllocatePool (NewMadtTableLength);
+ if (NewMadtTable == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: OUT_OF_SOURCES error.\n", __FUNCTION__));
+ break;
+ }
+
+ CopyMem (NewMadtTable, (UINT8 *)Table, Table->Length);
+ MadtHeader = (EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)NewMadtTable;
+ MadtHeader->Header.Length = (UINT32)NewMadtTableLength;
+
+ MadtMpWk = (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE *)(NewMadtTable + Table->Length);
+ MadtMpWk->Type = EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP;
+ MadtMpWk->Length = sizeof (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE);
+ MadtMpWk->MailBoxVersion = 1;
+ MadtMpWk->Reserved = 0;
+ MadtMpWk->MailBoxAddress = RelocateMailboxAddress;
+
+ Status = AcpiTableProtocol->InstallAcpiTable (AcpiTableProtocol, NewMadtTable, NewMadtTableLength, &NewTableKey);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to install new MADT table. %r\n", Status));
+ break;
+ }
+
+ Status = AcpiTableProtocol->UninstallAcpiTable (AcpiTableProtocol, OriginalTableKey);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Uninstall old MADT table error.\n"));
+ }
+
+ break;
+ }
+
+ Index++;
+ } while (!EFI_ERROR (Status));
+
+ if (NewMadtTable != NULL) {
+ FreePool (NewMadtTable);
+ }
+}
diff --git a/OvmfPkg/TdxDxe/TdxAcpiTable.h b/OvmfPkg/TdxDxe/TdxAcpiTable.h
new file mode 100644
index 000000000000..6b7615dc3687
--- /dev/null
+++ b/OvmfPkg/TdxDxe/TdxAcpiTable.h
@@ -0,0 +1,60 @@
+/** @file
+
+ Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TDX_ACPI_TABLE_H_
+#define TDX_ACPI_TABLE_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/PciIo.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/IntelTdx.h>
+#include <IndustryStandard/Acpi.h>
+
+VOID
+EFIAPI
+AsmGetRelocationMap (
+ OUT MP_RELOCATION_MAP *AddressMap
+ );
+
+/**
+ At the beginning of system boot, a 4K-aligned, 4K-size memory (Td mailbox) is
+ pre-allocated by host VMM. BSP & APs do the page accept together in that memory
+ region.
+
+ After that TDVF is designed to relocate the mailbox to a 4K-aligned, 4K-size
+ memory block which is allocated in the ACPI Nvs memory. APs are waken up and
+ spin around the relocated mailbox for further command.
+
+ @return EFI_PHYSICAL_ADDRESS Address of the relocated mailbox
+**/
+EFI_PHYSICAL_ADDRESS
+EFIAPI
+RelocateMailbox (
+ VOID
+ );
+
+/**
+ Alter the MADT when ACPI Table from QEMU is available.
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+**/
+VOID
+EFIAPI
+AlterAcpiTable (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+#endif
diff --git a/OvmfPkg/TdxDxe/TdxDxe.c b/OvmfPkg/TdxDxe/TdxDxe.c
new file mode 100644
index 000000000000..da392a492c63
--- /dev/null
+++ b/OvmfPkg/TdxDxe/TdxDxe.c
@@ -0,0 +1,261 @@
+/** @file
+
+ TDX Dxe driver. This driver is dispatched early in DXE, due to being list
+ in APRIORI.
+
+ This module is responsible for:
+ - Sets max logical cpus based on TDINFO
+ - Sets PCI PCDs based on resource hobs
+ - Alter MATD table to record address of Mailbox
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HobLib.h>
+#include <Protocol/Cpu.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <Library/PlatformInitLib.h>
+#include <Library/TdxLib.h>
+#include <TdxAcpiTable.h>
+#include <Library/MemEncryptTdxLib.h>
+
+/**
+ Location of resource hob matching type and starting address
+
+ @param[in] Type The type of resource hob to locate.
+
+ @param[in] Start The resource hob must at least begin at address.
+
+ @retval pointer to resource Return pointer to a resource hob that matches or NULL.
+**/
+STATIC
+EFI_HOB_RESOURCE_DESCRIPTOR *
+GetResourceDescriptor (
+ EFI_RESOURCE_TYPE Type,
+ EFI_PHYSICAL_ADDRESS Start,
+ EFI_PHYSICAL_ADDRESS End
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor = NULL;
+
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
+ while (Hob.Raw != NULL) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a:%d: resource type 0x%x %llx %llx\n",
+ __func__,
+ __LINE__,
+ Hob.ResourceDescriptor->ResourceType,
+ Hob.ResourceDescriptor->PhysicalStart,
+ Hob.ResourceDescriptor->ResourceLength
+ ));
+
+ if ((Hob.ResourceDescriptor->ResourceType == Type) &&
+ (Hob.ResourceDescriptor->PhysicalStart >= Start) &&
+ ((Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength) < End))
+ {
+ ResourceDescriptor = Hob.ResourceDescriptor;
+ break;
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
+ }
+
+ return ResourceDescriptor;
+}
+
+/**
+ Location of resource hob matching type and highest address below end
+
+ @param[in] Type The type of resource hob to locate.
+
+ @param[in] End The resource hob return is the closest to the End address
+
+ @retval pointer to resource Return pointer to a resource hob that matches or NULL.
+**/
+STATIC
+EFI_HOB_RESOURCE_DESCRIPTOR *
+GetHighestResourceDescriptor (
+ EFI_RESOURCE_TYPE Type,
+ EFI_PHYSICAL_ADDRESS End
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor = NULL;
+
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
+ while (Hob.Raw != NULL) {
+ if ((Hob.ResourceDescriptor->ResourceType == Type) &&
+ (Hob.ResourceDescriptor->PhysicalStart < End))
+ {
+ if (!ResourceDescriptor ||
+ (ResourceDescriptor->PhysicalStart < Hob.ResourceDescriptor->PhysicalStart))
+ {
+ ResourceDescriptor = Hob.ResourceDescriptor;
+ }
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
+ }
+
+ return ResourceDescriptor;
+}
+
+/**
+ Set the shared bit for mmio region in Tdx guest.
+
+ In Tdx guest there are 2 ways to access mmio, TdVmcall or direct access.
+ For direct access, the shared bit of the PageTableEntry should be set.
+ The mmio region information is retrieved from hob list.
+
+ @retval EFI_SUCCESS The shared bit is set successfully.
+ @retval EFI_UNSUPPORTED Setting the shared bit of memory region
+ is not supported
+**/
+EFI_STATUS
+SetMmioSharedBit (
+ VOID
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+
+ Hob.Raw = (UINT8 *)GetHobList ();
+
+ //
+ // Parse the HOB list until end of list or matching type is found.
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if ( (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR)
+ && (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO))
+ {
+ MemEncryptTdxSetPageSharedBit (
+ 0,
+ Hob.ResourceDescriptor->PhysicalStart,
+ EFI_SIZE_TO_PAGES (Hob.ResourceDescriptor->ResourceLength)
+ );
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+TdxDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ RETURN_STATUS PcdStatus;
+ EFI_HOB_RESOURCE_DESCRIPTOR *Res = NULL;
+ EFI_HOB_RESOURCE_DESCRIPTOR *MemRes = NULL;
+ EFI_HOB_PLATFORM_INFO *PlatformInfo = NULL;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINT32 CpuMaxLogicalProcessorNumber;
+ TD_RETURN_DATA TdReturnData;
+ EFI_EVENT QemuAcpiTableEvent;
+ void *Registration;
+
+ GuidHob = GetFirstGuidHob (&gUefiOvmfPkgPlatformInfoGuid);
+
+ if (GuidHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Both Td and Non-Td guest have PlatformInfoHob which contains the HostBridgePciDevId
+ //
+ PlatformInfo = (EFI_HOB_PLATFORM_INFO *)GET_GUID_HOB_DATA (GuidHob);
+ ASSERT (PlatformInfo->HostBridgePciDevId != 0);
+ PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfo->HostBridgePciDevId);
+ ASSERT_RETURN_ERROR (PcdStatus);
+
+ if (!TdIsEnabled ()) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SetMmioSharedBit ();
+
+ //
+ // Call TDINFO to get actual number of cpus in domain
+ //
+ Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+ ASSERT (Status == EFI_SUCCESS);
+
+ CpuMaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+
+ //
+ // Adjust PcdCpuMaxLogicalProcessorNumber, if needed. If firmware is configured for
+ // more than number of reported cpus, update.
+ //
+ if (CpuMaxLogicalProcessorNumber > TdReturnData.TdInfo.NumVcpus) {
+ PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, TdReturnData.TdInfo.NumVcpus);
+ ASSERT_RETURN_ERROR (PcdStatus);
+ }
+
+ //
+ // Register for protocol notifications to call the AlterAcpiTable(),
+ // the protocol will be installed in AcpiPlatformDxe when the ACPI
+ // table provided by Qemu is ready.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ AlterAcpiTable,
+ NULL,
+ &QemuAcpiTableEvent
+ );
+
+ Status = gBS->RegisterProtocolNotify (
+ &gQemuAcpiTableNotifyProtocolGuid,
+ QemuAcpiTableEvent,
+ &Registration
+ );
+
+ #define INIT_PCDSET(NAME, RES) do {\
+ PcdStatus = PcdSet64S (NAME##Base, (RES)->PhysicalStart); \
+ ASSERT_RETURN_ERROR (PcdStatus); \
+ PcdStatus = PcdSet64S (NAME##Size, (RES)->ResourceLength); \
+ ASSERT_RETURN_ERROR (PcdStatus); \
+} while(0)
+
+ if (PlatformInfo) {
+ PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfo->HostBridgePciDevId);
+
+ if ((Res = GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO, (EFI_PHYSICAL_ADDRESS)0x100000000, (EFI_PHYSICAL_ADDRESS)-1)) != NULL) {
+ INIT_PCDSET (PcdPciMmio64, Res);
+ }
+
+ if ((Res = GetResourceDescriptor (EFI_RESOURCE_IO, 0, 0x10001)) != NULL) {
+ INIT_PCDSET (PcdPciIo, Res);
+ }
+
+ //
+ // To find low mmio, first find top of low memory, and then search for io space.
+ //
+ if ((MemRes = GetHighestResourceDescriptor (EFI_RESOURCE_SYSTEM_MEMORY, 0xffc00000)) != NULL) {
+ if ((Res = GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO, MemRes->PhysicalStart, 0x100000000)) != NULL) {
+ INIT_PCDSET (PcdPciMmio32, Res);
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/TdxDxe/TdxDxe.inf b/OvmfPkg/TdxDxe/TdxDxe.inf
new file mode 100644
index 000000000000..b5976ab3ceba
--- /dev/null
+++ b/OvmfPkg/TdxDxe/TdxDxe.inf
@@ -0,0 +1,64 @@
+#/** @file
+#
+# Driver clears the encryption attribute from MMIO regions when TDX is enabled
+#
+# Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = TdxDxe
+ FILE_GUID = E750224E-7BCE-40AF-B5BB-47E3611EB5C2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = TdxDxeEntryPoint
+
+[Sources]
+ TdxDxe.c
+ TdxAcpiTable.c
+ X64/ApRunLoop.nasm
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ PcdLib
+ UefiDriverEntryPoint
+ TdxLib
+ HobLib
+ TdxMailboxLib
+ MemEncryptTdxLib
+
+[Depex]
+ TRUE
+
+[Guids]
+ gUefiOvmfPkgPlatformInfoGuid ## CONSUMES
+
+[Protocols]
+ gQemuAcpiTableNotifyProtocolGuid ## CONSUMES
+ gEfiAcpiSdtProtocolGuid ## CONSUMES
+ gEfiAcpiTableProtocolGuid ## CONSUMES
+
+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdPciIoBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdPciIoSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Base
+ gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Size
+ gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Base
+ gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress
diff --git a/OvmfPkg/TdxDxe/X64/ApRunLoop.nasm b/OvmfPkg/TdxDxe/X64/ApRunLoop.nasm
new file mode 100644
index 000000000000..49bd04415cfd
--- /dev/null
+++ b/OvmfPkg/TdxDxe/X64/ApRunLoop.nasm
@@ -0,0 +1,90 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; ApRunLoop.nasm
+;
+; Abstract:
+;
+; This is the assembly code for run loop for APs in the guest TD
+;
+;-------------------------------------------------------------------------------
+
+%include "TdxCommondefs.inc"
+
+DEFAULT REL
+
+SECTION .text
+
+BITS 64
+
+%define TDVMCALL_EXPOSE_REGS_MASK 0xffec
+%define TDVMCALL 0x0
+%define EXIT_REASON_CPUID 0xa
+
+%macro tdcall 0
+ db 0x66, 0x0f, 0x01, 0xcc
+%endmacro
+
+;
+; Relocated Ap Mailbox loop
+;
+; @param[in] RBX: Relocated mailbox address
+; @param[in] RBP: vCpuId
+;
+; @return None This routine does not return
+;
+global ASM_PFX(AsmRelocateApMailBoxLoop)
+ASM_PFX(AsmRelocateApMailBoxLoop):
+AsmRelocateApMailBoxLoopStart:
+
+ mov rax, TDVMCALL
+ mov rcx, TDVMCALL_EXPOSE_REGS_MASK
+ mov r11, EXIT_REASON_CPUID
+ mov r12, 0xb
+ tdcall
+ test rax, rax
+ jnz Panic
+ mov r8, r15
+
+MailBoxLoop:
+ ; Spin until command set
+ cmp dword [rbx + CommandOffset], MpProtectedModeWakeupCommandNoop
+ je MailBoxLoop
+ ; Determine if this is a broadcast or directly for my apic-id, if not, ignore
+ cmp dword [rbx + ApicidOffset], MailboxApicidBroadcast
+ je MailBoxProcessCommand
+ cmp dword [rbx + ApicidOffset], r8d
+ jne MailBoxLoop
+MailBoxProcessCommand:
+ cmp dword [rbx + CommandOffset], MpProtectedModeWakeupCommandWakeup
+ je MailBoxWakeUp
+ cmp dword [rbx + CommandOffset], MpProtectedModeWakeupCommandSleep
+ je MailBoxSleep
+ ; Don't support this command, so ignore
+ jmp MailBoxLoop
+MailBoxWakeUp:
+ mov rax, [rbx + WakeupVectorOffset]
+ ; OS sends a wakeup command for a given APIC ID, firmware is supposed to reset
+ ; the command field back to zero as acknowledgement.
+ mov qword [rbx + WakeupVectorOffset], 0
+ jmp rax
+MailBoxSleep:
+ jmp $
+Panic:
+ ud2
+BITS 64
+AsmRelocateApMailBoxLoopEnd:
+
+;-------------------------------------------------------------------------------------
+; AsmGetRelocationMap (&RelocationMap);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmGetRelocationMap)
+ASM_PFX(AsmGetRelocationMap):
+ lea rax, [ASM_PFX(AsmRelocateApMailBoxLoopStart)]
+ mov qword [rcx], rax
+ mov qword [rcx + 8h], AsmRelocateApMailBoxLoopEnd - AsmRelocateApMailBoxLoopStart
+ ret
+
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 33/37] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (31 preceding siblings ...)
2022-02-28 7:21 ` [PATCH V7 32/37] OvmfPkg: Add TdxDxe driver Min Xu
@ 2022-02-28 7:21 ` Min Xu
2022-02-28 7:21 ` [PATCH V7 34/37] OvmfPkg: Update IoMmuDxe to support TDX Min Xu
` (4 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:21 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
In the previous QemuFwCfgDxe only SEV is supported. This commit
introduce TDX support in QemuFwCfgDxe.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c | 9 +++++----
OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf | 1 +
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c
index f5787cd24d38..6a810928a060 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c
@@ -19,6 +19,7 @@
#include <Library/DebugLib.h>
#include <Library/QemuFwCfgLib.h>
#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemEncryptTdxLib.h>
#include <Library/MemEncryptSevLib.h>
#include "QemuFwCfgLibInternal.h"
@@ -85,7 +86,7 @@ QemuFwCfgInitialize (
DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n"));
}
- if (mQemuFwCfgDmaSupported && MemEncryptSevIsEnabled ()) {
+ if (mQemuFwCfgDmaSupported && (MemEncryptSevIsEnabled () || (MemEncryptTdxIsEnabled ()))) {
EFI_STATUS Status;
//
@@ -100,7 +101,7 @@ QemuFwCfgInitialize (
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
- "QemuFwCfgSevDma %a:%a Failed to locate IOMMU protocol.\n",
+ "QemuFwCfgDma %a:%a Failed to locate IOMMU protocol.\n",
gEfiCallerBaseName,
__FUNCTION__
));
@@ -411,10 +412,10 @@ InternalQemuFwCfgDmaBytes (
DataBuffer = Buffer;
//
- // When SEV is enabled, map Buffer to DMA address before issuing the DMA
+ // When SEV or TDX is enabled, map Buffer to DMA address before issuing the DMA
// request
//
- if (MemEncryptSevIsEnabled ()) {
+ if (MemEncryptSevIsEnabled () || MemEncryptTdxIsEnabled ()) {
VOID *AccessBuffer;
EFI_PHYSICAL_ADDRESS DataBufferAddress;
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf
index 48899ff1236a..ce3eaa5ed8b4 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf
@@ -43,6 +43,7 @@
IoLib
MemoryAllocationLib
MemEncryptSevLib
+ MemEncryptTdxLib
[Protocols]
gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 34/37] OvmfPkg: Update IoMmuDxe to support TDX
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (32 preceding siblings ...)
2022-02-28 7:21 ` [PATCH V7 33/37] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe Min Xu
@ 2022-02-28 7:21 ` Min Xu
2022-02-28 7:21 ` [PATCH V7 35/37] OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe Min Xu
` (3 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:21 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
The IOMMU protocol driver provides capabilities to set a DMA access
attribute and methods to allocate, free, map and unmap the DMA memory
for the PCI Bus devices.
The current IoMmuDxe driver supports DMA operations inside SEV guest.
To support DMA operation in TDX guest,
CC_GUEST_IS_XXX (PcdConfidentialComputingGuestAttr) is used to determine
if it is SEV guest or TDX guest.
Due to security reasons all DMA operations inside the SEV/TDX guest must
be performed on shared pages. The IOMMU protocol driver for the SEV/TDX
guest uses a bounce buffer to map guest DMA buffer to shared pages in
order to provide the support for DMA operations inside SEV/TDX guest.
The call of SEV or TDX specific function to set/clear EncMask/SharedBit
is determined by CC_GUEST_IS_XXX (PcdConfidentialComputingGuestAttr).
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/AmdSev/AmdSevX64.dsc | 1 +
OvmfPkg/Bhyve/BhyveX64.dsc | 1 +
OvmfPkg/CloudHv/CloudHvX64.dsc | 1 +
OvmfPkg/IoMmuDxe/AmdSevIoMmu.c | 103 +++++++++++++++++++++------------
OvmfPkg/IoMmuDxe/AmdSevIoMmu.h | 6 +-
OvmfPkg/IoMmuDxe/IoMmuDxe.c | 6 +-
OvmfPkg/IoMmuDxe/IoMmuDxe.inf | 5 ++
OvmfPkg/Microvm/MicrovmX64.dsc | 1 +
OvmfPkg/OvmfPkgX64.dsc | 2 +
OvmfPkg/OvmfXen.dsc | 1 +
10 files changed, 85 insertions(+), 42 deletions(-)
diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index c173a72134f4..58a606ae48bf 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -174,6 +174,7 @@
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
BlobVerifierLib|OvmfPkg/AmdSev/BlobVerifierLibSevHashes/BlobVerifierLibSevHashes.inf
+ MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
!if $(SOURCE_DEBUG_ENABLE) == TRUE
PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc
index 656e407473bb..5d08b8925051 100644
--- a/OvmfPkg/Bhyve/BhyveX64.dsc
+++ b/OvmfPkg/Bhyve/BhyveX64.dsc
@@ -169,6 +169,7 @@
VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
+ MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
diff --git a/OvmfPkg/CloudHv/CloudHvX64.dsc b/OvmfPkg/CloudHv/CloudHvX64.dsc
index d5259dedfef6..47254bf92088 100644
--- a/OvmfPkg/CloudHv/CloudHvX64.dsc
+++ b/OvmfPkg/CloudHv/CloudHvX64.dsc
@@ -184,6 +184,7 @@
!endif
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
+ MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
!if $(SOURCE_DEBUG_ENABLE) == TRUE
PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
diff --git a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c
index 16b5b4eac8bc..6b65897f032a 100644
--- a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c
+++ b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c
@@ -1,9 +1,9 @@
/** @file
The protocol provides support to allocate, free, map and umap a DMA buffer
- for bus master (e.g PciHostBridge). When SEV is enabled, the DMA operations
- must be performed on unencrypted buffer hence we use a bounce buffer to map
- the guest buffer into an unencrypted DMA buffer.
+ for bus master (e.g PciHostBridge). When SEV or TDX is enabled, the DMA
+ operations must be performed on unencrypted buffer hence we use a bounce
+ buffer to map the guest buffer into an unencrypted DMA buffer.
Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
@@ -12,6 +12,8 @@
**/
+#include <Library/PcdLib.h>
+#include <ConfidentialComputingGuestAttr.h>
#include "AmdSevIoMmu.h"
#define MAP_INFO_SIG SIGNATURE_64 ('M', 'A', 'P', '_', 'I', 'N', 'F', 'O')
@@ -74,7 +76,7 @@ typedef struct {
/**
Provides the controller-specific addresses required to access system memory
- from a DMA bus master. On SEV guest, the DMA operations must be performed on
+ from a DMA bus master. On SEV/TDX guest, the DMA operations must be performed on
shared buffer hence we allocate a bounce buffer to map the HostAddress to a
DeviceAddress. The Encryption attribute is removed from the DeviceAddress
buffer.
@@ -250,14 +252,28 @@ IoMmuMap (
goto FreeMapInfo;
}
- //
- // Clear the memory encryption mask on the plaintext buffer.
- //
- Status = MemEncryptSevClearPageEncMask (
- 0,
- MapInfo->PlainTextAddress,
- MapInfo->NumberOfPages
- );
+ if (CC_GUEST_IS_SEV (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ //
+ // Clear the memory encryption mask on the plaintext buffer.
+ //
+ Status = MemEncryptSevClearPageEncMask (
+ 0,
+ MapInfo->PlainTextAddress,
+ MapInfo->NumberOfPages
+ );
+ } else if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ //
+ // Set the memory shared bit.
+ //
+ Status = MemEncryptTdxSetPageSharedBit (
+ 0,
+ MapInfo->PlainTextAddress,
+ MapInfo->NumberOfPages
+ );
+ } else {
+ ASSERT (FALSE);
+ }
+
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
CpuDeadLoop ();
@@ -358,7 +374,7 @@ IoMmuUnmapWorker (
}
MapInfo = (MAP_INFO *)Mapping;
-
+ Status = EFI_SUCCESS;
//
// set CommonBufferHeader to suppress incorrect compiler/analyzer warnings
//
@@ -404,15 +420,30 @@ IoMmuUnmapWorker (
break;
}
- //
- // Restore the memory encryption mask on the area we used to hold the
- // plaintext.
- //
- Status = MemEncryptSevSetPageEncMask (
- 0,
- MapInfo->PlainTextAddress,
- MapInfo->NumberOfPages
- );
+ if (CC_GUEST_IS_SEV (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ //
+ // Restore the memory encryption mask on the area we used to hold the
+ // plaintext.
+ //
+ Status = MemEncryptSevSetPageEncMask (
+ 0,
+ MapInfo->PlainTextAddress,
+ MapInfo->NumberOfPages
+ );
+ } else if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ //
+ // Restore the memory shared bit mask on the area we used to hold the
+ // plaintext.
+ //
+ Status = MemEncryptTdxClearPageSharedBit (
+ 0,
+ MapInfo->PlainTextAddress,
+ MapInfo->NumberOfPages
+ );
+ } else {
+ ASSERT (FALSE);
+ }
+
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
CpuDeadLoop ();
@@ -739,7 +770,7 @@ IoMmuSetAttribute (
return EFI_UNSUPPORTED;
}
-EDKII_IOMMU_PROTOCOL mAmdSev = {
+EDKII_IOMMU_PROTOCOL mIoMmu = {
EDKII_IOMMU_PROTOCOL_REVISION,
IoMmuSetAttribute,
IoMmuMap,
@@ -771,7 +802,7 @@ EDKII_IOMMU_PROTOCOL mAmdSev = {
STATIC
VOID
EFIAPI
-AmdSevExitBoot (
+IoMmuExitBoot (
IN EFI_EVENT Event,
IN VOID *EventToSignal
)
@@ -779,11 +810,11 @@ AmdSevExitBoot (
//
// (1) The NotifyFunctions of all the events in
// EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before
- // AmdSevExitBoot() is entered.
+ // IoMmuExitBoot() is entered.
//
- // (2) AmdSevExitBoot() is executing minimally at TPL_CALLBACK.
+ // (2) IoMmuExitBoot() is executing minimally at TPL_CALLBACK.
//
- // (3) AmdSevExitBoot() has been queued in unspecified order relative to the
+ // (3) IoMmuExitBoot() has been queued in unspecified order relative to the
// NotifyFunctions of all the other events in
// EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as
// Event's.
@@ -791,13 +822,13 @@ AmdSevExitBoot (
// Consequences:
//
// - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions
- // queued at TPL_CALLBACK may be invoked after AmdSevExitBoot() returns.
+ // queued at TPL_CALLBACK may be invoked after IoMmuExitBoot() returns.
//
// - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions
- // queued at TPL_NOTIFY may be invoked after AmdSevExitBoot() returns; plus
+ // queued at TPL_NOTIFY may be invoked after IoMmuExitBoot() returns; plus
// *all* NotifyFunctions queued at TPL_CALLBACK will be invoked strictly
// after all NotifyFunctions queued at TPL_NOTIFY, including
- // AmdSevExitBoot(), have been invoked.
+ // IoMmuExitBoot(), have been invoked.
//
// - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we
// queue EventToSignal's NotifyFunction after the NotifyFunctions of *all*
@@ -823,7 +854,7 @@ AmdSevExitBoot (
STATIC
VOID
EFIAPI
-AmdSevUnmapAllMappings (
+IoMmuUnmapAllMappings (
IN EFI_EVENT Event,
IN VOID *Context
)
@@ -842,7 +873,7 @@ AmdSevUnmapAllMappings (
NextNode = GetNextNode (&mMapInfos, Node);
MapInfo = CR (Node, MAP_INFO, Link, MAP_INFO_SIG);
IoMmuUnmapWorker (
- &mAmdSev, // This
+ &mIoMmu, // This
MapInfo, // Mapping
TRUE // MemoryMapLocked
);
@@ -855,7 +886,7 @@ AmdSevUnmapAllMappings (
**/
EFI_STATUS
EFIAPI
-AmdSevInstallIoMmuProtocol (
+InstallIoMmuProtocol (
VOID
)
{
@@ -871,7 +902,7 @@ AmdSevInstallIoMmuProtocol (
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL, // Type
TPL_CALLBACK, // NotifyTpl
- AmdSevUnmapAllMappings, // NotifyFunction
+ IoMmuUnmapAllMappings, // NotifyFunction
NULL, // NotifyContext
&UnmapAllMappingsEvent // Event
);
@@ -886,7 +917,7 @@ AmdSevInstallIoMmuProtocol (
Status = gBS->CreateEvent (
EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type
TPL_CALLBACK, // NotifyTpl
- AmdSevExitBoot, // NotifyFunction
+ IoMmuExitBoot, // NotifyFunction
UnmapAllMappingsEvent, // NotifyContext
&ExitBootEvent // Event
);
@@ -898,7 +929,7 @@ AmdSevInstallIoMmuProtocol (
Status = gBS->InstallMultipleProtocolInterfaces (
&Handle,
&gEdkiiIoMmuProtocolGuid,
- &mAmdSev,
+ &mIoMmu,
NULL
);
if (EFI_ERROR (Status)) {
diff --git a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h
index 8244f28b57fd..8fdfa9968593 100644
--- a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h
+++ b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h
@@ -21,17 +21,17 @@
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemEncryptSevLib.h>
+#include <Library/MemEncryptTdxLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
/**
- Install IOMMU protocol to provide the DMA support for PciHostBridge and
- MemEncryptSevLib.
+ Install IOMMU protocol to provide the DMA support for PciHostBridge.
**/
EFI_STATUS
EFIAPI
-AmdSevInstallIoMmuProtocol (
+InstallIoMmuProtocol (
VOID
);
diff --git a/OvmfPkg/IoMmuDxe/IoMmuDxe.c b/OvmfPkg/IoMmuDxe/IoMmuDxe.c
index bca8c14c4076..86777dd05c26 100644
--- a/OvmfPkg/IoMmuDxe/IoMmuDxe.c
+++ b/OvmfPkg/IoMmuDxe/IoMmuDxe.c
@@ -22,11 +22,11 @@ IoMmuDxeEntryPoint (
EFI_HANDLE Handle;
//
- // When SEV is enabled, install IoMmu protocol otherwise install the
+ // When SEV or TDX is enabled, install IoMmu protocol otherwise install the
// placeholder protocol so that other dependent module can run.
//
- if (MemEncryptSevIsEnabled ()) {
- Status = AmdSevInstallIoMmuProtocol ();
+ if (MemEncryptSevIsEnabled () || MemEncryptTdxIsEnabled ()) {
+ Status = InstallIoMmuProtocol ();
} else {
Handle = NULL;
diff --git a/OvmfPkg/IoMmuDxe/IoMmuDxe.inf b/OvmfPkg/IoMmuDxe/IoMmuDxe.inf
index 2ebd74e5558c..e10be1dcff49 100644
--- a/OvmfPkg/IoMmuDxe/IoMmuDxe.inf
+++ b/OvmfPkg/IoMmuDxe/IoMmuDxe.inf
@@ -26,16 +26,21 @@
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
OvmfPkg/OvmfPkg.dec
+# UefiCpuPkg/UefiCpuPkg.dec
[LibraryClasses]
BaseLib
BaseMemoryLib
DebugLib
MemEncryptSevLib
+ MemEncryptTdxLib
MemoryAllocationLib
UefiBootServicesTableLib
UefiDriverEntryPoint
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr
+
[Protocols]
gEdkiiIoMmuProtocolGuid ## SOMETIME_PRODUCES
gIoMmuAbsentProtocolGuid ## SOMETIME_PRODUCES
diff --git a/OvmfPkg/Microvm/MicrovmX64.dsc b/OvmfPkg/Microvm/MicrovmX64.dsc
index 0eac0c02c630..2a63db397000 100644
--- a/OvmfPkg/Microvm/MicrovmX64.dsc
+++ b/OvmfPkg/Microvm/MicrovmX64.dsc
@@ -181,6 +181,7 @@
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
+ MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
!if $(SOURCE_DEBUG_ENABLE) == TRUE
PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index f1cb9ebafb69..266134a09c9e 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -187,6 +187,8 @@
VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
+ MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
+
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index aa27e2256ae9..f80c38fa213b 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -170,6 +170,7 @@
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
+ MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
!if $(SOURCE_DEBUG_ENABLE) == TRUE
PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 35/37] OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (33 preceding siblings ...)
2022-02-28 7:21 ` [PATCH V7 34/37] OvmfPkg: Update IoMmuDxe to support TDX Min Xu
@ 2022-02-28 7:21 ` Min Xu
2022-02-28 7:21 ` [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step Min Xu
` (2 subsequent siblings)
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:21 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
Anthony Perard, Julien Grall
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3711
XenTimerDxe is a local Apic timer driver and it has nothing to do
with Xen. So rename it to LocalApicTimerDxe.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Julien Grall <julien@xen.org>
Acked-by: Anthony PERARD <anthony.perard@citrix.com
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/CloudHv/CloudHvX64.dsc | 2 +-
OvmfPkg/CloudHv/CloudHvX64.fdf | 2 +-
.../XenTimerDxe.c => LocalApicTimerDxe/LocalApicTimerDxe.c} | 2 +-
.../XenTimerDxe.h => LocalApicTimerDxe/LocalApicTimerDxe.h} | 4 ++--
.../LocalApicTimerDxe.inf} | 6 +++---
OvmfPkg/Microvm/MicrovmX64.dsc | 2 +-
OvmfPkg/Microvm/MicrovmX64.fdf | 2 +-
OvmfPkg/OvmfXen.dsc | 2 +-
OvmfPkg/OvmfXen.fdf | 2 +-
9 files changed, 12 insertions(+), 12 deletions(-)
rename OvmfPkg/{XenTimerDxe/XenTimerDxe.c => LocalApicTimerDxe/LocalApicTimerDxe.c} (96%)
rename OvmfPkg/{XenTimerDxe/XenTimerDxe.h => LocalApicTimerDxe/LocalApicTimerDxe.h} (96%)
rename OvmfPkg/{XenTimerDxe/XenTimerDxe.inf => LocalApicTimerDxe/LocalApicTimerDxe.inf} (86%)
diff --git a/OvmfPkg/CloudHv/CloudHvX64.dsc b/OvmfPkg/CloudHv/CloudHvX64.dsc
index 47254bf92088..8a17267b4aa5 100644
--- a/OvmfPkg/CloudHv/CloudHvX64.dsc
+++ b/OvmfPkg/CloudHv/CloudHvX64.dsc
@@ -707,7 +707,7 @@
MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
UefiCpuPkg/CpuDxe/CpuDxe.inf
- OvmfPkg/XenTimerDxe/XenTimerDxe.inf
+ OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
diff --git a/OvmfPkg/CloudHv/CloudHvX64.fdf b/OvmfPkg/CloudHv/CloudHvX64.fdf
index ce3302c6d6ed..60721d0f2f56 100644
--- a/OvmfPkg/CloudHv/CloudHvX64.fdf
+++ b/OvmfPkg/CloudHv/CloudHvX64.fdf
@@ -234,7 +234,7 @@ INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
INF MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
INF UefiCpuPkg/CpuDxe/CpuDxe.inf
-INF OvmfPkg/XenTimerDxe/XenTimerDxe.inf
+INF OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
INF OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
diff --git a/OvmfPkg/XenTimerDxe/XenTimerDxe.c b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
similarity index 96%
rename from OvmfPkg/XenTimerDxe/XenTimerDxe.c
rename to OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
index bbd964eb7ad9..dd9352b12088 100644
--- a/OvmfPkg/XenTimerDxe/XenTimerDxe.c
+++ b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
@@ -8,7 +8,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
**/
-#include "XenTimerDxe.h"
+#include "LocalApicTimerDxe.h"
//
// The handle onto which the Timer Architectural Protocol will be installed
diff --git a/OvmfPkg/XenTimerDxe/XenTimerDxe.h b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.h
similarity index 96%
rename from OvmfPkg/XenTimerDxe/XenTimerDxe.h
rename to OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.h
index b55ece0d941e..93706995f8ab 100644
--- a/OvmfPkg/XenTimerDxe/XenTimerDxe.h
+++ b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.h
@@ -7,8 +7,8 @@ Copyright (c) 2019, Citrix Systems, Inc.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
-#ifndef _TIMER_H_
-#define _TIMER_H_
+#ifndef LOCAL_APIC_TIMER_H_
+#define LOCAL_APIC_TIMER_H_
#include <PiDxe.h>
diff --git a/OvmfPkg/XenTimerDxe/XenTimerDxe.inf b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
similarity index 86%
rename from OvmfPkg/XenTimerDxe/XenTimerDxe.inf
rename to OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
index add1d01bbf9c..63b75b75c921 100644
--- a/OvmfPkg/XenTimerDxe/XenTimerDxe.inf
+++ b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
@@ -10,7 +10,7 @@
[Defines]
INF_VERSION = 0x00010005
- BASE_NAME = XenTimerDxe
+ BASE_NAME = LocalApicTimerDxe
FILE_GUID = 52fe8196-f9de-4d07-b22f-51f77a0e7c41
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
@@ -30,8 +30,8 @@
LocalApicLib
[Sources]
- XenTimerDxe.h
- XenTimerDxe.c
+ LocalApicTimerDxe.h
+ LocalApicTimerDxe.c
[Protocols]
gEfiCpuArchProtocolGuid ## CONSUMES
diff --git a/OvmfPkg/Microvm/MicrovmX64.dsc b/OvmfPkg/Microvm/MicrovmX64.dsc
index 2a63db397000..6c18776809f1 100644
--- a/OvmfPkg/Microvm/MicrovmX64.dsc
+++ b/OvmfPkg/Microvm/MicrovmX64.dsc
@@ -665,7 +665,7 @@
MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
- OvmfPkg/XenTimerDxe/XenTimerDxe.inf
+ OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
UefiCpuPkg/CpuDxe/CpuDxe.inf
OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
diff --git a/OvmfPkg/Microvm/MicrovmX64.fdf b/OvmfPkg/Microvm/MicrovmX64.fdf
index 6999ac1a87b9..3adb492a4ad7 100644
--- a/OvmfPkg/Microvm/MicrovmX64.fdf
+++ b/OvmfPkg/Microvm/MicrovmX64.fdf
@@ -215,7 +215,7 @@ INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
INF MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF OvmfPkg/XenTimerDxe/XenTimerDxe.inf
+INF OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
INF UefiCpuPkg/CpuDxe/CpuDxe.inf
INF OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index f80c38fa213b..2626b322b654 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -557,7 +557,7 @@
MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
- OvmfPkg/XenTimerDxe/XenTimerDxe.inf
+ OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
UefiCpuPkg/CpuDxe/CpuDxe.inf
OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/OvmfPkg/OvmfXen.fdf b/OvmfPkg/OvmfXen.fdf
index a6acf3b835aa..8e9c6721f183 100644
--- a/OvmfPkg/OvmfXen.fdf
+++ b/OvmfPkg/OvmfXen.fdf
@@ -298,7 +298,7 @@ INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
INF MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF OvmfPkg/XenTimerDxe/XenTimerDxe.inf
+INF OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
INF UefiCpuPkg/CpuDxe/CpuDxe.inf
INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (34 preceding siblings ...)
2022-02-28 7:21 ` [PATCH V7 35/37] OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe Min Xu
@ 2022-02-28 7:21 ` Min Xu
2022-03-15 8:07 ` [edk2-devel] " Ni, Ray
2022-05-10 20:30 ` Lendacky, Thomas
2022-02-28 7:21 ` [PATCH V7 37/37] OvmfPkg: Switch timer in build time for OvmfPkg Min Xu
2022-03-01 2:19 ` 回复: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) gaoliming
37 siblings, 2 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:21 UTC (permalink / raw)
To: devel
Cc: Min Xu, Jiewen Yao, Gerd Hoffmann, Anthony Perard, Julien Grall,
Eric Dong, Ray Ni
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3711
Per SDM, changing the mode of APIC timer (from one-shot to periodic or
vice versa) by writing to the timer LVT entry does not start the timer.
To start the timer, it is necessary to write to the initial-count
register.
If initial-count is wrote before mode change, it's possible that timer
expired before the mode change. Thus failing the periodic mode.
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Julien Grall <julien@xen.org>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
.../Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
index 2d17177df12b..f26d9c93894f 100644
--- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
+++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
@@ -967,11 +967,6 @@ InitializeApicTimer (
//
InitializeLocalApicSoftwareEnable (TRUE);
- //
- // Program init-count register.
- //
- WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
-
if (DivideValue != 0) {
ASSERT (DivideValue <= 128);
ASSERT (DivideValue == GetPowerOfTwo32 ((UINT32)DivideValue));
@@ -996,6 +991,11 @@ InitializeApicTimer (
LvtTimer.Bits.Mask = 0;
LvtTimer.Bits.Vector = Vector;
WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
+
+ //
+ // Program init-count register.
+ //
+ WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
}
/**
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step
2022-02-28 7:21 ` [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step Min Xu
@ 2022-03-15 8:07 ` Ni, Ray
2022-05-10 20:30 ` Lendacky, Thomas
1 sibling, 0 replies; 72+ messages in thread
From: Ni, Ray @ 2022-03-15 8:07 UTC (permalink / raw)
To: Min Xu, devel
[-- Attachment #1: Type: text/plain, Size: 78 bytes --]
Thanks for fixing this potential bug. Reviewed-by: Ray Ni <ray.ni@intel.com>
[-- Attachment #2: Type: text/html, Size: 137 bytes --]
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step
2022-02-28 7:21 ` [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step Min Xu
2022-03-15 8:07 ` [edk2-devel] " Ni, Ray
@ 2022-05-10 20:30 ` Lendacky, Thomas
2022-05-11 2:00 ` Min Xu
1 sibling, 1 reply; 72+ messages in thread
From: Lendacky, Thomas @ 2022-05-10 20:30 UTC (permalink / raw)
To: devel, min.m.xu
Cc: Jiewen Yao, Gerd Hoffmann, Anthony Perard, Julien Grall,
Eric Dong, Ray Ni
On 2/28/22 01:21, Min Xu via groups.io wrote:
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3711
>
> Per SDM, changing the mode of APIC timer (from one-shot to periodic or
> vice versa) by writing to the timer LVT entry does not start the timer.
> To start the timer, it is necessary to write to the initial-count
> register.
>
> If initial-count is wrote before mode change, it's possible that timer
> expired before the mode change. Thus failing the periodic mode.
I'm replying to this patch since I can't find patch V12 46/47 anywhere in
my email.
I've bisected a regression in the Linux kernel to this patch when an
SEV-SNP guest is booted. The following message is issued in the kernel for
every AP being brought online:
APIC: Stale IRR: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000020 ISR: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000
Possibly a timing issue involving the mode switch with the interrupt
unmasked. If I leave the interrupt masked and only un-mask it
after the programming of the init-count, then the message goes away.
Thoughts?
Thanks,
Tom
>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Anthony Perard <anthony.perard@citrix.com>
> Cc: Julien Grall <julien@xen.org>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Acked-by: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>
> ---
> .../Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
> index 2d17177df12b..f26d9c93894f 100644
> --- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
> +++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
> @@ -967,11 +967,6 @@ InitializeApicTimer (
> //
> InitializeLocalApicSoftwareEnable (TRUE);
>
> - //
> - // Program init-count register.
> - //
> - WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
> -
> if (DivideValue != 0) {
> ASSERT (DivideValue <= 128);
> ASSERT (DivideValue == GetPowerOfTwo32 ((UINT32)DivideValue));
> @@ -996,6 +991,11 @@ InitializeApicTimer (
> LvtTimer.Bits.Mask = 0;
> LvtTimer.Bits.Vector = Vector;
> WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
> +
> + //
> + // Program init-count register.
> + //
> + WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
> }
>
> /**
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step
2022-05-10 20:30 ` Lendacky, Thomas
@ 2022-05-11 2:00 ` Min Xu
2022-05-11 14:06 ` Lendacky, Thomas
0 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-05-11 2:00 UTC (permalink / raw)
To: Tom Lendacky, devel@edk2.groups.io, Ni, Ray
Cc: Yao, Jiewen, Gerd Hoffmann, Anthony Perard, Julien Grall,
Dong, Eric
On May 11, 2022 4:30 AM, Tom Lendacky wrote:
> On 2/28/22 01:21, Min Xu via groups.io wrote:
> > BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3711
> >
> > Per SDM, changing the mode of APIC timer (from one-shot to periodic or
> > vice versa) by writing to the timer LVT entry does not start the timer.
> > To start the timer, it is necessary to write to the initial-count
> > register.
> >
> > If initial-count is wrote before mode change, it's possible that timer
> > expired before the mode change. Thus failing the periodic mode.
>
> I'm replying to this patch since I can't find patch V12 46/47 anywhere in my
> email.
>
> I've bisected a regression in the Linux kernel to this patch when an SEV-SNP
> guest is booted. The following message is issued in the kernel for every AP
> being brought online:
>
> APIC: Stale IRR:
> 00000000,00000000,00000000,00000000,00000000,00000000,00000000,000
> 00020 ISR:
> 00000000,00000000,00000000,00000000,00000000,00000000,00000000,000
> 00000
>
> Possibly a timing issue involving the mode switch with the interrupt
> unmasked. If I leave the interrupt masked and only un-mask it after the
> programming of the init-count, then the message goes away.
Do you mean in InitializeApicTimer, it should follow below steps:
1. mask LvtTimer. (set LvtTimer.Bits.Mask = 1)
2. Do other stuff, including programing the init-count register.
3. un-mask LvtTimer (set LvtTimer.Bit.Mask = 0)
Thanks
Min
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step
2022-05-11 2:00 ` Min Xu
@ 2022-05-11 14:06 ` Lendacky, Thomas
2022-05-12 0:52 ` Min Xu
0 siblings, 1 reply; 72+ messages in thread
From: Lendacky, Thomas @ 2022-05-11 14:06 UTC (permalink / raw)
To: Xu, Min M, devel@edk2.groups.io, Ni, Ray
Cc: Yao, Jiewen, Gerd Hoffmann, Anthony Perard, Julien Grall,
Dong, Eric
On 5/10/22 21:00, Xu, Min M wrote:
> On May 11, 2022 4:30 AM, Tom Lendacky wrote:
>> On 2/28/22 01:21, Min Xu via groups.io wrote:
>>> BZ: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D3711&data=05%7C01%7Cthomas.lendacky%40amd.com%7Cce8cd76e1b054fe277d808da32f20976%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637878312370633666%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=C%2F0BMTV%2FoZdUxLwRbqzjNVdlMvEKfl20z6RwKeMzr2c%3D&reserved=0
>>>
>>> Per SDM, changing the mode of APIC timer (from one-shot to periodic or
>>> vice versa) by writing to the timer LVT entry does not start the timer.
>>> To start the timer, it is necessary to write to the initial-count
>>> register.
>>>
>>> If initial-count is wrote before mode change, it's possible that timer
>>> expired before the mode change. Thus failing the periodic mode.
>>
>> I'm replying to this patch since I can't find patch V12 46/47 anywhere in my
>> email.
>>
>> I've bisected a regression in the Linux kernel to this patch when an SEV-SNP
>> guest is booted. The following message is issued in the kernel for every AP
>> being brought online:
>>
>> APIC: Stale IRR:
>> 00000000,00000000,00000000,00000000,00000000,00000000,00000000,000
>> 00020 ISR:
>> 00000000,00000000,00000000,00000000,00000000,00000000,00000000,000
>> 00000
>>
>> Possibly a timing issue involving the mode switch with the interrupt
>> unmasked. If I leave the interrupt masked and only un-mask it after the
>> programming of the init-count, then the message goes away.
>
> Do you mean in InitializeApicTimer, it should follow below steps:
> 1. mask LvtTimer. (set LvtTimer.Bits.Mask = 1)
> 2. Do other stuff, including programing the init-count register.
> 3. un-mask LvtTimer (set LvtTimer.Bit.Mask = 0)
Yes, I believe so. I'm not an expert on the APIC timer, but that seems
reasonable to me.
Thanks,
Tom
>
> Thanks
> Min
>
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step
2022-05-11 14:06 ` Lendacky, Thomas
@ 2022-05-12 0:52 ` Min Xu
2022-05-13 22:12 ` Lendacky, Thomas
0 siblings, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-05-12 0:52 UTC (permalink / raw)
To: devel@edk2.groups.io, thomas.lendacky@amd.com, Ni, Ray
Cc: Yao, Jiewen, Gerd Hoffmann, Anthony Perard, Julien Grall,
Dong, Eric
On May 11, 2022 10:06 PM, Lendacky, Thomas wrote:
> On 5/10/22 21:00, Xu, Min M wrote:
> > On May 11, 2022 4:30 AM, Tom Lendacky wrote:
> >> I'm replying to this patch since I can't find patch V12 46/47
> >> anywhere in my email.
> >>
> >> I've bisected a regression in the Linux kernel to this patch when an
> >> SEV-SNP guest is booted. The following message is issued in the
> >> kernel for every AP being brought online:
> >>
> >> APIC: Stale IRR:
> >>
> 00000000,00000000,00000000,00000000,00000000,00000000,00000000,000
> >> 00020 ISR:
> >>
> 00000000,00000000,00000000,00000000,00000000,00000000,00000000,000
> >> 00000
> >>
> >> Possibly a timing issue involving the mode switch with the interrupt
> >> unmasked. If I leave the interrupt masked and only un-mask it after
> >> the programming of the init-count, then the message goes away.
> >
> > Do you mean in InitializeApicTimer, it should follow below steps:
> > 1. mask LvtTimer. (set LvtTimer.Bits.Mask = 1) 2. Do other stuff,
> > including programing the init-count register.
> > 3. un-mask LvtTimer (set LvtTimer.Bit.Mask = 0)
>
> Yes, I believe so. I'm not an expert on the APIC timer, but that seems
> reasonable to me.
I tested this fix in Td guest and it has no side effect.
I check the Intel SDM (Vol.3A Chap 10.5 Handling Local Interrupts) but it doesn't describe the actual sequence of LvtTimer.Bits.Mask and programming of init-count register.
@ Ni, Ray, What's your thought about it?
Thanks
Min
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step
2022-05-12 0:52 ` Min Xu
@ 2022-05-13 22:12 ` Lendacky, Thomas
2022-05-19 21:54 ` Henz, Patrick
0 siblings, 1 reply; 72+ messages in thread
From: Lendacky, Thomas @ 2022-05-13 22:12 UTC (permalink / raw)
To: devel, min.m.xu, Ni, Ray
Cc: Yao, Jiewen, Gerd Hoffmann, Anthony Perard, Julien Grall,
Dong, Eric
On 5/11/22 19:52, Min Xu via groups.io wrote:
> On May 11, 2022 10:06 PM, Lendacky, Thomas wrote:
>> On 5/10/22 21:00, Xu, Min M wrote:
>>> On May 11, 2022 4:30 AM, Tom Lendacky wrote:
>>>> I'm replying to this patch since I can't find patch V12 46/47
>>>> anywhere in my email.
>>>>
>>>> I've bisected a regression in the Linux kernel to this patch when an
>>>> SEV-SNP guest is booted. The following message is issued in the
>>>> kernel for every AP being brought online:
>>>>
>>>> APIC: Stale IRR:
>>>>
>> 00000000,00000000,00000000,00000000,00000000,00000000,00000000,000
>>>> 00020 ISR:
>>>>
>> 00000000,00000000,00000000,00000000,00000000,00000000,00000000,000
>>>> 00000
>>>>
>>>> Possibly a timing issue involving the mode switch with the interrupt
>>>> unmasked. If I leave the interrupt masked and only un-mask it after
>>>> the programming of the init-count, then the message goes away.
>>>
>>> Do you mean in InitializeApicTimer, it should follow below steps:
>>> 1. mask LvtTimer. (set LvtTimer.Bits.Mask = 1) 2. Do other stuff,
>>> including programing the init-count register.
>>> 3. un-mask LvtTimer (set LvtTimer.Bit.Mask = 0)
>>
>> Yes, I believe so. I'm not an expert on the APIC timer, but that seems
>> reasonable to me.
> I tested this fix in Td guest and it has no side effect.
> I check the Intel SDM (Vol.3A Chap 10.5 Handling Local Interrupts) but it doesn't describe the actual sequence of LvtTimer.Bits.Mask and programming of init-count register.
> @ Ni, Ray, What's your thought about it?
I guess you can theoretically miss an interrupt if your initial count is
expires before you unmask the interrupt, so I think your fix is correct
and no changes are needed.
I need to double check whether I'm properly resetting the APIC when APs
are booted multiple times. Since this only occurs with SNP, I think this
is on my end.
Thanks,
Tom
>
> Thanks
> Min
>
>
>
>
>
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step
2022-05-13 22:12 ` Lendacky, Thomas
@ 2022-05-19 21:54 ` Henz, Patrick
2022-05-20 3:50 ` Jeff Fan
0 siblings, 1 reply; 72+ messages in thread
From: Henz, Patrick @ 2022-05-19 21:54 UTC (permalink / raw)
To: devel@edk2.groups.io, Lendacky, Thomas, min.m.xu@intel.com,
Ni, Ray
Cc: Yao, Jiewen, Gerd Hoffmann, Anthony Perard, Julien Grall,
Dong, Eric
Hi all,
We (Hewlett Packard Enterprise) are also running into a race condition due to how InitializeApicTimer initializes the APIC timers, we figured this might be a good place to report our findings. On the occasion we notice that APs get stuck in the timer interrupt handling code after getting woken up by the BSP. It appears that if the CurrentCount timer value provided by the BSP is sufficiently small, the brief amount of time between an AP calling InitializeApicTimer and calling DisableApicTimerInterrupt (see SyncLocalApicTimerSetting as an example) leaves enough room for an APIC timer interrupt to occur. This seems to become more frequent on larger systems with higher processor counts, from what we've gathered the increase in the number of locking sequence invocations appears to be making this condition far more likely to occur. We work on scaled systems with node controllers and we've really only seen this on larger systems, but it seems to us this could feasibly happen on smaller systems too. Our current solution is to add an additional argument to InitializeApicTimer, allowing the caller to specify whether or not APIC timer interrupts are to be enabled for the current thread.
Thanks,
Patrick Henz
Enterprise X86 Labs
Hewlett Packard Enterprise
patrick.henz@hpe.com
-----Original Message-----
From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of Lendacky, Thomas via groups.io
Sent: Friday, May 13, 2022 5:13 PM
To: devel@edk2.groups.io; min.m.xu@intel.com; Ni, Ray <ray.ni@intel.com>
Cc: Yao, Jiewen <jiewen.yao@intel.com>; Gerd Hoffmann <kraxel@redhat.com>; Anthony Perard <anthony.perard@citrix.com>; Julien Grall <julien@xen.org>; Dong, Eric <eric.dong@intel.com>
Subject: Re: [edk2-devel] [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step
On 5/11/22 19:52, Min Xu via groups.io wrote:
> On May 11, 2022 10:06 PM, Lendacky, Thomas wrote:
>> On 5/10/22 21:00, Xu, Min M wrote:
>>> On May 11, 2022 4:30 AM, Tom Lendacky wrote:
>>>> I'm replying to this patch since I can't find patch V12 46/47
>>>> anywhere in my email.
>>>>
>>>> I've bisected a regression in the Linux kernel to this patch when
>>>> an SEV-SNP guest is booted. The following message is issued in the
>>>> kernel for every AP being brought online:
>>>>
>>>> APIC: Stale IRR:
>>>>
>> 00000000,00000000,00000000,00000000,00000000,00000000,00000000,000
>>>> 00020 ISR:
>>>>
>> 00000000,00000000,00000000,00000000,00000000,00000000,00000000,000
>>>> 00000
>>>>
>>>> Possibly a timing issue involving the mode switch with the
>>>> interrupt unmasked. If I leave the interrupt masked and only
>>>> un-mask it after the programming of the init-count, then the message goes away.
>>>
>>> Do you mean in InitializeApicTimer, it should follow below steps:
>>> 1. mask LvtTimer. (set LvtTimer.Bits.Mask = 1) 2. Do other stuff,
>>> including programing the init-count register.
>>> 3. un-mask LvtTimer (set LvtTimer.Bit.Mask = 0)
>>
>> Yes, I believe so. I'm not an expert on the APIC timer, but that
>> seems reasonable to me.
> I tested this fix in Td guest and it has no side effect.
> I check the Intel SDM (Vol.3A Chap 10.5 Handling Local Interrupts) but it doesn't describe the actual sequence of LvtTimer.Bits.Mask and programming of init-count register.
> @ Ni, Ray, What's your thought about it?
I guess you can theoretically miss an interrupt if your initial count is expires before you unmask the interrupt, so I think your fix is correct and no changes are needed.
I need to double check whether I'm properly resetting the APIC when APs are booted multiple times. Since this only occurs with SNP, I think this is on my end.
Thanks,
Tom
>
> Thanks
> Min
>
>
>
>
>
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step
2022-05-19 21:54 ` Henz, Patrick
@ 2022-05-20 3:50 ` Jeff Fan
0 siblings, 0 replies; 72+ messages in thread
From: Jeff Fan @ 2022-05-20 3:50 UTC (permalink / raw)
To: devel@edk2.groups.io, patrick.henz, Lendacky, Thomas,
min.m.xu@intel.com, Ni, Ray
Cc: Jiewen Yao, Gerd Hoffmann, Anthony Perard, Julien Grall,
Dong, Eric
[-- Attachment #1: Type: text/plain, Size: 4361 bytes --]
Ray,
Could we add one API (like InitializeApicTimerEx) to intialize CPU local APCI with additional parameter to indicate if interrupt is to be enabled or not? Just like HPE's solution.
Jeff
fanjianfeng@byosoft.com.cn
From: Henz, Patrick
Date: 2022-05-20 05:54
To: devel@edk2.groups.io; Lendacky, Thomas; min.m.xu@intel.com; Ni, Ray
CC: Yao, Jiewen; Gerd Hoffmann; Anthony Perard; Julien Grall; Dong, Eric
Subject: Re: [edk2-devel] [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step
Hi all,
We (Hewlett Packard Enterprise) are also running into a race condition due to how InitializeApicTimer initializes the APIC timers, we figured this might be a good place to report our findings. On the occasion we notice that APs get stuck in the timer interrupt handling code after getting woken up by the BSP. It appears that if the CurrentCount timer value provided by the BSP is sufficiently small, the brief amount of time between an AP calling InitializeApicTimer and calling DisableApicTimerInterrupt (see SyncLocalApicTimerSetting as an example) leaves enough room for an APIC timer interrupt to occur. This seems to become more frequent on larger systems with higher processor counts, from what we've gathered the increase in the number of locking sequence invocations appears to be making this condition far more likely to occur. We work on scaled systems with node controllers and we've really only seen this on larger systems, but it seems to us this could feasibly happen on smaller systems too. Our current solution is to add an additional argument to InitializeApicTimer, allowing the caller to specify whether or not APIC timer interrupts are to be enabled for the current thread.
Thanks,
Patrick Henz
Enterprise X86 Labs
Hewlett Packard Enterprise
patrick.henz@hpe.com
-----Original Message-----
From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of Lendacky, Thomas via groups.io
Sent: Friday, May 13, 2022 5:13 PM
To: devel@edk2.groups.io; min.m.xu@intel.com; Ni, Ray <ray.ni@intel.com>
Cc: Yao, Jiewen <jiewen.yao@intel.com>; Gerd Hoffmann <kraxel@redhat.com>; Anthony Perard <anthony.perard@citrix.com>; Julien Grall <julien@xen.org>; Dong, Eric <eric.dong@intel.com>
Subject: Re: [edk2-devel] [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step
On 5/11/22 19:52, Min Xu via groups.io wrote:
> On May 11, 2022 10:06 PM, Lendacky, Thomas wrote:
>> On 5/10/22 21:00, Xu, Min M wrote:
>>> On May 11, 2022 4:30 AM, Tom Lendacky wrote:
>>>> I'm replying to this patch since I can't find patch V12 46/47
>>>> anywhere in my email.
>>>>
>>>> I've bisected a regression in the Linux kernel to this patch when
>>>> an SEV-SNP guest is booted. The following message is issued in the
>>>> kernel for every AP being brought online:
>>>>
>>>> APIC: Stale IRR:
>>>>
>> 00000000,00000000,00000000,00000000,00000000,00000000,00000000,000
>>>> 00020 ISR:
>>>>
>> 00000000,00000000,00000000,00000000,00000000,00000000,00000000,000
>>>> 00000
>>>>
>>>> Possibly a timing issue involving the mode switch with the
>>>> interrupt unmasked. If I leave the interrupt masked and only
>>>> un-mask it after the programming of the init-count, then the message goes away.
>>>
>>> Do you mean in InitializeApicTimer, it should follow below steps:
>>> 1. mask LvtTimer. (set LvtTimer.Bits.Mask = 1) 2. Do other stuff,
>>> including programing the init-count register.
>>> 3. un-mask LvtTimer (set LvtTimer.Bit.Mask = 0)
>>
>> Yes, I believe so. I'm not an expert on the APIC timer, but that
>> seems reasonable to me.
> I tested this fix in Td guest and it has no side effect.
> I check the Intel SDM (Vol.3A Chap 10.5 Handling Local Interrupts) but it doesn't describe the actual sequence of LvtTimer.Bits.Mask and programming of init-count register.
> @ Ni, Ray, What's your thought about it?
I guess you can theoretically miss an interrupt if your initial count is expires before you unmask the interrupt, so I think your fix is correct and no changes are needed.
I need to double check whether I'm properly resetting the APIC when APs are booted multiple times. Since this only occurs with SNP, I think this is on my end.
Thanks,
Tom
>
> Thanks
> Min
>
>
>
>
>
[-- Attachment #2: Type: text/html, Size: 7267 bytes --]
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH V7 37/37] OvmfPkg: Switch timer in build time for OvmfPkg
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (35 preceding siblings ...)
2022-02-28 7:21 ` [PATCH V7 36/37] UefiCpuPkg: Setting initial-count register as the last step Min Xu
@ 2022-02-28 7:21 ` Min Xu
2022-03-01 2:19 ` 回复: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) gaoliming
37 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-02-28 7:21 UTC (permalink / raw)
To: devel
Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3711
Discussion in https://bugzilla.tianocore.org/show_bug.cgi?id=1496 shows
that 8254TimerDxe was not written for OVMF. It was moved over from
PcAtChipsetPkg to OvmfPkg in 2019. Probably because OVMF was the only
user left.
Most likely the reason OVMF used 8254TimerDxe initially was that it could
just use the existing driver in PcAtChipsetPkg. And it simply hasn't
been changed ever.
CSM support was moved in 2019 too. (CSM support depends on 8254/8259
drivers). So 8254TimerDxe will be used when CSM_ENABLE=TRUE.
There are 4 .dsc which include the 8254Timer.
- OvmfPkg/AmdSev/AmdSevX64.dsc
- OvmfPkg/OvmfPkgIa32.dsc
- OvmfPkg/OvmfPkgIa32X64.dsc
- OvmfPkg/OvmfPkgX64.dsc
For the three OvmfPkg* configs using 8254TimerDxe with CSM_ENABLE=TRUE
and LapicTimerDxe otherwise.
For the AmdSev config it doesn't make sense to support a CSM. So use
the lapic timer unconditionally.
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>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Suggested-by: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/AmdSev/AmdSevX64.dsc | 5 +++--
OvmfPkg/AmdSev/AmdSevX64.fdf | 3 +--
OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c | 2 +-
OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf | 1 +
OvmfPkg/OvmfPkgIa32.dsc | 10 +++++++++-
OvmfPkg/OvmfPkgIa32.fdf | 8 ++++++--
OvmfPkg/OvmfPkgIa32X64.dsc | 10 +++++++++-
OvmfPkg/OvmfPkgIa32X64.fdf | 8 ++++++--
OvmfPkg/OvmfPkgX64.dsc | 10 +++++++++-
OvmfPkg/OvmfPkgX64.fdf | 8 ++++++--
10 files changed, 51 insertions(+), 14 deletions(-)
diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index 58a606ae48bf..fc83de90e49e 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -571,6 +571,8 @@
!include OvmfPkg/OvmfTpmPcds.dsc.inc
+ gEfiMdePkgTokenSpaceGuid.PcdFSBClock|100000000
+
[PcdsDynamicHii]
!include OvmfPkg/OvmfTpmPcdsHii.dsc.inc
@@ -639,10 +641,9 @@
}
MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
- OvmfPkg/8259InterruptControllerDxe/8259.inf
UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
UefiCpuPkg/CpuDxe/CpuDxe.inf
- OvmfPkg/8254TimerDxe/8254Timer.inf
+ OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
diff --git a/OvmfPkg/AmdSev/AmdSevX64.fdf b/OvmfPkg/AmdSev/AmdSevX64.fdf
index 31f2be66361f..844ba8a116d8 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.fdf
+++ b/OvmfPkg/AmdSev/AmdSevX64.fdf
@@ -206,10 +206,9 @@ INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
INF MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF OvmfPkg/8259InterruptControllerDxe/8259.inf
INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
INF UefiCpuPkg/CpuDxe/CpuDxe.inf
-INF OvmfPkg/8254TimerDxe/8254Timer.inf
+INF OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
INF OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
diff --git a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
index dd9352b12088..cbc17c979cb6 100644
--- a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
+++ b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
@@ -174,7 +174,7 @@ TimerDriverSetTimerPeriod (
//
DisableApicTimerInterrupt ();
} else {
- TimerFrequency = PcdGet32 (PcdFSBClock) / DivideValue;
+ TimerFrequency = PcdGet32 (PcdFSBClock) / (UINT32)DivideValue;
//
// Convert TimerPeriod into local APIC counts
diff --git a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
index 63b75b75c921..3ad28a148c5b 100644
--- a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+++ b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
@@ -1,5 +1,6 @@
## @file
# Local APIC timer driver that provides Timer Arch protocol.
+# PcdFSBClock is defined in MdePkg and it should be set by the consumer.
#
# Copyright (c) 2005 - 2019, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2019, Citrix Systems, Inc.
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 625cb06119cd..eb3c8f503818 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -642,6 +642,10 @@
# Set ConfidentialComputing defaults
gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr|0
+!if $(CSM_ENABLE) == FALSE
+ gEfiMdePkgTokenSpaceGuid.PcdFSBClock|100000000
+!endif
+
[PcdsDynamicHii]
!include OvmfPkg/OvmfTpmPcdsHii.dsc.inc
@@ -722,10 +726,14 @@
}
MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
- OvmfPkg/8259InterruptControllerDxe/8259.inf
UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
UefiCpuPkg/CpuDxe/CpuDxe.inf
+!ifdef $(CSM_ENABLE)
+ OvmfPkg/8259InterruptControllerDxe/8259.inf
OvmfPkg/8254TimerDxe/8254Timer.inf
+!else
+ OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+!endif
OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
index a6b2142ccd0c..3ab1755749d4 100644
--- a/OvmfPkg/OvmfPkgIa32.fdf
+++ b/OvmfPkg/OvmfPkgIa32.fdf
@@ -206,10 +206,14 @@ INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
INF MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF OvmfPkg/8259InterruptControllerDxe/8259.inf
INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
INF UefiCpuPkg/CpuDxe/CpuDxe.inf
-INF OvmfPkg/8254TimerDxe/8254Timer.inf
+!ifdef $(CSM_ENABLE)
+ INF OvmfPkg/8259InterruptControllerDxe/8259.inf
+ INF OvmfPkg/8254TimerDxe/8254Timer.inf
+!else
+ INF OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+!endif
INF OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 734cce4f3a94..8f92a346af64 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -652,6 +652,10 @@
# Set ConfidentialComputing defaults
gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr|0
+!if $(CSM_ENABLE) == FALSE
+ gEfiMdePkgTokenSpaceGuid.PcdFSBClock|100000000
+!endif
+
[PcdsDynamicDefault.X64]
# IPv4 and IPv6 PXE Boot support.
gEfiNetworkPkgTokenSpaceGuid.PcdIPv4PXESupport|0x01
@@ -738,10 +742,14 @@
}
MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
- OvmfPkg/8259InterruptControllerDxe/8259.inf
UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
UefiCpuPkg/CpuDxe/CpuDxe.inf
+!ifdef $(CSM_ENABLE)
+ OvmfPkg/8259InterruptControllerDxe/8259.inf
OvmfPkg/8254TimerDxe/8254Timer.inf
+!else
+ OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+!endif
OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
index 49266dd46768..e1638fa6ea38 100644
--- a/OvmfPkg/OvmfPkgIa32X64.fdf
+++ b/OvmfPkg/OvmfPkgIa32X64.fdf
@@ -210,10 +210,14 @@ INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
INF MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF OvmfPkg/8259InterruptControllerDxe/8259.inf
INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
INF UefiCpuPkg/CpuDxe/CpuDxe.inf
-INF OvmfPkg/8254TimerDxe/8254Timer.inf
+!ifdef $(CSM_ENABLE)
+ INF OvmfPkg/8259InterruptControllerDxe/8259.inf
+ INF OvmfPkg/8254TimerDxe/8254Timer.inf
+!else
+ INF OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+!endif
INF OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 266134a09c9e..9353abe6540b 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -667,6 +667,10 @@
# Set ConfidentialComputing defaults
gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr|0
+!if $(CSM_ENABLE) == FALSE
+ gEfiMdePkgTokenSpaceGuid.PcdFSBClock|100000000
+!endif
+
[PcdsDynamicHii]
!include OvmfPkg/OvmfTpmPcdsHii.dsc.inc
@@ -748,10 +752,14 @@
}
MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
- OvmfPkg/8259InterruptControllerDxe/8259.inf
UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
UefiCpuPkg/CpuDxe/CpuDxe.inf
+!ifdef $(CSM_ENABLE)
+ OvmfPkg/8259InterruptControllerDxe/8259.inf
OvmfPkg/8254TimerDxe/8254Timer.inf
+!else
+ OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+!endif
OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index d7c18bbc6ec1..71df28705ea8 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -233,10 +233,14 @@ INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
INF MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF OvmfPkg/8259InterruptControllerDxe/8259.inf
INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
INF UefiCpuPkg/CpuDxe/CpuDxe.inf
-INF OvmfPkg/8254TimerDxe/8254Timer.inf
+!ifdef $(CSM_ENABLE)
+ INF OvmfPkg/8259InterruptControllerDxe/8259.inf
+ INF OvmfPkg/8254TimerDxe/8254Timer.inf
+!else
+ INF OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+!endif
INF OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
--
2.29.2.windows.2
^ permalink raw reply related [flat|nested] 72+ messages in thread
* 回复: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A)
2022-02-28 7:20 [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
` (36 preceding siblings ...)
2022-02-28 7:21 ` [PATCH V7 37/37] OvmfPkg: Switch timer in build time for OvmfPkg Min Xu
@ 2022-03-01 2:19 ` gaoliming
2022-03-01 6:39 ` Min Xu
2022-03-10 6:21 ` Min Xu
37 siblings, 2 replies; 72+ messages in thread
From: gaoliming @ 2022-03-01 2:19 UTC (permalink / raw)
To: devel, min.m.xu
Cc: 'Brijesh Singh', 'Eric Dong',
'Erdem Aktas', 'Hao A Wu', 'Jian J Wang',
'James Bottomley', 'Jiewen Yao',
'Michael D Kinney', 'Ray Ni',
'Rahul Kumar', 'Tom Lendacky',
'Zhiguang Liu', 'Gerd Hoffmann'
Min:
I have two comments in MdePkg. The changes in MdeModulePkg are good to me.
1. Seemly, new APIs (TdCall, TdVmCall, TdIsEnabled) in BaseLib are X86 specific. How about define them in #if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64) in BaseLib.h?
2. I don't find new resource attribute EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in the latest PI PI_Spec_1_7_A_final_May1.pdf. Can you let me know which spec defines it?
Thanks
Liming
> -----邮件原件-----
> 发件人: devel@edk2.groups.io <devel@edk2.groups.io> 代表 Min Xu
> 发送时间: 2022年2月28日 15:21
> 收件人: devel@edk2.groups.io
> 抄送: Min Xu <min.m.xu@intel.com>; Brijesh Singh
> <brijesh.singh@amd.com>; Eric Dong <eric.dong@intel.com>; Erdem Aktas
> <erdemaktas@google.com>; Hao A Wu <hao.a.wu@intel.com>; Jian J Wang
> <jian.j.wang@intel.com>; James Bottomley <jejb@linux.ibm.com>; Jiewen
> Yao <jiewen.yao@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>;
> Michael D Kinney <michael.d.kinney@intel.com>; Ray Ni <ray.ni@intel.com>;
> Rahul Kumar <rahul1.kumar@intel.com>; Tom Lendacky
> <thomas.lendacky@amd.com>; Zhiguang Liu <zhiguang.liu@intel.com>; Gerd
> Hoffmann <kraxel@redhat.com>
> 主题: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A)
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3249
>
> 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.
>
> There are 2 configurations for TDVF to upstream. See below link for
> the definitions of the 2 configurations.
> https://edk2.groups.io/g/devel/message/76367
>
> This patch-set is to enable Config-A in OvmfPkg.
> - Merge the *basic* TDVF feature to existing OvmfX64Pkg.dsc. (Align
> with existing SEV)
> - Threat model: VMM is NOT out of TCB. (We don’t make things worse.)
> - The OvmfX64Pkg.dsc includes SEV/TDX/normal OVMF basic boot capability.
> The final binary can run on SEV/TDX/normal OVMF
> - No changes to existing OvmfPkgX64 image layout.
> - No need to add additional security features if they do not exist today
> - No need to remove features if they exist today.
> - RTMR is not supported
> - PEI phase is NOT skipped in either Td or Non-Td
>
> Patch 01 - 23 are changes in SEC phase. Also some libraries in these
> patches are workable in SEC/PEI/DXE.
>
> Patch 17 - 20 extract the common codes from OvmfPkg/PlatformPei to a new
> PlatformInitLib. Then OvmfPkg/PlatformPei is refactored with this lib.
> This is because there are 3 variants of PlatformPei in OvmfPkg and hence
> many codes are duplicated.
> Patch 21 then add Tdx specific codes in PlatformInitLib.
>
> Patch 24 - 29 are changes in PEI phase.
>
> Patch 30 - 34 are changes in DXE phase.
>
> Patch 35 - 37 are for local Apic timer DXE driver.
>
> [TDX]: https://software.intel.com/content/dam/develop/external/us/en/
> documents/tdx-whitepaper-final9-17.pdf
>
> [TDX-Module]: https://software.intel.com/content/dam/develop/external/
> us/en/documents/tdx-module-1.0-public-spec-v0.931.pdf
>
> [TDVF]: https://software.intel.com/content/dam/develop/external/us/en/
> documents/tdx-virtual-firmware-design-guide-rev-1.pdf
>
> [GCHI]: https://software.intel.com/content/dam/develop/external/us/en/
> documents/intel-tdx-guest-hypervisor-communication-interface-1.0-344426-
> 002.pdf
>
> Code is at https://github.com/mxu9/edk2/tree/tdvf_wave2.v7
>
> v7 changes:
> - Based on the comments from last review, 8 PlatformInitLib patches
> are squashed into 4 patches (#17-#20). These 4 patches are not
> related to Tdx guest. Tdx related codes of PlatformInitLib is
> in #21.
> - gUefiOvmfPkgTdxPlatformGuid is renamed as
> gUefiOvmfPkgPlatformInfoGuid.
> Because this GUID is used not only by Tdx guest, but also by
> Legacy guest.
> - PlatformInitLibNull is deleted.
> - In PlatformPei Pml4Entries is cap at 512 entries when
> mPhysMemAddressWidth > 48.
>
> v7 not-addressed comments
> - Comments in MpInitLib have not been addressed yet. It will be
> addressed in the following version.
> - Thanks much for your understanding.
>
> v6 changes:
> - PlatformInitLib and OvmfPkg/PlatformPei refactoring are covered in
> patch from 17 - 24. These patches are not related to Tdx guest. Tdx
> related codes of PlatformInitLib is in patch 25.
> - In the previous patch-sets, TdHob is processed in
> OvmfPkg/Sec/IntelTdx.c. Per Gerd's suggestion they are now moved
> to PlatformInitLib/IntelTdx.c. So that they can be reused in Config-B.
> - The default Accept page size is changed from 4K to 2M.
> - The BspAcceptMemoryResourceRange is refactored according to Gerd's
> comment.
> - In ApRunLoop.nasm command field is set to zero as acknowledgement.
> This is a fix based on the ACPI Spec v6.4,Sec titled "Multiprocessor
> Wakeup Structure".
>
> v6 not-addressed comments
> - Comments in MpInitLib have not been addressed yet. It will be
> addressed in the following version.
> - Thanks much for your understanding.
>
> v5 changes:
> - PlatformInitLib is introduced which wraps the common functions in
> OvmfPkg/PlatformPei. It is because there are a lot of duplicated
> codes for Platform initialization in PEI phase and there are at least
> 3 variants of PlatformPei. Another reason is that in TDVF Config-B
> PEI-less boot needs the similar initiliazation as PlatformPei. Based
> on the discussion with the community, PlatformInitLib is introduced.
> As the first stage OvmfPkg/PlatformPei is refactored with this lib.
> In the future the other 2 PlatformPei variants will be refactored
> as well.
> - PcdIgnoreVeHalt is deprecated.
> - Add spec link for Mailbox.
> - Other minor changes, such as comments, uncrustify formats, etc.
>
> v5 not-addressed comments
> - Comments in MpInitLib have not been addressed yet. It will be
> addressed in the following version.
> - Some comments may be missed. I will re-visit the review emails.
> - Thanks much for your understanding.
>
> v4 changes:
> - Split the TdxLib into 2 libraries. The TDX basic functions
> (TdCall / TdVmCall / TdIsEnabled) are moved to BaseLib (#2).
> The other functions are in TdxLib. (#3)
> - Based on above changes (TdCall/TdVmCall/TdIsEnabled in BaseLib)
> the TdxLib.inf is not necessary in some Pkgs, such as
> UefiPayloadPkg. The duplicated source code are deleted (BaseIoLib
> is the sample).
> - Drop the Accepting pages with TDX MP service. Instead only BSP
> accepts pages. There maybe boot performance issue. There are some
> mitigations to it, such as 2M accept page size, lazy accept, etc.
> We will re-visit this issue in a separate patch-set.
> - Relocate Mailbox in TdxDxe driver instead of in PlatformPei. This
> is to keep consistence with Config-B (PEI is skipped in Config-B).
> - SetMmioSharedBit in TdxDxe driver instead of in DxeIplPeim after
> CreateIdentityMappingPageTables. This is to keep consistence with
> Config-B (PEI is skipped in Config-B).
> - Some other minor changes, such as switch-case indention.
> - Rebase the code base (commit: 8c06c53b585a) and update the code with
> uncrustify.
>
> v4 not-addressed comments:
> - Comments in MpInitLib have not been addressed yet. It will be
> addressed in the next version.
> - BaseMemEncryptTdxLib is suggested to be merged with
> BaseMemEncryptSevLib. It will be addressed in the next version.
> - Gerd suggests a generic page table walker which is able to set
> and clear bits for a given memory range in both SEV and TDX guest.
> This suggestion will be addressed in the next version.
> - Some comments may be missed. I will re-visit the review emails.
> - Thanks much for your understanding.
>
> v3 changes:
> - LocalApicTimerDxe is split out to be a separate patch-series.
> - VmTdExitLibNull/VmgExitLib are removed. Instead the VmgExitLib
> is extended to handle #VE exception. (Patch 3-5)
> - Split the Tdx support of base IoLib into 4 commits. (Patch 6-9)
> - Alter of MADT table is updated. In previous version it was
> created from scratch. Now it gets the installed table, copy
> it to a larger buffer and append the ACPI_MADT_MPWK to it.
> (Patch 25)
> - Changes in BaseXApicX2ApicLib is refined based on the
> feedbacks. (Add spec link of MSR access definition, rename
> some funtion name, etc.) (Patch 11)
> - Use PcdConfidentialComputingGuestAttr to probe TDX guest instead
> of CPUID. But in some cases PcdConfidentialComputingGuestAttr
> cannot be used because it has not been set yet.
> - Some other minor changes.
>
> v3 not-addressed comments:
> - Some of the comments have not been addressed. This is because I
> need more time to consider how to address these comments.
> At the same time I want to submit a new version based on the above
> changes so that community can review in a more efficient way.
> (v2 is the version one month ago).
> - Comments in MpInitLib have not been addressed yet. It will be
> addressed in v4.
> - BaseMemEncryptTdxLib should be merged with BaseMemEncryptSevLib.
> It will be addressed in v4.
> - Some comments may be missed. I will re-visit the review emails.
> - Thanks much for your understanding.
>
> v2 changes:
> - Remove TdxProbeLib. It is to reduce the depencies of the lib.
> - In v1 a new function (AllocatePagesWithMemoryType) is added in
> PeiMemoryAllocationLib. This function is not necessary. It can
> be replaced by PeiServicesAllocatePages.
> - IoLibFifo.c is added in BaseIoLibIntrinsic. This file includes
> the functions of read/write of I/O port fifo. These functions
> will call TdIoReadFifo or SevIoReadFifo by checking TDX or SEV
> in run-time.
> - DXE related patches are added. (Patch 22-28)
> - Fix typo in commit/comment message, or some minor changes.
> - Rebase the edk2 code base. (4cc1458dbe00)
>
> Cc: Brijesh Singh <brijesh.singh@amd.com>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Erdem Aktas <erdemaktas@google.com>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: James Bottomley <jejb@linux.ibm.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Rahul Kumar <rahul1.kumar@intel.com>
> Cc: Tom Lendacky <thomas.lendacky@amd.com>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>
>
> Min Xu (37):
> MdePkg: Add Tdx.h
> MdePkg: Introduce basic Tdx functions in BaseLib
> MdePkg: Add TdxLib to wrap Tdx operations
> UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception
> OvmfPkg: Extend VmgExitLib to handle #VE exception
> UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
> MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic
> MdePkg: Support mmio for Tdx guest in BaseIoLibIntrinsic
> MdePkg: Support IoFifo for Tdx guest in BaseIoLibIntrinsic
> MdePkg: Support IoRead/IoWrite for Tdx guest in BaseIoLibIntrinsic
> UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
> MdePkg: Add macro to check SEV / TDX guest
> UefiCpuPkg: Enable Tdx support in MpInitLib
> OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
> OvmfPkg: Add TdxMailboxLib
> MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h
> OvmfPkg: Create initial version of PlatformInitLib
> OvmfPkg/PlatformInitLib: Add hob functions
> OvmfPkg/PlatformInitLib: Add memory functions
> OvmfPkg/PlatformInitLib: Add platform functions
> OvmfPkg: Update PlatformInitLib to process Tdx hoblist
> OvmfPkg/Sec: Declare local variable as volatile in
> SecCoreStartupWithStack
> OvmfPkg: Update Sec to support Tdx
> OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
> MdeModulePkg: EFER should not be changed in TDX
> MdeModulePkg: Add PcdTdxSharedBitMask
> UefiCpuPkg: Update AddressEncMask in CpuPageTable
> OvmfPkg: Update PlatformInitLib for Tdx guest to publish ram regions
> OvmfPkg: Update PlatformPei to support Tdx guest
> OvmfPkg: Update AcpiPlatformDxe to alter MADT table
> OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
> OvmfPkg: Add TdxDxe driver
> OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe
> OvmfPkg: Update IoMmuDxe to support TDX
> OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe
> UefiCpuPkg: Setting initial-count register as the last step
> OvmfPkg: Switch timer in build time for OvmfPkg
>
> MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 1 +
> .../Core/DxeIplPeim/X64/VirtualMemory.c | 7 +
> MdeModulePkg/MdeModulePkg.dec | 9 +
> .../Include/ConfidentialComputingGuestAttr.h | 3 +
> MdePkg/Include/IndustryStandard/Tdx.h | 203 ++++
> MdePkg/Include/Library/BaseLib.h | 62 ++
> MdePkg/Include/Library/TdxLib.h | 97 ++
> MdePkg/Include/Pi/PiHob.h | 8 +
> .../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf | 2 +
> .../BaseIoLibIntrinsicSev.inf | 7 +
> MdePkg/Library/BaseIoLibIntrinsic/IoLib.c | 81 +-
> MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c | 216 ++++
> MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c | 51 +-
> .../BaseIoLibIntrinsic/IoLibInternalTdx.c | 675 +++++++++++++
> .../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 497 +++++++++
> MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c | 73 +-
> MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h | 166 +++
> MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h | 410 ++++++++
> .../BaseIoLibIntrinsic/X64/IoFifoSev.nasm | 34 +-
> MdePkg/Library/BaseLib/BaseLib.inf | 11 +
> MdePkg/Library/BaseLib/IntelTdxNull.c | 83 ++
> MdePkg/Library/BaseLib/X64/TdCall.nasm | 85 ++
> MdePkg/Library/BaseLib/X64/TdProbe.c | 62 ++
> MdePkg/Library/BaseLib/X64/TdVmcall.nasm | 145 +++
> MdePkg/Library/TdxLib/AcceptPages.c | 180 ++++
> MdePkg/Library/TdxLib/Rtmr.c | 83 ++
> MdePkg/Library/TdxLib/TdInfo.c | 114 +++
> MdePkg/Library/TdxLib/TdxLib.inf | 37 +
> MdePkg/Library/TdxLib/TdxLibNull.c | 107 ++
> MdePkg/MdePkg.dec | 3 +
> MdePkg/MdePkg.dsc | 1 +
> OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf | 1 +
> OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c | 14 +-
> OvmfPkg/AmdSev/AmdSevX64.dsc | 8 +-
> OvmfPkg/AmdSev/AmdSevX64.fdf | 3 +-
> OvmfPkg/Bhyve/BhyveX64.dsc | 2 +
> OvmfPkg/CloudHv/CloudHvX64.dsc | 5 +-
> OvmfPkg/CloudHv/CloudHvX64.fdf | 2 +-
> OvmfPkg/Include/IndustryStandard/IntelTdx.h | 67 ++
> OvmfPkg/Include/Library/MemEncryptTdxLib.h | 81 ++
> OvmfPkg/Include/Library/PlatformInitLib.h | 286 ++++++
> OvmfPkg/Include/Library/TdxMailboxLib.h | 76 ++
> .../Include/Protocol/QemuAcpiTableNotify.h | 27 +
> OvmfPkg/Include/TdxCommondefs.inc | 51 +
> OvmfPkg/IoMmuDxe/AmdSevIoMmu.c | 103 +-
> OvmfPkg/IoMmuDxe/AmdSevIoMmu.h | 6 +-
> OvmfPkg/IoMmuDxe/IoMmuDxe.c | 6 +-
> OvmfPkg/IoMmuDxe/IoMmuDxe.inf | 5 +
> .../BaseMemEncryptTdxLib.inf | 44 +
> .../BaseMemEncryptTdxLibNull.inf | 35 +
> .../BaseMemoryEncryptionNull.c | 90 ++
> .../BaseMemEncryptTdxLib/MemoryEncryption.c | 948
> ++++++++++++++++++
> .../BaseMemEncryptTdxLib/VirtualMemory.h | 181 ++++
> .../PlatformInitLib}/Cmos.c | 32 +-
> OvmfPkg/Library/PlatformInitLib/IntelTdx.c | 553 ++++++++++
> .../Library/PlatformInitLib/IntelTdxNull.c | 46 +
> OvmfPkg/Library/PlatformInitLib/MemDetect.c | 707 +++++++++++++
> OvmfPkg/Library/PlatformInitLib/Platform.c | 597 +++++++++++
> .../PlatformInitLib/PlatformInitLib.inf | 94 ++
> OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c | 9 +-
> .../Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf | 1 +
> .../QemuFwCfgLib/QemuFwCfgLibInternal.h | 11 +
> OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c | 32 +
> .../Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf | 2 +
> OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c | 140 +++
> .../Library/TdxMailboxLib/TdxMailboxLib.inf | 52 +
> .../Library/TdxMailboxLib/TdxMailboxNull.c | 85 ++
> OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf | 3 +-
> OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h | 32 +
> .../Library/VmgExitLib/VmTdExitVeHandler.c | 559 +++++++++++
> OvmfPkg/Library/VmgExitLib/VmgExitLib.inf | 2 +
> .../Library/VmgExitLib/X64/TdVmcallCpuid.nasm | 146 +++
> .../LocalApicTimerDxe.c} | 4 +-
> .../LocalApicTimerDxe.h} | 4 +-
> .../LocalApicTimerDxe.inf} | 7 +-
> OvmfPkg/Microvm/MicrovmX64.dsc | 5 +-
> OvmfPkg/Microvm/MicrovmX64.fdf | 2 +-
> OvmfPkg/OvmfPkg.dec | 17 +
> OvmfPkg/OvmfPkgIa32.dsc | 12 +-
> OvmfPkg/OvmfPkgIa32.fdf | 8 +-
> OvmfPkg/OvmfPkgIa32X64.dsc | 14 +-
> OvmfPkg/OvmfPkgIa32X64.fdf | 8 +-
> OvmfPkg/OvmfPkgX64.dsc | 29 +-
> OvmfPkg/OvmfPkgX64.fdf | 11 +-
> OvmfPkg/OvmfXen.dsc | 4 +-
> OvmfPkg/OvmfXen.fdf | 2 +-
> OvmfPkg/PlatformPei/Cmos.h | 48 -
> OvmfPkg/PlatformPei/FeatureControl.c | 7 +-
> OvmfPkg/PlatformPei/IntelTdx.c | 54 +
> OvmfPkg/PlatformPei/MemDetect.c | 669 +-----------
> OvmfPkg/PlatformPei/Platform.c | 522 ++--------
> OvmfPkg/PlatformPei/Platform.h | 55 +-
> OvmfPkg/PlatformPei/PlatformPei.inf | 7 +-
> OvmfPkg/Sec/SecMain.c | 44 +-
> OvmfPkg/Sec/SecMain.inf | 3 +
> OvmfPkg/Sec/X64/SecEntry.nasm | 82 ++
> OvmfPkg/TdxDxe/TdxAcpiTable.c | 213 ++++
> OvmfPkg/TdxDxe/TdxAcpiTable.h | 60 ++
> OvmfPkg/TdxDxe/TdxDxe.c | 261 +++++
> OvmfPkg/TdxDxe/TdxDxe.inf | 64 ++
> OvmfPkg/TdxDxe/X64/ApRunLoop.nasm | 90 ++
> UefiCpuPkg/CpuDxe/CpuDxe.inf | 1 +
> UefiCpuPkg/CpuDxe/CpuPageTable.c | 4 +
> UefiCpuPkg/Include/Library/VmgExitLib.h | 28 +
> .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c | 170 +++-
> .../PeiDxeSmmCpuException.c | 17 +
> .../SecPeiCpuException.c | 18 +
> UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 3 +
> UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 15 +-
> UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h | 71 ++
> UefiCpuPkg/Library/MpInitLib/MpLib.c | 27 +
> UefiCpuPkg/Library/MpInitLib/MpLibTdx.c | 128 +++
> UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c | 73 ++
> UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 3 +
> .../Library/VmgExitLibNull/VmTdExitNull.c | 38 +
> .../Library/VmgExitLibNull/VmgExitLibNull.inf | 1 +
> 116 files changed, 10233 insertions(+), 1327 deletions(-)
> create mode 100644 MdePkg/Include/IndustryStandard/Tdx.h
> create mode 100644 MdePkg/Include/Library/TdxLib.h
> create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
> create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
> create mode 100644
> MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
> create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h
> create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
> create mode 100644 MdePkg/Library/BaseLib/IntelTdxNull.c
> create mode 100644 MdePkg/Library/BaseLib/X64/TdCall.nasm
> create mode 100644 MdePkg/Library/BaseLib/X64/TdProbe.c
> create mode 100644 MdePkg/Library/BaseLib/X64/TdVmcall.nasm
> create mode 100644 MdePkg/Library/TdxLib/AcceptPages.c
> create mode 100644 MdePkg/Library/TdxLib/Rtmr.c
> create mode 100644 MdePkg/Library/TdxLib/TdInfo.c
> create mode 100644 MdePkg/Library/TdxLib/TdxLib.inf
> create mode 100644 MdePkg/Library/TdxLib/TdxLibNull.c
> create mode 100644 OvmfPkg/Include/IndustryStandard/IntelTdx.h
> create mode 100644 OvmfPkg/Include/Library/MemEncryptTdxLib.h
> create mode 100644 OvmfPkg/Include/Library/PlatformInitLib.h
> create mode 100644 OvmfPkg/Include/Library/TdxMailboxLib.h
> create mode 100644 OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h
> create mode 100644 OvmfPkg/Include/TdxCommondefs.inc
> create mode 100644
> OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
> create mode 100644
> OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
> create mode 100644
> OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
> create mode 100644
> OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
> create mode 100644
> OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h
> rename OvmfPkg/{PlatformPei => Library/PlatformInitLib}/Cmos.c (61%)
> create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdx.c
> create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
> create mode 100644 OvmfPkg/Library/PlatformInitLib/MemDetect.c
> create mode 100644 OvmfPkg/Library/PlatformInitLib/Platform.c
> create mode 100644 OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
> create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
> create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
> create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c
> create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
> create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
> create mode 100644 OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm
> rename OvmfPkg/{XenTimerDxe/XenTimerDxe.c =>
> LocalApicTimerDxe/LocalApicTimerDxe.c} (95%)
> rename OvmfPkg/{XenTimerDxe/XenTimerDxe.h =>
> LocalApicTimerDxe/LocalApicTimerDxe.h} (96%)
> rename OvmfPkg/{XenTimerDxe/XenTimerDxe.inf =>
> LocalApicTimerDxe/LocalApicTimerDxe.inf} (80%)
> delete mode 100644 OvmfPkg/PlatformPei/Cmos.h
> create mode 100644 OvmfPkg/PlatformPei/IntelTdx.c
> create mode 100644 OvmfPkg/TdxDxe/TdxAcpiTable.c
> create mode 100644 OvmfPkg/TdxDxe/TdxAcpiTable.h
> create mode 100644 OvmfPkg/TdxDxe/TdxDxe.c
> create mode 100644 OvmfPkg/TdxDxe/TdxDxe.inf
> create mode 100644 OvmfPkg/TdxDxe/X64/ApRunLoop.nasm
> create mode 100644 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
> create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
> create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
> create mode 100644 UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c
>
> --
> 2.29.2.windows.2
>
>
>
>
>
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A)
2022-03-01 2:19 ` 回复: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) gaoliming
@ 2022-03-01 6:39 ` Min Xu
2022-03-01 6:53 ` Yao, Jiewen
2022-03-10 6:21 ` Min Xu
1 sibling, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-03-01 6:39 UTC (permalink / raw)
To: devel@edk2.groups.io, Gao, Liming
Cc: 'Brijesh Singh', Dong, Eric, Aktas, Erdem, Wu, Hao A,
Wang, Jian J, 'James Bottomley', Yao, Jiewen,
Kinney, Michael D, Ni, Ray, Kumar, Rahul1, 'Tom Lendacky',
Liu, Zhiguang, 'Gerd Hoffmann'
On March 1, 2022 10:20 AM, Gao Liming wrote:
>
> Min:
> I have two comments in MdePkg. The changes in MdeModulePkg are good
> to me.
> 1. Seemly, new APIs (TdCall, TdVmCall, TdIsEnabled) in BaseLib are X86
> specific. How about define them in #if defined (MDE_CPU_IA32) || defined
> (MDE_CPU_X64) in BaseLib.h?
Sure. It will be updated in the next version.
> 2. I don't find new resource attribute EFI_RESOURCE_ATTRIBUTE_ENCRYPTED
> in the latest PI PI_Spec_1_7_A_final_May1.pdf. Can you let me know which
> spec defines it?
EFI_RESOURCE_ATTRIBUTE_ENCRYPTED is deprecated. According to [TDVF] Table 7-1 private memory is distinguished with Unaccepted Memory by ResourceType (Private Mem is EFI_RESOURCE_SYSTEM_MEMORY, Unaccepted Mem is EFI_RESOURCE_MEMORY_UNACCEPTED). There is a PR about EFI_RESOURCE_MEMORY_UNACCEPTED and the PR is approved. https://github.com/microsoft/mu_basecore/pull/66
So in the next version EFI_RESOURCE_ATTRIBUTE_ENCRYPTED will be deleted.
Thanks
Min
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A)
2022-03-01 6:39 ` Min Xu
@ 2022-03-01 6:53 ` Yao, Jiewen
0 siblings, 0 replies; 72+ messages in thread
From: Yao, Jiewen @ 2022-03-01 6:53 UTC (permalink / raw)
To: Xu, Min M, devel@edk2.groups.io, Gao, Liming
Cc: 'Brijesh Singh', Dong, Eric, Aktas, Erdem, Wu, Hao A,
Wang, Jian J, 'James Bottomley', Kinney, Michael D,
Ni, Ray, Kumar, Rahul1, 'Tom Lendacky', Liu, Zhiguang,
'Gerd Hoffmann'
Just to clarify below:
#define EFI_RESOURCE_MEMORY_UNACCEPTED 0x00000007
This is proposed in https://github.com/microsoft/mu_basecore/pull/66/files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9e4R237, according to UEFI-Code-First.
The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification.
Thank you
Yao Jiewen
> -----Original Message-----
> From: Xu, Min M <min.m.xu@intel.com>
> Sent: Tuesday, March 1, 2022 2:40 PM
> To: devel@edk2.groups.io; Gao, Liming <gaoliming@byosoft.com.cn>
> Cc: 'Brijesh Singh' <brijesh.singh@amd.com>; Dong, Eric <eric.dong@intel.com>;
> Aktas, Erdem <erdemaktas@google.com>; Wu, Hao A <hao.a.wu@intel.com>;
> Wang, Jian J <jian.j.wang@intel.com>; 'James Bottomley' <jejb@linux.ibm.com>;
> Yao, Jiewen <jiewen.yao@intel.com>; Kinney, Michael D
> <michael.d.kinney@intel.com>; Ni, Ray <ray.ni@intel.com>; Kumar, Rahul1
> <rahul1.kumar@intel.com>; 'Tom Lendacky' <thomas.lendacky@amd.com>; Liu,
> Zhiguang <zhiguang.liu@intel.com>; 'Gerd Hoffmann' <kraxel@redhat.com>
> Subject: RE: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg
> (Config-A)
>
> On March 1, 2022 10:20 AM, Gao Liming wrote:
> >
> > Min:
> > I have two comments in MdePkg. The changes in MdeModulePkg are good
> > to me.
> > 1. Seemly, new APIs (TdCall, TdVmCall, TdIsEnabled) in BaseLib are X86
> > specific. How about define them in #if defined (MDE_CPU_IA32) || defined
> > (MDE_CPU_X64) in BaseLib.h?
> Sure. It will be updated in the next version.
>
> > 2. I don't find new resource attribute EFI_RESOURCE_ATTRIBUTE_ENCRYPTED
> > in the latest PI PI_Spec_1_7_A_final_May1.pdf. Can you let me know which
> > spec defines it?
> EFI_RESOURCE_ATTRIBUTE_ENCRYPTED is deprecated. According to [TDVF]
> Table 7-1 private memory is distinguished with Unaccepted Memory by
> ResourceType (Private Mem is EFI_RESOURCE_SYSTEM_MEMORY, Unaccepted
> Mem is EFI_RESOURCE_MEMORY_UNACCEPTED). There is a PR about
> EFI_RESOURCE_MEMORY_UNACCEPTED and the PR is approved.
> https://github.com/microsoft/mu_basecore/pull/66
> So in the next version EFI_RESOURCE_ATTRIBUTE_ENCRYPTED will be deleted.
>
> Thanks
> Min
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A)
2022-03-01 2:19 ` 回复: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A) gaoliming
2022-03-01 6:39 ` Min Xu
@ 2022-03-10 6:21 ` Min Xu
2022-03-11 3:19 ` 回复: " gaoliming
1 sibling, 1 reply; 72+ messages in thread
From: Min Xu @ 2022-03-10 6:21 UTC (permalink / raw)
To: devel@edk2.groups.io, Gao, Liming
Cc: 'Brijesh Singh', Dong, Eric, Aktas, Erdem, Wu, Hao A,
Wang, Jian J, 'James Bottomley', Yao, Jiewen,
Kinney, Michael D, Ni, Ray, Kumar, Rahul1, 'Tom Lendacky',
Liu, Zhiguang, 'Gerd Hoffmann'
Hi, Lingming
Besides below 2 comments in MdePkg, what's your opinion about below patches in MdePkg?
Patch 01 includes the Intel Trust Domain Extension definitions.
Patch 07-10 is about the BaseIoLibIntrinsic
Patch 12 add macros CC_GUEST_IS_SEV / CC_GUEST_IS_TDX to check SEV / TDX guest.
I am looking forward your comments about Patch 07 - 10.
01-MdePkg-Add-Tdx.h.patch
- https://edk2.groups.io/g/devel/message/87049
03-MdePkg-Add-TdxLib-to-wrap-Tdx-operations.patch
- https://edk2.groups.io/g/devel/message/87051
07-MdePkg-Add-helper-functions-for-Tdx-guest-in-BaseIoL.patch
- https://edk2.groups.io/g/devel/message/87055
08-MdePkg-Support-mmio-for-Tdx-guest-in-BaseIoLibIntrin.patch
- https://edk2.groups.io/g/devel/message/87056
09-MdePkg-Support-IoFifo-for-Tdx-guest-in-BaseIoLibIntr.patch
- https://edk2.groups.io/g/devel/message/87057
10-MdePkg-Support-IoRead-IoWrite-for-Tdx-guest-in-BaseI.patch
- https://edk2.groups.io/g/devel/message/87058
12-MdePkg-Add-macro-to-check-SEV-TDX-guest.patch
- https://edk2.groups.io/g/devel/message/87060
Thanks much!
> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of gaoliming
> Sent: Tuesday, March 1, 2022 10:20 AM
> To: devel@edk2.groups.io; Xu, Min M <min.m.xu@intel.com>
> Cc: 'Brijesh Singh' <brijesh.singh@amd.com>; Dong, Eric
> <eric.dong@intel.com>; Aktas, Erdem <erdemaktas@google.com>; Wu, Hao A
> <hao.a.wu@intel.com>; Wang, Jian J <jian.j.wang@intel.com>; 'James
> Bottomley' <jejb@linux.ibm.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Kinney, Michael D <michael.d.kinney@intel.com>; Ni, Ray <ray.ni@intel.com>;
> Kumar, Rahul1 <rahul1.kumar@intel.com>; 'Tom Lendacky'
> <thomas.lendacky@amd.com>; Liu, Zhiguang <zhiguang.liu@intel.com>; 'Gerd
> Hoffmann' <kraxel@redhat.com>
> Subject: 回复: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg
> (Config-A)
>
> Min:
> I have two comments in MdePkg. The changes in MdeModulePkg are good to
> me.
> 1. Seemly, new APIs (TdCall, TdVmCall, TdIsEnabled) in BaseLib are X86 specific.
> How about define them in #if defined (MDE_CPU_IA32) || defined
> (MDE_CPU_X64) in BaseLib.h?
> 2. I don't find new resource attribute EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in
> the latest PI PI_Spec_1_7_A_final_May1.pdf. Can you let me know which spec
> defines it?
>
> Thanks
> Liming
> > -----邮件原件-----
> > 发件人: devel@edk2.groups.io <devel@edk2.groups.io> 代表 Min Xu
> > 发送时间: 2022年2月28日 15:21
> > 收件人: devel@edk2.groups.io
> > 抄送: Min Xu <min.m.xu@intel.com>; Brijesh Singh
> > <brijesh.singh@amd.com>; Eric Dong <eric.dong@intel.com>; Erdem Aktas
> > <erdemaktas@google.com>; Hao A Wu <hao.a.wu@intel.com>; Jian J Wang
> > <jian.j.wang@intel.com>; James Bottomley <jejb@linux.ibm.com>; Jiewen
> > Yao <jiewen.yao@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>;
> > Michael D Kinney <michael.d.kinney@intel.com>; Ray Ni
> > <ray.ni@intel.com>; Rahul Kumar <rahul1.kumar@intel.com>; Tom Lendacky
> > <thomas.lendacky@amd.com>; Zhiguang Liu <zhiguang.liu@intel.com>; Gerd
> > Hoffmann <kraxel@redhat.com>
> > 主题: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg
> > (Config-A)
> >
> > REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3249
> >
> > 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.
> >
> > There are 2 configurations for TDVF to upstream. See below link for
> > the definitions of the 2 configurations.
> > https://edk2.groups.io/g/devel/message/76367
> >
> > This patch-set is to enable Config-A in OvmfPkg.
> > - Merge the *basic* TDVF feature to existing OvmfX64Pkg.dsc. (Align
> > with existing SEV)
> > - Threat model: VMM is NOT out of TCB. (We don’t make things worse.)
> > - The OvmfX64Pkg.dsc includes SEV/TDX/normal OVMF basic boot capability.
> > The final binary can run on SEV/TDX/normal OVMF
> > - No changes to existing OvmfPkgX64 image layout.
> > - No need to add additional security features if they do not exist
> > today
> > - No need to remove features if they exist today.
> > - RTMR is not supported
> > - PEI phase is NOT skipped in either Td or Non-Td
> >
> > Patch 01 - 23 are changes in SEC phase. Also some libraries in these
> > patches are workable in SEC/PEI/DXE.
> >
> > Patch 17 - 20 extract the common codes from OvmfPkg/PlatformPei to a
> > new PlatformInitLib. Then OvmfPkg/PlatformPei is refactored with this lib.
> > This is because there are 3 variants of PlatformPei in OvmfPkg and
> > hence many codes are duplicated.
> > Patch 21 then add Tdx specific codes in PlatformInitLib.
> >
> > Patch 24 - 29 are changes in PEI phase.
> >
> > Patch 30 - 34 are changes in DXE phase.
> >
> > Patch 35 - 37 are for local Apic timer DXE driver.
> >
> > [TDX]: https://software.intel.com/content/dam/develop/external/us/en/
> > documents/tdx-whitepaper-final9-17.pdf
> >
> > [TDX-Module]: https://software.intel.com/content/dam/develop/external/
> > us/en/documents/tdx-module-1.0-public-spec-v0.931.pdf
> >
> > [TDVF]: https://software.intel.com/content/dam/develop/external/us/en/
> > documents/tdx-virtual-firmware-design-guide-rev-1.pdf
> >
> > [GCHI]: https://software.intel.com/content/dam/develop/external/us/en/
> > documents/intel-tdx-guest-hypervisor-communication-interface-1.0-34442
> > 6-
> > 002.pdf
> >
> > Code is at https://github.com/mxu9/edk2/tree/tdvf_wave2.v7
> >
> > v7 changes:
> > - Based on the comments from last review, 8 PlatformInitLib patches
> > are squashed into 4 patches (#17-#20). These 4 patches are not
> > related to Tdx guest. Tdx related codes of PlatformInitLib is
> > in #21.
> > - gUefiOvmfPkgTdxPlatformGuid is renamed as
> > gUefiOvmfPkgPlatformInfoGuid.
> > Because this GUID is used not only by Tdx guest, but also by
> > Legacy guest.
> > - PlatformInitLibNull is deleted.
> > - In PlatformPei Pml4Entries is cap at 512 entries when
> > mPhysMemAddressWidth > 48.
> >
> > v7 not-addressed comments
> > - Comments in MpInitLib have not been addressed yet. It will be
> > addressed in the following version.
> > - Thanks much for your understanding.
> >
> > v6 changes:
> > - PlatformInitLib and OvmfPkg/PlatformPei refactoring are covered in
> > patch from 17 - 24. These patches are not related to Tdx guest. Tdx
> > related codes of PlatformInitLib is in patch 25.
> > - In the previous patch-sets, TdHob is processed in
> > OvmfPkg/Sec/IntelTdx.c. Per Gerd's suggestion they are now moved
> > to PlatformInitLib/IntelTdx.c. So that they can be reused in Config-B.
> > - The default Accept page size is changed from 4K to 2M.
> > - The BspAcceptMemoryResourceRange is refactored according to Gerd's
> > comment.
> > - In ApRunLoop.nasm command field is set to zero as acknowledgement.
> > This is a fix based on the ACPI Spec v6.4,Sec titled "Multiprocessor
> > Wakeup Structure".
> >
> > v6 not-addressed comments
> > - Comments in MpInitLib have not been addressed yet. It will be
> > addressed in the following version.
> > - Thanks much for your understanding.
> >
> > v5 changes:
> > - PlatformInitLib is introduced which wraps the common functions in
> > OvmfPkg/PlatformPei. It is because there are a lot of duplicated
> > codes for Platform initialization in PEI phase and there are at least
> > 3 variants of PlatformPei. Another reason is that in TDVF Config-B
> > PEI-less boot needs the similar initiliazation as PlatformPei. Based
> > on the discussion with the community, PlatformInitLib is introduced.
> > As the first stage OvmfPkg/PlatformPei is refactored with this lib.
> > In the future the other 2 PlatformPei variants will be refactored
> > as well.
> > - PcdIgnoreVeHalt is deprecated.
> > - Add spec link for Mailbox.
> > - Other minor changes, such as comments, uncrustify formats, etc.
> >
> > v5 not-addressed comments
> > - Comments in MpInitLib have not been addressed yet. It will be
> > addressed in the following version.
> > - Some comments may be missed. I will re-visit the review emails.
> > - Thanks much for your understanding.
> >
> > v4 changes:
> > - Split the TdxLib into 2 libraries. The TDX basic functions
> > (TdCall / TdVmCall / TdIsEnabled) are moved to BaseLib (#2).
> > The other functions are in TdxLib. (#3)
> > - Based on above changes (TdCall/TdVmCall/TdIsEnabled in BaseLib)
> > the TdxLib.inf is not necessary in some Pkgs, such as
> > UefiPayloadPkg. The duplicated source code are deleted (BaseIoLib
> > is the sample).
> > - Drop the Accepting pages with TDX MP service. Instead only BSP
> > accepts pages. There maybe boot performance issue. There are some
> > mitigations to it, such as 2M accept page size, lazy accept, etc.
> > We will re-visit this issue in a separate patch-set.
> > - Relocate Mailbox in TdxDxe driver instead of in PlatformPei. This
> > is to keep consistence with Config-B (PEI is skipped in Config-B).
> > - SetMmioSharedBit in TdxDxe driver instead of in DxeIplPeim after
> > CreateIdentityMappingPageTables. This is to keep consistence with
> > Config-B (PEI is skipped in Config-B).
> > - Some other minor changes, such as switch-case indention.
> > - Rebase the code base (commit: 8c06c53b585a) and update the code with
> > uncrustify.
> >
> > v4 not-addressed comments:
> > - Comments in MpInitLib have not been addressed yet. It will be
> > addressed in the next version.
> > - BaseMemEncryptTdxLib is suggested to be merged with
> > BaseMemEncryptSevLib. It will be addressed in the next version.
> > - Gerd suggests a generic page table walker which is able to set
> > and clear bits for a given memory range in both SEV and TDX guest.
> > This suggestion will be addressed in the next version.
> > - Some comments may be missed. I will re-visit the review emails.
> > - Thanks much for your understanding.
> >
> > v3 changes:
> > - LocalApicTimerDxe is split out to be a separate patch-series.
> > - VmTdExitLibNull/VmgExitLib are removed. Instead the VmgExitLib
> > is extended to handle #VE exception. (Patch 3-5)
> > - Split the Tdx support of base IoLib into 4 commits. (Patch 6-9)
> > - Alter of MADT table is updated. In previous version it was
> > created from scratch. Now it gets the installed table, copy
> > it to a larger buffer and append the ACPI_MADT_MPWK to it.
> > (Patch 25)
> > - Changes in BaseXApicX2ApicLib is refined based on the
> > feedbacks. (Add spec link of MSR access definition, rename
> > some funtion name, etc.) (Patch 11)
> > - Use PcdConfidentialComputingGuestAttr to probe TDX guest instead
> > of CPUID. But in some cases PcdConfidentialComputingGuestAttr
> > cannot be used because it has not been set yet.
> > - Some other minor changes.
> >
> > v3 not-addressed comments:
> > - Some of the comments have not been addressed. This is because I
> > need more time to consider how to address these comments.
> > At the same time I want to submit a new version based on the above
> > changes so that community can review in a more efficient way.
> > (v2 is the version one month ago).
> > - Comments in MpInitLib have not been addressed yet. It will be
> > addressed in v4.
> > - BaseMemEncryptTdxLib should be merged with BaseMemEncryptSevLib.
> > It will be addressed in v4.
> > - Some comments may be missed. I will re-visit the review emails.
> > - Thanks much for your understanding.
> >
> > v2 changes:
> > - Remove TdxProbeLib. It is to reduce the depencies of the lib.
> > - In v1 a new function (AllocatePagesWithMemoryType) is added in
> > PeiMemoryAllocationLib. This function is not necessary. It can
> > be replaced by PeiServicesAllocatePages.
> > - IoLibFifo.c is added in BaseIoLibIntrinsic. This file includes
> > the functions of read/write of I/O port fifo. These functions
> > will call TdIoReadFifo or SevIoReadFifo by checking TDX or SEV
> > in run-time.
> > - DXE related patches are added. (Patch 22-28)
> > - Fix typo in commit/comment message, or some minor changes.
> > - Rebase the edk2 code base. (4cc1458dbe00)
> >
> > Cc: Brijesh Singh <brijesh.singh@amd.com>
> > Cc: Eric Dong <eric.dong@intel.com>
> > Cc: Erdem Aktas <erdemaktas@google.com>
> > Cc: Hao A Wu <hao.a.wu@intel.com>
> > Cc: Jian J Wang <jian.j.wang@intel.com>
> > Cc: James Bottomley <jejb@linux.ibm.com>
> > Cc: Jiewen Yao <jiewen.yao@intel.com>
> > Cc: Liming Gao <gaoliming@byosoft.com.cn>
> > Cc: Michael D Kinney <michael.d.kinney@intel.com>
> > Cc: Ray Ni <ray.ni@intel.com>
> > Cc: Rahul Kumar <rahul1.kumar@intel.com>
> > Cc: Tom Lendacky <thomas.lendacky@amd.com>
> > Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > Signed-off-by: Min Xu <min.m.xu@intel.com>
> >
> > Min Xu (37):
> > MdePkg: Add Tdx.h
> > MdePkg: Introduce basic Tdx functions in BaseLib
> > MdePkg: Add TdxLib to wrap Tdx operations
> > UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception
> > OvmfPkg: Extend VmgExitLib to handle #VE exception
> > UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
> > MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic
> > MdePkg: Support mmio for Tdx guest in BaseIoLibIntrinsic
> > MdePkg: Support IoFifo for Tdx guest in BaseIoLibIntrinsic
> > MdePkg: Support IoRead/IoWrite for Tdx guest in BaseIoLibIntrinsic
> > UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
> > MdePkg: Add macro to check SEV / TDX guest
> > UefiCpuPkg: Enable Tdx support in MpInitLib
> > OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
> > OvmfPkg: Add TdxMailboxLib
> > MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h
> > OvmfPkg: Create initial version of PlatformInitLib
> > OvmfPkg/PlatformInitLib: Add hob functions
> > OvmfPkg/PlatformInitLib: Add memory functions
> > OvmfPkg/PlatformInitLib: Add platform functions
> > OvmfPkg: Update PlatformInitLib to process Tdx hoblist
> > OvmfPkg/Sec: Declare local variable as volatile in
> > SecCoreStartupWithStack
> > OvmfPkg: Update Sec to support Tdx
> > OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
> > MdeModulePkg: EFER should not be changed in TDX
> > MdeModulePkg: Add PcdTdxSharedBitMask
> > UefiCpuPkg: Update AddressEncMask in CpuPageTable
> > OvmfPkg: Update PlatformInitLib for Tdx guest to publish ram regions
> > OvmfPkg: Update PlatformPei to support Tdx guest
> > OvmfPkg: Update AcpiPlatformDxe to alter MADT table
> > OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
> > OvmfPkg: Add TdxDxe driver
> > OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe
> > OvmfPkg: Update IoMmuDxe to support TDX
> > OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe
> > UefiCpuPkg: Setting initial-count register as the last step
> > OvmfPkg: Switch timer in build time for OvmfPkg
> >
> > MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 1 +
> > .../Core/DxeIplPeim/X64/VirtualMemory.c | 7 +
> > MdeModulePkg/MdeModulePkg.dec | 9 +
> > .../Include/ConfidentialComputingGuestAttr.h | 3 +
> > MdePkg/Include/IndustryStandard/Tdx.h | 203 ++++
> > MdePkg/Include/Library/BaseLib.h | 62 ++
> > MdePkg/Include/Library/TdxLib.h | 97 ++
> > MdePkg/Include/Pi/PiHob.h | 8 +
> > .../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf | 2 +
> > .../BaseIoLibIntrinsicSev.inf | 7 +
> > MdePkg/Library/BaseIoLibIntrinsic/IoLib.c | 81 +-
> > MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c | 216 ++++
> > MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c | 51 +-
> > .../BaseIoLibIntrinsic/IoLibInternalTdx.c | 675 +++++++++++++
> > .../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 497 +++++++++
> > MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c | 73 +-
> > MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h | 166 +++
> > MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h | 410 ++++++++
> > .../BaseIoLibIntrinsic/X64/IoFifoSev.nasm | 34 +-
> > MdePkg/Library/BaseLib/BaseLib.inf | 11 +
> > MdePkg/Library/BaseLib/IntelTdxNull.c | 83 ++
> > MdePkg/Library/BaseLib/X64/TdCall.nasm | 85 ++
> > MdePkg/Library/BaseLib/X64/TdProbe.c | 62 ++
> > MdePkg/Library/BaseLib/X64/TdVmcall.nasm | 145 +++
> > MdePkg/Library/TdxLib/AcceptPages.c | 180 ++++
> > MdePkg/Library/TdxLib/Rtmr.c | 83 ++
> > MdePkg/Library/TdxLib/TdInfo.c | 114 +++
> > MdePkg/Library/TdxLib/TdxLib.inf | 37 +
> > MdePkg/Library/TdxLib/TdxLibNull.c | 107 ++
> > MdePkg/MdePkg.dec | 3 +
> > MdePkg/MdePkg.dsc | 1 +
> > OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf | 1 +
> > OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c | 14 +-
> > OvmfPkg/AmdSev/AmdSevX64.dsc | 8 +-
> > OvmfPkg/AmdSev/AmdSevX64.fdf | 3 +-
> > OvmfPkg/Bhyve/BhyveX64.dsc | 2 +
> > OvmfPkg/CloudHv/CloudHvX64.dsc | 5 +-
> > OvmfPkg/CloudHv/CloudHvX64.fdf | 2 +-
> > OvmfPkg/Include/IndustryStandard/IntelTdx.h | 67 ++
> > OvmfPkg/Include/Library/MemEncryptTdxLib.h | 81 ++
> > OvmfPkg/Include/Library/PlatformInitLib.h | 286 ++++++
> > OvmfPkg/Include/Library/TdxMailboxLib.h | 76 ++
> > .../Include/Protocol/QemuAcpiTableNotify.h | 27 +
> > OvmfPkg/Include/TdxCommondefs.inc | 51 +
> > OvmfPkg/IoMmuDxe/AmdSevIoMmu.c | 103 +-
> > OvmfPkg/IoMmuDxe/AmdSevIoMmu.h | 6 +-
> > OvmfPkg/IoMmuDxe/IoMmuDxe.c | 6 +-
> > OvmfPkg/IoMmuDxe/IoMmuDxe.inf | 5 +
> > .../BaseMemEncryptTdxLib.inf | 44 +
> > .../BaseMemEncryptTdxLibNull.inf | 35 +
> > .../BaseMemoryEncryptionNull.c | 90 ++
> > .../BaseMemEncryptTdxLib/MemoryEncryption.c | 948
> > ++++++++++++++++++
> > .../BaseMemEncryptTdxLib/VirtualMemory.h | 181 ++++
> > .../PlatformInitLib}/Cmos.c | 32 +-
> > OvmfPkg/Library/PlatformInitLib/IntelTdx.c | 553 ++++++++++
> > .../Library/PlatformInitLib/IntelTdxNull.c | 46 +
> > OvmfPkg/Library/PlatformInitLib/MemDetect.c | 707 +++++++++++++
> > OvmfPkg/Library/PlatformInitLib/Platform.c | 597 +++++++++++
> > .../PlatformInitLib/PlatformInitLib.inf | 94 ++
> > OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c | 9 +-
> > .../Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf | 1 +
> > .../QemuFwCfgLib/QemuFwCfgLibInternal.h | 11 +
> > OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c | 32 +
> > .../Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf | 2 +
> > OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c | 140 +++
> > .../Library/TdxMailboxLib/TdxMailboxLib.inf | 52 +
> > .../Library/TdxMailboxLib/TdxMailboxNull.c | 85 ++
> > OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf | 3 +-
> > OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h | 32 +
> > .../Library/VmgExitLib/VmTdExitVeHandler.c | 559 +++++++++++
> > OvmfPkg/Library/VmgExitLib/VmgExitLib.inf | 2 +
> > .../Library/VmgExitLib/X64/TdVmcallCpuid.nasm | 146 +++
> > .../LocalApicTimerDxe.c} | 4 +-
> > .../LocalApicTimerDxe.h} | 4 +-
> > .../LocalApicTimerDxe.inf} | 7 +-
> > OvmfPkg/Microvm/MicrovmX64.dsc | 5 +-
> > OvmfPkg/Microvm/MicrovmX64.fdf | 2 +-
> > OvmfPkg/OvmfPkg.dec | 17 +
> > OvmfPkg/OvmfPkgIa32.dsc | 12 +-
> > OvmfPkg/OvmfPkgIa32.fdf | 8 +-
> > OvmfPkg/OvmfPkgIa32X64.dsc | 14 +-
> > OvmfPkg/OvmfPkgIa32X64.fdf | 8 +-
> > OvmfPkg/OvmfPkgX64.dsc | 29 +-
> > OvmfPkg/OvmfPkgX64.fdf | 11 +-
> > OvmfPkg/OvmfXen.dsc | 4 +-
> > OvmfPkg/OvmfXen.fdf | 2 +-
> > OvmfPkg/PlatformPei/Cmos.h | 48 -
> > OvmfPkg/PlatformPei/FeatureControl.c | 7 +-
> > OvmfPkg/PlatformPei/IntelTdx.c | 54 +
> > OvmfPkg/PlatformPei/MemDetect.c | 669 +-----------
> > OvmfPkg/PlatformPei/Platform.c | 522 ++--------
> > OvmfPkg/PlatformPei/Platform.h | 55 +-
> > OvmfPkg/PlatformPei/PlatformPei.inf | 7 +-
> > OvmfPkg/Sec/SecMain.c | 44 +-
> > OvmfPkg/Sec/SecMain.inf | 3 +
> > OvmfPkg/Sec/X64/SecEntry.nasm | 82 ++
> > OvmfPkg/TdxDxe/TdxAcpiTable.c | 213 ++++
> > OvmfPkg/TdxDxe/TdxAcpiTable.h | 60 ++
> > OvmfPkg/TdxDxe/TdxDxe.c | 261 +++++
> > OvmfPkg/TdxDxe/TdxDxe.inf | 64 ++
> > OvmfPkg/TdxDxe/X64/ApRunLoop.nasm | 90 ++
> > UefiCpuPkg/CpuDxe/CpuDxe.inf | 1 +
> > UefiCpuPkg/CpuDxe/CpuPageTable.c | 4 +
> > UefiCpuPkg/Include/Library/VmgExitLib.h | 28 +
> > .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c | 170 +++-
> > .../PeiDxeSmmCpuException.c | 17 +
> > .../SecPeiCpuException.c | 18 +
> > UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 3 +
> > UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 15 +-
> > UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h | 71 ++
> > UefiCpuPkg/Library/MpInitLib/MpLib.c | 27 +
> > UefiCpuPkg/Library/MpInitLib/MpLibTdx.c | 128 +++
> > UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c | 73 ++
> > UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 3 +
> > .../Library/VmgExitLibNull/VmTdExitNull.c | 38 +
> > .../Library/VmgExitLibNull/VmgExitLibNull.inf | 1 +
> > 116 files changed, 10233 insertions(+), 1327 deletions(-) create
> > mode 100644 MdePkg/Include/IndustryStandard/Tdx.h
> > create mode 100644 MdePkg/Include/Library/TdxLib.h create mode
> > 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
> > create mode 100644
> > MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
> > create mode 100644
> > MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
> > create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h
> > create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
> > create mode 100644 MdePkg/Library/BaseLib/IntelTdxNull.c
> > create mode 100644 MdePkg/Library/BaseLib/X64/TdCall.nasm
> > create mode 100644 MdePkg/Library/BaseLib/X64/TdProbe.c
> > create mode 100644 MdePkg/Library/BaseLib/X64/TdVmcall.nasm
> > create mode 100644 MdePkg/Library/TdxLib/AcceptPages.c
> > create mode 100644 MdePkg/Library/TdxLib/Rtmr.c create mode 100644
> > MdePkg/Library/TdxLib/TdInfo.c create mode 100644
> > MdePkg/Library/TdxLib/TdxLib.inf create mode 100644
> > MdePkg/Library/TdxLib/TdxLibNull.c
> > create mode 100644 OvmfPkg/Include/IndustryStandard/IntelTdx.h
> > create mode 100644 OvmfPkg/Include/Library/MemEncryptTdxLib.h
> > create mode 100644 OvmfPkg/Include/Library/PlatformInitLib.h
> > create mode 100644 OvmfPkg/Include/Library/TdxMailboxLib.h
> > create mode 100644 OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h
> > create mode 100644 OvmfPkg/Include/TdxCommondefs.inc create mode
> > 100644
> OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
> > create mode 100644
> > OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
> > create mode 100644
> > OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
> > create mode 100644
> > OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
> > create mode 100644
> > OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h
> > rename OvmfPkg/{PlatformPei => Library/PlatformInitLib}/Cmos.c (61%)
> > create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdx.c
> > create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
> > create mode 100644 OvmfPkg/Library/PlatformInitLib/MemDetect.c
> > create mode 100644 OvmfPkg/Library/PlatformInitLib/Platform.c
> > create mode 100644
> > OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
> > create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
> > create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
> > create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c
> > create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
> > create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
> > create mode 100644 OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm
> > rename OvmfPkg/{XenTimerDxe/XenTimerDxe.c =>
> > LocalApicTimerDxe/LocalApicTimerDxe.c} (95%) rename
> > OvmfPkg/{XenTimerDxe/XenTimerDxe.h =>
> > LocalApicTimerDxe/LocalApicTimerDxe.h} (96%) rename
> > OvmfPkg/{XenTimerDxe/XenTimerDxe.inf =>
> > LocalApicTimerDxe/LocalApicTimerDxe.inf} (80%) delete mode 100644
> > OvmfPkg/PlatformPei/Cmos.h create mode 100644
> > OvmfPkg/PlatformPei/IntelTdx.c create mode 100644
> > OvmfPkg/TdxDxe/TdxAcpiTable.c create mode 100644
> > OvmfPkg/TdxDxe/TdxAcpiTable.h create mode 100644
> > OvmfPkg/TdxDxe/TdxDxe.c create mode 100644
> OvmfPkg/TdxDxe/TdxDxe.inf
> > create mode 100644 OvmfPkg/TdxDxe/X64/ApRunLoop.nasm create mode
> > 100644 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
> > create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
> > create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
> > create mode 100644 UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c
> >
> > --
> > 2.29.2.windows.2
> >
> >
> >
> >
> >
>
>
>
>
>
>
>
^ permalink raw reply [flat|nested] 72+ messages in thread
* 回复: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A)
2022-03-10 6:21 ` Min Xu
@ 2022-03-11 3:19 ` gaoliming
2022-03-11 7:17 ` Min Xu
0 siblings, 1 reply; 72+ messages in thread
From: gaoliming @ 2022-03-11 3:19 UTC (permalink / raw)
To: devel, min.m.xu
Cc: 'Brijesh Singh', 'Dong, Eric',
'Aktas, Erdem', 'Wu, Hao A',
'Wang, Jian J', 'James Bottomley',
'Yao, Jiewen', 'Kinney, Michael D',
'Ni, Ray', 'Kumar, Rahul1',
'Tom Lendacky', 'Liu, Zhiguang',
'Gerd Hoffmann'
Min:
I have one minor comment for TdxLib.h. This header file doesn't need to include below header files. Other patches in MdePkg are good to me. Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Uefi/UefiBaseType.h>
#include <Protocol/DebugSupport.h>
Thanks
Liming
> -----邮件原件-----
> 发件人: devel@edk2.groups.io <devel@edk2.groups.io> 代表 Min Xu
> 发送时间: 2022年3月10日 14:21
> 收件人: devel@edk2.groups.io; Gao, Liming <gaoliming@byosoft.com.cn>
> 抄送: 'Brijesh Singh' <brijesh.singh@amd.com>; Dong, Eric
> <eric.dong@intel.com>; Aktas, Erdem <erdemaktas@google.com>; Wu, Hao
> A <hao.a.wu@intel.com>; Wang, Jian J <jian.j.wang@intel.com>; 'James
> Bottomley' <jejb@linux.ibm.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Kinney, Michael D <michael.d.kinney@intel.com>; Ni, Ray <ray.ni@intel.com>;
> Kumar, Rahul1 <rahul1.kumar@intel.com>; 'Tom Lendacky'
> <thomas.lendacky@amd.com>; Liu, Zhiguang <zhiguang.liu@intel.com>;
> 'Gerd Hoffmann' <kraxel@redhat.com>
> 主题: Re: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg
> (Config-A)
>
> Hi, Lingming
> Besides below 2 comments in MdePkg, what's your opinion about below
> patches in MdePkg?
> Patch 01 includes the Intel Trust Domain Extension definitions.
> Patch 07-10 is about the BaseIoLibIntrinsic
> Patch 12 add macros CC_GUEST_IS_SEV / CC_GUEST_IS_TDX to check SEV /
> TDX guest.
>
> I am looking forward your comments about Patch 07 - 10.
>
> 01-MdePkg-Add-Tdx.h.patch
> - https://edk2.groups.io/g/devel/message/87049
> 03-MdePkg-Add-TdxLib-to-wrap-Tdx-operations.patch
> - https://edk2.groups.io/g/devel/message/87051
>
> 07-MdePkg-Add-helper-functions-for-Tdx-guest-in-BaseIoL.patch
> - https://edk2.groups.io/g/devel/message/87055
> 08-MdePkg-Support-mmio-for-Tdx-guest-in-BaseIoLibIntrin.patch
> - https://edk2.groups.io/g/devel/message/87056
> 09-MdePkg-Support-IoFifo-for-Tdx-guest-in-BaseIoLibIntr.patch
> - https://edk2.groups.io/g/devel/message/87057
> 10-MdePkg-Support-IoRead-IoWrite-for-Tdx-guest-in-BaseI.patch
> - https://edk2.groups.io/g/devel/message/87058
>
> 12-MdePkg-Add-macro-to-check-SEV-TDX-guest.patch
> - https://edk2.groups.io/g/devel/message/87060
>
> Thanks much!
>
> > -----Original Message-----
> > From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of
> gaoliming
> > Sent: Tuesday, March 1, 2022 10:20 AM
> > To: devel@edk2.groups.io; Xu, Min M <min.m.xu@intel.com>
> > Cc: 'Brijesh Singh' <brijesh.singh@amd.com>; Dong, Eric
> > <eric.dong@intel.com>; Aktas, Erdem <erdemaktas@google.com>; Wu, Hao
> A
> > <hao.a.wu@intel.com>; Wang, Jian J <jian.j.wang@intel.com>; 'James
> > Bottomley' <jejb@linux.ibm.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> > Kinney, Michael D <michael.d.kinney@intel.com>; Ni, Ray
> <ray.ni@intel.com>;
> > Kumar, Rahul1 <rahul1.kumar@intel.com>; 'Tom Lendacky'
> > <thomas.lendacky@amd.com>; Liu, Zhiguang <zhiguang.liu@intel.com>;
> 'Gerd
> > Hoffmann' <kraxel@redhat.com>
> > Subject: 回复: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg
> > (Config-A)
> >
> > Min:
> > I have two comments in MdePkg. The changes in MdeModulePkg are
> good to
> > me.
> > 1. Seemly, new APIs (TdCall, TdVmCall, TdIsEnabled) in BaseLib are X86
> specific.
> > How about define them in #if defined (MDE_CPU_IA32) || defined
> > (MDE_CPU_X64) in BaseLib.h?
> > 2. I don't find new resource attribute
> EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in
> > the latest PI PI_Spec_1_7_A_final_May1.pdf. Can you let me know which
> spec
> > defines it?
> >
> > Thanks
> > Liming
> > > -----邮件原件-----
> > > 发件人: devel@edk2.groups.io <devel@edk2.groups.io> 代表 Min Xu
> > > 发送时间: 2022年2月28日 15:21
> > > 收件人: devel@edk2.groups.io
> > > 抄送: Min Xu <min.m.xu@intel.com>; Brijesh Singh
> > > <brijesh.singh@amd.com>; Eric Dong <eric.dong@intel.com>; Erdem
> Aktas
> > > <erdemaktas@google.com>; Hao A Wu <hao.a.wu@intel.com>; Jian J
> Wang
> > > <jian.j.wang@intel.com>; James Bottomley <jejb@linux.ibm.com>;
> Jiewen
> > > Yao <jiewen.yao@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>;
> > > Michael D Kinney <michael.d.kinney@intel.com>; Ray Ni
> > > <ray.ni@intel.com>; Rahul Kumar <rahul1.kumar@intel.com>; Tom
> Lendacky
> > > <thomas.lendacky@amd.com>; Zhiguang Liu <zhiguang.liu@intel.com>;
> Gerd
> > > Hoffmann <kraxel@redhat.com>
> > > 主题: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg
> > > (Config-A)
> > >
> > > REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3249
> > >
> > > 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.
> > >
> > > There are 2 configurations for TDVF to upstream. See below link for
> > > the definitions of the 2 configurations.
> > > https://edk2.groups.io/g/devel/message/76367
> > >
> > > This patch-set is to enable Config-A in OvmfPkg.
> > > - Merge the *basic* TDVF feature to existing OvmfX64Pkg.dsc. (Align
> > > with existing SEV)
> > > - Threat model: VMM is NOT out of TCB. (We don’t make things worse.)
> > > - The OvmfX64Pkg.dsc includes SEV/TDX/normal OVMF basic boot
> capability.
> > > The final binary can run on SEV/TDX/normal OVMF
> > > - No changes to existing OvmfPkgX64 image layout.
> > > - No need to add additional security features if they do not exist
> > > today
> > > - No need to remove features if they exist today.
> > > - RTMR is not supported
> > > - PEI phase is NOT skipped in either Td or Non-Td
> > >
> > > Patch 01 - 23 are changes in SEC phase. Also some libraries in these
> > > patches are workable in SEC/PEI/DXE.
> > >
> > > Patch 17 - 20 extract the common codes from OvmfPkg/PlatformPei to a
> > > new PlatformInitLib. Then OvmfPkg/PlatformPei is refactored with this lib.
> > > This is because there are 3 variants of PlatformPei in OvmfPkg and
> > > hence many codes are duplicated.
> > > Patch 21 then add Tdx specific codes in PlatformInitLib.
> > >
> > > Patch 24 - 29 are changes in PEI phase.
> > >
> > > Patch 30 - 34 are changes in DXE phase.
> > >
> > > Patch 35 - 37 are for local Apic timer DXE driver.
> > >
> > > [TDX]: https://software.intel.com/content/dam/develop/external/us/en/
> > > documents/tdx-whitepaper-final9-17.pdf
> > >
> > > [TDX-Module]:
> https://software.intel.com/content/dam/develop/external/
> > > us/en/documents/tdx-module-1.0-public-spec-v0.931.pdf
> > >
> > > [TDVF]:
> https://software.intel.com/content/dam/develop/external/us/en/
> > > documents/tdx-virtual-firmware-design-guide-rev-1.pdf
> > >
> > > [GCHI]:
> https://software.intel.com/content/dam/develop/external/us/en/
> > >
> documents/intel-tdx-guest-hypervisor-communication-interface-1.0-34442
> > > 6-
> > > 002.pdf
> > >
> > > Code is at https://github.com/mxu9/edk2/tree/tdvf_wave2.v7
> > >
> > > v7 changes:
> > > - Based on the comments from last review, 8 PlatformInitLib patches
> > > are squashed into 4 patches (#17-#20). These 4 patches are not
> > > related to Tdx guest. Tdx related codes of PlatformInitLib is
> > > in #21.
> > > - gUefiOvmfPkgTdxPlatformGuid is renamed as
> > > gUefiOvmfPkgPlatformInfoGuid.
> > > Because this GUID is used not only by Tdx guest, but also by
> > > Legacy guest.
> > > - PlatformInitLibNull is deleted.
> > > - In PlatformPei Pml4Entries is cap at 512 entries when
> > > mPhysMemAddressWidth > 48.
> > >
> > > v7 not-addressed comments
> > > - Comments in MpInitLib have not been addressed yet. It will be
> > > addressed in the following version.
> > > - Thanks much for your understanding.
> > >
> > > v6 changes:
> > > - PlatformInitLib and OvmfPkg/PlatformPei refactoring are covered in
> > > patch from 17 - 24. These patches are not related to Tdx guest. Tdx
> > > related codes of PlatformInitLib is in patch 25.
> > > - In the previous patch-sets, TdHob is processed in
> > > OvmfPkg/Sec/IntelTdx.c. Per Gerd's suggestion they are now moved
> > > to PlatformInitLib/IntelTdx.c. So that they can be reused in Config-B.
> > > - The default Accept page size is changed from 4K to 2M.
> > > - The BspAcceptMemoryResourceRange is refactored according to
> Gerd's
> > > comment.
> > > - In ApRunLoop.nasm command field is set to zero as acknowledgement.
> > > This is a fix based on the ACPI Spec v6.4,Sec titled "Multiprocessor
> > > Wakeup Structure".
> > >
> > > v6 not-addressed comments
> > > - Comments in MpInitLib have not been addressed yet. It will be
> > > addressed in the following version.
> > > - Thanks much for your understanding.
> > >
> > > v5 changes:
> > > - PlatformInitLib is introduced which wraps the common functions in
> > > OvmfPkg/PlatformPei. It is because there are a lot of duplicated
> > > codes for Platform initialization in PEI phase and there are at least
> > > 3 variants of PlatformPei. Another reason is that in TDVF Config-B
> > > PEI-less boot needs the similar initiliazation as PlatformPei. Based
> > > on the discussion with the community, PlatformInitLib is introduced.
> > > As the first stage OvmfPkg/PlatformPei is refactored with this lib.
> > > In the future the other 2 PlatformPei variants will be refactored
> > > as well.
> > > - PcdIgnoreVeHalt is deprecated.
> > > - Add spec link for Mailbox.
> > > - Other minor changes, such as comments, uncrustify formats, etc.
> > >
> > > v5 not-addressed comments
> > > - Comments in MpInitLib have not been addressed yet. It will be
> > > addressed in the following version.
> > > - Some comments may be missed. I will re-visit the review emails.
> > > - Thanks much for your understanding.
> > >
> > > v4 changes:
> > > - Split the TdxLib into 2 libraries. The TDX basic functions
> > > (TdCall / TdVmCall / TdIsEnabled) are moved to BaseLib (#2).
> > > The other functions are in TdxLib. (#3)
> > > - Based on above changes (TdCall/TdVmCall/TdIsEnabled in BaseLib)
> > > the TdxLib.inf is not necessary in some Pkgs, such as
> > > UefiPayloadPkg. The duplicated source code are deleted (BaseIoLib
> > > is the sample).
> > > - Drop the Accepting pages with TDX MP service. Instead only BSP
> > > accepts pages. There maybe boot performance issue. There are some
> > > mitigations to it, such as 2M accept page size, lazy accept, etc.
> > > We will re-visit this issue in a separate patch-set.
> > > - Relocate Mailbox in TdxDxe driver instead of in PlatformPei. This
> > > is to keep consistence with Config-B (PEI is skipped in Config-B).
> > > - SetMmioSharedBit in TdxDxe driver instead of in DxeIplPeim after
> > > CreateIdentityMappingPageTables. This is to keep consistence with
> > > Config-B (PEI is skipped in Config-B).
> > > - Some other minor changes, such as switch-case indention.
> > > - Rebase the code base (commit: 8c06c53b585a) and update the code
> with
> > > uncrustify.
> > >
> > > v4 not-addressed comments:
> > > - Comments in MpInitLib have not been addressed yet. It will be
> > > addressed in the next version.
> > > - BaseMemEncryptTdxLib is suggested to be merged with
> > > BaseMemEncryptSevLib. It will be addressed in the next version.
> > > - Gerd suggests a generic page table walker which is able to set
> > > and clear bits for a given memory range in both SEV and TDX guest.
> > > This suggestion will be addressed in the next version.
> > > - Some comments may be missed. I will re-visit the review emails.
> > > - Thanks much for your understanding.
> > >
> > > v3 changes:
> > > - LocalApicTimerDxe is split out to be a separate patch-series.
> > > - VmTdExitLibNull/VmgExitLib are removed. Instead the VmgExitLib
> > > is extended to handle #VE exception. (Patch 3-5)
> > > - Split the Tdx support of base IoLib into 4 commits. (Patch 6-9)
> > > - Alter of MADT table is updated. In previous version it was
> > > created from scratch. Now it gets the installed table, copy
> > > it to a larger buffer and append the ACPI_MADT_MPWK to it.
> > > (Patch 25)
> > > - Changes in BaseXApicX2ApicLib is refined based on the
> > > feedbacks. (Add spec link of MSR access definition, rename
> > > some funtion name, etc.) (Patch 11)
> > > - Use PcdConfidentialComputingGuestAttr to probe TDX guest instead
> > > of CPUID. But in some cases PcdConfidentialComputingGuestAttr
> > > cannot be used because it has not been set yet.
> > > - Some other minor changes.
> > >
> > > v3 not-addressed comments:
> > > - Some of the comments have not been addressed. This is because I
> > > need more time to consider how to address these comments.
> > > At the same time I want to submit a new version based on the above
> > > changes so that community can review in a more efficient way.
> > > (v2 is the version one month ago).
> > > - Comments in MpInitLib have not been addressed yet. It will be
> > > addressed in v4.
> > > - BaseMemEncryptTdxLib should be merged with
> BaseMemEncryptSevLib.
> > > It will be addressed in v4.
> > > - Some comments may be missed. I will re-visit the review emails.
> > > - Thanks much for your understanding.
> > >
> > > v2 changes:
> > > - Remove TdxProbeLib. It is to reduce the depencies of the lib.
> > > - In v1 a new function (AllocatePagesWithMemoryType) is added in
> > > PeiMemoryAllocationLib. This function is not necessary. It can
> > > be replaced by PeiServicesAllocatePages.
> > > - IoLibFifo.c is added in BaseIoLibIntrinsic. This file includes
> > > the functions of read/write of I/O port fifo. These functions
> > > will call TdIoReadFifo or SevIoReadFifo by checking TDX or SEV
> > > in run-time.
> > > - DXE related patches are added. (Patch 22-28)
> > > - Fix typo in commit/comment message, or some minor changes.
> > > - Rebase the edk2 code base. (4cc1458dbe00)
> > >
> > > Cc: Brijesh Singh <brijesh.singh@amd.com>
> > > Cc: Eric Dong <eric.dong@intel.com>
> > > Cc: Erdem Aktas <erdemaktas@google.com>
> > > Cc: Hao A Wu <hao.a.wu@intel.com>
> > > Cc: Jian J Wang <jian.j.wang@intel.com>
> > > Cc: James Bottomley <jejb@linux.ibm.com>
> > > Cc: Jiewen Yao <jiewen.yao@intel.com>
> > > Cc: Liming Gao <gaoliming@byosoft.com.cn>
> > > Cc: Michael D Kinney <michael.d.kinney@intel.com>
> > > Cc: Ray Ni <ray.ni@intel.com>
> > > Cc: Rahul Kumar <rahul1.kumar@intel.com>
> > > Cc: Tom Lendacky <thomas.lendacky@amd.com>
> > > Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> > > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > > Signed-off-by: Min Xu <min.m.xu@intel.com>
> > >
> > > Min Xu (37):
> > > MdePkg: Add Tdx.h
> > > MdePkg: Introduce basic Tdx functions in BaseLib
> > > MdePkg: Add TdxLib to wrap Tdx operations
> > > UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception
> > > OvmfPkg: Extend VmgExitLib to handle #VE exception
> > > UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE
> exception
> > > MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic
> > > MdePkg: Support mmio for Tdx guest in BaseIoLibIntrinsic
> > > MdePkg: Support IoFifo for Tdx guest in BaseIoLibIntrinsic
> > > MdePkg: Support IoRead/IoWrite for Tdx guest in BaseIoLibIntrinsic
> > > UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
> > > MdePkg: Add macro to check SEV / TDX guest
> > > UefiCpuPkg: Enable Tdx support in MpInitLib
> > > OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
> > > OvmfPkg: Add TdxMailboxLib
> > > MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h
> > > OvmfPkg: Create initial version of PlatformInitLib
> > > OvmfPkg/PlatformInitLib: Add hob functions
> > > OvmfPkg/PlatformInitLib: Add memory functions
> > > OvmfPkg/PlatformInitLib: Add platform functions
> > > OvmfPkg: Update PlatformInitLib to process Tdx hoblist
> > > OvmfPkg/Sec: Declare local variable as volatile in
> > > SecCoreStartupWithStack
> > > OvmfPkg: Update Sec to support Tdx
> > > OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
> > > MdeModulePkg: EFER should not be changed in TDX
> > > MdeModulePkg: Add PcdTdxSharedBitMask
> > > UefiCpuPkg: Update AddressEncMask in CpuPageTable
> > > OvmfPkg: Update PlatformInitLib for Tdx guest to publish ram regions
> > > OvmfPkg: Update PlatformPei to support Tdx guest
> > > OvmfPkg: Update AcpiPlatformDxe to alter MADT table
> > > OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
> > > OvmfPkg: Add TdxDxe driver
> > > OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe
> > > OvmfPkg: Update IoMmuDxe to support TDX
> > > OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe
> > > UefiCpuPkg: Setting initial-count register as the last step
> > > OvmfPkg: Switch timer in build time for OvmfPkg
> > >
> > > MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 1 +
> > > .../Core/DxeIplPeim/X64/VirtualMemory.c | 7 +
> > > MdeModulePkg/MdeModulePkg.dec | 9 +
> > > .../Include/ConfidentialComputingGuestAttr.h | 3 +
> > > MdePkg/Include/IndustryStandard/Tdx.h | 203 ++++
> > > MdePkg/Include/Library/BaseLib.h | 62 ++
> > > MdePkg/Include/Library/TdxLib.h | 97 ++
> > > MdePkg/Include/Pi/PiHob.h | 8 +
> > > .../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf | 2 +
> > > .../BaseIoLibIntrinsicSev.inf | 7 +
> > > MdePkg/Library/BaseIoLibIntrinsic/IoLib.c | 81 +-
> > > MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c | 216 ++++
> > > MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c | 51 +-
> > > .../BaseIoLibIntrinsic/IoLibInternalTdx.c | 675 +++++++++++++
> > > .../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 497 +++++++++
> > > MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c | 73 +-
> > > MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h | 166 +++
> > > MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h | 410 ++++++++
> > > .../BaseIoLibIntrinsic/X64/IoFifoSev.nasm | 34 +-
> > > MdePkg/Library/BaseLib/BaseLib.inf | 11 +
> > > MdePkg/Library/BaseLib/IntelTdxNull.c | 83 ++
> > > MdePkg/Library/BaseLib/X64/TdCall.nasm | 85 ++
> > > MdePkg/Library/BaseLib/X64/TdProbe.c | 62 ++
> > > MdePkg/Library/BaseLib/X64/TdVmcall.nasm | 145 +++
> > > MdePkg/Library/TdxLib/AcceptPages.c | 180 ++++
> > > MdePkg/Library/TdxLib/Rtmr.c | 83 ++
> > > MdePkg/Library/TdxLib/TdInfo.c | 114 +++
> > > MdePkg/Library/TdxLib/TdxLib.inf | 37 +
> > > MdePkg/Library/TdxLib/TdxLibNull.c | 107 ++
> > > MdePkg/MdePkg.dec | 3 +
> > > MdePkg/MdePkg.dsc | 1 +
> > > OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf | 1 +
> > > OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c | 14 +-
> > > OvmfPkg/AmdSev/AmdSevX64.dsc | 8 +-
> > > OvmfPkg/AmdSev/AmdSevX64.fdf | 3 +-
> > > OvmfPkg/Bhyve/BhyveX64.dsc | 2 +
> > > OvmfPkg/CloudHv/CloudHvX64.dsc | 5 +-
> > > OvmfPkg/CloudHv/CloudHvX64.fdf | 2 +-
> > > OvmfPkg/Include/IndustryStandard/IntelTdx.h | 67 ++
> > > OvmfPkg/Include/Library/MemEncryptTdxLib.h | 81 ++
> > > OvmfPkg/Include/Library/PlatformInitLib.h | 286 ++++++
> > > OvmfPkg/Include/Library/TdxMailboxLib.h | 76 ++
> > > .../Include/Protocol/QemuAcpiTableNotify.h | 27 +
> > > OvmfPkg/Include/TdxCommondefs.inc | 51 +
> > > OvmfPkg/IoMmuDxe/AmdSevIoMmu.c | 103 +-
> > > OvmfPkg/IoMmuDxe/AmdSevIoMmu.h | 6 +-
> > > OvmfPkg/IoMmuDxe/IoMmuDxe.c | 6 +-
> > > OvmfPkg/IoMmuDxe/IoMmuDxe.inf | 5 +
> > > .../BaseMemEncryptTdxLib.inf | 44 +
> > > .../BaseMemEncryptTdxLibNull.inf | 35 +
> > > .../BaseMemoryEncryptionNull.c | 90 ++
> > > .../BaseMemEncryptTdxLib/MemoryEncryption.c | 948
> > > ++++++++++++++++++
> > > .../BaseMemEncryptTdxLib/VirtualMemory.h | 181 ++++
> > > .../PlatformInitLib}/Cmos.c | 32 +-
> > > OvmfPkg/Library/PlatformInitLib/IntelTdx.c | 553 ++++++++++
> > > .../Library/PlatformInitLib/IntelTdxNull.c | 46 +
> > > OvmfPkg/Library/PlatformInitLib/MemDetect.c | 707
> +++++++++++++
> > > OvmfPkg/Library/PlatformInitLib/Platform.c | 597 +++++++++++
> > > .../PlatformInitLib/PlatformInitLib.inf | 94 ++
> > > OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c | 9 +-
> > > .../Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf | 1 +
> > > .../QemuFwCfgLib/QemuFwCfgLibInternal.h | 11 +
> > > OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c | 32 +
> > > .../Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf | 2 +
> > > OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c | 140 +++
> > > .../Library/TdxMailboxLib/TdxMailboxLib.inf | 52 +
> > > .../Library/TdxMailboxLib/TdxMailboxNull.c | 85 ++
> > > OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf | 3 +-
> > > OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h | 32 +
> > > .../Library/VmgExitLib/VmTdExitVeHandler.c | 559 +++++++++++
> > > OvmfPkg/Library/VmgExitLib/VmgExitLib.inf | 2 +
> > > .../Library/VmgExitLib/X64/TdVmcallCpuid.nasm | 146 +++
> > > .../LocalApicTimerDxe.c} | 4 +-
> > > .../LocalApicTimerDxe.h} | 4 +-
> > > .../LocalApicTimerDxe.inf} | 7 +-
> > > OvmfPkg/Microvm/MicrovmX64.dsc | 5 +-
> > > OvmfPkg/Microvm/MicrovmX64.fdf | 2 +-
> > > OvmfPkg/OvmfPkg.dec | 17 +
> > > OvmfPkg/OvmfPkgIa32.dsc | 12 +-
> > > OvmfPkg/OvmfPkgIa32.fdf | 8 +-
> > > OvmfPkg/OvmfPkgIa32X64.dsc | 14 +-
> > > OvmfPkg/OvmfPkgIa32X64.fdf | 8 +-
> > > OvmfPkg/OvmfPkgX64.dsc | 29 +-
> > > OvmfPkg/OvmfPkgX64.fdf | 11 +-
> > > OvmfPkg/OvmfXen.dsc | 4 +-
> > > OvmfPkg/OvmfXen.fdf | 2 +-
> > > OvmfPkg/PlatformPei/Cmos.h | 48 -
> > > OvmfPkg/PlatformPei/FeatureControl.c | 7 +-
> > > OvmfPkg/PlatformPei/IntelTdx.c | 54 +
> > > OvmfPkg/PlatformPei/MemDetect.c | 669 +-----------
> > > OvmfPkg/PlatformPei/Platform.c | 522 ++--------
> > > OvmfPkg/PlatformPei/Platform.h | 55 +-
> > > OvmfPkg/PlatformPei/PlatformPei.inf | 7 +-
> > > OvmfPkg/Sec/SecMain.c | 44 +-
> > > OvmfPkg/Sec/SecMain.inf | 3 +
> > > OvmfPkg/Sec/X64/SecEntry.nasm | 82 ++
> > > OvmfPkg/TdxDxe/TdxAcpiTable.c | 213 ++++
> > > OvmfPkg/TdxDxe/TdxAcpiTable.h | 60 ++
> > > OvmfPkg/TdxDxe/TdxDxe.c | 261 +++++
> > > OvmfPkg/TdxDxe/TdxDxe.inf | 64 ++
> > > OvmfPkg/TdxDxe/X64/ApRunLoop.nasm | 90 ++
> > > UefiCpuPkg/CpuDxe/CpuDxe.inf | 1 +
> > > UefiCpuPkg/CpuDxe/CpuPageTable.c | 4 +
> > > UefiCpuPkg/Include/Library/VmgExitLib.h | 28 +
> > > .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c | 170 +++-
> > > .../PeiDxeSmmCpuException.c | 17 +
> > > .../SecPeiCpuException.c | 18 +
> > > UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 3 +
> > > UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 15 +-
> > > UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h | 71 ++
> > > UefiCpuPkg/Library/MpInitLib/MpLib.c | 27 +
> > > UefiCpuPkg/Library/MpInitLib/MpLibTdx.c | 128 +++
> > > UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c | 73 ++
> > > UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 3 +
> > > .../Library/VmgExitLibNull/VmTdExitNull.c | 38 +
> > > .../Library/VmgExitLibNull/VmgExitLibNull.inf | 1 +
> > > 116 files changed, 10233 insertions(+), 1327 deletions(-) create
> > > mode 100644 MdePkg/Include/IndustryStandard/Tdx.h
> > > create mode 100644 MdePkg/Include/Library/TdxLib.h create mode
> > > 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
> > > create mode 100644
> > > MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
> > > create mode 100644
> > > MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
> > > create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h
> > > create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
> > > create mode 100644 MdePkg/Library/BaseLib/IntelTdxNull.c
> > > create mode 100644 MdePkg/Library/BaseLib/X64/TdCall.nasm
> > > create mode 100644 MdePkg/Library/BaseLib/X64/TdProbe.c
> > > create mode 100644 MdePkg/Library/BaseLib/X64/TdVmcall.nasm
> > > create mode 100644 MdePkg/Library/TdxLib/AcceptPages.c
> > > create mode 100644 MdePkg/Library/TdxLib/Rtmr.c create mode
> 100644
> > > MdePkg/Library/TdxLib/TdInfo.c create mode 100644
> > > MdePkg/Library/TdxLib/TdxLib.inf create mode 100644
> > > MdePkg/Library/TdxLib/TdxLibNull.c
> > > create mode 100644 OvmfPkg/Include/IndustryStandard/IntelTdx.h
> > > create mode 100644 OvmfPkg/Include/Library/MemEncryptTdxLib.h
> > > create mode 100644 OvmfPkg/Include/Library/PlatformInitLib.h
> > > create mode 100644 OvmfPkg/Include/Library/TdxMailboxLib.h
> > > create mode 100644
> OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h
> > > create mode 100644 OvmfPkg/Include/TdxCommondefs.inc create
> mode
> > > 100644
> > OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
> > > create mode 100644
> > > OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
> > > create mode 100644
> > > OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
> > > create mode 100644
> > > OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
> > > create mode 100644
> > > OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h
> > > rename OvmfPkg/{PlatformPei => Library/PlatformInitLib}/Cmos.c (61%)
> > > create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdx.c
> > > create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
> > > create mode 100644 OvmfPkg/Library/PlatformInitLib/MemDetect.c
> > > create mode 100644 OvmfPkg/Library/PlatformInitLib/Platform.c
> > > create mode 100644
> > > OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
> > > create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
> > > create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
> > > create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c
> > > create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
> > > create mode 100644
> OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
> > > create mode 100644
> OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm
> > > rename OvmfPkg/{XenTimerDxe/XenTimerDxe.c =>
> > > LocalApicTimerDxe/LocalApicTimerDxe.c} (95%) rename
> > > OvmfPkg/{XenTimerDxe/XenTimerDxe.h =>
> > > LocalApicTimerDxe/LocalApicTimerDxe.h} (96%) rename
> > > OvmfPkg/{XenTimerDxe/XenTimerDxe.inf =>
> > > LocalApicTimerDxe/LocalApicTimerDxe.inf} (80%) delete mode 100644
> > > OvmfPkg/PlatformPei/Cmos.h create mode 100644
> > > OvmfPkg/PlatformPei/IntelTdx.c create mode 100644
> > > OvmfPkg/TdxDxe/TdxAcpiTable.c create mode 100644
> > > OvmfPkg/TdxDxe/TdxAcpiTable.h create mode 100644
> > > OvmfPkg/TdxDxe/TdxDxe.c create mode 100644
> > OvmfPkg/TdxDxe/TdxDxe.inf
> > > create mode 100644 OvmfPkg/TdxDxe/X64/ApRunLoop.nasm create
> mode
> > > 100644 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
> > > create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
> > > create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
> > > create mode 100644
> UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c
> > >
> > > --
> > > 2.29.2.windows.2
> > >
> > >
> > >
> > >
> > >
> >
> >
> >
> >
> >
> >
> >
>
>
>
>
>
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [edk2-devel] [PATCH V7 00/37] Enable Intel TDX in OvmfPkg (Config-A)
2022-03-11 3:19 ` 回复: " gaoliming
@ 2022-03-11 7:17 ` Min Xu
0 siblings, 0 replies; 72+ messages in thread
From: Min Xu @ 2022-03-11 7:17 UTC (permalink / raw)
To: devel@edk2.groups.io, Gao, Liming
Cc: 'Brijesh Singh', Dong, Eric, Aktas, Erdem, Wu, Hao A,
Wang, Jian J, 'James Bottomley', Yao, Jiewen,
Kinney, Michael D, Ni, Ray, Kumar, Rahul1, 'Tom Lendacky',
Liu, Zhiguang, 'Gerd Hoffmann'
On March 11, 2022 11:20 AM, Gao Liming wrote:
> Min:
> I have one minor comment for TdxLib.h. This header file doesn't need to include
> below header files. Other patches in MdePkg are good to me. Reviewed-by:
> Liming Gao <gaoliming@byosoft.com.cn>
>
> #include <Library/BaseLib.h>
> #include <Library/DebugLib.h>
> #include <Uefi/UefiBaseType.h>
> #include <Protocol/DebugSupport.h>
>
Thanks for the reminder. They will be deleted in the next version.
Thanks
Min
^ permalink raw reply [flat|nested] 72+ messages in thread