public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH V3 01/10] OvmfPkg: Add Tdx BFV/CFV PCDs and PcdOvmfImageSizeInKb
       [not found] <cover.1627364332.git.min.m.xu@intel.com>
@ 2021-07-27  5:42 ` Min Xu
  2021-07-27  5:42 ` [PATCH V3 02/10] OvmfPkg: Add Tdx metadata Min Xu
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 36+ messages in thread
From: Min Xu @ 2021-07-27  5:42 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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 | 12 +++++++++++-
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 6ae733f6e39f..6d9bb91e9274 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -321,6 +321,19 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretBase|0x0|UINT32|0x42
   gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretSize|0x0|UINT32|0x43
 
+  ## The base address and size of the TDX Cfv base and size.
+  gUefiOvmfPkgTokenSpaceGuid.PcdCfvBase|0|UINT32|0x47
+  gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataOffset|0|UINT32|0x48
+  gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize|0|UINT32|0x49
+
+  ## The base address and size of the TDX Bfv base and size.
+  gUefiOvmfPkgTokenSpaceGuid.PcdBfvBase|0|UINT32|0x4a
+  gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataOffset|0|UINT32|0x4b
+  gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataSize|0|UINT32|0x4c
+
+  ## Size of the Ovmf image in KB
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfImageSizeInKb|0|UINT32|0x4d
+
 [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..401e491e4cbe 100644
--- a/OvmfPkg/OvmfPkgDefines.fdf.inc
+++ b/OvmfPkg/OvmfPkgDefines.fdf.inc
@@ -2,13 +2,14 @@
 #  FDF include file that defines the main macros and sets the dependent PCDs.
 #
 #  Copyright (C) 2014, Red Hat, Inc.
-#  Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ##
 
 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


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH V3 02/10] OvmfPkg: Add Tdx metadata
       [not found] <cover.1627364332.git.min.m.xu@intel.com>
  2021-07-27  5:42 ` [PATCH V3 01/10] OvmfPkg: Add Tdx BFV/CFV PCDs and PcdOvmfImageSizeInKb Min Xu
@ 2021-07-27  5:42 ` Min Xu
  2021-07-27  5:42 ` [PATCH V3 03/10] OvmfPkg: Set TdMailbox initial value and macros Min Xu
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 36+ messages in thread
From: Min Xu @ 2021-07-27  5:42 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

Tdx Metadata 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.
 _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/_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. SEV and TDX will not run at the same time. So TDX re-use the
memory region defined by SEV.
 - MailBox      : PcdOvmfSecGhcbBackupBase|PcdOvmfSecGhcbBackupSize
 - TdHob        : PcdOvmfSecGhcbBase|PcdOvmfSecGhcbSize
 - TdxPageTable : PcdOvmfSecGhcbPageTableBase|PcdOvmfSecGhcbPageTableSize

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 | 17 ++++
 OvmfPkg/ResetVector/ResetVector.inf          | 11 ++-
 OvmfPkg/ResetVector/ResetVector.nasmb        | 47 +++++++++-
 OvmfPkg/ResetVector/X64/TdxMetadata.asm      | 97 ++++++++++++++++++++
 4 files changed, 169 insertions(+), 3 deletions(-)
 create mode 100644 OvmfPkg/ResetVector/X64/TdxMetadata.asm

diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
index 9c0b5853a46f..ac86ce69ebe8 100644
--- a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
+++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
@@ -47,6 +47,23 @@ 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 Secret block
 ;
diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index dc38f68919cd..fd65c0c9621d 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
 #
@@ -43,6 +43,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 5fbacaed5f9d..b653fe87abd6 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -4,6 +4,7 @@
 ;
 ; Copyright (c) 2008 - 2013, Intel Corporation. All rights reserved.<BR>
 ; Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
 ; SPDX-License-Identifier: BSD-2-Clause-Patent
 ;
 ;------------------------------------------------------------------------------
@@ -67,6 +68,44 @@
     %error "This implementation inherently depends on PcdOvmfSecGhcbBase not straddling a 2MB boundary"
   %endif
 
+  ;
+  ; TDX meta data
+  ;
+  %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
+
+  %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 PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
 
   %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
@@ -76,8 +115,11 @@
   %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/PageTables64.asm"
+
+  %include "X64/TdxMetadata.asm"
+
+  %include "Ia32/Flat32ToFlat64.asm"
+  %include "Ia32/PageTables64.asm"
 %endif
 
 %include "Ia16/Real16ToFlat32.asm"
@@ -88,5 +130,6 @@
   %define SEV_ES_AP_RESET_IP  FixedPcdGet32 (PcdSevEsWorkAreaBase)
   %define SEV_LAUNCH_SECRET_BASE  FixedPcdGet32 (PcdSevLaunchSecretBase)
   %define SEV_LAUNCH_SECRET_SIZE  FixedPcdGet32 (PcdSevLaunchSecretSize)
+  %define OVMF_IMAGE_SIZE_IN_KB   FixedPcdGet32 (PcdOvmfImageSizeInKb)
 %include "Ia16/ResetVectorVtf0.asm"
 
diff --git a/OvmfPkg/ResetVector/X64/TdxMetadata.asm b/OvmfPkg/ResetVector/X64/TdxMetadata.asm
new file mode 100644
index 000000000000..8dba8daa0165
--- /dev/null
+++ b/OvmfPkg/ResetVector/X64/TdxMetadata.asm
@@ -0,0 +1,97 @@
+;------------------------------------------------------------------------------
+; @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_VIRTUAL_FIRMWARE
+
+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
+
+_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


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH V3 03/10] OvmfPkg: Set TdMailbox initial value and macros
       [not found] <cover.1627364332.git.min.m.xu@intel.com>
  2021-07-27  5:42 ` [PATCH V3 01/10] OvmfPkg: Add Tdx BFV/CFV PCDs and PcdOvmfImageSizeInKb Min Xu
  2021-07-27  5:42 ` [PATCH V3 02/10] OvmfPkg: Add Tdx metadata Min Xu
@ 2021-07-27  5:42 ` Min Xu
  2021-07-27  5:42 ` [PATCH V3 04/10] OvmfPkg: Add TDX_PT_ADDR defition in ResetVector.nasmb Min Xu
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 36+ messages in thread
From: Min Xu @ 2021-07-27  5:42 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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

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

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

diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 5fa8c0895808..c587d1412803 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -87,6 +87,12 @@ gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpaceGuid.PcdSevE
 
 0x00C000|0x001000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
+DATA = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+}
 
 0x010000|0x010000
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index b653fe87abd6..42b4a3791d29 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -106,6 +106,18 @@
   %define TDX_EXTRA_PAGE_TABLE_BASE FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase)
   %define TDX_EXTRA_PAGE_TABLE_SIZE FixedPcdGet32 (PcdOvmfSecGhcbPageTableSize)
 
+  ;
+  ; TdMailboxBase [0x10, 0x800] is reserved for OS.
+  ; Td guest initialize piece of this area (TdMailboxBase [0x10,0x20]) to
+  ; record the Td guest info so that this information can be used in the
+  ; following ResetVector flow.
+  ;
+  %define TD_MAILBOX_WORKAREA_OFFSET    0x10
+  %define TDX_WORK_AREA                 (TDX_MAILBOX_MEMORY_BASE + TD_MAILBOX_WORKAREA_OFFSET)
+  %define TDX_WORK_AREA_PAGELEVEL5      (TDX_WORK_AREA + 4)
+  %define TDX_WORK_AREA_PGTBL_READY     (TDX_WORK_AREA + 5)
+  %define TDX_WORK_AREA_INITVP          (TDX_WORK_AREA + 8)
+  %define TDX_WORK_AREA_INFO            (TDX_WORK_AREA + 8 + 4)
   %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
 
   %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH V3 04/10] OvmfPkg: Add TDX_PT_ADDR defition in ResetVector.nasmb
       [not found] <cover.1627364332.git.min.m.xu@intel.com>
                   ` (2 preceding siblings ...)
  2021-07-27  5:42 ` [PATCH V3 03/10] OvmfPkg: Set TdMailbox initial value and macros Min Xu
@ 2021-07-27  5:42 ` Min Xu
  2021-07-27  5:42 ` [PATCH V3 05/10] OvmfPkg: Add IntelTdx.asm in ResetVector Min Xu
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 36+ messages in thread
From: Min Xu @ 2021-07-27  5:42 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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

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

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


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH V3 05/10] OvmfPkg: Add IntelTdx.asm in ResetVector
       [not found] <cover.1627364332.git.min.m.xu@intel.com>
                   ` (3 preceding siblings ...)
  2021-07-27  5:42 ` [PATCH V3 04/10] OvmfPkg: Add TDX_PT_ADDR defition in ResetVector.nasmb Min Xu
@ 2021-07-27  5:42 ` Min Xu
  2021-07-27  5:42 ` [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm " Min Xu
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 36+ messages in thread
From: Min Xu @ 2021-07-27  5:42 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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

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

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

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

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


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
       [not found] <cover.1627364332.git.min.m.xu@intel.com>
                   ` (4 preceding siblings ...)
  2021-07-27  5:42 ` [PATCH V3 05/10] OvmfPkg: Add IntelTdx.asm in ResetVector Min Xu
@ 2021-07-27  5:42 ` Min Xu
  2021-07-27 10:56   ` Brijesh Singh
  2021-07-27  5:42 ` [PATCH V3 07/10] OvmfPkg: Add ReloadFlat32 Min Xu
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 36+ messages in thread
From: Min Xu @ 2021-07-27  5:42 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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

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

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

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

diff --git a/OvmfPkg/ResetVector/Ia32/AmdSev.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
new file mode 100644
index 000000000000..962b7e169c61
--- /dev/null
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -0,0 +1,526 @@
+;------------------------------------------------------------------------------
+; @file
+; AMD SEV routines
+;
+; Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+
+BITS  32
+;
+; SEV-ES #VC exception handler support
+;
+; #VC handler local variable locations
+;
+%define VC_CPUID_RESULT_EAX         0
+%define VC_CPUID_RESULT_EBX         4
+%define VC_CPUID_RESULT_ECX         8
+%define VC_CPUID_RESULT_EDX        12
+%define VC_GHCB_MSR_EDX            16
+%define VC_GHCB_MSR_EAX            20
+%define VC_CPUID_REQUEST_REGISTER  24
+%define VC_CPUID_FUNCTION          28
+
+; #VC handler total local variable size
+;
+%define VC_VARIABLE_SIZE           32
+
+; #VC handler GHCB CPUID request/response protocol values
+;
+%define GHCB_CPUID_REQUEST          4
+%define GHCB_CPUID_RESPONSE         5
+%define GHCB_CPUID_REGISTER_SHIFT  30
+%define CPUID_INSN_LEN              2
+
+;
+; Check if Secure Encrypted Virtualization (SEV) features are enabled.
+;
+; Register usage is tight in this routine, so multiple calls for the
+; same CPUID and MSR data are performed to keep things simple.
+;
+; Modified:  EAX, EBX, ECX, EDX, ESP
+;
+; If SEV is enabled then EAX will be at least 32.
+; If SEV is disabled then EAX will be zero.
+;
+CheckSevFeatures:
+    ; Set the first byte of the workarea to zero to communicate to the SEC
+    ; phase that SEV-ES is not enabled. If SEV-ES is enabled, the CPUID
+    ; instruction will trigger a #VC exception where the first byte of the
+    ; workarea will be set to one or, if CPUID is not being intercepted,
+    ; the MSR check below will set the first byte of the workarea to one.
+    mov     byte[SEV_ES_WORK_AREA], 0
+
+    ;
+    ; Set up exception handlers to check for SEV-ES
+    ;   Load temporary RAM stack based on PCDs (see SevEsIdtVmmComm for
+    ;   stack usage)
+    ;   Establish exception handlers
+    ;
+    mov       esp, SEV_ES_VC_TOP_OF_STACK
+    mov       eax, ADDR_OF(Idtr)
+    lidt      [cs:eax]
+
+    ; Check if we have a valid (0x8000_001F) CPUID leaf
+    ;   CPUID raises a #VC exception if running as an SEV-ES guest
+    mov       eax, 0x80000000
+    cpuid
+
+    ; This check should fail on Intel or Non SEV AMD CPUs. In future if
+    ; Intel CPUs supports this CPUID leaf then we are guranteed to have exact
+    ; same bit definition.
+    cmp       eax, 0x8000001f
+    jl        NoSev
+
+    ; Check for SEV memory encryption feature:
+    ; CPUID  Fn8000_001F[EAX] - Bit 1
+    ;   CPUID raises a #VC exception if running as an SEV-ES guest
+    mov       eax, 0x8000001f
+    cpuid
+    bt        eax, 1
+    jnc       NoSev
+
+    ; Check if SEV memory encryption is enabled
+    ;  MSR_0xC0010131 - Bit 0 (SEV enabled)
+    mov       ecx, 0xc0010131
+    rdmsr
+    bt        eax, 0
+    jnc       NoSev
+
+    ; Check for SEV-ES memory encryption feature:
+    ; CPUID  Fn8000_001F[EAX] - Bit 3
+    ;   CPUID raises a #VC exception if running as an SEV-ES guest
+    mov       eax, 0x8000001f
+    cpuid
+    bt        eax, 3
+    jnc       GetSevEncBit
+
+    ; Check if SEV-ES is enabled
+    ;  MSR_0xC0010131 - Bit 1 (SEV-ES enabled)
+    mov       ecx, 0xc0010131
+    rdmsr
+    bt        eax, 1
+    jnc       GetSevEncBit
+
+    ; Set the first byte of the workarea to one to communicate to the SEC
+    ; phase that SEV-ES is enabled.
+    mov       byte[SEV_ES_WORK_AREA], 1
+
+GetSevEncBit:
+    ; Get pte bit position to enable memory encryption
+    ; CPUID Fn8000_001F[EBX] - Bits 5:0
+    ;
+    and       ebx, 0x3f
+    mov       eax, ebx
+
+    ; The encryption bit position is always above 31
+    sub       ebx, 32
+    jns       SevSaveMask
+
+    ; Encryption bit was reported as 31 or below, enter a HLT loop
+SevEncBitLowHlt:
+    cli
+    hlt
+    jmp       SevEncBitLowHlt
+
+SevSaveMask:
+    xor       edx, edx
+    bts       edx, ebx
+
+    mov       dword[SEV_ES_WORK_AREA_ENC_MASK], 0
+    mov       dword[SEV_ES_WORK_AREA_ENC_MASK + 4], edx
+    jmp       SevExit
+
+NoSev:
+    ;
+    ; Perform an SEV-ES sanity check by seeing if a #VC exception occurred.
+    ;
+    cmp       byte[SEV_ES_WORK_AREA], 0
+    jz        NoSevPass
+
+    ;
+    ; A #VC was received, yet CPUID indicates no SEV-ES support, something
+    ; isn't right.
+    ;
+NoSevEsVcHlt:
+    cli
+    hlt
+    jmp       NoSevEsVcHlt
+
+NoSevPass:
+    xor       eax, eax
+
+SevExit:
+    ;
+    ; Clear exception handlers and stack
+    ;
+    push      eax
+    mov       eax, ADDR_OF(IdtrClear)
+    lidt      [cs:eax]
+    pop       eax
+    mov       esp, 0
+
+    OneTimeCallRet CheckSevFeatures
+
+;
+; Called before SetCr3ForPageTables64 in SEV guests
+;
+; Modified: EAX, EBX, ECX, EDX, ESP
+;
+PreSetCr3ForPageTables64Sev:
+    ; In Tdx TDX_WORK_AREA was set to 'TDXG'.
+    ; CheckSevFeatures cannot be called in Tdx guest because SEV_ES_WORK_AREA
+    ; cannot be accessed in this situation. Any memory region to be accessed
+    ; in Td guest should be accepted first.
+    cmp     dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
+    jz      ExitPreSetCr3ForPageTables64Sev
+
+    OneTimeCall     CheckSevFeatures
+
+ExitPreSetCr3ForPageTables64Sev:
+    OneTimeCallRet  PreSetCr3ForPageTables64Sev
+
+;
+; It is called in SEV after SetCr3PageTables64
+;
+; Modified:  EAX, EBX, ECX, EDX, ESP
+;
+PostSetCr3PageTables64Sev:
+    ; In Tdx TDX_WORK_AREA was set to 'TDXG'.
+    ; CheckSevFeatures cannot be called in Tdx because SEV_ES_WORK_AREA
+    ; cannot be accessed in this situation. Any memory region to be accessed
+    ; in Td guest should be accepted first.
+    cmp     dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
+    jz      ExitPostSetCr3PageTables64Sev
+
+    mov     eax, cr4
+    bts     eax, 5                      ; enable PAE
+    mov     cr4, eax
+
+    mov     ecx, 0xc0000080
+    rdmsr
+    bts     eax, 8                      ; set LME
+    wrmsr
+
+    ;
+    ; SEV-ES mitigation check support
+    ;
+    xor     ebx, ebx
+
+    cmp     byte[SEV_ES_WORK_AREA], 0
+    jz      EnablePaging
+
+    ;
+    ; SEV-ES is active, perform a quick sanity check against the reported
+    ; encryption bit position. This is to help mitigate against attacks where
+    ; the hypervisor reports an incorrect encryption bit position.
+    ;
+    ; This is the first step in a two step process. Before paging is enabled
+    ; writes to memory are encrypted. Using the RDRAND instruction (available
+    ; on all SEV capable processors), write 64-bits of random data to the
+    ; SEV_ES_WORK_AREA and maintain the random data in registers (register
+    ; state is protected under SEV-ES). This will be used in the second step.
+    ;
+RdRand1:
+    rdrand  ecx
+    jnc     RdRand1
+    mov     dword[SEV_ES_WORK_AREA_RDRAND], ecx
+RdRand2:
+    rdrand  edx
+    jnc     RdRand2
+    mov     dword[SEV_ES_WORK_AREA_RDRAND + 4], edx
+
+    ;
+    ; Use EBX instead of the SEV_ES_WORK_AREA memory to determine whether to
+    ; perform the second step.
+    ;
+    mov     ebx, 1
+
+EnablePaging:
+    mov     eax, cr0
+    bts     eax, 31                     ; set PG
+    mov     cr0, eax                    ; enable paging
+
+ExitPostSetCr3PageTables64Sev:
+
+    OneTimeCallRet PostSetCr3PageTables64Sev
+
+;
+; Start of #VC exception handling routines
+;
+
+SevEsIdtNotCpuid:
+    ;
+    ; Use VMGEXIT to request termination.
+    ;   1 - #VC was not for CPUID
+    ;
+    mov     eax, 1
+    jmp     SevEsIdtTerminate
+
+SevEsIdtNoCpuidResponse:
+    ;
+    ; Use VMGEXIT to request termination.
+    ;   2 - GHCB_CPUID_RESPONSE not received
+    ;
+    mov     eax, 2
+
+SevEsIdtTerminate:
+    ;
+    ; Use VMGEXIT to request termination. At this point the reason code is
+    ; located in EAX, so shift it left 16 bits to the proper location.
+    ;
+    ; EAX[11:0]  => 0x100 - request termination
+    ; EAX[15:12] => 0x1   - OVMF
+    ; EAX[23:16] => 0xXX  - REASON CODE
+    ;
+    shl     eax, 16
+    or      eax, 0x1100
+    xor     edx, edx
+    mov     ecx, 0xc0010130
+    wrmsr
+    ;
+    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
+    ; mode, so work around this by temporarily switching to 64-bit mode.
+    ;
+BITS    64
+    rep     vmmcall
+BITS    32
+
+    ;
+    ; We shouldn't come back from the VMGEXIT, but if we do, just loop.
+    ;
+SevEsIdtHlt:
+    hlt
+    jmp     SevEsIdtHlt
+    iret
+
+    ;
+    ; Total stack usage for the #VC handler is 44 bytes:
+    ;   - 12 bytes for the exception IRET (after popping error code)
+    ;   - 32 bytes for the local variables.
+    ;
+SevEsIdtVmmComm:
+    ;
+    ; If we're here, then we are an SEV-ES guest and this
+    ; was triggered by a CPUID instruction
+    ;
+    ; Set the first byte of the workarea to one to communicate that
+    ; a #VC was taken.
+    mov     byte[SEV_ES_WORK_AREA], 1
+
+    pop     ecx                     ; Error code
+    cmp     ecx, 0x72               ; Be sure it was CPUID
+    jne     SevEsIdtNotCpuid
+
+    ; Set up local variable room on the stack
+    ;   CPUID function         : + 28
+    ;   CPUID request register : + 24
+    ;   GHCB MSR (EAX)         : + 20
+    ;   GHCB MSR (EDX)         : + 16
+    ;   CPUID result (EDX)     : + 12
+    ;   CPUID result (ECX)     : + 8
+    ;   CPUID result (EBX)     : + 4
+    ;   CPUID result (EAX)     : + 0
+    sub     esp, VC_VARIABLE_SIZE
+
+    ; Save the CPUID function being requested
+    mov     [esp + VC_CPUID_FUNCTION], eax
+
+    ; The GHCB CPUID protocol uses the following mapping to request
+    ; a specific register:
+    ;   0 => EAX, 1 => EBX, 2 => ECX, 3 => EDX
+    ;
+    ; Set EAX as the first register to request. This will also be used as a
+    ; loop variable to request all register values (EAX to EDX).
+    xor     eax, eax
+    mov     [esp + VC_CPUID_REQUEST_REGISTER], eax
+
+    ; Save current GHCB MSR value
+    mov     ecx, 0xc0010130
+    rdmsr
+    mov     [esp + VC_GHCB_MSR_EAX], eax
+    mov     [esp + VC_GHCB_MSR_EDX], edx
+
+NextReg:
+    ;
+    ; Setup GHCB MSR
+    ;   GHCB_MSR[63:32] = CPUID function
+    ;   GHCB_MSR[31:30] = CPUID register
+    ;   GHCB_MSR[11:0]  = CPUID request protocol
+    ;
+    mov     eax, [esp + VC_CPUID_REQUEST_REGISTER]
+    cmp     eax, 4
+    jge     VmmDone
+
+    shl     eax, GHCB_CPUID_REGISTER_SHIFT
+    or      eax, GHCB_CPUID_REQUEST
+    mov     edx, [esp + VC_CPUID_FUNCTION]
+    mov     ecx, 0xc0010130
+    wrmsr
+
+    ;
+    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
+    ; mode, so work around this by temporarily switching to 64-bit mode.
+    ;
+BITS    64
+    rep     vmmcall
+BITS    32
+
+    ;
+    ; Read GHCB MSR
+    ;   GHCB_MSR[63:32] = CPUID register value
+    ;   GHCB_MSR[31:30] = CPUID register
+    ;   GHCB_MSR[11:0]  = CPUID response protocol
+    ;
+    mov     ecx, 0xc0010130
+    rdmsr
+    mov     ecx, eax
+    and     ecx, 0xfff
+    cmp     ecx, GHCB_CPUID_RESPONSE
+    jne     SevEsIdtNoCpuidResponse
+
+    ; Save returned value
+    shr     eax, GHCB_CPUID_REGISTER_SHIFT
+    mov     [esp + eax * 4], edx
+
+    ; Next register
+    inc     word [esp + VC_CPUID_REQUEST_REGISTER]
+
+    jmp     NextReg
+
+VmmDone:
+    ;
+    ; At this point we have all CPUID register values. Restore the GHCB MSR,
+    ; set the return register values and return.
+    ;
+    mov     eax, [esp + VC_GHCB_MSR_EAX]
+    mov     edx, [esp + VC_GHCB_MSR_EDX]
+    mov     ecx, 0xc0010130
+    wrmsr
+
+    mov     eax, [esp + VC_CPUID_RESULT_EAX]
+    mov     ebx, [esp + VC_CPUID_RESULT_EBX]
+    mov     ecx, [esp + VC_CPUID_RESULT_ECX]
+    mov     edx, [esp + VC_CPUID_RESULT_EDX]
+
+    add     esp, VC_VARIABLE_SIZE
+
+    ; Update the EIP value to skip over the now handled CPUID instruction
+    ; (the CPUID instruction has a length of 2)
+    add     word [esp], CPUID_INSN_LEN
+    iret
+
+ALIGN   2
+
+Idtr:
+    dw      IDT_END - IDT_BASE - 1  ; Limit
+    dd      ADDR_OF(IDT_BASE)       ; Base
+
+IdtrClear:
+    dw      0                       ; Limit
+    dd      0                       ; Base
+
+ALIGN   16
+
+;
+; The Interrupt Descriptor Table (IDT)
+;   This will be used to determine if SEV-ES is enabled.  Upon execution
+;   of the CPUID instruction, a VMM Communication Exception will occur.
+;   This will tell us if SEV-ES is enabled.  We can use the current value
+;   of the GHCB MSR to determine the SEV attributes.
+;
+IDT_BASE:
+;
+; Vectors 0 - 28 (No handlers)
+;
+%rep 29
+    dw      0                                    ; Offset low bits 15..0
+    dw      0x10                                 ; Selector
+    db      0                                    ; Reserved
+    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
+    dw      0                                    ; Offset high bits 31..16
+%endrep
+;
+; Vector 29 (VMM Communication Exception)
+;
+    dw      (ADDR_OF(SevEsIdtVmmComm) & 0xffff)  ; Offset low bits 15..0
+    dw      0x10                                 ; Selector
+    db      0                                    ; Reserved
+    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
+    dw      (ADDR_OF(SevEsIdtVmmComm) >> 16)     ; Offset high bits 31..16
+;
+; Vectors 30 - 31 (No handlers)
+;
+%rep 2
+    dw      0                                    ; Offset low bits 15..0
+    dw      0x10                                 ; Selector
+    db      0                                    ; Reserved
+    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
+    dw      0                                    ; Offset high bits 31..16
+%endrep
+IDT_END:
+
+BITS 64
+
+;
+; Called after Jump64BitAndLandHere
+;
+PostJump64BitAndLandHereSev:
+
+    ;
+    ; If it is Tdx guest, jump to exit point directly.
+    ; This is because following code may access the memory region which has
+    ; not been accepted. It is not allowed in Tdx guests.
+    ;
+    mov     eax, dword[TDX_WORK_AREA]
+    cmp     eax, 0x47584454             ; 'TDXG'
+    jz      GoodCompare
+
+    ;
+    ; Check if the second step of the SEV-ES mitigation is to be performed.
+    ;
+    test    ebx, ebx
+    jz      InsnCompare
+
+    ;
+    ; SEV-ES is active, perform the second step of the encryption bit postion
+    ; mitigation check. The ECX and EDX register contain data from RDRAND that
+    ; was stored to memory in encrypted form. If the encryption bit position is
+    ; valid, the contents of ECX and EDX will match the memory location.
+    ;
+    cmp     dword[SEV_ES_WORK_AREA_RDRAND], ecx
+    jne     SevEncBitHlt
+    cmp     dword[SEV_ES_WORK_AREA_RDRAND + 4], edx
+    jne     SevEncBitHlt
+
+    ;
+    ; If SEV or SEV-ES is active, perform a quick sanity check against
+    ; the reported encryption bit position. This is to help mitigate
+    ; against attacks where the hypervisor reports an incorrect encryption
+    ; bit position. If SEV is not active, this check will always succeed.
+    ;
+    ; The cmp instruction compares the first four bytes of the cmp instruction
+    ; itself (which will be read decrypted if SEV or SEV-ES is active and the
+    ; encryption bit position is valid) against the immediate within the
+    ; instruction (an instruction fetch is always decrypted correctly by
+    ; hardware) based on RIP relative addressing.
+    ;
+InsnCompare:
+    cmp     dword[rel InsnCompare], 0xFFF63D81
+    je      GoodCompare
+
+    ;
+    ; The hypervisor provided an incorrect encryption bit position, do not
+    ; proceed.
+    ;
+SevEncBitHlt:
+    cli
+    hlt
+    jmp     SevEncBitHlt
+
+GoodCompare:
+    OneTimeCallRet PostJump64BitAndLandHereSev
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH V3 07/10] OvmfPkg: Add ReloadFlat32
       [not found] <cover.1627364332.git.min.m.xu@intel.com>
                   ` (5 preceding siblings ...)
  2021-07-27  5:42 ` [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm " Min Xu
@ 2021-07-27  5:42 ` Min Xu
  2021-07-27  5:42 ` [PATCH V3 08/10] OvmfPkg: Add Init32 Min Xu
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 36+ messages in thread
From: Min Xu @ 2021-07-27  5:42 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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

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

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


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH V3 08/10] OvmfPkg: Add Init32
       [not found] <cover.1627364332.git.min.m.xu@intel.com>
                   ` (6 preceding siblings ...)
  2021-07-27  5:42 ` [PATCH V3 07/10] OvmfPkg: Add ReloadFlat32 Min Xu
@ 2021-07-27  5:42 ` Min Xu
  2021-07-27  5:42 ` [PATCH V3 09/10] OvmfPkg: Create Main.asm in ResetVector Min Xu
  2021-07-27  5:42 ` [PATCH V3 10/10] OvmfPkg: Update ResetVector to support Tdx Min Xu
  9 siblings, 0 replies; 36+ messages in thread
From: Min Xu @ 2021-07-27  5:42 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

Init32.asm is the entry point of doing the 32-bit protected mode
initialization. Here ReloadFlat32 is called. After that InitTdx is called
to do Tdx initialization if it is Tdx guests. In the future if SEV has
something to initialize, InitSev (for example) can be called in Init32.

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

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


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH V3 09/10] OvmfPkg: Create Main.asm in ResetVector
       [not found] <cover.1627364332.git.min.m.xu@intel.com>
                   ` (7 preceding siblings ...)
  2021-07-27  5:42 ` [PATCH V3 08/10] OvmfPkg: Add Init32 Min Xu
@ 2021-07-27  5:42 ` Min Xu
  2021-07-27  5:42 ` [PATCH V3 10/10] OvmfPkg: Update ResetVector to support Tdx Min Xu
  9 siblings, 0 replies; 36+ messages in thread
From: Min Xu @ 2021-07-27  5:42 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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

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

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


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH V3 10/10] OvmfPkg: Update ResetVector to support Tdx
       [not found] <cover.1627364332.git.min.m.xu@intel.com>
                   ` (8 preceding siblings ...)
  2021-07-27  5:42 ` [PATCH V3 09/10] OvmfPkg: Create Main.asm in ResetVector Min Xu
@ 2021-07-27  5:42 ` Min Xu
  9 siblings, 0 replies; 36+ messages in thread
From: Min Xu @ 2021-07-27  5:42 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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

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

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

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

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

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

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

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

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

diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
index ac86ce69ebe8..a390ed81d021 100644
--- a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
+++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
@@ -155,10 +155,31 @@ resetVector:
 ;
 ; This is where the processor will begin execution
 ;
+; In IA32 we follow the standard reset vector flow. While in X64, Td guest
+; may be supported. Td guest requires the startup mode to be 32-bit
+; protected mode but the legacy VM startup mode is 16-bit real mode.
+; To make NASM generate such shared entry code that behaves correctly in
+; both 16-bit and 32-bit mode, more BITS directives are added.
+;
+%ifdef ARCH_IA32
+
     nop
     nop
     jmp     EarlyBspInitReal16
 
+%else
+
+    smsw    ax
+    test    al, 1
+    jz      .Real
+BITS 32
+    jmp     Main32
+BITS 16
+.Real:
+    jmp     EarlyBspInitReal16
+
+%endif
+
 ALIGN   16
 
 fourGigabytes:
diff --git a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
index c6d0d898bcd1..40cf6cea55bb 100644
--- a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
+++ b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
@@ -11,107 +11,39 @@
 BITS    32
 
 ;
-; Modified:  EAX, ECX, EDX
+; Transition from 32 bit flat protected mode into 64 bit flag protected mode
+;
+; To handle the situations of Tdx/SEV/Legacy guests, Pre/Post routines are
+; called. For example, SevPreSetCr3ForPageTables64 check the Sev features
+; and set the EAX value. TdxPostSetCr3PageTables64 set the CR0/CR4 and adjust
+; the CR3 if GPAW is 52.
+;
+; But in Tdx guest, memory region cannot be accessed before it is accepted
+; (except the case that the memory region is initialized by host VMM before
+; the guest is launched.) So in the beginning of Pre/Post routines it would
+; check if it is Tdx guest by checking the TDX_WORK_AREA.
+;
+; Modified:  EAX, EBX, ECX, EDX, ESP
 ;
 Transition32FlatTo64Flat:
 
+    OneTimeCall PreSetCr3ForPageTables64Sev
+
+SetPageTables64:
     OneTimeCall SetCr3ForPageTables64
 
-    mov     eax, cr4
-    bts     eax, 5                      ; enable PAE
-    mov     cr4, eax
+    OneTimeCall PostSetCr3PageTables64Tdx
 
-    mov     ecx, 0xc0000080
-    rdmsr
-    bts     eax, 8                      ; set LME
-    wrmsr
-
-    ;
-    ; SEV-ES mitigation check support
-    ;
-    xor     ebx, ebx
-
-    cmp     byte[SEV_ES_WORK_AREA], 0
-    jz      EnablePaging
-
-    ;
-    ; SEV-ES is active, perform a quick sanity check against the reported
-    ; encryption bit position. This is to help mitigate against attacks where
-    ; the hypervisor reports an incorrect encryption bit position.
-    ;
-    ; This is the first step in a two step process. Before paging is enabled
-    ; writes to memory are encrypted. Using the RDRAND instruction (available
-    ; on all SEV capable processors), write 64-bits of random data to the
-    ; SEV_ES_WORK_AREA and maintain the random data in registers (register
-    ; state is protected under SEV-ES). This will be used in the second step.
-    ;
-RdRand1:
-    rdrand  ecx
-    jnc     RdRand1
-    mov     dword[SEV_ES_WORK_AREA_RDRAND], ecx
-RdRand2:
-    rdrand  edx
-    jnc     RdRand2
-    mov     dword[SEV_ES_WORK_AREA_RDRAND + 4], edx
-
-    ;
-    ; Use EBX instead of the SEV_ES_WORK_AREA memory to determine whether to
-    ; perform the second step.
-    ;
-    mov     ebx, 1
-
-EnablePaging:
-    mov     eax, cr0
-    bts     eax, 31                     ; set PG
-    mov     cr0, eax                    ; enable paging
+    OneTimeCall PostSetCr3PageTables64Sev
 
     jmp     LINEAR_CODE64_SEL:ADDR_OF(jumpTo64BitAndLandHere)
+
 BITS    64
+
 jumpTo64BitAndLandHere:
 
-    ;
-    ; Check if the second step of the SEV-ES mitigation is to be performed.
-    ;
-    test    ebx, ebx
-    jz      InsnCompare
+    OneTimeCall PostJump64BitAndLandHereSev
 
-    ;
-    ; SEV-ES is active, perform the second step of the encryption bit postion
-    ; mitigation check. The ECX and EDX register contain data from RDRAND that
-    ; was stored to memory in encrypted form. If the encryption bit position is
-    ; valid, the contents of ECX and EDX will match the memory location.
-    ;
-    cmp     dword[SEV_ES_WORK_AREA_RDRAND], ecx
-    jne     SevEncBitHlt
-    cmp     dword[SEV_ES_WORK_AREA_RDRAND + 4], edx
-    jne     SevEncBitHlt
-
-    ;
-    ; If SEV or SEV-ES is active, perform a quick sanity check against
-    ; the reported encryption bit position. This is to help mitigate
-    ; against attacks where the hypervisor reports an incorrect encryption
-    ; bit position. If SEV is not active, this check will always succeed.
-    ;
-    ; The cmp instruction compares the first four bytes of the cmp instruction
-    ; itself (which will be read decrypted if SEV or SEV-ES is active and the
-    ; encryption bit position is valid) against the immediate within the
-    ; instruction (an instruction fetch is always decrypted correctly by
-    ; hardware) based on RIP relative addressing.
-    ;
-InsnCompare:
-    cmp     dword[rel InsnCompare], 0xFFF63D81
-    je      GoodCompare
-
-    ;
-    ; The hypervisor provided an incorrect encryption bit position, do not
-    ; proceed.
-    ;
-SevEncBitHlt:
-    cli
-    hlt
-    jmp     SevEncBitHlt
-
-GoodCompare:
     debugShowPostCode POSTCODE_64BIT_MODE
 
     OneTimeCallRet Transition32FlatTo64Flat
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index 5fae8986d9da..ac365b114ee5 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -36,198 +36,97 @@ BITS    32
 %define PAGE_PDP_ATTR (PAGE_ACCESSED + \
                        PAGE_READ_WRITE + \
                        PAGE_PRESENT)
-
-;
-; SEV-ES #VC exception handler support
-;
-; #VC handler local variable locations
-;
-%define VC_CPUID_RESULT_EAX         0
-%define VC_CPUID_RESULT_EBX         4
-%define VC_CPUID_RESULT_ECX         8
-%define VC_CPUID_RESULT_EDX        12
-%define VC_GHCB_MSR_EDX            16
-%define VC_GHCB_MSR_EAX            20
-%define VC_CPUID_REQUEST_REGISTER  24
-%define VC_CPUID_FUNCTION          28
-
-; #VC handler total local variable size
-;
-%define VC_VARIABLE_SIZE           32
-
-; #VC handler GHCB CPUID request/response protocol values
-;
-%define GHCB_CPUID_REQUEST          4
-%define GHCB_CPUID_RESPONSE         5
-%define GHCB_CPUID_REGISTER_SHIFT  30
-%define CPUID_INSN_LEN              2
-
-
-; Check if Secure Encrypted Virtualization (SEV) features are enabled.
-;
-; Register usage is tight in this routine, so multiple calls for the
-; same CPUID and MSR data are performed to keep things simple.
-;
-; Modified:  EAX, EBX, ECX, EDX, ESP
 ;
-; If SEV is enabled then EAX will be at least 32.
-; If SEV is disabled then EAX will be zero.
+; Extra page tables built by Tdx guests
 ;
-CheckSevFeatures:
-    ; Set the first byte of the workarea to zero to communicate to the SEC
-    ; phase that SEV-ES is not enabled. If SEV-ES is enabled, the CPUID
-    ; instruction will trigger a #VC exception where the first byte of the
-    ; workarea will be set to one or, if CPUID is not being intercepted,
-    ; the MSR check below will set the first byte of the workarea to one.
-    mov     byte[SEV_ES_WORK_AREA], 0
+TdxBuildExtraPageTables:
+    xor     eax, eax
+    mov     ecx, 0x400
+tdClearTdxPageTablesMemoryLoop:
+    mov     dword [ecx * 4 + TDX_PT_ADDR (0) - 4], eax
+    loop    tdClearTdxPageTablesMemoryLoop
 
+    ;xor     edx, edx
     ;
-    ; Set up exception handlers to check for SEV-ES
-    ;   Load temporary RAM stack based on PCDs (see SevEsIdtVmmComm for
-    ;   stack usage)
-    ;   Establish exception handlers
-    ;
-    mov       esp, SEV_ES_VC_TOP_OF_STACK
-    mov       eax, ADDR_OF(Idtr)
-    lidt      [cs:eax]
-
-    ; Check if we have a valid (0x8000_001F) CPUID leaf
-    ;   CPUID raises a #VC exception if running as an SEV-ES guest
-    mov       eax, 0x80000000
-    cpuid
-
-    ; This check should fail on Intel or Non SEV AMD CPUs. In future if
-    ; Intel CPUs supports this CPUID leaf then we are guranteed to have exact
-    ; same bit definition.
-    cmp       eax, 0x8000001f
-    jl        NoSev
-
-    ; Check for SEV memory encryption feature:
-    ; CPUID  Fn8000_001F[EAX] - Bit 1
-    ;   CPUID raises a #VC exception if running as an SEV-ES guest
-    mov       eax, 0x8000001f
-    cpuid
-    bt        eax, 1
-    jnc       NoSev
-
-    ; Check if SEV memory encryption is enabled
-    ;  MSR_0xC0010131 - Bit 0 (SEV enabled)
-    mov       ecx, 0xc0010131
-    rdmsr
-    bt        eax, 0
-    jnc       NoSev
-
-    ; Check for SEV-ES memory encryption feature:
-    ; CPUID  Fn8000_001F[EAX] - Bit 3
-    ;   CPUID raises a #VC exception if running as an SEV-ES guest
-    mov       eax, 0x8000001f
-    cpuid
-    bt        eax, 3
-    jnc       GetSevEncBit
-
-    ; Check if SEV-ES is enabled
-    ;  MSR_0xC0010131 - Bit 1 (SEV-ES enabled)
-    mov       ecx, 0xc0010131
-    rdmsr
-    bt        eax, 1
-    jnc       GetSevEncBit
-
-    ; Set the first byte of the workarea to one to communicate to the SEC
-    ; phase that SEV-ES is enabled.
-    mov       byte[SEV_ES_WORK_AREA], 1
-
-GetSevEncBit:
-    ; Get pte bit position to enable memory encryption
-    ; CPUID Fn8000_001F[EBX] - Bits 5:0
+    ; Top level Page Directory Pointers (1 * 256TB entry)
     ;
-    and       ebx, 0x3f
-    mov       eax, ebx
-
-    ; The encryption bit position is always above 31
-    sub       ebx, 32
-    jns       SevSaveMask
+    mov     dword[TDX_PT_ADDR (0)], PT_ADDR (0) + PAGE_PDP_ATTR
+    ;mov     dword[TDX_PT_ADDR (4)], edx
 
-    ; Encryption bit was reported as 31 or below, enter a HLT loop
-SevEncBitLowHlt:
-    cli
-    hlt
-    jmp       SevEncBitLowHlt
+    mov     byte[TDX_WORK_AREA_PGTBL_READY], 1
 
-SevSaveMask:
-    xor       edx, edx
-    bts       edx, ebx
+    OneTimeCallRet TdxBuildExtraPageTables
 
-    mov       dword[SEV_ES_WORK_AREA_ENC_MASK], 0
-    mov       dword[SEV_ES_WORK_AREA_ENC_MASK + 4], edx
-    jmp       SevExit
-
-NoSev:
+;
+; Ghcb page tables built by SEV
+;
+SevBuildGhcbPageTables:
     ;
-    ; Perform an SEV-ES sanity check by seeing if a #VC exception occurred.
+    ; The initial GHCB will live at GHCB_BASE and needs to be un-encrypted.
+    ; This requires the 2MB page for this range be broken down into 512 4KB
+    ; pages.  All will be marked encrypted, except for the GHCB.
     ;
-    cmp       byte[SEV_ES_WORK_AREA], 0
-    jz        NoSevPass
+    mov     ecx, (GHCB_BASE >> 21)
+    mov     eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
+    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
 
     ;
-    ; A #VC was received, yet CPUID indicates no SEV-ES support, something
-    ; isn't right.
+    ; Page Table Entries (512 * 4KB entries => 2MB)
     ;
-NoSevEsVcHlt:
-    cli
-    hlt
-    jmp       NoSevEsVcHlt
-
-NoSevPass:
-    xor       eax, eax
+    mov     ecx, 512
+pageTableEntries4kLoop:
+    mov     eax, ecx
+    dec     eax
+    shl     eax, 12
+    add     eax, GHCB_BASE & 0xFFE0_0000
+    add     eax, PAGE_4K_PDE_ATTR
+    mov     [ecx * 8 + GHCB_PT_ADDR - 8], eax
+    mov     [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx
+    loop    pageTableEntries4kLoop
 
-SevExit:
     ;
-    ; Clear exception handlers and stack
+    ; Clear the encryption bit from the GHCB entry
     ;
-    push      eax
-    mov       eax, ADDR_OF(IdtrClear)
-    lidt      [cs:eax]
-    pop       eax
-    mov       esp, 0
-
-    OneTimeCallRet CheckSevFeatures
-
-; Check if Secure Encrypted Virtualization - Encrypted State (SEV-ES) feature
-; is enabled.
-;
-; Modified:  EAX
-;
-; If SEV-ES is enabled then EAX will be non-zero.
-; If SEV-ES is disabled then EAX will be zero.
-;
-IsSevEsEnabled:
-    xor       eax, eax
-
-    ; During CheckSevFeatures, the SEV_ES_WORK_AREA was set to 1 if
-    ; SEV-ES is enabled.
-    cmp       byte[SEV_ES_WORK_AREA], 1
-    jne       SevEsDisabled
+    mov     ecx, (GHCB_BASE & 0x1F_FFFF) >> 12
+    mov     [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0
 
-    mov       eax, 1
+    mov     ecx, GHCB_SIZE / 4
+    xor     eax, eax
+clearGhcbMemoryLoop:
+    mov     dword[ecx * 4 + GHCB_BASE - 4], eax
+    loop    clearGhcbMemoryLoop
 
-SevEsDisabled:
-    OneTimeCallRet IsSevEsEnabled
+    OneTimeCallRet  SevBuildGhcbPageTables
 
 ;
 ; Modified:  EAX, EBX, ECX, EDX
 ;
 SetCr3ForPageTables64:
 
-    OneTimeCall   CheckSevFeatures
     xor     edx, edx
+
+CheckTdx:
+    cmp     dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
+    jnz     CheckSev
+
+    ;
+    ; In Td guest, BSP builds the page table and set the flag of
+    ; TDX_WORK_AREA_PGTBL_READY. APs check this flag and then set
+    ; cr3 directly.
+    ;
+    cmp     byte[TDX_WORK_AREA_PGTBL_READY], 1
+    jz      SetCr3
+    jmp     BuildPageTables
+
+CheckSev:
     test    eax, eax
-    jz      SevNotActive
+    jz      BuildPageTables
 
     ; If SEV is enabled, C-bit is always above 31
     sub     eax, 32
     bts     edx, eax
 
-SevNotActive:
+BuildPageTables:
 
     ;
     ; For OVMF, build some initial page tables at
@@ -277,44 +176,22 @@ pageTableEntriesLoop:
     mov     [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
     loop    pageTableEntriesLoop
 
-    OneTimeCall   IsSevEsEnabled
-    test    eax, eax
-    jz      SetCr3
-
     ;
-    ; The initial GHCB will live at GHCB_BASE and needs to be un-encrypted.
-    ; This requires the 2MB page for this range be broken down into 512 4KB
-    ; pages.  All will be marked encrypted, except for the GHCB.
+    ; If it is Td guest, TdxExtraPageTable should be initialized as well
     ;
-    mov     ecx, (GHCB_BASE >> 21)
-    mov     eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
-    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
+    cmp     dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
+    jnz     IsSevEs
 
-    ;
-    ; Page Table Entries (512 * 4KB entries => 2MB)
-    ;
-    mov     ecx, 512
-pageTableEntries4kLoop:
-    mov     eax, ecx
-    dec     eax
-    shl     eax, 12
-    add     eax, GHCB_BASE & 0xFFE0_0000
-    add     eax, PAGE_4K_PDE_ATTR
-    mov     [ecx * 8 + GHCB_PT_ADDR - 8], eax
-    mov     [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx
-    loop    pageTableEntries4kLoop
+    OneTimeCall TdxBuildExtraPageTables
+    jmp     SetCr3
 
-    ;
-    ; Clear the encryption bit from the GHCB entry
-    ;
-    mov     ecx, (GHCB_BASE & 0x1F_FFFF) >> 12
-    mov     [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0
+IsSevEs:
+    ; During CheckSevFeatures, the SEV_ES_WORK_AREA was set to 1 if
+    ; SEV-ES is enabled.
+    cmp       byte[SEV_ES_WORK_AREA], 1
+    jne       SetCr3
 
-    mov     ecx, GHCB_SIZE / 4
-    xor     eax, eax
-clearGhcbMemoryLoop:
-    mov     dword[ecx * 4 + GHCB_BASE - 4], eax
-    loop    clearGhcbMemoryLoop
+    OneTimeCall SevBuildGhcbPageTables
 
 SetCr3:
     ;
@@ -325,217 +202,4 @@ SetCr3:
 
     OneTimeCallRet SetCr3ForPageTables64
 
-;
-; Start of #VC exception handling routines
-;
 
-SevEsIdtNotCpuid:
-    ;
-    ; Use VMGEXIT to request termination.
-    ;   1 - #VC was not for CPUID
-    ;
-    mov     eax, 1
-    jmp     SevEsIdtTerminate
-
-SevEsIdtNoCpuidResponse:
-    ;
-    ; Use VMGEXIT to request termination.
-    ;   2 - GHCB_CPUID_RESPONSE not received
-    ;
-    mov     eax, 2
-
-SevEsIdtTerminate:
-    ;
-    ; Use VMGEXIT to request termination. At this point the reason code is
-    ; located in EAX, so shift it left 16 bits to the proper location.
-    ;
-    ; EAX[11:0]  => 0x100 - request termination
-    ; EAX[15:12] => 0x1   - OVMF
-    ; EAX[23:16] => 0xXX  - REASON CODE
-    ;
-    shl     eax, 16
-    or      eax, 0x1100
-    xor     edx, edx
-    mov     ecx, 0xc0010130
-    wrmsr
-    ;
-    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
-    ; mode, so work around this by temporarily switching to 64-bit mode.
-    ;
-BITS    64
-    rep     vmmcall
-BITS    32
-
-    ;
-    ; We shouldn't come back from the VMGEXIT, but if we do, just loop.
-    ;
-SevEsIdtHlt:
-    hlt
-    jmp     SevEsIdtHlt
-    iret
-
-    ;
-    ; Total stack usage for the #VC handler is 44 bytes:
-    ;   - 12 bytes for the exception IRET (after popping error code)
-    ;   - 32 bytes for the local variables.
-    ;
-SevEsIdtVmmComm:
-    ;
-    ; If we're here, then we are an SEV-ES guest and this
-    ; was triggered by a CPUID instruction
-    ;
-    ; Set the first byte of the workarea to one to communicate that
-    ; a #VC was taken.
-    mov     byte[SEV_ES_WORK_AREA], 1
-
-    pop     ecx                     ; Error code
-    cmp     ecx, 0x72               ; Be sure it was CPUID
-    jne     SevEsIdtNotCpuid
-
-    ; Set up local variable room on the stack
-    ;   CPUID function         : + 28
-    ;   CPUID request register : + 24
-    ;   GHCB MSR (EAX)         : + 20
-    ;   GHCB MSR (EDX)         : + 16
-    ;   CPUID result (EDX)     : + 12
-    ;   CPUID result (ECX)     : + 8
-    ;   CPUID result (EBX)     : + 4
-    ;   CPUID result (EAX)     : + 0
-    sub     esp, VC_VARIABLE_SIZE
-
-    ; Save the CPUID function being requested
-    mov     [esp + VC_CPUID_FUNCTION], eax
-
-    ; The GHCB CPUID protocol uses the following mapping to request
-    ; a specific register:
-    ;   0 => EAX, 1 => EBX, 2 => ECX, 3 => EDX
-    ;
-    ; Set EAX as the first register to request. This will also be used as a
-    ; loop variable to request all register values (EAX to EDX).
-    xor     eax, eax
-    mov     [esp + VC_CPUID_REQUEST_REGISTER], eax
-
-    ; Save current GHCB MSR value
-    mov     ecx, 0xc0010130
-    rdmsr
-    mov     [esp + VC_GHCB_MSR_EAX], eax
-    mov     [esp + VC_GHCB_MSR_EDX], edx
-
-NextReg:
-    ;
-    ; Setup GHCB MSR
-    ;   GHCB_MSR[63:32] = CPUID function
-    ;   GHCB_MSR[31:30] = CPUID register
-    ;   GHCB_MSR[11:0]  = CPUID request protocol
-    ;
-    mov     eax, [esp + VC_CPUID_REQUEST_REGISTER]
-    cmp     eax, 4
-    jge     VmmDone
-
-    shl     eax, GHCB_CPUID_REGISTER_SHIFT
-    or      eax, GHCB_CPUID_REQUEST
-    mov     edx, [esp + VC_CPUID_FUNCTION]
-    mov     ecx, 0xc0010130
-    wrmsr
-
-    ;
-    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
-    ; mode, so work around this by temporarily switching to 64-bit mode.
-    ;
-BITS    64
-    rep     vmmcall
-BITS    32
-
-    ;
-    ; Read GHCB MSR
-    ;   GHCB_MSR[63:32] = CPUID register value
-    ;   GHCB_MSR[31:30] = CPUID register
-    ;   GHCB_MSR[11:0]  = CPUID response protocol
-    ;
-    mov     ecx, 0xc0010130
-    rdmsr
-    mov     ecx, eax
-    and     ecx, 0xfff
-    cmp     ecx, GHCB_CPUID_RESPONSE
-    jne     SevEsIdtNoCpuidResponse
-
-    ; Save returned value
-    shr     eax, GHCB_CPUID_REGISTER_SHIFT
-    mov     [esp + eax * 4], edx
-
-    ; Next register
-    inc     word [esp + VC_CPUID_REQUEST_REGISTER]
-
-    jmp     NextReg
-
-VmmDone:
-    ;
-    ; At this point we have all CPUID register values. Restore the GHCB MSR,
-    ; set the return register values and return.
-    ;
-    mov     eax, [esp + VC_GHCB_MSR_EAX]
-    mov     edx, [esp + VC_GHCB_MSR_EDX]
-    mov     ecx, 0xc0010130
-    wrmsr
-
-    mov     eax, [esp + VC_CPUID_RESULT_EAX]
-    mov     ebx, [esp + VC_CPUID_RESULT_EBX]
-    mov     ecx, [esp + VC_CPUID_RESULT_ECX]
-    mov     edx, [esp + VC_CPUID_RESULT_EDX]
-
-    add     esp, VC_VARIABLE_SIZE
-
-    ; Update the EIP value to skip over the now handled CPUID instruction
-    ; (the CPUID instruction has a length of 2)
-    add     word [esp], CPUID_INSN_LEN
-    iret
-
-ALIGN   2
-
-Idtr:
-    dw      IDT_END - IDT_BASE - 1  ; Limit
-    dd      ADDR_OF(IDT_BASE)       ; Base
-
-IdtrClear:
-    dw      0                       ; Limit
-    dd      0                       ; Base
-
-ALIGN   16
-
-;
-; The Interrupt Descriptor Table (IDT)
-;   This will be used to determine if SEV-ES is enabled.  Upon execution
-;   of the CPUID instruction, a VMM Communication Exception will occur.
-;   This will tell us if SEV-ES is enabled.  We can use the current value
-;   of the GHCB MSR to determine the SEV attributes.
-;
-IDT_BASE:
-;
-; Vectors 0 - 28 (No handlers)
-;
-%rep 29
-    dw      0                                    ; Offset low bits 15..0
-    dw      0x10                                 ; Selector
-    db      0                                    ; Reserved
-    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
-    dw      0                                    ; Offset high bits 31..16
-%endrep
-;
-; Vector 29 (VMM Communication Exception)
-;
-    dw      (ADDR_OF(SevEsIdtVmmComm) & 0xffff)  ; Offset low bits 15..0
-    dw      0x10                                 ; Selector
-    db      0                                    ; Reserved
-    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
-    dw      (ADDR_OF(SevEsIdtVmmComm) >> 16)     ; Offset high bits 31..16
-;
-; Vectors 30 - 31 (No handlers)
-;
-%rep 2
-    dw      0                                    ; Offset low bits 15..0
-    dw      0x10                                 ; Selector
-    db      0                                    ; Reserved
-    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
-    dw      0                                    ; Offset high bits 31..16
-%endrep
-IDT_END:
diff --git a/OvmfPkg/ResetVector/Main.asm b/OvmfPkg/ResetVector/Main.asm
index dbebfb9e5d29..0418e0294920 100644
--- a/OvmfPkg/ResetVector/Main.asm
+++ b/OvmfPkg/ResetVector/Main.asm
@@ -36,6 +36,20 @@ Main16:
 
 BITS    32
 
+%ifdef ARCH_X64
+
+    jmp SearchBfv
+
+;
+; Entry point of Main32
+;
+Main32:
+
+    OneTimeCall Init32
+
+%endif
+
+SearchBfv:
     ;
     ; Search for the Boot Firmware Volume (BFV)
     ;
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 0ac6d7a6fd33..ade8ce6f08a5 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -132,6 +132,10 @@
   %define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
 
   %include "X64/TdxMetadata.asm"
+  %include "Ia32/Init32.asm"
+  %include "Ia32/IntelTdx.asm"
+  %include "Ia32/AmdSev.asm"
+  %include "Ia32/ReloadFlat32.asm"
 
   %include "Ia32/Flat32ToFlat64.asm"
   %include "Ia32/PageTables64.asm"
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-27  5:42 ` [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm " Min Xu
@ 2021-07-27 10:56   ` Brijesh Singh
  2021-07-27 11:51     ` Min Xu
  0 siblings, 1 reply; 36+ messages in thread
From: Brijesh Singh @ 2021-07-27 10:56 UTC (permalink / raw)
  To: Min Xu, devel
  Cc: brijesh.singh, Ard Biesheuvel, Jordan Justen, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

Hi Min,

This refactoring is already done by the SNP patch series.

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

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

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

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

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

thanks


On 7/27/21 12:42 AM, Min Xu wrote:
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
>
> AmdSev.asm includes below routines:
>  - CheckSevFeatures
>    Check if Secure Encrypted Virtualization (SEV) features are enabled.
>  - PreSetCr3ForPageTables64Sev
>    It is called before SetCr3ForPageTables64 in SEV guests.
>  - PostSetCr3PageTables64Sev
>    It is called after SetCr3PageTables64 in SEV guests.
>  - PostJump64BitAndLandHereSev
>    It is called after Jump64BitAndLandHere in SEV guests.
>  - #VC exception handling routines
>
> These routines are extracted from PageTables64.asm and Flat32ToFlat64.asm
> Need AMD engineers' help to review/validate the patch so that there is
> no regression. Thanks in advance!
>
> Note:
>   In above Pre/Post routines, dword[TDX_WORK_AREA] should be checked
>   to see if it is 'TDXG' (Tdx guests). This is because some memory region
>   for example, byte[SEV_ES_WORK_AREA] cannot be accessed in Tdx guests.
>   Tdx requires that any memory region to be accessed should be accepted
>   first or initialized by host VMM before Td guest is launched.
>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Brijesh Singh <brijesh.singh@amd.com>
> Cc: Erdem Aktas <erdemaktas@google.com>
> Cc: James Bottomley <jejb@linux.ibm.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Tom Lendacky <thomas.lendacky@amd.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>
> ---
>  OvmfPkg/ResetVector/Ia32/AmdSev.asm | 526 ++++++++++++++++++++++++++++
>  1 file changed, 526 insertions(+)
>  create mode 100644 OvmfPkg/ResetVector/Ia32/AmdSev.asm
>
> diff --git a/OvmfPkg/ResetVector/Ia32/AmdSev.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
> new file mode 100644
> index 000000000000..962b7e169c61
> --- /dev/null
> +++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
> @@ -0,0 +1,526 @@
> +;------------------------------------------------------------------------------
> +; @file
> +; AMD SEV routines
> +;
> +; Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
> +; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +;
> +; SPDX-License-Identifier: BSD-2-Clause-Patent
> +;
> +;------------------------------------------------------------------------------
> +
> +
> +BITS  32
> +;
> +; SEV-ES #VC exception handler support
> +;
> +; #VC handler local variable locations
> +;
> +%define VC_CPUID_RESULT_EAX         0
> +%define VC_CPUID_RESULT_EBX         4
> +%define VC_CPUID_RESULT_ECX         8
> +%define VC_CPUID_RESULT_EDX        12
> +%define VC_GHCB_MSR_EDX            16
> +%define VC_GHCB_MSR_EAX            20
> +%define VC_CPUID_REQUEST_REGISTER  24
> +%define VC_CPUID_FUNCTION          28
> +
> +; #VC handler total local variable size
> +;
> +%define VC_VARIABLE_SIZE           32
> +
> +; #VC handler GHCB CPUID request/response protocol values
> +;
> +%define GHCB_CPUID_REQUEST          4
> +%define GHCB_CPUID_RESPONSE         5
> +%define GHCB_CPUID_REGISTER_SHIFT  30
> +%define CPUID_INSN_LEN              2
> +
> +;
> +; Check if Secure Encrypted Virtualization (SEV) features are enabled.
> +;
> +; Register usage is tight in this routine, so multiple calls for the
> +; same CPUID and MSR data are performed to keep things simple.
> +;
> +; Modified:  EAX, EBX, ECX, EDX, ESP
> +;
> +; If SEV is enabled then EAX will be at least 32.
> +; If SEV is disabled then EAX will be zero.
> +;
> +CheckSevFeatures:
> +    ; Set the first byte of the workarea to zero to communicate to the SEC
> +    ; phase that SEV-ES is not enabled. If SEV-ES is enabled, the CPUID
> +    ; instruction will trigger a #VC exception where the first byte of the
> +    ; workarea will be set to one or, if CPUID is not being intercepted,
> +    ; the MSR check below will set the first byte of the workarea to one.
> +    mov     byte[SEV_ES_WORK_AREA], 0
> +
> +    ;
> +    ; Set up exception handlers to check for SEV-ES
> +    ;   Load temporary RAM stack based on PCDs (see SevEsIdtVmmComm for
> +    ;   stack usage)
> +    ;   Establish exception handlers
> +    ;
> +    mov       esp, SEV_ES_VC_TOP_OF_STACK
> +    mov       eax, ADDR_OF(Idtr)
> +    lidt      [cs:eax]
> +
> +    ; Check if we have a valid (0x8000_001F) CPUID leaf
> +    ;   CPUID raises a #VC exception if running as an SEV-ES guest
> +    mov       eax, 0x80000000
> +    cpuid
> +
> +    ; This check should fail on Intel or Non SEV AMD CPUs. In future if
> +    ; Intel CPUs supports this CPUID leaf then we are guranteed to have exact
> +    ; same bit definition.
> +    cmp       eax, 0x8000001f
> +    jl        NoSev
> +
> +    ; Check for SEV memory encryption feature:
> +    ; CPUID  Fn8000_001F[EAX] - Bit 1
> +    ;   CPUID raises a #VC exception if running as an SEV-ES guest
> +    mov       eax, 0x8000001f
> +    cpuid
> +    bt        eax, 1
> +    jnc       NoSev
> +
> +    ; Check if SEV memory encryption is enabled
> +    ;  MSR_0xC0010131 - Bit 0 (SEV enabled)
> +    mov       ecx, 0xc0010131
> +    rdmsr
> +    bt        eax, 0
> +    jnc       NoSev
> +
> +    ; Check for SEV-ES memory encryption feature:
> +    ; CPUID  Fn8000_001F[EAX] - Bit 3
> +    ;   CPUID raises a #VC exception if running as an SEV-ES guest
> +    mov       eax, 0x8000001f
> +    cpuid
> +    bt        eax, 3
> +    jnc       GetSevEncBit
> +
> +    ; Check if SEV-ES is enabled
> +    ;  MSR_0xC0010131 - Bit 1 (SEV-ES enabled)
> +    mov       ecx, 0xc0010131
> +    rdmsr
> +    bt        eax, 1
> +    jnc       GetSevEncBit
> +
> +    ; Set the first byte of the workarea to one to communicate to the SEC
> +    ; phase that SEV-ES is enabled.
> +    mov       byte[SEV_ES_WORK_AREA], 1
> +
> +GetSevEncBit:
> +    ; Get pte bit position to enable memory encryption
> +    ; CPUID Fn8000_001F[EBX] - Bits 5:0
> +    ;
> +    and       ebx, 0x3f
> +    mov       eax, ebx
> +
> +    ; The encryption bit position is always above 31
> +    sub       ebx, 32
> +    jns       SevSaveMask
> +
> +    ; Encryption bit was reported as 31 or below, enter a HLT loop
> +SevEncBitLowHlt:
> +    cli
> +    hlt
> +    jmp       SevEncBitLowHlt
> +
> +SevSaveMask:
> +    xor       edx, edx
> +    bts       edx, ebx
> +
> +    mov       dword[SEV_ES_WORK_AREA_ENC_MASK], 0
> +    mov       dword[SEV_ES_WORK_AREA_ENC_MASK + 4], edx
> +    jmp       SevExit
> +
> +NoSev:
> +    ;
> +    ; Perform an SEV-ES sanity check by seeing if a #VC exception occurred.
> +    ;
> +    cmp       byte[SEV_ES_WORK_AREA], 0
> +    jz        NoSevPass
> +
> +    ;
> +    ; A #VC was received, yet CPUID indicates no SEV-ES support, something
> +    ; isn't right.
> +    ;
> +NoSevEsVcHlt:
> +    cli
> +    hlt
> +    jmp       NoSevEsVcHlt
> +
> +NoSevPass:
> +    xor       eax, eax
> +
> +SevExit:
> +    ;
> +    ; Clear exception handlers and stack
> +    ;
> +    push      eax
> +    mov       eax, ADDR_OF(IdtrClear)
> +    lidt      [cs:eax]
> +    pop       eax
> +    mov       esp, 0
> +
> +    OneTimeCallRet CheckSevFeatures
> +
> +;
> +; Called before SetCr3ForPageTables64 in SEV guests
> +;
> +; Modified: EAX, EBX, ECX, EDX, ESP
> +;
> +PreSetCr3ForPageTables64Sev:
> +    ; In Tdx TDX_WORK_AREA was set to 'TDXG'.
> +    ; CheckSevFeatures cannot be called in Tdx guest because SEV_ES_WORK_AREA
> +    ; cannot be accessed in this situation. Any memory region to be accessed
> +    ; in Td guest should be accepted first.
> +    cmp     dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
> +    jz      ExitPreSetCr3ForPageTables64Sev
> +
> +    OneTimeCall     CheckSevFeatures
> +
> +ExitPreSetCr3ForPageTables64Sev:
> +    OneTimeCallRet  PreSetCr3ForPageTables64Sev
> +
> +;
> +; It is called in SEV after SetCr3PageTables64
> +;
> +; Modified:  EAX, EBX, ECX, EDX, ESP
> +;
> +PostSetCr3PageTables64Sev:
> +    ; In Tdx TDX_WORK_AREA was set to 'TDXG'.
> +    ; CheckSevFeatures cannot be called in Tdx because SEV_ES_WORK_AREA
> +    ; cannot be accessed in this situation. Any memory region to be accessed
> +    ; in Td guest should be accepted first.
> +    cmp     dword[TDX_WORK_AREA], 0x47584454 ; 'TDXG'
> +    jz      ExitPostSetCr3PageTables64Sev
> +
> +    mov     eax, cr4
> +    bts     eax, 5                      ; enable PAE
> +    mov     cr4, eax
> +
> +    mov     ecx, 0xc0000080
> +    rdmsr
> +    bts     eax, 8                      ; set LME
> +    wrmsr
> +
> +    ;
> +    ; SEV-ES mitigation check support
> +    ;
> +    xor     ebx, ebx
> +
> +    cmp     byte[SEV_ES_WORK_AREA], 0
> +    jz      EnablePaging
> +
> +    ;
> +    ; SEV-ES is active, perform a quick sanity check against the reported
> +    ; encryption bit position. This is to help mitigate against attacks where
> +    ; the hypervisor reports an incorrect encryption bit position.
> +    ;
> +    ; This is the first step in a two step process. Before paging is enabled
> +    ; writes to memory are encrypted. Using the RDRAND instruction (available
> +    ; on all SEV capable processors), write 64-bits of random data to the
> +    ; SEV_ES_WORK_AREA and maintain the random data in registers (register
> +    ; state is protected under SEV-ES). This will be used in the second step.
> +    ;
> +RdRand1:
> +    rdrand  ecx
> +    jnc     RdRand1
> +    mov     dword[SEV_ES_WORK_AREA_RDRAND], ecx
> +RdRand2:
> +    rdrand  edx
> +    jnc     RdRand2
> +    mov     dword[SEV_ES_WORK_AREA_RDRAND + 4], edx
> +
> +    ;
> +    ; Use EBX instead of the SEV_ES_WORK_AREA memory to determine whether to
> +    ; perform the second step.
> +    ;
> +    mov     ebx, 1
> +
> +EnablePaging:
> +    mov     eax, cr0
> +    bts     eax, 31                     ; set PG
> +    mov     cr0, eax                    ; enable paging
> +
> +ExitPostSetCr3PageTables64Sev:
> +
> +    OneTimeCallRet PostSetCr3PageTables64Sev
> +
> +;
> +; Start of #VC exception handling routines
> +;
> +
> +SevEsIdtNotCpuid:
> +    ;
> +    ; Use VMGEXIT to request termination.
> +    ;   1 - #VC was not for CPUID
> +    ;
> +    mov     eax, 1
> +    jmp     SevEsIdtTerminate
> +
> +SevEsIdtNoCpuidResponse:
> +    ;
> +    ; Use VMGEXIT to request termination.
> +    ;   2 - GHCB_CPUID_RESPONSE not received
> +    ;
> +    mov     eax, 2
> +
> +SevEsIdtTerminate:
> +    ;
> +    ; Use VMGEXIT to request termination. At this point the reason code is
> +    ; located in EAX, so shift it left 16 bits to the proper location.
> +    ;
> +    ; EAX[11:0]  => 0x100 - request termination
> +    ; EAX[15:12] => 0x1   - OVMF
> +    ; EAX[23:16] => 0xXX  - REASON CODE
> +    ;
> +    shl     eax, 16
> +    or      eax, 0x1100
> +    xor     edx, edx
> +    mov     ecx, 0xc0010130
> +    wrmsr
> +    ;
> +    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
> +    ; mode, so work around this by temporarily switching to 64-bit mode.
> +    ;
> +BITS    64
> +    rep     vmmcall
> +BITS    32
> +
> +    ;
> +    ; We shouldn't come back from the VMGEXIT, but if we do, just loop.
> +    ;
> +SevEsIdtHlt:
> +    hlt
> +    jmp     SevEsIdtHlt
> +    iret
> +
> +    ;
> +    ; Total stack usage for the #VC handler is 44 bytes:
> +    ;   - 12 bytes for the exception IRET (after popping error code)
> +    ;   - 32 bytes for the local variables.
> +    ;
> +SevEsIdtVmmComm:
> +    ;
> +    ; If we're here, then we are an SEV-ES guest and this
> +    ; was triggered by a CPUID instruction
> +    ;
> +    ; Set the first byte of the workarea to one to communicate that
> +    ; a #VC was taken.
> +    mov     byte[SEV_ES_WORK_AREA], 1
> +
> +    pop     ecx                     ; Error code
> +    cmp     ecx, 0x72               ; Be sure it was CPUID
> +    jne     SevEsIdtNotCpuid
> +
> +    ; Set up local variable room on the stack
> +    ;   CPUID function         : + 28
> +    ;   CPUID request register : + 24
> +    ;   GHCB MSR (EAX)         : + 20
> +    ;   GHCB MSR (EDX)         : + 16
> +    ;   CPUID result (EDX)     : + 12
> +    ;   CPUID result (ECX)     : + 8
> +    ;   CPUID result (EBX)     : + 4
> +    ;   CPUID result (EAX)     : + 0
> +    sub     esp, VC_VARIABLE_SIZE
> +
> +    ; Save the CPUID function being requested
> +    mov     [esp + VC_CPUID_FUNCTION], eax
> +
> +    ; The GHCB CPUID protocol uses the following mapping to request
> +    ; a specific register:
> +    ;   0 => EAX, 1 => EBX, 2 => ECX, 3 => EDX
> +    ;
> +    ; Set EAX as the first register to request. This will also be used as a
> +    ; loop variable to request all register values (EAX to EDX).
> +    xor     eax, eax
> +    mov     [esp + VC_CPUID_REQUEST_REGISTER], eax
> +
> +    ; Save current GHCB MSR value
> +    mov     ecx, 0xc0010130
> +    rdmsr
> +    mov     [esp + VC_GHCB_MSR_EAX], eax
> +    mov     [esp + VC_GHCB_MSR_EDX], edx
> +
> +NextReg:
> +    ;
> +    ; Setup GHCB MSR
> +    ;   GHCB_MSR[63:32] = CPUID function
> +    ;   GHCB_MSR[31:30] = CPUID register
> +    ;   GHCB_MSR[11:0]  = CPUID request protocol
> +    ;
> +    mov     eax, [esp + VC_CPUID_REQUEST_REGISTER]
> +    cmp     eax, 4
> +    jge     VmmDone
> +
> +    shl     eax, GHCB_CPUID_REGISTER_SHIFT
> +    or      eax, GHCB_CPUID_REQUEST
> +    mov     edx, [esp + VC_CPUID_FUNCTION]
> +    mov     ecx, 0xc0010130
> +    wrmsr
> +
> +    ;
> +    ; Issue VMGEXIT - NASM doesn't support the vmmcall instruction in 32-bit
> +    ; mode, so work around this by temporarily switching to 64-bit mode.
> +    ;
> +BITS    64
> +    rep     vmmcall
> +BITS    32
> +
> +    ;
> +    ; Read GHCB MSR
> +    ;   GHCB_MSR[63:32] = CPUID register value
> +    ;   GHCB_MSR[31:30] = CPUID register
> +    ;   GHCB_MSR[11:0]  = CPUID response protocol
> +    ;
> +    mov     ecx, 0xc0010130
> +    rdmsr
> +    mov     ecx, eax
> +    and     ecx, 0xfff
> +    cmp     ecx, GHCB_CPUID_RESPONSE
> +    jne     SevEsIdtNoCpuidResponse
> +
> +    ; Save returned value
> +    shr     eax, GHCB_CPUID_REGISTER_SHIFT
> +    mov     [esp + eax * 4], edx
> +
> +    ; Next register
> +    inc     word [esp + VC_CPUID_REQUEST_REGISTER]
> +
> +    jmp     NextReg
> +
> +VmmDone:
> +    ;
> +    ; At this point we have all CPUID register values. Restore the GHCB MSR,
> +    ; set the return register values and return.
> +    ;
> +    mov     eax, [esp + VC_GHCB_MSR_EAX]
> +    mov     edx, [esp + VC_GHCB_MSR_EDX]
> +    mov     ecx, 0xc0010130
> +    wrmsr
> +
> +    mov     eax, [esp + VC_CPUID_RESULT_EAX]
> +    mov     ebx, [esp + VC_CPUID_RESULT_EBX]
> +    mov     ecx, [esp + VC_CPUID_RESULT_ECX]
> +    mov     edx, [esp + VC_CPUID_RESULT_EDX]
> +
> +    add     esp, VC_VARIABLE_SIZE
> +
> +    ; Update the EIP value to skip over the now handled CPUID instruction
> +    ; (the CPUID instruction has a length of 2)
> +    add     word [esp], CPUID_INSN_LEN
> +    iret
> +
> +ALIGN   2
> +
> +Idtr:
> +    dw      IDT_END - IDT_BASE - 1  ; Limit
> +    dd      ADDR_OF(IDT_BASE)       ; Base
> +
> +IdtrClear:
> +    dw      0                       ; Limit
> +    dd      0                       ; Base
> +
> +ALIGN   16
> +
> +;
> +; The Interrupt Descriptor Table (IDT)
> +;   This will be used to determine if SEV-ES is enabled.  Upon execution
> +;   of the CPUID instruction, a VMM Communication Exception will occur.
> +;   This will tell us if SEV-ES is enabled.  We can use the current value
> +;   of the GHCB MSR to determine the SEV attributes.
> +;
> +IDT_BASE:
> +;
> +; Vectors 0 - 28 (No handlers)
> +;
> +%rep 29
> +    dw      0                                    ; Offset low bits 15..0
> +    dw      0x10                                 ; Selector
> +    db      0                                    ; Reserved
> +    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
> +    dw      0                                    ; Offset high bits 31..16
> +%endrep
> +;
> +; Vector 29 (VMM Communication Exception)
> +;
> +    dw      (ADDR_OF(SevEsIdtVmmComm) & 0xffff)  ; Offset low bits 15..0
> +    dw      0x10                                 ; Selector
> +    db      0                                    ; Reserved
> +    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
> +    dw      (ADDR_OF(SevEsIdtVmmComm) >> 16)     ; Offset high bits 31..16
> +;
> +; Vectors 30 - 31 (No handlers)
> +;
> +%rep 2
> +    dw      0                                    ; Offset low bits 15..0
> +    dw      0x10                                 ; Selector
> +    db      0                                    ; Reserved
> +    db      0x8E                                 ; Gate Type (IA32_IDT_GATE_TYPE_INTERRUPT_32)
> +    dw      0                                    ; Offset high bits 31..16
> +%endrep
> +IDT_END:
> +
> +BITS 64
> +
> +;
> +; Called after Jump64BitAndLandHere
> +;
> +PostJump64BitAndLandHereSev:
> +
> +    ;
> +    ; If it is Tdx guest, jump to exit point directly.
> +    ; This is because following code may access the memory region which has
> +    ; not been accepted. It is not allowed in Tdx guests.
> +    ;
> +    mov     eax, dword[TDX_WORK_AREA]
> +    cmp     eax, 0x47584454             ; 'TDXG'
> +    jz      GoodCompare
> +
> +    ;
> +    ; Check if the second step of the SEV-ES mitigation is to be performed.
> +    ;
> +    test    ebx, ebx
> +    jz      InsnCompare
> +
> +    ;
> +    ; SEV-ES is active, perform the second step of the encryption bit postion
> +    ; mitigation check. The ECX and EDX register contain data from RDRAND that
> +    ; was stored to memory in encrypted form. If the encryption bit position is
> +    ; valid, the contents of ECX and EDX will match the memory location.
> +    ;
> +    cmp     dword[SEV_ES_WORK_AREA_RDRAND], ecx
> +    jne     SevEncBitHlt
> +    cmp     dword[SEV_ES_WORK_AREA_RDRAND + 4], edx
> +    jne     SevEncBitHlt
> +
> +    ;
> +    ; If SEV or SEV-ES is active, perform a quick sanity check against
> +    ; the reported encryption bit position. This is to help mitigate
> +    ; against attacks where the hypervisor reports an incorrect encryption
> +    ; bit position. If SEV is not active, this check will always succeed.
> +    ;
> +    ; The cmp instruction compares the first four bytes of the cmp instruction
> +    ; itself (which will be read decrypted if SEV or SEV-ES is active and the
> +    ; encryption bit position is valid) against the immediate within the
> +    ; instruction (an instruction fetch is always decrypted correctly by
> +    ; hardware) based on RIP relative addressing.
> +    ;
> +InsnCompare:
> +    cmp     dword[rel InsnCompare], 0xFFF63D81
> +    je      GoodCompare
> +
> +    ;
> +    ; The hypervisor provided an incorrect encryption bit position, do not
> +    ; proceed.
> +    ;
> +SevEncBitHlt:
> +    cli
> +    hlt
> +    jmp     SevEncBitHlt
> +
> +GoodCompare:
> +    OneTimeCallRet PostJump64BitAndLandHereSev

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-27 10:56   ` Brijesh Singh
@ 2021-07-27 11:51     ` Min Xu
  2021-07-27 12:31       ` Brijesh Singh
  0 siblings, 1 reply; 36+ messages in thread
From: Min Xu @ 2021-07-27 11:51 UTC (permalink / raw)
  To: Brijesh Singh, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky

On July 27, 2021 6:57 PM, Brijesh Singh wrote:
> Hi Min,
> 
> This refactoring is already done by the SNP patch series.
> 
> https://edk2.groups.io/g/devel/message/77336?p=,,,20,0,0,0::Created,,post
> erid%3A5969970,20,2,20,83891510
> 
> It appears that you are also pulling in some of TDX logic inside the
> AMDSev.asm such as
> 
> ;
> +PostJump64BitAndLandHereSev:
> +
> +    ;
> +    ; If it is Tdx guest, jump to exit point directly.
> +    ; This is because following code may access the memory region which has
> +    ; not been accepted. It is not allowed in Tdx guests.
> +    ;
> +    mov     eax, dword[TDX_WORK_AREA]
> +    cmp     eax, 0x47584454             ; 'TDXG'
> +    jz      GoodCompare
> 
> Why we are referring the TDX workarea inside the AmdSev.asm ?
See my explanation in the above comments. In Tdx guests memory region cannot
be accessed unless it is accepted by guest or initialized by the host VMM. In 
PostJump64BitAndLandHereSev there is access to dword[SEV_ES_WORK_AREA_RDRAND]
which is not initialized by host VMM. If this code will not be executed in 
Tdx guest, then the above check is not needed. I need your help to confirm it.

There are similar Tdx check in my patch of AmdSev.asm. For example in CheckSevFeatures
byte[SEV_ES_WORK_AREA] is used to record the SEV-ES flag. This memory region is
not initialized by host VMM either. So in Tdx it will trigger error.

Another solution is that the memory region used by SEV in ResetVector are added
Into Tdx metadata so that host VMM will initialize those memory region when 
It creates the Td guest. What's your opinion?
> 
> I will take out my refactoring patch outside of the SNP series and submit it so
> that you can build on top of. This will simplify review process.
>
Thank you very much for the refactoring.  I will refine my patch based on it. 
>
> thanks
> 
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-27 11:51     ` Min Xu
@ 2021-07-27 12:31       ` Brijesh Singh
  2021-07-27 12:46         ` Yao, Jiewen
  2021-07-28  0:40         ` Min Xu
  0 siblings, 2 replies; 36+ messages in thread
From: Brijesh Singh @ 2021-07-27 12:31 UTC (permalink / raw)
  To: Xu, Min M, devel@edk2.groups.io
  Cc: brijesh.singh, Ard Biesheuvel, Justen, Jordan L, Erdem Aktas,
	James Bottomley, Yao, Jiewen, Tom Lendacky


On 7/27/21 6:51 AM, Xu, Min M wrote:
> On July 27, 2021 6:57 PM, Brijesh Singh wrote:
>> Hi Min,
>>
>> This refactoring is already done by the SNP patch series.
>>
>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2.groups.io%2Fg%2Fdevel%2Fmessage%2F77336%3Fp%3D%2C%2C%2C20%2C0%2C0%2C0%3A%3ACreated%2C%2Cpost&amp;data=04%7C01%7Cbrijesh.singh%40amd.com%7C22b61f2ff5bb48348b0608d950f4d7c5%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637629834792320372%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=tMGpR4a2uZTTR%2FsciTN0oeca2mZ32GfX3K78lA5BWas%3D&amp;reserved=0
>> erid%3A5969970,20,2,20,83891510
>>
>> It appears that you are also pulling in some of TDX logic inside the
>> AMDSev.asm such as
>>
>> ;
>> +PostJump64BitAndLandHereSev:
>> +
>> +    ;
>> +    ; If it is Tdx guest, jump to exit point directly.
>> +    ; This is because following code may access the memory region which has
>> +    ; not been accepted. It is not allowed in Tdx guests.
>> +    ;
>> +    mov     eax, dword[TDX_WORK_AREA]
>> +    cmp     eax, 0x47584454             ; 'TDXG'
>> +    jz      GoodCompare
>>
>> Why we are referring the TDX workarea inside the AmdSev.asm ?
> See my explanation in the above comments. In Tdx guests memory region cannot
> be accessed unless it is accepted by guest or initialized by the host VMM. In 
> PostJump64BitAndLandHereSev there is access to dword[SEV_ES_WORK_AREA_RDRAND]
> which is not initialized by host VMM. If this code will not be executed in 
> Tdx guest, then the above check is not needed. I need your help to confirm it.
>
> There are similar Tdx check in my patch of AmdSev.asm. For example in CheckSevFeatures
> byte[SEV_ES_WORK_AREA] is used to record the SEV-ES flag. This memory region is
> not initialized by host VMM either. So in Tdx it will trigger error.
>
> Another solution is that the memory region used by SEV in ResetVector are added
> Into Tdx metadata so that host VMM will initialize those memory region when 
> It creates the Td guest. What's your opinion?

I am not full versed on TDX yet and sorry I am not able to follow you
question completely to provide any advice. With SEV and SEV-ES, a guest
can access the memory without going through the validation process, but
with the SEV-SNP, the page need to be validated (aka accepted) before
the access. In SNP series, we ensure that the data pages used in the
reset vector are pre-validated during the VM creation time -- this
allows us to access the pages without going through accept process. If I
follow you correctly on your metadata comment then it is similar to
saying is pre-validate these range of pages used in the reset vector
code (that include GHCB page, Page table pages etc), right ? 

For SEV-SNP, see this patch

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

A VMM (qemu) looks for the range of page it need to prevalidate before
the boot, the range is provided through the GUID (SevSnpBootBlock).

>> I will take out my refactoring patch outside of the SNP series and submit it so
>> that you can build on top of. This will simplify review process.
>>
> Thank you very much for the refactoring.  I will refine my patch based on it. 
>> thanks
>>
>>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-27 12:31       ` Brijesh Singh
@ 2021-07-27 12:46         ` Yao, Jiewen
  2021-07-28  5:07           ` Min Xu
  2021-07-28  0:40         ` Min Xu
  1 sibling, 1 reply; 36+ messages in thread
From: Yao, Jiewen @ 2021-07-27 12:46 UTC (permalink / raw)
  To: Brijesh Singh, Xu, Min M, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky

HI Min
I agree with Brijesh.

The basic rule is: SEV file shall never refer to TDX data structure. TDX file shall never refer to SEV data structure.
These code should be isolated clearly.

Do we still need that logic if we follow the new pattern?

Thank you
Yao Jiewen

> -----Original Message-----
> From: Brijesh Singh <brijesh.singh@amd.com>
> Sent: Tuesday, July 27, 2021 8:31 PM
> To: Xu, Min M <min.m.xu@intel.com>; devel@edk2.groups.io
> Cc: brijesh.singh@amd.com; Ard Biesheuvel <ardb+tianocore@kernel.org>;
> Justen, Jordan L <jordan.l.justen@intel.com>; Erdem Aktas
> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Yao,
> Jiewen <jiewen.yao@intel.com>; Tom Lendacky <thomas.lendacky@amd.com>
> Subject: Re: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
> 
> 
> On 7/27/21 6:51 AM, Xu, Min M wrote:
> > On July 27, 2021 6:57 PM, Brijesh Singh wrote:
> >> Hi Min,
> >>
> >> This refactoring is already done by the SNP patch series.
> >>
> >>
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2.gr
> oups.io%2Fg%2Fdevel%2Fmessage%2F77336%3Fp%3D%2C%2C%2C20%2C0%2
> C0%2C0%3A%3ACreated%2C%2Cpost&amp;data=04%7C01%7Cbrijesh.singh%4
> 0amd.com%7C22b61f2ff5bb48348b0608d950f4d7c5%7C3dd8961fe4884e608e1
> 1a82d994e183d%7C0%7C0%7C637629834792320372%7CUnknown%7CTWFpb
> GZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6M
> n0%3D%7C1000&amp;sdata=tMGpR4a2uZTTR%2FsciTN0oeca2mZ32GfX3K78lA
> 5BWas%3D&amp;reserved=0
> >> erid%3A5969970,20,2,20,83891510
> >>
> >> It appears that you are also pulling in some of TDX logic inside the
> >> AMDSev.asm such as
> >>
> >> ;
> >> +PostJump64BitAndLandHereSev:
> >> +
> >> +    ;
> >> +    ; If it is Tdx guest, jump to exit point directly.
> >> +    ; This is because following code may access the memory region which has
> >> +    ; not been accepted. It is not allowed in Tdx guests.
> >> +    ;
> >> +    mov     eax, dword[TDX_WORK_AREA]
> >> +    cmp     eax, 0x47584454             ; 'TDXG'
> >> +    jz      GoodCompare
> >>
> >> Why we are referring the TDX workarea inside the AmdSev.asm ?
> > See my explanation in the above comments. In Tdx guests memory region
> cannot
> > be accessed unless it is accepted by guest or initialized by the host VMM. In
> > PostJump64BitAndLandHereSev there is access to
> dword[SEV_ES_WORK_AREA_RDRAND]
> > which is not initialized by host VMM. If this code will not be executed in
> > Tdx guest, then the above check is not needed. I need your help to confirm it.
> >
> > There are similar Tdx check in my patch of AmdSev.asm. For example in
> CheckSevFeatures
> > byte[SEV_ES_WORK_AREA] is used to record the SEV-ES flag. This memory
> region is
> > not initialized by host VMM either. So in Tdx it will trigger error.
> >
> > Another solution is that the memory region used by SEV in ResetVector are
> added
> > Into Tdx metadata so that host VMM will initialize those memory region when
> > It creates the Td guest. What's your opinion?
> 
> I am not full versed on TDX yet and sorry I am not able to follow you
> question completely to provide any advice. With SEV and SEV-ES, a guest
> can access the memory without going through the validation process, but
> with the SEV-SNP, the page need to be validated (aka accepted) before
> the access. In SNP series, we ensure that the data pages used in the
> reset vector are pre-validated during the VM creation time -- this
> allows us to access the pages without going through accept process. If I
> follow you correctly on your metadata comment then it is similar to
> saying is pre-validate these range of pages used in the reset vector
> code (that include GHCB page, Page table pages etc), right ?
> 
> For SEV-SNP, see this patch
> 
> https://edk2.groups.io/g/devel/message/77342?p=,,,20,0,0,0::Created,,posteri
> d%3A5969970,20,2,20,83891520
> 
> A VMM (qemu) looks for the range of page it need to prevalidate before
> the boot, the range is provided through the GUID (SevSnpBootBlock).
> 
> >> I will take out my refactoring patch outside of the SNP series and submit it so
> >> that you can build on top of. This will simplify review process.
> >>
> > Thank you very much for the refactoring.  I will refine my patch based on it.
> >> thanks
> >>
> >>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-27 12:31       ` Brijesh Singh
  2021-07-27 12:46         ` Yao, Jiewen
@ 2021-07-28  0:40         ` Min Xu
  1 sibling, 0 replies; 36+ messages in thread
From: Min Xu @ 2021-07-28  0:40 UTC (permalink / raw)
  To: Brijesh Singh, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky

On July 27, 2021 8:31 PM, Brijesh Singh wrote:
> On 7/27/21 6:51 AM, Xu, Min M wrote:
> > On July 27, 2021 6:57 PM, Brijesh Singh wrote:
> >> Hi Min,
> >>
> >> This refactoring is already done by the SNP patch series.
> >>
> >>
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk
> >>
> 2.groups.io%2Fg%2Fdevel%2Fmessage%2F77336%3Fp%3D%2C%2C%2C20%
> 2C0%2C0%2
> >>
> C0%3A%3ACreated%2C%2Cpost&amp;data=04%7C01%7Cbrijesh.singh%40a
> md.com%
> >>
> 7C22b61f2ff5bb48348b0608d950f4d7c5%7C3dd8961fe4884e608e11a82d994
> e183d
> >> %7C0%7C0%7C637629834792320372%7CUnknown%7CTWFpbGZsb3d8ey
> JWIjoiMC4wLjA
> >>
> wMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;s
> data=
> >>
> tMGpR4a2uZTTR%2FsciTN0oeca2mZ32GfX3K78lA5BWas%3D&amp;reserved
> =0
> >> erid%3A5969970,20,2,20,83891510
> >>
> >> It appears that you are also pulling in some of TDX logic inside the
> >> AMDSev.asm such as
> >>
> >> ;
> >> +PostJump64BitAndLandHereSev:
> >> +
> >> +    ;
> >> +    ; If it is Tdx guest, jump to exit point directly.
> >> +    ; This is because following code may access the memory region which
> has
> >> +    ; not been accepted. It is not allowed in Tdx guests.
> >> +    ;
> >> +    mov     eax, dword[TDX_WORK_AREA]
> >> +    cmp     eax, 0x47584454             ; 'TDXG'
> >> +    jz      GoodCompare
> >>
> >> Why we are referring the TDX workarea inside the AmdSev.asm ?
> > See my explanation in the above comments. In Tdx guests memory region
> > cannot be accessed unless it is accepted by guest or initialized by
> > the host VMM. In PostJump64BitAndLandHereSev there is access to
> > dword[SEV_ES_WORK_AREA_RDRAND] which is not initialized by host
> VMM.
> > If this code will not be executed in Tdx guest, then the above check is not
> needed. I need your help to confirm it.
> >
> > There are similar Tdx check in my patch of AmdSev.asm. For example in
> > CheckSevFeatures byte[SEV_ES_WORK_AREA] is used to record the SEV-ES
> > flag. This memory region is not initialized by host VMM either. So in Tdx it
> will trigger error.
> >
> > Another solution is that the memory region used by SEV in ResetVector
> > are added Into Tdx metadata so that host VMM will initialize those
> > memory region when It creates the Td guest. What's your opinion?
> 
> I am not full versed on TDX yet and sorry I am not able to follow you
> question completely to provide any advice. With SEV and SEV-ES, a guest can
> access the memory without going through the validation process, but with
> the SEV-SNP, the page need to be validated (aka accepted) before the access.
TDX has the same requirement.
> In SNP series, we ensure that the data pages used in the reset vector are pre-
> validated during the VM creation time -- this allows us to access the pages
> without going through accept process. If I follow you correctly on your
> metadata comment then it is similar to saying is pre-validate these range of
> pages used in the reset vector code (that include GHCB page, Page table
> pages etc), right ?
That's right. Tdx metadata describes the memory region which host VMM initialized
during the VM creation time.

In the current patch-set, below memory region are described in Tdx metadata.
 - TdMailbox (PcdOvmfSecGhcbBackupBase)
 - TdHob(PcdOvmfSecGhcbBase)
 - TdExtraPage(PcdOvmfSecGhcbPageTableBase)
 - OvmfPageTable (PcdOvmfSecPageTablesBase)
These memory regions are initialized by host VMM so they can be accessed in ResetVector in Tdx guests.

In the SEV codes, I find some memory is accessed as well. CheckSevFeatures is the example.
In CheckSevFeatures byte[SEV_ES_WORK_AREA] (PcdSevEsWorkAreaBase) is used to record/check
if it is SEV. So if this function is called in Tdx guest, then error is triggered.

What I am concerned is that, in the current pattern:
====================
	OneTimeCall   PreMainFunctionHookSev
	OneTimeCall   PreMainFunctionHookTdx
MainFunction:
	XXXXXX
	OneTimeCall   PostMainFunctionHookSev
	OneTimeCall   PostMainFunctionHookTdx
====================
The TEE function need implement a TEE check function (such as IsSev, or IsTdx). 
Tdx call CPUID(0x21) to determine if it is tdx guest in the very beginning of ResetVector. Then 'TDXG' is set
in TDX_WORK_AREA. 
SEV does the similar work which call CheckSevFeatures to set SEV_ES_WORK_AREA to 1.
After that both TDX and SEV read the above WORK_AREA to check it is TDX or SEV or legacy guest.

In Tdx the access to SEV_ES_WORK_AREA will trigger error because SEV_ES_WORK_AREA is initialized by host VMM.
In SEV-SNP I am afraid the access to TDX_WORK_AREA will trigger error too.

I am wondering if TDX and SEV can use the same memory region (for example, TEE_WORK_AREA) as the work area?
So that this work area is guaranteed to be initialized in both TDX and SEV. Structure of the TEE_WORK_AREA may
look like this:
  typedef struct {
      UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
      UINT8  Others[];
  } TEE_WORK_AREA;

> 
> For SEV-SNP, see this patch
> 
> https://edk2.groups.io/g/devel/message/77342?p=,,,20,0,0,0::Created,,post
> erid%3A5969970,20,2,20,83891520
> 
> A VMM (qemu) looks for the range of page it need to prevalidate before the
> boot, the range is provided through the GUID (SevSnpBootBlock).
> 
> >> I will take out my refactoring patch outside of the SNP series and
> >> submit it so that you can build on top of. This will simplify review process.
> >>
> > Thank you very much for the refactoring.  I will refine my patch based on it.
> >> thanks
> >>
> >>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-27 12:46         ` Yao, Jiewen
@ 2021-07-28  5:07           ` Min Xu
  2021-07-28  6:04             ` Yao, Jiewen
  0 siblings, 1 reply; 36+ messages in thread
From: Min Xu @ 2021-07-28  5:07 UTC (permalink / raw)
  To: Yao, Jiewen, Brijesh Singh, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky

On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
> HI Min
> I agree with Brijesh.
> 
> The basic rule is: SEV file shall never refer to TDX data structure. TDX file
> shall never refer to SEV data structure.
> These code should be isolated clearly.
> 
> Do we still need that logic if we follow the new pattern?
I have replied to Brijesh's mail about the concern of the new pattern. 

I have some concern in the current pattern:
====================
	OneTimeCall   PreMainFunctionHookSev
	OneTimeCall   PreMainFunctionHookTdx
MainFunction:
	XXXXXX
	OneTimeCall   PostMainFunctionHookSev
	OneTimeCall   PostMainFunctionHookTdx
====================
The TEE function need implement a TEE check function (such as IsSev, or IsTdx). 

Tdx call CPUID(0x21) to determine if it is tdx guest in the very beginning of ResetVector. Then 'TDXG' is set
in TDX_WORK_AREA. SEV does the similar work which call CheckSevFeatures to set SEV_ES_WORK_AREA to 1.

After that both TDX and SEV read the above WORK_AREA to check if it is TDX or SEV or legacy guest.

In Tdx the access to SEV_ES_WORK_AREA will trigger error because SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
In SEV-SNP I am afraid the access to TDX_WORK_AREA will trigger error too.

I am wondering if TDX and SEV can use the same memory region (for example, TEE_WORK_AREA) as the work area?
So that this work area is guaranteed to be initialized in both TDX and SEV. Structure of the TEE_WORK_AREA may
look like this:
  typedef struct {
      UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
      UINT8  Others[];
  } TEE_WORK_AREA;
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-28  5:07           ` Min Xu
@ 2021-07-28  6:04             ` Yao, Jiewen
  2021-07-28  6:58               ` Min Xu
  0 siblings, 1 reply; 36+ messages in thread
From: Yao, Jiewen @ 2021-07-28  6:04 UTC (permalink / raw)
  To: Xu, Min M
  Cc: Brijesh Singh, devel@edk2.groups.io, Ard Biesheuvel,
	Justen, Jordan L, Erdem Aktas, James Bottomley, Tom Lendacky

It does not necessary to be a working area.

We just need a common TEE flag to indicate if the system run in legacy, SEV, or TDX, right?

thank you!
Yao, Jiewen


> 在 2021年7月28日,下午1:07,Xu, Min M <min.m.xu@intel.com> 写道:
> 
> On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
>> HI Min
>> I agree with Brijesh.
>> 
>> The basic rule is: SEV file shall never refer to TDX data structure. TDX file
>> shall never refer to SEV data structure.
>> These code should be isolated clearly.
>> 
>> Do we still need that logic if we follow the new pattern?
> I have replied to Brijesh's mail about the concern of the new pattern. 
> 
> I have some concern in the current pattern:
> ====================
>    OneTimeCall   PreMainFunctionHookSev
>    OneTimeCall   PreMainFunctionHookTdx
> MainFunction:
>    XXXXXX
>    OneTimeCall   PostMainFunctionHookSev
>    OneTimeCall   PostMainFunctionHookTdx
> ====================
> The TEE function need implement a TEE check function (such as IsSev, or IsTdx). 
> 
> Tdx call CPUID(0x21) to determine if it is tdx guest in the very beginning of ResetVector. Then 'TDXG' is set
> in TDX_WORK_AREA. SEV does the similar work which call CheckSevFeatures to set SEV_ES_WORK_AREA to 1.
> 
> After that both TDX and SEV read the above WORK_AREA to check if it is TDX or SEV or legacy guest.
> 
> In Tdx the access to SEV_ES_WORK_AREA will trigger error because SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
> In SEV-SNP I am afraid the access to TDX_WORK_AREA will trigger error too.
> 
> I am wondering if TDX and SEV can use the same memory region (for example, TEE_WORK_AREA) as the work area?
> So that this work area is guaranteed to be initialized in both TDX and SEV. Structure of the TEE_WORK_AREA may
> look like this:
>  typedef struct {
>      UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
>      UINT8  Others[];
>  } TEE_WORK_AREA;
>> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-28  6:04             ` Yao, Jiewen
@ 2021-07-28  6:58               ` Min Xu
  2021-07-28  7:54                 ` Yao, Jiewen
  0 siblings, 1 reply; 36+ messages in thread
From: Min Xu @ 2021-07-28  6:58 UTC (permalink / raw)
  To: Yao, Jiewen
  Cc: Brijesh Singh, devel@edk2.groups.io, Ard Biesheuvel,
	Justen, Jordan L, Erdem Aktas, James Bottomley, Tom Lendacky

On July 28, 2021 2:05 PM, Yao, Jiewen wrote:
> It does not necessary to be a working area.
> 
> We just need a common TEE flag to indicate if the system run in legacy, SEV, or
> TDX, right?
Right. We need somewhere to store this flag, either in a Register or in Memory. 
If it is memory, then in Tdx the memory region should be initialized by host VMM.
> 
> thank you!
> Yao, Jiewen
> 
> 
> > 在 2021年7月28日,下午1:07,Xu, Min M <min.m.xu@intel.com> 写道:
> >
> > On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
> >> HI Min
> >> I agree with Brijesh.
> >>
> >> The basic rule is: SEV file shall never refer to TDX data structure.
> >> TDX file shall never refer to SEV data structure.
> >> These code should be isolated clearly.
> >>
> >> Do we still need that logic if we follow the new pattern?
> > I have replied to Brijesh's mail about the concern of the new pattern.
> >
> > I have some concern in the current pattern:
> > ====================
> >    OneTimeCall   PreMainFunctionHookSev
> >    OneTimeCall   PreMainFunctionHookTdx
> > MainFunction:
> >    XXXXXX
> >    OneTimeCall   PostMainFunctionHookSev
> >    OneTimeCall   PostMainFunctionHookTdx
> > ====================
> > The TEE function need implement a TEE check function (such as IsSev, or IsTdx).
> >
> > Tdx call CPUID(0x21) to determine if it is tdx guest in the very
> > beginning of ResetVector. Then 'TDXG' is set in TDX_WORK_AREA. SEV does
> the similar work which call CheckSevFeatures to set SEV_ES_WORK_AREA to 1.
> >
> > After that both TDX and SEV read the above WORK_AREA to check if it is TDX
> or SEV or legacy guest.
> >
> > In Tdx the access to SEV_ES_WORK_AREA will trigger error because
> SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
> > In SEV-SNP I am afraid the access to TDX_WORK_AREA will trigger error too.
> >
> > I am wondering if TDX and SEV can use the same memory region (for example,
> TEE_WORK_AREA) as the work area?
> > So that this work area is guaranteed to be initialized in both TDX and
> > SEV. Structure of the TEE_WORK_AREA may look like this:
> >  typedef struct {
> >      UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
> >      UINT8  Others[];
> >  } TEE_WORK_AREA;
> >>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-28  6:58               ` Min Xu
@ 2021-07-28  7:54                 ` Yao, Jiewen
  2021-07-28  8:34                   ` Min Xu
  2021-07-28 14:34                   ` Brijesh Singh
  0 siblings, 2 replies; 36+ messages in thread
From: Yao, Jiewen @ 2021-07-28  7:54 UTC (permalink / raw)
  To: Xu, Min M
  Cc: Brijesh Singh, devel@edk2.groups.io, Ard Biesheuvel,
	Justen, Jordan L, Erdem Aktas, James Bottomley, Tom Lendacky

Yes. I am thinking the same thing.

[CC Flag memory location]
1) A general purpose register, such as EBP.

2) A global variable, such as 
.data
TeeFlags: DD 0

3) A fixed region in stack, such as
dword[STACK_TOP - 4]

4) A new CC common fixed region, such as 
dword[CC_COMMON_FLAGS]

5) A fixed region piggyback on existing CC working area, such as
dword[CC_WORKING_AREA]

Hi Brijesh/Min
Any preference?

[CC Indicator Flags]
Proposal: UINT8[4]

Byte [0] Version: 0
byte [1] Length: 4
byte [2] Type:
	0: legacy
	1: SEV
	2: TDX
byte [3] Sub Type: 
	If Type is 0 (legacy), then
		0: legacy
	If Type is 1 (SEV), then
		0: SEV
		1: SEV-ES
		2: SEV-SNP
	If Type is 2 (TDX), then
		0: TDX 1.0

Thank you
Yao Jiewen


> -----Original Message-----
> From: Xu, Min M <min.m.xu@intel.com>
> Sent: Wednesday, July 28, 2021 2:58 PM
> To: Yao, Jiewen <jiewen.yao@intel.com>
> Cc: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io; Ard
> Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>; James
> Bottomley <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
> Subject: RE: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
> 
> On July 28, 2021 2:05 PM, Yao, Jiewen wrote:
> > It does not necessary to be a working area.
> >
> > We just need a common TEE flag to indicate if the system run in legacy, SEV,
> or
> > TDX, right?
> Right. We need somewhere to store this flag, either in a Register or in Memory.
> If it is memory, then in Tdx the memory region should be initialized by host VMM.
> >
> > thank you!
> > Yao, Jiewen
> >
> >
> > > 在 2021年7月28日,下午1:07,Xu, Min M <min.m.xu@intel.com> 写道:
> > >
> > > On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
> > >> HI Min
> > >> I agree with Brijesh.
> > >>
> > >> The basic rule is: SEV file shall never refer to TDX data structure.
> > >> TDX file shall never refer to SEV data structure.
> > >> These code should be isolated clearly.
> > >>
> > >> Do we still need that logic if we follow the new pattern?
> > > I have replied to Brijesh's mail about the concern of the new pattern.
> > >
> > > I have some concern in the current pattern:
> > > ====================
> > >    OneTimeCall   PreMainFunctionHookSev
> > >    OneTimeCall   PreMainFunctionHookTdx
> > > MainFunction:
> > >    XXXXXX
> > >    OneTimeCall   PostMainFunctionHookSev
> > >    OneTimeCall   PostMainFunctionHookTdx
> > > ====================
> > > The TEE function need implement a TEE check function (such as IsSev, or
> IsTdx).
> > >
> > > Tdx call CPUID(0x21) to determine if it is tdx guest in the very
> > > beginning of ResetVector. Then 'TDXG' is set in TDX_WORK_AREA. SEV does
> > the similar work which call CheckSevFeatures to set SEV_ES_WORK_AREA to 1.
> > >
> > > After that both TDX and SEV read the above WORK_AREA to check if it is TDX
> > or SEV or legacy guest.
> > >
> > > In Tdx the access to SEV_ES_WORK_AREA will trigger error because
> > SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
> > > In SEV-SNP I am afraid the access to TDX_WORK_AREA will trigger error too.
> > >
> > > I am wondering if TDX and SEV can use the same memory region (for
> example,
> > TEE_WORK_AREA) as the work area?
> > > So that this work area is guaranteed to be initialized in both TDX and
> > > SEV. Structure of the TEE_WORK_AREA may look like this:
> > >  typedef struct {
> > >      UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
> > >      UINT8  Others[];
> > >  } TEE_WORK_AREA;
> > >>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-28  7:54                 ` Yao, Jiewen
@ 2021-07-28  8:34                   ` Min Xu
  2021-07-28 14:34                   ` Brijesh Singh
  1 sibling, 0 replies; 36+ messages in thread
From: Min Xu @ 2021-07-28  8:34 UTC (permalink / raw)
  To: Yao, Jiewen
  Cc: Brijesh Singh, devel@edk2.groups.io, Ard Biesheuvel,
	Justen, Jordan L, Erdem Aktas, James Bottomley, Tom Lendacky

I noticed SEV has the memory region of SEV_ES_WORK_AREA (gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase) in MEMFD
The definition is below:
  typedef struct _SEC_SEV_ES_WORK_AREA {
    UINT8    SevEsEnabled;
    UINT8    Reserved1[7];
    UINT64   RandomData;
    UINT64   EncryptionMask;
  } SEC_SEV_ES_WORK_AREA;

In ResetVector SEV flag is recorded in the first byte of SEV_ES_WORK_AREA. In SecMain.c this flag is read to determine SEV.

I am thinking whether this memory region can be used by both TDX and SEV. (This is option 5)

SEV_ES_WORK_AREA will be added in tdx metadata so that it is initialized by host VMM and can be accessed in Tdx guest.
In SEV guest I believe SEV_ES_WORK_AREA can be accessed without any error.
The first 8 bytes of SEV_ES_WORK_AREA can be redefined as [CC Indicator Flags].

> -----Original Message-----
> From: Yao, Jiewen <jiewen.yao@intel.com>
> Sent: Wednesday, July 28, 2021 3:55 PM
> To: Xu, Min M <min.m.xu@intel.com>
> Cc: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io; Ard
> Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>;
> James Bottomley <jejb@linux.ibm.com>; Tom Lendacky
> <thomas.lendacky@amd.com>
> Subject: RE: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
> 
> Yes. I am thinking the same thing.
> 
> [CC Flag memory location]
> 1) A general purpose register, such as EBP.
> 
> 2) A global variable, such as
> .data
> TeeFlags: DD 0
> 
> 3) A fixed region in stack, such as
> dword[STACK_TOP - 4]
> 
> 4) A new CC common fixed region, such as dword[CC_COMMON_FLAGS]
> 
> 5) A fixed region piggyback on existing CC working area, such as
> dword[CC_WORKING_AREA]
> 
> Hi Brijesh/Min
> Any preference?
> 
> [CC Indicator Flags]
> Proposal: UINT8[4]
> 
> Byte [0] Version: 0
> byte [1] Length: 4
> byte [2] Type:
> 	0: legacy
> 	1: SEV
> 	2: TDX
> byte [3] Sub Type:
> 	If Type is 0 (legacy), then
> 		0: legacy
> 	If Type is 1 (SEV), then
> 		0: SEV
> 		1: SEV-ES
> 		2: SEV-SNP
> 	If Type is 2 (TDX), then
> 		0: TDX 1.0
> 
> Thank you
> Yao Jiewen
> 
> 
> > -----Original Message-----
> > From: Xu, Min M <min.m.xu@intel.com>
> > Sent: Wednesday, July 28, 2021 2:58 PM
> > To: Yao, Jiewen <jiewen.yao@intel.com>
> > Cc: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io; Ard
> > Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
> > <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>;
> > James Bottomley <jejb@linux.ibm.com>; Tom Lendacky
> > <thomas.lendacky@amd.com>
> > Subject: RE: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
> >
> > On July 28, 2021 2:05 PM, Yao, Jiewen wrote:
> > > It does not necessary to be a working area.
> > >
> > > We just need a common TEE flag to indicate if the system run in
> > > legacy, SEV,
> > or
> > > TDX, right?
> > Right. We need somewhere to store this flag, either in a Register or in
> Memory.
> > If it is memory, then in Tdx the memory region should be initialized by host
> VMM.
> > >
> > > thank you!
> > > Yao, Jiewen
> > >
> > >
> > > > 在 2021年7月28日,下午1:07,Xu, Min M <min.m.xu@intel.com>
> 写道:
> > > >
> > > > On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
> > > >> HI Min
> > > >> I agree with Brijesh.
> > > >>
> > > >> The basic rule is: SEV file shall never refer to TDX data structure.
> > > >> TDX file shall never refer to SEV data structure.
> > > >> These code should be isolated clearly.
> > > >>
> > > >> Do we still need that logic if we follow the new pattern?
> > > > I have replied to Brijesh's mail about the concern of the new pattern.
> > > >
> > > > I have some concern in the current pattern:
> > > > ====================
> > > >    OneTimeCall   PreMainFunctionHookSev
> > > >    OneTimeCall   PreMainFunctionHookTdx
> > > > MainFunction:
> > > >    XXXXXX
> > > >    OneTimeCall   PostMainFunctionHookSev
> > > >    OneTimeCall   PostMainFunctionHookTdx
> > > > ====================
> > > > The TEE function need implement a TEE check function (such as
> > > > IsSev, or
> > IsTdx).
> > > >
> > > > Tdx call CPUID(0x21) to determine if it is tdx guest in the very
> > > > beginning of ResetVector. Then 'TDXG' is set in TDX_WORK_AREA. SEV
> > > > does
> > > the similar work which call CheckSevFeatures to set SEV_ES_WORK_AREA
> to 1.
> > > >
> > > > After that both TDX and SEV read the above WORK_AREA to check if
> > > > it is TDX
> > > or SEV or legacy guest.
> > > >
> > > > In Tdx the access to SEV_ES_WORK_AREA will trigger error because
> > > SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
> > > > In SEV-SNP I am afraid the access to TDX_WORK_AREA will trigger error
> too.
> > > >
> > > > I am wondering if TDX and SEV can use the same memory region (for
> > example,
> > > TEE_WORK_AREA) as the work area?
> > > > So that this work area is guaranteed to be initialized in both TDX
> > > > and SEV. Structure of the TEE_WORK_AREA may look like this:
> > > >  typedef struct {
> > > >      UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
> > > >      UINT8  Others[];
> > > >  } TEE_WORK_AREA;
> > > >>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-28  7:54                 ` Yao, Jiewen
  2021-07-28  8:34                   ` Min Xu
@ 2021-07-28 14:34                   ` Brijesh Singh
  2021-07-28 15:22                     ` [edk2-devel] " Yao, Jiewen
  1 sibling, 1 reply; 36+ messages in thread
From: Brijesh Singh @ 2021-07-28 14:34 UTC (permalink / raw)
  To: Yao, Jiewen, Xu, Min M
  Cc: brijesh.singh, devel@edk2.groups.io, Ard Biesheuvel,
	Justen, Jordan L, Erdem Aktas, James Bottomley, Tom Lendacky

Hi Jiewen and Min,

See my comments below.


On 7/28/21 2:54 AM, Yao, Jiewen wrote:
> Yes. I am thinking the same thing.
> 
> [CC Flag memory location]
> 1) A general purpose register, such as EBP.
> 
> 2) A global variable, such as
> .data
> TeeFlags: DD 0
> 
> 3) A fixed region in stack, such as
> dword[STACK_TOP - 4]
> 
> 4) A new CC common fixed region, such as
> dword[CC_COMMON_FLAGS]
> 
> 5) A fixed region piggyback on existing CC working area, such as
> dword[CC_WORKING_AREA]
> 
> Hi Brijesh/Min
> Any preference?
> 
> [CC Indicator Flags]
> Proposal: UINT8[4]
> 
> Byte [0] Version: 0
> byte [1] Length: 4
> byte [2] Type:
> 	0: legacy
> 	1: SEV
> 	2: TDX
> byte [3] Sub Type:
> 	If Type is 0 (legacy), then
> 		0: legacy
> 	If Type is 1 (SEV), then
> 		0: SEV
> 		1: SEV-ES
> 		2: SEV-SNP
> 	If Type is 2 (TDX), then
> 		0: TDX 1.0
> 
> Thank you
> Yao Jiewen
> 
> 
>> -----Original Message-----
>> From: Xu, Min M <min.m.xu@intel.com>
>> Sent: Wednesday, July 28, 2021 2:58 PM
>> To: Yao, Jiewen <jiewen.yao@intel.com>
>> Cc: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io; Ard
>> Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
>> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>; James
>> Bottomley <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
>> Subject: RE: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
>>
>> On July 28, 2021 2:05 PM, Yao, Jiewen wrote:
>>> It does not necessary to be a working area.
>>>
>>> We just need a common TEE flag to indicate if the system run in legacy, SEV,
>> or
>>> TDX, right?
>> Right. We need somewhere to store this flag, either in a Register or in Memory.
>> If it is memory, then in Tdx the memory region should be initialized by host VMM.
>>>
>>> thank you!
>>> Yao, Jiewen
>>>
>>>
>>>> 在 2021年7月28日,下午1:07,Xu, Min M <min.m.xu@intel.com> 写道:
>>>>
>>>> On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
>>>>> HI Min
>>>>> I agree with Brijesh.
>>>>>
>>>>> The basic rule is: SEV file shall never refer to TDX data structure.
>>>>> TDX file shall never refer to SEV data structure.
>>>>> These code should be isolated clearly.
>>>>>
>>>>> Do we still need that logic if we follow the new pattern?
>>>> I have replied to Brijesh's mail about the concern of the new pattern.
>>>>
>>>> I have some concern in the current pattern:
>>>> ====================
>>>>     OneTimeCall   PreMainFunctionHookSev
>>>>     OneTimeCall   PreMainFunctionHookTdx
>>>> MainFunction:
>>>>     XXXXXX
>>>>     OneTimeCall   PostMainFunctionHookSev
>>>>     OneTimeCall   PostMainFunctionHookTdx
>>>> ====================
>>>> The TEE function need implement a TEE check function (such as IsSev, or
>> IsTdx).
>>>>
>>>> Tdx call CPUID(0x21) to determine if it is tdx guest in the very
>>>> beginning of ResetVector. Then 'TDXG' is set in TDX_WORK_AREA. SEV does
>>> the similar work which call CheckSevFeatures to set SEV_ES_WORK_AREA to 1.
>>>>
>>>> After that both TDX and SEV read the above WORK_AREA to check if it is TDX
>>> or SEV or legacy guest.
>>>>
>>>> In Tdx the access to SEV_ES_WORK_AREA will trigger error because
>>> SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
>>>> In SEV-SNP I am afraid the access to TDX_WORK_AREA will trigger error too.
>>>>
>>>> I am wondering if TDX and SEV can use the same memory region (for
>> example,
>>> TEE_WORK_AREA) as the work area?
>>>> So that this work area is guaranteed to be initialized in both TDX and
>>>> SEV. Structure of the TEE_WORK_AREA may look like this:
>>>>   typedef struct {
>>>>       UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
>>>>       UINT8  Others[];
>>>>   } TEE_WORK_AREA;
>>>>>

Are we reserving a new page for the TDX_WORK_AREA ? I am wondering why 
can't we use the SEV_ES_WORK_AREA instead of wasting space in the MEMFD.

The SEV_ES_WORK_AREA layout looks like this:

typedef struct _SEC_SEV_ES_WORK_AREA {
   UINT8    SevEsEnabled;
   UINT8    Reserved1[7];

   UINT64   RandomData;

   UINT64   EncryptionMask;
} SEC_SEV_ES_WORK_AREA;

There is reserved bit after the SevEsEnabled and one byte can be used 
for the TdxEnabled;

typedef struct _SEC_SEV_ES_WORK_AREA {
   UINT8    SevEsEnabled;
   UINT8    TdxEnabled;
   UINT8    Reserved2[6];

   UINT64   RandomData;

   UINT64   EncryptionMask;
} SEC_SEV_ES_WORK_AREA;

The SEV_ES_WORK_AREA can be treated as a TEE_WORK_AREA and we can be 
pull out from MemEncrypSevLib.h to CcWorkAreaLib.h and rename the 
structure (if needed).

Both the SEV-SNP and TEE host-VMM accepts the TEE_WORK_AREA before 
booting the guest to ensure that its safe to access the memory without 
going through the accept/validation process.

In case of the TDX, the reset vector code sets the TdxEnabled on the 
entry. In case of the SEV, the workarea is valid from SEC to PEI phase 
only and it gets reused for other purposes. The PEI phase set the Pcd's
(such as SevEsEnabled or SevEnabled etc) so that Dxe or other EDK2 core 
does not need to know anything about the workarea and they simply can 
read the PCDs.

-Brijesh

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-28 14:34                   ` Brijesh Singh
@ 2021-07-28 15:22                     ` Yao, Jiewen
  2021-07-28 15:59                       ` Brijesh Singh
  0 siblings, 1 reply; 36+ messages in thread
From: Yao, Jiewen @ 2021-07-28 15:22 UTC (permalink / raw)
  To: devel@edk2.groups.io, brijesh.singh@amd.com, Xu, Min M
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky

Hi Brijesh
Thanks!

I think if we want to reuse this, we need rename the data structure.

First, we should use a generic name.

Second, I don’t think it is good idea to define two *enable* fields. Since only one of them should be enabled, we should use 1 field as enumeration.

Third, we should hide the SEV specific and TDX specific definition in CC common work area.

If we agree to use a common work area, I recommend below:

typedef struct {
   UINT8    HeaderVersion; // 0
   UINT8    HeadLength; // 4
   UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
   UINT8    SubType; // Type specific sub type, if needed.
} CC_COMMON_WORK_AREA_HEADER;

typedef struct {
   CC_COMMON_WORK_AREA_HEADER Header;
   // reset is valid if Type == 1
   UINT8    Reserved1[4];
   UINT64   RandomData;
   UINT64   EncryptionMask;
} SEC_SEV_ES_WORK_AREA;

typedef struct {
   CC_COMMON_WORK_AREA_HEADER Header;
   // reset is valid if Type == 2
   UINT8    TdxSpecific[];  // TBD
} TDX_WORK_AREA;

Thank you
Yao Jiewen

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Brijesh
> Singh via groups.io
> Sent: Wednesday, July 28, 2021 10:34 PM
> To: Yao, Jiewen <jiewen.yao@intel.com>; Xu, Min M <min.m.xu@intel.com>
> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Ard Biesheuvel
> <ardb+tianocore@kernel.org>; Justen, Jordan L <jordan.l.justen@intel.com>;
> Erdem Aktas <erdemaktas@google.com>; James Bottomley
> <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> ResetVector
> 
> Hi Jiewen and Min,
> 
> See my comments below.
> 
> 
> On 7/28/21 2:54 AM, Yao, Jiewen wrote:
> > Yes. I am thinking the same thing.
> >
> > [CC Flag memory location]
> > 1) A general purpose register, such as EBP.
> >
> > 2) A global variable, such as
> > .data
> > TeeFlags: DD 0
> >
> > 3) A fixed region in stack, such as
> > dword[STACK_TOP - 4]
> >
> > 4) A new CC common fixed region, such as
> > dword[CC_COMMON_FLAGS]
> >
> > 5) A fixed region piggyback on existing CC working area, such as
> > dword[CC_WORKING_AREA]
> >
> > Hi Brijesh/Min
> > Any preference?
> >
> > [CC Indicator Flags]
> > Proposal: UINT8[4]
> >
> > Byte [0] Version: 0
> > byte [1] Length: 4
> > byte [2] Type:
> > 	0: legacy
> > 	1: SEV
> > 	2: TDX
> > byte [3] Sub Type:
> > 	If Type is 0 (legacy), then
> > 		0: legacy
> > 	If Type is 1 (SEV), then
> > 		0: SEV
> > 		1: SEV-ES
> > 		2: SEV-SNP
> > 	If Type is 2 (TDX), then
> > 		0: TDX 1.0
> >
> > Thank you
> > Yao Jiewen
> >
> >
> >> -----Original Message-----
> >> From: Xu, Min M <min.m.xu@intel.com>
> >> Sent: Wednesday, July 28, 2021 2:58 PM
> >> To: Yao, Jiewen <jiewen.yao@intel.com>
> >> Cc: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io; Ard
> >> Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
> >> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>;
> James
> >> Bottomley <jejb@linux.ibm.com>; Tom Lendacky
> <thomas.lendacky@amd.com>
> >> Subject: RE: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
> >>
> >> On July 28, 2021 2:05 PM, Yao, Jiewen wrote:
> >>> It does not necessary to be a working area.
> >>>
> >>> We just need a common TEE flag to indicate if the system run in legacy, SEV,
> >> or
> >>> TDX, right?
> >> Right. We need somewhere to store this flag, either in a Register or in
> Memory.
> >> If it is memory, then in Tdx the memory region should be initialized by host
> VMM.
> >>>
> >>> thank you!
> >>> Yao, Jiewen
> >>>
> >>>
> >>>> 在 2021年7月28日,下午1:07,Xu, Min M <min.m.xu@intel.com> 写
> 道:
> >>>>
> >>>> On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
> >>>>> HI Min
> >>>>> I agree with Brijesh.
> >>>>>
> >>>>> The basic rule is: SEV file shall never refer to TDX data structure.
> >>>>> TDX file shall never refer to SEV data structure.
> >>>>> These code should be isolated clearly.
> >>>>>
> >>>>> Do we still need that logic if we follow the new pattern?
> >>>> I have replied to Brijesh's mail about the concern of the new pattern.
> >>>>
> >>>> I have some concern in the current pattern:
> >>>> ====================
> >>>>     OneTimeCall   PreMainFunctionHookSev
> >>>>     OneTimeCall   PreMainFunctionHookTdx
> >>>> MainFunction:
> >>>>     XXXXXX
> >>>>     OneTimeCall   PostMainFunctionHookSev
> >>>>     OneTimeCall   PostMainFunctionHookTdx
> >>>> ====================
> >>>> The TEE function need implement a TEE check function (such as IsSev, or
> >> IsTdx).
> >>>>
> >>>> Tdx call CPUID(0x21) to determine if it is tdx guest in the very
> >>>> beginning of ResetVector. Then 'TDXG' is set in TDX_WORK_AREA. SEV
> does
> >>> the similar work which call CheckSevFeatures to set SEV_ES_WORK_AREA to
> 1.
> >>>>
> >>>> After that both TDX and SEV read the above WORK_AREA to check if it is
> TDX
> >>> or SEV or legacy guest.
> >>>>
> >>>> In Tdx the access to SEV_ES_WORK_AREA will trigger error because
> >>> SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
> >>>> In SEV-SNP I am afraid the access to TDX_WORK_AREA will trigger error
> too.
> >>>>
> >>>> I am wondering if TDX and SEV can use the same memory region (for
> >> example,
> >>> TEE_WORK_AREA) as the work area?
> >>>> So that this work area is guaranteed to be initialized in both TDX and
> >>>> SEV. Structure of the TEE_WORK_AREA may look like this:
> >>>>   typedef struct {
> >>>>       UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
> >>>>       UINT8  Others[];
> >>>>   } TEE_WORK_AREA;
> >>>>>
> 
> Are we reserving a new page for the TDX_WORK_AREA ? I am wondering why
> can't we use the SEV_ES_WORK_AREA instead of wasting space in the MEMFD.
> 
> The SEV_ES_WORK_AREA layout looks like this:
> 
> typedef struct _SEC_SEV_ES_WORK_AREA {
>    UINT8    SevEsEnabled;
>    UINT8    Reserved1[7];
> 
>    UINT64   RandomData;
> 
>    UINT64   EncryptionMask;
> } SEC_SEV_ES_WORK_AREA;
> 
> There is reserved bit after the SevEsEnabled and one byte can be used
> for the TdxEnabled;
> 
> typedef struct _SEC_SEV_ES_WORK_AREA {
>    UINT8    SevEsEnabled;
>    UINT8    TdxEnabled;
>    UINT8    Reserved2[6];
> 
>    UINT64   RandomData;
> 
>    UINT64   EncryptionMask;
> } SEC_SEV_ES_WORK_AREA;
> 
> The SEV_ES_WORK_AREA can be treated as a TEE_WORK_AREA and we can be
> pull out from MemEncrypSevLib.h to CcWorkAreaLib.h and rename the
> structure (if needed).
> 
> Both the SEV-SNP and TEE host-VMM accepts the TEE_WORK_AREA before
> booting the guest to ensure that its safe to access the memory without
> going through the accept/validation process.
> 
> In case of the TDX, the reset vector code sets the TdxEnabled on the
> entry. In case of the SEV, the workarea is valid from SEC to PEI phase
> only and it gets reused for other purposes. The PEI phase set the Pcd's
> (such as SevEsEnabled or SevEnabled etc) so that Dxe or other EDK2 core
> does not need to know anything about the workarea and they simply can
> read the PCDs.
> 
> -Brijesh
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-28 15:22                     ` [edk2-devel] " Yao, Jiewen
@ 2021-07-28 15:59                       ` Brijesh Singh
  2021-07-28 16:26                         ` Yao, Jiewen
  0 siblings, 1 reply; 36+ messages in thread
From: Brijesh Singh @ 2021-07-28 15:59 UTC (permalink / raw)
  To: Yao, Jiewen, devel@edk2.groups.io, Xu, Min M
  Cc: brijesh.singh, Ard Biesheuvel, Justen, Jordan L, Erdem Aktas,
	James Bottomley, Tom Lendacky

Hi Yao Jiewen,

I guess I am still trying to figure out why we need the header in the 
work area. Can't we do something like this:

typedef struct {
	UINT8    SevEsEnabled;

	// If Es is enabled then this field must be zeroed
	UINT8    MustBeZero;

	UINT8    Reserved1[6];

	UINT64   RandomData;

	UINT64   EncryptionMask;
} SEC_SEV_ES_WORK_AREA;

typedef struct {
	// If Tdx is enabled then it must be zeroed
	UINT8    MustBeZero

	UINT8    TdxEnabled;

	UINT8    Reserved2[6];
	....

} TX_WORK_AREA;

typedef union {
	SEC_SEV_ES_WORK_AREA SevEsWorkArea;
	TDX_WORK_AREA	     TdxWorkArea;
} CC_WORK_AREA;

I am trying to minimize the changes to the existing code. The SEV and 
TDX probe logic should ensure that if the feature is detected, then it 
must clear the MustBeZero'ed field.

Basically, we already have a 64-bit value reserved in the SevEsWork area 
and currently only one byte is used and second byte can be detected for 
the TDX. Basically the which encryption technology is active the 
definition of the work area will change.

Am I missing something ?

Thanks

On 7/28/21 10:22 AM, Yao, Jiewen wrote:
> Hi Brijesh
> Thanks!
> 
> I think if we want to reuse this, we need rename the data structure.
> 
> First, we should use a generic name.
> 
> Second, I don’t think it is good idea to define two *enable* fields. Since only one of them should be enabled, we should use 1 field as enumeration.
> 
> Third, we should hide the SEV specific and TDX specific definition in CC common work area.
> 
> If we agree to use a common work area, I recommend below:
> 
> typedef struct {
>     UINT8    HeaderVersion; // 0
>     UINT8    HeadLength; // 4
>     UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
>     UINT8    SubType; // Type specific sub type, if needed.
> } CC_COMMON_WORK_AREA_HEADER;
> 
> typedef struct {
>     CC_COMMON_WORK_AREA_HEADER Header;
>     // reset is valid if Type == 1
>     UINT8    Reserved1[4];
>     UINT64   RandomData;
>     UINT64   EncryptionMask;
> } SEC_SEV_ES_WORK_AREA;
> 
> typedef struct {
>     CC_COMMON_WORK_AREA_HEADER Header;
>     // reset is valid if Type == 2
>     UINT8    TdxSpecific[];  // TBD
> } TDX_WORK_AREA;
> 
> Thank you
> Yao Jiewen
> 
>> -----Original Message-----
>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Brijesh
>> Singh via groups.io
>> Sent: Wednesday, July 28, 2021 10:34 PM
>> To: Yao, Jiewen <jiewen.yao@intel.com>; Xu, Min M <min.m.xu@intel.com>
>> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Ard Biesheuvel
>> <ardb+tianocore@kernel.org>; Justen, Jordan L <jordan.l.justen@intel.com>;
>> Erdem Aktas <erdemaktas@google.com>; James Bottomley
>> <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
>> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
>> ResetVector
>>
>> Hi Jiewen and Min,
>>
>> See my comments below.
>>
>>
>> On 7/28/21 2:54 AM, Yao, Jiewen wrote:
>>> Yes. I am thinking the same thing.
>>>
>>> [CC Flag memory location]
>>> 1) A general purpose register, such as EBP.
>>>
>>> 2) A global variable, such as
>>> .data
>>> TeeFlags: DD 0
>>>
>>> 3) A fixed region in stack, such as
>>> dword[STACK_TOP - 4]
>>>
>>> 4) A new CC common fixed region, such as
>>> dword[CC_COMMON_FLAGS]
>>>
>>> 5) A fixed region piggyback on existing CC working area, such as
>>> dword[CC_WORKING_AREA]
>>>
>>> Hi Brijesh/Min
>>> Any preference?
>>>
>>> [CC Indicator Flags]
>>> Proposal: UINT8[4]
>>>
>>> Byte [0] Version: 0
>>> byte [1] Length: 4
>>> byte [2] Type:
>>> 	0: legacy
>>> 	1: SEV
>>> 	2: TDX
>>> byte [3] Sub Type:
>>> 	If Type is 0 (legacy), then
>>> 		0: legacy
>>> 	If Type is 1 (SEV), then
>>> 		0: SEV
>>> 		1: SEV-ES
>>> 		2: SEV-SNP
>>> 	If Type is 2 (TDX), then
>>> 		0: TDX 1.0
>>>
>>> Thank you
>>> Yao Jiewen
>>>
>>>
>>>> -----Original Message-----
>>>> From: Xu, Min M <min.m.xu@intel.com>
>>>> Sent: Wednesday, July 28, 2021 2:58 PM
>>>> To: Yao, Jiewen <jiewen.yao@intel.com>
>>>> Cc: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io; Ard
>>>> Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
>>>> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>;
>> James
>>>> Bottomley <jejb@linux.ibm.com>; Tom Lendacky
>> <thomas.lendacky@amd.com>
>>>> Subject: RE: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
>>>>
>>>> On July 28, 2021 2:05 PM, Yao, Jiewen wrote:
>>>>> It does not necessary to be a working area.
>>>>>
>>>>> We just need a common TEE flag to indicate if the system run in legacy, SEV,
>>>> or
>>>>> TDX, right?
>>>> Right. We need somewhere to store this flag, either in a Register or in
>> Memory.
>>>> If it is memory, then in Tdx the memory region should be initialized by host
>> VMM.
>>>>>
>>>>> thank you!
>>>>> Yao, Jiewen
>>>>>
>>>>>
>>>>>> 在 2021年7月28日,下午1:07,Xu, Min M <min.m.xu@intel.com> 写
>> 道:
>>>>>>
>>>>>> On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
>>>>>>> HI Min
>>>>>>> I agree with Brijesh.
>>>>>>>
>>>>>>> The basic rule is: SEV file shall never refer to TDX data structure.
>>>>>>> TDX file shall never refer to SEV data structure.
>>>>>>> These code should be isolated clearly.
>>>>>>>
>>>>>>> Do we still need that logic if we follow the new pattern?
>>>>>> I have replied to Brijesh's mail about the concern of the new pattern.
>>>>>>
>>>>>> I have some concern in the current pattern:
>>>>>> ====================
>>>>>>      OneTimeCall   PreMainFunctionHookSev
>>>>>>      OneTimeCall   PreMainFunctionHookTdx
>>>>>> MainFunction:
>>>>>>      XXXXXX
>>>>>>      OneTimeCall   PostMainFunctionHookSev
>>>>>>      OneTimeCall   PostMainFunctionHookTdx
>>>>>> ====================
>>>>>> The TEE function need implement a TEE check function (such as IsSev, or
>>>> IsTdx).
>>>>>>
>>>>>> Tdx call CPUID(0x21) to determine if it is tdx guest in the very
>>>>>> beginning of ResetVector. Then 'TDXG' is set in TDX_WORK_AREA. SEV
>> does
>>>>> the similar work which call CheckSevFeatures to set SEV_ES_WORK_AREA to
>> 1.
>>>>>>
>>>>>> After that both TDX and SEV read the above WORK_AREA to check if it is
>> TDX
>>>>> or SEV or legacy guest.
>>>>>>
>>>>>> In Tdx the access to SEV_ES_WORK_AREA will trigger error because
>>>>> SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
>>>>>> In SEV-SNP I am afraid the access to TDX_WORK_AREA will trigger error
>> too.
>>>>>>
>>>>>> I am wondering if TDX and SEV can use the same memory region (for
>>>> example,
>>>>> TEE_WORK_AREA) as the work area?
>>>>>> So that this work area is guaranteed to be initialized in both TDX and
>>>>>> SEV. Structure of the TEE_WORK_AREA may look like this:
>>>>>>    typedef struct {
>>>>>>        UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
>>>>>>        UINT8  Others[];
>>>>>>    } TEE_WORK_AREA;
>>>>>>>
>>
>> Are we reserving a new page for the TDX_WORK_AREA ? I am wondering why
>> can't we use the SEV_ES_WORK_AREA instead of wasting space in the MEMFD.
>>
>> The SEV_ES_WORK_AREA layout looks like this:
>>
>> typedef struct _SEC_SEV_ES_WORK_AREA {
>>     UINT8    SevEsEnabled;
>>     UINT8    Reserved1[7];
>>
>>     UINT64   RandomData;
>>
>>     UINT64   EncryptionMask;
>> } SEC_SEV_ES_WORK_AREA;
>>
>> There is reserved bit after the SevEsEnabled and one byte can be used
>> for the TdxEnabled;
>>
>> typedef struct _SEC_SEV_ES_WORK_AREA {
>>     UINT8    SevEsEnabled;
>>     UINT8    TdxEnabled;
>>     UINT8    Reserved2[6];
>>
>>     UINT64   RandomData;
>>
>>     UINT64   EncryptionMask;
>> } SEC_SEV_ES_WORK_AREA;
>>
>> The SEV_ES_WORK_AREA can be treated as a TEE_WORK_AREA and we can be
>> pull out from MemEncrypSevLib.h to CcWorkAreaLib.h and rename the
>> structure (if needed).
>>
>> Both the SEV-SNP and TEE host-VMM accepts the TEE_WORK_AREA before
>> booting the guest to ensure that its safe to access the memory without
>> going through the accept/validation process.
>>
>> In case of the TDX, the reset vector code sets the TdxEnabled on the
>> entry. In case of the SEV, the workarea is valid from SEC to PEI phase
>> only and it gets reused for other purposes. The PEI phase set the Pcd's
>> (such as SevEsEnabled or SevEnabled etc) so that Dxe or other EDK2 core
>> does not need to know anything about the workarea and they simply can
>> read the PCDs.
>>
>> -Brijesh
>>
>>
>> 
>>
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-28 15:59                       ` Brijesh Singh
@ 2021-07-28 16:26                         ` Yao, Jiewen
  2021-07-28 18:58                           ` Brijesh Singh
  0 siblings, 1 reply; 36+ messages in thread
From: Yao, Jiewen @ 2021-07-28 16:26 UTC (permalink / raw)
  To: devel@edk2.groups.io, brijesh.singh@amd.com, Xu, Min M
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky

I would say it is NOT the best software practice to define 2 enable fields to indicate one type.

What if some software error, set both TdxEnable and SevEnable at same time?
How do you detect such error?

If some code may check the SEV only, and some code may check TDX only, then both code can run. That will be a disaster. The code is hard to maintain and hard to debug.

Another consideration is: what if someone wants to set the third type?
Do we want to reserve the 3rd byte? To indicate the third type? It is not scalable.

The best software practice it to just define one field as enumeration. So any software can only set Tdx or Sev. The result is consistent, no matter you check the SEV at first or TDX at first.
If there is 3rd bytes, we just need assign the 3rd value to it, without impact any other field.


I think we can add "must zero" in the comment. But it does not mean there will be no error during development.

UNION is not a type safe structure. Usually, the consumer of UNION shall refer to a common field to know what the type of union is - I treat that as header.

Since we are defining a common data structure, I think we can do some clean up.
Or if you have concern to change SEC_SEV_ES_WORK_AREA, we can define a new CC WORK_AREA without touching SEV_SEV_ES_WORKING_AREA.

Thank you
Yao Jiewen


> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Brijesh
> Singh via groups.io
> Sent: Wednesday, July 28, 2021 11:59 PM
> To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Xu, Min M
> <min.m.xu@intel.com>
> Cc: brijesh.singh@amd.com; Ard Biesheuvel <ardb+tianocore@kernel.org>;
> Justen, Jordan L <jordan.l.justen@intel.com>; Erdem Aktas
> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
> Lendacky <thomas.lendacky@amd.com>
> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> ResetVector
> 
> Hi Yao Jiewen,
> 
> I guess I am still trying to figure out why we need the header in the
> work area. Can't we do something like this:
> 
> typedef struct {
> 	UINT8    SevEsEnabled;
> 
> 	// If Es is enabled then this field must be zeroed
> 	UINT8    MustBeZero;
> 
> 	UINT8    Reserved1[6];
> 
> 	UINT64   RandomData;
> 
> 	UINT64   EncryptionMask;
> } SEC_SEV_ES_WORK_AREA;
> 
> typedef struct {
> 	// If Tdx is enabled then it must be zeroed
> 	UINT8    MustBeZero
> 
> 	UINT8    TdxEnabled;
> 
> 	UINT8    Reserved2[6];
> 	....
> 
> } TX_WORK_AREA;
> 
> typedef union {
> 	SEC_SEV_ES_WORK_AREA SevEsWorkArea;
> 	TDX_WORK_AREA	     TdxWorkArea;
> } CC_WORK_AREA;
> 
> I am trying to minimize the changes to the existing code. The SEV and
> TDX probe logic should ensure that if the feature is detected, then it
> must clear the MustBeZero'ed field.
> 
> Basically, we already have a 64-bit value reserved in the SevEsWork area
> and currently only one byte is used and second byte can be detected for
> the TDX. Basically the which encryption technology is active the
> definition of the work area will change.
> 
> Am I missing something ?
> 
> Thanks
> 
> On 7/28/21 10:22 AM, Yao, Jiewen wrote:
> > Hi Brijesh
> > Thanks!
> >
> > I think if we want to reuse this, we need rename the data structure.
> >
> > First, we should use a generic name.
> >
> > Second, I don’t think it is good idea to define two *enable* fields. Since only
> one of them should be enabled, we should use 1 field as enumeration.
> >
> > Third, we should hide the SEV specific and TDX specific definition in CC
> common work area.
> >
> > If we agree to use a common work area, I recommend below:
> >
> > typedef struct {
> >     UINT8    HeaderVersion; // 0
> >     UINT8    HeadLength; // 4
> >     UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
> >     UINT8    SubType; // Type specific sub type, if needed.
> > } CC_COMMON_WORK_AREA_HEADER;
> >
> > typedef struct {
> >     CC_COMMON_WORK_AREA_HEADER Header;
> >     // reset is valid if Type == 1
> >     UINT8    Reserved1[4];
> >     UINT64   RandomData;
> >     UINT64   EncryptionMask;
> > } SEC_SEV_ES_WORK_AREA;
> >
> > typedef struct {
> >     CC_COMMON_WORK_AREA_HEADER Header;
> >     // reset is valid if Type == 2
> >     UINT8    TdxSpecific[];  // TBD
> > } TDX_WORK_AREA;
> >
> > Thank you
> > Yao Jiewen
> >
> >> -----Original Message-----
> >> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Brijesh
> >> Singh via groups.io
> >> Sent: Wednesday, July 28, 2021 10:34 PM
> >> To: Yao, Jiewen <jiewen.yao@intel.com>; Xu, Min M <min.m.xu@intel.com>
> >> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Ard Biesheuvel
> >> <ardb+tianocore@kernel.org>; Justen, Jordan L <jordan.l.justen@intel.com>;
> >> Erdem Aktas <erdemaktas@google.com>; James Bottomley
> >> <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
> >> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> >> ResetVector
> >>
> >> Hi Jiewen and Min,
> >>
> >> See my comments below.
> >>
> >>
> >> On 7/28/21 2:54 AM, Yao, Jiewen wrote:
> >>> Yes. I am thinking the same thing.
> >>>
> >>> [CC Flag memory location]
> >>> 1) A general purpose register, such as EBP.
> >>>
> >>> 2) A global variable, such as
> >>> .data
> >>> TeeFlags: DD 0
> >>>
> >>> 3) A fixed region in stack, such as
> >>> dword[STACK_TOP - 4]
> >>>
> >>> 4) A new CC common fixed region, such as
> >>> dword[CC_COMMON_FLAGS]
> >>>
> >>> 5) A fixed region piggyback on existing CC working area, such as
> >>> dword[CC_WORKING_AREA]
> >>>
> >>> Hi Brijesh/Min
> >>> Any preference?
> >>>
> >>> [CC Indicator Flags]
> >>> Proposal: UINT8[4]
> >>>
> >>> Byte [0] Version: 0
> >>> byte [1] Length: 4
> >>> byte [2] Type:
> >>> 	0: legacy
> >>> 	1: SEV
> >>> 	2: TDX
> >>> byte [3] Sub Type:
> >>> 	If Type is 0 (legacy), then
> >>> 		0: legacy
> >>> 	If Type is 1 (SEV), then
> >>> 		0: SEV
> >>> 		1: SEV-ES
> >>> 		2: SEV-SNP
> >>> 	If Type is 2 (TDX), then
> >>> 		0: TDX 1.0
> >>>
> >>> Thank you
> >>> Yao Jiewen
> >>>
> >>>
> >>>> -----Original Message-----
> >>>> From: Xu, Min M <min.m.xu@intel.com>
> >>>> Sent: Wednesday, July 28, 2021 2:58 PM
> >>>> To: Yao, Jiewen <jiewen.yao@intel.com>
> >>>> Cc: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io; Ard
> >>>> Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
> >>>> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>;
> >> James
> >>>> Bottomley <jejb@linux.ibm.com>; Tom Lendacky
> >> <thomas.lendacky@amd.com>
> >>>> Subject: RE: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
> >>>>
> >>>> On July 28, 2021 2:05 PM, Yao, Jiewen wrote:
> >>>>> It does not necessary to be a working area.
> >>>>>
> >>>>> We just need a common TEE flag to indicate if the system run in legacy,
> SEV,
> >>>> or
> >>>>> TDX, right?
> >>>> Right. We need somewhere to store this flag, either in a Register or in
> >> Memory.
> >>>> If it is memory, then in Tdx the memory region should be initialized by host
> >> VMM.
> >>>>>
> >>>>> thank you!
> >>>>> Yao, Jiewen
> >>>>>
> >>>>>
> >>>>>> 在 2021年7月28日,下午1:07,Xu, Min M <min.m.xu@intel.com>
> 写
> >> 道:
> >>>>>>
> >>>>>> On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
> >>>>>>> HI Min
> >>>>>>> I agree with Brijesh.
> >>>>>>>
> >>>>>>> The basic rule is: SEV file shall never refer to TDX data structure.
> >>>>>>> TDX file shall never refer to SEV data structure.
> >>>>>>> These code should be isolated clearly.
> >>>>>>>
> >>>>>>> Do we still need that logic if we follow the new pattern?
> >>>>>> I have replied to Brijesh's mail about the concern of the new pattern.
> >>>>>>
> >>>>>> I have some concern in the current pattern:
> >>>>>> ====================
> >>>>>>      OneTimeCall   PreMainFunctionHookSev
> >>>>>>      OneTimeCall   PreMainFunctionHookTdx
> >>>>>> MainFunction:
> >>>>>>      XXXXXX
> >>>>>>      OneTimeCall   PostMainFunctionHookSev
> >>>>>>      OneTimeCall   PostMainFunctionHookTdx
> >>>>>> ====================
> >>>>>> The TEE function need implement a TEE check function (such as IsSev, or
> >>>> IsTdx).
> >>>>>>
> >>>>>> Tdx call CPUID(0x21) to determine if it is tdx guest in the very
> >>>>>> beginning of ResetVector. Then 'TDXG' is set in TDX_WORK_AREA. SEV
> >> does
> >>>>> the similar work which call CheckSevFeatures to set SEV_ES_WORK_AREA
> to
> >> 1.
> >>>>>>
> >>>>>> After that both TDX and SEV read the above WORK_AREA to check if it is
> >> TDX
> >>>>> or SEV or legacy guest.
> >>>>>>
> >>>>>> In Tdx the access to SEV_ES_WORK_AREA will trigger error because
> >>>>> SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
> >>>>>> In SEV-SNP I am afraid the access to TDX_WORK_AREA will trigger error
> >> too.
> >>>>>>
> >>>>>> I am wondering if TDX and SEV can use the same memory region (for
> >>>> example,
> >>>>> TEE_WORK_AREA) as the work area?
> >>>>>> So that this work area is guaranteed to be initialized in both TDX and
> >>>>>> SEV. Structure of the TEE_WORK_AREA may look like this:
> >>>>>>    typedef struct {
> >>>>>>        UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
> >>>>>>        UINT8  Others[];
> >>>>>>    } TEE_WORK_AREA;
> >>>>>>>
> >>
> >> Are we reserving a new page for the TDX_WORK_AREA ? I am wondering why
> >> can't we use the SEV_ES_WORK_AREA instead of wasting space in the
> MEMFD.
> >>
> >> The SEV_ES_WORK_AREA layout looks like this:
> >>
> >> typedef struct _SEC_SEV_ES_WORK_AREA {
> >>     UINT8    SevEsEnabled;
> >>     UINT8    Reserved1[7];
> >>
> >>     UINT64   RandomData;
> >>
> >>     UINT64   EncryptionMask;
> >> } SEC_SEV_ES_WORK_AREA;
> >>
> >> There is reserved bit after the SevEsEnabled and one byte can be used
> >> for the TdxEnabled;
> >>
> >> typedef struct _SEC_SEV_ES_WORK_AREA {
> >>     UINT8    SevEsEnabled;
> >>     UINT8    TdxEnabled;
> >>     UINT8    Reserved2[6];
> >>
> >>     UINT64   RandomData;
> >>
> >>     UINT64   EncryptionMask;
> >> } SEC_SEV_ES_WORK_AREA;
> >>
> >> The SEV_ES_WORK_AREA can be treated as a TEE_WORK_AREA and we can
> be
> >> pull out from MemEncrypSevLib.h to CcWorkAreaLib.h and rename the
> >> structure (if needed).
> >>
> >> Both the SEV-SNP and TEE host-VMM accepts the TEE_WORK_AREA before
> >> booting the guest to ensure that its safe to access the memory without
> >> going through the accept/validation process.
> >>
> >> In case of the TDX, the reset vector code sets the TdxEnabled on the
> >> entry. In case of the SEV, the workarea is valid from SEC to PEI phase
> >> only and it gets reused for other purposes. The PEI phase set the Pcd's
> >> (such as SevEsEnabled or SevEnabled etc) so that Dxe or other EDK2 core
> >> does not need to know anything about the workarea and they simply can
> >> read the PCDs.
> >>
> >> -Brijesh
> >>
> >>
> >>
> >>
> >
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-28 16:26                         ` Yao, Jiewen
@ 2021-07-28 18:58                           ` Brijesh Singh
  2021-07-28 23:48                             ` Yao, Jiewen
  0 siblings, 1 reply; 36+ messages in thread
From: Brijesh Singh @ 2021-07-28 18:58 UTC (permalink / raw)
  To: Yao, Jiewen, devel@edk2.groups.io, Xu, Min M
  Cc: brijesh.singh, Ard Biesheuvel, Justen, Jordan L, Erdem Aktas,
	James Bottomley, Tom Lendacky



On 7/28/21 11:26 AM, Yao, Jiewen wrote:
> I would say it is NOT the best software practice to define 2 enable fields to indicate one type.
> 
> What if some software error, set both TdxEnable and SevEnable at same time?
> How do you detect such error?

Hmm, aren't we saying it is a software bug. In that case another bug can 
also mess up the structure header.

> 
> If some code may check the SEV only, and some code may check TDX only, then both code can run. That will be a disaster. The code is hard to maintain and hard to debug.
> 
> Another consideration is: what if someone wants to set the third type?
> Do we want to reserve the 3rd byte? To indicate the third type? It is not scalable.
> 
> The best software practice it to just define one field as enumeration. So any software can only set Tdx or Sev. The result is consistent, no matter you check the SEV at first or TDX at first.
> If there is 3rd bytes, we just need assign the 3rd value to it, without impact any other field.
> 

I was trying to see if we can make it work without requiring any changes 
to UefiCpuPkg etc (which uses the EsWorkArea).


> 
> I think we can add "must zero" in the comment. But it does not mean there will be no error during development.
> 
> UNION is not a type safe structure. Usually, the consumer of UNION shall refer to a common field to know what the type of union is - I treat that as header.
> 
> Since we are defining a common data structure, I think we can do some clean up.
> Or if you have concern to change SEC_SEV_ES_WORK_AREA, we can define a new CC WORK_AREA without touching SEV_SEV_ES_WORKING_AREA.
> 

In your below structure, I assume the SEV or TDX probe will set the Type 
only when it detects that feature is active. But which layer of the 
software is going to set the type to zero to indicate its a legacy guest ?

typedef struct {
	UINT8    HeaderVersion; // 0
	UINT8    HeadLength; // 4
	UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
	UINT8    SubType; // Type specific sub type, if needed.
} CC_COMMON_WORK_AREA_HEADER;

i.e In this call sequence:

OneTimeCall   PreMainFunctionHookSev
OneTimeCall   PreMainFunctionHookTdx

....


The PreMainFunctionHookSev will detect whether SEV is active or not. If 
its active then set the type = MEM_ENCRYPT_SEV; and similarly the Tdx 
hook will set the type=MEM_ENCRYPT_TDX. What if neither TDX or SEV is 
enabled. At this time we will depend on hypervisor to ensure that value 
at that memory is zero.

Additionally, do you see a need for the HeadLength field in this 
structure ? In asm it is preferred if we can access the actual workarea 
pointer at the fixed location instead of first reading the HeadLength to 
determine how much it need to skip.


> Thank you
> Yao Jiewen
> 
> 
>> -----Original Message-----
>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Brijesh
>> Singh via groups.io
>> Sent: Wednesday, July 28, 2021 11:59 PM
>> To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Xu, Min M
>> <min.m.xu@intel.com>
>> Cc: brijesh.singh@amd.com; Ard Biesheuvel <ardb+tianocore@kernel.org>;
>> Justen, Jordan L <jordan.l.justen@intel.com>; Erdem Aktas
>> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
>> Lendacky <thomas.lendacky@amd.com>
>> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
>> ResetVector
>>
>> Hi Yao Jiewen,
>>
>> I guess I am still trying to figure out why we need the header in the
>> work area. Can't we do something like this:
>>
>> typedef struct {
>> 	UINT8    SevEsEnabled;
>>
>> 	// If Es is enabled then this field must be zeroed
>> 	UINT8    MustBeZero;
>>
>> 	UINT8    Reserved1[6];
>>
>> 	UINT64   RandomData;
>>
>> 	UINT64   EncryptionMask;
>> } SEC_SEV_ES_WORK_AREA;
>>
>> typedef struct {
>> 	// If Tdx is enabled then it must be zeroed
>> 	UINT8    MustBeZero
>>
>> 	UINT8    TdxEnabled;
>>
>> 	UINT8    Reserved2[6];
>> 	....
>>
>> } TX_WORK_AREA;
>>
>> typedef union {
>> 	SEC_SEV_ES_WORK_AREA SevEsWorkArea;
>> 	TDX_WORK_AREA	     TdxWorkArea;
>> } CC_WORK_AREA;
>>
>> I am trying to minimize the changes to the existing code. The SEV and
>> TDX probe logic should ensure that if the feature is detected, then it
>> must clear the MustBeZero'ed field.
>>
>> Basically, we already have a 64-bit value reserved in the SevEsWork area
>> and currently only one byte is used and second byte can be detected for
>> the TDX. Basically the which encryption technology is active the
>> definition of the work area will change.
>>
>> Am I missing something ?
>>
>> Thanks
>>
>> On 7/28/21 10:22 AM, Yao, Jiewen wrote:
>>> Hi Brijesh
>>> Thanks!
>>>
>>> I think if we want to reuse this, we need rename the data structure.
>>>
>>> First, we should use a generic name.
>>>
>>> Second, I don’t think it is good idea to define two *enable* fields. Since only
>> one of them should be enabled, we should use 1 field as enumeration.
>>>
>>> Third, we should hide the SEV specific and TDX specific definition in CC
>> common work area.
>>>
>>> If we agree to use a common work area, I recommend below:
>>>
>>> typedef struct {
>>>      UINT8    HeaderVersion; // 0
>>>      UINT8    HeadLength; // 4
>>>      UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
>>>      UINT8    SubType; // Type specific sub type, if needed.
>>> } CC_COMMON_WORK_AREA_HEADER;
>>>
>>> typedef struct {
>>>      CC_COMMON_WORK_AREA_HEADER Header;
>>>      // reset is valid if Type == 1
>>>      UINT8    Reserved1[4];
>>>      UINT64   RandomData;
>>>      UINT64   EncryptionMask;
>>> } SEC_SEV_ES_WORK_AREA;
>>>
>>> typedef struct {
>>>      CC_COMMON_WORK_AREA_HEADER Header;
>>>      // reset is valid if Type == 2
>>>      UINT8    TdxSpecific[];  // TBD
>>> } TDX_WORK_AREA;
>>>
>>> Thank you
>>> Yao Jiewen
>>>
>>>> -----Original Message-----
>>>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Brijesh
>>>> Singh via groups.io
>>>> Sent: Wednesday, July 28, 2021 10:34 PM
>>>> To: Yao, Jiewen <jiewen.yao@intel.com>; Xu, Min M <min.m.xu@intel.com>
>>>> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Ard Biesheuvel
>>>> <ardb+tianocore@kernel.org>; Justen, Jordan L <jordan.l.justen@intel.com>;
>>>> Erdem Aktas <erdemaktas@google.com>; James Bottomley
>>>> <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
>>>> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
>>>> ResetVector
>>>>
>>>> Hi Jiewen and Min,
>>>>
>>>> See my comments below.
>>>>
>>>>
>>>> On 7/28/21 2:54 AM, Yao, Jiewen wrote:
>>>>> Yes. I am thinking the same thing.
>>>>>
>>>>> [CC Flag memory location]
>>>>> 1) A general purpose register, such as EBP.
>>>>>
>>>>> 2) A global variable, such as
>>>>> .data
>>>>> TeeFlags: DD 0
>>>>>
>>>>> 3) A fixed region in stack, such as
>>>>> dword[STACK_TOP - 4]
>>>>>
>>>>> 4) A new CC common fixed region, such as
>>>>> dword[CC_COMMON_FLAGS]
>>>>>
>>>>> 5) A fixed region piggyback on existing CC working area, such as
>>>>> dword[CC_WORKING_AREA]
>>>>>
>>>>> Hi Brijesh/Min
>>>>> Any preference?
>>>>>
>>>>> [CC Indicator Flags]
>>>>> Proposal: UINT8[4]
>>>>>
>>>>> Byte [0] Version: 0
>>>>> byte [1] Length: 4
>>>>> byte [2] Type:
>>>>> 	0: legacy
>>>>> 	1: SEV
>>>>> 	2: TDX
>>>>> byte [3] Sub Type:
>>>>> 	If Type is 0 (legacy), then
>>>>> 		0: legacy
>>>>> 	If Type is 1 (SEV), then
>>>>> 		0: SEV
>>>>> 		1: SEV-ES
>>>>> 		2: SEV-SNP
>>>>> 	If Type is 2 (TDX), then
>>>>> 		0: TDX 1.0
>>>>>
>>>>> Thank you
>>>>> Yao Jiewen
>>>>>
>>>>>
>>>>>> -----Original Message-----
>>>>>> From: Xu, Min M <min.m.xu@intel.com>
>>>>>> Sent: Wednesday, July 28, 2021 2:58 PM
>>>>>> To: Yao, Jiewen <jiewen.yao@intel.com>
>>>>>> Cc: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io; Ard
>>>>>> Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
>>>>>> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>;
>>>> James
>>>>>> Bottomley <jejb@linux.ibm.com>; Tom Lendacky
>>>> <thomas.lendacky@amd.com>
>>>>>> Subject: RE: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
>>>>>>
>>>>>> On July 28, 2021 2:05 PM, Yao, Jiewen wrote:
>>>>>>> It does not necessary to be a working area.
>>>>>>>
>>>>>>> We just need a common TEE flag to indicate if the system run in legacy,
>> SEV,
>>>>>> or
>>>>>>> TDX, right?
>>>>>> Right. We need somewhere to store this flag, either in a Register or in
>>>> Memory.
>>>>>> If it is memory, then in Tdx the memory region should be initialized by host
>>>> VMM.
>>>>>>>
>>>>>>> thank you!
>>>>>>> Yao, Jiewen
>>>>>>>
>>>>>>>
>>>>>>>> 在 2021年7月28日,下午1:07,Xu, Min M <min.m.xu@intel.com>
>> 写
>>>> 道:
>>>>>>>>
>>>>>>>> On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
>>>>>>>>> HI Min
>>>>>>>>> I agree with Brijesh.
>>>>>>>>>
>>>>>>>>> The basic rule is: SEV file shall never refer to TDX data structure.
>>>>>>>>> TDX file shall never refer to SEV data structure.
>>>>>>>>> These code should be isolated clearly.
>>>>>>>>>
>>>>>>>>> Do we still need that logic if we follow the new pattern?
>>>>>>>> I have replied to Brijesh's mail about the concern of the new pattern.
>>>>>>>>
>>>>>>>> I have some concern in the current pattern:
>>>>>>>> ====================
>>>>>>>>       OneTimeCall   PreMainFunctionHookSev
>>>>>>>>       OneTimeCall   PreMainFunctionHookTdx
>>>>>>>> MainFunction:
>>>>>>>>       XXXXXX
>>>>>>>>       OneTimeCall   PostMainFunctionHookSev
>>>>>>>>       OneTimeCall   PostMainFunctionHookTdx
>>>>>>>> ====================
>>>>>>>> The TEE function need implement a TEE check function (such as IsSev, or
>>>>>> IsTdx).
>>>>>>>>
>>>>>>>> Tdx call CPUID(0x21) to determine if it is tdx guest in the very
>>>>>>>> beginning of ResetVector. Then 'TDXG' is set in TDX_WORK_AREA. SEV
>>>> does
>>>>>>> the similar work which call CheckSevFeatures to set SEV_ES_WORK_AREA
>> to
>>>> 1.
>>>>>>>>
>>>>>>>> After that both TDX and SEV read the above WORK_AREA to check if it is
>>>> TDX
>>>>>>> or SEV or legacy guest.
>>>>>>>>
>>>>>>>> In Tdx the access to SEV_ES_WORK_AREA will trigger error because
>>>>>>> SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
>>>>>>>> In SEV-SNP I am afraid the access to TDX_WORK_AREA will trigger error
>>>> too.
>>>>>>>>
>>>>>>>> I am wondering if TDX and SEV can use the same memory region (for
>>>>>> example,
>>>>>>> TEE_WORK_AREA) as the work area?
>>>>>>>> So that this work area is guaranteed to be initialized in both TDX and
>>>>>>>> SEV. Structure of the TEE_WORK_AREA may look like this:
>>>>>>>>     typedef struct {
>>>>>>>>         UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
>>>>>>>>         UINT8  Others[];
>>>>>>>>     } TEE_WORK_AREA;
>>>>>>>>>
>>>>
>>>> Are we reserving a new page for the TDX_WORK_AREA ? I am wondering why
>>>> can't we use the SEV_ES_WORK_AREA instead of wasting space in the
>> MEMFD.
>>>>
>>>> The SEV_ES_WORK_AREA layout looks like this:
>>>>
>>>> typedef struct _SEC_SEV_ES_WORK_AREA {
>>>>      UINT8    SevEsEnabled;
>>>>      UINT8    Reserved1[7];
>>>>
>>>>      UINT64   RandomData;
>>>>
>>>>      UINT64   EncryptionMask;
>>>> } SEC_SEV_ES_WORK_AREA;
>>>>
>>>> There is reserved bit after the SevEsEnabled and one byte can be used
>>>> for the TdxEnabled;
>>>>
>>>> typedef struct _SEC_SEV_ES_WORK_AREA {
>>>>      UINT8    SevEsEnabled;
>>>>      UINT8    TdxEnabled;
>>>>      UINT8    Reserved2[6];
>>>>
>>>>      UINT64   RandomData;
>>>>
>>>>      UINT64   EncryptionMask;
>>>> } SEC_SEV_ES_WORK_AREA;
>>>>
>>>> The SEV_ES_WORK_AREA can be treated as a TEE_WORK_AREA and we can
>> be
>>>> pull out from MemEncrypSevLib.h to CcWorkAreaLib.h and rename the
>>>> structure (if needed).
>>>>
>>>> Both the SEV-SNP and TEE host-VMM accepts the TEE_WORK_AREA before
>>>> booting the guest to ensure that its safe to access the memory without
>>>> going through the accept/validation process.
>>>>
>>>> In case of the TDX, the reset vector code sets the TdxEnabled on the
>>>> entry. In case of the SEV, the workarea is valid from SEC to PEI phase
>>>> only and it gets reused for other purposes. The PEI phase set the Pcd's
>>>> (such as SevEsEnabled or SevEnabled etc) so that Dxe or other EDK2 core
>>>> does not need to know anything about the workarea and they simply can
>>>> read the PCDs.
>>>>
>>>> -Brijesh
>>>>
>>>>
>>>>
>>>>
>>>
>>
>>
>> 
>>
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-28 18:58                           ` Brijesh Singh
@ 2021-07-28 23:48                             ` Yao, Jiewen
  2021-07-29  2:44                               ` Min Xu
  0 siblings, 1 reply; 36+ messages in thread
From: Yao, Jiewen @ 2021-07-28 23:48 UTC (permalink / raw)
  To: Brijesh Singh, devel@edk2.groups.io, Xu, Min M
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky

Comment below:

> -----Original Message-----
> From: Brijesh Singh <brijesh.singh@amd.com>
> Sent: Thursday, July 29, 2021 2:59 AM
> To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Xu, Min M
> <min.m.xu@intel.com>
> Cc: brijesh.singh@amd.com; Ard Biesheuvel <ardb+tianocore@kernel.org>;
> Justen, Jordan L <jordan.l.justen@intel.com>; Erdem Aktas
> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
> Lendacky <thomas.lendacky@amd.com>
> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> ResetVector
> 
> 
> 
> On 7/28/21 11:26 AM, Yao, Jiewen wrote:
> > I would say it is NOT the best software practice to define 2 enable fields to
> indicate one type.
> >
> > What if some software error, set both TdxEnable and SevEnable at same time?
> > How do you detect such error?
> 
> Hmm, aren't we saying it is a software bug. In that case another bug can
> also mess up the structure header.
[Jiewen] Yes. I treat it as a software implementation bug.
The key thing in software design is to avoid the developer making mistake, help debug issues, help maintain the code easily.


> 
> >
> > If some code may check the SEV only, and some code may check TDX only,
> then both code can run. That will be a disaster. The code is hard to maintain and
> hard to debug.
> >
> > Another consideration is: what if someone wants to set the third type?
> > Do we want to reserve the 3rd byte? To indicate the third type? It is not
> scalable.
> >
> > The best software practice it to just define one field as enumeration. So any
> software can only set Tdx or Sev. The result is consistent, no matter you check
> the SEV at first or TDX at first.
> > If there is 3rd bytes, we just need assign the 3rd value to it, without impact any
> other field.
> >
> 
> I was trying to see if we can make it work without requiring any changes
> to UefiCpuPkg etc (which uses the EsWorkArea).
[Jiewen] I agree with you.
And I think the priority should be:
1) make a good design following the best practice.
2) minimize the change.

I don’t think two *enable* fields can satisfy #1.
And I am open on how to do #2. (See rest comment below)



> 
> 
> >
> > I think we can add "must zero" in the comment. But it does not mean there will
> be no error during development.
> >
> > UNION is not a type safe structure. Usually, the consumer of UNION shall
> refer to a common field to know what the type of union is - I treat that as
> header.
> >
> > Since we are defining a common data structure, I think we can do some clean
> up.
> > Or if you have concern to change SEC_SEV_ES_WORK_AREA, we can define a
> new CC WORK_AREA without touching SEV_SEV_ES_WORKING_AREA.
> >
> 
> In your below structure, I assume the SEV or TDX probe will set the Type
> only when it detects that feature is active. But which layer of the
> software is going to set the type to zero to indicate its a legacy guest ?
[Jiewen] Good question.
I expect some initialization function, such as InitCcWorkAreaSev, InitCcWorkAreaTdx.
The default value Legacy shall be override in InitCcWorkArea after capability check.
PreMainFunctionHookXXX is common patter for all function. It just checks the CcWorkArea.



> 
> typedef struct {
> 	UINT8    HeaderVersion; // 0
> 	UINT8    HeadLength; // 4
> 	UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
> 	UINT8    SubType; // Type specific sub type, if needed.
> } CC_COMMON_WORK_AREA_HEADER;
> 
> i.e In this call sequence:
> 
> OneTimeCall   PreMainFunctionHookSev
> OneTimeCall   PreMainFunctionHookTdx
> 
> ....
> 
> The PreMainFunctionHookSev will detect whether SEV is active or not. If
> its active then set the type = MEM_ENCRYPT_SEV; and similarly the Tdx
> hook will set the type=MEM_ENCRYPT_TDX. What if neither TDX or SEV is
> enabled. At this time we will depend on hypervisor to ensure that value
> at that memory is zero.
[Jiewen] I think we just let InitCcWorkAreaSev and InitCcWorkAreaTdx override the default value.
InitCcWorkArea{Sev,Tdx}:
	// Detect Hardware Capability 
	// If discovered, then set Type = {SEV,TDX}
	// Else, leave it as is




> 
> Additionally, do you see a need for the HeadLength field in this
> structure ? In asm it is preferred if we can access the actual workarea
> pointer at the fixed location instead of first reading the HeadLength to
> determine how much it need to skip.
[Jiewen] You are right.
Length/Version is NOT absolutely necessary, if the header is simple enough. If you think we don’t need them, I am OK to remove them.
I think only "Type" is mandatory, which tells us the category.
I think "SubType" is useful, because we might want to know if it is SEV, or SEV-ES, or SEV-SNP, and if it is TDX 1.0, or TDX.future. Please let me know your thought.


One question on SEC_SEV_ES_WORK_AREA. Since you have SEV/SEV-ES/SEV-SNP, is this SEV_ES_WORK_AREA only for SEV_ES? Or it is also used in SEV (no SEV_ES), and SEV_SNP ?
For example, when we see SevEsEnable=0, how do we know it is SEV (no SEV_ES) or legacy (no SEV, no SEV_ES)? Or we don’t need care in SEV (no SEV_ES) case.




> 
> 
> > Thank you
> > Yao Jiewen
> >
> >
> >> -----Original Message-----
> >> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Brijesh
> >> Singh via groups.io
> >> Sent: Wednesday, July 28, 2021 11:59 PM
> >> To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Xu, Min M
> >> <min.m.xu@intel.com>
> >> Cc: brijesh.singh@amd.com; Ard Biesheuvel <ardb+tianocore@kernel.org>;
> >> Justen, Jordan L <jordan.l.justen@intel.com>; Erdem Aktas
> >> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
> >> Lendacky <thomas.lendacky@amd.com>
> >> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> >> ResetVector
> >>
> >> Hi Yao Jiewen,
> >>
> >> I guess I am still trying to figure out why we need the header in the
> >> work area. Can't we do something like this:
> >>
> >> typedef struct {
> >> 	UINT8    SevEsEnabled;
> >>
> >> 	// If Es is enabled then this field must be zeroed
> >> 	UINT8    MustBeZero;
> >>
> >> 	UINT8    Reserved1[6];
> >>
> >> 	UINT64   RandomData;
> >>
> >> 	UINT64   EncryptionMask;
> >> } SEC_SEV_ES_WORK_AREA;
> >>
> >> typedef struct {
> >> 	// If Tdx is enabled then it must be zeroed
> >> 	UINT8    MustBeZero
> >>
> >> 	UINT8    TdxEnabled;
> >>
> >> 	UINT8    Reserved2[6];
> >> 	....
> >>
> >> } TX_WORK_AREA;
> >>
> >> typedef union {
> >> 	SEC_SEV_ES_WORK_AREA SevEsWorkArea;
> >> 	TDX_WORK_AREA	     TdxWorkArea;
> >> } CC_WORK_AREA;
> >>
> >> I am trying to minimize the changes to the existing code. The SEV and
> >> TDX probe logic should ensure that if the feature is detected, then it
> >> must clear the MustBeZero'ed field.
> >>
> >> Basically, we already have a 64-bit value reserved in the SevEsWork area
> >> and currently only one byte is used and second byte can be detected for
> >> the TDX. Basically the which encryption technology is active the
> >> definition of the work area will change.
> >>
> >> Am I missing something ?
> >>
> >> Thanks
> >>
> >> On 7/28/21 10:22 AM, Yao, Jiewen wrote:
> >>> Hi Brijesh
> >>> Thanks!
> >>>
> >>> I think if we want to reuse this, we need rename the data structure.
> >>>
> >>> First, we should use a generic name.
> >>>
> >>> Second, I don’t think it is good idea to define two *enable* fields. Since only
> >> one of them should be enabled, we should use 1 field as enumeration.
> >>>
> >>> Third, we should hide the SEV specific and TDX specific definition in CC
> >> common work area.
> >>>
> >>> If we agree to use a common work area, I recommend below:
> >>>
> >>> typedef struct {
> >>>      UINT8    HeaderVersion; // 0
> >>>      UINT8    HeadLength; // 4
> >>>      UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
> >>>      UINT8    SubType; // Type specific sub type, if needed.
> >>> } CC_COMMON_WORK_AREA_HEADER;
> >>>
> >>> typedef struct {
> >>>      CC_COMMON_WORK_AREA_HEADER Header;
> >>>      // reset is valid if Type == 1
> >>>      UINT8    Reserved1[4];
> >>>      UINT64   RandomData;
> >>>      UINT64   EncryptionMask;
> >>> } SEC_SEV_ES_WORK_AREA;
> >>>
> >>> typedef struct {
> >>>      CC_COMMON_WORK_AREA_HEADER Header;
> >>>      // reset is valid if Type == 2
> >>>      UINT8    TdxSpecific[];  // TBD
> >>> } TDX_WORK_AREA;
> >>>
> >>> Thank you
> >>> Yao Jiewen
> >>>
> >>>> -----Original Message-----
> >>>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Brijesh
> >>>> Singh via groups.io
> >>>> Sent: Wednesday, July 28, 2021 10:34 PM
> >>>> To: Yao, Jiewen <jiewen.yao@intel.com>; Xu, Min M
> <min.m.xu@intel.com>
> >>>> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Ard Biesheuvel
> >>>> <ardb+tianocore@kernel.org>; Justen, Jordan L
> <jordan.l.justen@intel.com>;
> >>>> Erdem Aktas <erdemaktas@google.com>; James Bottomley
> >>>> <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
> >>>> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> >>>> ResetVector
> >>>>
> >>>> Hi Jiewen and Min,
> >>>>
> >>>> See my comments below.
> >>>>
> >>>>
> >>>> On 7/28/21 2:54 AM, Yao, Jiewen wrote:
> >>>>> Yes. I am thinking the same thing.
> >>>>>
> >>>>> [CC Flag memory location]
> >>>>> 1) A general purpose register, such as EBP.
> >>>>>
> >>>>> 2) A global variable, such as
> >>>>> .data
> >>>>> TeeFlags: DD 0
> >>>>>
> >>>>> 3) A fixed region in stack, such as
> >>>>> dword[STACK_TOP - 4]
> >>>>>
> >>>>> 4) A new CC common fixed region, such as
> >>>>> dword[CC_COMMON_FLAGS]
> >>>>>
> >>>>> 5) A fixed region piggyback on existing CC working area, such as
> >>>>> dword[CC_WORKING_AREA]
> >>>>>
> >>>>> Hi Brijesh/Min
> >>>>> Any preference?
> >>>>>
> >>>>> [CC Indicator Flags]
> >>>>> Proposal: UINT8[4]
> >>>>>
> >>>>> Byte [0] Version: 0
> >>>>> byte [1] Length: 4
> >>>>> byte [2] Type:
> >>>>> 	0: legacy
> >>>>> 	1: SEV
> >>>>> 	2: TDX
> >>>>> byte [3] Sub Type:
> >>>>> 	If Type is 0 (legacy), then
> >>>>> 		0: legacy
> >>>>> 	If Type is 1 (SEV), then
> >>>>> 		0: SEV
> >>>>> 		1: SEV-ES
> >>>>> 		2: SEV-SNP
> >>>>> 	If Type is 2 (TDX), then
> >>>>> 		0: TDX 1.0
> >>>>>
> >>>>> Thank you
> >>>>> Yao Jiewen
> >>>>>
> >>>>>
> >>>>>> -----Original Message-----
> >>>>>> From: Xu, Min M <min.m.xu@intel.com>
> >>>>>> Sent: Wednesday, July 28, 2021 2:58 PM
> >>>>>> To: Yao, Jiewen <jiewen.yao@intel.com>
> >>>>>> Cc: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io; Ard
> >>>>>> Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
> >>>>>> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>;
> >>>> James
> >>>>>> Bottomley <jejb@linux.ibm.com>; Tom Lendacky
> >>>> <thomas.lendacky@amd.com>
> >>>>>> Subject: RE: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> ResetVector
> >>>>>>
> >>>>>> On July 28, 2021 2:05 PM, Yao, Jiewen wrote:
> >>>>>>> It does not necessary to be a working area.
> >>>>>>>
> >>>>>>> We just need a common TEE flag to indicate if the system run in legacy,
> >> SEV,
> >>>>>> or
> >>>>>>> TDX, right?
> >>>>>> Right. We need somewhere to store this flag, either in a Register or in
> >>>> Memory.
> >>>>>> If it is memory, then in Tdx the memory region should be initialized by
> host
> >>>> VMM.
> >>>>>>>
> >>>>>>> thank you!
> >>>>>>> Yao, Jiewen
> >>>>>>>
> >>>>>>>
> >>>>>>>> 在 2021年7月28日,下午1:07,Xu, Min M <min.m.xu@intel.com>
> >> 写
> >>>> 道:
> >>>>>>>>
> >>>>>>>> On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
> >>>>>>>>> HI Min
> >>>>>>>>> I agree with Brijesh.
> >>>>>>>>>
> >>>>>>>>> The basic rule is: SEV file shall never refer to TDX data structure.
> >>>>>>>>> TDX file shall never refer to SEV data structure.
> >>>>>>>>> These code should be isolated clearly.
> >>>>>>>>>
> >>>>>>>>> Do we still need that logic if we follow the new pattern?
> >>>>>>>> I have replied to Brijesh's mail about the concern of the new pattern.
> >>>>>>>>
> >>>>>>>> I have some concern in the current pattern:
> >>>>>>>> ====================
> >>>>>>>>       OneTimeCall   PreMainFunctionHookSev
> >>>>>>>>       OneTimeCall   PreMainFunctionHookTdx
> >>>>>>>> MainFunction:
> >>>>>>>>       XXXXXX
> >>>>>>>>       OneTimeCall   PostMainFunctionHookSev
> >>>>>>>>       OneTimeCall   PostMainFunctionHookTdx
> >>>>>>>> ====================
> >>>>>>>> The TEE function need implement a TEE check function (such as IsSev,
> or
> >>>>>> IsTdx).
> >>>>>>>>
> >>>>>>>> Tdx call CPUID(0x21) to determine if it is tdx guest in the very
> >>>>>>>> beginning of ResetVector. Then 'TDXG' is set in TDX_WORK_AREA.
> SEV
> >>>> does
> >>>>>>> the similar work which call CheckSevFeatures to set
> SEV_ES_WORK_AREA
> >> to
> >>>> 1.
> >>>>>>>>
> >>>>>>>> After that both TDX and SEV read the above WORK_AREA to check if it
> is
> >>>> TDX
> >>>>>>> or SEV or legacy guest.
> >>>>>>>>
> >>>>>>>> In Tdx the access to SEV_ES_WORK_AREA will trigger error because
> >>>>>>> SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
> >>>>>>>> In SEV-SNP I am afraid the access to TDX_WORK_AREA will trigger
> error
> >>>> too.
> >>>>>>>>
> >>>>>>>> I am wondering if TDX and SEV can use the same memory region (for
> >>>>>> example,
> >>>>>>> TEE_WORK_AREA) as the work area?
> >>>>>>>> So that this work area is guaranteed to be initialized in both TDX and
> >>>>>>>> SEV. Structure of the TEE_WORK_AREA may look like this:
> >>>>>>>>     typedef struct {
> >>>>>>>>         UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
> >>>>>>>>         UINT8  Others[];
> >>>>>>>>     } TEE_WORK_AREA;
> >>>>>>>>>
> >>>>
> >>>> Are we reserving a new page for the TDX_WORK_AREA ? I am wondering
> why
> >>>> can't we use the SEV_ES_WORK_AREA instead of wasting space in the
> >> MEMFD.
> >>>>
> >>>> The SEV_ES_WORK_AREA layout looks like this:
> >>>>
> >>>> typedef struct _SEC_SEV_ES_WORK_AREA {
> >>>>      UINT8    SevEsEnabled;
> >>>>      UINT8    Reserved1[7];
> >>>>
> >>>>      UINT64   RandomData;
> >>>>
> >>>>      UINT64   EncryptionMask;
> >>>> } SEC_SEV_ES_WORK_AREA;
> >>>>
> >>>> There is reserved bit after the SevEsEnabled and one byte can be used
> >>>> for the TdxEnabled;
> >>>>
> >>>> typedef struct _SEC_SEV_ES_WORK_AREA {
> >>>>      UINT8    SevEsEnabled;
> >>>>      UINT8    TdxEnabled;
> >>>>      UINT8    Reserved2[6];
> >>>>
> >>>>      UINT64   RandomData;
> >>>>
> >>>>      UINT64   EncryptionMask;
> >>>> } SEC_SEV_ES_WORK_AREA;
> >>>>
> >>>> The SEV_ES_WORK_AREA can be treated as a TEE_WORK_AREA and we
> can
> >> be
> >>>> pull out from MemEncrypSevLib.h to CcWorkAreaLib.h and rename the
> >>>> structure (if needed).
> >>>>
> >>>> Both the SEV-SNP and TEE host-VMM accepts the TEE_WORK_AREA
> before
> >>>> booting the guest to ensure that its safe to access the memory without
> >>>> going through the accept/validation process.
> >>>>
> >>>> In case of the TDX, the reset vector code sets the TdxEnabled on the
> >>>> entry. In case of the SEV, the workarea is valid from SEC to PEI phase
> >>>> only and it gets reused for other purposes. The PEI phase set the Pcd's
> >>>> (such as SevEsEnabled or SevEnabled etc) so that Dxe or other EDK2 core
> >>>> does not need to know anything about the workarea and they simply can
> >>>> read the PCDs.
> >>>>
> >>>> -Brijesh
> >>>>
> >>>>
> >>>>
> >>>>
> >>>
> >>
> >>
> >> 
> >>
> >

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-28 23:48                             ` Yao, Jiewen
@ 2021-07-29  2:44                               ` Min Xu
  2021-07-29  4:29                                 ` Brijesh Singh
  0 siblings, 1 reply; 36+ messages in thread
From: Min Xu @ 2021-07-29  2:44 UTC (permalink / raw)
  To: Yao, Jiewen, Brijesh Singh, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky

Jiewen & Singh

From the discussion I am thinking we have below rules to follow to the design the structure
of TEE_WORK_AREA:
1. Design should be flexible but not too complicated
2. Reuse the current SEV_ES_WORK_AREA (PcdSevEsWorkAreaBase) as TEE_WORK_AREA
3. TEE_WORK_AREA should be initialized to all-0 at the beginning of ResetVecotr
4. Reduce the changes to exiting code if possible

So I try to make below conclusions below: (Please review)
1. SEV_ES_WORK_AREA is used as the TEE_WORK_AREA by both TDX and SEV, maybe in
the future it can be used by other CC technologies.

2. In MEMFD, add below initial value. So that TEE_WORK_AREA is guaranteed to be cleared
in legacy guest. In TDX this memory region is initialized to be all-0 by host VMM. In SEV the memory
region is cleared as well.
  0x00B000|0x001000
  gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaSize
  DATA = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  }

3. The structure of TEE_WORK_AREA
  The current SEV_ES_WORK_AREA is defined as below:
  typedef struct {
    UINT8    SevEsEnabled;
    UINT8    Reserved1[7];
    [Others...]
} SEC_SEV_ES_WORK_AREA;

So I think the TEE_WORK_AREA can be:
  Byte[0] Type:
    	0: legacy 1: SEV 	2: TDX 
  Byte[1] Subtype:
              If Type is 0, then it is 0
	If Type is 1, then it is up to SEV's definition
	If Type is 2, then it is up to TDX's definition
 Byte[] other bytes are defined based on the Type/Subtype

I check the code in SecMain.c.
 SevEsIsEnabled() need updated to check SevEsWorkarea->SevEsEnabled == 1, not non-0.
@Brijesh Singh Is there any other code need update?

> -----Original Message-----
> From: Yao, Jiewen <jiewen.yao@intel.com>
> Sent: Thursday, July 29, 2021 7:49 AM
> To: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io; Xu, Min M
> <min.m.xu@intel.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>; James
> Bottomley <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
> Subject: RE: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> ResetVector
> 
> Comment below:
> 
> > -----Original Message-----
> > From: Brijesh Singh <brijesh.singh@amd.com>
> > Sent: Thursday, July 29, 2021 2:59 AM
> > To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Xu, Min
> > M <min.m.xu@intel.com>
> > Cc: brijesh.singh@amd.com; Ard Biesheuvel <ardb+tianocore@kernel.org>;
> > Justen, Jordan L <jordan.l.justen@intel.com>; Erdem Aktas
> > <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
> > Lendacky <thomas.lendacky@amd.com>
> > Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> > ResetVector
> >
> >
> >
> > On 7/28/21 11:26 AM, Yao, Jiewen wrote:
> > > I would say it is NOT the best software practice to define 2 enable
> > > fields to
> > indicate one type.
> > >
> > > What if some software error, set both TdxEnable and SevEnable at same
> time?
> > > How do you detect such error?
> >
> > Hmm, aren't we saying it is a software bug. In that case another bug
> > can also mess up the structure header.
> [Jiewen] Yes. I treat it as a software implementation bug.
> The key thing in software design is to avoid the developer making mistake, help
> debug issues, help maintain the code easily.
> 
> 
> >
> > >
> > > If some code may check the SEV only, and some code may check TDX
> > > only,
> > then both code can run. That will be a disaster. The code is hard to
> > maintain and hard to debug.
> > >
> > > Another consideration is: what if someone wants to set the third type?
> > > Do we want to reserve the 3rd byte? To indicate the third type? It
> > > is not
> > scalable.
> > >
> > > The best software practice it to just define one field as
> > > enumeration. So any
> > software can only set Tdx or Sev. The result is consistent, no matter
> > you check the SEV at first or TDX at first.
> > > If there is 3rd bytes, we just need assign the 3rd value to it,
> > > without impact any
> > other field.
> > >
> >
> > I was trying to see if we can make it work without requiring any
> > changes to UefiCpuPkg etc (which uses the EsWorkArea).
> [Jiewen] I agree with you.
> And I think the priority should be:
> 1) make a good design following the best practice.
> 2) minimize the change.
> 
> I don’t think two *enable* fields can satisfy #1.
> And I am open on how to do #2. (See rest comment below)
> 
> 
> 
> >
> >
> > >
> > > I think we can add "must zero" in the comment. But it does not mean
> > > there will
> > be no error during development.
> > >
> > > UNION is not a type safe structure. Usually, the consumer of UNION
> > > shall
> > refer to a common field to know what the type of union is - I treat
> > that as header.
> > >
> > > Since we are defining a common data structure, I think we can do
> > > some clean
> > up.
> > > Or if you have concern to change SEC_SEV_ES_WORK_AREA, we can define
> > > a
> > new CC WORK_AREA without touching SEV_SEV_ES_WORKING_AREA.
> > >
> >
> > In your below structure, I assume the SEV or TDX probe will set the
> > Type only when it detects that feature is active. But which layer of
> > the software is going to set the type to zero to indicate its a legacy guest ?
> [Jiewen] Good question.
> I expect some initialization function, such as InitCcWorkAreaSev,
> InitCcWorkAreaTdx.
> The default value Legacy shall be override in InitCcWorkArea after capability
> check.
> PreMainFunctionHookXXX is common patter for all function. It just checks the
> CcWorkArea.
> 
> 
> 
> >
> > typedef struct {
> > 	UINT8    HeaderVersion; // 0
> > 	UINT8    HeadLength; // 4
> > 	UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
> > 	UINT8    SubType; // Type specific sub type, if needed.
> > } CC_COMMON_WORK_AREA_HEADER;
> >
> > i.e In this call sequence:
> >
> > OneTimeCall   PreMainFunctionHookSev
> > OneTimeCall   PreMainFunctionHookTdx
> >
> > ....
> >
> > The PreMainFunctionHookSev will detect whether SEV is active or not.
> > If its active then set the type = MEM_ENCRYPT_SEV; and similarly the
> > Tdx hook will set the type=MEM_ENCRYPT_TDX. What if neither TDX or SEV
> > is enabled. At this time we will depend on hypervisor to ensure that
> > value at that memory is zero.
> [Jiewen] I think we just let InitCcWorkAreaSev and InitCcWorkAreaTdx override
> the default value.
> InitCcWorkArea{Sev,Tdx}:
> 	// Detect Hardware Capability
> 	// If discovered, then set Type = {SEV,TDX}
> 	// Else, leave it as is
> 
> 
> 
> 
> >
> > Additionally, do you see a need for the HeadLength field in this
> > structure ? In asm it is preferred if we can access the actual
> > workarea pointer at the fixed location instead of first reading the
> > HeadLength to determine how much it need to skip.
> [Jiewen] You are right.
> Length/Version is NOT absolutely necessary, if the header is simple enough. If
> you think we don’t need them, I am OK to remove them.
> I think only "Type" is mandatory, which tells us the category.
> I think "SubType" is useful, because we might want to know if it is SEV, or SEV-ES,
> or SEV-SNP, and if it is TDX 1.0, or TDX.future. Please let me know your thought.
> 
> 
> One question on SEC_SEV_ES_WORK_AREA. Since you have SEV/SEV-ES/SEV-
> SNP, is this SEV_ES_WORK_AREA only for SEV_ES? Or it is also used in SEV (no
> SEV_ES), and SEV_SNP ?
> For example, when we see SevEsEnable=0, how do we know it is SEV (no SEV_ES)
> or legacy (no SEV, no SEV_ES)? Or we don’t need care in SEV (no SEV_ES) case.
> 
> 
> 
> 
> >
> >
> > > Thank you
> > > Yao Jiewen
> > >
> > >
> > >> -----Original Message-----
> > >> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of
> > >> Brijesh Singh via groups.io
> > >> Sent: Wednesday, July 28, 2021 11:59 PM
> > >> To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Xu,
> > >> Min M <min.m.xu@intel.com>
> > >> Cc: brijesh.singh@amd.com; Ard Biesheuvel
> > >> <ardb+tianocore@kernel.org>; Justen, Jordan L
> > >> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>;
> > >> James Bottomley <jejb@linux.ibm.com>; Tom Lendacky
> > >> <thomas.lendacky@amd.com>
> > >> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm
> > >> in ResetVector
> > >>
> > >> Hi Yao Jiewen,
> > >>
> > >> I guess I am still trying to figure out why we need the header in
> > >> the work area. Can't we do something like this:
> > >>
> > >> typedef struct {
> > >> 	UINT8    SevEsEnabled;
> > >>
> > >> 	// If Es is enabled then this field must be zeroed
> > >> 	UINT8    MustBeZero;
> > >>
> > >> 	UINT8    Reserved1[6];
> > >>
> > >> 	UINT64   RandomData;
> > >>
> > >> 	UINT64   EncryptionMask;
> > >> } SEC_SEV_ES_WORK_AREA;
> > >>
> > >> typedef struct {
> > >> 	// If Tdx is enabled then it must be zeroed
> > >> 	UINT8    MustBeZero
> > >>
> > >> 	UINT8    TdxEnabled;
> > >>
> > >> 	UINT8    Reserved2[6];
> > >> 	....
> > >>
> > >> } TX_WORK_AREA;
> > >>
> > >> typedef union {
> > >> 	SEC_SEV_ES_WORK_AREA SevEsWorkArea;
> > >> 	TDX_WORK_AREA	     TdxWorkArea;
> > >> } CC_WORK_AREA;
> > >>
> > >> I am trying to minimize the changes to the existing code. The SEV
> > >> and TDX probe logic should ensure that if the feature is detected,
> > >> then it must clear the MustBeZero'ed field.
> > >>
> > >> Basically, we already have a 64-bit value reserved in the SevEsWork
> > >> area and currently only one byte is used and second byte can be
> > >> detected for the TDX. Basically the which encryption technology is
> > >> active the definition of the work area will change.
> > >>
> > >> Am I missing something ?
> > >>
> > >> Thanks
> > >>
> > >> On 7/28/21 10:22 AM, Yao, Jiewen wrote:
> > >>> Hi Brijesh
> > >>> Thanks!
> > >>>
> > >>> I think if we want to reuse this, we need rename the data structure.
> > >>>
> > >>> First, we should use a generic name.
> > >>>
> > >>> Second, I don’t think it is good idea to define two *enable*
> > >>> fields. Since only
> > >> one of them should be enabled, we should use 1 field as enumeration.
> > >>>
> > >>> Third, we should hide the SEV specific and TDX specific definition
> > >>> in CC
> > >> common work area.
> > >>>
> > >>> If we agree to use a common work area, I recommend below:
> > >>>
> > >>> typedef struct {
> > >>>      UINT8    HeaderVersion; // 0
> > >>>      UINT8    HeadLength; // 4
> > >>>      UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
> > >>>      UINT8    SubType; // Type specific sub type, if needed.
> > >>> } CC_COMMON_WORK_AREA_HEADER;
> > >>>
> > >>> typedef struct {
> > >>>      CC_COMMON_WORK_AREA_HEADER Header;
> > >>>      // reset is valid if Type == 1
> > >>>      UINT8    Reserved1[4];
> > >>>      UINT64   RandomData;
> > >>>      UINT64   EncryptionMask;
> > >>> } SEC_SEV_ES_WORK_AREA;
> > >>>
> > >>> typedef struct {
> > >>>      CC_COMMON_WORK_AREA_HEADER Header;
> > >>>      // reset is valid if Type == 2
> > >>>      UINT8    TdxSpecific[];  // TBD
> > >>> } TDX_WORK_AREA;
> > >>>
> > >>> Thank you
> > >>> Yao Jiewen
> > >>>
> > >>>> -----Original Message-----
> > >>>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of
> > >>>> Brijesh Singh via groups.io
> > >>>> Sent: Wednesday, July 28, 2021 10:34 PM
> > >>>> To: Yao, Jiewen <jiewen.yao@intel.com>; Xu, Min M
> > <min.m.xu@intel.com>
> > >>>> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Ard Biesheuvel
> > >>>> <ardb+tianocore@kernel.org>; Justen, Jordan L
> > <jordan.l.justen@intel.com>;
> > >>>> Erdem Aktas <erdemaktas@google.com>; James Bottomley
> > >>>> <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
> > >>>> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add
> > >>>> AmdSev.asm in ResetVector
> > >>>>
> > >>>> Hi Jiewen and Min,
> > >>>>
> > >>>> See my comments below.
> > >>>>
> > >>>>
> > >>>> On 7/28/21 2:54 AM, Yao, Jiewen wrote:
> > >>>>> Yes. I am thinking the same thing.
> > >>>>>
> > >>>>> [CC Flag memory location]
> > >>>>> 1) A general purpose register, such as EBP.
> > >>>>>
> > >>>>> 2) A global variable, such as
> > >>>>> .data
> > >>>>> TeeFlags: DD 0
> > >>>>>
> > >>>>> 3) A fixed region in stack, such as dword[STACK_TOP - 4]
> > >>>>>
> > >>>>> 4) A new CC common fixed region, such as dword[CC_COMMON_FLAGS]
> > >>>>>
> > >>>>> 5) A fixed region piggyback on existing CC working area, such as
> > >>>>> dword[CC_WORKING_AREA]
> > >>>>>
> > >>>>> Hi Brijesh/Min
> > >>>>> Any preference?
> > >>>>>
> > >>>>> [CC Indicator Flags]
> > >>>>> Proposal: UINT8[4]
> > >>>>>
> > >>>>> Byte [0] Version: 0
> > >>>>> byte [1] Length: 4
> > >>>>> byte [2] Type:
> > >>>>> 	0: legacy
> > >>>>> 	1: SEV
> > >>>>> 	2: TDX
> > >>>>> byte [3] Sub Type:
> > >>>>> 	If Type is 0 (legacy), then
> > >>>>> 		0: legacy
> > >>>>> 	If Type is 1 (SEV), then
> > >>>>> 		0: SEV
> > >>>>> 		1: SEV-ES
> > >>>>> 		2: SEV-SNP
> > >>>>> 	If Type is 2 (TDX), then
> > >>>>> 		0: TDX 1.0
> > >>>>>
> > >>>>> Thank you
> > >>>>> Yao Jiewen
> > >>>>>
> > >>>>>
> > >>>>>> -----Original Message-----
> > >>>>>> From: Xu, Min M <min.m.xu@intel.com>
> > >>>>>> Sent: Wednesday, July 28, 2021 2:58 PM
> > >>>>>> To: Yao, Jiewen <jiewen.yao@intel.com>
> > >>>>>> Cc: Brijesh Singh <brijesh.singh@amd.com>;
> > >>>>>> devel@edk2.groups.io; Ard Biesheuvel
> > >>>>>> <ardb+tianocore@kernel.org>; Justen, Jordan L
> > >>>>>> <jordan.l.justen@intel.com>; Erdem Aktas
> > >>>>>> <erdemaktas@google.com>;
> > >>>> James
> > >>>>>> Bottomley <jejb@linux.ibm.com>; Tom Lendacky
> > >>>> <thomas.lendacky@amd.com>
> > >>>>>> Subject: RE: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> > ResetVector
> > >>>>>>
> > >>>>>> On July 28, 2021 2:05 PM, Yao, Jiewen wrote:
> > >>>>>>> It does not necessary to be a working area.
> > >>>>>>>
> > >>>>>>> We just need a common TEE flag to indicate if the system run
> > >>>>>>> in legacy,
> > >> SEV,
> > >>>>>> or
> > >>>>>>> TDX, right?
> > >>>>>> Right. We need somewhere to store this flag, either in a
> > >>>>>> Register or in
> > >>>> Memory.
> > >>>>>> If it is memory, then in Tdx the memory region should be
> > >>>>>> initialized by
> > host
> > >>>> VMM.
> > >>>>>>>
> > >>>>>>> thank you!
> > >>>>>>> Yao, Jiewen
> > >>>>>>>
> > >>>>>>>
> > >>>>>>>> 在 2021年7月28日,下午1:07,Xu, Min M
> <min.m.xu@intel.com>
> > >> 写
> > >>>> 道:
> > >>>>>>>>
> > >>>>>>>> On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
> > >>>>>>>>> HI Min
> > >>>>>>>>> I agree with Brijesh.
> > >>>>>>>>>
> > >>>>>>>>> The basic rule is: SEV file shall never refer to TDX data structure.
> > >>>>>>>>> TDX file shall never refer to SEV data structure.
> > >>>>>>>>> These code should be isolated clearly.
> > >>>>>>>>>
> > >>>>>>>>> Do we still need that logic if we follow the new pattern?
> > >>>>>>>> I have replied to Brijesh's mail about the concern of the new pattern.
> > >>>>>>>>
> > >>>>>>>> I have some concern in the current pattern:
> > >>>>>>>> ====================
> > >>>>>>>>       OneTimeCall   PreMainFunctionHookSev
> > >>>>>>>>       OneTimeCall   PreMainFunctionHookTdx
> > >>>>>>>> MainFunction:
> > >>>>>>>>       XXXXXX
> > >>>>>>>>       OneTimeCall   PostMainFunctionHookSev
> > >>>>>>>>       OneTimeCall   PostMainFunctionHookTdx
> > >>>>>>>> ====================
> > >>>>>>>> The TEE function need implement a TEE check function (such as
> > >>>>>>>> IsSev,
> > or
> > >>>>>> IsTdx).
> > >>>>>>>>
> > >>>>>>>> Tdx call CPUID(0x21) to determine if it is tdx guest in the
> > >>>>>>>> very beginning of ResetVector. Then 'TDXG' is set in
> TDX_WORK_AREA.
> > SEV
> > >>>> does
> > >>>>>>> the similar work which call CheckSevFeatures to set
> > SEV_ES_WORK_AREA
> > >> to
> > >>>> 1.
> > >>>>>>>>
> > >>>>>>>> After that both TDX and SEV read the above WORK_AREA to check
> > >>>>>>>> if it
> > is
> > >>>> TDX
> > >>>>>>> or SEV or legacy guest.
> > >>>>>>>>
> > >>>>>>>> In Tdx the access to SEV_ES_WORK_AREA will trigger error
> > >>>>>>>> because
> > >>>>>>> SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
> > >>>>>>>> In SEV-SNP I am afraid the access to TDX_WORK_AREA will
> > >>>>>>>> trigger
> > error
> > >>>> too.
> > >>>>>>>>
> > >>>>>>>> I am wondering if TDX and SEV can use the same memory region
> > >>>>>>>> (for
> > >>>>>> example,
> > >>>>>>> TEE_WORK_AREA) as the work area?
> > >>>>>>>> So that this work area is guaranteed to be initialized in
> > >>>>>>>> both TDX and SEV. Structure of the TEE_WORK_AREA may look like
> this:
> > >>>>>>>>     typedef struct {
> > >>>>>>>>         UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
> > >>>>>>>>         UINT8  Others[];
> > >>>>>>>>     } TEE_WORK_AREA;
> > >>>>>>>>>
> > >>>>
> > >>>> Are we reserving a new page for the TDX_WORK_AREA ? I am
> > >>>> wondering
> > why
> > >>>> can't we use the SEV_ES_WORK_AREA instead of wasting space in the
> > >> MEMFD.
> > >>>>
> > >>>> The SEV_ES_WORK_AREA layout looks like this:
> > >>>>
> > >>>> typedef struct _SEC_SEV_ES_WORK_AREA {
> > >>>>      UINT8    SevEsEnabled;
> > >>>>      UINT8    Reserved1[7];
> > >>>>
> > >>>>      UINT64   RandomData;
> > >>>>
> > >>>>      UINT64   EncryptionMask;
> > >>>> } SEC_SEV_ES_WORK_AREA;
> > >>>>
> > >>>> There is reserved bit after the SevEsEnabled and one byte can be
> > >>>> used for the TdxEnabled;
> > >>>>
> > >>>> typedef struct _SEC_SEV_ES_WORK_AREA {
> > >>>>      UINT8    SevEsEnabled;
> > >>>>      UINT8    TdxEnabled;
> > >>>>      UINT8    Reserved2[6];
> > >>>>
> > >>>>      UINT64   RandomData;
> > >>>>
> > >>>>      UINT64   EncryptionMask;
> > >>>> } SEC_SEV_ES_WORK_AREA;
> > >>>>
> > >>>> The SEV_ES_WORK_AREA can be treated as a TEE_WORK_AREA and we
> > can
> > >> be
> > >>>> pull out from MemEncrypSevLib.h to CcWorkAreaLib.h and rename the
> > >>>> structure (if needed).
> > >>>>
> > >>>> Both the SEV-SNP and TEE host-VMM accepts the TEE_WORK_AREA
> > before
> > >>>> booting the guest to ensure that its safe to access the memory
> > >>>> without going through the accept/validation process.
> > >>>>
> > >>>> In case of the TDX, the reset vector code sets the TdxEnabled on
> > >>>> the entry. In case of the SEV, the workarea is valid from SEC to
> > >>>> PEI phase only and it gets reused for other purposes. The PEI
> > >>>> phase set the Pcd's (such as SevEsEnabled or SevEnabled etc) so
> > >>>> that Dxe or other EDK2 core does not need to know anything about
> > >>>> the workarea and they simply can read the PCDs.
> > >>>>
> > >>>> -Brijesh
> > >>>>
> > >>>>
> > >>>>
> > >>>>
> > >>>
> > >>
> > >>
> > >> 
> > >>
> > >

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-29  2:44                               ` Min Xu
@ 2021-07-29  4:29                                 ` Brijesh Singh
  2021-07-29  5:17                                   ` Yao, Jiewen
  2021-07-29  6:07                                   ` Min Xu
  0 siblings, 2 replies; 36+ messages in thread
From: Brijesh Singh @ 2021-07-29  4:29 UTC (permalink / raw)
  To: Xu, Min M, Yao, Jiewen, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky


On 7/28/21 9:44 PM, Xu, Min M wrote:
> Jiewen & Singh
>
> From the discussion I am thinking we have below rules to follow to the design the structure
> of TEE_WORK_AREA:
> 1. Design should be flexible but not too complicated
> 2. Reuse the current SEV_ES_WORK_AREA (PcdSevEsWorkAreaBase) as TEE_WORK_AREA
> 3. TEE_WORK_AREA should be initialized to all-0 at the beginning of ResetVecotr
> 4. Reduce the changes to exiting code if possible
>
> So I try to make below conclusions below: (Please review)
> 1. SEV_ES_WORK_AREA is used as the TEE_WORK_AREA by both TDX and SEV, maybe in
> the future it can be used by other CC technologies.
>
> 2. In MEMFD, add below initial value. So that TEE_WORK_AREA is guaranteed to be cleared
> in legacy guest. In TDX this memory region is initialized to be all-0 by host VMM. In SEV the memory
> region is cleared as well.
>   0x00B000|0x001000
>   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaSize
>   DATA = {
>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>   }

Hmm, I thought the contents of the data pages are controlled by the host
VMM. If the backing pages are not zero filled then there is no guarantee
that memory will be zero.  To verify it:

1. I applied your above change in OvmfPkgX86.fdt. I modified the DATA
values from 0x00 -> 0xCC

2. Modified the SecMain.c to dump the SevEsWorkArea on entry

And dump does not contain the 0xcc.

And to confirm further,  I attached to the qemu with the GDB before the
booting the OVMF, and modified the SevEsWorkArea with some garbage
number  and this time the dump printed garbage value I put through the
debugger.

In summary, the OVMF to zero the workarea memory on the entry and we
cannot rely on the DATA={0x00, 0x00...} to zero the CCWorkArea.

Did I miss something ?


>
> 3. The structure of TEE_WORK_AREA
>   The current SEV_ES_WORK_AREA is defined as below:
>   typedef struct {
>     UINT8    SevEsEnabled;
>     UINT8    Reserved1[7];
>     [Others...]
> } SEC_SEV_ES_WORK_AREA;
>
> So I think the TEE_WORK_AREA can be:
>   Byte[0] Type:
>     	0: legacy 1: SEV 	2: TDX 
>   Byte[1] Subtype:
>               If Type is 0, then it is 0
> 	If Type is 1, then it is up to SEV's definition
> 	If Type is 2, then it is up to TDX's definition
>  Byte[] other bytes are defined based on the Type/Subtype

I personally like Yao Jiewen's struct definition, but I can also live
with this one as well :). The only question I had was with his proposal
was what if we remove the Length and Version fields. If the header
length was fixed then life would be much easier in the ASM code. 


> I check the code in SecMain.c.
>  SevEsIsEnabled() need updated to check SevEsWorkarea->SevEsEnabled == 1, not non-0.
> @Brijesh Singh Is there any other code need update?

As noted before, the SevEsWorkAreas is used to pass the information from
the Sec to PEI phase. The workarea gets reused for totally different
purpose after the PEI phase.

thanks

>> -----Original Message-----
>> From: Yao, Jiewen <jiewen.yao@intel.com>
>> Sent: Thursday, July 29, 2021 7:49 AM
>> To: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io; Xu, Min M
>> <min.m.xu@intel.com>
>> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
>> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>; James
>> Bottomley <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
>> Subject: RE: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
>> ResetVector
>>
>> Comment below:
>>
>>> -----Original Message-----
>>> From: Brijesh Singh <brijesh.singh@amd.com>
>>> Sent: Thursday, July 29, 2021 2:59 AM
>>> To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Xu, Min
>>> M <min.m.xu@intel.com>
>>> Cc: brijesh.singh@amd.com; Ard Biesheuvel <ardb+tianocore@kernel.org>;
>>> Justen, Jordan L <jordan.l.justen@intel.com>; Erdem Aktas
>>> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
>>> Lendacky <thomas.lendacky@amd.com>
>>> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
>>> ResetVector
>>>
>>>
>>>
>>> On 7/28/21 11:26 AM, Yao, Jiewen wrote:
>>>> I would say it is NOT the best software practice to define 2 enable
>>>> fields to
>>> indicate one type.
>>>> What if some software error, set both TdxEnable and SevEnable at same
>> time?
>>>> How do you detect such error?
>>> Hmm, aren't we saying it is a software bug. In that case another bug
>>> can also mess up the structure header.
>> [Jiewen] Yes. I treat it as a software implementation bug.
>> The key thing in software design is to avoid the developer making mistake, help
>> debug issues, help maintain the code easily.
>>
>>
>>>> If some code may check the SEV only, and some code may check TDX
>>>> only,
>>> then both code can run. That will be a disaster. The code is hard to
>>> maintain and hard to debug.
>>>> Another consideration is: what if someone wants to set the third type?
>>>> Do we want to reserve the 3rd byte? To indicate the third type? It
>>>> is not
>>> scalable.
>>>> The best software practice it to just define one field as
>>>> enumeration. So any
>>> software can only set Tdx or Sev. The result is consistent, no matter
>>> you check the SEV at first or TDX at first.
>>>> If there is 3rd bytes, we just need assign the 3rd value to it,
>>>> without impact any
>>> other field.
>>> I was trying to see if we can make it work without requiring any
>>> changes to UefiCpuPkg etc (which uses the EsWorkArea).
>> [Jiewen] I agree with you.
>> And I think the priority should be:
>> 1) make a good design following the best practice.
>> 2) minimize the change.
>>
>> I don’t think two *enable* fields can satisfy #1.
>> And I am open on how to do #2. (See rest comment below)
>>
>>
>>
>>>
>>>> I think we can add "must zero" in the comment. But it does not mean
>>>> there will
>>> be no error during development.
>>>> UNION is not a type safe structure. Usually, the consumer of UNION
>>>> shall
>>> refer to a common field to know what the type of union is - I treat
>>> that as header.
>>>> Since we are defining a common data structure, I think we can do
>>>> some clean
>>> up.
>>>> Or if you have concern to change SEC_SEV_ES_WORK_AREA, we can define
>>>> a
>>> new CC WORK_AREA without touching SEV_SEV_ES_WORKING_AREA.
>>> In your below structure, I assume the SEV or TDX probe will set the
>>> Type only when it detects that feature is active. But which layer of
>>> the software is going to set the type to zero to indicate its a legacy guest ?
>> [Jiewen] Good question.
>> I expect some initialization function, such as InitCcWorkAreaSev,
>> InitCcWorkAreaTdx.
>> The default value Legacy shall be override in InitCcWorkArea after capability
>> check.
>> PreMainFunctionHookXXX is common patter for all function. It just checks the
>> CcWorkArea.
>>
>>
>>
>>> typedef struct {
>>> 	UINT8    HeaderVersion; // 0
>>> 	UINT8    HeadLength; // 4
>>> 	UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
>>> 	UINT8    SubType; // Type specific sub type, if needed.
>>> } CC_COMMON_WORK_AREA_HEADER;
>>>
>>> i.e In this call sequence:
>>>
>>> OneTimeCall   PreMainFunctionHookSev
>>> OneTimeCall   PreMainFunctionHookTdx
>>>
>>> ....
>>>
>>> The PreMainFunctionHookSev will detect whether SEV is active or not.
>>> If its active then set the type = MEM_ENCRYPT_SEV; and similarly the
>>> Tdx hook will set the type=MEM_ENCRYPT_TDX. What if neither TDX or SEV
>>> is enabled. At this time we will depend on hypervisor to ensure that
>>> value at that memory is zero.
>> [Jiewen] I think we just let InitCcWorkAreaSev and InitCcWorkAreaTdx override
>> the default value.
>> InitCcWorkArea{Sev,Tdx}:
>> 	// Detect Hardware Capability
>> 	// If discovered, then set Type = {SEV,TDX}
>> 	// Else, leave it as is
>>
>>
>>
>>
>>> Additionally, do you see a need for the HeadLength field in this
>>> structure ? In asm it is preferred if we can access the actual
>>> workarea pointer at the fixed location instead of first reading the
>>> HeadLength to determine how much it need to skip.
>> [Jiewen] You are right.
>> Length/Version is NOT absolutely necessary, if the header is simple enough. If
>> you think we don’t need them, I am OK to remove them.
>> I think only "Type" is mandatory, which tells us the category.
>> I think "SubType" is useful, because we might want to know if it is SEV, or SEV-ES,
>> or SEV-SNP, and if it is TDX 1.0, or TDX.future. Please let me know your thought.
>>
>>
>> One question on SEC_SEV_ES_WORK_AREA. Since you have SEV/SEV-ES/SEV-
>> SNP, is this SEV_ES_WORK_AREA only for SEV_ES? Or it is also used in SEV (no
>> SEV_ES), and SEV_SNP ?
>> For example, when we see SevEsEnable=0, how do we know it is SEV (no SEV_ES)
>> or legacy (no SEV, no SEV_ES)? Or we don’t need care in SEV (no SEV_ES) case.
>>
>>
>>
>>
>>>
>>>> Thank you
>>>> Yao Jiewen
>>>>
>>>>
>>>>> -----Original Message-----
>>>>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of
>>>>> Brijesh Singh via groups.io
>>>>> Sent: Wednesday, July 28, 2021 11:59 PM
>>>>> To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Xu,
>>>>> Min M <min.m.xu@intel.com>
>>>>> Cc: brijesh.singh@amd.com; Ard Biesheuvel
>>>>> <ardb+tianocore@kernel.org>; Justen, Jordan L
>>>>> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>;
>>>>> James Bottomley <jejb@linux.ibm.com>; Tom Lendacky
>>>>> <thomas.lendacky@amd.com>
>>>>> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm
>>>>> in ResetVector
>>>>>
>>>>> Hi Yao Jiewen,
>>>>>
>>>>> I guess I am still trying to figure out why we need the header in
>>>>> the work area. Can't we do something like this:
>>>>>
>>>>> typedef struct {
>>>>> 	UINT8    SevEsEnabled;
>>>>>
>>>>> 	// If Es is enabled then this field must be zeroed
>>>>> 	UINT8    MustBeZero;
>>>>>
>>>>> 	UINT8    Reserved1[6];
>>>>>
>>>>> 	UINT64   RandomData;
>>>>>
>>>>> 	UINT64   EncryptionMask;
>>>>> } SEC_SEV_ES_WORK_AREA;
>>>>>
>>>>> typedef struct {
>>>>> 	// If Tdx is enabled then it must be zeroed
>>>>> 	UINT8    MustBeZero
>>>>>
>>>>> 	UINT8    TdxEnabled;
>>>>>
>>>>> 	UINT8    Reserved2[6];
>>>>> 	....
>>>>>
>>>>> } TX_WORK_AREA;
>>>>>
>>>>> typedef union {
>>>>> 	SEC_SEV_ES_WORK_AREA SevEsWorkArea;
>>>>> 	TDX_WORK_AREA	     TdxWorkArea;
>>>>> } CC_WORK_AREA;
>>>>>
>>>>> I am trying to minimize the changes to the existing code. The SEV
>>>>> and TDX probe logic should ensure that if the feature is detected,
>>>>> then it must clear the MustBeZero'ed field.
>>>>>
>>>>> Basically, we already have a 64-bit value reserved in the SevEsWork
>>>>> area and currently only one byte is used and second byte can be
>>>>> detected for the TDX. Basically the which encryption technology is
>>>>> active the definition of the work area will change.
>>>>>
>>>>> Am I missing something ?
>>>>>
>>>>> Thanks
>>>>>
>>>>> On 7/28/21 10:22 AM, Yao, Jiewen wrote:
>>>>>> Hi Brijesh
>>>>>> Thanks!
>>>>>>
>>>>>> I think if we want to reuse this, we need rename the data structure.
>>>>>>
>>>>>> First, we should use a generic name.
>>>>>>
>>>>>> Second, I don’t think it is good idea to define two *enable*
>>>>>> fields. Since only
>>>>> one of them should be enabled, we should use 1 field as enumeration.
>>>>>> Third, we should hide the SEV specific and TDX specific definition
>>>>>> in CC
>>>>> common work area.
>>>>>> If we agree to use a common work area, I recommend below:
>>>>>>
>>>>>> typedef struct {
>>>>>>      UINT8    HeaderVersion; // 0
>>>>>>      UINT8    HeadLength; // 4
>>>>>>      UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
>>>>>>      UINT8    SubType; // Type specific sub type, if needed.
>>>>>> } CC_COMMON_WORK_AREA_HEADER;
>>>>>>
>>>>>> typedef struct {
>>>>>>      CC_COMMON_WORK_AREA_HEADER Header;
>>>>>>      // reset is valid if Type == 1
>>>>>>      UINT8    Reserved1[4];
>>>>>>      UINT64   RandomData;
>>>>>>      UINT64   EncryptionMask;
>>>>>> } SEC_SEV_ES_WORK_AREA;
>>>>>>
>>>>>> typedef struct {
>>>>>>      CC_COMMON_WORK_AREA_HEADER Header;
>>>>>>      // reset is valid if Type == 2
>>>>>>      UINT8    TdxSpecific[];  // TBD
>>>>>> } TDX_WORK_AREA;
>>>>>>
>>>>>> Thank you
>>>>>> Yao Jiewen
>>>>>>
>>>>>>> -----Original Message-----
>>>>>>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of
>>>>>>> Brijesh Singh via groups.io
>>>>>>> Sent: Wednesday, July 28, 2021 10:34 PM
>>>>>>> To: Yao, Jiewen <jiewen.yao@intel.com>; Xu, Min M
>>> <min.m.xu@intel.com>
>>>>>>> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Ard Biesheuvel
>>>>>>> <ardb+tianocore@kernel.org>; Justen, Jordan L
>>> <jordan.l.justen@intel.com>;
>>>>>>> Erdem Aktas <erdemaktas@google.com>; James Bottomley
>>>>>>> <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
>>>>>>> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add
>>>>>>> AmdSev.asm in ResetVector
>>>>>>>
>>>>>>> Hi Jiewen and Min,
>>>>>>>
>>>>>>> See my comments below.
>>>>>>>
>>>>>>>
>>>>>>> On 7/28/21 2:54 AM, Yao, Jiewen wrote:
>>>>>>>> Yes. I am thinking the same thing.
>>>>>>>>
>>>>>>>> [CC Flag memory location]
>>>>>>>> 1) A general purpose register, such as EBP.
>>>>>>>>
>>>>>>>> 2) A global variable, such as
>>>>>>>> .data
>>>>>>>> TeeFlags: DD 0
>>>>>>>>
>>>>>>>> 3) A fixed region in stack, such as dword[STACK_TOP - 4]
>>>>>>>>
>>>>>>>> 4) A new CC common fixed region, such as dword[CC_COMMON_FLAGS]
>>>>>>>>
>>>>>>>> 5) A fixed region piggyback on existing CC working area, such as
>>>>>>>> dword[CC_WORKING_AREA]
>>>>>>>>
>>>>>>>> Hi Brijesh/Min
>>>>>>>> Any preference?
>>>>>>>>
>>>>>>>> [CC Indicator Flags]
>>>>>>>> Proposal: UINT8[4]
>>>>>>>>
>>>>>>>> Byte [0] Version: 0
>>>>>>>> byte [1] Length: 4
>>>>>>>> byte [2] Type:
>>>>>>>> 	0: legacy
>>>>>>>> 	1: SEV
>>>>>>>> 	2: TDX
>>>>>>>> byte [3] Sub Type:
>>>>>>>> 	If Type is 0 (legacy), then
>>>>>>>> 		0: legacy
>>>>>>>> 	If Type is 1 (SEV), then
>>>>>>>> 		0: SEV
>>>>>>>> 		1: SEV-ES
>>>>>>>> 		2: SEV-SNP
>>>>>>>> 	If Type is 2 (TDX), then
>>>>>>>> 		0: TDX 1.0
>>>>>>>>
>>>>>>>> Thank you
>>>>>>>> Yao Jiewen
>>>>>>>>
>>>>>>>>
>>>>>>>>> -----Original Message-----
>>>>>>>>> From: Xu, Min M <min.m.xu@intel.com>
>>>>>>>>> Sent: Wednesday, July 28, 2021 2:58 PM
>>>>>>>>> To: Yao, Jiewen <jiewen.yao@intel.com>
>>>>>>>>> Cc: Brijesh Singh <brijesh.singh@amd.com>;
>>>>>>>>> devel@edk2.groups.io; Ard Biesheuvel
>>>>>>>>> <ardb+tianocore@kernel.org>; Justen, Jordan L
>>>>>>>>> <jordan.l.justen@intel.com>; Erdem Aktas
>>>>>>>>> <erdemaktas@google.com>;
>>>>>>> James
>>>>>>>>> Bottomley <jejb@linux.ibm.com>; Tom Lendacky
>>>>>>> <thomas.lendacky@amd.com>
>>>>>>>>> Subject: RE: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
>>> ResetVector
>>>>>>>>> On July 28, 2021 2:05 PM, Yao, Jiewen wrote:
>>>>>>>>>> It does not necessary to be a working area.
>>>>>>>>>>
>>>>>>>>>> We just need a common TEE flag to indicate if the system run
>>>>>>>>>> in legacy,
>>>>> SEV,
>>>>>>>>> or
>>>>>>>>>> TDX, right?
>>>>>>>>> Right. We need somewhere to store this flag, either in a
>>>>>>>>> Register or in
>>>>>>> Memory.
>>>>>>>>> If it is memory, then in Tdx the memory region should be
>>>>>>>>> initialized by
>>> host
>>>>>>> VMM.
>>>>>>>>>> thank you!
>>>>>>>>>> Yao, Jiewen
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>> 在 2021年7月28日,下午1:07,Xu, Min M
>> <min.m.xu@intel.com>
>>>>> 写
>>>>>>> 道:
>>>>>>>>>>> On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
>>>>>>>>>>>> HI Min
>>>>>>>>>>>> I agree with Brijesh.
>>>>>>>>>>>>
>>>>>>>>>>>> The basic rule is: SEV file shall never refer to TDX data structure.
>>>>>>>>>>>> TDX file shall never refer to SEV data structure.
>>>>>>>>>>>> These code should be isolated clearly.
>>>>>>>>>>>>
>>>>>>>>>>>> Do we still need that logic if we follow the new pattern?
>>>>>>>>>>> I have replied to Brijesh's mail about the concern of the new pattern.
>>>>>>>>>>>
>>>>>>>>>>> I have some concern in the current pattern:
>>>>>>>>>>> ====================
>>>>>>>>>>>       OneTimeCall   PreMainFunctionHookSev
>>>>>>>>>>>       OneTimeCall   PreMainFunctionHookTdx
>>>>>>>>>>> MainFunction:
>>>>>>>>>>>       XXXXXX
>>>>>>>>>>>       OneTimeCall   PostMainFunctionHookSev
>>>>>>>>>>>       OneTimeCall   PostMainFunctionHookTdx
>>>>>>>>>>> ====================
>>>>>>>>>>> The TEE function need implement a TEE check function (such as
>>>>>>>>>>> IsSev,
>>> or
>>>>>>>>> IsTdx).
>>>>>>>>>>> Tdx call CPUID(0x21) to determine if it is tdx guest in the
>>>>>>>>>>> very beginning of ResetVector. Then 'TDXG' is set in
>> TDX_WORK_AREA.
>>> SEV
>>>>>>> does
>>>>>>>>>> the similar work which call CheckSevFeatures to set
>>> SEV_ES_WORK_AREA
>>>>> to
>>>>>>> 1.
>>>>>>>>>>> After that both TDX and SEV read the above WORK_AREA to check
>>>>>>>>>>> if it
>>> is
>>>>>>> TDX
>>>>>>>>>> or SEV or legacy guest.
>>>>>>>>>>> In Tdx the access to SEV_ES_WORK_AREA will trigger error
>>>>>>>>>>> because
>>>>>>>>>> SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
>>>>>>>>>>> In SEV-SNP I am afraid the access to TDX_WORK_AREA will
>>>>>>>>>>> trigger
>>> error
>>>>>>> too.
>>>>>>>>>>> I am wondering if TDX and SEV can use the same memory region
>>>>>>>>>>> (for
>>>>>>>>> example,
>>>>>>>>>> TEE_WORK_AREA) as the work area?
>>>>>>>>>>> So that this work area is guaranteed to be initialized in
>>>>>>>>>>> both TDX and SEV. Structure of the TEE_WORK_AREA may look like
>> this:
>>>>>>>>>>>     typedef struct {
>>>>>>>>>>>         UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
>>>>>>>>>>>         UINT8  Others[];
>>>>>>>>>>>     } TEE_WORK_AREA;
>>>>>>> Are we reserving a new page for the TDX_WORK_AREA ? I am
>>>>>>> wondering
>>> why
>>>>>>> can't we use the SEV_ES_WORK_AREA instead of wasting space in the
>>>>> MEMFD.
>>>>>>> The SEV_ES_WORK_AREA layout looks like this:
>>>>>>>
>>>>>>> typedef struct _SEC_SEV_ES_WORK_AREA {
>>>>>>>      UINT8    SevEsEnabled;
>>>>>>>      UINT8    Reserved1[7];
>>>>>>>
>>>>>>>      UINT64   RandomData;
>>>>>>>
>>>>>>>      UINT64   EncryptionMask;
>>>>>>> } SEC_SEV_ES_WORK_AREA;
>>>>>>>
>>>>>>> There is reserved bit after the SevEsEnabled and one byte can be
>>>>>>> used for the TdxEnabled;
>>>>>>>
>>>>>>> typedef struct _SEC_SEV_ES_WORK_AREA {
>>>>>>>      UINT8    SevEsEnabled;
>>>>>>>      UINT8    TdxEnabled;
>>>>>>>      UINT8    Reserved2[6];
>>>>>>>
>>>>>>>      UINT64   RandomData;
>>>>>>>
>>>>>>>      UINT64   EncryptionMask;
>>>>>>> } SEC_SEV_ES_WORK_AREA;
>>>>>>>
>>>>>>> The SEV_ES_WORK_AREA can be treated as a TEE_WORK_AREA and we
>>> can
>>>>> be
>>>>>>> pull out from MemEncrypSevLib.h to CcWorkAreaLib.h and rename the
>>>>>>> structure (if needed).
>>>>>>>
>>>>>>> Both the SEV-SNP and TEE host-VMM accepts the TEE_WORK_AREA
>>> before
>>>>>>> booting the guest to ensure that its safe to access the memory
>>>>>>> without going through the accept/validation process.
>>>>>>>
>>>>>>> In case of the TDX, the reset vector code sets the TdxEnabled on
>>>>>>> the entry. In case of the SEV, the workarea is valid from SEC to
>>>>>>> PEI phase only and it gets reused for other purposes. The PEI
>>>>>>> phase set the Pcd's (such as SevEsEnabled or SevEnabled etc) so
>>>>>>> that Dxe or other EDK2 core does not need to know anything about
>>>>>>> the workarea and they simply can read the PCDs.
>>>>>>>
>>>>>>> -Brijesh
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>
>>>>> 
>>>>>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-29  4:29                                 ` Brijesh Singh
@ 2021-07-29  5:17                                   ` Yao, Jiewen
  2021-07-29  6:07                                   ` Min Xu
  1 sibling, 0 replies; 36+ messages in thread
From: Yao, Jiewen @ 2021-07-29  5:17 UTC (permalink / raw)
  To: devel@edk2.groups.io, brijesh.singh@amd.com
  Cc: Xu, Min M, Ard Biesheuvel, Justen, Jordan L, Erdem Aktas,
	James Bottomley, Tom Lendacky

comment below

thank you!
Yao, Jiewen


> 在 2021年7月29日,下午12:29,Brijesh Singh via groups.io <brijesh.singh=amd.com@groups.io> 写道:
> 
> 
>> On 7/28/21 9:44 PM, Xu, Min M wrote:
>> Jiewen & Singh
>> 
>> From the discussion I am thinking we have below rules to follow to the design the structure
>> of TEE_WORK_AREA:
>> 1. Design should be flexible but not too complicated
>> 2. Reuse the current SEV_ES_WORK_AREA (PcdSevEsWorkAreaBase) as TEE_WORK_AREA
>> 3. TEE_WORK_AREA should be initialized to all-0 at the beginning of ResetVecotr
>> 4. Reduce the changes to exiting code if possible
>> 
>> So I try to make below conclusions below: (Please review)
>> 1. SEV_ES_WORK_AREA is used as the TEE_WORK_AREA by both TDX and SEV, maybe in
>> the future it can be used by other CC technologies.
>> 
>> 2. In MEMFD, add below initial value. So that TEE_WORK_AREA is guaranteed to be cleared
>> in legacy guest. In TDX this memory region is initialized to be all-0 by host VMM. In SEV the memory
>> region is cleared as well.
>>  0x00B000|0x001000
>>  gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaSize
>>  DATA = {
>>    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>>    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>>    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>>    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>>  }
> 
> Hmm, I thought the contents of the data pages are controlled by the host
> VMM. If the backing pages are not zero filled then there is no guarantee
> that memory will be zero.  To verify it:
> 
> 1. I applied your above change in OvmfPkgX86.fdt. I modified the DATA
> values from 0x00 -> 0xCC
> 
> 2. Modified the SecMain.c to dump the SevEsWorkArea on entry
> 
> And dump does not contain the 0xcc.
> 
> And to confirm further,  I attached to the qemu with the GDB before the
> booting the OVMF, and modified the SevEsWorkArea with some garbage
> number  and this time the dump printed garbage value I put through the
> debugger.
> 
> In summary, the OVMF to zero the workarea memory on the entry and we
> cannot rely on the DATA={0x00, 0x00...} to zero the CCWorkArea.
> 
> Did I miss something ?
[jiewen] I am not sure how SEV works. 
For TDX, this memory is private memory. VMM or QEMU cannot modify it *after* launch.
VMM or QEMU may modify it *before* launch. That will be detected by attestation later if it is added memory. That will be zeroed with accept page if it is auged memory. 
So in TDX, I have no concern.

Anyway, I think the logic can be:
=====
CcWorkArea.Type = 0;
InitCcWorkAreaSev(); // set Type=1 if SEV
InitCcWorkAreaTdx(); // set Type=2 if TDX
=====

> 
> 
>> 
>> 3. The structure of TEE_WORK_AREA
>>  The current SEV_ES_WORK_AREA is defined as below:
>>  typedef struct {
>>    UINT8    SevEsEnabled;
>>    UINT8    Reserved1[7];
>>    [Others...]
>> } SEC_SEV_ES_WORK_AREA;
>> 
>> So I think the TEE_WORK_AREA can be:
>>  Byte[0] Type:
>>        0: legacy 1: SEV    2: TDX 
>>  Byte[1] Subtype:
>>              If Type is 0, then it is 0
>>    If Type is 1, then it is up to SEV's definition
>>    If Type is 2, then it is up to TDX's definition
>> Byte[] other bytes are defined based on the Type/Subtype
> 
> I personally like Yao Jiewen's struct definition, but I can also live
> with this one as well :). The only question I had was with his proposal
> was what if we remove the Length and Version fields. If the header
> length was fixed then life would be much easier in the ASM code. 
[jiewen] I am ok to remove version and length. The we need very carefully maintain the compatibility. 

How about below:

typedef struct {
  UINT8 Type;
  UINT8 SubType;
  UINT8 Reserved[6];
} CC_WORK_AREA_HEAD;

That almost aligns with existing SEV_ES. 

> 
> 
>> I check the code in SecMain.c.
>> SevEsIsEnabled() need updated to check SevEsWorkarea->SevEsEnabled == 1, not non-0.
>> @Brijesh Singh Is there any other code need update?
> 
> As noted before, the SevEsWorkAreas is used to pass the information from
> the Sec to PEI phase. The workarea gets reused for totally different
> purpose after the PEI phase.
[jiewen] Sorry.  I am not aware of that.
Any documentation?
Is that SEV specific purpose? Or generic CC purpose?


> 
> thanks
> 
>>> -----Original Message-----
>>> From: Yao, Jiewen <jiewen.yao@intel.com>
>>> Sent: Thursday, July 29, 2021 7:49 AM
>>> To: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io; Xu, Min M
>>> <min.m.xu@intel.com>
>>> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
>>> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>; James
>>> Bottomley <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
>>> Subject: RE: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
>>> ResetVector
>>> 
>>> Comment below:
>>> 
>>>> -----Original Message-----
>>>> From: Brijesh Singh <brijesh.singh@amd.com>
>>>> Sent: Thursday, July 29, 2021 2:59 AM
>>>> To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Xu, Min
>>>> M <min.m.xu@intel.com>
>>>> Cc: brijesh.singh@amd.com; Ard Biesheuvel <ardb+tianocore@kernel.org>;
>>>> Justen, Jordan L <jordan.l.justen@intel.com>; Erdem Aktas
>>>> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
>>>> Lendacky <thomas.lendacky@amd.com>
>>>> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
>>>> ResetVector
>>>> 
>>>> 
>>>> 
>>>> On 7/28/21 11:26 AM, Yao, Jiewen wrote:
>>>>> I would say it is NOT the best software practice to define 2 enable
>>>>> fields to
>>>> indicate one type.
>>>>> What if some software error, set both TdxEnable and SevEnable at same
>>> time?
>>>>> How do you detect such error?
>>>> Hmm, aren't we saying it is a software bug. In that case another bug
>>>> can also mess up the structure header.
>>> [Jiewen] Yes. I treat it as a software implementation bug.
>>> The key thing in software design is to avoid the developer making mistake, help
>>> debug issues, help maintain the code easily.
>>> 
>>> 
>>>>> If some code may check the SEV only, and some code may check TDX
>>>>> only,
>>>> then both code can run. That will be a disaster. The code is hard to
>>>> maintain and hard to debug.
>>>>> Another consideration is: what if someone wants to set the third type?
>>>>> Do we want to reserve the 3rd byte? To indicate the third type? It
>>>>> is not
>>>> scalable.
>>>>> The best software practice it to just define one field as
>>>>> enumeration. So any
>>>> software can only set Tdx or Sev. The result is consistent, no matter
>>>> you check the SEV at first or TDX at first.
>>>>> If there is 3rd bytes, we just need assign the 3rd value to it,
>>>>> without impact any
>>>> other field.
>>>> I was trying to see if we can make it work without requiring any
>>>> changes to UefiCpuPkg etc (which uses the EsWorkArea).
>>> [Jiewen] I agree with you.
>>> And I think the priority should be:
>>> 1) make a good design following the best practice.
>>> 2) minimize the change.
>>> 
>>> I don’t think two *enable* fields can satisfy #1.
>>> And I am open on how to do #2. (See rest comment below)
>>> 
>>> 
>>> 
>>>> 
>>>>> I think we can add "must zero" in the comment. But it does not mean
>>>>> there will
>>>> be no error during development.
>>>>> UNION is not a type safe structure. Usually, the consumer of UNION
>>>>> shall
>>>> refer to a common field to know what the type of union is - I treat
>>>> that as header.
>>>>> Since we are defining a common data structure, I think we can do
>>>>> some clean
>>>> up.
>>>>> Or if you have concern to change SEC_SEV_ES_WORK_AREA, we can define
>>>>> a
>>>> new CC WORK_AREA without touching SEV_SEV_ES_WORKING_AREA.
>>>> In your below structure, I assume the SEV or TDX probe will set the
>>>> Type only when it detects that feature is active. But which layer of
>>>> the software is going to set the type to zero to indicate its a legacy guest ?
>>> [Jiewen] Good question.
>>> I expect some initialization function, such as InitCcWorkAreaSev,
>>> InitCcWorkAreaTdx.
>>> The default value Legacy shall be override in InitCcWorkArea after capability
>>> check.
>>> PreMainFunctionHookXXX is common patter for all function. It just checks the
>>> CcWorkArea.
>>> 
>>> 
>>> 
>>>> typedef struct {
>>>>    UINT8    HeaderVersion; // 0
>>>>    UINT8    HeadLength; // 4
>>>>    UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
>>>>    UINT8    SubType; // Type specific sub type, if needed.
>>>> } CC_COMMON_WORK_AREA_HEADER;
>>>> 
>>>> i.e In this call sequence:
>>>> 
>>>> OneTimeCall   PreMainFunctionHookSev
>>>> OneTimeCall   PreMainFunctionHookTdx
>>>> 
>>>> ....
>>>> 
>>>> The PreMainFunctionHookSev will detect whether SEV is active or not.
>>>> If its active then set the type = MEM_ENCRYPT_SEV; and similarly the
>>>> Tdx hook will set the type=MEM_ENCRYPT_TDX. What if neither TDX or SEV
>>>> is enabled. At this time we will depend on hypervisor to ensure that
>>>> value at that memory is zero.
>>> [Jiewen] I think we just let InitCcWorkAreaSev and InitCcWorkAreaTdx override
>>> the default value.
>>> InitCcWorkArea{Sev,Tdx}:
>>>    // Detect Hardware Capability
>>>    // If discovered, then set Type = {SEV,TDX}
>>>    // Else, leave it as is
>>> 
>>> 
>>> 
>>> 
>>>> Additionally, do you see a need for the HeadLength field in this
>>>> structure ? In asm it is preferred if we can access the actual
>>>> workarea pointer at the fixed location instead of first reading the
>>>> HeadLength to determine how much it need to skip.
>>> [Jiewen] You are right.
>>> Length/Version is NOT absolutely necessary, if the header is simple enough. If
>>> you think we don’t need them, I am OK to remove them.
>>> I think only "Type" is mandatory, which tells us the category.
>>> I think "SubType" is useful, because we might want to know if it is SEV, or SEV-ES,
>>> or SEV-SNP, and if it is TDX 1.0, or TDX.future. Please let me know your thought.
>>> 
>>> 
>>> One question on SEC_SEV_ES_WORK_AREA. Since you have SEV/SEV-ES/SEV-
>>> SNP, is this SEV_ES_WORK_AREA only for SEV_ES? Or it is also used in SEV (no
>>> SEV_ES), and SEV_SNP ?
>>> For example, when we see SevEsEnable=0, how do we know it is SEV (no SEV_ES)
>>> or legacy (no SEV, no SEV_ES)? Or we don’t need care in SEV (no SEV_ES) case.
>>> 
>>> 
>>> 
>>> 
>>>> 
>>>>> Thank you
>>>>> Yao Jiewen
>>>>> 
>>>>> 
>>>>>> -----Original Message-----
>>>>>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of
>>>>>> Brijesh Singh via groups.io
>>>>>> Sent: Wednesday, July 28, 2021 11:59 PM
>>>>>> To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Xu,
>>>>>> Min M <min.m.xu@intel.com>
>>>>>> Cc: brijesh.singh@amd.com; Ard Biesheuvel
>>>>>> <ardb+tianocore@kernel.org>; Justen, Jordan L
>>>>>> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>;
>>>>>> James Bottomley <jejb@linux.ibm.com>; Tom Lendacky
>>>>>> <thomas.lendacky@amd.com>
>>>>>> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm
>>>>>> in ResetVector
>>>>>> 
>>>>>> Hi Yao Jiewen,
>>>>>> 
>>>>>> I guess I am still trying to figure out why we need the header in
>>>>>> the work area. Can't we do something like this:
>>>>>> 
>>>>>> typedef struct {
>>>>>>    UINT8    SevEsEnabled;
>>>>>> 
>>>>>>    // If Es is enabled then this field must be zeroed
>>>>>>    UINT8    MustBeZero;
>>>>>> 
>>>>>>    UINT8    Reserved1[6];
>>>>>> 
>>>>>>    UINT64   RandomData;
>>>>>> 
>>>>>>    UINT64   EncryptionMask;
>>>>>> } SEC_SEV_ES_WORK_AREA;
>>>>>> 
>>>>>> typedef struct {
>>>>>>    // If Tdx is enabled then it must be zeroed
>>>>>>    UINT8    MustBeZero
>>>>>> 
>>>>>>    UINT8    TdxEnabled;
>>>>>> 
>>>>>>    UINT8    Reserved2[6];
>>>>>>    ....
>>>>>> 
>>>>>> } TX_WORK_AREA;
>>>>>> 
>>>>>> typedef union {
>>>>>>    SEC_SEV_ES_WORK_AREA SevEsWorkArea;
>>>>>>    TDX_WORK_AREA         TdxWorkArea;
>>>>>> } CC_WORK_AREA;
>>>>>> 
>>>>>> I am trying to minimize the changes to the existing code. The SEV
>>>>>> and TDX probe logic should ensure that if the feature is detected,
>>>>>> then it must clear the MustBeZero'ed field.
>>>>>> 
>>>>>> Basically, we already have a 64-bit value reserved in the SevEsWork
>>>>>> area and currently only one byte is used and second byte can be
>>>>>> detected for the TDX. Basically the which encryption technology is
>>>>>> active the definition of the work area will change.
>>>>>> 
>>>>>> Am I missing something ?
>>>>>> 
>>>>>> Thanks
>>>>>> 
>>>>>> On 7/28/21 10:22 AM, Yao, Jiewen wrote:
>>>>>>> Hi Brijesh
>>>>>>> Thanks!
>>>>>>> 
>>>>>>> I think if we want to reuse this, we need rename the data structure.
>>>>>>> 
>>>>>>> First, we should use a generic name.
>>>>>>> 
>>>>>>> Second, I don’t think it is good idea to define two *enable*
>>>>>>> fields. Since only
>>>>>> one of them should be enabled, we should use 1 field as enumeration.
>>>>>>> Third, we should hide the SEV specific and TDX specific definition
>>>>>>> in CC
>>>>>> common work area.
>>>>>>> If we agree to use a common work area, I recommend below:
>>>>>>> 
>>>>>>> typedef struct {
>>>>>>>     UINT8    HeaderVersion; // 0
>>>>>>>     UINT8    HeadLength; // 4
>>>>>>>     UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
>>>>>>>     UINT8    SubType; // Type specific sub type, if needed.
>>>>>>> } CC_COMMON_WORK_AREA_HEADER;
>>>>>>> 
>>>>>>> typedef struct {
>>>>>>>     CC_COMMON_WORK_AREA_HEADER Header;
>>>>>>>     // reset is valid if Type == 1
>>>>>>>     UINT8    Reserved1[4];
>>>>>>>     UINT64   RandomData;
>>>>>>>     UINT64   EncryptionMask;
>>>>>>> } SEC_SEV_ES_WORK_AREA;
>>>>>>> 
>>>>>>> typedef struct {
>>>>>>>     CC_COMMON_WORK_AREA_HEADER Header;
>>>>>>>     // reset is valid if Type == 2
>>>>>>>     UINT8    TdxSpecific[];  // TBD
>>>>>>> } TDX_WORK_AREA;
>>>>>>> 
>>>>>>> Thank you
>>>>>>> Yao Jiewen
>>>>>>> 
>>>>>>>> -----Original Message-----
>>>>>>>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of
>>>>>>>> Brijesh Singh via groups.io
>>>>>>>> Sent: Wednesday, July 28, 2021 10:34 PM
>>>>>>>> To: Yao, Jiewen <jiewen.yao@intel.com>; Xu, Min M
>>>> <min.m.xu@intel.com>
>>>>>>>> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Ard Biesheuvel
>>>>>>>> <ardb+tianocore@kernel.org>; Justen, Jordan L
>>>> <jordan.l.justen@intel.com>;
>>>>>>>> Erdem Aktas <erdemaktas@google.com>; James Bottomley
>>>>>>>> <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
>>>>>>>> Subject: Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add
>>>>>>>> AmdSev.asm in ResetVector
>>>>>>>> 
>>>>>>>> Hi Jiewen and Min,
>>>>>>>> 
>>>>>>>> See my comments below.
>>>>>>>> 
>>>>>>>> 
>>>>>>>> On 7/28/21 2:54 AM, Yao, Jiewen wrote:
>>>>>>>>> Yes. I am thinking the same thing.
>>>>>>>>> 
>>>>>>>>> [CC Flag memory location]
>>>>>>>>> 1) A general purpose register, such as EBP.
>>>>>>>>> 
>>>>>>>>> 2) A global variable, such as
>>>>>>>>> .data
>>>>>>>>> TeeFlags: DD 0
>>>>>>>>> 
>>>>>>>>> 3) A fixed region in stack, such as dword[STACK_TOP - 4]
>>>>>>>>> 
>>>>>>>>> 4) A new CC common fixed region, such as dword[CC_COMMON_FLAGS]
>>>>>>>>> 
>>>>>>>>> 5) A fixed region piggyback on existing CC working area, such as
>>>>>>>>> dword[CC_WORKING_AREA]
>>>>>>>>> 
>>>>>>>>> Hi Brijesh/Min
>>>>>>>>> Any preference?
>>>>>>>>> 
>>>>>>>>> [CC Indicator Flags]
>>>>>>>>> Proposal: UINT8[4]
>>>>>>>>> 
>>>>>>>>> Byte [0] Version: 0
>>>>>>>>> byte [1] Length: 4
>>>>>>>>> byte [2] Type:
>>>>>>>>>    0: legacy
>>>>>>>>>    1: SEV
>>>>>>>>>    2: TDX
>>>>>>>>> byte [3] Sub Type:
>>>>>>>>>    If Type is 0 (legacy), then
>>>>>>>>>        0: legacy
>>>>>>>>>    If Type is 1 (SEV), then
>>>>>>>>>        0: SEV
>>>>>>>>>        1: SEV-ES
>>>>>>>>>        2: SEV-SNP
>>>>>>>>>    If Type is 2 (TDX), then
>>>>>>>>>        0: TDX 1.0
>>>>>>>>> 
>>>>>>>>> Thank you
>>>>>>>>> Yao Jiewen
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>>> -----Original Message-----
>>>>>>>>>> From: Xu, Min M <min.m.xu@intel.com>
>>>>>>>>>> Sent: Wednesday, July 28, 2021 2:58 PM
>>>>>>>>>> To: Yao, Jiewen <jiewen.yao@intel.com>
>>>>>>>>>> Cc: Brijesh Singh <brijesh.singh@amd.com>;
>>>>>>>>>> devel@edk2.groups.io; Ard Biesheuvel
>>>>>>>>>> <ardb+tianocore@kernel.org>; Justen, Jordan L
>>>>>>>>>> <jordan.l.justen@intel.com>; Erdem Aktas
>>>>>>>>>> <erdemaktas@google.com>;
>>>>>>>> James
>>>>>>>>>> Bottomley <jejb@linux.ibm.com>; Tom Lendacky
>>>>>>>> <thomas.lendacky@amd.com>
>>>>>>>>>> Subject: RE: [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
>>>> ResetVector
>>>>>>>>>> On July 28, 2021 2:05 PM, Yao, Jiewen wrote:
>>>>>>>>>>> It does not necessary to be a working area.
>>>>>>>>>>> 
>>>>>>>>>>> We just need a common TEE flag to indicate if the system run
>>>>>>>>>>> in legacy,
>>>>>> SEV,
>>>>>>>>>> or
>>>>>>>>>>> TDX, right?
>>>>>>>>>> Right. We need somewhere to store this flag, either in a
>>>>>>>>>> Register or in
>>>>>>>> Memory.
>>>>>>>>>> If it is memory, then in Tdx the memory region should be
>>>>>>>>>> initialized by
>>>> host
>>>>>>>> VMM.
>>>>>>>>>>> thank you!
>>>>>>>>>>> Yao, Jiewen
>>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>>>> 在 2021年7月28日,下午1:07,Xu, Min M
>>> <min.m.xu@intel.com>
>>>>>> 写
>>>>>>>> 道:
>>>>>>>>>>>> On July 27, 2021 8:46 PM, Yao, Jiewen wrote:
>>>>>>>>>>>>> HI Min
>>>>>>>>>>>>> I agree with Brijesh.
>>>>>>>>>>>>> 
>>>>>>>>>>>>> The basic rule is: SEV file shall never refer to TDX data structure.
>>>>>>>>>>>>> TDX file shall never refer to SEV data structure.
>>>>>>>>>>>>> These code should be isolated clearly.
>>>>>>>>>>>>> 
>>>>>>>>>>>>> Do we still need that logic if we follow the new pattern?
>>>>>>>>>>>> I have replied to Brijesh's mail about the concern of the new pattern.
>>>>>>>>>>>> 
>>>>>>>>>>>> I have some concern in the current pattern:
>>>>>>>>>>>> ====================
>>>>>>>>>>>>      OneTimeCall   PreMainFunctionHookSev
>>>>>>>>>>>>      OneTimeCall   PreMainFunctionHookTdx
>>>>>>>>>>>> MainFunction:
>>>>>>>>>>>>      XXXXXX
>>>>>>>>>>>>      OneTimeCall   PostMainFunctionHookSev
>>>>>>>>>>>>      OneTimeCall   PostMainFunctionHookTdx
>>>>>>>>>>>> ====================
>>>>>>>>>>>> The TEE function need implement a TEE check function (such as
>>>>>>>>>>>> IsSev,
>>>> or
>>>>>>>>>> IsTdx).
>>>>>>>>>>>> Tdx call CPUID(0x21) to determine if it is tdx guest in the
>>>>>>>>>>>> very beginning of ResetVector. Then 'TDXG' is set in
>>> TDX_WORK_AREA.
>>>> SEV
>>>>>>>> does
>>>>>>>>>>> the similar work which call CheckSevFeatures to set
>>>> SEV_ES_WORK_AREA
>>>>>> to
>>>>>>>> 1.
>>>>>>>>>>>> After that both TDX and SEV read the above WORK_AREA to check
>>>>>>>>>>>> if it
>>>> is
>>>>>>>> TDX
>>>>>>>>>>> or SEV or legacy guest.
>>>>>>>>>>>> In Tdx the access to SEV_ES_WORK_AREA will trigger error
>>>>>>>>>>>> because
>>>>>>>>>>> SEV_ES_WORK_AREA is *NOT* initialized by host VMM.
>>>>>>>>>>>> In SEV-SNP I am afraid the access to TDX_WORK_AREA will
>>>>>>>>>>>> trigger
>>>> error
>>>>>>>> too.
>>>>>>>>>>>> I am wondering if TDX and SEV can use the same memory region
>>>>>>>>>>>> (for
>>>>>>>>>> example,
>>>>>>>>>>> TEE_WORK_AREA) as the work area?
>>>>>>>>>>>> So that this work area is guaranteed to be initialized in
>>>>>>>>>>>> both TDX and SEV. Structure of the TEE_WORK_AREA may look like
>>> this:
>>>>>>>>>>>>    typedef struct {
>>>>>>>>>>>>        UINT8  Flag[4];         'TDXG' or 'SEVG' or all-0
>>>>>>>>>>>>        UINT8  Others[];
>>>>>>>>>>>>    } TEE_WORK_AREA;
>>>>>>>> Are we reserving a new page for the TDX_WORK_AREA ? I am
>>>>>>>> wondering
>>>> why
>>>>>>>> can't we use the SEV_ES_WORK_AREA instead of wasting space in the
>>>>>> MEMFD.
>>>>>>>> The SEV_ES_WORK_AREA layout looks like this:
>>>>>>>> 
>>>>>>>> typedef struct _SEC_SEV_ES_WORK_AREA {
>>>>>>>>     UINT8    SevEsEnabled;
>>>>>>>>     UINT8    Reserved1[7];
>>>>>>>> 
>>>>>>>>     UINT64   RandomData;
>>>>>>>> 
>>>>>>>>     UINT64   EncryptionMask;
>>>>>>>> } SEC_SEV_ES_WORK_AREA;
>>>>>>>> 
>>>>>>>> There is reserved bit after the SevEsEnabled and one byte can be
>>>>>>>> used for the TdxEnabled;
>>>>>>>> 
>>>>>>>> typedef struct _SEC_SEV_ES_WORK_AREA {
>>>>>>>>     UINT8    SevEsEnabled;
>>>>>>>>     UINT8    TdxEnabled;
>>>>>>>>     UINT8    Reserved2[6];
>>>>>>>> 
>>>>>>>>     UINT64   RandomData;
>>>>>>>> 
>>>>>>>>     UINT64   EncryptionMask;
>>>>>>>> } SEC_SEV_ES_WORK_AREA;
>>>>>>>> 
>>>>>>>> The SEV_ES_WORK_AREA can be treated as a TEE_WORK_AREA and we
>>>> can
>>>>>> be
>>>>>>>> pull out from MemEncrypSevLib.h to CcWorkAreaLib.h and rename the
>>>>>>>> structure (if needed).
>>>>>>>> 
>>>>>>>> Both the SEV-SNP and TEE host-VMM accepts the TEE_WORK_AREA
>>>> before
>>>>>>>> booting the guest to ensure that its safe to access the memory
>>>>>>>> without going through the accept/validation process.
>>>>>>>> 
>>>>>>>> In case of the TDX, the reset vector code sets the TdxEnabled on
>>>>>>>> the entry. In case of the SEV, the workarea is valid from SEC to
>>>>>>>> PEI phase only and it gets reused for other purposes. The PEI
>>>>>>>> phase set the Pcd's (such as SevEsEnabled or SevEnabled etc) so
>>>>>>>> that Dxe or other EDK2 core does not need to know anything about
>>>>>>>> the workarea and they simply can read the PCDs.
>>>>>>>> 
>>>>>>>> -Brijesh
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> 
> 
> 
> 
> 
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-29  4:29                                 ` Brijesh Singh
  2021-07-29  5:17                                   ` Yao, Jiewen
@ 2021-07-29  6:07                                   ` Min Xu
  2021-07-29 10:07                                     ` Brijesh Singh
  1 sibling, 1 reply; 36+ messages in thread
From: Min Xu @ 2021-07-29  6:07 UTC (permalink / raw)
  To: Brijesh Singh, Yao, Jiewen, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky

On July 29, 2021 12:29 PM, Brijesh Singh wrote:
> On 7/28/21 9:44 PM, Xu, Min M wrote:
> > Jiewen & Singh
> >
> > From the discussion I am thinking we have below rules to follow to the
> > design the structure of TEE_WORK_AREA:
> > 1. Design should be flexible but not too complicated 2. Reuse the
> > current SEV_ES_WORK_AREA (PcdSevEsWorkAreaBase) as TEE_WORK_AREA 3.
> > TEE_WORK_AREA should be initialized to all-0 at the beginning of
> > ResetVecotr 4. Reduce the changes to exiting code if possible
> >
> > So I try to make below conclusions below: (Please review) 1.
> > SEV_ES_WORK_AREA is used as the TEE_WORK_AREA by both TDX and SEV,
> > maybe in the future it can be used by other CC technologies.
> >
> > 2. In MEMFD, add below initial value. So that TEE_WORK_AREA is
> > guaranteed to be cleared in legacy guest. In TDX this memory region is
> > initialized to be all-0 by host VMM. In SEV the memory region is cleared as well.
> >   0x00B000|0x001000
> >
> gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpace
> Guid.PcdSevEsWorkAreaSize
> >   DATA = {
> >     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> >     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> >     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> >     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> >   }
> 
> Hmm, I thought the contents of the data pages are controlled by the host VMM.
> If the backing pages are not zero filled then there is no guarantee that memory
> will be zero.  To verify it:
> 
> 1. I applied your above change in OvmfPkgX86.fdt. I modified the DATA values
> from 0x00 -> 0xCC
> 
> 2. Modified the SecMain.c to dump the SevEsWorkArea on entry
> 
> And dump does not contain the 0xcc.
> 
> And to confirm further,  I attached to the qemu with the GDB before the booting
> the OVMF, and modified the SevEsWorkArea with some garbage number  and
> this time the dump printed garbage value I put through the debugger.
> 
> In summary, the OVMF to zero the workarea memory on the entry and we
> cannot rely on the DATA={0x00, 0x00...} to zero the CCWorkArea.
So in legacy guest, CCWorkArea is cleared to all-0 without the DATA={0x00,0x00...}, right?

> 
> Did I miss something ?
> 
> 
> >
> > 3. The structure of TEE_WORK_AREA
> >   The current SEV_ES_WORK_AREA is defined as below:
> >   typedef struct {
> >     UINT8    SevEsEnabled;
> >     UINT8    Reserved1[7];
> >     [Others...]
> > } SEC_SEV_ES_WORK_AREA;
> >
> > So I think the TEE_WORK_AREA can be:
> >   Byte[0] Type:
> >     	0: legacy 1: SEV 	2: TDX
> >   Byte[1] Subtype:
> >               If Type is 0, then it is 0
> > 	If Type is 1, then it is up to SEV's definition
> > 	If Type is 2, then it is up to TDX's definition  Byte[] other bytes
> > are defined based on the Type/Subtype
> 
> I personally like Yao Jiewen's struct definition, but I can also live with this one as
> well :). The only question I had was with his proposal was what if we remove the
> Length and Version fields. If the header length was fixed then life would be much
> easier in the ASM code.
Yao Jiewen's structure is like below. If the HeaderVersion/HeaderLength are removed
you will find it is just what I am saying. The first 2 bytes are used to distinguish the
legacy/SEV/TDX. The left bytes are up to the first 2 bytes.
typedef struct {
     UINT8    HeaderVersion; // 0
     UINT8    HeadLength; // 4
     UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
     UINT8    SubType; // Type specific sub type, if needed.
} CC_COMMON_WORK_AREA_HEADER;

typedef struct {
     CC_COMMON_WORK_AREA_HEADER Header;
     // reset is valid if Type == 1
     UINT8    Reserved1[4];
     UINT64   RandomData;
     UINT64   EncryptionMask;
} SEC_SEV_ES_WORK_AREA;

typedef struct {
     CC_COMMON_WORK_AREA_HEADER Header;
     // reset is valid if Type == 2
     UINT8    TdxSpecific[];  // TBD
} TDX_WORK_AREA;
> 
> 
> > I check the code in SecMain.c.
> >  SevEsIsEnabled() need updated to check SevEsWorkarea->SevEsEnabled == 1,
> not non-0.
> > @Brijesh Singh Is there any other code need update?
> 
> As noted before, the SevEsWorkAreas is used to pass the information from the
> Sec to PEI phase. The workarea gets reused for totally different purpose after
> the PEI phase.
So only the above line in SecMain.c/SevEsIsEnabled() need updated, right?
> 
Thanks!
Xu, Min

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-29  6:07                                   ` Min Xu
@ 2021-07-29 10:07                                     ` Brijesh Singh
  2021-07-29 11:53                                       ` Min Xu
  0 siblings, 1 reply; 36+ messages in thread
From: Brijesh Singh @ 2021-07-29 10:07 UTC (permalink / raw)
  To: Xu, Min M, Yao, Jiewen, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky


On 7/29/21 1:07 AM, Xu, Min M wrote:
> On July 29, 2021 12:29 PM, Brijesh Singh wrote:
>> On 7/28/21 9:44 PM, Xu, Min M wrote:
>>> Jiewen & Singh
>>>
>>> From the discussion I am thinking we have below rules to follow to the
>>> design the structure of TEE_WORK_AREA:
>>> 1. Design should be flexible but not too complicated 2. Reuse the
>>> current SEV_ES_WORK_AREA (PcdSevEsWorkAreaBase) as TEE_WORK_AREA 3.
>>> TEE_WORK_AREA should be initialized to all-0 at the beginning of
>>> ResetVecotr 4. Reduce the changes to exiting code if possible
>>>
>>> So I try to make below conclusions below: (Please review) 1.
>>> SEV_ES_WORK_AREA is used as the TEE_WORK_AREA by both TDX and SEV,
>>> maybe in the future it can be used by other CC technologies.
>>>
>>> 2. In MEMFD, add below initial value. So that TEE_WORK_AREA is
>>> guaranteed to be cleared in legacy guest. In TDX this memory region is
>>> initialized to be all-0 by host VMM. In SEV the memory region is cleared as well.
>>>   0x00B000|0x001000
>>>
>> gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpace
>> Guid.PcdSevEsWorkAreaSize
>>>   DATA = {
>>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>>>   }
>> Hmm, I thought the contents of the data pages are controlled by the host VMM.
>> If the backing pages are not zero filled then there is no guarantee that memory
>> will be zero.  To verify it:
>>
>> 1. I applied your above change in OvmfPkgX86.fdt. I modified the DATA values
>> from 0x00 -> 0xCC
>>
>> 2. Modified the SecMain.c to dump the SevEsWorkArea on entry
>>
>> And dump does not contain the 0xcc.
>>
>> And to confirm further,  I attached to the qemu with the GDB before the booting
>> the OVMF, and modified the SevEsWorkArea with some garbage number  and
>> this time the dump printed garbage value I put through the debugger.
>>
>> In summary, the OVMF to zero the workarea memory on the entry and we
>> cannot rely on the DATA={0x00, 0x00...} to zero the CCWorkArea.
> So in legacy guest, CCWorkArea is cleared to all-0 without the DATA={0x00,0x00...}, right?

Okay, maybe I was not able to communicate it correctly.

The run I did is for the legacy guest. For the legacy guest, the
contents of the CCWorkArea may *not* be always zero even when you use
the DATA={0x00, 0x00...}.

Currently, Qemu uses zero filled backing pages, so we will get a zero
filled CCWorkArea; but nothing says that a backing page *must* be zero.
Another VMM may choose to do things differently. In summary, the OVMF
reset vector code must zero  the CCWorkArea  before calling SEV or TDX
probes.

thanks


>
>> Did I miss something ?
>>
>>
>>> 3. The structure of TEE_WORK_AREA
>>>   The current SEV_ES_WORK_AREA is defined as below:
>>>   typedef struct {
>>>     UINT8    SevEsEnabled;
>>>     UINT8    Reserved1[7];
>>>     [Others...]
>>> } SEC_SEV_ES_WORK_AREA;
>>>
>>> So I think the TEE_WORK_AREA can be:
>>>   Byte[0] Type:
>>>     	0: legacy 1: SEV 	2: TDX
>>>   Byte[1] Subtype:
>>>               If Type is 0, then it is 0
>>> 	If Type is 1, then it is up to SEV's definition
>>> 	If Type is 2, then it is up to TDX's definition  Byte[] other bytes
>>> are defined based on the Type/Subtype
>> I personally like Yao Jiewen's struct definition, but I can also live with this one as
>> well :). The only question I had was with his proposal was what if we remove the
>> Length and Version fields. If the header length was fixed then life would be much
>> easier in the ASM code.
> Yao Jiewen's structure is like below. If the HeaderVersion/HeaderLength are removed
> you will find it is just what I am saying. The first 2 bytes are used to distinguish the
> legacy/SEV/TDX. The left bytes are up to the first 2 bytes.
> typedef struct {
>      UINT8    HeaderVersion; // 0
>      UINT8    HeadLength; // 4
>      UINT8    Type; // 0 - legacy, 1 - SEV, 2 - TDX
>      UINT8    SubType; // Type specific sub type, if needed.
> } CC_COMMON_WORK_AREA_HEADER;
>
> typedef struct {
>      CC_COMMON_WORK_AREA_HEADER Header;
>      // reset is valid if Type == 1
>      UINT8    Reserved1[4];
>      UINT64   RandomData;
>      UINT64   EncryptionMask;
> } SEC_SEV_ES_WORK_AREA;
>
> typedef struct {
>      CC_COMMON_WORK_AREA_HEADER Header;
>      // reset is valid if Type == 2
>      UINT8    TdxSpecific[];  // TBD
> } TDX_WORK_AREA;
>>
>>> I check the code in SecMain.c.
>>>  SevEsIsEnabled() need updated to check SevEsWorkarea->SevEsEnabled == 1,
>> not non-0.
>>> @Brijesh Singh Is there any other code need update?
>> As noted before, the SevEsWorkAreas is used to pass the information from the
>> Sec to PEI phase. The workarea gets reused for totally different purpose after
>> the PEI phase.
> So only the above line in SecMain.c/SevEsIsEnabled() need updated, right?
> Thanks!
> Xu, Min

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-29 10:07                                     ` Brijesh Singh
@ 2021-07-29 11:53                                       ` Min Xu
  2021-07-29 12:12                                         ` Yao, Jiewen
  0 siblings, 1 reply; 36+ messages in thread
From: Min Xu @ 2021-07-29 11:53 UTC (permalink / raw)
  To: Brijesh Singh, Yao, Jiewen, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky

On July 29, 2021 6:08 PM, Brijesh Singh wrote:
> On 7/29/21 1:07 AM, Xu, Min M wrote:
> > On July 29, 2021 12:29 PM, Brijesh Singh wrote:
> >> On 7/28/21 9:44 PM, Xu, Min M wrote:
> >>> Jiewen & Singh
> >>>
> >>> From the discussion I am thinking we have below rules to follow to
> >>> the design the structure of TEE_WORK_AREA:
> >>> 1. Design should be flexible but not too complicated 2. Reuse the
> >>> current SEV_ES_WORK_AREA (PcdSevEsWorkAreaBase) as
> TEE_WORK_AREA 3.
> >>> TEE_WORK_AREA should be initialized to all-0 at the beginning of
> >>> ResetVecotr 4. Reduce the changes to exiting code if possible
> >>>
> >>> So I try to make below conclusions below: (Please review) 1.
> >>> SEV_ES_WORK_AREA is used as the TEE_WORK_AREA by both TDX and
> SEV,
> >>> maybe in the future it can be used by other CC technologies.
> >>>
> >>> 2. In MEMFD, add below initial value. So that TEE_WORK_AREA is
> >>> guaranteed to be cleared in legacy guest. In TDX this memory region
> >>> is initialized to be all-0 by host VMM. In SEV the memory region is
> cleared as well.
> >>>   0x00B000|0x001000
> >>>
> >>
> gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpa
> ce
> >> Guid.PcdSevEsWorkAreaSize
> >>>   DATA = {
> >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> >>>   }
> >> Hmm, I thought the contents of the data pages are controlled by the host
> VMM.
> >> If the backing pages are not zero filled then there is no guarantee
> >> that memory will be zero.  To verify it:
> >>
> >> 1. I applied your above change in OvmfPkgX86.fdt. I modified the DATA
> >> values from 0x00 -> 0xCC
> >>
> >> 2. Modified the SecMain.c to dump the SevEsWorkArea on entry
> >>
> >> And dump does not contain the 0xcc.
> >>
> >> And to confirm further,  I attached to the qemu with the GDB before
> >> the booting the OVMF, and modified the SevEsWorkArea with some
> >> garbage number  and this time the dump printed garbage value I put
> through the debugger.
> >>
> >> In summary, the OVMF to zero the workarea memory on the entry and
> we
> >> cannot rely on the DATA={0x00, 0x00...} to zero the CCWorkArea.
> > So in legacy guest, CCWorkArea is cleared to all-0 without the
> DATA={0x00,0x00...}, right?
> 
> Okay, maybe I was not able to communicate it correctly.
> 
> The run I did is for the legacy guest. For the legacy guest, the contents of the
> CCWorkArea may *not* be always zero even when you use the DATA={0x00,
> 0x00...}.
> 
> Currently, Qemu uses zero filled backing pages, so we will get a zero filled
> CCWorkArea; but nothing says that a backing page *must* be zero.
> Another VMM may choose to do things differently. In summary, the OVMF
> reset vector code must zero  the CCWorkArea  before calling SEV or TDX
> probes.
> 
Ah, I see. 
In current CheckSevFeatures, byte[SEV_ES_WORK_AREA] is cleared to0. 
Then its values is set based on the result of SEV probe. 

There is a bug here. CheckTdxFeatures does the similar work and it sets the 
WORK_AREA to 2. If CheckSevFeatures is called after CheckTdxFeatures, then
WORK_AREA is cleared and it is set to 0 because it is not SEV. The value is override.

I think there are 2 options:
Option 1:
Neither CheckTdxFeatures nor CheckSevFeatures should clear WORK_AREA. Instead
It should be cleared to 0 outside and before these 2 calls. So in Main16 after
TransitionFromReal16To32BitFlat WORK_AREA is cleared to 0. In Tdx guest this WORK_AREA
is initialized to 0 by host VMM.

Option 2:
Another option is to figure out a mechanism that only one CheckXXXFeatures is called.
Since there are 2 entry point in Main.asm: Main16 and Main32.
In Main16 CheckSevFeatures is called after TransitionFromReal16To32BitFlat. (eax should
be saved because it is used in SetCr3ForPageTables64)
In Main32 CheckTdxFeatures is called after ReloadFlat32.

What's your opinion?


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-29 11:53                                       ` Min Xu
@ 2021-07-29 12:12                                         ` Yao, Jiewen
  2021-07-29 12:46                                           ` Brijesh Singh
  2021-07-29 13:22                                           ` Min Xu
  0 siblings, 2 replies; 36+ messages in thread
From: Yao, Jiewen @ 2021-07-29 12:12 UTC (permalink / raw)
  To: Xu, Min M, Brijesh Singh, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky

Hey
I am not sure why Min did not response to my latest email.
I did give suggestion in my previous comment.

=====
CcWorkArea.Type = 0;
InitCcWorkAreaSev(); // set Type=1 if SEV
InitCcWorkAreaTdx(); // set Type=2 if TDX
=====

That is option 1.

Thank you
Yao Jiewen

> -----Original Message-----
> From: Xu, Min M <min.m.xu@intel.com>
> Sent: Thursday, July 29, 2021 7:54 PM
> To: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
> <jiewen.yao@intel.com>; devel@edk2.groups.io
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>; James
> Bottomley <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
> Subject: RE: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> ResetVector
> 
> On July 29, 2021 6:08 PM, Brijesh Singh wrote:
> > On 7/29/21 1:07 AM, Xu, Min M wrote:
> > > On July 29, 2021 12:29 PM, Brijesh Singh wrote:
> > >> On 7/28/21 9:44 PM, Xu, Min M wrote:
> > >>> Jiewen & Singh
> > >>>
> > >>> From the discussion I am thinking we have below rules to follow to
> > >>> the design the structure of TEE_WORK_AREA:
> > >>> 1. Design should be flexible but not too complicated 2. Reuse the
> > >>> current SEV_ES_WORK_AREA (PcdSevEsWorkAreaBase) as
> > TEE_WORK_AREA 3.
> > >>> TEE_WORK_AREA should be initialized to all-0 at the beginning of
> > >>> ResetVecotr 4. Reduce the changes to exiting code if possible
> > >>>
> > >>> So I try to make below conclusions below: (Please review) 1.
> > >>> SEV_ES_WORK_AREA is used as the TEE_WORK_AREA by both TDX and
> > SEV,
> > >>> maybe in the future it can be used by other CC technologies.
> > >>>
> > >>> 2. In MEMFD, add below initial value. So that TEE_WORK_AREA is
> > >>> guaranteed to be cleared in legacy guest. In TDX this memory region
> > >>> is initialized to be all-0 by host VMM. In SEV the memory region is
> > cleared as well.
> > >>>   0x00B000|0x001000
> > >>>
> > >>
> > gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpa
> > ce
> > >> Guid.PcdSevEsWorkAreaSize
> > >>>   DATA = {
> > >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> > >>>   }
> > >> Hmm, I thought the contents of the data pages are controlled by the host
> > VMM.
> > >> If the backing pages are not zero filled then there is no guarantee
> > >> that memory will be zero.  To verify it:
> > >>
> > >> 1. I applied your above change in OvmfPkgX86.fdt. I modified the DATA
> > >> values from 0x00 -> 0xCC
> > >>
> > >> 2. Modified the SecMain.c to dump the SevEsWorkArea on entry
> > >>
> > >> And dump does not contain the 0xcc.
> > >>
> > >> And to confirm further,  I attached to the qemu with the GDB before
> > >> the booting the OVMF, and modified the SevEsWorkArea with some
> > >> garbage number  and this time the dump printed garbage value I put
> > through the debugger.
> > >>
> > >> In summary, the OVMF to zero the workarea memory on the entry and
> > we
> > >> cannot rely on the DATA={0x00, 0x00...} to zero the CCWorkArea.
> > > So in legacy guest, CCWorkArea is cleared to all-0 without the
> > DATA={0x00,0x00...}, right?
> >
> > Okay, maybe I was not able to communicate it correctly.
> >
> > The run I did is for the legacy guest. For the legacy guest, the contents of the
> > CCWorkArea may *not* be always zero even when you use the DATA={0x00,
> > 0x00...}.
> >
> > Currently, Qemu uses zero filled backing pages, so we will get a zero filled
> > CCWorkArea; but nothing says that a backing page *must* be zero.
> > Another VMM may choose to do things differently. In summary, the OVMF
> > reset vector code must zero  the CCWorkArea  before calling SEV or TDX
> > probes.
> >
> Ah, I see.
> In current CheckSevFeatures, byte[SEV_ES_WORK_AREA] is cleared to0.
> Then its values is set based on the result of SEV probe.
> 
> There is a bug here. CheckTdxFeatures does the similar work and it sets the
> WORK_AREA to 2. If CheckSevFeatures is called after CheckTdxFeatures, then
> WORK_AREA is cleared and it is set to 0 because it is not SEV. The value is
> override.
> 
> I think there are 2 options:
> Option 1:
> Neither CheckTdxFeatures nor CheckSevFeatures should clear WORK_AREA.
> Instead
> It should be cleared to 0 outside and before these 2 calls. So in Main16 after
> TransitionFromReal16To32BitFlat WORK_AREA is cleared to 0. In Tdx guest this
> WORK_AREA
> is initialized to 0 by host VMM.
> 
> Option 2:
> Another option is to figure out a mechanism that only one CheckXXXFeatures is
> called.
> Since there are 2 entry point in Main.asm: Main16 and Main32.
> In Main16 CheckSevFeatures is called after TransitionFromReal16To32BitFlat.
> (eax should
> be saved because it is used in SetCr3ForPageTables64)
> In Main32 CheckTdxFeatures is called after ReloadFlat32.
> 
> What's your opinion?


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-29 12:12                                         ` Yao, Jiewen
@ 2021-07-29 12:46                                           ` Brijesh Singh
  2021-07-29 13:22                                           ` Min Xu
  1 sibling, 0 replies; 36+ messages in thread
From: Brijesh Singh @ 2021-07-29 12:46 UTC (permalink / raw)
  To: Yao, Jiewen, Xu, Min M, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky

On 7/29/21 7:12 AM, Yao, Jiewen wrote:
> Hey
> I am not sure why Min did not response to my latest email.
> I did give suggestion in my previous comment.
>
> =====
> CcWorkArea.Type = 0;
> InitCcWorkAreaSev(); // set Type=1 if SEV
> InitCcWorkAreaTdx(); // set Type=2 if TDX
> =====
>
> That is option 1.

Yes that is exactly what we want Jiewen. 

The OvmfPkg reset vector should initialize the type to zero on entry,
and SEV/TDX will update the value (only if the feature is detected).


> Thank you
> Yao Jiewen
>
>> -----Original Message-----
>> From: Xu, Min M <min.m.xu@intel.com>
>> Sent: Thursday, July 29, 2021 7:54 PM
>> To: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
>> <jiewen.yao@intel.com>; devel@edk2.groups.io
>> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
>> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>; James
>> Bottomley <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
>> Subject: RE: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
>> ResetVector
>>
>> On July 29, 2021 6:08 PM, Brijesh Singh wrote:
>>> On 7/29/21 1:07 AM, Xu, Min M wrote:
>>>> On July 29, 2021 12:29 PM, Brijesh Singh wrote:
>>>>> On 7/28/21 9:44 PM, Xu, Min M wrote:
>>>>>> Jiewen & Singh
>>>>>>
>>>>>> From the discussion I am thinking we have below rules to follow to
>>>>>> the design the structure of TEE_WORK_AREA:
>>>>>> 1. Design should be flexible but not too complicated 2. Reuse the
>>>>>> current SEV_ES_WORK_AREA (PcdSevEsWorkAreaBase) as
>>> TEE_WORK_AREA 3.
>>>>>> TEE_WORK_AREA should be initialized to all-0 at the beginning of
>>>>>> ResetVecotr 4. Reduce the changes to exiting code if possible
>>>>>>
>>>>>> So I try to make below conclusions below: (Please review) 1.
>>>>>> SEV_ES_WORK_AREA is used as the TEE_WORK_AREA by both TDX and
>>> SEV,
>>>>>> maybe in the future it can be used by other CC technologies.
>>>>>>
>>>>>> 2. In MEMFD, add below initial value. So that TEE_WORK_AREA is
>>>>>> guaranteed to be cleared in legacy guest. In TDX this memory region
>>>>>> is initialized to be all-0 by host VMM. In SEV the memory region is
>>> cleared as well.
>>>>>>   0x00B000|0x001000
>>>>>>
>>> gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpa
>>> ce
>>>>> Guid.PcdSevEsWorkAreaSize
>>>>>>   DATA = {
>>>>>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>>>>>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>>>>>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>>>>>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>>>>>>   }
>>>>> Hmm, I thought the contents of the data pages are controlled by the host
>>> VMM.
>>>>> If the backing pages are not zero filled then there is no guarantee
>>>>> that memory will be zero.  To verify it:
>>>>>
>>>>> 1. I applied your above change in OvmfPkgX86.fdt. I modified the DATA
>>>>> values from 0x00 -> 0xCC
>>>>>
>>>>> 2. Modified the SecMain.c to dump the SevEsWorkArea on entry
>>>>>
>>>>> And dump does not contain the 0xcc.
>>>>>
>>>>> And to confirm further,  I attached to the qemu with the GDB before
>>>>> the booting the OVMF, and modified the SevEsWorkArea with some
>>>>> garbage number  and this time the dump printed garbage value I put
>>> through the debugger.
>>>>> In summary, the OVMF to zero the workarea memory on the entry and
>>> we
>>>>> cannot rely on the DATA={0x00, 0x00...} to zero the CCWorkArea.
>>>> So in legacy guest, CCWorkArea is cleared to all-0 without the
>>> DATA={0x00,0x00...}, right?
>>>
>>> Okay, maybe I was not able to communicate it correctly.
>>>
>>> The run I did is for the legacy guest. For the legacy guest, the contents of the
>>> CCWorkArea may *not* be always zero even when you use the DATA={0x00,
>>> 0x00...}.
>>>
>>> Currently, Qemu uses zero filled backing pages, so we will get a zero filled
>>> CCWorkArea; but nothing says that a backing page *must* be zero.
>>> Another VMM may choose to do things differently. In summary, the OVMF
>>> reset vector code must zero  the CCWorkArea  before calling SEV or TDX
>>> probes.
>>>
>> Ah, I see.
>> In current CheckSevFeatures, byte[SEV_ES_WORK_AREA] is cleared to0.
>> Then its values is set based on the result of SEV probe.
>>
>> There is a bug here. CheckTdxFeatures does the similar work and it sets the
>> WORK_AREA to 2. If CheckSevFeatures is called after CheckTdxFeatures, then
>> WORK_AREA is cleared and it is set to 0 because it is not SEV. The value is
>> override.
>>
>> I think there are 2 options:
>> Option 1:
>> Neither CheckTdxFeatures nor CheckSevFeatures should clear WORK_AREA.
>> Instead
>> It should be cleared to 0 outside and before these 2 calls. So in Main16 after
>> TransitionFromReal16To32BitFlat WORK_AREA is cleared to 0. In Tdx guest this
>> WORK_AREA
>> is initialized to 0 by host VMM.
>>
>> Option 2:
>> Another option is to figure out a mechanism that only one CheckXXXFeatures is
>> called.
>> Since there are 2 entry point in Main.asm: Main16 and Main32.
>> In Main16 CheckSevFeatures is called after TransitionFromReal16To32BitFlat.
>> (eax should
>> be saved because it is used in SetCr3ForPageTables64)
>> In Main32 CheckTdxFeatures is called after ReloadFlat32.
>>
>> What's your opinion?

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-29 12:12                                         ` Yao, Jiewen
  2021-07-29 12:46                                           ` Brijesh Singh
@ 2021-07-29 13:22                                           ` Min Xu
  2021-07-29 15:37                                             ` Yao, Jiewen
  1 sibling, 1 reply; 36+ messages in thread
From: Min Xu @ 2021-07-29 13:22 UTC (permalink / raw)
  To: Yao, Jiewen, Brijesh Singh, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky

On July 29, 2021 8:13 PM, Yao Jiewen wrote:
> Hey
> I am not sure why Min did not response to my latest email.
> I did give suggestion in my previous comment.
> 
Ah, sorry I missed it. There are too many mails. 
> =====
> CcWorkArea.Type = 0;
> InitCcWorkAreaSev(); // set Type=1 if SEV InitCcWorkAreaTdx(); // set Type=2 if
> TDX =====
> 
> That is option 1.
> 
> Thank you
> Yao Jiewen
> 
> > -----Original Message-----
> > From: Xu, Min M <min.m.xu@intel.com>
> > Sent: Thursday, July 29, 2021 7:54 PM
> > To: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
> > <jiewen.yao@intel.com>; devel@edk2.groups.io
> > Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
> > <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>;
> > James Bottomley <jejb@linux.ibm.com>; Tom Lendacky
> > <thomas.lendacky@amd.com>
> > Subject: RE: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> > ResetVector
> >
> > On July 29, 2021 6:08 PM, Brijesh Singh wrote:
> > > On 7/29/21 1:07 AM, Xu, Min M wrote:
> > > > On July 29, 2021 12:29 PM, Brijesh Singh wrote:
> > > >> On 7/28/21 9:44 PM, Xu, Min M wrote:
> > > >>> Jiewen & Singh
> > > >>>
> > > >>> From the discussion I am thinking we have below rules to follow
> > > >>> to the design the structure of TEE_WORK_AREA:
> > > >>> 1. Design should be flexible but not too complicated 2. Reuse
> > > >>> the current SEV_ES_WORK_AREA (PcdSevEsWorkAreaBase) as
> > > TEE_WORK_AREA 3.
> > > >>> TEE_WORK_AREA should be initialized to all-0 at the beginning of
> > > >>> ResetVecotr 4. Reduce the changes to exiting code if possible
> > > >>>
> > > >>> So I try to make below conclusions below: (Please review) 1.
> > > >>> SEV_ES_WORK_AREA is used as the TEE_WORK_AREA by both TDX and
> > > SEV,
> > > >>> maybe in the future it can be used by other CC technologies.
> > > >>>
> > > >>> 2. In MEMFD, add below initial value. So that TEE_WORK_AREA is
> > > >>> guaranteed to be cleared in legacy guest. In TDX this memory
> > > >>> region is initialized to be all-0 by host VMM. In SEV the memory
> > > >>> region is
> > > cleared as well.
> > > >>>   0x00B000|0x001000
> > > >>>
> > > >>
> > >
> gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpa
> > > ce
> > > >> Guid.PcdSevEsWorkAreaSize
> > > >>>   DATA = {
> > > >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > > >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > > >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > > >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> > > >>>   }
> > > >> Hmm, I thought the contents of the data pages are controlled by
> > > >> the host
> > > VMM.
> > > >> If the backing pages are not zero filled then there is no
> > > >> guarantee that memory will be zero.  To verify it:
> > > >>
> > > >> 1. I applied your above change in OvmfPkgX86.fdt. I modified the
> > > >> DATA values from 0x00 -> 0xCC
> > > >>
> > > >> 2. Modified the SecMain.c to dump the SevEsWorkArea on entry
> > > >>
> > > >> And dump does not contain the 0xcc.
> > > >>
> > > >> And to confirm further,  I attached to the qemu with the GDB
> > > >> before the booting the OVMF, and modified the SevEsWorkArea with
> > > >> some garbage number  and this time the dump printed garbage value
> > > >> I put
> > > through the debugger.
> > > >>
> > > >> In summary, the OVMF to zero the workarea memory on the entry and
> > > we
> > > >> cannot rely on the DATA={0x00, 0x00...} to zero the CCWorkArea.
> > > > So in legacy guest, CCWorkArea is cleared to all-0 without the
> > > DATA={0x00,0x00...}, right?
> > >
> > > Okay, maybe I was not able to communicate it correctly.
> > >
> > > The run I did is for the legacy guest. For the legacy guest, the
> > > contents of the CCWorkArea may *not* be always zero even when you
> > > use the DATA={0x00, 0x00...}.
> > >
> > > Currently, Qemu uses zero filled backing pages, so we will get a
> > > zero filled CCWorkArea; but nothing says that a backing page *must* be
> zero.
> > > Another VMM may choose to do things differently. In summary, the
> > > OVMF reset vector code must zero  the CCWorkArea  before calling SEV
> > > or TDX probes.
> > >
> > Ah, I see.
> > In current CheckSevFeatures, byte[SEV_ES_WORK_AREA] is cleared to0.
> > Then its values is set based on the result of SEV probe.
> >
> > There is a bug here. CheckTdxFeatures does the similar work and it
> > sets the WORK_AREA to 2. If CheckSevFeatures is called after
> > CheckTdxFeatures, then WORK_AREA is cleared and it is set to 0 because
> > it is not SEV. The value is override.
> >
> > I think there are 2 options:
> > Option 1:
> > Neither CheckTdxFeatures nor CheckSevFeatures should clear WORK_AREA.
> > Instead
> > It should be cleared to 0 outside and before these 2 calls. So in
> > Main16 after TransitionFromReal16To32BitFlat WORK_AREA is cleared to
> > 0. In Tdx guest this WORK_AREA is initialized to 0 by host VMM.
> >
> > Option 2:
> > Another option is to figure out a mechanism that only one
> > CheckXXXFeatures is called.
> > Since there are 2 entry point in Main.asm: Main16 and Main32.
> > In Main16 CheckSevFeatures is called after TransitionFromReal16To32BitFlat.
> > (eax should
> > be saved because it is used in SetCr3ForPageTables64) In Main32
> > CheckTdxFeatures is called after ReloadFlat32.
> >
> > What's your opinion?


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in ResetVector
  2021-07-29 13:22                                           ` Min Xu
@ 2021-07-29 15:37                                             ` Yao, Jiewen
  0 siblings, 0 replies; 36+ messages in thread
From: Yao, Jiewen @ 2021-07-29 15:37 UTC (permalink / raw)
  To: Xu, Min M, Brijesh Singh, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Erdem Aktas, James Bottomley,
	Tom Lendacky

Indeed. Too many emails.

Glad that we can reach consensus finally. :-)

Thanks, Min and Brijesh.

> -----Original Message-----
> From: Xu, Min M <min.m.xu@intel.com>
> Sent: Thursday, July 29, 2021 9:22 PM
> To: Yao, Jiewen <jiewen.yao@intel.com>; Brijesh Singh
> <brijesh.singh@amd.com>; devel@edk2.groups.io
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
> <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>; James
> Bottomley <jejb@linux.ibm.com>; Tom Lendacky <thomas.lendacky@amd.com>
> Subject: RE: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> ResetVector
> 
> On July 29, 2021 8:13 PM, Yao Jiewen wrote:
> > Hey
> > I am not sure why Min did not response to my latest email.
> > I did give suggestion in my previous comment.
> >
> Ah, sorry I missed it. There are too many mails.
> > =====
> > CcWorkArea.Type = 0;
> > InitCcWorkAreaSev(); // set Type=1 if SEV InitCcWorkAreaTdx(); // set Type=2
> if
> > TDX =====
> >
> > That is option 1.
> >
> > Thank you
> > Yao Jiewen
> >
> > > -----Original Message-----
> > > From: Xu, Min M <min.m.xu@intel.com>
> > > Sent: Thursday, July 29, 2021 7:54 PM
> > > To: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
> > > <jiewen.yao@intel.com>; devel@edk2.groups.io
> > > Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
> > > <jordan.l.justen@intel.com>; Erdem Aktas <erdemaktas@google.com>;
> > > James Bottomley <jejb@linux.ibm.com>; Tom Lendacky
> > > <thomas.lendacky@amd.com>
> > > Subject: RE: [edk2-devel] [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm in
> > > ResetVector
> > >
> > > On July 29, 2021 6:08 PM, Brijesh Singh wrote:
> > > > On 7/29/21 1:07 AM, Xu, Min M wrote:
> > > > > On July 29, 2021 12:29 PM, Brijesh Singh wrote:
> > > > >> On 7/28/21 9:44 PM, Xu, Min M wrote:
> > > > >>> Jiewen & Singh
> > > > >>>
> > > > >>> From the discussion I am thinking we have below rules to follow
> > > > >>> to the design the structure of TEE_WORK_AREA:
> > > > >>> 1. Design should be flexible but not too complicated 2. Reuse
> > > > >>> the current SEV_ES_WORK_AREA (PcdSevEsWorkAreaBase) as
> > > > TEE_WORK_AREA 3.
> > > > >>> TEE_WORK_AREA should be initialized to all-0 at the beginning of
> > > > >>> ResetVecotr 4. Reduce the changes to exiting code if possible
> > > > >>>
> > > > >>> So I try to make below conclusions below: (Please review) 1.
> > > > >>> SEV_ES_WORK_AREA is used as the TEE_WORK_AREA by both TDX and
> > > > SEV,
> > > > >>> maybe in the future it can be used by other CC technologies.
> > > > >>>
> > > > >>> 2. In MEMFD, add below initial value. So that TEE_WORK_AREA is
> > > > >>> guaranteed to be cleared in legacy guest. In TDX this memory
> > > > >>> region is initialized to be all-0 by host VMM. In SEV the memory
> > > > >>> region is
> > > > cleared as well.
> > > > >>>   0x00B000|0x001000
> > > > >>>
> > > > >>
> > > >
> > gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase|gUefiCpuPkgTokenSpa
> > > > ce
> > > > >> Guid.PcdSevEsWorkAreaSize
> > > > >>>   DATA = {
> > > > >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > > > >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > > > >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > > > >>>     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> > > > >>>   }
> > > > >> Hmm, I thought the contents of the data pages are controlled by
> > > > >> the host
> > > > VMM.
> > > > >> If the backing pages are not zero filled then there is no
> > > > >> guarantee that memory will be zero.  To verify it:
> > > > >>
> > > > >> 1. I applied your above change in OvmfPkgX86.fdt. I modified the
> > > > >> DATA values from 0x00 -> 0xCC
> > > > >>
> > > > >> 2. Modified the SecMain.c to dump the SevEsWorkArea on entry
> > > > >>
> > > > >> And dump does not contain the 0xcc.
> > > > >>
> > > > >> And to confirm further,  I attached to the qemu with the GDB
> > > > >> before the booting the OVMF, and modified the SevEsWorkArea with
> > > > >> some garbage number  and this time the dump printed garbage value
> > > > >> I put
> > > > through the debugger.
> > > > >>
> > > > >> In summary, the OVMF to zero the workarea memory on the entry and
> > > > we
> > > > >> cannot rely on the DATA={0x00, 0x00...} to zero the CCWorkArea.
> > > > > So in legacy guest, CCWorkArea is cleared to all-0 without the
> > > > DATA={0x00,0x00...}, right?
> > > >
> > > > Okay, maybe I was not able to communicate it correctly.
> > > >
> > > > The run I did is for the legacy guest. For the legacy guest, the
> > > > contents of the CCWorkArea may *not* be always zero even when you
> > > > use the DATA={0x00, 0x00...}.
> > > >
> > > > Currently, Qemu uses zero filled backing pages, so we will get a
> > > > zero filled CCWorkArea; but nothing says that a backing page *must* be
> > zero.
> > > > Another VMM may choose to do things differently. In summary, the
> > > > OVMF reset vector code must zero  the CCWorkArea  before calling SEV
> > > > or TDX probes.
> > > >
> > > Ah, I see.
> > > In current CheckSevFeatures, byte[SEV_ES_WORK_AREA] is cleared to0.
> > > Then its values is set based on the result of SEV probe.
> > >
> > > There is a bug here. CheckTdxFeatures does the similar work and it
> > > sets the WORK_AREA to 2. If CheckSevFeatures is called after
> > > CheckTdxFeatures, then WORK_AREA is cleared and it is set to 0 because
> > > it is not SEV. The value is override.
> > >
> > > I think there are 2 options:
> > > Option 1:
> > > Neither CheckTdxFeatures nor CheckSevFeatures should clear WORK_AREA.
> > > Instead
> > > It should be cleared to 0 outside and before these 2 calls. So in
> > > Main16 after TransitionFromReal16To32BitFlat WORK_AREA is cleared to
> > > 0. In Tdx guest this WORK_AREA is initialized to 0 by host VMM.
> > >
> > > Option 2:
> > > Another option is to figure out a mechanism that only one
> > > CheckXXXFeatures is called.
> > > Since there are 2 entry point in Main.asm: Main16 and Main32.
> > > In Main16 CheckSevFeatures is called after TransitionFromReal16To32BitFlat.
> > > (eax should
> > > be saved because it is used in SetCr3ForPageTables64) In Main32
> > > CheckTdxFeatures is called after ReloadFlat32.
> > >
> > > What's your opinion?


^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2021-07-29 15:38 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <cover.1627364332.git.min.m.xu@intel.com>
2021-07-27  5:42 ` [PATCH V3 01/10] OvmfPkg: Add Tdx BFV/CFV PCDs and PcdOvmfImageSizeInKb Min Xu
2021-07-27  5:42 ` [PATCH V3 02/10] OvmfPkg: Add Tdx metadata Min Xu
2021-07-27  5:42 ` [PATCH V3 03/10] OvmfPkg: Set TdMailbox initial value and macros Min Xu
2021-07-27  5:42 ` [PATCH V3 04/10] OvmfPkg: Add TDX_PT_ADDR defition in ResetVector.nasmb Min Xu
2021-07-27  5:42 ` [PATCH V3 05/10] OvmfPkg: Add IntelTdx.asm in ResetVector Min Xu
2021-07-27  5:42 ` [PATCH V3 06/10] OvmfPkg: Add AmdSev.asm " Min Xu
2021-07-27 10:56   ` Brijesh Singh
2021-07-27 11:51     ` Min Xu
2021-07-27 12:31       ` Brijesh Singh
2021-07-27 12:46         ` Yao, Jiewen
2021-07-28  5:07           ` Min Xu
2021-07-28  6:04             ` Yao, Jiewen
2021-07-28  6:58               ` Min Xu
2021-07-28  7:54                 ` Yao, Jiewen
2021-07-28  8:34                   ` Min Xu
2021-07-28 14:34                   ` Brijesh Singh
2021-07-28 15:22                     ` [edk2-devel] " Yao, Jiewen
2021-07-28 15:59                       ` Brijesh Singh
2021-07-28 16:26                         ` Yao, Jiewen
2021-07-28 18:58                           ` Brijesh Singh
2021-07-28 23:48                             ` Yao, Jiewen
2021-07-29  2:44                               ` Min Xu
2021-07-29  4:29                                 ` Brijesh Singh
2021-07-29  5:17                                   ` Yao, Jiewen
2021-07-29  6:07                                   ` Min Xu
2021-07-29 10:07                                     ` Brijesh Singh
2021-07-29 11:53                                       ` Min Xu
2021-07-29 12:12                                         ` Yao, Jiewen
2021-07-29 12:46                                           ` Brijesh Singh
2021-07-29 13:22                                           ` Min Xu
2021-07-29 15:37                                             ` Yao, Jiewen
2021-07-28  0:40         ` Min Xu
2021-07-27  5:42 ` [PATCH V3 07/10] OvmfPkg: Add ReloadFlat32 Min Xu
2021-07-27  5:42 ` [PATCH V3 08/10] OvmfPkg: Add Init32 Min Xu
2021-07-27  5:42 ` [PATCH V3 09/10] OvmfPkg: Create Main.asm in ResetVector Min Xu
2021-07-27  5:42 ` [PATCH V3 10/10] OvmfPkg: Update ResetVector to support Tdx Min Xu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox