Date   

[PATCH 16/23] OvmfPkg: Add TdxMailboxLib

Min Xu
 

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Include/Library/TdxMailboxLib.h | 75 ++++++++++
OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c | 138 ++++++++++++++++++
.../Library/TdxMailboxLib/TdxMailboxLib.inf | 52 +++++++
.../Library/TdxMailboxLib/TdxMailboxNull.c | 86 +++++++++++
OvmfPkg/OvmfPkg.dec | 4 +
5 files changed, 355 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..a410a9618495
--- /dev/null
+++ b/OvmfPkg/Include/Library/TdxMailboxLib.h
@@ -0,0 +1,75 @@
+/** @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..688ac6ca8262
--- /dev/null
+++ b/OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
@@ -0,0 +1,138 @@
+/** @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..f15222d51f45
--- /dev/null
+++ b/OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c
@@ -0,0 +1,86 @@
+/** @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 8d1f3b03488c..d478a4b8e418 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


[PATCH 15/23] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard

Min Xu
 

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

IntelTdx.h defines the defitions used by TDX in OvmfPkg:
- Mailbox related defitions,such as the data structure, command code,
AP relocation defitions.
- EFI_HOB_PLATFORM_INFO describes the TDX platform information

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Include/IndustryStandard/IntelTdx.h | 77 +++++++++++++++++++++
1 file changed, 77 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..2370f18289a1
--- /dev/null
+++ b/OvmfPkg/Include/IndustryStandard/IntelTdx.h
@@ -0,0 +1,77 @@
+/** @file
+ TBD
+
+ 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;
+
+typedef struct {
+ ///
+ EFI_HOB_GUID_TYPE GuidHeader;
+ UINT64 RelocatedMailBox;
+ UINT16 HostBridgePciDevId;
+ BOOLEAN SetNxForStack;
+ UINT8 SystemStates[6];
+} EFI_HOB_PLATFORM_INFO;
+
+#pragma pack()
+
+#endif
--
2.29.2.windows.2


[PATCH 14/23] OvmfPkg: Update SecEntry.nasm to support Tdx

Min Xu
 

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

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.

There are 2 commands are supported:
- WakeUp:
BSP issues this command to move APs to final OS spinloop and Mailbox
in reserved memory.
- AcceptPages:
To mitigate the performance impact of accepting pages in SEC phase on
BSP, BSP will parse memory resources and assign each AP the task of
accepting a subset of pages. This command may be called several times
until all memory resources are processed. In accepting pages, PageLevel
may fall back to smaller one if SIZE_MISMATCH error is returned.

TdxCommondefs.inc is added which includes the common definitions used by
the APs in SecEntry.nasm.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Include/TdxCommondefs.inc | 51 +++++
OvmfPkg/Sec/SecMain.inf | 1 +
OvmfPkg/Sec/X64/SecEntry.nasm | 313 ++++++++++++++++++++++++++++++
3 files changed, 365 insertions(+)
create mode 100644 OvmfPkg/Include/TdxCommondefs.inc

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/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
index 7f78dcee2772..75cd5ee7264b 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -70,6 +70,7 @@
gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd
gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase

[FeaturePcd]
gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
diff --git a/OvmfPkg/Sec/X64/SecEntry.nasm b/OvmfPkg/Sec/X64/SecEntry.nasm
index 1cc680a70716..8c4d9047e070 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,31 @@ extern ASM_PFX(SecCoreStartupWithStack)
global ASM_PFX(_ModuleEntryPoint)
ASM_PFX(_ModuleEntryPoint):

+ ;
+ ; Td guest flag is stored in TDX_WORK_AREA which is in Mailbox[0x10,0x20]
+ ;
+ %define CC_WORK_AREA FixedPcdGet32 (PcdSevEsWorkAreaBase)
+ mov eax, CC_WORK_AREA
+ cmp byte[eax], 2
+ 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 +97,286 @@ 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
+
+ cmp eax, MpProtectedModeWakeupCommandAcceptPages
+ jne .check_command
+
+ ;
+ ; AP Accept Pages
+ ;
+ ; Accept Pages in TDX is time-consuming, especially for big memory.
+ ; One of the mitigation is to accept pages by BSP and APs parallely.
+ ;
+ ; For example, there are 4 CPUs (1 BSP and 3 APs). Totally there are
+ ; 1G memory to be accepted.
+ ;
+ ; BSP is responsible for the memory regions of:
+ ; Start : StartAddress + ChunkSize * (4) * Index
+ ; Length: ChunkSize
+ ; APs is reponsible for the memory regions of:
+ ; Start : StartAddress + ChunkSize * (4) * Index + ChunkSize * CpuId
+ ; Length: ChunkSize
+ ;
+ ; TDCALL_TDACCEPTPAGE supports the PageSize of 4K and 2M. Sometimes when
+ ; the PageSize is 2M, TDX_PAGE_SIZE_MISMATCH is returned as the error code.
+ ; In this case, TDVF need fall back to 4k PageSize to accept again.
+ ;
+ ; If any errors happened in accept pages, an error code is recorded in
+ ; Mailbox [ErrorsOffset + CpuIndex]
+ ;
+.ap_accept_page:
+
+ ;
+ ; Clear the errors and fallback flag
+ ;
+ mov al, ERROR_NON
+ mov byte[rsp + ErrorsOffset + rbp], al
+ xor r12, r12
+
+ ;
+ ; Get PhysicalAddress/ChunkSize/PageSize
+ ;
+ mov rcx, [rsp + AcceptPageArgsPhysicalStart]
+ mov rbx, [rsp + AcceptPageArgsChunkSize]
+
+ ;
+ ; Set AcceptPageLevel based on the AcceptPagesize
+ ; Currently only 2M/4K page size is acceptable
+ ;
+ mov r15, [rsp + AcceptPageArgsPageSize]
+ cmp r15, SIZE_4KB
+ je .set_4kb
+ cmp r15, SIZE_2MB
+ je .set_2mb
+
+ mov al, ERROR_INVALID_ACCEPT_PAGE_SIZE
+ mov byte[rsp + ErrorsOffset + rbp], al
+ jmp .do_finish_command
+
+.set_4kb:
+ mov r15, PAGE_ACCEPT_LEVEL_4K
+ jmp .physical_address
+
+.set_2mb:
+ mov r15, PAGE_ACCEPT_LEVEL_2M
+
+.physical_address:
+ ;
+ ; PhysicalAddress += (CpuId * ChunkSize)
+ ;
+ xor rdx, rdx
+ mov eax, ebp
+ mul ebx
+ add rcx, rax
+ shl rdx, 32
+ add rcx, rdx
+
+.do_accept_next_range:
+ ;
+ ; Make sure we don't accept page beyond ending page
+ ; This could happen is ChunkSize crosses the end of region
+ ;
+ cmp rcx, [rsp + AcceptPageArgsPhysicalEnd ]
+ jge .do_finish_command
+
+ ;
+ ; Save starting address for this region
+ ;
+ mov r11, rcx
+
+ ;
+ ; Size = MIN(ChunkSize, PhysicalEnd - PhysicalAddress);
+ ;
+ mov rax, [rsp + AcceptPageArgsPhysicalEnd]
+ sub rax, rcx
+ cmp rax, rbx
+ jge .do_accept_loop
+ mov rbx, rax
+
+.do_accept_loop:
+ ;
+ ; RCX: Accept address
+ ; R15: Accept Page Level
+ ; R12: Flag of fall back accept
+ ;
+ mov rax, TDCALL_TDACCEPTPAGE
+ xor rdx, rdx
+ or rcx, r15
+
+ tdcall
+
+ ;
+ ; Check status code in RAX
+ ;
+ test rax, rax
+ jz .accept_success
+
+ shr rax, 32
+ cmp eax, TDX_PAGE_ALREADY_ACCEPTED
+ jz .already_accepted
+
+ cmp eax, TDX_PAGE_SIZE_MISMATCH
+ jz .accept_size_mismatch
+
+ ;
+ ; other error
+ ;
+ mov al, ERROR_ACCEPT_PAGE_ERROR
+ mov byte[rsp + ErrorsOffset + rbp], al
+ jmp .do_finish_command
+
+.accept_size_mismatch:
+ ;
+ ; Check the current PageLevel.
+ ; ACCEPT_LEVEL_4K is the least level and cannot fall back any more.
+ ; If in this case, just record the error and return
+ ;
+ cmp r15, PAGE_ACCEPT_LEVEL_4K
+ jne .do_fallback_accept
+ mov al, ERROR_INVALID_FALLBACK_PAGE_LEVEL
+ mov byte[rsp + ErrorsOffset + rbp], al
+ jmp .do_finish_command
+
+.do_fallback_accept:
+ ;
+ ; In fall back accept, just loop 512 times (2M = 512 * 4K)
+ ; Save the rcx in r13.
+ ; Decrease the PageLevel in R15.
+ ; R12 indicates it is in a fall back accept loop.
+ ;
+ mov r14, 512
+ and rcx, ~0x3ULL
+ mov r13, rcx
+ xor rdx, rdx
+ dec r15
+ mov r12, 1
+
+ jmp .do_accept_loop
+
+.accept_success:
+ ;
+ ; Keep track of how many accepts per cpu
+ ;
+ inc dword[rsp + TalliesOffset + rbp * 4]
+
+ ;
+ ; R12 indicate whether it is a fall back accept
+ ; If it is a success of fall back accept
+ ; Just loop 512 times to .do_accept_loop
+ ;
+ test r12, r12
+ jz .normal_accept_success
+
+ ;
+ ; This is fallback accept success
+ ;
+ add rcx, SIZE_4KB
+ dec r14
+ test r14, r14
+ jz .fallback_accept_done
+ jmp .do_accept_loop
+
+.fallback_accept_done:
+ ;
+ ; Fall back accept done.
+ ; Restore the start address to RCX from R13
+ ; Clear the fall back accept flag
+ ;
+ mov rcx, r13
+ inc r15
+ xor r12, r12
+
+.already_accepted:
+ ;
+ ; Handle the sitution of fall back accpet
+ ;
+ test r12, r12
+ jnz .accept_success
+
+.normal_accept_success:
+ ;
+ ; Reduce accept size by a PageSize, and increment address
+ ;
+ mov r12, [rsp + AcceptPageArgsPageSize]
+ sub rbx, r12
+ add rcx, r12
+ xor r12, r12
+
+ ;
+ ; We may be given multiple pages to accept, make sure we
+ ; aren't done
+ ;
+ test rbx, rbx
+ jne .do_accept_loop
+
+ ;
+ ; Restore address before, and then increment by stride (num-cpus * ChunkSize)
+ ;
+ xor rdx, rdx
+ mov rcx, r11
+ mov eax, r8d
+ mov ebx, [rsp + AcceptPageArgsChunkSize]
+ mul ebx
+ add rcx, rax
+ shl rdx, 32
+ add rcx, rdx
+ jmp .do_accept_next_range
+
+.do_finish_command:
+ mov eax, 0FFFFFFFFh
+ lock xadd dword [rsp + CpusExitingOffset], eax
+ dec eax
+
+.check_exiting_cnt:
+ cmp eax, 0
+ je .do_wait_loop
+ mov eax, dword[rsp + CpusExitingOffset]
+ jmp .check_exiting_cnt
+
+.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


[PATCH 13/23] UefiCpuPkg: Enable Tdx support in MpInitLib

Min Xu
 

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 5 +
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 14 +-
UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h | 107 +++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.c | 26 ++++
UefiCpuPkg/Library/MpInitLib/MpLibTdx.c | 142 ++++++++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c | 117 +++++++++++++++
UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 5 +
.../Library/MpInitLib/X64/IntelTdcall.nasm | 120 +++++++++++++++
8 files changed, 535 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
create mode 100644 UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index d34419c2a524..2e1cc34d2657 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -22,10 +22,13 @@
#

[Sources.IA32]
+ MpLibTdxNull.c
Ia32/MpFuncs.nasm

[Sources.X64]
+ MpLibTdx.c
X64/MpFuncs.nasm
+ X64/IntelTdcall.nasm

[Sources.common]
MpEqu.inc
@@ -33,6 +36,7 @@
MpLib.c
MpLib.h
Microcode.c
+ MpIntelTdx.h

[Packages]
MdePkg/MdePkg.dec
@@ -76,3 +80,4 @@
gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdTdxIsEnabled ## CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 93fc63bf93e3..b7275db3d564 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,7 +16,6 @@
#include <Library/VmgExitLib.h>
#include <Register/Amd/Fam17Msr.h>
#include <Register/Amd/Ghcb.h>
-
#include <Protocol/Timer.h>

#define AP_SAFE_STACK_SIZE 128
@@ -801,6 +801,10 @@ MpInitLibStartupThisAP (
{
EFI_STATUS Status;

+ if (MpTdxIsEnabled ()) {
+ return EFI_UNSUPPORTED;
+ }
+
//
// temporarily stop checkAllApsStatus for avoid resource dead-lock.
//
@@ -857,6 +861,10 @@ MpInitLibSwitchBSP (
EFI_TIMER_ARCH_PROTOCOL *Timer;
UINT64 TimerPeriod;

+ if (MpTdxIsEnabled ()) {
+ return EFI_UNSUPPORTED;
+ }
+
TimerPeriod = 0;
//
// Locate Timer Arch Protocol
@@ -930,6 +938,10 @@ MpInitLibEnableDisableAP (
EFI_STATUS Status;
BOOLEAN TempStopCheckState;

+ if (MpTdxIsEnabled ()) {
+ 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..cbb45d2eaf0a
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
@@ -0,0 +1,107 @@
+/** @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
+ );
+
+/**
+ 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
+**/
+EFI_STATUS
+EFIAPI
+MyTdCall (
+ IN UINT64 Leaf,
+ IN UINT64 Arg1,
+ IN UINT64 Arg2,
+ IN UINT64 Arg3,
+ IN OUT VOID *Results
+ );
+
+/**
+ Whether Intel TDX is enabled.
+
+ @return TRUE TDX enabled
+ @return FALSE TDX not enabled
+**/
+BOOLEAN
+EFIAPI
+MpTdxIsEnabled (
+ VOID
+ );
+
+#endif
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index b9a06747edbf..d03ad8ff483e 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -9,6 +9,7 @@
**/

#include "MpLib.h"
+#include "MpIntelTdx.h"
#include <Library/VmgExitLib.h>
#include <Register/Amd/Fam17Msr.h>
#include <Register/Amd/Ghcb.h>
@@ -1965,6 +1966,10 @@ MpInitLibInitialize (
UINTN BackupBufferAddr;
UINTN ApIdtBase;

+ if (MpTdxIsEnabled ()) {
+ return EFI_SUCCESS;
+ }
+
OldCpuMpData = GetCpuMpDataFromGuidedHob ();
if (OldCpuMpData == NULL) {
MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
@@ -2215,6 +2220,10 @@ MpInitLibGetProcessorInfo (
CPU_INFO_IN_HOB *CpuInfoInHob;
UINTN OriginalProcessorNumber;

+ if (MpTdxIsEnabled ()) {
+ return TdxMpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, HealthData);
+ }
+
CpuMpData = GetCpuMpData ();
CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;

@@ -2446,6 +2455,10 @@ EnableDisableApWorker (
CPU_MP_DATA *CpuMpData;
UINTN CallerNumber;

+ if (MpTdxIsEnabled ()) {
+ return EFI_UNSUPPORTED;
+ }
+
CpuMpData = GetCpuMpData ();

//
@@ -2506,6 +2519,11 @@ MpInitLibWhoAmI (
return EFI_INVALID_PARAMETER;
}

+ if (MpTdxIsEnabled ()) {
+ *ProcessorNumber = 0;
+ return EFI_SUCCESS;
+ }
+
CpuMpData = GetCpuMpData ();

return GetProcessorNumber (CpuMpData, ProcessorNumber);
@@ -2544,6 +2562,10 @@ MpInitLibGetNumberOfProcessors (
UINTN EnabledProcessorNumber;
UINTN Index;

+ if (MpTdxIsEnabled ()) {
+ return TdxMpInitLibGetNumberOfProcessors(NumberOfProcessors, NumberOfEnabledProcessors);
+ }
+
CpuMpData = GetCpuMpData ();

if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
@@ -2629,6 +2651,10 @@ StartupAllCPUsWorker (
BOOLEAN HasEnabledAp;
CPU_STATE ApState;

+ if (MpTdxIsEnabled ()) {
+ 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..2c4445ff02b6
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
@@ -0,0 +1,142 @@
+/** @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/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 = MyTdCall(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 = MyTdCall(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;
+}
+
+/**
+ Whether Intel TDX is enabled.
+
+ @return TRUE TDX enabled
+ @return FALSE TDX not enabled
+**/
+BOOLEAN
+EFIAPI
+MpTdxIsEnabled (
+ VOID
+ )
+{
+ return PcdGetBool (PcdTdxIsEnabled);
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
new file mode 100644
index 000000000000..b00c8deefb5f
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
@@ -0,0 +1,117 @@
+/** @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;
+}
+
+/**
+ Whether Intel TDX is enabled.
+
+ @return TRUE TDX enabled
+ @return FALSE TDX not enabled
+**/
+BOOLEAN
+EFIAPI
+MpTdxIsEnabled (
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ 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
+**/
+EFI_STATUS
+EFIAPI
+MyTdCall (
+ IN UINT64 Leaf,
+ IN UINT64 Arg1,
+ IN UINT64 Arg2,
+ IN UINT64 Arg3,
+ IN OUT VOID *Results
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 36fcb96b5852..fe246b74aaef 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -22,10 +22,13 @@
#

[Sources.IA32]
+ MpLibTdxNull.c
Ia32/MpFuncs.nasm

[Sources.X64]
+ MpLibTdx.c
X64/MpFuncs.nasm
+ X64/IntelTdcall.nasm

[Sources.common]
MpEqu.inc
@@ -33,6 +36,7 @@
MpLib.c
MpLib.h
Microcode.c
+ MpIntelTdx.h

[Packages]
MdePkg/MdePkg.dec
@@ -65,6 +69,7 @@
gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdTdxIsEnabled ## CONSUMES

[Ppis]
gEdkiiPeiShadowMicrocodePpiGuid ## SOMETIMES_CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm b/UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm
new file mode 100644
index 000000000000..9f83b9e73acb
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm
@@ -0,0 +1,120 @@
+;------------------------------------------------------------------------------
+;*
+;* 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)
+
+%macro tdcall_regs_preamble 2
+ mov rax, %1
+
+ 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
+
+; TdCall (
+; UINT64 Leaf, // Rcx
+; UINT64 P1, // Rdx
+; UINT64 P2, // R8
+; UINT64 P3, // R9
+; UINT64 Results, // rsp + 0x28
+; )
+global ASM_PFX(MyTdCall)
+ASM_PFX(MyTdCall):
+ 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
--
2.29.2.windows.2


[PATCH 12/23] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception #ve

Min Xu
 

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 VmTdExitLib
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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
.../DxeCpuExceptionHandlerLib.inf | 1 +
.../PeiCpuExceptionHandlerLib.inf | 1 +
.../PeiDxeSmmCpuException.c | 18 ++++++++++++++++++
.../SecPeiCpuException.c | 19 +++++++++++++++++++
.../SecPeiCpuExceptionHandlerLib.inf | 1 +
.../SmmCpuExceptionHandlerLib.inf | 1 +
.../Xcode5SecPeiCpuExceptionHandlerLib.inf | 1 +
7 files changed, 42 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
index e7a81bebdb13..630a83bf003b 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -61,3 +61,4 @@
MemoryAllocationLib
DebugLib
VmgExitLib
+ VmTdExitLib
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
index cf5bfe40832b..63a7abfb6242 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
@@ -53,6 +53,7 @@
MemoryAllocationLib
SynchronizationLib
VmgExitLib
+ VmTdExitLib

[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard # CONSUMES
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
index 892d349d4b37..0976a880825b 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
@@ -8,6 +8,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent

#include <Library/DebugLib.h>
#include <Library/VmgExitLib.h>
+#include <Library/VmTdExitLib.h>
#include "CpuExceptionCommon.h"

/**
@@ -45,6 +46,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 01b5a2f1f4fc..173047a6b494 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
@@ -8,6 +8,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent

#include <PiPei.h>
#include <Library/VmgExitLib.h>
+#include <Library/VmTdExitLib.h>
#include "CpuExceptionCommon.h"

CONST UINTN mDoFarReturnFlag = 0;
@@ -43,6 +44,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.
//
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
index 8ae4feae6238..4aeab2057b08 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
@@ -49,6 +49,7 @@
LocalApicLib
PeCoffGetEntryPointLib
VmgExitLib
+ VmTdExitLib

[FeaturePcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
index c9f20da05860..2622e48103f3 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
@@ -52,6 +52,7 @@
PeCoffGetEntryPointLib
DebugLib
VmgExitLib
+ VmTdExitLib

[FeaturePcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf
index a15f125d5b5e..36ccb7ef97ec 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf
@@ -54,6 +54,7 @@
LocalApicLib
PeCoffGetEntryPointLib
VmgExitLib
+ VmTdExitLib

[FeaturePcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
--
2.29.2.windows.2


[PATCH 11/23] OvmfPkg: Implement library support for VmTdExitLib in Ovmf

Min Xu
 

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

The base VmTdExitLib library provides a default limited interface. As
it does not provide full support, create an OVMF version of this library
to begin the process of providing full support of TDX within OVMF.

PcdIgnoreVeHalt is created in OvmfPkg.dec to ignore the VE halt in TDX.

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf | 41 ++
.../Library/VmTdExitLib/VmTdExitVeHandler.c | 515 ++++++++++++++++++
OvmfPkg/OvmfPkg.dec | 3 +
3 files changed, 559 insertions(+)
create mode 100644 OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf
create mode 100644 OvmfPkg/Library/VmTdExitLib/VmTdExitVeHandler.c

diff --git a/OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf b/OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf
new file mode 100644
index 000000000000..0d9430034330
--- /dev/null
+++ b/OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf
@@ -0,0 +1,41 @@
+## @file
+# VMTDEXIT Support Library.
+#
+# Copyright (c) 2020, Intel Inc. All rights reserved.<BR>
+# Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VmTdExitLib
+ FILE_GUID = b29eabb0-f9a3-11ea-8b6e-0800200c9a66
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = VmTdExitLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources.common]
+ VmTdExitVeHandler.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ TdxLib
+
+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdIgnoreVeHalt
+
+
diff --git a/OvmfPkg/Library/VmTdExitLib/VmTdExitVeHandler.c b/OvmfPkg/Library/VmTdExitLib/VmTdExitVeHandler.c
new file mode 100644
index 000000000000..6e41261cd108
--- /dev/null
+++ b/OvmfPkg/Library/VmTdExitLib/VmTdExitVeHandler.c
@@ -0,0 +1,515 @@
+/** @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 <Library/TdxLib.h>
+#include <Library/VmTdExitLib.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:
+ if (FixedPcdGetBool (PcdIgnoreVeHalt) == FALSE) {
+ 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/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index ccda130f0ef6..8d1f3b03488c 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -342,6 +342,9 @@
## Size of the Ovmf image in KB
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfImageSizeInKb|0|UINT32|0x4f

+ ## Ignore the VE halt in Tdx
+ gUefiOvmfPkgTokenSpaceGuid.PcdIgnoreVeHalt|FALSE|BOOLEAN|0x50
+
[PcdsDynamic, PcdsDynamicEx]
gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
--
2.29.2.windows.2


[PATCH 10/23] OvmfPkg: Prepare OvmfPkg to use the VmTdExitLib library

Min Xu
 

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

Various CpuExceptionHandlerLib libraries will updated to use the new
VmTdExitLib library. To prevent any build breakage, update the OvmfPkg
DSC files that use a form of the CpuExceptionHandlerLib library to
include the VmTdExitLib 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/OvmfPkgIa32.dsc | 1 +
OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
OvmfPkg/OvmfPkgX64.dsc | 1 +
OvmfPkg/OvmfXen.dsc | 1 +
4 files changed, 4 insertions(+)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index d1d92c97bae3..1e1765060e3f 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -243,6 +243,7 @@
[LibraryClasses.common]
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+ VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf

[LibraryClasses.common.SEC]
TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index a467ab7090fb..2eadb51683c9 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -247,6 +247,7 @@
[LibraryClasses.common]
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+ VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf

[LibraryClasses.common.SEC]
TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index e56b83d95e09..3376c4f4c2f9 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -247,6 +247,7 @@
[LibraryClasses.common]
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
+ VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf

[LibraryClasses.common.SEC]
TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index 3c1ca6bfd493..d8d559dacca6 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
+ VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf

[LibraryClasses.common.SEC]
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSecLib.inf
--
2.29.2.windows.2


[PATCH 09/23] UefiCpuPkg: Add VmTdExitLibNull

Min Xu
 

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

VmTdExitLib performs the necessary processing to handle a #VE exception.
VmTdExitLibNull is a NULL instance of VmTdExitLib which provides a default
limited interface. A full feature version of VmTdExitLib should be created
later (for example in OvmfPkg).

PcdTdxIsEnabled indicates if Tdx is enabled.

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
UefiCpuPkg/Include/Library/VmTdExitLib.h | 47 +++++++++++++++++++
.../Library/VmTdExitLibNull/VmTdExitLibNull.c | 37 +++++++++++++++
.../VmTdExitLibNull/VmTdExitLibNull.inf | 34 ++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 9 ++++
UefiCpuPkg/UefiCpuPkg.dsc | 2 +
5 files changed, 129 insertions(+)
create mode 100644 UefiCpuPkg/Include/Library/VmTdExitLib.h
create mode 100644 UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.c
create mode 100644 UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf

diff --git a/UefiCpuPkg/Include/Library/VmTdExitLib.h b/UefiCpuPkg/Include/Library/VmTdExitLib.h
new file mode 100644
index 000000000000..a55a76dc7a30
--- /dev/null
+++ b/UefiCpuPkg/Include/Library/VmTdExitLib.h
@@ -0,0 +1,47 @@
+/** @file
+ Public header file for the VMTDEXIT Support library class.
+
+ This library class defines some routines used when invoking the VMEXIT
+ instruction in support of VMX and TDX to handle #VE exceptions.
+
+ Copyright (c) 2020 - 2021, Intel Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef VMTD_EXIT_LIB_H_
+#define VMTD_EXIT_LIB_H_
+
+#include <Library/BaseLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Protocol/DebugSupport.h>
+
+#define VE_EXCEPTION 20
+
+/**
+ 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/VmTdExitLibNull/VmTdExitLibNull.c b/UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.c
new file mode 100644
index 000000000000..a632abfab498
--- /dev/null
+++ b/UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.c
@@ -0,0 +1,37 @@
+/** @file
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Library/BaseLib.h>
+#include <Library/VmTdExitLib.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/VmTdExitLibNull/VmTdExitLibNull.inf b/UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
new file mode 100644
index 000000000000..ae9af1b7f56b
--- /dev/null
+++ b/UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
@@ -0,0 +1,34 @@
+## @file
+# VMTDEXIT Support Library.
+#
+# Copyright (c) 2020, Intel Inc. All rights reserved.<BR>
+# Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VmTdExitLibNull
+ FILE_GUID = 79BD5323-6CF4-4ECF-A132-F7D31EEADC1E
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = VmTdExitLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = X64 IA32
+#
+
+[Sources.common]
+ VmTdExitLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 62acb291f309..fdc7f9ff48e9 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -62,6 +62,9 @@
## @libraryclass Provides function for loading microcode.
MicrocodeLib|Include/Library/MicrocodeLib.h

+ ## @libraryclass Provides function to support VMTDEXIT processing.
+ VmgExitLib|Include/Library/VmTdExitLib.h
+
[Guids]
gUefiCpuPkgTokenSpaceGuid = { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa, 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }}
gMsegSmramGuid = { 0x5802bce4, 0xeeee, 0x4e33, { 0xa1, 0x30, 0xeb, 0xad, 0x27, 0xf0, 0xe4, 0x39 }}
@@ -396,5 +399,11 @@
# @Prompt SEV-ES Status
gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled|FALSE|BOOLEAN|0x60000016

+ ## This dynamic PCD indicates whether Intel TDX is enabled
+ # TRUE - Intel TDX is enabled
+ # FALSE - Intel TDX is not enabled
+ # @Prompt Intel TDX Status
+ gUefiCpuPkgTokenSpaceGuid.PcdTdxIsEnabled|FALSE|BOOLEAN|0x60000017
+
[UserExtensions.TianoCore."ExtraFiles"]
UefiCpuPkgExtra.uni
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 47768b10d5be..a7853f6f6097 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -60,6 +60,7 @@
PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+ VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
MicrocodeLib|UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf
TdxProbeLib|MdePkg/Library/TdxProbeLib/TdxProbeLib.inf
TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
@@ -160,6 +161,7 @@
UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
UefiCpuPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.inf
UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+ UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf
UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf
UefiCpuPkg/SecCore/SecCore.inf
--
2.29.2.windows.2


[PATCH 08/23] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib

Min Xu
 

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.

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
.../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c | 172 +++++++++++++++++-
.../BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf | 2 +
UefiCpuPkg/UefiCpuPkg.dsc | 2 +
3 files changed, 168 insertions(+), 8 deletions(-)

diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
index cdcbca046191..793ea61b50fa 100644
--- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
+++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
@@ -23,11 +23,166 @@
#include <Library/TimerLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiCpuLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
+#include <Library/TdxProbeLib.h>

//
// Library internal functions
//

+/**
+ Some MSRs in TDX are directly read/write from/to CPU.
+
+ @param MsrIndex Index of the MSR
+ @retval TRUE MSR direct read/write from/to CPU.
+ @retval FALSE MSR not direct read/write from/to CPU.
+
+**/
+BOOLEAN
+EFIAPI
+AccessMsrNative (
+ IN UINT32 MsrIndex
+ )
+{
+ 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 TRUE;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+/**
+ Read MSR value.
+
+ @param MsrIndex Index of the MSR to read
+ @retval 64-bit Value of MSR.
+
+**/
+UINT64
+EFIAPI
+ReadMsrReg64 (
+ IN UINT32 MsrIndex
+ )
+{
+ UINT64 Val;
+ UINT64 Status;
+ if (!AccessMsrNative (MsrIndex) && TdxIsEnabled ()) {
+ 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 Val Value to be written to the MSR
+
+**/
+VOID
+EFIAPI
+WriteMsrReg64 (
+ IN UINT32 MsrIndex,
+ IN UINT64 Val
+ )
+{
+ UINT64 Status;
+ if (!AccessMsrNative (MsrIndex) && TdxIsEnabled ()) {
+ Status = TdVmCall (TDVMCALL_WRMSR, (UINT64) MsrIndex, Val, 0, 0, 0);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+ } else {
+ AsmWriteMsr64 (MsrIndex, Val);
+ }
+}
+
+/**
+ Read MSR value.
+
+ @param MsrIndex Index of the MSR to read
+ @retval 32-bit Value of MSR.
+
+**/
+UINT32
+EFIAPI
+ReadMsrReg32 (
+ IN UINT32 MsrIndex
+ )
+{
+ UINT64 Val;
+ UINT64 Status;
+ if (!AccessMsrNative (MsrIndex) && TdxIsEnabled ()) {
+ Status = TdVmCall (TDVMCALL_RDMSR, (UINT64) MsrIndex, 0, 0, 0, &Val);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+ } else {
+ Val = AsmReadMsr32 (MsrIndex);
+ }
+ return (UINT32)(UINTN) Val;
+}
+
+/**
+ Write to MSR.
+
+ @param MsrIndex Index of the MSR to write to
+ @param Val Value to be written to the MSR
+
+**/
+VOID
+EFIAPI
+WriteMsrReg32 (
+ IN UINT32 MsrIndex,
+ IN UINT32 Val
+ )
+{
+ UINT64 Status;
+ if (!AccessMsrNative (MsrIndex) && TdxIsEnabled ()) {
+ Status = TdVmCall (TDVMCALL_WRMSR, (UINT64) MsrIndex, (UINT64) Val, 0, 0, 0);
+ if (Status != 0) {
+ DEBUG((DEBUG_ERROR, "WriteMsrReg32 returned failure. Status=0x%llx\n", Status));
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+ } else {
+ AsmWriteMsr32 (MsrIndex, Val);
+ }
+}
+
/**
Determine if the CPU supports the Local APIC Base Address MSR.

@@ -77,7 +232,7 @@ GetLocalApicBaseAddress (
return PcdGet32 (PcdCpuLocalApicBaseAddress);
}

- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Uint64 = ReadMsrReg64 (MSR_IA32_APIC_BASE);

return (UINTN)(LShiftU64 ((UINT64) ApicBaseMsr.Bits.ApicBaseHi, 32)) +
(((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);
@@ -108,12 +263,12 @@ SetLocalApicBaseAddress (
return;
}

- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Uint64 = ReadMsrReg64 (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);
+ WriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
}

/**
@@ -153,7 +308,7 @@ ReadLocalApicReg (
ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);

MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
- return AsmReadMsr32 (MsrIndex);
+ return ReadMsrReg32 (MsrIndex);
}
}

@@ -202,7 +357,7 @@ WriteLocalApicReg (
// Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.
//
MemoryFence ();
- AsmWriteMsr32 (MsrIndex, Value);
+ WriteMsrReg32 (MsrIndex, Value);
}
}

@@ -309,7 +464,7 @@ GetApicMode (
return LOCAL_APIC_MODE_XAPIC;
}

- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Uint64 = ReadMsrReg64 (MSR_IA32_APIC_BASE);
//
// Local APIC should have been enabled
//
@@ -350,13 +505,14 @@ SetApicMode (

CurrentMode = GetApicMode ();
if (CurrentMode == LOCAL_APIC_MODE_XAPIC) {
+
switch (ApicMode) {
case LOCAL_APIC_MODE_XAPIC:
break;
case LOCAL_APIC_MODE_X2APIC:
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Uint64 = ReadMsrReg64 (MSR_IA32_APIC_BASE);
ApicBaseMsr.Bits.EXTD = 1;
- AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+ WriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
break;
default:
ASSERT (FALSE);
diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
index 1e2a4f8b790f..2367a3349008 100644
--- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
+++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
@@ -39,6 +39,8 @@
IoLib
PcdLib
UefiCpuLib
+ TdxLib
+ TdxProbeLib

[Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuInitIpiDelayInMicroSeconds ## SOMETIMES_CONSUMES
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 699c91626bd8..47768b10d5be 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -61,6 +61,8 @@
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
MicrocodeLib|UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf
+ TdxProbeLib|MdePkg/Library/TdxProbeLib/TdxProbeLib.inf
+ TdxLib|MdePkg/Library/TdxLib/TdxLib.inf

[LibraryClasses.common.SEC]
PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf
--
2.29.2.windows.2


[PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx

Min Xu
 

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.

BaseIoLibIntrinsicSev.inf is the IoLib used by OvmfPkg. TDVF updates
BaseIoLibIntrinsicSev to support I/O in Td guest. Below files are updated
to support I/O in Td guest.
- IoLib.c
- IoLibGcc.c
- IoLibMsc.c
- X64/IoFifoSev.nasm

In the I/O functions of above files, if IsTdxGuest() returns TRUE, then
Td I/O routine is called, otherwise the legacy I/O routine is called.
Td I/O routines are declared in IoLibTdx.h and implemented in
IoLibInternalTdx.c.

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 is created which holds the null stub of the Td I/O
routines. IoLibInternalTdxNull.c is included in BaseIoLibIntrinsic.inf.
BaseIoLibIntrinsic.inf doesn't import TdxProbeLib/TdxLib so that the Pkgs
which include BaseIoLibIntrinsic.inf need not include TdxProbeLib/TdxLib.

BaseIoLibIntrinsicArmVirt.inf is not touched because it shares no files
with BaseIoLibIntrinsicSev.

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>
---
.../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf | 2 +
.../BaseIoLibIntrinsicSev.inf | 6 +-
MdePkg/Library/BaseIoLibIntrinsic/IoLib.c | 97 ++-
MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c | 49 +-
.../BaseIoLibIntrinsic/IoLibInternalTdx.c | 690 ++++++++++++++++++
.../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 499 +++++++++++++
MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c | 73 +-
MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h | 411 +++++++++++
.../BaseIoLibIntrinsic/X64/IoFifoSev.nasm | 133 ++++
9 files changed, 1911 insertions(+), 49 deletions(-)
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/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 34f9d1d1062f..53ff8d6fd37d 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]
@@ -50,4 +53,5 @@
DebugLib
BaseLib
RegisterFilterLib
-
+ TdxLib
+ TdxProbeLib
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c
index d0d7044f0901..68298749ee56 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.
@@ -70,6 +71,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,9 +89,13 @@ MmioRead8 (

Flag = FilterBeforeMmIoRead (FilterWidth8, Address, &Value);
if (Flag) {
- MemoryFence ();
- Value = *(volatile UINT8*)Address;
- MemoryFence ();
+ if (IsTdxGuest ()) {
+ Value = TdMmioRead8 (Address);
+ } else {
+ MemoryFence ();
+ Value = *(volatile UINT8*)Address;
+ MemoryFence ();
+ }
}
FilterAfterMmIoRead (FilterWidth8, Address, &Value);

@@ -104,6 +111,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.

@@ -121,9 +130,13 @@ MmioWrite8 (

Flag = FilterBeforeMmIoWrite (FilterWidth8, Address, &Value);
if (Flag) {
- MemoryFence ();
- *(volatile UINT8*)Address = Value;
- MemoryFence ();
+ if (IsTdxGuest ()) {
+ TdMmioWrite8 (Address, Value);
+ } else {
+ MemoryFence ();
+ *(volatile UINT8*)Address = Value;
+ MemoryFence ();
+ }
}
FilterAfterMmIoWrite (FilterWidth8, Address, &Value);

@@ -140,6 +153,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.
@@ -157,9 +172,13 @@ MmioRead16 (
ASSERT ((Address & 1) == 0);
Flag = FilterBeforeMmIoRead (FilterWidth16, Address, &Value);
if (Flag) {
- MemoryFence ();
- Value = *(volatile UINT16*)Address;
- MemoryFence ();
+ if (IsTdxGuest ()) {
+ Value = TdMmioRead16 (Address);
+ } else {
+ MemoryFence ();
+ Value = *(volatile UINT16*)Address;
+ MemoryFence ();
+ }
}
FilterAfterMmIoRead (FilterWidth16, Address, &Value);

@@ -176,6 +195,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.

@@ -195,9 +216,13 @@ MmioWrite16 (

Flag = FilterBeforeMmIoWrite (FilterWidth16, Address, &Value);
if (Flag) {
- MemoryFence ();
- *(volatile UINT16*)Address = Value;
- MemoryFence ();
+ if (IsTdxGuest ()) {
+ TdMmioWrite16 (Address, Value);
+ } else {
+ MemoryFence ();
+ *(volatile UINT16*)Address = Value;
+ MemoryFence ();
+ }
}
FilterAfterMmIoWrite (FilterWidth16, Address, &Value);

@@ -214,6 +239,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.
@@ -232,9 +259,13 @@ MmioRead32 (

Flag = FilterBeforeMmIoRead (FilterWidth32, Address, &Value);
if (Flag) {
- MemoryFence ();
- Value = *(volatile UINT32*)Address;
- MemoryFence ();
+ if (IsTdxGuest ()) {
+ Value = TdMmioRead32 (Address);
+ } else {
+ MemoryFence ();
+ Value = *(volatile UINT32*)Address;
+ MemoryFence ();
+ }
}
FilterAfterMmIoRead (FilterWidth32, Address, &Value);

@@ -251,6 +282,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.

@@ -270,9 +303,13 @@ MmioWrite32 (

Flag = FilterBeforeMmIoWrite (FilterWidth32, Address, &Value);
if (Flag) {
- MemoryFence ();
- *(volatile UINT32*)Address = Value;
- MemoryFence ();
+ if (IsTdxGuest ()) {
+ TdMmioWrite32 (Address, Value);
+ } else {
+ MemoryFence ();
+ *(volatile UINT32*)Address = Value;
+ MemoryFence ();
+ }
}
FilterAfterMmIoWrite (FilterWidth32, Address, &Value);

@@ -289,6 +326,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.
@@ -307,9 +346,13 @@ MmioRead64 (

Flag = FilterBeforeMmIoRead (FilterWidth64, Address, &Value);
if (Flag) {
- MemoryFence ();
- Value = *(volatile UINT64*)Address;
- MemoryFence ();
+ if (IsTdxGuest ()) {
+ Value = TdMmioRead64 (Address);
+ } else {
+ MemoryFence ();
+ Value = *(volatile UINT64*)Address;
+ MemoryFence ();
+ }
}
FilterAfterMmIoRead (FilterWidth64, Address, &Value);

@@ -326,6 +369,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.

@@ -343,9 +388,13 @@ MmioWrite64 (

Flag = FilterBeforeMmIoWrite (FilterWidth64, Address, &Value);
if (Flag) {
- MemoryFence ();
- *(volatile UINT64*)Address = Value;
- MemoryFence ();
+ if (IsTdxGuest ()) {
+ TdMmioWrite64 (Address, Value);
+ } else {
+ MemoryFence ();
+ *(volatile UINT64*)Address = Value;
+ MemoryFence ();
+ }
}
FilterAfterMmIoWrite (FilterWidth64, Address, &Value);

diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
index ecf9ed61911f..42b5d5743a4f 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
@@ -17,6 +17,7 @@


#include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"

/**
Reads an 8-bit I/O port.
@@ -25,7 +26,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.

@@ -43,7 +46,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);

@@ -93,6 +106,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.
@@ -111,7 +126,11 @@ IoRead16 (

Flag = FilterBeforeIoRead (FilterWidth16, Port, &Data);
if (Flag) {
+ if (IsTdxGuest ()) {
+ Data = TdIoRead16 (Port);
+ } else {
__asm__ __volatile__ ("inw %w1,%w0" : "=a" (Data) : "d" ((UINT16)Port));
+ }
}
FilterAfterIoRead (FilterWidth16, Port, &Data);

@@ -128,6 +147,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.

@@ -148,7 +169,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);

@@ -165,6 +190,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.
@@ -183,7 +210,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);

@@ -200,6 +231,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.

@@ -219,7 +252,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/IoLibInternalTdx.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
new file mode 100644
index 000000000000..4c342f6d3873
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
@@ -0,0 +1,690 @@
+/** @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/TdxProbeLib.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
+
+/**
+ Check if it is Tdx guest.
+
+ @return TRUE It is Tdx guest
+ @return FALSE It is not Tdx guest
+
+**/
+BOOLEAN
+EFIAPI
+IsTdxGuest (
+ VOID
+ )
+{
+ return TdxIsEnabled ();
+}
+
+
+/**
+ 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;
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+ if (Status != 0) {
+ Value = *(volatile UINT64*) Address;
+ }
+ MemoryFence ();
+
+ 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;
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_WRITE, Address, Val, 0);
+ if (Status != 0) {
+ *(volatile UINT8*) Address = Value;
+ }
+ MemoryFence ();
+
+ 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;
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+ if (Status != 0) {
+ Value = *(volatile UINT64*) Address;
+ }
+ MemoryFence ();
+
+ 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);
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_WRITE, Address, Val, 0);
+ if (Status != 0) {
+ *(volatile UINT16*) Address = Value;
+ }
+ MemoryFence ();
+
+ 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;
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+ if (Status != 0) {
+ Value = *(volatile UINT64*)Address;
+ }
+ MemoryFence ();
+
+ 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);
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_WRITE, Address, Val, 0);
+ if (Status != 0) {
+ *(volatile UINT32*)Address = Value;
+ }
+ MemoryFence ();
+
+ 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;
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+ if (Status != 0) {
+ Value = *(volatile UINT64*)Address;
+ }
+ MemoryFence ();
+
+ 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);
+
+ Address |= TdSharedPageMask ();
+
+ MemoryFence ();
+ Val = Value;
+ Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_WRITE, Address, Val, 0);
+ if (Status != 0) {
+ *(volatile UINT64*)Address = Value;
+ }
+ MemoryFence ();
+ 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..f518d8ffd825
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
@@ -0,0 +1,499 @@
+/** @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/IoLibMsc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
index d2bc5f527cf6..4d7945ae496f 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
@@ -16,6 +16,7 @@


#include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"

//
// Microsoft Visual Studio 7.1 Function Prototypes for I/O Intrinsics.
@@ -54,6 +55,8 @@ void _ReadWriteBarrier (void);

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.
@@ -70,9 +73,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);

@@ -88,6 +95,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.

@@ -105,9 +114,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);

@@ -124,6 +137,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.
@@ -142,9 +157,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);

@@ -161,6 +180,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.

@@ -180,9 +201,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);

@@ -199,6 +224,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.
@@ -217,9 +244,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);

@@ -236,6 +267,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.

@@ -255,9 +288,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);

diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
new file mode 100644
index 000000000000..3aad197d3b39
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
@@ -0,0 +1,411 @@
+/** @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
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm b/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
index 106f8881c55c..7f426495bbe3 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
+++ b/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
@@ -10,6 +10,79 @@
DEFAULT REL
SECTION .text

+extern ASM_PFX(TdIoReadFifo8)
+extern ASM_PFX(TdIoReadFifo16)
+extern ASM_PFX(TdIoReadFifo32)
+extern ASM_PFX(TdIoWriteFifo8)
+extern ASM_PFX(TdIoWriteFifo16)
+extern ASM_PFX(TdIoWriteFifo32)
+
+;------------------------------------------------------------------------------
+; Check whether we need to unroll the String I/O in Tdx guest
+;
+; Return // eax (1 - unroll, 0 - no unroll)
+;------------------------------------------------------------------------------
+global ASM_PFX(TdxNoRepIo)
+ASM_PFX(TdxNoRepIo):
+ ; CPUID clobbers ebx, ecx and edx
+ push rbx
+ push rcx
+ push rdx
+
+ ;
+ ; CPUID (0)
+ ;
+ mov eax, 0
+ cpuid
+ cmp ebx, 0x756e6547 ; "Genu"
+ jne @NoTdx
+ cmp edx, 0x49656e69 ; "ineI"
+ jne @NoTdx
+ cmp ecx, 0x6c65746e ; "ntel"
+ jne @NoTdx
+
+ ;
+ ; CPUID (1)
+ ;
+ mov eax, 1
+ cpuid
+ test ecx, 0x80000000
+ jz @NoTdx
+
+ ;
+ ; CPUID[0].EAX >= 0x21?
+ ;
+ mov eax, 0
+ cpuid
+ cmp eax, 0x21
+ jl @NoTdx
+
+ ;
+ ; CPUID (0x21,0)
+ ;
+ mov eax, 0x21
+ mov ecx, 0
+ cpuid
+
+ cmp ebx, 0x65746E49 ; "Inte"
+ jne @NoTdx
+ cmp edx, 0x5844546C ; "lTDX"
+ jne @NoTdx
+ cmp ecx, 0x20202020 ; " "
+ jne @NoTdx
+
+ mov rax, 1
+ jmp @ExitTdxNoRepIo
+
+@NoTdx:
+ mov rax, 0
+
+@ExitTdxNoRepIo:
+ pop rdx
+ pop rcx
+ pop rbx
+ ret
+
;------------------------------------------------------------------------------
; Check whether we need to unroll the String I/O in SEV guest
;
@@ -75,6 +148,16 @@ ASM_PFX(SevNoRepIo):
;------------------------------------------------------------------------------
global ASM_PFX(IoReadFifo8)
ASM_PFX(IoReadFifo8):
+ call ASM_PFX(TdxNoRepIo)
+ test rax, rax
+ jz @NonTd_IoReadFifo8
+
+ sub rsp, 020h
+ call TdIoReadFifo8
+ add rsp, 020h
+ ret
+
+@NonTd_IoReadFifo8:
xchg rcx, rdx
xchg rdi, r8 ; rdi: buffer address; r8: save rdi

@@ -111,6 +194,16 @@ ASM_PFX(IoReadFifo8):
;------------------------------------------------------------------------------
global ASM_PFX(IoReadFifo16)
ASM_PFX(IoReadFifo16):
+ call ASM_PFX(TdxNoRepIo)
+ test rax, rax
+ jz @NonTd_IoReadFifo16
+
+ sub rsp, 020h
+ call TdIoReadFifo16
+ add rsp, 020h
+ ret
+
+@NonTd_IoReadFifo16:
xchg rcx, rdx
xchg rdi, r8 ; rdi: buffer address; r8: save rdi

@@ -147,6 +240,16 @@ ASM_PFX(IoReadFifo16):
;------------------------------------------------------------------------------
global ASM_PFX(IoReadFifo32)
ASM_PFX(IoReadFifo32):
+ call ASM_PFX(TdxNoRepIo)
+ test rax, rax
+ jz @NonTd_IoReadFifo32
+
+ sub rsp, 020h
+ call TdIoReadFifo32
+ add rsp, 020h
+ ret
+
+@NonTd_IoReadFifo32:
xchg rcx, rdx
xchg rdi, r8 ; rdi: buffer address; r8: save rdi

@@ -183,6 +286,16 @@ ASM_PFX(IoReadFifo32):
;------------------------------------------------------------------------------
global ASM_PFX(IoWriteFifo8)
ASM_PFX(IoWriteFifo8):
+ call ASM_PFX(TdxNoRepIo)
+ test rax, rax
+ jz @NonTd_IoWriteFifo8
+
+ sub rsp, 020h
+ call TdIoWriteFifo8
+ add rsp, 020h
+ ret
+
+@NonTd_IoWriteFifo8:
xchg rcx, rdx
xchg rsi, r8 ; rsi: buffer address; r8: save rsi

@@ -219,6 +332,16 @@ ASM_PFX(IoWriteFifo8):
;------------------------------------------------------------------------------
global ASM_PFX(IoWriteFifo16)
ASM_PFX(IoWriteFifo16):
+ call ASM_PFX(TdxNoRepIo)
+ test rax, rax
+ jz @NonTd_IoWriteFifo16
+
+ sub rsp, 020h
+ call TdIoWriteFifo16
+ add rsp, 020h
+ ret
+
+@NonTd_IoWriteFifo16:
xchg rcx, rdx
xchg rsi, r8 ; rsi: buffer address; r8: save rsi

@@ -255,6 +378,16 @@ ASM_PFX(IoWriteFifo16):
;------------------------------------------------------------------------------
global ASM_PFX(IoWriteFifo32)
ASM_PFX(IoWriteFifo32):
+ call ASM_PFX(TdxNoRepIo)
+ test rax, rax
+ jz @NonTd_IoWriteFifo32
+
+ sub rsp, 020h
+ call TdIoWriteFifo32
+ add rsp, 020h
+ ret
+
+@NonTd_IoWriteFifo32:
xchg rcx, rdx
xchg rsi, r8 ; rsi: buffer address; r8: save rsi

--
2.29.2.windows.2


[PATCH 06/23] MdePkg: Add TdxLib to wrap Tdx operations

Min Xu
 

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:
- TdCall : Cause a VM exit to the Intel TDX module.
- TdVmCall : It helps invoke services from the host VMM to pass/
receive information.
- TdVmCallCpuid : Enable the TD guest to request VMM to emulate CPUID
- 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 virutal CPUs.
- TdVCpuNum : Get the number of virtual CPUs. (In some case VMM may
add more vCPU in runtime).

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>
---
MdePkg/Include/Library/TdxLib.h | 167 +++++++++++++++++++
MdePkg/Library/TdxLib/AcceptPages.c | 136 ++++++++++++++++
MdePkg/Library/TdxLib/Rtmr.c | 118 ++++++++++++++
MdePkg/Library/TdxLib/TdInfo.c | 101 ++++++++++++
MdePkg/Library/TdxLib/TdxLib.inf | 39 +++++
MdePkg/Library/TdxLib/TdxLibNull.c | 192 ++++++++++++++++++++++
MdePkg/Library/TdxLib/X64/Tdcall.nasm | 120 ++++++++++++++
MdePkg/Library/TdxLib/X64/Tdvmcall.nasm | 206 ++++++++++++++++++++++++
MdePkg/MdePkg.dec | 3 +
MdePkg/MdePkg.dsc | 1 +
10 files changed, 1083 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
create mode 100644 MdePkg/Library/TdxLib/X64/Tdcall.nasm
create mode 100644 MdePkg/Library/TdxLib/X64/Tdvmcall.nasm

diff --git a/MdePkg/Include/Library/TdxLib.h b/MdePkg/Include/Library/TdxLib.h
new file mode 100644
index 000000000000..43a7d709657e
--- /dev/null
+++ b/MdePkg/Include/Library/TdxLib.h
@@ -0,0 +1,167 @@
+/** @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.
+ @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 UINT64 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
+ );
+
+
+/**
+ 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
+**/
+EFI_STATUS
+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
+
+**/
+EFI_STATUS
+EFIAPI
+TdVmCall (
+ IN UINT64 Leaf,
+ IN UINT64 Arg1,
+ IN UINT64 Arg2,
+ IN UINT64 Arg3,
+ IN UINT64 Arg4,
+ IN OUT VOID *Results
+ );
+
+/**
+ 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/MdePkg/Library/TdxLib/AcceptPages.c b/MdePkg/Library/TdxLib/AcceptPages.c
new file mode 100644
index 000000000000..8941dc05b114
--- /dev/null
+++ b/MdePkg/Library/TdxLib/AcceptPages.c
@@ -0,0 +1,136 @@
+/** @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;
+
+// PageSize is mapped to PageLevel like below:
+// 4KB - 0, 2MB - 1
+UINT64 mTdxAcceptPageLevelMap[2] = {
+ SIZE_4KB,
+ SIZE_2MB
+};
+
+/**
+ This function gets the PageLevel according to the input page size.
+
+ @param[in] PageSize Page size
+
+ @return UINTN The mapped page level
+**/
+UINTN
+GetGpaPageLevel (
+ UINT64 PageSize
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof (mTdxAcceptPageLevelMap) / sizeof (mTdxAcceptPageLevelMap[0]); 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.
+ @param[in] NumberOfPages Number of the pages to be accepted.
+ @param[in] PageSize GPA page size. Only accept 1G/2M/4K size.
+
+ @return EFI_SUCCESS Accept successfully
+ @return others Indicate other errors
+**/
+EFI_STATUS
+EFIAPI
+TdAcceptPages (
+ IN UINT64 StartAddress,
+ IN UINT64 NumberOfPages,
+ IN UINT64 PageSize
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Address;
+ UINT64 TdxStatus;
+ UINT64 Index;
+ UINT64 GpaPageLevel;
+ UINT64 PageSize2;
+
+ Address = StartAddress;
+
+ GpaPageLevel = (UINT64) GetGpaPageLevel (PageSize);
+ if (GpaPageLevel > sizeof (mTdxAcceptPageLevelMap) / sizeof (mTdxAcceptPageLevelMap[0])) {
+ 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++) {
+ 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++;
+ } 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 {
+
+ //
+ // 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..c86902ae21bc
--- /dev/null
+++ b/MdePkg/Library/TdxLib/Rtmr.c
@@ -0,0 +1,118 @@
+/** @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 + 64)
+#define EXTEND_BUFFER_ADDRESS_MASK 0x3f
+
+
+#pragma pack(16)
+typedef struct {
+ UINT8 Buffer[TD_EXTEND_BUFFER_LEN];
+} TDX_EXTEND_BUFFER;
+#pragma pack()
+
+UINT8 *mExtendBufferAddress = NULL;
+TDX_EXTEND_BUFFER mExtendBuffer;
+
+/**
+ TD.RTMR.EXTEND requires 64B-aligned guest physical address of
+ 48B-extension data. In runtime we walk thru the Buffer to find
+ out a 64B-aligned start address.
+
+ @return Start address of the extend buffer
+
+**/
+UINT8 *
+EFIAPI
+GetExtendBuffer (
+ VOID
+ )
+{
+ UINT8 *ExtendBufferAddress;
+ UINT64 Gap;
+
+ if (mExtendBufferAddress != NULL) {
+ return mExtendBufferAddress;
+ }
+
+ ExtendBufferAddress = mExtendBuffer.Buffer;
+
+ Gap = 0x40 - ((UINT64)(UINTN)ExtendBufferAddress & EXTEND_BUFFER_ADDRESS_MASK);
+ mExtendBufferAddress = (UINT8*)((UINT64)(UINTN)ExtendBufferAddress + Gap);
+
+ DEBUG ((DEBUG_VERBOSE, "ExtendBufferAddress: 0x%p, Gap: 0x%x\n", ExtendBufferAddress, Gap));
+ DEBUG ((DEBUG_VERBOSE, "mExtendBufferAddress: 0x%p\n", mExtendBufferAddress));
+
+ ASSERT (mExtendBufferAddress + 64 <= ExtendBufferAddress + TD_EXTEND_BUFFER_LEN);
+
+ return mExtendBufferAddress;
+}
+
+
+/**
+ 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 (Index >= 0 && Index < RTMR_COUNT);
+ ASSERT (DataLen == SHA384_DIGEST_SIZE);
+
+ ExtendBuffer = GetExtendBuffer();
+ ASSERT (ExtendBuffer != NULL);
+ 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..ed07fc522f26
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdInfo.c
@@ -0,0 +1,101 @@
+/** @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;
+
+/**
+ 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
+ )
+{
+ UINT64 Status;
+ UINT8 Gpaw;
+ TD_RETURN_DATA TdReturnData;
+
+ if (mTdSharedPageMask != 0) {
+ return mTdSharedPageMask;
+ }
+
+ Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+ ASSERT (Status == TDX_EXIT_REASON_SUCCESS);
+
+ Gpaw = (UINT8)(TdReturnData.TdInfo.Gpaw & 0x3f);
+ ASSERT(Gpaw == 48 || Gpaw == 52);
+ mTdSharedPageMask = 1ULL << (Gpaw - 1);
+ return mTdSharedPageMask;
+}
+
+/**
+ This function gets the maximum number of Virtual CPUs that are usable for
+ Td Guest.
+
+ @return maximum Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdMaxVCpuNum (
+ VOID
+ )
+{
+ UINT64 Status;
+ TD_RETURN_DATA TdReturnData;
+
+ if (mTdMaxVCpuNum != 0) {
+ return mTdMaxVCpuNum;
+ }
+
+ Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+ ASSERT (Status == TDX_EXIT_REASON_SUCCESS);
+
+ mTdMaxVCpuNum = TdReturnData.TdInfo.MaxVcpus;
+
+ return mTdMaxVCpuNum;
+}
+
+/**
+ This function gets the number of Virtual CPUs that are usable for Td
+ Guest.
+
+ @return Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdVCpuNum (
+ VOID
+ )
+{
+ UINT64 Status;
+ TD_RETURN_DATA TdReturnData;
+
+ //
+ // Due to the possible change of vcpu num in run-time, do the Td call
+ // for every query.
+ //
+ Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+ ASSERT (Status == TDX_EXIT_REASON_SUCCESS);
+
+ return TdReturnData.TdInfo.NumVcpus;
+}
diff --git a/MdePkg/Library/TdxLib/TdxLib.inf b/MdePkg/Library/TdxLib/TdxLib.inf
new file mode 100644
index 000000000000..772abcc49d8b
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdxLib.inf
@@ -0,0 +1,39 @@
+## @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
+ X64/Tdcall.nasm
+ X64/Tdvmcall.nasm
+
+[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..5a8f19c6d8d2
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdxLibNull.c
@@ -0,0 +1,192 @@
+/** @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 UINT64 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;
+}
+
+
+/**
+ 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
+**/
+EFI_STATUS
+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
+
+**/
+EFI_STATUS
+EFIAPI
+TdVmCall (
+ IN UINT64 Leaf,
+ IN UINT64 Arg1,
+ IN UINT64 Arg2,
+ IN UINT64 Arg3,
+ IN UINT64 Arg4,
+ IN OUT VOID *Results
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ 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
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/MdePkg/Library/TdxLib/X64/Tdcall.nasm b/MdePkg/Library/TdxLib/X64/Tdcall.nasm
new file mode 100644
index 000000000000..eebd4880e2dc
--- /dev/null
+++ b/MdePkg/Library/TdxLib/X64/Tdcall.nasm
@@ -0,0 +1,120 @@
+;------------------------------------------------------------------------------
+;*
+;* 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)
+
+%macro tdcall_regs_preamble 2
+ mov rax, %1
+
+ 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
+
+; 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/TdxLib/X64/Tdvmcall.nasm b/MdePkg/Library/TdxLib/X64/Tdvmcall.nasm
new file mode 100644
index 000000000000..33bb811a3a25
--- /dev/null
+++ b/MdePkg/Library/TdxLib/X64/Tdvmcall.nasm
@@ -0,0 +1,206 @@
+;------------------------------------------------------------------------------
+;*
+;* 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
+
+ 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
+
+;------------------------------------------------------------------------------
+; 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
+; 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
+
+ ; Panic 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
+
+.panic:
+ ud2
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index 5702b0596499..94160588018f 100644
--- a/MdePkg/MdePkg.dec
+++ b/MdePkg/MdePkg.dec
@@ -299,6 +299,9 @@
## @libraryclass Provides function to support TDX probe processing.
TdxProbeLib|Include/Library/TdxProbeLib.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 a62a9504bc12..b7f99b2f2772 100644
--- a/MdePkg/MdePkg.dsc
+++ b/MdePkg/MdePkg.dsc
@@ -176,6 +176,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


[PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx

Min Xu
 

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

Guest software can be designed to run either as a TD, as a legacy virtual
machine, or directly on the CPU, based on enumeration of its run-time
environment. CPUID leaf 0x21 emulation is done by the Intel TDX module.
Sub-leaf 0 returns the values of "IntelTDX " in EBX/EDX/ECX.

TdxProbeLib provides *TdxIsEnabled* to determine Td or Non-Td.

On IA32 it always return FALSE because Intel TDX only works on X64.

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>
---
MdePkg/Include/Library/TdxProbeLib.h | 25 +++++
MdePkg/Library/TdxProbeLib/InternalTdxProbe.h | 25 +++++
MdePkg/Library/TdxProbeLib/TdProbeNull.c | 25 +++++
MdePkg/Library/TdxProbeLib/TdxProbeLib.c | 35 +++++++
MdePkg/Library/TdxProbeLib/TdxProbeLib.inf | 34 +++++++
MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm | 97 +++++++++++++++++++
MdePkg/MdePkg.dec | 3 +
MdePkg/MdePkg.dsc | 1 +
8 files changed, 245 insertions(+)
create mode 100644 MdePkg/Include/Library/TdxProbeLib.h
create mode 100644 MdePkg/Library/TdxProbeLib/InternalTdxProbe.h
create mode 100644 MdePkg/Library/TdxProbeLib/TdProbeNull.c
create mode 100644 MdePkg/Library/TdxProbeLib/TdxProbeLib.c
create mode 100644 MdePkg/Library/TdxProbeLib/TdxProbeLib.inf
create mode 100644 MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm

diff --git a/MdePkg/Include/Library/TdxProbeLib.h b/MdePkg/Include/Library/TdxProbeLib.h
new file mode 100644
index 000000000000..d4fa4ba4cdf8
--- /dev/null
+++ b/MdePkg/Include/Library/TdxProbeLib.h
@@ -0,0 +1,25 @@
+/** @file
+ TdxProbeLib definitions
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TDX_PROBE_LIB_H_
+#define TDX_PROBE_LIB_H_
+
+#include <Library/BaseLib.h>
+
+/**
+ Whether Intel TDX is enabled.
+
+ @return TRUE TDX enabled
+ @return FALSE TDX not enabled
+**/
+BOOLEAN
+EFIAPI
+TdxIsEnabled (
+ VOID);
+
+#endif
diff --git a/MdePkg/Library/TdxProbeLib/InternalTdxProbe.h b/MdePkg/Library/TdxProbeLib/InternalTdxProbe.h
new file mode 100644
index 000000000000..53cbbeda8cd8
--- /dev/null
+++ b/MdePkg/Library/TdxProbeLib/InternalTdxProbe.h
@@ -0,0 +1,25 @@
+/** @file
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef INTERNAL_TDX_PROBE_H_
+#define INTERNAL_TDX_PROBE_H_
+
+#define PROBE_IS_TD_GUEST 0
+#define PROBE_NOT_TD_GUEST 1
+
+/**
+ The internal Td Probe implementation.
+
+ @return 0 TD guest
+ @return others Non-TD guest
+**/
+UINTN
+EFIAPI
+TdProbe (
+ VOID
+ );
+
+#endif
diff --git a/MdePkg/Library/TdxProbeLib/TdProbeNull.c b/MdePkg/Library/TdxProbeLib/TdProbeNull.c
new file mode 100644
index 000000000000..12e9e1f8a7d4
--- /dev/null
+++ b/MdePkg/Library/TdxProbeLib/TdProbeNull.c
@@ -0,0 +1,25 @@
+/** @file
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Library/BaseLib.h>
+#include "InternalTdxProbe.h"
+
+/**
+ TDX only works in X64. So allways return -1 to indicate Non-Td.
+
+ @return 0 TD guest
+ @return others Non-TD guest
+**/
+UINTN
+EFIAPI
+TdProbe (
+ VOID
+ )
+{
+ return PROBE_NOT_TD_GUEST;
+}
diff --git a/MdePkg/Library/TdxProbeLib/TdxProbeLib.c b/MdePkg/Library/TdxProbeLib/TdxProbeLib.c
new file mode 100644
index 000000000000..3f4524dc16a6
--- /dev/null
+++ b/MdePkg/Library/TdxProbeLib/TdxProbeLib.c
@@ -0,0 +1,35 @@
+/** @file
+ instance of TdxProbeLib
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Library/BaseLib.h>
+#include <Library/TdxProbeLib.h>
+#include "InternalTdxProbe.h"
+
+BOOLEAN mTdxEnabled = FALSE;
+BOOLEAN mTdxProbed = FALSE;
+
+/**
+ Whether Intel TDX is enabled.
+
+ @return TRUE TDX enabled
+ @return FALSE TDX not enabled
+**/
+BOOLEAN
+EFIAPI
+TdxIsEnabled (
+ VOID)
+{
+ if (mTdxProbed) {
+ return mTdxEnabled;
+ }
+
+ mTdxEnabled = TdProbe () == PROBE_IS_TD_GUEST;
+ mTdxProbed = TRUE;
+ return mTdxEnabled;
+}
diff --git a/MdePkg/Library/TdxProbeLib/TdxProbeLib.inf b/MdePkg/Library/TdxProbeLib/TdxProbeLib.inf
new file mode 100644
index 000000000000..59fc12c41569
--- /dev/null
+++ b/MdePkg/Library/TdxProbeLib/TdxProbeLib.inf
@@ -0,0 +1,34 @@
+## @file
+# Tdx Probe library instance
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TdxProbeLib
+ FILE_GUID = 26BF0B58-6E9D-4375-A363-52FD83FB82CE
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TdxProbeLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ TdxProbeLib.c
+ InternalTdxProbe.h
+
+[Sources.X64]
+ X64/TdProbe.nasm
+
+[Sources.IA32]
+ TdProbeNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
diff --git a/MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm b/MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm
new file mode 100644
index 000000000000..ed941830f0ca
--- /dev/null
+++ b/MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm
@@ -0,0 +1,97 @@
+;------------------------------------------------------------------------------
+;*
+;* CPUID leaf 0x21 emulation is done by the Intel TDX module. Sub-leaf 0
+;* returns the values of "IntelTDX " in EBX/EDX/ECX.
+;*
+;* Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+%define TD_PROBE_TD_GUEST 0
+%define TD_PROBE_NOT_TD_GUEST 1
+
+%macro td_push_regs 0
+ push rbp
+ mov rbp, rsp
+ push r15
+ push r14
+ push r13
+ push r12
+ push rbx
+ push rsi
+ push rdi
+%endmacro
+
+%macro td_pop_regs 0
+ pop rdi
+ pop rsi
+ pop rbx
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+ pop rbp
+%endmacro
+
+
+global ASM_PFX(TdProbe)
+ASM_PFX(TdProbe):
+
+ td_push_regs
+
+ ;
+ ; CPUID (0)
+ ;
+ mov eax, 0
+ cpuid
+ cmp ebx, 0x756e6547 ; "Genu"
+ jne .not_td
+ cmp edx, 0x49656e69 ; "ineI"
+ jne .not_td
+ cmp ecx, 0x6c65746e ; "ntel"
+ jne .not_td
+
+ ;
+ ; CPUID (1)
+ ;
+ mov eax, 1
+ cpuid
+ test ecx, 0x80000000
+ jz .not_td
+
+ ;
+ ; CPUID[0].EAX >= 0x21?
+ ;
+ mov eax, 0
+ cpuid
+ cmp eax, 0x21
+ jl .not_td
+
+ ;
+ ; CPUID (0x21,0)
+ ;
+ mov eax, 0x21
+ mov ecx, 0
+ cpuid
+
+ cmp ebx, 0x65746E49 ; "Inte"
+ jne .not_td
+ cmp edx, 0x5844546C ; "lTDX"
+ jne .not_td
+ cmp ecx, 0x20202020 ; " "
+ jne .not_td
+
+ mov rax, TD_PROBE_TD_GUEST
+ jmp .exit
+
+.not_td:
+ mov rax, TD_PROBE_NOT_TD_GUEST
+
+.exit:
+ td_pop_regs
+ ret
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index a28a2daaffa8..5702b0596499 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 probe processing.
+ TdxProbeLib|Include/Library/TdxProbeLib.h
+
[Guids]
#
# GUID defined in UEFI2.1/UEFI2.0/EFI1.1
diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc
index a94959169b2f..a62a9504bc12 100644
--- a/MdePkg/MdePkg.dsc
+++ b/MdePkg/MdePkg.dsc
@@ -130,6 +130,7 @@
MdePkg/Library/StandaloneMmServicesTableLib/StandaloneMmServicesTableLib.inf

MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
+ MdePkg/Library/TdxProbeLib/TdxProbeLib.inf

[Components.IA32, Components.X64, Components.ARM, Components.AARCH64]
#
--
2.29.2.windows.2


[PATCH 04/23] MdePkg: Add Tdx.h

Min Xu
 

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
MdePkg/Include/IndustryStandard/Tdx.h | 200 ++++++++++++++++++++++++++
1 file changed, 200 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..c50470708b56
--- /dev/null
+++ b/MdePkg/Include/IndustryStandard/Tdx.h
@@ -0,0 +1,200 @@
+/** @file
+ Intel Trust Domain Extension definitions
+
+ 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


[PATCH 03/23] OvmfPkg/ResetVector: Enable Intel TDX in ResetVector of Ovmf

Min Xu
 

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

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

Note: Intel TDX only is available on X64, so the Tdx related changes are
in X64 path. In IA32 path, there may be null stub to make the build
success.

This patch includes below major changes.

1. CC_WORK_AREA
Ovmf is able to run on different types of VM guest with ONE image. These
VM guest includes the Legacy guest, SEV guest and TDX guest. In
ResetVector CC_WORK_AREA is such a memory region to record the VM guest
information. Below is the definition of the work area.

typedef struct {
UINT8 Type; // 0 legacy, 1 SEV, 2 TDX
UINT8 SubType; // Depends on Type
UINT8 Rsvd[2]; // Reserved
union VM_GUEST {
TDX_WORK_AREA Tdx;
SEV_WORK_AREA Sev;
} Guest;
} CC_WORK_AREA_HEAD;

typedef struct {
... ...
} TDX_WORK_AREA

typedef struct {
... ...
} SEV_WORK_AREA

2. X64/IntelTdxMetadata.asm
IntelTdxMetadata describes the information about the image for VMM use.
For example, the base address and length of the TdHob, TdMailbox, etc.
Its offset is put in a GUID-ed structure which is appended in the GUID-ed
chain from a fixed GPA (0xffffffd0). Below are the items in TdxMetadata:
_Bfv:
Boot Firmware Volume
_Cfv:
Configuration Firmware Volume
_Stack:
Initial stack
_Heap:
Initial heap
_MailBox:
TDVF reserves the memory region so each AP can receive the message
sent by the guest OS.
_CcWorkarea:
Compute Confidential work area which is consumed by CC technologies,
such as SEV, TDX.
_TdHob:
VMM pass the resource information in TdHob to TDVF.
_TdxPageTable:
If 5-level page table is supported (GPAW is 52), a top level page
directory pointers (1 * 256TB entry) is generated in this page.
_OvmfPageTable:
Initial page table for standard Ovmf.

TDVF indicate above chunk of temporary initialized memory region (_Stack/
_Heap/_MailBox/_CcWorkarea/_TdHob/_TdxPageTables/OvmfPageTable) to support
TDVF code finishing the memory initialization. Because the other
unaccepted memory cannot be accessed until they're accepted.

Since AMD SEV has already defined some SEV specific memory region in
MEMFD. TDX re-use the memory regions defined by SEV.
- MailBox : PcdOvmfSecGhcbBackupBase|PcdOvmfSecGhcbBackupSize
- TdHob : PcdOvmfSecGhcbBase|PcdOvmfSecGhcbSize
- TdxPageTable : PcdOvmfSecGhcbPageTableBase|PcdOvmfSecGhcbPageTableSize
- CcWorkArea : PcdSevEsWorkAreaBase|PcdSevEsWorkAreaSize

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

- InitTdxWorkarea
It initialize the CC_WORK_AREA. Because it is called by both BSP and
APs and to avoid the race condition, only BSP can initialize the
WORK_AREA. AP will wait until the field of TDX_WORK_AREA_PGTBL_READY
is set.

- ReloadFlat32
After reset all CPUs in TDX are initialized to 32-bit protected mode.
But GDT register is not set. So this routine loads the GDT and set the
CR0, then jump to Flat 32 protected mode. After that CR4 and other
registers are set.

- InitTdx
This routine wrap above 3 routines together to do Tdx initialization
in ResetVector phase.

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

- IsTdxEnabled
It is a OneTimeCall to probe if TDX is enabled by checking the
CC_WORK_AREA.

4. Ia32/AmdSev.asm
AmdSev.asm includes the SEV routines used in ResetVector. This patch
remove the code of clearing SEV_ES_WORK_AREA in CheckSevFeatures. The
clearing of SEV_ES_WORK_AREA is called at Main16 in Main.asm.

5. Main.asm
Previously OvmfPkg/ResetVector use the Main.asm in UefiCpuPkg. There is
only Main16 entry point. Main32 entry point is needed in Main.asm because
of Intel TDX. To reduce the complexity of Main.asm in UefiCpuPkg, OvmfPkg
create its own Main.asm to meet the requirement of Intel TDX. There are
below changes in this Main.asm:
- A new entry point (Main32) is added. TDX guest will jump to Main32
from ResetVecotr.
- In Main16 entry point, after TransitionFromReal16To32BitFlat,
CC_WORK_AREA is cleared to 0.

6. Ia32/PageTables64.asm
GPAW of TDX can be 48 or 52, which determines the level of page table.
If Level-5(GPAW 52) paging is supported, then an extra page is needed
to hold the top level Page Directory Pointers (1 * 256TB entry).

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

8. ResetVector.nasmb
TDX related macros and files are added in ResetVecotr.nasmb.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 39 +++
OvmfPkg/ResetVector/Ia32/AmdSev.asm | 7 -
OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm | 9 +
OvmfPkg/ResetVector/Ia32/IntelTdx.asm | 265 +++++++++++++++++++
OvmfPkg/ResetVector/Ia32/PageTables64.asm | 113 +++++---
OvmfPkg/ResetVector/Main.asm | 121 +++++++++
OvmfPkg/ResetVector/ResetVector.inf | 12 +-
OvmfPkg/ResetVector/ResetVector.nasmb | 48 +++-
OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm | 110 ++++++++
9 files changed, 679 insertions(+), 45 deletions(-)
create mode 100644 OvmfPkg/ResetVector/Ia32/IntelTdx.asm
create mode 100644 OvmfPkg/ResetVector/Main.asm
create mode 100644 OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm

diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
index 7ec3c6e980c3..62feeacbee7b 100644
--- a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
+++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
@@ -47,6 +47,24 @@ TIMES (15 - ((guidedStructureEnd - guidedStructureStart + 15) % 16)) DB 0
;
guidedStructureStart:

+%ifdef ARCH_X64
+;
+; TDX Metadata offset block
+;
+; If TdxMetadata.asm is included then we need below block which describes
+; the offset of TdxMetadata block in Ovmf image
+;
+; GUID : e47a6535-984a-4798-865e-4685a7bf8ec2
+;
+tdxMetadataOffsetStart:
+ DD (OVMF_IMAGE_SIZE_IN_KB * 1024 - (fourGigabytes - TdxMetadataGuid - 16))
+ DD tdxMetadataOffsetEnd - tdxMetadataOffsetStart
+ DB 0x35, 0x65, 0x7a, 0xe4, 0x4a, 0x98, 0x98, 0x47
+ DB 0x86, 0x5e, 0x46, 0x85, 0xa7, 0xbf, 0x8e, 0xc2
+tdxMetadataOffsetEnd:
+
+%endif
+
; SEV Hash Table Block
;
; This describes the guest ram area where the hypervisor should
@@ -158,10 +176,31 @@ resetVector:
;
; This is where the processor will begin execution
;
+; In IA32 we follow the standard reset vector flow. While in X64, Td guest
+; may be supported. Td guest requires the startup mode to be 32-bit
+; protected mode but the legacy VM startup mode is 16-bit real mode.
+; To make NASM generate such shared entry code that behaves correctly in
+; both 16-bit and 32-bit mode, more BITS directives are added.
+;
+%ifdef ARCH_IA32
+
nop
nop
jmp EarlyBspInitReal16

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

fourGigabytes:
diff --git a/OvmfPkg/ResetVector/Ia32/AmdSev.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
index aa95d06eaddb..d0d9890d5c4b 100644
--- a/OvmfPkg/ResetVector/Ia32/AmdSev.asm
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -128,13 +128,6 @@ SevEsUnexpectedRespTerminate:
; If SEV is disabled then EAX will be zero.
;
CheckSevFeatures:
- ; Set the first byte of the workarea to zero to communicate to the SEC
- ; phase that SEV-ES is not enabled. If SEV-ES is enabled, the CPUID
- ; instruction will trigger a #VC exception where the first byte of the
- ; workarea will be set to one or, if CPUID is not being intercepted,
- ; the MSR check below will set the first byte of the workarea to one.
- mov byte[SEV_ES_WORK_AREA], 0
-
;
; Set up exception handlers to check for SEV-ES
; Load temporary RAM stack based on PCDs (see SevEsIdtVmmComm for
diff --git a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
index c6d0d898bcd1..ea8723efd417 100644
--- a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
+++ b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
@@ -17,6 +17,14 @@ Transition32FlatTo64Flat:

OneTimeCall SetCr3ForPageTables64

+ OneTimeCall PostSetCr3PageTables64Tdx
+
+ ;
+ ; If it is TDX, we're done and jump to enable paging
+ ;
+ cmp byte[CC_WORK_AREA], VM_GUEST_TDX
+ je EnablePaging
+
mov eax, cr4
bts eax, 5 ; enable PAE
mov cr4, eax
@@ -71,6 +79,7 @@ jumpTo64BitAndLandHere:

;
; Check if the second step of the SEV-ES mitigation is to be performed.
+ ; If it is Tdx, ebx is cleared in PostSetCr3PageTables64Tdx.
;
test ebx, ebx
jz InsnCompare
diff --git a/OvmfPkg/ResetVector/Ia32/IntelTdx.asm b/OvmfPkg/ResetVector/Ia32/IntelTdx.asm
new file mode 100644
index 000000000000..f40331a5cbce
--- /dev/null
+++ b/OvmfPkg/ResetVector/Ia32/IntelTdx.asm
@@ -0,0 +1,265 @@
+;------------------------------------------------------------------------------
+; @file
+; Intel TDX routines
+;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+%define SEC_DEFAULT_CR0 0x00000023
+%define SEC_DEFAULT_CR4 0x640
+
+%define VM_GUEST_TDX 2
+
+BITS 32
+
+;
+; Check if it is Intel Tdx
+;
+; Modified: EAX, EBX, ECX, EDX
+;
+; If it is Intel Tdx, EAX is zero
+; If it is not Intel Tdx, EAX is non-zero
+;
+IsTdx:
+ ;
+ ; CPUID (0)
+ ;
+ mov eax, 0
+ cpuid
+ cmp ebx, 0x756e6547 ; "Genu"
+ jne IsNotTdx
+ cmp edx, 0x49656e69 ; "ineI"
+ jne IsNotTdx
+ cmp ecx, 0x6c65746e ; "ntel"
+ jne IsNotTdx
+
+ ;
+ ; CPUID (1)
+ ;
+ mov eax, 1
+ cpuid
+ test ecx, 0x80000000
+ jz IsNotTdx
+
+ ;
+ ; CPUID[0].EAX >= 0x21?
+ ;
+ mov eax, 0
+ cpuid
+ cmp eax, 0x21
+ jl IsNotTdx
+
+ ;
+ ; CPUID (0x21,0)
+ ;
+ mov eax, 0x21
+ mov ecx, 0
+ cpuid
+
+ cmp ebx, 0x65746E49 ; "Inte"
+ jne IsNotTdx
+ cmp edx, 0x5844546C ; "lTDX"
+ jne IsNotTdx
+ cmp ecx, 0x20202020 ; " "
+ jne IsNotTdx
+
+ mov eax, 0
+ jmp ExitIsTdx
+
+IsNotTdx:
+ mov eax, 1
+
+ExitIsTdx:
+
+ OneTimeCallRet IsTdx
+
+;
+; Initialize Tdx work area (CC_WORK_AREA) if it is Tdx guest.
+; BSP and APs all go here. Only BSP can initialize the WORK_AREA
+;
+; typedef struct {
+; UINT8 Type; // 0 legacy, 1 SEV, 2 TDX
+; UINT8 SubType; // Depends on Type
+; UINT8 Rsvd[2]; // Reserved
+; union VM_GUEST {
+; TDX_WORK_AREA Tdx;
+; SEV_WORK_AREA Sev;
+; } Guest;
+; } CC_WORK_AREA_HEAD;
+;
+; typedef struct {
+; UINT8 IsPageLevel5;
+; UINT8 IsPageTableReady;
+; UINT8 Rsvd[2];
+; UINT32 Gpaw;
+; } TDX_WORK_AREA
+;
+; Param[in] EBP[6:0] CPU Supported GPAW (48 or 52)
+; Param[in] ESI[31:0] vCPU ID (BSP is 0, others are AP)
+;
+; Modified: EBP
+;
+InitTdxWorkarea:
+
+ ;
+ ; First check if it is Tdx
+ ;
+ OneTimeCall IsTdx
+
+ test eax, eax
+ jnz ExitInitTdxWorkarea
+
+ ;
+ ; In Td guest, BSP/AP shares the same entry point
+ ; BSP builds up the page table, while APs shouldn't do the same task.
+ ; Instead, APs just leverage the page table which is built by BSP.
+ ; APs will wait until the page table is ready.
+ ;
+ cmp esi, 0
+ je TdxBspEntry
+
+TdxApWait:
+ cmp byte[TDX_WORK_AREA_PGTBL_READY], 0
+ je TdxApWait
+ jmp ExitInitTdxWorkarea
+
+TdxBspEntry:
+ ;
+ ; Set Type and SubType of CC_WORK_AREA so that the
+ ; following code can use these information.
+ ;
+ mov byte[CC_WORK_AREA], VM_GUEST_TDX
+ mov byte[CC_WORK_AREA_SUBTYPE], 0
+
+ ;
+ ; EBP[6:0] CPU supported GPA width
+ ;
+ and ebp, 0x3f
+ cmp ebp, 52
+ jl NotPageLevel5
+ mov byte[TDX_WORK_AREA_PAGELEVEL5], 1
+
+NotPageLevel5:
+ mov DWORD[TDX_WORK_AREA_GPAW], ebp
+
+ExitInitTdxWorkarea:
+ OneTimeCallRet InitTdxWorkarea
+
+;
+; Load the GDT and set the CR0, then jump to Flat 32 protected mode.
+;
+; Modified: EAX, EBX, CR0, CR4, DS, ES, FS, GS, SS
+;
+ReloadFlat32:
+
+ cli
+ mov ebx, ADDR_OF(gdtr)
+ lgdt [ebx]
+
+ mov eax, SEC_DEFAULT_CR0
+ mov cr0, eax
+
+ jmp LINEAR_CODE_SEL:dword ADDR_OF(jumpToFlat32BitAndLandHere)
+
+jumpToFlat32BitAndLandHere:
+
+ mov eax, SEC_DEFAULT_CR4
+ mov cr4, eax
+
+ debugShowPostCode POSTCODE_32BIT_MODE
+
+ mov ax, LINEAR_SEL
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ OneTimeCallRet ReloadFlat32
+
+;
+; Tdx initialization after entering into ResetVector
+;
+; Modified: EAX, EBX, ECX, EDX, EBP, EDI, ESP
+;
+InitTdx:
+ ;
+ ; Save EBX in EBP because EBX will be changed in ReloadFlat32
+ ;
+ mov ebp, ebx
+
+ ;
+ ; First load the GDT and jump to Flat32 mode
+ ;
+ OneTimeCall ReloadFlat32
+
+ ;
+ ; Initialization of Tdx work area
+ ;
+ OneTimeCall InitTdxWorkarea
+
+ OneTimeCallRet InitTdx
+
+;
+; Called after SetCr3PageTables64 in Tdx guest to set CR0/CR4.
+; If GPAW is 52, then CR3 is adjusted as well.
+;
+; Modified: EAX, EBX, CR0, CR3, CR4
+;
+PostSetCr3PageTables64Tdx:
+ ;
+ ; TDX_WORK_AREA was set in InitTdx if it is Tdx guest
+ ;
+ cmp byte[CC_WORK_AREA], VM_GUEST_TDX
+ jne ExitPostSetCr3PageTables64Tdx
+
+ mov eax, cr4
+ bts eax, 5 ; enable PAE
+
+ ;
+ ; byte[TDX_WORK_AREA_PAGELEVEL5] holds the indicator whether 52bit is
+ ; supported. if it is the case, need to set LA57 and use 5-level paging
+ ;
+ cmp byte[TDX_WORK_AREA_PAGELEVEL5], 0
+ jz TdxSetCr4
+ bts eax, 12
+
+TdxSetCr4:
+ mov cr4, eax
+ mov ebx, cr3
+
+ ;
+ ; if la57 is not set, we are ok
+ ; if using 5-level paging, adjust top-level page directory
+ ;
+ bt eax, 12
+ jnc TdxSetCr3
+ mov ebx, TDX_PT_ADDR (0)
+
+TdxSetCr3:
+ mov cr3, ebx
+
+ xor ebx, ebx
+
+ExitPostSetCr3PageTables64Tdx:
+ OneTimeCallRet PostSetCr3PageTables64Tdx
+
+;
+; Check if TDX is enabled
+;
+; Modified: EAX
+;
+; If TDX is enabled then EAX will be 1
+; If TDX is disabled then EAX will be 0.
+;
+IsTdxEnabled:
+ xor eax, eax
+ cmp byte[CC_WORK_AREA], VM_GUEST_TDX
+ jne NotTdx
+ mov eax, 1
+
+NotTdx:
+ OneTimeCallRet IsTdxEnabled
+
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index eacdb69ddb9f..1f4c0c50ac2e 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -37,11 +37,81 @@ BITS 32
PAGE_READ_WRITE + \
PAGE_PRESENT)

+TdxBuildExtraPageTables:
+ ;
+ ; Extra page tables built by Tdx guests
+ ;
+ xor eax, eax
+ mov ecx, 0x400
+tdClearTdxPageTablesMemoryLoop:
+ mov dword [ecx * 4 + TDX_PT_ADDR(0) - 4], eax
+ loop tdClearTdxPageTablesMemoryLoop
+
+ ;
+ ; Top level Page Directory Pointers (1 * 256TB entry)
+ ;
+ mov dword[TDX_PT_ADDR (0)], PT_ADDR(0) + PAGE_PDP_ATTR
+
+ ;
+ ; Set TDX_WORK_AREA_PGTBL_READY to notify APs to go
+ ;
+ mov byte[TDX_WORK_AREA_PGTBL_READY], 1
+
+ OneTimeCallRet TdxBuildExtraPageTables
+
+SevBuildGhcbPageTables:
+ ;
+ ; The initial GHCB will live at GHCB_BASE and needs to be un-encrypted.
+ ; This requires the 2MB page for this range be broken down into 512 4KB
+ ; pages. All will be marked encrypted, except for the GHCB.
+ ;
+ mov ecx, (GHCB_BASE >> 21)
+ mov eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
+ mov [ecx * 8 + PT_ADDR (0x2000)], eax
+
+ ;
+ ; Page Table Entries (512 * 4KB entries => 2MB)
+ ;
+ mov ecx, 512
+pageTableEntries4kLoop:
+ mov eax, ecx
+ dec eax
+ shl eax, 12
+ add eax, GHCB_BASE & 0xFFE0_0000
+ add eax, PAGE_4K_PDE_ATTR
+ mov [ecx * 8 + GHCB_PT_ADDR - 8], eax
+ mov [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx
+ loop pageTableEntries4kLoop
+
+ ;
+ ; Clear the encryption bit from the GHCB entry
+ ;
+ mov ecx, (GHCB_BASE & 0x1F_FFFF) >> 12
+ mov [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0
+
+ mov ecx, GHCB_SIZE / 4
+ xor eax, eax
+clearGhcbMemoryLoop:
+ mov dword[ecx * 4 + GHCB_BASE - 4], eax
+ loop clearGhcbMemoryLoop
+
+ OneTimeCallRet SevBuildGhcbPageTables
+
;
; Modified: EAX, EBX, ECX, EDX
;
SetCr3ForPageTables64:

+ cmp byte[CC_WORK_AREA], VM_GUEST_TDX
+ jne CheckSev
+
+ cmp byte[TDX_WORK_AREA_PGTBL_READY], 1
+ je SetCr3
+
+ xor edx, edx
+ jmp SevNotActive
+
+CheckSev:
OneTimeCall CheckSevFeatures
xor edx, edx
test eax, eax
@@ -101,44 +171,19 @@ pageTableEntriesLoop:
mov [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
loop pageTableEntriesLoop

+ OneTimeCall IsTdxEnabled
+ test eax, eax
+ jz IsSevEs
+
+ OneTimeCall TdxBuildExtraPageTables
+ jmp SetCr3
+
+IsSevEs:
OneTimeCall IsSevEsEnabled
test eax, eax
jz SetCr3

- ;
- ; The initial GHCB will live at GHCB_BASE and needs to be un-encrypted.
- ; This requires the 2MB page for this range be broken down into 512 4KB
- ; pages. All will be marked encrypted, except for the GHCB.
- ;
- mov ecx, (GHCB_BASE >> 21)
- mov eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
- mov [ecx * 8 + PT_ADDR (0x2000)], eax
-
- ;
- ; Page Table Entries (512 * 4KB entries => 2MB)
- ;
- mov ecx, 512
-pageTableEntries4kLoop:
- mov eax, ecx
- dec eax
- shl eax, 12
- add eax, GHCB_BASE & 0xFFE0_0000
- add eax, PAGE_4K_PDE_ATTR
- mov [ecx * 8 + GHCB_PT_ADDR - 8], eax
- mov [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx
- loop pageTableEntries4kLoop
-
- ;
- ; Clear the encryption bit from the GHCB entry
- ;
- mov ecx, (GHCB_BASE & 0x1F_FFFF) >> 12
- mov [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0
-
- mov ecx, GHCB_SIZE / 4
- xor eax, eax
-clearGhcbMemoryLoop:
- mov dword[ecx * 4 + GHCB_BASE - 4], eax
- loop clearGhcbMemoryLoop
+ OneTimeCall SevBuildGhcbPageTables

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

[Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase
+ gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaSize
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
@@ -43,6 +44,15 @@
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfImageSizeInKb
+ gUefiOvmfPkgTokenSpaceGuid.PcdCfvBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataOffset
+ gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdBfvBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataOffset
+ gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataSize

[FixedPcd]
gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretBase
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index acec46a32450..528a6603a20e 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -67,6 +67,44 @@
%error "This implementation inherently depends on PcdOvmfSecGhcbBase not straddling a 2MB boundary"
%endif

+ %define TDX_BFV_RAW_DATA_OFFSET FixedPcdGet32 (PcdBfvRawDataOffset)
+ %define TDX_BFV_RAW_DATA_SIZE FixedPcdGet32 (PcdBfvRawDataSize)
+ %define TDX_BFV_MEMORY_BASE FixedPcdGet32 (PcdBfvBase)
+ %define TDX_BFV_MEMORY_SIZE FixedPcdGet32 (PcdBfvRawDataSize)
+
+ %define TDX_CFV_RAW_DATA_OFFSET FixedPcdGet32 (PcdCfvRawDataOffset)
+ %define TDX_CFV_RAW_DATA_SIZE FixedPcdGet32 (PcdCfvRawDataSize)
+ %define TDX_CFV_MEMORY_BASE FixedPcdGet32 (PcdCfvBase),
+ %define TDX_CFV_MEMORY_SIZE FixedPcdGet32 (PcdCfvRawDataSize),
+
+ %define TDX_HEAP_MEMORY_BASE FixedPcdGet32 (PcdOvmfSecPeiTempRamBase)
+ %define TDX_HEAP_MEMORY_SIZE FixedPcdGet32 (PcdOvmfSecPeiTempRamSize) / 2
+
+ %define TDX_STACK_MEMORY_BASE (TDX_HEAP_MEMORY_BASE + TDX_HEAP_MEMORY_SIZE)
+ %define TDX_STACK_MEMORY_SIZE FixedPcdGet32 (PcdOvmfSecPeiTempRamSize) / 2
+
+ %define TDX_HOB_MEMORY_BASE FixedPcdGet32 (PcdOvmfSecGhcbBase)
+ %define TDX_HOB_MEMORY_SIZE FixedPcdGet32 (PcdOvmfSecGhcbSize)
+
+ %define TDX_MAILBOX_MEMORY_BASE FixedPcdGet32 (PcdOvmfSecGhcbBackupBase)
+ %define TDX_MAILBOX_MEMORY_SIZE FixedPcdGet32 (PcdOvmfSecGhcbBackupSize)
+
+ %define OVMF_PAGE_TABLE_BASE FixedPcdGet32 (PcdOvmfSecPageTablesBase)
+ %define OVMF_PAGE_TABLE_SIZE FixedPcdGet32 (PcdOvmfSecPageTablesSize)
+
+ %define TDX_EXTRA_PAGE_TABLE_BASE FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase)
+ %define TDX_EXTRA_PAGE_TABLE_SIZE FixedPcdGet32 (PcdOvmfSecGhcbPageTableSize)
+
+ %define CC_WORK_AREA_MEMORY_BASE FixedPcdGet32 (PcdSevEsWorkAreaBase)
+ %define CC_WORK_AREA_MEMORY_SIZE FixedPcdGet32 (PcdSevEsWorkAreaSize)
+ %define CC_WORK_AREA (CC_WORK_AREA_MEMORY_BASE)
+ %define CC_WORK_AREA_SUBTYPE (CC_WORK_AREA + 1)
+ %define TDX_WORK_AREA_PAGELEVEL5 (CC_WORK_AREA + 4)
+ %define TDX_WORK_AREA_PGTBL_READY (CC_WORK_AREA + 5)
+ %define TDX_WORK_AREA_GPAW (CC_WORK_AREA + 8)
+
+ %define TDX_PT_ADDR(Offset) (TDX_EXTRA_PAGE_TABLE_BASE + (Offset))
+
%define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))

%define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
@@ -76,9 +114,12 @@
%define SEV_ES_WORK_AREA_RDRAND (FixedPcdGet32 (PcdSevEsWorkAreaBase) + 8)
%define SEV_ES_WORK_AREA_ENC_MASK (FixedPcdGet32 (PcdSevEsWorkAreaBase) + 16)
%define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
-%include "Ia32/Flat32ToFlat64.asm"
-%include "Ia32/AmdSev.asm"
-%include "Ia32/PageTables64.asm"
+
+ %include "X64/IntelTdxMetadata.asm"
+ %include "Ia32/IntelTdx.asm"
+ %include "Ia32/Flat32ToFlat64.asm"
+ %include "Ia32/AmdSev.asm"
+ %include "Ia32/PageTables64.asm"
%endif

%include "Ia16/Real16ToFlat32.asm"
@@ -91,5 +132,6 @@
%define SEV_LAUNCH_SECRET_SIZE FixedPcdGet32 (PcdSevLaunchSecretSize)
%define SEV_FW_HASH_BLOCK_BASE FixedPcdGet32 (PcdQemuHashTableBase)
%define SEV_FW_HASH_BLOCK_SIZE FixedPcdGet32 (PcdQemuHashTableSize)
+ %define OVMF_IMAGE_SIZE_IN_KB FixedPcdGet32 (PcdOvmfImageSizeInKb)
%include "Ia16/ResetVectorVtf0.asm"

diff --git a/OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm b/OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm
new file mode 100644
index 000000000000..97b1e915d899
--- /dev/null
+++ b/OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm
@@ -0,0 +1,110 @@
+;------------------------------------------------------------------------------
+; @file
+; Tdx Virtual Firmware metadata
+;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+BITS 64
+
+%define TDX_METADATA_SECTION_TYPE_BFV 0
+%define TDX_METADATA_SECTION_TYPE_CFV 1
+%define TDX_METADATA_SECTION_TYPE_TD_HOB 2
+%define TDX_METADATA_SECTION_TYPE_TEMP_MEM 3
+%define TDX_METADATA_VERSION 1
+%define TDX_METADATA_ATTRIBUTES_EXTENDMR 0x00000001
+
+ALIGN 16
+TIMES (15 - ((TdxGuidedStructureEnd - TdxGuidedStructureStart + 15) % 16)) DB 0
+
+TdxGuidedStructureStart:
+
+;
+; TDVF meta data
+;
+TdxMetadataGuid:
+ DB 0xf3, 0xf9, 0xea, 0xe9, 0x8e, 0x16, 0xd5, 0x44
+ DB 0xa8, 0xeb, 0x7f, 0x4d, 0x87, 0x38, 0xf6, 0xae
+
+_Descriptor:
+ DB 'T','D','V','F' ; Signature
+ DD TdxGuidedStructureEnd - _Descriptor ; Length
+ DD TDX_METADATA_VERSION ; Version
+ DD (TdxGuidedStructureEnd - _Descriptor - 16)/32 ; Number of sections
+
+_Bfv:
+ DD TDX_BFV_RAW_DATA_OFFSET
+ DD TDX_BFV_RAW_DATA_SIZE
+ DQ TDX_BFV_MEMORY_BASE
+ DQ TDX_BFV_MEMORY_SIZE
+ DD TDX_METADATA_SECTION_TYPE_BFV
+ DD TDX_METADATA_ATTRIBUTES_EXTENDMR
+
+_Cfv:
+ DD TDX_CFV_RAW_DATA_OFFSET
+ DD TDX_CFV_RAW_DATA_SIZE
+ DQ TDX_CFV_MEMORY_BASE
+ DQ TDX_CFV_MEMORY_SIZE
+ DD TDX_METADATA_SECTION_TYPE_CFV
+ DD 0
+
+_Stack:
+ DD 0
+ DD 0
+ DQ TDX_STACK_MEMORY_BASE
+ DQ TDX_STACK_MEMORY_SIZE
+ DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
+ DD 0
+
+_Heap:
+ DD 0
+ DD 0
+ DQ TDX_HEAP_MEMORY_BASE
+ DQ TDX_HEAP_MEMORY_SIZE
+ DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
+ DD 0
+
+_MailBox:
+ DD 0
+ DD 0
+ DQ TDX_MAILBOX_MEMORY_BASE
+ DQ TDX_MAILBOX_MEMORY_SIZE
+ DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
+ DD 0
+
+_CcWorkarea:
+ DD 0
+ DD 0
+ DQ CC_WORK_AREA_MEMORY_BASE
+ DQ CC_WORK_AREA_MEMORY_SIZE
+ DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
+ DD 0
+
+_TdHob:
+ DD 0
+ DD 0
+ DQ TDX_HOB_MEMORY_BASE
+ DQ TDX_HOB_MEMORY_SIZE
+ DD TDX_METADATA_SECTION_TYPE_TD_HOB
+ DD 0
+
+_TdxPageTable:
+ DD 0
+ DD 0
+ DQ TDX_EXTRA_PAGE_TABLE_BASE
+ DQ TDX_EXTRA_PAGE_TABLE_SIZE
+ DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
+ DD 0
+
+_OvmfPageTable:
+ DD 0
+ DD 0
+ DQ OVMF_PAGE_TABLE_BASE
+ DQ OVMF_PAGE_TABLE_SIZE
+ DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
+ DD 0
+
+TdxGuidedStructureEnd:
+ALIGN 16
--
2.29.2.windows.2


[PATCH 02/23] OvmfPkg/Sec: Update the check logic in SevEsIsEnabled

Min Xu
 

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

SevEsIsEnabled return TRUE if SevEsWorkArea->SevEsEnabled is non-zero.
It is correct when SevEsWorkArea is only used by SEV. After Intel TDX
is enabled in Ovmf, the SevEsWorkArea is shared by TDX and SEV. (This
is to avoid the waist of memory region in MEMFD). The value of
SevEsWorkArea->SevEsEnabled now is :
0 if in Legacy guest
1 if in SEV
2 if in Tdx guest
That's why the changes is made.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/Sec/SecMain.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 9db67e17b2aa..e166a9389a1a 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -828,7 +828,7 @@ SevEsIsEnabled (

SevEsWorkArea = (SEC_SEV_ES_WORK_AREA *) FixedPcdGet32 (PcdSevEsWorkAreaBase);

- return ((SevEsWorkArea != NULL) && (SevEsWorkArea->SevEsEnabled != 0));
+ return ((SevEsWorkArea != NULL) && (SevEsWorkArea->SevEsEnabled == 1));
}

VOID
--
2.29.2.windows.2


[PATCH 01/23] OvmfPkg: Add Tdx BFV/CFV PCDs and PcdOvmfImageSizeInKb

Min Xu
 

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

Tdx Virtual Firmware (TDVF) includes one Firmware Volume (FV) known
as the Boot Firmware Volume (BFV). The FV format is defined in the
UEFI Platform Initialization (PI) spec. BFV includes all TDVF components
required during boot.

TDVF also include a configuration firmware volume (CFV) that is separated
from the BFV. The reason is because the CFV is measured in RTMR, while
the BFV is measured in MRTD.

In practice BFV is the code part of Ovmf image. CFV is the vars part of
Ovmf image (exclude the SPARE part).

PcdOvmfImageSizeInKb is added which is used to calculate the offset
of TdxMetadata in ResetVectorVtf0.asm.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
OvmfPkg/OvmfPkg.dec | 13 +++++++++++++
OvmfPkg/OvmfPkgDefines.fdf.inc | 10 ++++++++++
2 files changed, 23 insertions(+)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 8fb6f257e8e8..ccda130f0ef6 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -329,6 +329,19 @@
gUefiOvmfPkgTokenSpaceGuid.PcdQemuHashTableBase|0x0|UINT32|0x47
gUefiOvmfPkgTokenSpaceGuid.PcdQemuHashTableSize|0x0|UINT32|0x48

+ ## The base address and size of the TDX Cfv base and size.
+ gUefiOvmfPkgTokenSpaceGuid.PcdCfvBase|0|UINT32|0x49
+ gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataOffset|0|UINT32|0x4a
+ gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize|0|UINT32|0x4b
+
+ ## The base address and size of the TDX Bfv base and size.
+ gUefiOvmfPkgTokenSpaceGuid.PcdBfvBase|0|UINT32|0x4c
+ gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataOffset|0|UINT32|0x4d
+ gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataSize|0|UINT32|0x4e
+
+ ## Size of the Ovmf image in KB
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfImageSizeInKb|0|UINT32|0x4f
+
[PcdsDynamic, PcdsDynamicEx]
gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/OvmfPkgDefines.fdf.inc b/OvmfPkg/OvmfPkgDefines.fdf.inc
index 35fd454b97ab..777b7755b198 100644
--- a/OvmfPkg/OvmfPkgDefines.fdf.inc
+++ b/OvmfPkg/OvmfPkgDefines.fdf.inc
@@ -9,6 +9,7 @@
##

DEFINE BLOCK_SIZE = 0x1000
+DEFINE VARS_OFFSET = 0

#
# A firmware binary built with FD_SIZE_IN_KB=1024, and a firmware binary built
@@ -66,6 +67,7 @@ DEFINE SECFV_OFFSET = 0x003CC000
DEFINE SECFV_SIZE = 0x34000
!endif

+SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfImageSizeInKb = $(FD_SIZE_IN_KB)
SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress = $(FW_BASE_ADDRESS)
SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareFdSize = $(FW_SIZE)
SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareBlockSize = $(BLOCK_SIZE)
@@ -82,6 +84,14 @@ SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize = $(BLOCK_SIZ
SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwSpareBase = gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwWorkingBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize = $(VARS_SPARE_SIZE)

+SET gUefiOvmfPkgTokenSpaceGuid.PcdCfvBase = $(FW_BASE_ADDRESS)
+SET gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataOffset = $(VARS_OFFSET)
+SET gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize = $(VARS_LIVE_SIZE)
+
+SET gUefiOvmfPkgTokenSpaceGuid.PcdBfvBase = $(CODE_BASE_ADDRESS)
+SET gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataOffset = $(VARS_SIZE)
+SET gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataSize = $(CODE_SIZE)
+
!if $(SMM_REQUIRE) == TRUE
SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 = gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageVariableBase
SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase = gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwWorkingBase
--
2.29.2.windows.2


[PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI)

Min Xu
 

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.

The patch-sets to support Intel TDX in OvmfPkg is split into several
waves. This is Wave-2 which enables Intel TDX in SEC/PEI phases of
OvmfPkgX64. (This is because Intel TDX is only available on X64).

Note:
As mentioned above the whole TDX Virtual Firmware upstream to EDK2 is
splitted into several waves. Wave-1 is focused on the changes in
OvmfPkg/ResetVector. It is still in review. (Hope we can finish it soon).
Wave-2 is focused on the changes in SEC/PEI phases. To make the review
more efficient we send Wave-2 before the review of Wave-1 is finished.
Wave-2 has little dependencies on Wave-1 except some PCDs definitions.
So reviewers can skip Patch 01-03. Once Wave-1 is done, Wave-2 will be
rebased on the latest code base. Thanks for your understanding.

Patch 01-03 are the patches of Wave-1 (ResetVector phase). They can be
skipped.

Patch 04 - 18 are changes in SEC phase. Also some libraries in these patches
are workable in both SEC and PEI.

Patch 19 - 23 are changes for PEI phase.

Patch 04:
Tdx.h is added in the patch which 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

Patch 05:
It provides *TdxIsEnabled* to determine Td or Non-Td by a new CPUID
leaf(0x21).

Patch 06:
TdxLib is provided in this patch to wrap the functions which perform the
related Tdx operation.

Patch 07:
TDVF chooses para-virtualized I/O which use the TDG.VP.VMCALL function
to invoke the funtions provided by the host VMM to perform I/O.
BaseIoLibIntrinsicSev.inf is updated to support the I/O in Tdx guest.
Some null stub are also added in BaseIoLibIntrinsic.inf to prevent the
broken of build process.

Patch 08:
In this patch BaseXApicX2ApicLib is updated to support Intel TDX. The
major change is access to MSR because some MSR should be accessed via
explicit requests from the host VMM using TDCALL(TDG.VP.VMCALL).

Patch 09 - 12:
These patches add VmTdExitLib library and add base support to handle #VE
exceptions under the help of VmTdExitLib.

Patch 13:
This patch enable Tdx support in MpInitLib.

Patch 14:
In this patch 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.
They wait for command to see if the command is for me. If so execute
the command.

Patch 15:
IntelTdx.h is added to define the defitions used by TDX in OvmfPkg.

Patch 16:
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.

Patch 17:
In this patch EFI_RESOURCE_ATTRIBUTE_ENCRYPTED is added which indicates
the attribute of Physical memory encrypted.

Patch 18:
Now we're ready to update SecMain.c to support Intel TDX. The major
changes of this patch is to accept the private memory described in
Td hoblist. Then TDVF follow the standard OVMF flow and jump to PEI
phase.

Patch 19:
This patch checks Tdx in QemuFwCfgPei to avoid DMA operation. 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).

Patch 20:
A new function - AllocatePagesWithMemoryType - is added in
PeiMemoryAllocationLib. This is because when doing RelocateMailbox,
the memory of ACPI Nvs need be allocated.

Patch 21:
PcdUse1GPageTable is set to FALSE by default in OvmfPkgX64.dsc. It gives
no chance to support 1G page table. To support 1G page table in TDX this
PCD is set to TRUE in OvmfPkgX64.dsc.

Patch 22:
In TDX IA32_ERER is RO to host VMM. It could not be changed. A new PCD -
PcdIa32EferChangeAllowed - is added in MdeModulePkg.dec and it will be
set to FALSE in Tdx guest.

Patch 23:
Intel TDX has its own requirement in InitializePlatform (PlatformPei).
- Publish the ram region
- Relocate mailbox
- Create PlatformInfoHob

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

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

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

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>

Min Xu (23):
OvmfPkg: Add Tdx BFV/CFV PCDs and PcdOvmfImageSizeInKb
OvmfPkg/Sec: Update the check logic in SevEsIsEnabled
OvmfPkg/ResetVector: Enable Intel TDX in ResetVector of Ovmf
MdePkg: Add Tdx.h
MdePkg: Add TdxProbeLib to probe Intel Tdx
MdePkg: Add TdxLib to wrap Tdx operations
MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
UefiCpuPkg: Add VmTdExitLibNull
OvmfPkg: Prepare OvmfPkg to use the VmTdExitLib library
OvmfPkg: Implement library support for VmTdExitLib in Ovmf
UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
UefiCpuPkg: Enable Tdx support in MpInitLib
OvmfPkg: Update SecEntry.nasm to support Tdx
OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
OvmfPkg: Add TdxMailboxLib
MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h
OvmfPkg: Enable Tdx in SecMain.c
OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
MdePkg: Add AllocatePagesWithMemoryType support in
PeiMemoryAllocationLib
OvmfPkg: Add PcdUse1GPageTable support for TDX
MdeModulePkg: EFER should not be changed in TDX
OvmfPkg: Update PlatformPei to support TDX

MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf | 1 +
.../Core/DxeIplPeim/X64/VirtualMemory.c | 6 +
MdeModulePkg/MdeModulePkg.dec | 5 +
MdePkg/Include/IndustryStandard/Tdx.h | 200 +++++
MdePkg/Include/Library/MemoryAllocationLib.h | 21 +
MdePkg/Include/Library/TdxLib.h | 167 +++++
MdePkg/Include/Library/TdxProbeLib.h | 25 +
MdePkg/Include/Pi/PiHob.h | 8 +
.../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf | 2 +
.../BaseIoLibIntrinsicSev.inf | 6 +-
MdePkg/Library/BaseIoLibIntrinsic/IoLib.c | 97 ++-
MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c | 49 +-
.../BaseIoLibIntrinsic/IoLibInternalTdx.c | 690 ++++++++++++++++++
.../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 499 +++++++++++++
MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c | 73 +-
MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h | 411 +++++++++++
.../BaseIoLibIntrinsic/X64/IoFifoSev.nasm | 133 ++++
.../MemoryAllocationLib.c | 27 +
MdePkg/Library/TdxLib/AcceptPages.c | 136 ++++
MdePkg/Library/TdxLib/Rtmr.c | 118 +++
MdePkg/Library/TdxLib/TdInfo.c | 101 +++
MdePkg/Library/TdxLib/TdxLib.inf | 39 +
MdePkg/Library/TdxLib/TdxLibNull.c | 192 +++++
MdePkg/Library/TdxLib/X64/Tdcall.nasm | 120 +++
MdePkg/Library/TdxLib/X64/Tdvmcall.nasm | 206 ++++++
MdePkg/Library/TdxProbeLib/InternalTdxProbe.h | 25 +
MdePkg/Library/TdxProbeLib/TdProbeNull.c | 25 +
MdePkg/Library/TdxProbeLib/TdxProbeLib.c | 35 +
MdePkg/Library/TdxProbeLib/TdxProbeLib.inf | 34 +
MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm | 97 +++
MdePkg/MdePkg.dec | 6 +
MdePkg/MdePkg.dsc | 2 +
OvmfPkg/Include/IndustryStandard/IntelTdx.h | 77 ++
OvmfPkg/Include/Library/TdxMailboxLib.h | 75 ++
OvmfPkg/Include/TdxCommondefs.inc | 51 ++
OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c | 15 +
.../Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf | 1 +
OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c | 138 ++++
.../Library/TdxMailboxLib/TdxMailboxLib.inf | 52 ++
.../Library/TdxMailboxLib/TdxMailboxNull.c | 86 +++
OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf | 41 ++
.../Library/VmTdExitLib/VmTdExitVeHandler.c | 515 +++++++++++++
OvmfPkg/OvmfPkg.dec | 27 +
OvmfPkg/OvmfPkgDefines.fdf.inc | 10 +
OvmfPkg/OvmfPkgIa32.dsc | 4 +
OvmfPkg/OvmfPkgIa32X64.dsc | 4 +
OvmfPkg/OvmfPkgX64.dsc | 8 +
OvmfPkg/OvmfXen.dsc | 1 +
OvmfPkg/PlatformPei/FeatureControl.c | 9 +-
OvmfPkg/PlatformPei/IntelTdx.c | 268 +++++++
OvmfPkg/PlatformPei/IntelTdxNull.c | 35 +
OvmfPkg/PlatformPei/MemDetect.c | 20 +-
OvmfPkg/PlatformPei/Platform.c | 2 +
OvmfPkg/PlatformPei/Platform.h | 17 +
OvmfPkg/PlatformPei/PlatformPei.inf | 14 +
OvmfPkg/PlatformPei/X64/ApRunLoop.nasm | 83 +++
OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 39 +
OvmfPkg/ResetVector/Ia32/AmdSev.asm | 7 -
OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm | 9 +
OvmfPkg/ResetVector/Ia32/IntelTdx.asm | 265 +++++++
OvmfPkg/ResetVector/Ia32/PageTables64.asm | 113 ++-
OvmfPkg/ResetVector/Main.asm | 121 +++
OvmfPkg/ResetVector/ResetVector.inf | 12 +-
OvmfPkg/ResetVector/ResetVector.nasmb | 48 +-
OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm | 110 +++
OvmfPkg/Sec/IntelTdx.c | 608 +++++++++++++++
OvmfPkg/Sec/IntelTdx.h | 33 +
OvmfPkg/Sec/SecMain.c | 45 +-
OvmfPkg/Sec/SecMain.inf | 7 +
OvmfPkg/Sec/X64/SecEntry.nasm | 313 ++++++++
UefiCpuPkg/Include/Library/VmTdExitLib.h | 47 ++
.../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c | 172 ++++-
.../BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf | 2 +
.../DxeCpuExceptionHandlerLib.inf | 1 +
.../PeiCpuExceptionHandlerLib.inf | 1 +
.../PeiDxeSmmCpuException.c | 18 +
.../SecPeiCpuException.c | 19 +
.../SecPeiCpuExceptionHandlerLib.inf | 1 +
.../SmmCpuExceptionHandlerLib.inf | 1 +
.../Xcode5SecPeiCpuExceptionHandlerLib.inf | 1 +
UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 5 +
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 14 +-
UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h | 107 +++
UefiCpuPkg/Library/MpInitLib/MpLib.c | 26 +
UefiCpuPkg/Library/MpInitLib/MpLibTdx.c | 142 ++++
UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c | 117 +++
UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 5 +
.../Library/MpInitLib/X64/IntelTdcall.nasm | 120 +++
.../Library/VmTdExitLibNull/VmTdExitLibNull.c | 37 +
.../VmTdExitLibNull/VmTdExitLibNull.inf | 34 +
UefiCpuPkg/UefiCpuPkg.dec | 9 +
UefiCpuPkg/UefiCpuPkg.dsc | 4 +
92 files changed, 7610 insertions(+), 112 deletions(-)
create mode 100644 MdePkg/Include/IndustryStandard/Tdx.h
create mode 100644 MdePkg/Include/Library/TdxLib.h
create mode 100644 MdePkg/Include/Library/TdxProbeLib.h
create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.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
create mode 100644 MdePkg/Library/TdxLib/X64/Tdcall.nasm
create mode 100644 MdePkg/Library/TdxLib/X64/Tdvmcall.nasm
create mode 100644 MdePkg/Library/TdxProbeLib/InternalTdxProbe.h
create mode 100644 MdePkg/Library/TdxProbeLib/TdProbeNull.c
create mode 100644 MdePkg/Library/TdxProbeLib/TdxProbeLib.c
create mode 100644 MdePkg/Library/TdxProbeLib/TdxProbeLib.inf
create mode 100644 MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm
create mode 100644 OvmfPkg/Include/IndustryStandard/IntelTdx.h
create mode 100644 OvmfPkg/Include/Library/TdxMailboxLib.h
create mode 100644 OvmfPkg/Include/TdxCommondefs.inc
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/VmTdExitLib/VmTdExitLib.inf
create mode 100644 OvmfPkg/Library/VmTdExitLib/VmTdExitVeHandler.c
create mode 100644 OvmfPkg/PlatformPei/IntelTdx.c
create mode 100644 OvmfPkg/PlatformPei/IntelTdxNull.c
create mode 100644 OvmfPkg/PlatformPei/X64/ApRunLoop.nasm
create mode 100644 OvmfPkg/ResetVector/Ia32/IntelTdx.asm
create mode 100644 OvmfPkg/ResetVector/Main.asm
create mode 100644 OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm
create mode 100644 OvmfPkg/Sec/IntelTdx.c
create mode 100644 OvmfPkg/Sec/IntelTdx.h
create mode 100644 UefiCpuPkg/Include/Library/VmTdExitLib.h
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/MpInitLib/X64/IntelTdcall.nasm
create mode 100644 UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.c
create mode 100644 UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf

--
2.29.2.windows.2


Re: [PATCH] RedfishClientPkg/ConvertLib: Common code and header files

Nickle Wang
 

Looks like we miss function header in this patch...

Nickle

-----Original Message-----
From: Chang, Abner (HPS SW/FW Technologist) <abner.chang@hpe.com>
Sent: Thursday, August 12, 2021 2:08 PM
To: devel@edk2.groups.io
Cc: Wang, Nickle (HPS SW) <nickle.wang@hpe.com>; Liming Gao <gaoliming@byosoft.com.cn>
Subject: [PATCH] RedfishClientPkg/ConvertLib: Common code and header files

ConverterLib/ is the folder of script-generated JSON to C library for the each Redfish schema. The common code and header files in this patch are used by those libraries.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Cc: Nickle Wang <nickle.wang@hpe.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
---
.../ConverterLib/include/RedfishCsCommon.h | 122 +++
.../ConverterLib/include/RedfishDataTypeDef.h | 45 +
.../src/RedfishCsMemoryInternal.h | 36 +
.../ConverterLib/src/RedfishCsCommon.c | 831 ++++++++++++++++++
.../ConverterLib/src/RedfishCsMemory.c | 144 +++
5 files changed, 1178 insertions(+)
create mode 100644 RedfishClientPkg/ConverterLib/include/RedfishCsCommon.h
create mode 100644 RedfishClientPkg/ConverterLib/include/RedfishDataTypeDef.h
create mode 100644 RedfishClientPkg/ConverterLib/src/RedfishCsMemoryInternal.h
create mode 100644 RedfishClientPkg/ConverterLib/src/RedfishCsCommon.c
create mode 100644 RedfishClientPkg/ConverterLib/src/RedfishCsMemory.c

diff --git a/RedfishClientPkg/ConverterLib/include/RedfishCsCommon.h b/RedfishClientPkg/ConverterLib/include/RedfishCsCommon.h
new file mode 100644
index 0000000000..3810836123
--- /dev/null
+++ b/RedfishClientPkg/ConverterLib/include/RedfishCsCommon.h
@@ -0,0 +1,122 @@
+/** @file
+
+ (C) Copyright 2018-2021 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef REDFISH_CS_COMMON_H_
+#define REDFISH_CS_COMMON_H_
+
+#include "RedfishDataTypeDef.h"
+
+RedfishCS_Link * InitializeLinkHead (RedfishCS_Link *LinkHead);
+RedfishCS_Link * InsertHeadLink (RedfishCS_Link *ListHead,
+RedfishCS_Link *Entry); RedfishCS_Link * InsertTailLink (RedfishCS_Link
+*ListHead, RedfishCS_Link *Entry); RedfishCS_Link * GetFirstLink (const
+RedfishCS_Link *List); RedfishCS_Link * GetLastLink (const
+RedfishCS_Link *List); RedfishCS_Link * GetNextLink (const
+RedfishCS_Link *List, const RedfishCS_Link *Node); RedfishCS_Link *
+GetPreviousLink ( const RedfishCS_Link *List, const RedfishCS_Link
+*Node); RedfishCS_Link *RemoveLink ( const RedfishCS_Link *Link);
+RedfishCS_bool IsLinkEmpty (const RedfishCS_Link *LinkHead);
+RedfishCS_bool IsLinkAtEnd (const RedfishCS_Link *LinkHead, const
+RedfishCS_Link *ThisLink); RedfishCS_status recordCsRootMemory (void
+*memCs); RedfishCS_status allocateRecordCsMemory (RedfishCS_void
+*rootCs, RedfishCS_uint32 size, RedfishCS_void **Dst); RedfishCS_status
+allocateRecordCsZeroMemory (RedfishCS_void *rootCs, RedfishCS_uint32
+size, RedfishCS_void **Dst); RedfishCS_status
+allocateArrayRecordCsMemory(RedfishCS_void *rootCs, RedfishCS_uint32
+ArrayInstanceSize, RedfishCS_uint64 ArraySize, RedfishCS_void **Dst);
+RedfishCS_status allocateDuplicateStr (void *Cs, char *Str, void
+**DstBuffer); RedfishCS_status DestoryCsMemory (RedfishCS_void
+*rootCs);
+
+typedef struct _RedfishCS_char_Array RedfishCS_char_Array; typedef
+struct _RedfishCS_int64_Array RedfishCS_int64_Array; typedef struct
+_RedfishCS_bool_Array RedfishCS_bool_Array; typedef struct
+_RedfishCS_Link_Array RedfishCS_Link_Array; typedef struct
+_RedfishCS_EmptyProp_KeyValue RedfishCS_EmptyProp_KeyValue;
+
+typedef enum {
+ RedfishCS_Type_CS = 1,
+ RedfishCS_Type_CS_EmptyProp,
+ RedfishCS_Type_JSON,
+ RedfishCS_Type_Uri
+} RedfishCS_Type;
+
+typedef struct _RedfishCS_Header {
+ RedfishCS_Link LinkEntry;
+ RedfishCS_Type ResourceType;
+ RedfishCS_char *KeyName;
+ RedfishCS_char *ThisUri;
+} RedfishCS_Header;
+
+typedef struct _RedfishCS_Type_Uri_Data {
+ RedfishCS_Header Header;
+ RedfishCS_char *Uri;
+} RedfishCS_Type_Uri_Data;
+
+typedef struct _RedfishCS_Type_CS_Data {
+ RedfishCS_Header Header;
+ //
+ // Followed by C structure of resource.
+ //
+} RedfishCS_Type_CS_Data;
+
+typedef struct _RedfishCS_Type_JSON_Data {
+ RedfishCS_Header Header;
+ RedfishCS_char *JsonText;
+} RedfishCS_Type_JSON_Data;
+
+typedef struct _RedfishCS_Number {
+ RedfishCS_uint16 Value;
+ RedfishCS_uint16 MaxValue;
+ RedfishCS_uint16 MinValue;
+} RedfishCS_Number;
+
+typedef struct _RedfishCS_char_Array {
+ RedfishCS_char_Array *Next;
+ RedfishCS_char *ArrayValue;
+} RedfishCS_char_Array;
+
+typedef struct _RedfishCS_int64_Array {
+ RedfishCS_int64_Array *Next;
+ RedfishCS_int64 *ArrayValue;
+} RedfishCS_int64_Array;
+
+typedef struct _RedfishCS_bool_Array {
+ RedfishCS_bool_Array *Next;
+ RedfishCS_bool *ArrayValue;
+} RedfishCS_bool_Array;
+
+typedef struct _RedfishCS_Link_Array {
+ RedfishCS_Link_Array *Next;
+ RedfishCS_Link *ArrayValue;
+} RedfishCS_Link_Array;
+
+typedef enum {
+ RedfishCS_Vague_DataType_String = 1,
+ RedfishCS_Vague_DataType_Int64,
+ RedfishCS_Vague_DataType_Bool
+} RedfishCS_Vague_DataType;
+
+typedef union {
+ RedfishCS_char *CharPtr;
+ RedfishCS_bool *BoolPtr;
+ RedfishCS_int64 *Int64Ptr;
+} RedfishCS_Vague_Ptr;
+
+typedef struct _RedfishCS_Vague {
+ RedfishCS_Vague_DataType DataType;
+ RedfishCS_Vague_Ptr DataValue;
+} RedfishCS_Vague;
+
+typedef struct _RedfishCS_EmptyProp_KeyValue {
+ RedfishCS_EmptyProp_KeyValue *NextKeyValuePtr;
+ RedfishCS_char *KeyNamePtr;
+ RedfishCS_Vague *Value;
+} RedfishCS_EmptyProp_KeyValue;
+
+typedef struct _RedfishCS_Type_EmptyProp_CS_Data {
+ RedfishCS_Header Header;
+ RedfishCS_uint32 NunmOfProperties;
+ RedfishCS_EmptyProp_KeyValue *KeyValuePtr; }
+RedfishCS_Type_EmptyProp_CS_Data;
+
+#endif
diff --git a/RedfishClientPkg/ConverterLib/include/RedfishDataTypeDef.h b/RedfishClientPkg/ConverterLib/include/RedfishDataTypeDef.h
new file mode 100644
index 0000000000..8c903482aa
--- /dev/null
+++ b/RedfishClientPkg/ConverterLib/include/RedfishDataTypeDef.h
@@ -0,0 +1,45 @@
+/** @file
+
+ (C) Copyright 2018-2021 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef REDFISH_CS_DATA_TYPE_H_
+#define REDFISH_CS_DATA_TYPE_H_
+
+#include <jansson.h>
+
+typedef char RedfishCS_char;
+typedef int RedfishCS_bool;
+typedef signed char RedfishCS_int8;
+typedef unsigned char RedfishCS_uint8;
+typedef int RedfishCS_int16;
+typedef int RedfishCS_int;
+typedef unsigned int RedfishCS_uint16;
+typedef long int RedfishCS_int32;
+typedef unsigned long int RedfishCS_uint32;
+typedef long long RedfishCS_int64;
+typedef unsigned long long RedfishCS_uint64;
+typedef void RedfishCS_void;
+
+#define RedfishCS_boolean_false 0
+#define RedfishCS_boolean_true 1
+
+typedef RedfishCS_int64 RedfishCS_status;
+#define RedfishCS_status_success 0
+#define RedfishCS_status_unsupported -1
+#define RedfishCS_status_invalid_parameter -2
+#define RedfishCS_status_insufficient_memory -3
+#define RedfishCS_status_not_found -4
+#define RedfishCS_status_unknown_error -5
+
+typedef struct _RedfishCS_Link RedfishCS_Link; struct _RedfishCS_Link {
+ RedfishCS_Link *BackLink;
+ RedfishCS_Link *ForwardLink;
+};
+
+#endif
+
+
diff --git a/RedfishClientPkg/ConverterLib/src/RedfishCsMemoryInternal.h b/RedfishClientPkg/ConverterLib/src/RedfishCsMemoryInternal.h
new file mode 100644
index 0000000000..689aff9519
--- /dev/null
+++ b/RedfishClientPkg/ConverterLib/src/RedfishCsMemoryInternal.h
@@ -0,0 +1,36 @@
+/** @file
+
+ (C) Copyright 2018-2021 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef
+REDFISH_CS_MEMORY_INTERNAL_H_ #define REDFISH_CS_MEMORY_INTERNAL_H_
+
+#include "RedfishDataTypeDef.h"
+
+RedfishCS_Link * InitializeLinkHead (RedfishCS_Link *LinkHead);
+RedfishCS_Link * InsertHeadLink (RedfishCS_Link *ListHead,
+RedfishCS_Link *Entry); RedfishCS_Link * InsertTailLink (RedfishCS_Link
+*ListHead, RedfishCS_Link *Entry); RedfishCS_Link * GetFirstLink (const
+RedfishCS_Link *List); RedfishCS_Link * GetLastLink (const
+RedfishCS_Link *List); RedfishCS_Link * GetNextLink (const
+RedfishCS_Link *List, const RedfishCS_Link *Node); RedfishCS_Link *
+GetPreviousLink ( const RedfishCS_Link *List, const RedfishCS_Link
+*Node); RedfishCS_Link *RemoveLink ( const RedfishCS_Link *Link);
+RedfishCS_bool IsLinkEmpty (const RedfishCS_Link *LinkHead);
+RedfishCS_bool IsLinkAtEnd (const RedfishCS_Link *LinkHead, const
+RedfishCS_Link *ThisLink);
+
+typedef struct _RedfishCS_Internal_memory_link {
+ RedfishCS_Link nextLink;
+ void *memoryPtr;
+} RedfishCS_Internal_memory_link;
+
+typedef struct _RedfishCS_Internal_memory_root {
+ RedfishCS_Link nextRoot;
+ RedfishCS_Link memBlocks;
+ void *CsPtr;
+} RedfishCS_Internal_memory_root;
+
+#endif
+
+
diff --git a/RedfishClientPkg/ConverterLib/src/RedfishCsCommon.c b/RedfishClientPkg/ConverterLib/src/RedfishCsCommon.c
new file mode 100644
index 0000000000..cb80121831
--- /dev/null
+++ b/RedfishClientPkg/ConverterLib/src/RedfishCsCommon.c
@@ -0,0 +1,831 @@
+/** @file
+
+ (C) Copyright 2018-2021 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishCsCommon.h"
+#include "RedfishCsMemoryInternal.h"
+#include <jansson.h>
+#include <stdlib.h>
+#include <string.h>
+
+RedfishCS_status GetRedfishPropertyVague(void *Cs, json_t *JsonObj,
+char *Key, RedfishCS_Vague **DstBuffer);
+
+RedfishCS_Link *InitializeLinkHead (RedfishCS_Link *ListHead) {
+ ListHead->ForwardLink = ListHead;
+ ListHead->BackLink = ListHead;
+ return ListHead;
+}
+
+RedfishCS_Link *InsertHeadLink (RedfishCS_Link *ListHead,
+RedfishCS_Link *Entry) {
+ Entry->ForwardLink = ListHead->ForwardLink;
+ Entry->BackLink = ListHead;
+ Entry->ForwardLink->BackLink = Entry;
+ ListHead->ForwardLink = Entry;
+ return ListHead;
+}
+
+RedfishCS_Link * InsertTailLink (RedfishCS_Link *ListHead,
+RedfishCS_Link *Entry) {
+ Entry->ForwardLink = ListHead;
+ Entry->BackLink = ListHead->BackLink;
+ Entry->BackLink->ForwardLink = Entry;
+ ListHead->BackLink = Entry;
+ return ListHead;
+}
+
+RedfishCS_Link *GetFirstLink (const RedfishCS_Link *List) {
+ return List->ForwardLink;
+}
+
+RedfishCS_Link *GetLastLink (const RedfishCS_Link *List) {
+ return List->BackLink;
+}
+
+RedfishCS_Link *GetNextLink (const RedfishCS_Link *List, const
+RedfishCS_Link *Node) {
+ return Node->ForwardLink;
+}
+
+RedfishCS_Link *GetPreviousLink (const RedfishCS_Link *List, const
+RedfishCS_Link *Node) {
+ return Node->BackLink;
+}
+RedfishCS_Link *RemoveLink ( const RedfishCS_Link *Link) {
+ Link->ForwardLink->BackLink = Link->BackLink;
+ Link->BackLink->ForwardLink = Link->ForwardLink;
+ return Link->ForwardLink;
+}
+
+RedfishCS_bool IsLinkEmpty (const RedfishCS_Link *LinkHead) { return
+(RedfishCS_bool)(LinkHead->ForwardLink == LinkHead); }
+
+RedfishCS_bool IsLinkAtEnd (const RedfishCS_Link *LinkHead, const
+RedfishCS_Link *ThisLink) {
+ return (RedfishCS_bool)(ThisLink->ForwardLink == LinkHead); }
+
+RedfishCS_status allocateDuplicateStr (void *Cs, char *Str, void
+**DstBuffer) {
+ RedfishCS_status Status;
+
+ if (Str == NULL || strlen(Str) == 0) {
+ *DstBuffer = NULL;
+ return RedfishCS_status_success;
+ }
+ Status = allocateRecordCsMemory(Cs, (RedfishCS_int)strlen(Str) + 1,
+(void **)DstBuffer);
+ if (Status != RedfishCS_status_success) {
+ return Status;
+ }
+ memcpy (*DstBuffer, Str, strlen(Str) + 1);
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status CreateCsUriByOdataId (json_t *JsonOj, RedfishCS_char
+*ParentUri, RedfishCS_Type_Uri_Data **CsTypeUriData) {
+ json_t *TempJsonObj;
+ RedfishCS_Type_Uri_Data *CsTypeUri;
+
+ CsTypeUri = NULL;
+ TempJsonObj = json_object_get(JsonOj, "@odata.id");
+ if (TempJsonObj == NULL) {
+ return RedfishCS_status_not_found;
+ }
+ CsTypeUri = malloc (sizeof (RedfishCS_Type_Uri_Data));
+ if (CsTypeUri == NULL) {
+ return RedfishCS_status_insufficient_memory;
+ }
+ InitializeLinkHead (&CsTypeUri->Header.LinkEntry);
+ CsTypeUri->Header.ResourceType = RedfishCS_Type_Uri;
+ CsTypeUri->Header.ThisUri = ParentUri;
+ CsTypeUri->Header.KeyName = (RedfishCS_char *)strdup ("@odata.id");
+ CsTypeUri->Uri = (RedfishCS_char *)strdup (json_string_value
+(TempJsonObj));
+ *CsTypeUriData = CsTypeUri;
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status CreateCsUriByNode (void *Cs, json_t *JsonOj,
+RedfishCS_char *NodeName, RedfishCS_char *ParentUri,
+RedfishCS_Type_Uri_Data **CsTypeUriData) {
+ json_t *TempJsonObj;
+ json_t *TempJsonObj2;
+ RedfishCS_Type_Uri_Data *CsTypeUri;
+ RedfishCS_status Status;
+
+ CsTypeUri = NULL;
+
+ if (NodeName != NULL) {
+ TempJsonObj = json_object_get(JsonOj, NodeName);
+ if (TempJsonObj == NULL) {
+ return RedfishCS_status_not_found;
+ }
+ } else {
+ if (JsonOj == NULL) {
+ return RedfishCS_status_not_found;
+ }
+ TempJsonObj = JsonOj;
+ }
+
+ TempJsonObj2 = json_object_get(TempJsonObj, "@odata.id");
+ if (TempJsonObj2 != NULL) {
+ Status = allocateRecordCsMemory (Cs, sizeof (RedfishCS_Type_Uri_Data), (void **)&CsTypeUri);
+ if (Status != RedfishCS_status_success) {
+ return Status;
+ }
+ InitializeLinkHead (&CsTypeUri->Header.LinkEntry);
+ CsTypeUri->Header.ResourceType = RedfishCS_Type_Uri;
+ CsTypeUri->Header.ThisUri = ParentUri;
+ Status = allocateDuplicateStr (Cs, NodeName, (void **)&CsTypeUri->Header.KeyName);
+ if (Status != RedfishCS_status_success) {
+ return Status;
+ }
+ *CsTypeUriData = CsTypeUri;
+ Status = allocateDuplicateStr (Cs, (char *)json_string_value (TempJsonObj2), (void **)&CsTypeUri->Uri);
+ return Status;
+ }
+ return RedfishCS_status_invalid_parameter;
+}
+
+RedfishCS_status CreateCsJsonByNode (void *Cs, json_t *JsonObj,
+RedfishCS_char *NodeName, RedfishCS_char *ParentUri,
+RedfishCS_Type_JSON_Data **CsTypeJsonData) {
+ json_t *TempJsonObj;
+ RedfishCS_Type_JSON_Data *CsTypeJson;
+ RedfishCS_char *TempChar;
+ RedfishCS_char *DumpStr;
+ RedfishCS_status Status;
+
+ CsTypeJson = NULL;
+ if (NodeName != NULL) {
+ TempJsonObj = json_object_get(JsonObj, NodeName);
+ if (TempJsonObj == NULL) {
+ return RedfishCS_status_not_found;
+ }
+ } else {
+ // Dump JSON from JsonObj.
+ TempJsonObj = JsonObj;
+ }
+ TempChar = json_dumps ((const json_t *)TempJsonObj, JSON_INDENT (2));
+ if (TempChar != NULL) {
+ Status = allocateRecordCsMemory (Cs, sizeof (RedfishCS_Type_JSON_Data), (void **)&CsTypeJson);
+ if (Status != RedfishCS_status_success) {
+ return Status;
+ }
+ Status = allocateRecordCsMemory (Cs, (RedfishCS_int)strlen (TempChar) + 1, (void **)&DumpStr);
+ if (Status != RedfishCS_status_success) {
+ return Status;
+ }
+ strncpy (DumpStr, TempChar, strlen (TempChar) + 1);
+ InitializeLinkHead(&CsTypeJson->Header.LinkEntry);
+ CsTypeJson->Header.ResourceType = RedfishCS_Type_JSON;
+ CsTypeJson->Header.ThisUri = ParentUri;
+ Status = allocateDuplicateStr (Cs, NodeName, (void **)&CsTypeJson->Header.KeyName);
+ if (Status != RedfishCS_status_success) {
+ return Status;
+ }
+ CsTypeJson->JsonText = DumpStr;
+ *CsTypeJsonData = CsTypeJson;
+ return RedfishCS_status_success;
+ }
+ return RedfishCS_status_invalid_parameter;
+}
+
+RedfishCS_status CreateEmptyPropCsJson(RedfishCS_void *Cs, json_t
+*JsonObj, RedfishCS_char *NodeName, RedfishCS_char *ParentUri,
+RedfishCS_Type_EmptyProp_CS_Data **CsTypeEmptyPropCSData,
+RedfishCS_uint32 NunmOfProperties) {
+ json_t *TempJsonObj;
+ RedfishCS_status Status;
+ RedfishCS_Type_EmptyProp_CS_Data *CsTypeEmptyPropCS;
+ RedfishCS_char *KeyName;
+ json_t *KeyValueObj;
+ RedfishCS_void *n;
+ RedfishCS_EmptyProp_KeyValue **KeyValuePtr;
+ RedfishCS_EmptyProp_KeyValue *KeyValue;
+
+ CsTypeEmptyPropCS = NULL;
+ if (NodeName != NULL) {
+ TempJsonObj = json_object_get(JsonObj, NodeName);
+ if (TempJsonObj == NULL) {
+ return RedfishCS_status_not_found;
+ }
+ }
+ Status = allocateRecordCsMemory(Cs,
+ sizeof(RedfishCS_Type_EmptyProp_CS_Data), (void **)&CsTypeEmptyPropCS); if (Status != RedfishCS_status_success) {
+ return Status;
+ }
+ InitializeLinkHead(&CsTypeEmptyPropCS->Header.LinkEntry);
+ CsTypeEmptyPropCS->Header.ResourceType = RedfishCS_Type_CS_EmptyProp;
+ CsTypeEmptyPropCS->Header.ThisUri = ParentUri; Status =
+ allocateDuplicateStr(Cs, NodeName, (void
+ **)&CsTypeEmptyPropCS->Header.KeyName);
+ if (Status != RedfishCS_status_success) {
+ return Status;
+ }
+ CsTypeEmptyPropCS->NunmOfProperties = NunmOfProperties; // //
+ Create instance for each key-value.
+ //
+ KeyValuePtr = &CsTypeEmptyPropCS->KeyValuePtr;
+ json_object_foreach_safe(TempJsonObj, n, KeyName, KeyValueObj) {
+ Status = allocateRecordCsMemory(Cs, sizeof(RedfishCS_EmptyProp_KeyValue), (void **)&KeyValue);
+ if (Status != RedfishCS_status_success) {
+ return Status;
+ }
+ Status = allocateDuplicateStr(Cs, (char *)KeyName, (void **)&KeyValue->KeyNamePtr);
+ if (Status != RedfishCS_status_success) {
+ return Status;
+ }
+ Status = GetRedfishPropertyVague(Cs, TempJsonObj, (char *)KeyName, &KeyValue->Value);
+ if (Status != RedfishCS_status_success) {
+ return Status;
+ }
+
+ *KeyValuePtr = KeyValue;
+ KeyValuePtr = &KeyValue->NextKeyValuePtr; }
+
+ *CsTypeEmptyPropCSData = CsTypeEmptyPropCS;
+ return RedfishCS_status_success;
+}
+
+RedfishCS_bool CheckSupportedPropTypeInEmptyProperty(json_t *JsonObj) {
+ //
+ // Only support below property types for the property is declared as
+ // empty property in schema.
+ // e.g. "properties": {}
+ //
+ if (json_is_string(JsonObj) ||
+ json_is_integer(JsonObj) ||
+ //json_is_real(JsonObj) ||
+ json_is_number(JsonObj) ||
+ json_is_boolean(JsonObj)) {
+ return RedfishCS_boolean_true;
+ }
+ return RedfishCS_boolean_false;
+}
+
+RedfishCS_bool CheckEmptyPropJsonObject(json_t *JsonObj,
+RedfishCS_uint32 *NumOfProperty) {
+ RedfishCS_char *NewKey;
+ json_t *Value;
+ RedfishCS_void *n;
+ RedfishCS_uint32 Num;
+
+ Num = 0;
+ json_object_foreach_safe(JsonObj, n, NewKey, Value) {
+ if (!CheckSupportedPropTypeInEmptyProperty(Value)) {
+ return RedfishCS_boolean_false;
+ }
+ Num ++;
+ }
+ if (NumOfProperty != NULL) {
+ *NumOfProperty = Num;
+ }
+ return RedfishCS_boolean_true;
+}
+
+RedfishCS_bool SupportedRedfishResource (RedfishCS_char *Odata_Type,
+RedfishCS_char *NameSpace, RedfishCS_char *Version, RedfishCS_char
+*DataType) {
+ RedfishCS_char *TargetDataType;
+
+ if (Odata_Type == NULL || NameSpace == NULL || DataType == NULL) {
+ return RedfishCS_boolean_false;
+ }
+ if (Version != NULL) {
+ TargetDataType = malloc(strlen(NameSpace) + strlen(Version) + strlen(DataType) + 16); // Plus 16 bytes to make more room.
+ // Actually we just need 1 byte for "#"
+ // Two bytes for "." and one byte for NULL terminator.
+ } else {
+ TargetDataType = malloc(strlen(NameSpace) + strlen(DataType) + 16); // Plus 16 bytes to make more room.
+ // Actually we just need 1 byte for "#"
+ // Two bytes for "." and one byte for NULL terminator.
+ }
+ if (TargetDataType == NULL) {
+ return RedfishCS_boolean_false;
+ }
+ TargetDataType [0] = 0; // Insert NULL terminator.
+ strcat (TargetDataType, "#");
+ strcat (TargetDataType, NameSpace);
+ strcat (TargetDataType, ".");
+ if (Version != NULL && (strcmp (Version, "noversioned") != 0)) {
+ strcat(TargetDataType, Version);
+ strcat (TargetDataType, ".");
+ }
+ strcat (TargetDataType, DataType);
+ if (strcmp (Odata_Type, TargetDataType) == 0) {
+ return RedfishCS_boolean_true;
+ }
+ free (TargetDataType);
+ return RedfishCS_boolean_false;
+}
+
+RedfishCS_status
+CreateCsUriOrJsonByNode (void *Cs, json_t *JsonObj, RedfishCS_char
+*NodeName, RedfishCS_char *ParentUri, RedfishCS_Link *LinkHead) {
+ json_t *JsonObjTemp;
+ RedfishCS_Type_Uri_Data *CsTypeUri;
+ RedfishCS_Type_JSON_Data *CsTypeJson;
+ RedfishCS_status Status;
+
+ Status = RedfishCS_status_invalid_parameter;
+ JsonObjTemp = json_object_get (JsonObj, NodeName);
+ if (JsonObjTemp == NULL) {
+ return RedfishCS_status_not_found;
+ }
+ if (json_object_size(JsonObjTemp) == 1) {
+ Status = CreateCsUriByNode (Cs, JsonObj, NodeName, ParentUri, &CsTypeUri);
+ if (Status == RedfishCS_status_success) {
+ InsertTailLink (LinkHead, &CsTypeUri->Header.LinkEntry);
+ return RedfishCS_status_success;
+ }
+ } else {
+ Status = CreateCsJsonByNode (Cs, JsonObj, NodeName, ParentUri, &CsTypeJson);
+ if (Status == RedfishCS_status_success) {
+ InsertTailLink (LinkHead, &CsTypeJson->Header.LinkEntry);
+ return RedfishCS_status_success;
+ }
+ }
+ return Status;
+}
+
+RedfishCS_status
+CreateCsUriOrJsonByNodeArray (void *Cs, json_t *JsonObj, RedfishCS_char
+*NodeName, RedfishCS_char *ParentUri, RedfishCS_Link *LinkHead) {
+ json_t *JsonObjTemp;
+ json_t *JsonObjArray;
+ RedfishCS_Type_Uri_Data *CsTypeUri;
+ RedfishCS_Type_JSON_Data *CsTypeJson;
+ RedfishCS_status Status;
+ RedfishCS_uint16 ArrayIndex;
+
+ Status = RedfishCS_status_invalid_parameter;
+ JsonObjTemp = json_object_get (JsonObj, NodeName);
+ if (JsonObjTemp == NULL) {
+ return RedfishCS_status_not_found;
+ }
+ if (json_array_size (JsonObjTemp) == 0) {
+ return RedfishCS_status_success;
+ }
+ for (ArrayIndex = 0; ArrayIndex < (RedfishCS_uint16)json_array_size (JsonObjTemp); ArrayIndex ++) {
+ JsonObjArray = json_array_get (JsonObjTemp, (size_t)ArrayIndex);
+ if (JsonObjArray == NULL) {
+ continue;
+ }
+ if (json_object_size(JsonObjArray) == 1) {
+ Status = CreateCsUriByNode (Cs, JsonObjArray, NULL, ParentUri, &CsTypeUri);
+ if (Status == RedfishCS_status_success) {
+ InsertTailLink (LinkHead, &CsTypeUri->Header.LinkEntry);
+ }
+ } else {
+ Status = CreateCsJsonByNode (Cs, JsonObjArray, NULL, ParentUri, &CsTypeJson);
+ if (Status == RedfishCS_status_success) {
+ InsertTailLink (LinkHead, &CsTypeJson->Header.LinkEntry);
+ }
+ }
+ }
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status
+CreateJsonPayloadAndCs (char *JsonRawText, char *ResourceType, char
+*ResourceVersion, char *TypeName, json_t **JsonObjReturned, void **Cs,
+int size) {
+ json_t *TempJsonObj;
+ RedfishCS_char *TempChar;
+ RedfishCS_Header *Header;
+ void *TempCS;
+
+ if (JsonRawText == NULL ||
+ ResourceType == NULL ||
+ TypeName == NULL ||
+ Cs == NULL ||
+ size == 0
+ ) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ *JsonObjReturned = json_loads(JsonRawText, 0, NULL);
+ if (*JsonObjReturned == NULL) {
+ return RedfishCS_status_unknown_error;
+ }
+ TempJsonObj = json_object_get(*JsonObjReturned, "@odata.type");
+ if (TempJsonObj == NULL) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ TempChar = (RedfishCS_char *)json_string_value(TempJsonObj);
+ if (TempChar == NULL || ! SupportedRedfishResource (TempChar, ResourceType, ResourceVersion, TypeName)) {
+ return RedfishCS_status_unsupported;
+ }
+ TempCS = malloc (size);
+ if (TempCS == NULL) {
+ return RedfishCS_status_insufficient_memory;
+ }
+ memset (TempCS, 0, size);
+ Header = (RedfishCS_Header *)TempCS;
+ Header->ResourceType = RedfishCS_Type_CS;
+ Header->KeyName = NULL;
+ InitializeLinkHead (&Header->LinkEntry);
+ *Cs = TempCS;
+ return recordCsRootMemory (TempCS);
+}
+
+RedfishCS_status GetRedfishPropertyStr (void *Cs, json_t *JsonObj, char
+*Key, RedfishCS_char **DstBuffer) {
+ json_t *TempJsonObj;
+ RedfishCS_status Status;
+
+ if (DstBuffer == NULL) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ *DstBuffer = NULL;
+
+ TempJsonObj = json_object_get(JsonObj, Key);
+ if (TempJsonObj == NULL){
+ return RedfishCS_status_not_found;
+ }
+ Status = allocateDuplicateStr (Cs, (char
+*)json_string_value(TempJsonObj), (void **)DstBuffer);
+ return Status;
+}
+
+RedfishCS_status GetRedfishPropertyBoolean (void *Cs, json_t *JsonObj,
+char *Key, RedfishCS_bool **DstBuffer) {
+ json_t *TempJsonObj;
+ RedfishCS_status Status;
+
+ if (DstBuffer == NULL) {
+ return RedfishCS_status_not_found;
+ }
+ TempJsonObj = json_object_get(JsonObj, Key);
+ if (TempJsonObj == NULL){
+ return RedfishCS_status_not_found;
+ }
+ Status = allocateRecordCsMemory(Cs, sizeof(RedfishCS_bool), (void
+**)DstBuffer);
+ if (Status != RedfishCS_status_success){
+ return Status;
+ }
+ if (json_is_true(TempJsonObj)) {
+ **DstBuffer = RedfishCS_boolean_true;
+ } else {
+ **DstBuffer = RedfishCS_boolean_false;
+ }
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status GetRedfishPropertyInt64 (void *Cs, json_t *JsonObj,
+char *Key, RedfishCS_int64 **Dst) {
+ RedfishCS_status Status;
+ const json_t *TempJsonObj;
+
+ if (Dst == NULL) {
+ return RedfishCS_status_invalid_parameter;
+ }
+
+ TempJsonObj = json_object_get(JsonObj, Key);
+ if (TempJsonObj == NULL) {
+ return RedfishCS_status_not_found;
+ }
+ Status = allocateRecordCsMemory(Cs, sizeof(RedfishCS_int64), (void
+**)Dst);
+ if (Status != RedfishCS_status_success){
+ return Status;
+ }
+ **Dst = (RedfishCS_int64)json_integer_value(TempJsonObj);
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status GetRedfishPropertyVague (void *Cs, json_t *JsonObj,
+char *Key, RedfishCS_Vague **DstBuffer) {
+ json_t *TempJsonObj;
+ RedfishCS_status Status;
+ RedfishCS_Vague *VagueData;
+
+ if (DstBuffer == NULL) {
+ return RedfishCS_status_not_found;
+ }
+ TempJsonObj = json_object_get(JsonObj, Key); if (TempJsonObj ==
+ NULL){
+ return RedfishCS_status_not_found;
+ }
+ Status = allocateRecordCsMemory(Cs, sizeof(RedfishCS_Vague), (void
+ **)&VagueData); if (Status != RedfishCS_status_success){
+ return Status;
+ }
+
+ if (json_is_string(TempJsonObj)) {
+ VagueData->DataType = RedfishCS_Vague_DataType_String;
+ Status = GetRedfishPropertyStr (Cs, JsonObj, Key,
+&VagueData->DataValue.CharPtr);
+ } else if (json_is_integer(TempJsonObj)) {
+ VagueData->DataType = RedfishCS_Vague_DataType_Int64;
+ Status = GetRedfishPropertyInt64 (Cs, JsonObj, Key,
+&VagueData->DataValue.Int64Ptr);
+ } else if (json_is_boolean(TempJsonObj)) {
+ VagueData->DataType = RedfishCS_Vague_DataType_Bool;
+ Status = GetRedfishPropertyBoolean (Cs, JsonObj, Key,
+&VagueData->DataValue.BoolPtr);
+ } else if (json_is_null(TempJsonObj)) {
+ *DstBuffer = NULL; // No value for this key
+ free (VagueData);
+ return RedfishCS_status_success;
+ } else {
+ return RedfishCS_status_unsupported;
+ }
+ if (Status == RedfishCS_status_success) {
+ *DstBuffer = VagueData;
+ }
+ return Status;
+}
+
+RedfishCS_status InsertJsonStringObj (json_t *ParentJsonObj, char *Key,
+RedfishCS_char *StringValue) {
+ json_t *JsonValue;
+ RedfishCS_char NullStr[] = "";
+ RedfishCS_char *InsertStr;
+
+ InsertStr = StringValue;
+ if (ParentJsonObj == NULL) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ if (InsertStr == (char *)NULL) {
+ InsertStr = NullStr;
+ }
+ JsonValue = json_string(InsertStr);
+ if (JsonValue == NULL) {
+ return RedfishCS_status_unsupported;
+ }
+ if (json_object_set_new (ParentJsonObj, Key, JsonValue) == -1) {
+ return RedfishCS_status_unsupported;
+ }
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status InsertJsonBoolObj (json_t *ParentJsonObj, char *Key,
+RedfishCS_bool *BoolValue) {
+ json_t *JsonValue;
+
+ if (ParentJsonObj == NULL) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ if (BoolValue == (RedfishCS_bool *)NULL) {
+ return RedfishCS_status_success; // No value for this key.
+ }
+ JsonValue = json_boolean((BOOLEAN)*BoolValue);
+ if (JsonValue == NULL) {
+ return RedfishCS_status_unsupported;
+ }
+ if (json_object_set_new (ParentJsonObj, Key, JsonValue) == -1) {
+ return RedfishCS_status_unsupported;
+ }
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status InsertJsonInt64Obj (json_t *ParentJsonObj, char *Key,
+RedfishCS_int64 *Int64Value) {
+ json_t *JsonValue;
+
+ if (ParentJsonObj == NULL) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ if (Int64Value == (RedfishCS_int64 *)NULL) {
+ return RedfishCS_status_success; // No value for this key.
+ }
+ JsonValue = json_integer((json_int_t)*Int64Value);
+ if (JsonValue == NULL) {
+ return RedfishCS_status_unsupported;
+ }
+ if (json_object_set_new (ParentJsonObj, Key, JsonValue) == -1) {
+ return RedfishCS_status_unsupported;
+ }
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status InsertJsonVagueObj (json_t *ParentJsonObj, char *Key,
+RedfishCS_Vague *VagueValue) {
+ json_t *JsonValue;
+ RedfishCS_char NullStr[] = "";
+
+ if (ParentJsonObj == NULL) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ if (VagueValue == (RedfishCS_Vague *)NULL) {
+ JsonValue = json_null(); // No value for this key.
+ } else if (VagueValue->DataType == RedfishCS_Vague_DataType_String) {
+ if (VagueValue->DataValue.CharPtr == NULL) {
+ JsonValue = json_string(NullStr);
+ } else {
+ JsonValue = json_string(VagueValue->DataValue.CharPtr);
+ }
+ } else if (VagueValue->DataType == RedfishCS_Vague_DataType_Int64) {
+ JsonValue =
+json_integer((json_int_t)*VagueValue->DataValue.Int64Ptr);
+ } else if (VagueValue->DataType == RedfishCS_Vague_DataType_Bool) {
+ JsonValue = json_boolean((BOOLEAN)*VagueValue->DataValue.BoolPtr);
+ } else {
+ return RedfishCS_status_invalid_parameter;
+ }
+ if (json_object_set_new (ParentJsonObj, Key, JsonValue) == -1) {
+ return RedfishCS_status_unsupported;
+ }
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status InsertJsonLinkObj (json_t *JsonObj, char *Key,
+RedfishCS_Link *Link) {
+ json_t *JsonTextObj;
+ RedfishCS_Type_JSON_Data *CsJsonHeader;
+
+ if (Link == NULL || JsonObj == NULL) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ if (IsLinkEmpty (Link)) {
+ return RedfishCS_status_success;
+ }
+
+ CsJsonHeader = (RedfishCS_Type_JSON_Data *)GetFirstLink (Link); if
+ (CsJsonHeader->Header.ResourceType != RedfishCS_Type_JSON &&
+ CsJsonHeader->Header.ResourceType != RedfishCS_Type_Uri) {
+ // Only support JSON/URI property for CStructure to JSON
+ return RedfishCS_status_unsupported; } if (CsJsonHeader->JsonText
+ == NULL) {
+ return RedfishCS_status_invalid_parameter;
+ }
+
+ if (CsJsonHeader->Header.ResourceType == RedfishCS_Type_JSON) {
+ JsonTextObj = json_loads(CsJsonHeader->JsonText, 0, NULL);
+ if (json_object_set_new (JsonObj, Key, JsonTextObj) == -1) {
+ return RedfishCS_status_unsupported;
+ }
+ } else {
+ JsonTextObj = json_string (CsJsonHeader->JsonText);
+ if (json_object_set_new (JsonObj, Key, JsonTextObj) == -1) {
+ return RedfishCS_status_unsupported;
+ }
+ }
+
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status InsertJsonStringArrayObj (json_t *ParentJsonObj, char
+*Key, RedfishCS_char_Array *StringValueArray) {
+ json_t *ArrayJson;
+ json_t *ArrayMember;
+ RedfishCS_char_Array *NextArray;
+ RedfishCS_char NullStr[] = "";
+
+ if (ParentJsonObj == NULL) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ if (StringValueArray == (RedfishCS_char_Array *)NULL) {
+ return RedfishCS_status_success; // No value for this key.
+ }
+ ArrayJson = json_array();
+ if (ArrayJson == NULL) {
+ return RedfishCS_status_unsupported; } NextArray =
+ StringValueArray; do {
+ if (NextArray->ArrayValue == NULL) {
+ ArrayMember = json_string(NullStr);
+ } else {
+ ArrayMember = json_string(NextArray->ArrayValue);
+ }
+ if (json_array_append_new (ArrayJson, ArrayMember) != 0) {
+ return RedfishCS_status_unsupported;
+ }
+ NextArray = NextArray->Next;
+ } while (NextArray != NULL);
+
+ if (json_object_set_new (ParentJsonObj, Key, ArrayJson) == -1) {
+ return RedfishCS_status_unsupported;
+ }
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status InsertJsonBoolArrayObj (json_t *ParentJsonObj, char
+*Key, RedfishCS_bool_Array *BoolValueArray) {
+ json_t *ArrayJson;
+ json_t *ArrayMember;
+ RedfishCS_bool_Array *NextArray;
+
+ if (ParentJsonObj == NULL) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ if (BoolValueArray == (RedfishCS_bool_Array *)NULL) {
+ return RedfishCS_status_success; // No value for this key.
+ }
+ ArrayJson = json_array();
+ if (ArrayJson == NULL) {
+ return RedfishCS_status_unsupported; } NextArray =
+ BoolValueArray; do {
+ ArrayMember = json_boolean((BOOLEAN)*NextArray->ArrayValue);
+ if (json_array_append_new (ArrayJson, ArrayMember) != 0) {
+ return RedfishCS_status_unsupported;
+ }
+ NextArray = NextArray->Next;
+ } while (NextArray != NULL);
+
+ if (json_object_set_new (ParentJsonObj, Key, ArrayJson) == -1) {
+ return RedfishCS_status_unsupported;
+ }
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status InsertJsonInt64ArrayObj (json_t *ParentJsonObj, char
+*Key, RedfishCS_int64_Array *Int64ValueArray) {
+ json_t *ArrayJson;
+ json_t *ArrayMember;
+ RedfishCS_int64_Array *NextArray;
+
+ if (ParentJsonObj == NULL) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ if (Int64ValueArray == (RedfishCS_int64_Array *)NULL) {
+ return RedfishCS_status_success; // No value for this key.
+ }
+ ArrayJson = json_array();
+ if (ArrayJson == NULL) {
+ return RedfishCS_status_unsupported; } NextArray =
+ Int64ValueArray; do {
+ ArrayMember = json_integer(*NextArray->ArrayValue);
+ if (json_array_append_new (ArrayJson, ArrayMember) != 0) {
+ return RedfishCS_status_unsupported;
+ }
+ NextArray = NextArray->Next;
+ } while (NextArray != NULL);
+
+ if (json_object_set_new (ParentJsonObj, Key, ArrayJson) == -1) {
+ return RedfishCS_status_unsupported;
+ }
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status InsertJsonLinkArrayObj (json_t *ParentJsonObj, char
+*Key, RedfishCS_Link *LinkArray) {
+ json_t *ArrayJson;
+ json_t *ArrayMember;
+ RedfishCS_Type_Uri_Data *ThisLink;
+
+ if (ParentJsonObj == NULL) {
+ return RedfishCS_status_invalid_parameter;
+ }
+
+ if (IsLinkEmpty (LinkArray)) {
+ return RedfishCS_status_success;
+ }
+
+ ArrayJson = json_array();
+ if (ArrayJson == NULL) {
+ return RedfishCS_status_unsupported;
+ }
+ ThisLink = (RedfishCS_Type_Uri_Data *)GetFirstLink (LinkArray);
+ while (RedfishCS_boolean_true){
+ if (ThisLink->Header.ResourceType != RedfishCS_Type_Uri) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ if (ThisLink->Uri != (RedfishCS_char *)NULL) {
+ ArrayMember = json_string(ThisLink->Uri);
+ if (json_array_append_new (ArrayJson, ArrayMember) != 0) {
+ return RedfishCS_status_unsupported;
+ }
+ }
+ if (IsLinkAtEnd (LinkArray, &ThisLink->Header.LinkEntry)) {
+ if (json_object_set_new (ParentJsonObj, Key, ArrayJson) == -1) {
+ return RedfishCS_status_unsupported;
+ }
+ return RedfishCS_status_success;
+ }
+ ThisLink = (RedfishCS_Type_Uri_Data *)GetNextLink(LinkArray,
+&ThisLink->Header.LinkEntry);
+ };
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status CsEmptyPropLinkToJson(json_t *ParentJsonObj, char
+*Key, RedfishCS_Link *Link) {
+ RedfishCS_uint32 Index;
+ RedfishCS_Type_EmptyProp_CS_Data *EmptyProp_CS_Ptr;
+ RedfishCS_EmptyProp_KeyValue *KeyValuePtr;
+ json_t *JsonObj;
+ RedfishCS_status Status;
+
+ EmptyProp_CS_Ptr = (RedfishCS_Type_EmptyProp_CS_Data
+ *)GetFirstLink(Link); if (EmptyProp_CS_Ptr->Header.ResourceType != RedfishCS_Type_CS_EmptyProp) {
+ return RedfishCS_status_unsupported;
+ }
+
+ JsonObj = json_object();
+ KeyValuePtr = EmptyProp_CS_Ptr->KeyValuePtr;
+ for (Index = 0; Index < EmptyProp_CS_Ptr->NunmOfProperties; Index++) {
+ Status = InsertJsonVagueObj(JsonObj, KeyValuePtr->KeyNamePtr, KeyValuePtr->Value);
+ if (Status != RedfishCS_status_success) {
+ return Status;
+ }
+ KeyValuePtr = KeyValuePtr->NextKeyValuePtr;
+ }
+ if (json_object_set_new(ParentJsonObj, Key, JsonObj) != 0) {
+ return RedfishCS_status_unknown_error;
+ }
+ return RedfishCS_status_success;
+}
+
diff --git a/RedfishClientPkg/ConverterLib/src/RedfishCsMemory.c b/RedfishClientPkg/ConverterLib/src/RedfishCsMemory.c
new file mode 100644
index 0000000000..9dbab2c0b1
--- /dev/null
+++ b/RedfishClientPkg/ConverterLib/src/RedfishCsMemory.c
@@ -0,0 +1,144 @@
+/** @file
+
+ (C) Copyright 2018-2021 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RedfishCsMemoryInternal.h"
+#include <stdlib.h>
+#include <string.h>
+
+RedfishCS_Link CsMemRoot = {&CsMemRoot, &CsMemRoot};
+
+RedfishCS_status recordCsRootMemory (void *memCs) {
+ RedfishCS_Internal_memory_root *memRoot;
+
+ memRoot = malloc (sizeof(RedfishCS_Internal_memory_root));
+ if (memRoot == NULL) {
+ return RedfishCS_status_insufficient_memory;
+ }
+ InitializeLinkHead (&memRoot->nextRoot);
+ InitializeLinkHead (&memRoot->memBlocks);
+ memRoot->CsPtr = memCs;
+ InsertTailLink (&CsMemRoot, &memRoot->nextRoot);
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status allocateRecordCsMemory (RedfishCS_void *rootCs,
+RedfishCS_uint32 size, RedfishCS_void **Dst) {
+ RedfishCS_Internal_memory_root *memRoot;
+ RedfishCS_Internal_memory_link *memLink;
+
+ if (IsLinkEmpty (&CsMemRoot)) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ memRoot = (RedfishCS_Internal_memory_root *)GetFirstLink
+ (&CsMemRoot); while (RedfishCS_boolean_true){
+ if (memRoot->CsPtr == rootCs) {
+ // Allocation memory and record it.
+ memLink = malloc (sizeof(RedfishCS_Internal_memory_link));
+ if (memLink == NULL) {
+ return RedfishCS_status_insufficient_memory;
+ }
+ *Dst = malloc (size);
+ if (*Dst == NULL) {
+ free (memLink);
+ return RedfishCS_status_insufficient_memory;
+ }
+ memset (*Dst, 0, size);
+ memset (memLink, 0, sizeof(RedfishCS_Internal_memory_link));
+ InitializeLinkHead (&memLink->nextLink);
+ memLink->memoryPtr = *Dst;
+ InsertTailLink (&memRoot->memBlocks, &memLink->nextLink);
+ return RedfishCS_status_success;
+ }
+ if (IsLinkAtEnd (&CsMemRoot, (RedfishCS_Link *)&memRoot->nextRoot)) {
+ break;
+ }
+ memRoot = (RedfishCS_Internal_memory_root *)GetNextLink
+ (&CsMemRoot, &memRoot->nextRoot); };
+
+ return RedfishCS_status_invalid_parameter;
+}
+
+RedfishCS_status allocateRecordCsZeroMemory (RedfishCS_void *rootCs,
+RedfishCS_uint32 size, RedfishCS_void **Dst) {
+ RedfishCS_status Status;
+
+ Status = allocateRecordCsMemory (rootCs, size, Dst);
+ if (Status != RedfishCS_status_success || *Dst == NULL) {
+ return Status;
+ }
+ memset (*Dst, 0, size);
+ return RedfishCS_status_success;
+}
+
+RedfishCS_status DestoryCsMemory (RedfishCS_void *rootCs) {
+ RedfishCS_Internal_memory_root *memRoot;
+ RedfishCS_Internal_memory_link *memLink;
+
+ if (IsLinkEmpty (&CsMemRoot)) {
+ return RedfishCS_status_invalid_parameter;
+ }
+ memRoot = (RedfishCS_Internal_memory_root *)GetFirstLink
+(&CsMemRoot);
+ while (RedfishCS_boolean_true){
+ if (memRoot->CsPtr == rootCs) {
+ if (IsLinkEmpty (&memRoot->memBlocks)) {
+ return RedfishCS_status_success;
+ }
+ while (RedfishCS_boolean_true) {
+ memLink = (RedfishCS_Internal_memory_link *)GetLastLink(&memRoot->memBlocks);
+ if (memLink->memoryPtr != NULL) {
+ free (memLink->memoryPtr);
+ RemoveLink (&memLink->nextLink);
+ free (memLink);
+ }
+ if (IsLinkEmpty (&memRoot->memBlocks)) {
+ RemoveLink (&memRoot->nextRoot);
+ free (memRoot);
+ free (rootCs);
+ return RedfishCS_status_success;
+ }
+ }
+ }
+ if (IsLinkAtEnd (&CsMemRoot, (RedfishCS_Link *)&memRoot->nextRoot)) {
+ break;
+ }
+ memRoot = (RedfishCS_Internal_memory_root *)GetNextLink
+(&CsMemRoot, &memRoot->nextRoot);
+ };
+ return RedfishCS_status_invalid_parameter;
+}
+RedfishCS_status allocateArrayRecordCsMemory(RedfishCS_void *rootCs,
+RedfishCS_uint32 ArrayInstanceSize, RedfishCS_uint64 ArraySize,
+RedfishCS_void **Dst) {
+ RedfishCS_uint16 Index;
+ RedfishCS_void *ArrayInstance;
+ RedfishCS_void *PreArrayInstance;
+ RedfishCS_status Status;
+ RedfishCS_uint16 SizeOfVoid;
+
+ for (Index = 0; Index < ArraySize; Index ++) {
+ Status = allocateRecordCsMemory(rootCs, ArrayInstanceSize, &ArrayInstance);
+ if (Status != RedfishCS_status_success) {
+ return Status;
+ }
+ memset (ArrayInstance, 0, ArrayInstanceSize);
+ if (Index == 0) {
+ *Dst = ArrayInstance;
+ } else {
+ SizeOfVoid = sizeof (RedfishCS_void *);
+ if (SizeOfVoid == sizeof (RedfishCS_uint32)) {
+ *((RedfishCS_uint32 *)PreArrayInstance) = (RedfishCS_uint32)(unsigned long long)ArrayInstance; // Next link.
+ } else if (SizeOfVoid == sizeof (RedfishCS_uint64)){
+ *((RedfishCS_uint64 *)PreArrayInstance) = (RedfishCS_uint64)ArrayInstance; // Next link.
+ } else {
+ return RedfishCS_status_invalid_parameter;
+ }
+ }
+ PreArrayInstance = ArrayInstance;
+ }
+ return RedfishCS_status_success;
+}
--
2.17.1


Re: [PATCH EDK2 v3 1/1] MdeModulePkg/UefiSortLib:Add UefiSortLib unit test

Wu, Hao A
 

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Wu, Hao
A
Sent: Wednesday, August 11, 2021 4:33 PM
To: Liming Gao <gaoliming@byosoft.com.cn>; Wenyi Xie
<xiewenyi2@huawei.com>; devel@edk2.groups.io
Cc: songdongkuang@huawei.com; Wang, Jian J <jian.j.wang@intel.com>
Subject: Re: [edk2-devel] [PATCH EDK2 v3 1/1]
MdeModulePkg/UefiSortLib:Add UefiSortLib unit test

-----Original Message-----
From: Wenyi Xie <xiewenyi2@huawei.com>
Sent: Wednesday, August 11, 2021 2:36 PM
To: devel@edk2.groups.io; Wang, Jian J <jian.j.wang@intel.com>; Wu, Hao
A
<hao.a.wu@intel.com>
Cc: songdongkuang@huawei.com; xiewenyi2@huawei.com
Subject: [PATCH EDK2 v3 1/1] MdeModulePkg/UefiSortLib:Add UefiSortLib
unit test

Adding two unit test case for UefiSortLib. One is a test on sorting an array
of
UINT32 by using PerformQuickSort, another is a test on comparing the
same
buffer by using StringCompare.
Add 'main' function name to ECC exception list to avoid ECC error.

Reviewed-by: Hao A Wu <hao.a.wu@intel.com>

Hello Liming,

Since the patch looks more like a feature than a bugfix to me, I would like to
confirm that can I merge this change now?
I already gave my 'R-b' tag for the V2 patch on 29th July, but met some ECC
check issues during previous merging attempt.
I verified that the latest patch can pass the merging test
(https://github.com/tianocore/edk2/pull/1892).

Since no objection received, pushed via:
PR - https://github.com/tianocore/edk2/pull/1892
Commit - https://github.com/tianocore/edk2/commit/ac826886c98524e918753419c039d8b44198943f

If this commit breaks the Soft Feature Freeze rule, please help to raise. I will revert it.

Best Regards,
Hao Wu



Best Regards,
Hao Wu



Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Signed-off-by: Wenyi Xie <xiewenyi2@huawei.com>
---
MdeModulePkg/Test/MdeModulePkgHostTest.dsc | 6 +
MdeModulePkg/Library/UefiSortLib/UnitTest/UefiSortLibUnitTest.inf | 32
+++
MdeModulePkg/Library/UefiSortLib/UnitTest/UefiSortLibUnitTest.c | 207
++++++++++++++++++++
MdeModulePkg/MdeModulePkg.ci.yaml | 1 +
4 files changed, 246 insertions(+)

diff --git a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
index 4da4692c8451..c9ec835df65d 100644
--- a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
+++ b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
@@ -41,3 +41,9 @@ [Components]
<PcdsFixedAtBuild>

gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDis
able|TRUE
}
+
+ MdeModulePkg/Library/UefiSortLib/UnitTest/UefiSortLibUnitTest.inf {
+ <LibraryClasses>
+ UefiSortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
+
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ }
diff --git
a/MdeModulePkg/Library/UefiSortLib/UnitTest/UefiSortLibUnitTest.inf
b/MdeModulePkg/Library/UefiSortLib/UnitTest/UefiSortLibUnitTest.inf
new file mode 100644
index 000000000000..85d8dcd69619
--- /dev/null
+++
b/MdeModulePkg/Library/UefiSortLib/UnitTest/UefiSortLibUnitTest.inf
@@ -0,0 +1,32 @@
+## @file
+# This is a unit test for the UefiSortLib.
+#
+# Copyright (C) Huawei Technologies Co., Ltd. All rights reserved #
+SPDX-License-Identifier: BSD-2-Clause-Patent ##
+
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = UefiSortLibUnitTest
+ FILE_GUID = 271337A3-0D79-BA3E-BC03-714E518E3B1B
+ VERSION_STRING = 1.0
+ MODULE_TYPE = HOST_APPLICATION
+
+#
+# The following information is for reference only and not required by the
build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ UefiSortLibUnitTest.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[LibraryClasses]
+ UnitTestLib
+ DebugLib
+ UefiSortLib
diff --git
a/MdeModulePkg/Library/UefiSortLib/UnitTest/UefiSortLibUnitTest.c
b/MdeModulePkg/Library/UefiSortLib/UnitTest/UefiSortLibUnitTest.c
new file mode 100644
index 000000000000..4f44a02c5b5d
--- /dev/null
+++ b/MdeModulePkg/Library/UefiSortLib/UnitTest/UefiSortLibUnitTest.c
@@ -0,0 +1,207 @@
+/** @file
+ Unit tests of the UefiSortLib
+
+ Copyright (C) Huawei Technologies Co., Ltd. All rights reserved
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Library/UnitTestLib.h>
+#include <Library/SortLib.h>
+
+#define UNIT_TEST_APP_NAME "UefiSortLib Unit Tests"
+#define UNIT_TEST_APP_VERSION "1.0"
+
+#define TEST_ARRAY_SIZE_9 9
+
+/**
+ The function is called by PerformQuickSort to compare int values.
+
+ @param[in] Left The pointer to first buffer.
+ @param[in] Right The pointer to second buffer.
+
+ @retval 0 Buffer1 equal to Buffer2.
+ @return <0 Buffer1 is less than Buffer2.
+ @return >0 Buffer1 is greater than Buffer2.
+
+**/
+INTN
+EFIAPI
+TestCompareFunction (
+ IN CONST VOID *Left,
+ IN CONST VOID *Right
+ )
+{
+ if (*(UINT32*)Right > *(UINT32*)Left) {
+ return 1;
+ } else if (*(UINT32*)Right < *(UINT32*)Left) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ Unit test for PerformQuickSort () API of the UefiSortLib.
+
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that may
+ consume it.
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has
failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SortUINT32ArrayShouldSucceed (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ UINTN TestCount;
+ UINT32 Index;
+ UINT32 TestBuffer[TEST_ARRAY_SIZE_9];
+ UINT32 TestResult[TEST_ARRAY_SIZE_9];
+
+ TestCount = TEST_ARRAY_SIZE_9;
+ for (Index = 0; Index < TEST_ARRAY_SIZE_9; Index++) {
+ TestBuffer[Index] = Index + 1;
+ TestResult[Index] = TEST_ARRAY_SIZE_9 - Index; }
+
+ PerformQuickSort (TestBuffer, TestCount, sizeof (UINT32),
+ (SORT_COMPARE)TestCompareFunction);
+ UT_ASSERT_MEM_EQUAL (TestBuffer, TestResult, sizeof (UINT32) *
+ TEST_ARRAY_SIZE_9);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test for StringCompare () API of the UefiSortLib.
+
+ @param[in] Context [Optional] An optional parameter that enables:
+ 1) test-case reuse with varied parameters and
+ 2) test-case re-entry for Target tests that need a
+ reboot. This parameter is a VOID* and it is the
+ responsibility of the test author to ensure that the
+ contents are well understood by all test cases that may
+ consume it.
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the
test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has
failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+CompareSameBufferShouldSucceed (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ INTN retval;
+ CONST CHAR16* TestBuffer[] = { L"abcdefg" };
+
+ retval = StringCompare (TestBuffer, TestBuffer); UT_ASSERT_TRUE
+ (retval == 0);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Initialze the unit test framework, suite, and unit tests for the
+ UefiSortLib and run the UefiSortLib unit test.
+
+ @retval EFI_SUCCESS All test cases were dispatched.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources
available to
+ initialize the unit tests.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UnitTestingEntry (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UNIT_TEST_FRAMEWORK_HANDLE Framework;
+ UNIT_TEST_SUITE_HANDLE SortTests;
+
+ Framework = NULL;
+
+ DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME,
+ UNIT_TEST_APP_VERSION ));
+
+ //
+ // Start setting up the test framework for running the tests.
+ //
+ Status = InitUnitTestFramework (&Framework, UNIT_TEST_APP_NAME,
+ gEfiCallerBaseName, UNIT_TEST_APP_VERSION); if (EFI_ERROR (Status))
{
+ DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status
= %r\n", Status));
+ goto EXIT;
+ }
+
+ //
+ // Populate the UefiSortLib Unit Test Suite.
+ //
+ Status = CreateUnitTestSuite (&SortTests, Framework, "UefiSortLib
+ Sort Tests", "UefiSortLib.SortLib", NULL, NULL); if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for UefiSortLib
API Tests\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ //
+ --------------Suite--------Description------------Name--------------Fu
+ nction----------------Pre---Post---Context-----------
+ //
+ AddTestCase (SortTests, "Sort the Array", "Sort",
SortUINT32ArrayShouldSucceed, NULL, NULL, NULL);
+ AddTestCase (SortTests, "Compare the Buffer", "Compare",
CompareSameBufferShouldSucceed, NULL, NULL, NULL);
+
+ //
+ // Execute the tests.
+ //
+ Status = RunAllTestSuites (Framework);
+
+EXIT:
+ if (Framework) {
+ FreeUnitTestFramework (Framework);
+ }
+
+ return Status;
+}
+
+///
+/// Avoid ECC error for function name that starts with lower case
+letter /// #define UefiSortLibUnitTestMain main
+
+/**
+ Standard POSIX C entry point for host based unit test execution.
+
+ @param[in] Argc Number of arguments
+ @param[in] Argv Array of pointers to arguments
+
+ @retval 0 Success
+ @retval other Error
+**/
+INT32
+UefiSortLibUnitTestMain (
+ IN INT32 Argc,
+ IN CHAR8 *Argv[]
+ )
+{
+ UnitTestingEntry ();
+ return 0;
+}
diff --git a/MdeModulePkg/MdeModulePkg.ci.yaml
b/MdeModulePkg/MdeModulePkg.ci.yaml
index 8e01caf94cbf..aa304f2ccd5c 100644
--- a/MdeModulePkg/MdeModulePkg.ci.yaml
+++ b/MdeModulePkg/MdeModulePkg.ci.yaml
@@ -19,6 +19,7 @@
"ExceptionList": [
"8005", "UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE.UID",
"8005", "UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE.HID",
+ "8001", "UefiSortLibUnitTestMain",
],
## Both file path and directory path are accepted.
"IgnoreFiles": [
--
2.20.1.windows.1




Re: [PATCH v2 1/2] BaseTools: Define the read-only data section name per toolchain

Marvin Häuser <mhaeuser@...>
 

On 11/08/2021 19:19, Andrew Fish wrote:


On Aug 11, 2021, at 1:11 AM, Marvin Häuser <mhaeuser@posteo.de <mailto:mhaeuser@posteo.de>> wrote:

On 10/08/2021 23:58, Andrew Fish wrote:

On Aug 10, 2021, at 2:30 PM, Marvin Häuser <mhaeuser@posteo.de <mailto:mhaeuser@posteo.de>> wrote:

On 10/08/2021 21:35, Andrew Fish via groups.io <http://groups.io> wrote:

On Aug 10, 2021, at 1:27 AM, Marvin Häuser <mhaeuser@posteo.de <mailto:mhaeuser@posteo.de> <mailto:mhaeuser@posteo.de <mailto:mhaeuser@posteo.de>>> wrote:

On 10/08/2021 06:19, Andrew Fish via groups.io <http://groups.io> <http://groups.io <http://groups.io>> wrote:

On Aug 9, 2021, at 2:51 AM, Marvin Häuser <mhaeuser@posteo.de <mailto:mhaeuser@posteo.de> <mailto:mhaeuser@posteo.de <mailto:mhaeuser@posteo.de>> <mailto:mhaeuser@posteo.de <mailto:mhaeuser@posteo.de> <mailto:mhaeuser@posteo.de <mailto:mhaeuser@posteo.de>>>> wrote:

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3318 <https://bugzilla.tianocore.org/show_bug.cgi?id=3318> <https://bugzilla.tianocore.org/show_bug.cgi?id=3318 <https://bugzilla.tianocore.org/show_bug.cgi?id=3318>> <https://bugzilla.tianocore.org/show_bug.cgi?id=3318 <https://bugzilla.tianocore.org/show_bug.cgi?id=3318> <https://bugzilla.tianocore.org/show_bug.cgi?id=3318 <https://bugzilla.tianocore.org/show_bug.cgi?id=3318>>>

Different toolchains of the EDK II build system may generate ELF or
Mach-O files, which use the ".rodata" naming convention, or PE/COFF
files, which use the ".rdata" naming convention. Section permissions
are chosen based on this name per file format by NASM. To harden
image permission security, and to save space by avoiding both
".rdata" and ".rodata" sections being emitted, expose the appropriate
name as a preprocessor constant.

Cc: Bob Feng <bob.c.feng@intel.com <mailto:bob.c.feng@intel.com> <mailto:bob.c.feng@intel.com <mailto:bob.c.feng@intel.com>> <mailto:bob.c.feng@intel.com <mailto:bob.c.feng@intel.com> <mailto:bob.c.feng@intel.com <mailto:bob.c.feng@intel.com>>>>
Cc: Liming Gao <gaoliming@byosoft.com.cn <mailto:gaoliming@byosoft.com.cn> <mailto:gaoliming@byosoft.com.cn <mailto:gaoliming@byosoft.com.cn>> <mailto:gaoliming@byosoft.com.cn <mailto:gaoliming@byosoft.com.cn> <mailto:gaoliming@byosoft.com.cn <mailto:gaoliming@byosoft.com.cn>>>>
Cc: Yuwei Chen <yuwei.chen@intel.com <mailto:yuwei.chen@intel.com> <mailto:yuwei.chen@intel.com <mailto:yuwei.chen@intel.com>> <mailto:yuwei.chen@intel.com <mailto:yuwei.chen@intel.com> <mailto:yuwei.chen@intel.com <mailto:yuwei.chen@intel.com>>>>
Cc: Vitaly Cheptsov <vit9696@protonmail.com <mailto:vit9696@protonmail.com> <mailto:vit9696@protonmail.com <mailto:vit9696@protonmail.com>> <mailto:vit9696@protonmail.com <mailto:vit9696@protonmail.com> <mailto:vit9696@protonmail.com <mailto:vit9696@protonmail.com>>>>
Signed-off-by: Marvin Häuser <mhaeuser@posteo.de <mailto:mhaeuser@posteo.de> <mailto:mhaeuser@posteo.de <mailto:mhaeuser@posteo.de>> <mailto:mhaeuser@posteo.de <mailto:mhaeuser@posteo.de> <mailto:mhaeuser@posteo.de <mailto:mhaeuser@posteo.de>>>>
---
BaseTools/Conf/tools_def.template | 172 ++++++++++----------
1 file changed, 86 insertions(+), 86 deletions(-)

diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template
index 2e6b382ab623..84d464916c4d 100755
--- a/BaseTools/Conf/tools_def.template
+++ b/BaseTools/Conf/tools_def.template
@@ -463,9 +463,9 @@ NOOPT_VS2008_IA32_CC_FLAGS        = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE
RELEASE_VS2008_IA32_ASM_FLAGS     = /nologo /c /WX /W3 /Cx /coff /Zd

NOOPT_VS2008_IA32_ASM_FLAGS       = /nologo /c /WX /W3 /Cx /coff /Zd /Zi



-  DEBUG_VS2008_IA32_NASM_FLAGS    = -Ox -f win32 -g

-RELEASE_VS2008_IA32_NASM_FLAGS    = -Ox -f win32

-NOOPT_VS2008_IA32_NASM_FLAGS      = -O0 -f win32 -g

+  DEBUG_VS2008_IA32_NASM_FLAGS    = -Ox -f win32 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2008_IA32_NASM_FLAGS    = -Ox -f win32 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2008_IA32_NASM_FLAGS      = -O0 -f win32 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2008_IA32_DLINK_FLAGS   = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2008_IA32_DLINK_FLAGS   = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -495,9 +495,9 @@ NOOPT_VS2008_X64_CC_FLAGS       = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /G
RELEASE_VS2008_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd

NOOPT_VS2008_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd /Zi



-  DEBUG_VS2008_X64_NASM_FLAGS   = -Ox -f win64 -g

-RELEASE_VS2008_X64_NASM_FLAGS   = -Ox -f win64

-NOOPT_VS2008_X64_NASM_FLAGS     = -O0 -f win64 -g

+  DEBUG_VS2008_X64_NASM_FLAGS   = -Ox -f win64 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2008_X64_NASM_FLAGS   = -Ox -f win64 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2008_X64_NASM_FLAGS     = -O0 -f win64 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2008_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2008_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -574,9 +574,9 @@ NOOPT_VS2008x86_IA32_CC_FLAGS      = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE
RELEASE_VS2008x86_IA32_ASM_FLAGS   = /nologo /c /WX /W3 /Cx /coff /Zd

NOOPT_VS2008x86_IA32_ASM_FLAGS     = /nologo /c /WX /W3 /Cx /coff /Zd /Zi



-  DEBUG_VS2008x86_IA32_NASM_FLAGS  = -Ox -f win32 -g

-RELEASE_VS2008x86_IA32_NASM_FLAGS  = -Ox -f win32

-NOOPT_VS2008x86_IA32_NASM_FLAGS    = -O0 -f win32 -g

+  DEBUG_VS2008x86_IA32_NASM_FLAGS  = -Ox -f win32 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2008x86_IA32_NASM_FLAGS  = -Ox -f win32 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2008x86_IA32_NASM_FLAGS    = -O0 -f win32 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2008x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2008x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -605,9 +605,9 @@ NOOPT_VS2008x86_X64_CC_FLAGS       = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE
RELEASE_VS2008x86_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd

NOOPT_VS2008x86_X64_ASM_FLAGS      = /nologo /c /WX /W3 /Cx /Zd /Zi



-  DEBUG_VS2008x86_X64_NASM_FLAGS   = -Ox -f win64 -g

-RELEASE_VS2008x86_X64_NASM_FLAGS   = -Ox -f win64

-NOOPT_VS2008x86_X64_NASM_FLAGS     = -O0 -f win64 -g

+  DEBUG_VS2008x86_X64_NASM_FLAGS   = -Ox -f win64 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2008x86_X64_NASM_FLAGS   = -Ox -f win64 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2008x86_X64_NASM_FLAGS     = -O0 -f win64 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2008x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2008x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -688,9 +688,9 @@ NOOPT_VS2010_IA32_CC_FLAGS        = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE
RELEASE_VS2010_IA32_ASM_FLAGS     = /nologo /c /WX /W3 /Cx /coff /Zd

NOOPT_VS2010_IA32_ASM_FLAGS       = /nologo /c /WX /W3 /Cx /coff /Zd /Zi



-  DEBUG_VS2010_IA32_NASM_FLAGS    = -Ox -f win32 -g

-RELEASE_VS2010_IA32_NASM_FLAGS    = -Ox -f win32

-NOOPT_VS2010_IA32_NASM_FLAGS      = -O0 -f win32 -g

+  DEBUG_VS2010_IA32_NASM_FLAGS    = -Ox -f win32 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2010_IA32_NASM_FLAGS    = -Ox -f win32 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2010_IA32_NASM_FLAGS      = -O0 -f win32 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2010_IA32_DLINK_FLAGS   = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2010_IA32_DLINK_FLAGS   = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -720,9 +720,9 @@ NOOPT_VS2010_X64_CC_FLAGS       = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /G
RELEASE_VS2010_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd

NOOPT_VS2010_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd /Zi



-  DEBUG_VS2010_X64_NASM_FLAGS   = -Ox -f win64 -g

-RELEASE_VS2010_X64_NASM_FLAGS   = -Ox -f win64

-NOOPT_VS2010_X64_NASM_FLAGS     = -O0 -f win64 -g

+  DEBUG_VS2010_X64_NASM_FLAGS   = -Ox -f win64 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2010_X64_NASM_FLAGS   = -Ox -f win64 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2010_X64_NASM_FLAGS     = -O0 -f win64 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2010_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2010_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -799,9 +799,9 @@ NOOPT_VS2010x86_IA32_CC_FLAGS      = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE
RELEASE_VS2010x86_IA32_ASM_FLAGS   = /nologo /c /WX /W3 /Cx /coff /Zd

NOOPT_VS2010x86_IA32_ASM_FLAGS     = /nologo /c /WX /W3 /Cx /coff /Zd /Zi



-  DEBUG_VS2010x86_IA32_NASM_FLAGS  = -Ox -f win32 -g

-RELEASE_VS2010x86_IA32_NASM_FLAGS  = -Ox -f win32

-NOOPT_VS2010x86_IA32_NASM_FLAGS    = -O0 -f win32 -g

+  DEBUG_VS2010x86_IA32_NASM_FLAGS  = -Ox -f win32 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2010x86_IA32_NASM_FLAGS  = -Ox -f win32 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2010x86_IA32_NASM_FLAGS    = -O0 -f win32 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2010x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2010x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -831,9 +831,9 @@ NOOPT_VS2010x86_X64_CC_FLAGS       = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE
RELEASE_VS2010x86_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd

NOOPT_VS2010x86_X64_ASM_FLAGS      = /nologo /c /WX /W3 /Cx /Zd /Zi



-  DEBUG_VS2010x86_X64_NASM_FLAGS   = -Ox -f win64 -g

-RELEASE_VS2010x86_X64_NASM_FLAGS   = -Ox -f win64

-NOOPT_VS2010x86_X64_NASM_FLAGS     = -O0 -f win64 -g

+  DEBUG_VS2010x86_X64_NASM_FLAGS   = -Ox -f win64 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2010x86_X64_NASM_FLAGS   = -Ox -f win64 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2010x86_X64_NASM_FLAGS     = -O0 -f win64 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2010x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2010x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -913,9 +913,9 @@ NOOPT_VS2012_IA32_CC_FLAGS        = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768
RELEASE_VS2012_IA32_ASM_FLAGS     = /nologo /c /WX /W3 /Cx /coff /Zd

NOOPT_VS2012_IA32_ASM_FLAGS       = /nologo /c /WX /W3 /Cx /coff /Zd /Zi



-  DEBUG_VS2012_IA32_NASM_FLAGS    = -Ox -f win32 -g

-RELEASE_VS2012_IA32_NASM_FLAGS    = -Ox -f win32

-NOOPT_VS2012_IA32_NASM_FLAGS      = -O0 -f win32 -g

+  DEBUG_VS2012_IA32_NASM_FLAGS    = -Ox -f win32 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2012_IA32_NASM_FLAGS    = -Ox -f win32 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2012_IA32_NASM_FLAGS      = -O0 -f win32 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2012_IA32_DLINK_FLAGS   = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2012_IA32_DLINK_FLAGS   = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -945,9 +945,9 @@ NOOPT_VS2012_X64_CC_FLAGS       = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /G
RELEASE_VS2012_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd

NOOPT_VS2012_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd /Zi



-  DEBUG_VS2012_X64_NASM_FLAGS   = -Ox -f win64 -g

-RELEASE_VS2012_X64_NASM_FLAGS   = -Ox -f win64

-NOOPT_VS2012_X64_NASM_FLAGS     = -O0 -f win64 -g

+  DEBUG_VS2012_X64_NASM_FLAGS   = -Ox -f win64 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2012_X64_NASM_FLAGS   = -Ox -f win64 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2012_X64_NASM_FLAGS     = -O0 -f win64 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2012_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2012_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1024,9 +1024,9 @@ NOOPT_VS2012x86_IA32_CC_FLAGS      = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768
RELEASE_VS2012x86_IA32_ASM_FLAGS   = /nologo /c /WX /W3 /Cx /coff /Zd

NOOPT_VS2012x86_IA32_ASM_FLAGS     = /nologo /c /WX /W3 /Cx /coff /Zd /Zi



-  DEBUG_VS2012x86_IA32_NASM_FLAGS  = -Ox -f win32 -g

-RELEASE_VS2012x86_IA32_NASM_FLAGS  = -Ox -f win32

-NOOPT_VS2012x86_IA32_NASM_FLAGS    = -O0 -f win32 -g

+  DEBUG_VS2012x86_IA32_NASM_FLAGS  = -Ox -f win32 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2012x86_IA32_NASM_FLAGS  = -Ox -f win32 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2012x86_IA32_NASM_FLAGS    = -O0 -f win32 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2012x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2012x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1056,9 +1056,9 @@ NOOPT_VS2012x86_X64_CC_FLAGS       = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE
RELEASE_VS2012x86_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd

NOOPT_VS2012x86_X64_ASM_FLAGS      = /nologo /c /WX /W3 /Cx /Zd /Zi



-  DEBUG_VS2012x86_X64_NASM_FLAGS   = -Ox -f win64 -g

-RELEASE_VS2012x86_X64_NASM_FLAGS   = -Ox -f win64

-NOOPT_VS2012x86_X64_NASM_FLAGS     = -O0 -f win64 -g

+  DEBUG_VS2012x86_X64_NASM_FLAGS   = -Ox -f win64 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2012x86_X64_NASM_FLAGS   = -Ox -f win64 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2012x86_X64_NASM_FLAGS     = -O0 -f win64 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2012x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2012x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1138,9 +1138,9 @@ NOOPT_VS2013_IA32_CC_FLAGS        = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768
RELEASE_VS2013_IA32_ASM_FLAGS     = /nologo /c /WX /W3 /Cx /coff /Zd

NOOPT_VS2013_IA32_ASM_FLAGS       = /nologo /c /WX /W3 /Cx /coff /Zd /Zi



-  DEBUG_VS2013_IA32_NASM_FLAGS    = -Ox -f win32 -g

-RELEASE_VS2013_IA32_NASM_FLAGS    = -Ox -f win32

-NOOPT_VS2013_IA32_NASM_FLAGS      = -O0 -f win32 -g

+  DEBUG_VS2013_IA32_NASM_FLAGS    = -Ox -f win32 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2013_IA32_NASM_FLAGS    = -Ox -f win32 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2013_IA32_NASM_FLAGS      = -O0 -f win32 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2013_IA32_DLINK_FLAGS   = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2013_IA32_DLINK_FLAGS   = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1170,9 +1170,9 @@ NOOPT_VS2013_X64_CC_FLAGS       = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /G
RELEASE_VS2013_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd

NOOPT_VS2013_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd /Zi



-  DEBUG_VS2013_X64_NASM_FLAGS   = -Ox -f win64 -g

-RELEASE_VS2013_X64_NASM_FLAGS   = -Ox -f win64

-NOOPT_VS2013_X64_NASM_FLAGS     = -O0 -f win64 -g

+  DEBUG_VS2013_X64_NASM_FLAGS   = -Ox -f win64 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2013_X64_NASM_FLAGS   = -Ox -f win64 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2013_X64_NASM_FLAGS     = -O0 -f win64 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2013_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2013_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1249,9 +1249,9 @@ NOOPT_VS2013x86_IA32_CC_FLAGS      = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768
RELEASE_VS2013x86_IA32_ASM_FLAGS   = /nologo /c /WX /W3 /Cx /coff /Zd

NOOPT_VS2013x86_IA32_ASM_FLAGS     = /nologo /c /WX /W3 /Cx /coff /Zd /Zi



-  DEBUG_VS2013x86_IA32_NASM_FLAGS  = -Ox -f win32 -g

-RELEASE_VS2013x86_IA32_NASM_FLAGS  = -Ox -f win32

-NOOPT_VS2013x86_IA32_NASM_FLAGS    = -O0 -f win32 -g

+  DEBUG_VS2013x86_IA32_NASM_FLAGS  = -Ox -f win32 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2013x86_IA32_NASM_FLAGS  = -Ox -f win32 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2013x86_IA32_NASM_FLAGS    = -O0 -f win32 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2013x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2013x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1281,9 +1281,9 @@ NOOPT_VS2013x86_X64_CC_FLAGS       = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE
RELEASE_VS2013x86_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd

NOOPT_VS2013x86_X64_ASM_FLAGS      = /nologo /c /WX /W3 /Cx /Zd /Zi



-  DEBUG_VS2013x86_X64_NASM_FLAGS   = -Ox -f win64 -g

-RELEASE_VS2013x86_X64_NASM_FLAGS   = -Ox -f win64

-NOOPT_VS2013x86_X64_NASM_FLAGS     = -O0 -f win64 -g

+  DEBUG_VS2013x86_X64_NASM_FLAGS   = -Ox -f win64 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2013x86_X64_NASM_FLAGS   = -Ox -f win64 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2013x86_X64_NASM_FLAGS     = -O0 -f win64 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2013x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2013x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1364,9 +1364,9 @@ NOOPT_VS2015_IA32_CC_FLAGS        = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768
RELEASE_VS2015_IA32_ASM_FLAGS     = /nologo /c /WX /W3 /Cx /coff /Zd

NOOPT_VS2015_IA32_ASM_FLAGS       = /nologo /c /WX /W3 /Cx /coff /Zd /Zi



-  DEBUG_VS2015_IA32_NASM_FLAGS    = -Ox -f win32 -g

-RELEASE_VS2015_IA32_NASM_FLAGS    = -Ox -f win32

-NOOPT_VS2015_IA32_NASM_FLAGS      = -O0 -f win32 -g

+  DEBUG_VS2015_IA32_NASM_FLAGS    = -Ox -f win32 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2015_IA32_NASM_FLAGS    = -Ox -f win32 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2015_IA32_NASM_FLAGS      = -O0 -f win32 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2015_IA32_DLINK_FLAGS   = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2015_IA32_DLINK_FLAGS   = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1396,9 +1396,9 @@ NOOPT_VS2015_X64_CC_FLAGS       = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /G
RELEASE_VS2015_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd

NOOPT_VS2015_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd /Zi



-  DEBUG_VS2015_X64_NASM_FLAGS   = -Ox -f win64 -g

-RELEASE_VS2015_X64_NASM_FLAGS   = -Ox -f win64

-NOOPT_VS2015_X64_NASM_FLAGS     = -O0 -f win64 -g

+  DEBUG_VS2015_X64_NASM_FLAGS   = -Ox -f win64 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2015_X64_NASM_FLAGS   = -Ox -f win64 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2015_X64_NASM_FLAGS     = -O0 -f win64 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2015_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2015_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1476,9 +1476,9 @@ NOOPT_VS2015x86_IA32_CC_FLAGS      = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768
RELEASE_VS2015x86_IA32_ASM_FLAGS   = /nologo /c /WX /W3 /Cx /coff /Zd

NOOPT_VS2015x86_IA32_ASM_FLAGS     = /nologo /c /WX /W3 /Cx /coff /Zd /Zi



-  DEBUG_VS2015x86_IA32_NASM_FLAGS  = -Ox -f win32 -g

-RELEASE_VS2015x86_IA32_NASM_FLAGS  = -Ox -f win32

-NOOPT_VS2015x86_IA32_NASM_FLAGS    = -O0 -f win32 -g

+  DEBUG_VS2015x86_IA32_NASM_FLAGS  = -Ox -f win32 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2015x86_IA32_NASM_FLAGS  = -Ox -f win32 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2015x86_IA32_NASM_FLAGS    = -O0 -f win32 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2015x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2015x86_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1508,9 +1508,9 @@ NOOPT_VS2015x86_X64_CC_FLAGS       = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE
RELEASE_VS2015x86_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd

NOOPT_VS2015x86_X64_ASM_FLAGS      = /nologo /c /WX /W3 /Cx /Zd /Zi



-  DEBUG_VS2015x86_X64_NASM_FLAGS   = -Ox -f win64 -g

-RELEASE_VS2015x86_X64_NASM_FLAGS   = -Ox -f win64

-NOOPT_VS2015x86_X64_NASM_FLAGS     = -O0 -f win64 -g

+  DEBUG_VS2015x86_X64_NASM_FLAGS   = -Ox -f win64 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2015x86_X64_NASM_FLAGS   = -Ox -f win64 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2015x86_X64_NASM_FLAGS     = -O0 -f win64 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2015x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2015x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1586,9 +1586,9 @@ NOOPT_VS2017_IA32_CC_FLAGS      = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D
RELEASE_VS2017_IA32_ASM_FLAGS   = /nologo /c /WX /W3 /Cx /coff /Zd

NOOPT_VS2017_IA32_ASM_FLAGS     = /nologo /c /WX /W3 /Cx /coff /Zd /Zi



-  DEBUG_VS2017_IA32_NASM_FLAGS  = -Ox -f win32 -g

-RELEASE_VS2017_IA32_NASM_FLAGS  = -Ox -f win32

-NOOPT_VS2017_IA32_NASM_FLAGS    = -O0 -f win32 -g

+  DEBUG_VS2017_IA32_NASM_FLAGS  = -Ox -f win32 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2017_IA32_NASM_FLAGS  = -Ox -f win32 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2017_IA32_NASM_FLAGS    = -O0 -f win32 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2017_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2017_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1616,9 +1616,9 @@ NOOPT_VS2017_X64_CC_FLAGS       = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /G
RELEASE_VS2017_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd

NOOPT_VS2017_X64_ASM_FLAGS      = /nologo /c /WX /W3 /Cx /Zd /Zi



-  DEBUG_VS2017_X64_NASM_FLAGS   = -Ox -f win64 -g

-RELEASE_VS2017_X64_NASM_FLAGS   = -Ox -f win64

-NOOPT_VS2017_X64_NASM_FLAGS     = -O0 -f win64 -g

+  DEBUG_VS2017_X64_NASM_FLAGS   = -Ox -f win64 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2017_X64_NASM_FLAGS   = -Ox -f win64 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2017_X64_NASM_FLAGS     = -O0 -f win64 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2017_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4281 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2017_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4281 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1744,9 +1744,9 @@ NOOPT_VS2019_IA32_CC_FLAGS      = /nologo /arch:IA32 /c /WX /GS- /W4 /Gs32768 /D
RELEASE_VS2019_IA32_ASM_FLAGS   = /nologo /c /WX /W3 /Cx /coff /Zd

NOOPT_VS2019_IA32_ASM_FLAGS     = /nologo /c /WX /W3 /Cx /coff /Zd /Zi



-  DEBUG_VS2019_IA32_NASM_FLAGS  = -Ox -f win32 -g

-RELEASE_VS2019_IA32_NASM_FLAGS  = -Ox -f win32

-NOOPT_VS2019_IA32_NASM_FLAGS    = -O0 -f win32 -g

+  DEBUG_VS2019_IA32_NASM_FLAGS  = -Ox -f win32 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2019_IA32_NASM_FLAGS  = -Ox -f win32 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2019_IA32_NASM_FLAGS    = -O0 -f win32 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2019_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2019_IA32_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -1774,9 +1774,9 @@ NOOPT_VS2019_X64_CC_FLAGS       = /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /G
RELEASE_VS2019_X64_ASM_FLAGS    = /nologo /c /WX /W3 /Cx /Zd

NOOPT_VS2019_X64_ASM_FLAGS      = /nologo /c /WX /W3 /Cx /Zd /Zi



-  DEBUG_VS2019_X64_NASM_FLAGS   = -Ox -f win64 -g

-RELEASE_VS2019_X64_NASM_FLAGS   = -Ox -f win64

-NOOPT_VS2019_X64_NASM_FLAGS     = -O0 -f win64 -g

+  DEBUG_VS2019_X64_NASM_FLAGS   = -Ox -f win64 -g -DRODATA_SECTION_NAME=.rdata

+RELEASE_VS2019_X64_NASM_FLAGS   = -Ox -f win64 -DRODATA_SECTION_NAME=.rdata

+NOOPT_VS2019_X64_NASM_FLAGS     = -O0 -f win64 -g -DRODATA_SECTION_NAME=.rdata



  DEBUG_VS2019_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4281 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

RELEASE_VS2019_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4281 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data

@@ -2030,7 +2030,7 @@ DEFINE GCC_PP_FLAGS                        = -E -x assembler-with-cpp -include A
*_GCC48_IA32_DLINK2_FLAGS         = DEF(GCC48_IA32_DLINK2_FLAGS)

*_GCC48_IA32_RC_FLAGS             = DEF(GCC_IA32_RC_FLAGS)

*_GCC48_IA32_OBJCOPY_FLAGS        =

-*_GCC48_IA32_NASM_FLAGS           = -f elf32

+*_GCC48_IA32_NASM_FLAGS           = -f elf32 -DRODATA_SECTION_NAME=.rodata



  DEBUG_GCC48_IA32_CC_FLAGS       = DEF(GCC48_IA32_CC_FLAGS) -Os

RELEASE_GCC48_IA32_CC_FLAGS       = DEF(GCC48_IA32_CC_FLAGS) -Os -Wno-unused-but-set-variable

@@ -2058,7 +2058,7 @@ RELEASE_GCC48_IA32_CC_FLAGS       = DEF(GCC48_IA32_CC_FLAGS) -Os -Wno-unused-but
*_GCC48_X64_DLINK2_FLAGS         = DEF(GCC48_X64_DLINK2_FLAGS)

*_GCC48_X64_RC_FLAGS             = DEF(GCC_X64_RC_FLAGS)

*_GCC48_X64_OBJCOPY_FLAGS        =

-*_GCC48_X64_NASM_FLAGS           = -f elf64

+*_GCC48_X64_NASM_FLAGS           = -f elf64 -DRODATA_SECTION_NAME=.rodata



  DEBUG_GCC48_X64_CC_FLAGS       = DEF(GCC48_X64_CC_FLAGS) -Os

RELEASE_GCC48_X64_CC_FLAGS       = DEF(GCC48_X64_CC_FLAGS) -Os -Wno-unused-but-set-variable

@@ -2170,7 +2170,7 @@ RELEASE_GCC48_AARCH64_CC_FLAGS   = DEF(GCC48_AARCH64_CC_FLAGS) -Wno-unused-but-s
*_GCC49_IA32_DLINK2_FLAGS         = DEF(GCC49_IA32_DLINK2_FLAGS)

*_GCC49_IA32_RC_FLAGS             = DEF(GCC_IA32_RC_FLAGS)

*_GCC49_IA32_OBJCOPY_FLAGS        =

-*_GCC49_IA32_NASM_FLAGS           = -f elf32

+*_GCC49_IA32_NASM_FLAGS           = -f elf32 -DRODATA_SECTION_NAME=.rodata



  DEBUG_GCC49_IA32_CC_FLAGS       = DEF(GCC49_IA32_CC_FLAGS) -Os

RELEASE_GCC49_IA32_CC_FLAGS       = DEF(GCC49_IA32_CC_FLAGS) -Os -Wno-unused-but-set-variable -Wno-unused-const-variable

@@ -2198,7 +2198,7 @@ RELEASE_GCC49_IA32_CC_FLAGS       = DEF(GCC49_IA32_CC_FLAGS) -Os -Wno-unused-but
*_GCC49_X64_DLINK2_FLAGS         = DEF(GCC49_X64_DLINK2_FLAGS)

*_GCC49_X64_RC_FLAGS             = DEF(GCC_X64_RC_FLAGS)

*_GCC49_X64_OBJCOPY_FLAGS        =

-*_GCC49_X64_NASM_FLAGS           = -f elf64

+*_GCC49_X64_NASM_FLAGS           = -f elf64 -DRODATA_SECTION_NAME=.rodata



  DEBUG_GCC49_X64_CC_FLAGS       = DEF(GCC49_X64_CC_FLAGS) -Os

RELEASE_GCC49_X64_CC_FLAGS       = DEF(GCC49_X64_CC_FLAGS) -Os -Wno-unused-but-set-variable -Wno-unused-const-variable

@@ -2316,7 +2316,7 @@ RELEASE_GCC49_AARCH64_DLINK_XIPFLAGS = -z common-page-size=0x20
*_GCC5_IA32_DLINK2_FLAGS         = DEF(GCC5_IA32_DLINK2_FLAGS) -no-pie

*_GCC5_IA32_RC_FLAGS             = DEF(GCC_IA32_RC_FLAGS)

*_GCC5_IA32_OBJCOPY_FLAGS        =

-*_GCC5_IA32_NASM_FLAGS           = -f elf32

+*_GCC5_IA32_NASM_FLAGS           = -f elf32 -DRODATA_SECTION_NAME=.rodata



  DEBUG_GCC5_IA32_CC_FLAGS       = DEF(GCC5_IA32_CC_FLAGS) -flto -Os

  DEBUG_GCC5_IA32_DLINK_FLAGS    = DEF(GCC5_IA32_X64_DLINK_FLAGS) -flto -Os -Wl,-m,elf_i386,--oformat=elf32-i386

@@ -2348,7 +2348,7 @@ RELEASE_GCC5_IA32_DLINK_FLAGS    = DEF(GCC5_IA32_X64_DLINK_FLAGS) -flto -Os -Wl,
*_GCC5_X64_DLINK2_FLAGS          = DEF(GCC5_X64_DLINK2_FLAGS)

*_GCC5_X64_RC_FLAGS              = DEF(GCC_X64_RC_FLAGS)

*_GCC5_X64_OBJCOPY_FLAGS         =

-*_GCC5_X64_NASM_FLAGS            = -f elf64

+*_GCC5_X64_NASM_FLAGS            = -f elf64 -DRODATA_SECTION_NAME=.rodata



  DEBUG_GCC5_X64_CC_FLAGS        = DEF(GCC5_X64_CC_FLAGS) -flto -DUSING_LTO -Os

  DEBUG_GCC5_X64_DLINK_FLAGS     = DEF(GCC5_X64_DLINK_FLAGS) -flto -Os

@@ -2589,7 +2589,7 @@ DEFINE CLANG38_ALL_CC_FLAGS         = DEF(GCC48_ALL_CC_FLAGS) DEF(CLANG38_WARNIN
*_CLANG38_IA32_ASM_FLAGS            = DEF(GCC5_ASM_FLAGS) -m32 -march=i386 DEF(CLANG38_IA32_TARGET)

*_CLANG38_IA32_RC_FLAGS             = DEF(GCC_IA32_RC_FLAGS)

*_CLANG38_IA32_OBJCOPY_FLAGS        =

-*_CLANG38_IA32_NASM_FLAGS           = -f elf32

+*_CLANG38_IA32_NASM_FLAGS           = -f elf32 -DRODATA_SECTION_NAME=.rodata

*_CLANG38_IA32_PP_FLAGS             = DEF(GCC_PP_FLAGS) DEF(CLANG38_IA32_TARGET)

*_CLANG38_IA32_ASLPP_FLAGS          = DEF(GCC_ASLPP_FLAGS) DEF(CLANG38_IA32_TARGET)

*_CLANG38_IA32_VFRPP_FLAGS          = DEF(GCC_VFRPP_FLAGS) DEF(CLANG38_IA32_TARGET)

@@ -2626,7 +2626,7 @@ NOOPT_CLANG38_IA32_DLINK2_FLAGS     = DEF(GCC5_IA32_DLINK2_FLAGS) -O0
*_CLANG38_X64_ASM_FLAGS            = DEF(GCC5_ASM_FLAGS) -m64 DEF(CLANG38_X64_TARGET)

*_CLANG38_X64_RC_FLAGS             = DEF(GCC_X64_RC_FLAGS)

*_CLANG38_X64_OBJCOPY_FLAGS        =

-*_CLANG38_X64_NASM_FLAGS           = -f elf64

+*_CLANG38_X64_NASM_FLAGS           = -f elf64 -DRODATA_SECTION_NAME=.rodata

*_CLANG38_X64_PP_FLAGS             = DEF(GCC_PP_FLAGS) DEF(CLANG38_X64_TARGET)

*_CLANG38_X64_ASLPP_FLAGS          = DEF(GCC_ASLPP_FLAGS) DEF(CLANG38_X64_TARGET)

*_CLANG38_X64_VFRPP_FLAGS          = DEF(GCC_VFRPP_FLAGS) DEF(CLANG38_X64_TARGET)

@@ -2777,7 +2777,7 @@ DEFINE CLANGPDB_ALL_CC_FLAGS         = DEF(GCC48_ALL_CC_FLAGS) DEF(CLANGPDB_WARN
*_CLANGPDB_IA32_ASLCC_FLAGS          = DEF(GCC_ASLCC_FLAGS) -m32 -fno-lto DEF(CLANGPDB_IA32_TARGET)

*_CLANGPDB_IA32_ASM_FLAGS            = DEF(GCC_ASM_FLAGS) -m32 -march=i386 DEF(CLANGPDB_IA32_TARGET)

*_CLANGPDB_IA32_OBJCOPY_FLAGS        =

-*_CLANGPDB_IA32_NASM_FLAGS           = -f win32

+*_CLANGPDB_IA32_NASM_FLAGS           = -f win32 -DRODATA_SECTION_NAME=.rdata

*_CLANGPDB_IA32_PP_FLAGS             = DEF(GCC_PP_FLAGS) DEF(CLANGPDB_IA32_TARGET)

*_CLANGPDB_IA32_ASLPP_FLAGS          = DEF(GCC_ASLPP_FLAGS) DEF(CLANGPDB_IA32_TARGET)

*_CLANGPDB_IA32_VFRPP_FLAGS          = DEF(GCC_VFRPP_FLAGS) DEF(CLANGPDB_IA32_TARGET)

@@ -2811,7 +2811,7 @@ NOOPT_CLANGPDB_IA32_DLINK2_FLAGS     =
*_CLANGPDB_X64_ASLCC_FLAGS          = DEF(GCC_ASLCC_FLAGS) -m64 -fno-lto DEF(CLANGPDB_X64_TARGET)

*_CLANGPDB_X64_ASM_FLAGS            = DEF(GCC_ASM_FLAGS) -m64 DEF(CLANGPDB_X64_TARGET)

*_CLANGPDB_X64_OBJCOPY_FLAGS        =

-*_CLANGPDB_X64_NASM_FLAGS           = -f win64

+*_CLANGPDB_X64_NASM_FLAGS           = -f win64 -DRODATA_SECTION_NAME=.rdata

*_CLANGPDB_X64_PP_FLAGS             = DEF(GCC_PP_FLAGS) DEF(CLANGPDB_X64_TARGET)

*_CLANGPDB_X64_ASLPP_FLAGS          = DEF(GCC_ASLPP_FLAGS) DEF(CLANGPDB_X64_TARGET)

*_CLANGPDB_X64_VFRPP_FLAGS          = DEF(GCC_VFRPP_FLAGS) DEF(CLANGPDB_X64_TARGET)

@@ -2878,7 +2878,7 @@ DEFINE CLANGDWARF_X64_DLINK2_FLAGS        = -Wl,--defsym=PECOFF_HEADER_SIZE=0x22
*_CLANGDWARF_IA32_ASM_FLAGS            = DEF(GCC5_ASM_FLAGS) -m32 -march=i386 DEF(CLANG38_IA32_TARGET)

*_CLANGDWARF_IA32_RC_FLAGS             = DEF(GCC_IA32_RC_FLAGS)

*_CLANGDWARF_IA32_OBJCOPY_FLAGS        =

-*_CLANGDWARF_IA32_NASM_FLAGS           = -f elf32

+*_CLANGDWARF_IA32_NASM_FLAGS           = -f elf32 -DRODATA_SECTION_NAME=.rodata

*_CLANGDWARF_IA32_PP_FLAGS             = DEF(GCC_PP_FLAGS) DEF(CLANG38_IA32_TARGET)

*_CLANGDWARF_IA32_ASLPP_FLAGS          = DEF(GCC_ASLPP_FLAGS) DEF(CLANG38_IA32_TARGET)

*_CLANGDWARF_IA32_VFRPP_FLAGS          = DEF(GCC_VFRPP_FLAGS) DEF(CLANG38_IA32_TARGET)

@@ -2914,7 +2914,7 @@ NOOPT_CLANGDWARF_IA32_DLINK2_FLAGS     = DEF(CLANGDWARF_IA32_DLINK2_FLAGS) -O0 -
*_CLANGDWARF_X64_ASM_FLAGS            = DEF(GCC5_ASM_FLAGS) -m64 DEF(CLANG38_X64_TARGET)

*_CLANGDWARF_X64_RC_FLAGS             = DEF(GCC_X64_RC_FLAGS)

*_CLANGDWARF_X64_OBJCOPY_FLAGS        =

-*_CLANGDWARF_X64_NASM_FLAGS           = -f elf64

+*_CLANGDWARF_X64_NASM_FLAGS           = -f elf64 -DRODATA_SECTION_NAME=.rodata

*_CLANGDWARF_X64_PP_FLAGS             = DEF(GCC_PP_FLAGS) DEF(CLANG38_X64_TARGET)

*_CLANGDWARF_X64_ASLPP_FLAGS          = DEF(GCC_ASLPP_FLAGS) DEF(CLANG38_X64_TARGET)

*_CLANGDWARF_X64_VFRPP_FLAGS          = DEF(GCC_VFRPP_FLAGS) DEF(CLANG38_X64_TARGET)

@@ -2985,7 +2985,7 @@ RELEASE_XCODE5_IA32_DLINK_FLAGS      = -arch i386 -u _$(IMAGE_ENTRY_POINT) -e _$
  DEBUG_XCODE5_IA32_ASM_FLAGS  = -arch i386 -g

  NOOPT_XCODE5_IA32_ASM_FLAGS  = -arch i386 -g

RELEASE_XCODE5_IA32_ASM_FLAGS  = -arch i386

-      *_XCODE5_IA32_NASM_FLAGS = -f macho32

+      *_XCODE5_IA32_NASM_FLAGS = -f macho32 -DRODATA_SECTION_NAME=.rodata


An EFI Mach-O file does not contain a .rodata section. A Mach-O contains a __DATA segment that is broken up into sections. For a typical EFI image there are __const, __data, __bss sections in the __DATA segment [1].
Yes, and ".rodata" is almost a synonym for "__DATA,__const", with a small exception [1]. Maybe it'd be clearer if the macro was renamed to "NASM_RODATA_SECTION_NAME", to indicate this is not just a "raw" name, but NASM gives it a semantic meaning?

The mtoc [2] tool used to convert mach-O to PE/COFF converts the entire __DATA segment (__const, __data, and __bss) into the .data section. Thus adding any kind of new data section is a no-op at best.
This is a part I missed, because I do not have an Xcode toolchain at hand, so thanks for investigating. However this, in my opinion, is a flaw with Mach-O/mtoc and not with my patch. It seems like the only difference between __TEXT,__const and __DATA,__const is whether the data is targeted by a relocation or not. Such a concept does not exist for PE/COFF (and I think not even for ELF, but I'm not too familiar with it), thus the logical PE/COFF section __DATA,__const should be merged into is .rdata (and .rdata may or may not be merged into .text in an earlier step, I assume transitivity). I could change the macro definition to explicitly declare __TEXT,__const, but that would still put the compiler-emitted data in the wrong section. Does Xcode provide anything remotely similar to GNU linker scripts which we can use to move the section?

Please also note that .rodata is used for Xcode-based toolchains already (in fact, all toolchains, and this is the issue), I'm not regressing anything. I just expected it to work fine as-is. This patch mainly fixed PE/COFF-based toolchains, which get both .rdata from the compiler and .rodata with RX permissions from NASM, because ".rodata" only has a semantic meaning for ELF and Mach-O outputs, but not for PE/COFF.

If you want something to be read only for Xcode/clang you are better off putting it in the __TEXT section [3]. The __TEXT section is read only and for X64 can not even contain relocations.
Well, this kind of is an issue. We would need to introduce an arbitrary constraint on the relocation part that holds only for Xcode-based toolchains. Does the compiler emit an error when data in __TEXT,__const is targeted by a relocation?
The Xcode linker emits a fatal error on X64 for a relocation in the __TEXT section, everything needs to be RIP relative and the compiler does that for free. We generally only run into this for hand coded assembler and the fix is to use RIP relative addressing in the assembly.
Good, thanks for confirming! Still, this would be a bit of an awkward constraints for Xcode only.
It is a physics problem we can’t fix, so I end up writing some patches to fix other peoples assembler from time to time. The CI building with Xcode helps with this a lot.
(I think all open ends of the other threads are in here too, so let's drop them and go on only here?)

Right, ok, thanks!

Also see above regarding compiler-emitted __DATA,__const.
OK so the current nasm `SECTION .rodata`[1]  gets mapped to __TEXT,__const[2] for Xcode clang, and this is done by nasm (I dumped the object file). GenFw and mtoc only run on executables, also they tend to be conservative as they need to keep the layout the same and the relative layout between sections the same, but in this case it is nasm placing the data in the text section.

So what I’d like to see in the patch is to define RODATA_SECTION_NAME to match what is actually happening. So for XCODE that would be `__TEXT,__const` not `.rodata`.
We can do that, but what to do about compiler-emitted __DATA,__const?
Sorry I don’t understand what RODATA_SECTION_NAME has to do with the compiler? I thought it was for nasm?
Yes, it is for NASM. My point is, the actual issue is not that my macro uses __DATA,__const, but that __DATA,__const is not merged into .text, but into .data. Fixing the macro fixes where the NASM definitions go, but what about the C definitions? I cannot test it, as I said, because I don't have an Xcode machine, but let's say we have a stupid example like this:

volatile UINT32 a;
volatile UINT32 *CONST p = &a;
In this case p ends up in a __DATA__,__const section since &a requires a relocation.
OK, good, thanks!



The value of p is constant, so it can be placed in a constant data section. p points to a global variable, so if the compiler does not manage to somehow turn this into relative addressing (let's assume it does not), it needs to generate a relocation. This means the compiler cannot put it in __TEXT,__const, so it has to put it in __DATA,__const (of course it could put it in other __DATA sections, but let's assume the compiler agrees this should be read-only). The very same issue will arise and no matter the choice of the compiler, this will end up in .data. Do you agree? Or do we have some guarantee that Apple Clang cannot emit __DATA,__const?
I don’t see your bigger point. The compiler is free to implement as it sees fit. Which section some code ends up in is more of an implementation detail for the compiler, and we can’t really depend on that?
Your point, rightfully, was that things that we request to be read-only (may) end up being read-write. My issue is that, if the compiler requests this pointer to be read-only (it may not, but also it may), our PE executable does not honour it either. __DATA,__const is a section for constant data, and we put it into a read-write section. The bigger point is, whenever the compile stack wants something read-only (be that NASM or be that Apple Clang, anything really), we should actually ensure it is read-only. I can do that for only NASM by forcing the __TEXT,__const section name (at the cost of prohibiting relocs), but I do not know how to do it for Apple Clang. At worst we could take a hacked-ish solution, where all Mach-O segments are converted to PE/COFF sections - with the exception of the __DATA,__const section, which, if aligned on a segment alignment boundary, can be inserted between the two other parts .data is split into. I read in the XNU source that the ARM protection code does something roughly like this [1], but I'm really far from well-versed in the deep details of macOS.

Sorry for this not being "integrated" in above text, but I found two more things while looking for citation 1.

1) Mach-O sections can be renamed, including the preceding segment name [2]. According to the very next line, the example actually creates a new segment. Does it allow merging into another, existing segment? What if I did something like:

-Wl,-rename_section,__DATA,__const,__TEXT,__const2

or even

-Wl,-rename_section,__DATA,__const,__TEXT,__const

i.e. can it merge two sections together? if __DATA,__const had data with relocs, would the renaming trigger the "no relocs" error of __TEXT, or does that happen before section renaming? Any chance it can be turned off?

1.1) Actually, for the standalone .rodata section, we can just rename it to __DATA_CONST,__const, as I have seen elsewhere in XNU. No hacked-ish solution needed. :)

2) We actually can force the compiler to put data in the constant data segment [3]. This is of course not used in EDK II, and probably neither portable nor necessary, but an interesting detail. I really think we should honour it either way.

I will likely try to get my hands on some sort of Apple development environment soon, but I cannot promise much right now. I think it really is better if I can test through all toolchains myself. If you release Apple Clang for Linux, I also won't complain of course. :)



We should double check what is happening for ELF on x86, ARM, RiskV, etc. and do the same thing. I assume all the tools that generate PE/COFF directly are good with .rodata?
They are not, that is the whole point of the patch in its current shape. .rodata is valid for ELF and Mach-O, PE/COFF needs .rdata.

I think it is likely as simple as dumping the EFL object file in objdump or gdb for the given toolchain (like my Xcode example).

TL;DR It looks to me like nasm does some SECTION translations under the hood to make code portable, and I’d like to make sure we capture those in the new NASM_RODATA_SECTION_NAME. If some one is doing a security review having NASM_RODATA_SECTION_NAME is going to imply that a .rodata section is being used by that specific toolchain, and I think that is much worse than the current “magic” behavior in nasm. We are much better off explaining what is really happening, since it is not very obvious.
I feel like I'm too tired to get the point. Do you mean you want comments whenever this section name is used? Or comments in tools_def?
I think I’d settle for a more descriptive commit comment that better defines what the define means like I mentioned in the other mail.
Hmm no, we can do that too, but in that case I really want comments in the code. tools_def is not really documented at all, maybe it is time to introduce an example comment so at least new things get commented? Maybe just the start of a macro list. Relying on "git blame" to figure out simple things is rather awful.

One more thing from another thread: Yes, the new macro should refer to object file section naming. I want this patch to get object file sections proper and sound. From there on we can fix the linking stage to emit proper and sound executables in a later patch.
OK then please refactor the commit message to make it clear that this patch is to get the correct section in the object files, and work is still need to get this into executable images.
Sure.


For Xcode you can make it __DATA__,__const since that is the closest thing to read only data and I think that is your intent.
I would like to do that, but only if we can ensure __DATA,__const is merged into .text, or is a separate RNX section.


GenFW is part of EDKII BaseTools and mtoc is part of the open source CCTOOLS project and both those tools would need to be modified to create a .rodata section in PE/COFF.
Yes, that should not be a big problem. Remaining issues for me:
1) How to merge __DATA,__const into .text, or how to emit a standalone .rodata section, for Xcode-based toolchains? (Some ideas above, will ping Vitaly soon as well)
2) How to submit modified mtoc? Any chance it could be maintained in EDK II like GenFw? (Would be nice if you could provide some insight)
3) How to merge .rdata into .text for MSVC? (I will try to research this soon-ish, but no promises)
4) How to design a toggle for the platform maintainer to choose between .text merge and standalone .rodata?

Please note that I'm not asking you to research any of those questions (but 2) would be nice :) ), this is merely a summary of open points till the second stage (correct executables, not just correct object sections) can be properly approached.

Thanks for your time and insight!

Best regards,
Marvin


[1] https://github.com/apple/darwin-xnu/blob/a1babec6b135d1f35b2590a1990af3c5c5393479/osfmk/arm/arm_vm_init.c#L318-L324

[2] https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/makedefs/MakeInc.def#L578

[3] https://github.com/apple/darwin-xnu/blob/8f02f2a044b9bb1ad951987ef5bab20ec9486310/libsa/lastkerneldataconst.c#L48


Thanks,

Andrew Fish

Best regards,
Marvin


Thanks,

Andrew Fish

Best regards,
Marvin

[1] https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.nasm#L14 <https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.nasm#L14> <https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.nasm#L14 <https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.nasm#L14>>

[2] $otool -V -s __TEXT __constBuild/OvmfX64/DEBUG_XCODE5/X64/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib/OUTPUT/X64/InitializeFpu.obj
Build//OvmfX64/DEBUG_XCODE5/X64/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib/OUTPUT/X64/InitializeFpu.obj:
Contents of (__TEXT,__const) section
0000001d  7f 03 80 1f 00 00

$ otool -l Build//OvmfX64/DEBUG_XCODE5/X64/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib/OUTPUT/X64/InitializeFpu.obj
Build/OvmfX64/DEBUG_XCODE5/X64/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib/OUTPUT/X64/InitializeFpu.obj:
Load command 0
      cmd LC_SEGMENT_64
  cmdsize 232
  segname
   vmaddr 0x0000000000000000
   vmsize 0x0000000000000026
  fileoff 288
 filesize 38
  maxprot 0x00000007
 initprot 0x00000007
   nsects 2
    flags 0x0
Section
  sectname __text
   segname __TEXT
      addr 0x0000000000000000
      size 0x000000000000001d
    offset 288
     align 2^0 (1)
    reloff 328
    nreloc 2
     flags 0x80000500
 reserved1 0
 reserved2 0
Section
  sectname __const
   segname __TEXT
      addr 0x000000000000001d
      size 0x0000000000000006
    offset 320
     align 2^0 (1)
    reloff 0
    nreloc 0
     flags 0x00000000
 reserved1 0
 reserved2 0
Load command 1
     cmd LC_SYMTAB
 cmdsize 24
  symoff 344
   nsyms 3
  stroff 392
 strsize 63

Thanks,

Andrew Fish


Thanks for your notes and insight!

Best regards,
Marvin


[1]
"For compatibility with other Unix platforms, the following standard names are also supported:
[...]
.rodata  = __DATA,__const data
[...]
If the .rodata section contains no relocations, it is instead put into the __TEXT,__const section unless this section has already been specified explicitly."
https://www.nasm.us/xdoc/2.13.01/html/nasmdoc7.html <https://www.nasm.us/xdoc/2.13.01/html/nasmdoc7.html> <https://www.nasm.us/xdoc/2.13.01/html/nasmdoc7.html <https://www.nasm.us/xdoc/2.13.01/html/nasmdoc7.html>>

[1] otool -lh DxeCore.dll
...
Load command 1
      cmd LC_SEGMENT_64
  cmdsize 312
  segname __DATA
   vmaddr 0x000000000002b000
   vmsize 0x0000000000147000
  fileoff 180224
 filesize 8192
  maxprot 0x00000003
 initprot 0x00000003
   nsects 3
    flags 0x0
Section
  sectname __const
   segname __DATA
      addr 0x000000000002b000
      size 0x0000000000000718
    offset 180224
     align 2^4 (16)
    reloff 0
    nreloc 0
     flags 0x00000000
 reserved1 0
 reserved2 0
Section
  sectname __data
   segname __DATA
      addr 0x000000000002b720
      size 0x00000000000014f0
    offset 182048
     align 2^4 (16)
    reloff 0
    nreloc 0
     flags 0x00000000
 reserved1 0
 reserved2 0
Section
  sectname __bss
   segname __DATA
      addr 0x000000000002cc10
      size 0x0000000000144e11
    offset 0
     align 2^4 (16)
    reloff 0
    nreloc 0
     flags 0x00000001
 reserved1 0
 reserved2 0


[2] https://opensource.apple.com/source/cctools/cctools-698/efitools/mtoc.c.auto.html <https://opensource.apple.com/source/cctools/cctools-698/efitools/mtoc.c.auto.html> <https://opensource.apple.com/source/cctools/cctools-698/efitools/mtoc.c.auto.html <https://opensource.apple.com/source/cctools/cctools-698/efitools/mtoc.c.auto.html>>

[3] otool more output…
Load command 0
      cmd LC_SEGMENT_64
  cmdsize 392
  segname __TEXT
   vmaddr 0x0000000000000240
   vmsize 0x00000000000296c0
  fileoff 1184
 filesize 169664
  maxprot 0x00000005
 initprot 0x00000005
   nsects 4
    flags 0x0
Section
  sectname __text
   segname __TEXT
      addr 0x0000000000000240
      size 0x000000000002489f
    offset 1184
     align 2^3 (8)
    reloff 0
    nreloc 0
     flags 0x80000400
 reserved1 0
 reserved2 0
Section
  sectname __cstring
   segname __TEXT
      addr 0x0000000000024ae0
      size 0x000000000000496d
    offset 150848
     align 2^4 (16)
    reloff 0
    nreloc 0
     flags 0x00000002
 reserved1 0
 reserved2 0
Section
  sectname __ustring
   segname __TEXT
      addr 0x000000000002944e
      size 0x0000000000000048
    offset 169646
     align 2^1 (2)
    reloff 0
    nreloc 0
     flags 0x00000000
 reserved1 0
 reserved2 0
Section
  sectname __const
   segname __TEXT
      addr 0x00000000000294a0
      size 0x0000000000000448
    offset 169728
     align 2^4 (16)
    reloff 0
    nreloc 0
     flags 0x00000000
 reserved1 0
 reserved2 0

Thanks,

Andrew Fish


  DEBUG_XCODE5_IA32_CC_FLAGS   = -arch i386 -c -g -Os       -Wall -Werror -include AutoGen.h -funsigned-char -fno-stack-protector -fno-builtin -fshort-wchar -fasm-blocks -mdynamic-no-pic -mno-implicit-float -mms-bitfields -msoft-float -Wno-unused-parameter -Wno-missing-braces -Wno-missing-field-initializers -Wno-tautological-compare -Wno-sign-compare -Wno-varargs -ftrap-function=undefined_behavior_has_been_optimized_away_by_clang $(PLATFORM_FLAGS)

@@ -3003,7 +3003,7 @@ RELEASE_XCODE5_X64_DLINK_FLAGS      = -arch x86_64 -u _$(IMAGE_ENTRY_POINT) -e _
  DEBUG_XCODE5_X64_ASM_FLAGS  = -arch x86_64 -g

  NOOPT_XCODE5_X64_ASM_FLAGS  = -arch x86_64 -g

RELEASE_XCODE5_X64_ASM_FLAGS  = -arch x86_64

-      *_XCODE5_X64_NASM_FLAGS = -f macho64

+      *_XCODE5_X64_NASM_FLAGS = -f macho64 -DRODATA_SECTION_NAME=.rodata

*_XCODE5_*_PP_FLAGS         = -E -x assembler-with-cpp -include AutoGen.h

*_XCODE5_*_VFRPP_FLAGS      = -x c -E -P -DVFRCOMPILE -include $(MODULE_NAME)StrDefs.h



--
2.31.1










10601 - 10620 of 89697