public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Wenxing Hou" <wenxing.hou@intel.com>
To: devel@edk2.groups.io
Cc: Jiewen Yao <jiewen.yao@intel.com>, Rahul Kumar <rahul1.kumar@intel.com>
Subject: [edk2-devel] [PATCH 5/9] SecurityPkg: Add TCG PFP 1.06 support.
Date: Tue,  2 Apr 2024 10:31:21 +0800	[thread overview]
Message-ID: <20240402023125.4168-6-wenxing.hou@intel.com> (raw)
In-Reply-To: <20240402023125.4168-1-wenxing.hou@intel.com>

Add new api Tpm2ExtendNvIndex.
It is uesd in HashCompleteAndExtend when PcrIndex > MAX_PCR_INDEX.

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Signed-off-by: Wenxing Hou <wenxing.hou@intel.com>
---
 SecurityPkg/Include/Library/Tpm2CommandLib.h  |  23 +++-
 .../HashLibBaseCryptoRouterDxe.c              |  88 +++++++++++--
 .../Library/Tpm2CommandLib/Tpm2NVStorage.c    | 122 +++++++++++++++++-
 SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c             |  61 ++++++++-
 SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf           |   4 +-
 5 files changed, 278 insertions(+), 20 deletions(-)

diff --git a/SecurityPkg/Include/Library/Tpm2CommandLib.h b/SecurityPkg/Include/Library/Tpm2CommandLib.h
index a2fb97f18d..70eec84c90 100644
--- a/SecurityPkg/Include/Library/Tpm2CommandLib.h
+++ b/SecurityPkg/Include/Library/Tpm2CommandLib.h
@@ -1,7 +1,7 @@
 /** @file
   This library is used by other modules to send TPM2 command.
 
-Copyright (c) 2013 - 2021, Intel Corporation. All rights reserved. <BR>
+Copyright (c) 2013 - 2024, Intel Corporation. All rights reserved. <BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
@@ -467,6 +467,27 @@ Tpm2NvGlobalWriteLock (
   IN      TPMS_AUTH_COMMAND  *AuthSession OPTIONAL
   );
 
+/**
+  This command extends a value to an area in NV memory that was previously defined by TPM2_NV_DefineSpace().
+
+  @param[in]  AuthHandle         the handle indicating the source of the authorization value.
+  @param[in]  NvIndex            The NV Index of the area to extend.
+  @param[in]  AuthSession        Auth Session context
+  @param[in]  InData             The data to extend.
+
+  @retval EFI_SUCCESS            Operation completed successfully.
+  @retval EFI_DEVICE_ERROR       The command was unsuccessful.
+  @retval EFI_NOT_FOUND          The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvExtend (
+  IN      TPMI_RH_NV_AUTH    AuthHandle,
+  IN      TPMI_RH_NV_INDEX   NvIndex,
+  IN      TPMS_AUTH_COMMAND  *AuthSession  OPTIONAL,
+  IN      TPM2B_MAX_BUFFER   *InData
+  );
+
 /**
   This command is used to cause an update to the indicated PCR.
   The digests parameter contains one or more tagged digest value identified by an algorithm ID.
diff --git a/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c b/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c
index ee8fe6e06e..2169c5e185 100644
--- a/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c
+++ b/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c
@@ -3,7 +3,7 @@
   hash handler registered, such as SHA1, SHA256.
   Platform can use PcdTpm2HashMask to mask some hash engines.
 
-Copyright (c) 2013 - 2021, Intel Corporation. All rights reserved. <BR>
+Copyright (c) 2013 - 2024, Intel Corporation. All rights reserved. <BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
@@ -16,6 +16,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include <Library/MemoryAllocationLib.h>
 #include <Library/PcdLib.h>
 #include <Library/HashLib.h>
+#include <Protocol/Tcg2Protocol.h>
 
 #include "HashLibBaseCryptoRouterCommon.h"
 
@@ -128,6 +129,49 @@ HashUpdate (
   return EFI_SUCCESS;
 }
 
+/**
+  Extend to TPM NvIndex.
+
+  @param[in]  NvIndex            The NV Index of the area to extend.
+  @param[in]  DataSize           The data size to extend.
+  @param[in]  Data               The data to extend.
+
+  @retval EFI_SUCCESS            Operation completed successfully.
+  @retval EFI_DEVICE_ERROR       The command was unsuccessful.
+  @retval EFI_NOT_FOUND          The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2ExtendNvIndex (
+  TPMI_RH_NV_INDEX  NvIndex,
+  UINT16            DataSize,
+  BYTE              *Data
+  )
+{
+  EFI_STATUS        Status;
+  TPMI_RH_NV_AUTH   AuthHandle;
+  TPM2B_MAX_BUFFER  NvExtendData;
+
+  AuthHandle = TPM_RH_PLATFORM;
+  ZeroMem (&NvExtendData, sizeof (NvExtendData));
+  CopyMem (NvExtendData.buffer, Data, DataSize);
+  NvExtendData.size = DataSize;
+  Status            = Tpm2NvExtend (
+                        AuthHandle,
+                        NvIndex,
+                        NULL,
+                        &NvExtendData
+                        );
+  if (EFI_ERROR (Status)) {
+    DEBUG (
+      (DEBUG_ERROR, "Extend TPM NV index failed, Index: 0x%x Status: %d\n",
+       NvIndex, Status)
+      );
+  }
+
+  return Status;
+}
+
 /**
   Hash sequence complete and extend to PCR.
 
@@ -149,11 +193,16 @@ HashCompleteAndExtend (
   OUT TPML_DIGEST_VALUES  *DigestList
   )
 {
-  TPML_DIGEST_VALUES  Digest;
-  HASH_HANDLE         *HashCtx;
-  UINTN               Index;
-  EFI_STATUS          Status;
-  UINT32              HashMask;
+  TPML_DIGEST_VALUES               Digest;
+  HASH_HANDLE                      *HashCtx;
+  UINTN                            Index;
+  EFI_STATUS                       Status;
+  UINT32                           HashMask;
+  TPML_DIGEST_VALUES               TcgPcrEvent2Digest;
+  EFI_TCG2_EVENT_ALGORITHM_BITMAP  TpmHashAlgorithmBitmap;
+  UINT32                           ActivePcrBanks;
+  UINT32                           *BufferPtr;
+  UINT32                           DigestListBinSize;
 
   if (mHashInterfaceCount == 0) {
     return EFI_UNSUPPORTED;
@@ -175,10 +224,29 @@ HashCompleteAndExtend (
 
   FreePool (HashCtx);
 
-  Status = Tpm2PcrExtend (
-             PcrIndex,
-             DigestList
-             );
+  if (PcrIndex <= MAX_PCR_INDEX) {
+    Status = Tpm2PcrExtend (
+               PcrIndex,
+               DigestList
+               );
+  } else {
+    Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &ActivePcrBanks);
+    ASSERT_EFI_ERROR (Status);
+    ActivePcrBanks = ActivePcrBanks & mSupportedHashMaskCurrent;
+    ZeroMem (&TcgPcrEvent2Digest, sizeof (TcgPcrEvent2Digest));
+    BufferPtr         = CopyDigestListToBuffer (&TcgPcrEvent2Digest, DigestList, ActivePcrBanks);
+    DigestListBinSize = (UINT32)((UINT8 *)BufferPtr - (UINT8 *)&TcgPcrEvent2Digest);
+
+    //
+    // Extend to TPM NvIndex
+    //
+    Status = Tpm2ExtendNvIndex (
+               PcrIndex,
+               (UINT16)DigestListBinSize,
+               (BYTE *)&TcgPcrEvent2Digest
+               );
+  }
+
   return Status;
 }
 
diff --git a/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c b/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c
index 5077ace7c2..f11f7696b1 100644
--- a/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c
+++ b/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c
@@ -1,7 +1,7 @@
 /** @file
   Implement TPM2 NVStorage related command.
 
-Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR>
+Copyright (c) 2013 - 2024, Intel Corporation. All rights reserved. <BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
@@ -148,6 +148,22 @@ typedef struct {
   TPMS_AUTH_RESPONSE      AuthSession;
 } TPM2_NV_GLOBALWRITELOCK_RESPONSE;
 
+typedef struct {
+  TPM2_COMMAND_HEADER    Header;
+  TPMI_RH_NV_AUTH        AuthHandle;
+  TPMI_RH_NV_INDEX       NvIndex;
+  UINT32                 AuthSessionSize;
+  TPMS_AUTH_COMMAND      AuthSession;
+  TPM2B_MAX_BUFFER       Data;
+  UINT16                 Offset;
+} TPM2_NV_EXTEND_COMMAND;
+
+typedef struct {
+  TPM2_RESPONSE_HEADER    Header;
+  UINT32                  AuthSessionSize;
+  TPMS_AUTH_RESPONSE      AuthSession;
+} TPM2_NV_EXTEND_RESPONSE;
+
 #pragma pack()
 
 /**
@@ -1052,3 +1068,107 @@ Done:
   ZeroMem (&RecvBuffer, sizeof (RecvBuffer));
   return Status;
 }
+
+/**
+  This command extends a value to an area in NV memory that was previously defined by TPM2_NV_DefineSpace().
+
+  @param[in]  AuthHandle         the handle indicating the source of the authorization value.
+  @param[in]  NvIndex            The NV Index of the area to extend.
+  @param[in]  AuthSession        Auth Session context
+  @param[in]  InData             The data to extend.
+
+  @retval EFI_SUCCESS            Operation completed successfully.
+  @retval EFI_DEVICE_ERROR       The command was unsuccessful.
+  @retval EFI_NOT_FOUND          The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvExtend (
+  IN      TPMI_RH_NV_AUTH    AuthHandle,
+  IN      TPMI_RH_NV_INDEX   NvIndex,
+  IN      TPMS_AUTH_COMMAND  *AuthSession  OPTIONAL,
+  IN      TPM2B_MAX_BUFFER   *InData
+  )
+{
+  EFI_STATUS               Status;
+  TPM2_NV_EXTEND_COMMAND   SendBuffer;
+  TPM2_NV_EXTEND_RESPONSE  RecvBuffer;
+  UINT32                   SendBufferSize;
+  UINT32                   RecvBufferSize;
+  UINT8                    *Buffer;
+  UINT32                   SessionInfoSize;
+  TPM_RC                   ResponseCode;
+
+  //
+  // Construct command
+  //
+  SendBuffer.Header.tag         = SwapBytes16 (TPM_ST_SESSIONS);
+  SendBuffer.Header.commandCode = SwapBytes32 (TPM_CC_NV_Extend);
+
+  SendBuffer.AuthHandle = SwapBytes32 (AuthHandle);
+  SendBuffer.NvIndex    = SwapBytes32 (NvIndex);
+
+  //
+  // Add in Auth session
+  //
+  Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+  // sessionInfoSize
+  SessionInfoSize            = CopyAuthSessionCommand (AuthSession, Buffer);
+  Buffer                    += SessionInfoSize;
+  SendBuffer.AuthSessionSize = SwapBytes32 (SessionInfoSize);
+
+  WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (InData->size));
+  Buffer += sizeof (UINT16);
+  CopyMem (Buffer, InData->buffer, InData->size);
+  Buffer += InData->size;
+
+  SendBufferSize              = (UINT32)(Buffer - (UINT8 *)&SendBuffer);
+  SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+  //
+  // send Tpm command
+  //
+  RecvBufferSize = sizeof (RecvBuffer);
+  Status         = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+    DEBUG ((DEBUG_ERROR, "Tpm2NvExtend - RecvBufferSize Error - %x\n", RecvBufferSize));
+    Status = EFI_DEVICE_ERROR;
+    goto Done;
+  }
+
+  ResponseCode = SwapBytes32 (RecvBuffer.Header.responseCode);
+  if (ResponseCode != TPM_RC_SUCCESS) {
+    DEBUG ((DEBUG_ERROR, "Tpm2NvExtend - responseCode - %x\n", ResponseCode));
+  }
+
+  switch (ResponseCode) {
+    case TPM_RC_SUCCESS:
+      // return data
+      break;
+    case TPM_RC_ATTRIBUTES:
+      Status = EFI_UNSUPPORTED;
+      break;
+    case TPM_RC_NV_AUTHORIZATION:
+      Status = EFI_SECURITY_VIOLATION;
+      break;
+    case TPM_RC_NV_LOCKED:
+      Status = EFI_ACCESS_DENIED;
+      break;
+    default:
+      Status = EFI_DEVICE_ERROR;
+      break;
+  }
+
+Done:
+  //
+  // Clear AuthSession Content
+  //
+  ZeroMem (&SendBuffer, sizeof (SendBuffer));
+  ZeroMem (&RecvBuffer, sizeof (RecvBuffer));
+  return Status;
+}
diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c
index f6ea8b2bbf..1d5e73fec8 100644
--- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c
+++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c
@@ -1,7 +1,7 @@
 /** @file
   This module implements Tcg2 Protocol.
 
-Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2015 - 2024, Intel Corporation. All rights reserved.<BR>
 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -19,6 +19,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include <Guid/EventExitBootServiceFailed.h>
 #include <Guid/ImageAuthentication.h>
 #include <Guid/TpmInstance.h>
+#include <Guid/DeviceAuthentication.h>
 
 #include <Protocol/DevicePath.h>
 #include <Protocol/MpService.h>
@@ -1230,10 +1231,25 @@ TcgDxeHashLogExtendEvent (
     //
     // Do not do TPM extend for EV_NO_ACTION
     //
-    Status = EFI_SUCCESS;
-    InitNoActionEvent (&NoActionEvent, NewEventHdr->EventSize);
-    if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) {
-      Status = TcgDxeLogHashEvent (&(NoActionEvent.Digests), NewEventHdr, NewEventData);
+    if (NewEventHdr->PCRIndex <= MAX_PCR_INDEX) {
+      Status = EFI_SUCCESS;
+      InitNoActionEvent (&NoActionEvent, NewEventHdr->EventSize);
+      if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) {
+        Status = TcgDxeLogHashEvent (&(NoActionEvent.Digests), NewEventHdr, NewEventData);
+      }
+    } else {
+      //
+      // Extend to NvIndex
+      //
+      Status = HashAndExtend (
+                 NewEventHdr->PCRIndex,
+                 HashData,
+                 (UINTN)HashDataLen,
+                 &DigestList
+                 );
+      if (!EFI_ERROR (Status)) {
+        Status = TcgDxeLogHashEvent (&DigestList, NewEventHdr, NewEventData);
+      }
     }
 
     return Status;
@@ -1317,7 +1333,7 @@ Tcg2HashLogExtendEvent (
     return EFI_INVALID_PARAMETER;
   }
 
-  if (Event->Header.PCRIndex > MAX_PCR_INDEX) {
+  if ((Event->Header.EventType != EV_NO_ACTION) && (Event->Header.PCRIndex > MAX_PCR_INDEX)) {
     return EFI_INVALID_PARAMETER;
   }
 
@@ -2063,7 +2079,7 @@ MeasureVariable (
       );
   }
 
-  if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) {
+  if ((EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) || (EventType == EV_EFI_SPDM_DEVICE_POLICY)) {
     //
     // Digest is the event data (UEFI_VARIABLE_DATA)
     //
@@ -2319,6 +2335,37 @@ MeasureAllSecureVariables (
     DEBUG ((DEBUG_INFO, "Skip measuring variable %s since it's deleted\n", EFI_IMAGE_SECURITY_DATABASE2));
   }
 
+  //
+  // Meaurement UEFI device signature database
+  //
+  if ((PcdGet32 (PcdTcgPfpMeasurementRevision) >= TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2_REV_106) &&
+      (PcdGet8 (PcdEnableSpdmDeviceAuthenticaion) != 0))
+  {
+    Status = GetVariable2 (EFI_DEVICE_SECURITY_DATABASE, &gEfiDeviceSignatureDatabaseGuid, &Data, &DataSize);
+    if (Status == EFI_SUCCESS) {
+      Status = MeasureVariable (
+                 PCR_INDEX_FOR_SIGNATURE_DB,
+                 EV_EFI_SPDM_DEVICE_POLICY,
+                 EFI_DEVICE_SECURITY_DATABASE,
+                 &gEfiDeviceSignatureDatabaseGuid,
+                 Data,
+                 DataSize
+                 );
+      FreePool (Data);
+    } else if (Status == EFI_NOT_FOUND) {
+      Data     = NULL;
+      DataSize = 0;
+      Status   = MeasureVariable (
+                   PCR_INDEX_FOR_SIGNATURE_DB,
+                   EV_EFI_SPDM_DEVICE_POLICY,
+                   EFI_DEVICE_SECURITY_DATABASE,
+                   &gEfiDeviceSignatureDatabaseGuid,
+                   Data,
+                   DataSize
+                   );
+    }
+  }
+
   return EFI_SUCCESS;
 }
 
diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf
index 7dc7a2683d..73cf1fec16 100644
--- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf
+++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf
@@ -16,7 +16,7 @@
 #  This external input must be validated carefully to avoid security issue like
 #  buffer overflow, integer overflow.
 #
-# Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2015 - 2024, Intel Corporation. All rights reserved.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ##
@@ -86,6 +86,7 @@
   gTcgEvent2EntryHobGuid                             ## SOMETIMES_CONSUMES  ## HOB
   gTpm2StartupLocalityHobGuid                        ## SOMETIMES_CONSUMES  ## HOB
   gTcg800155PlatformIdEventHobGuid                   ## SOMETIMES_CONSUMES  ## HOB
+  gEfiDeviceSignatureDatabaseGuid
 
 [Protocols]
   gEfiTcg2ProtocolGuid                               ## PRODUCES
@@ -107,6 +108,7 @@
   gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLaml                        ## PRODUCES
   gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLasa                        ## PRODUCES
   gEfiMdeModulePkgTokenSpaceGuid.PcdTcgPfpMeasurementRevision               ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEnableSpdmDeviceAuthenticaion           ## CONSUMES
 
 [Depex]
   # According to PcdTpm2AcpiTableRev definition in SecurityPkg.dec
-- 
2.26.2.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117310): https://edk2.groups.io/g/devel/message/117310
Mute This Topic: https://groups.io/mt/105281053/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



  parent reply	other threads:[~2024-04-02  2:31 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-02  2:31 [edk2-devel] [PATCH 0/9] Add DeviceSecurity feature based on PFP 1.06 spec Wenxing Hou
2024-04-02  2:31 ` [edk2-devel] [PATCH 1/9] MdePkg: Add SPDM1.2 support Wenxing Hou
2024-04-02  2:31 ` [edk2-devel] [PATCH 2/9] MdePkg: Add TCG PFP 1.06 support Wenxing Hou
2024-04-02  2:31 ` [edk2-devel] [PATCH 3/9] MdePkg: Add devAuthBoot GlobalVariable Wenxing Hou
2024-04-02  2:31 ` [edk2-devel] [PATCH 4/9] MdeModulePkg/Variable: Add TCG SPDM device measurement update Wenxing Hou
2024-04-04 15:57   ` Michael Kubacki
2024-04-08  1:59     ` Wenxing Hou
2024-04-02  2:31 ` Wenxing Hou [this message]
2024-04-02  2:31 ` [edk2-devel] [PATCH 6/9] SecurityPkg: add DeviceSecurity support Wenxing Hou
2024-04-02  2:31 ` [edk2-devel] [PATCH 7/9] .pytool/CISettings.py: add libspdm submodule Wenxing Hou
2024-04-03 17:32   ` Joey Vagedes via groups.io
2024-04-02  2:31 ` [edk2-devel] [PATCH 8/9] .gitmodule: Add libspdm submodule for EDKII Wenxing Hou
2024-04-02  2:31 ` [edk2-devel] [PATCH 9/9] SecurityPkg: Add libspdm submodule Wenxing Hou
2024-04-09 15:13 ` [edk2-devel] [PATCH 0/9] Add DeviceSecurity feature based on PFP 1.06 spec Michael D Kinney
2024-04-15  2:08   ` Wenxing Hou
2024-04-16  9:25     ` Yao, Jiewen
     [not found]     ` <17C6B87A036D5709.13290@groups.io>
2024-04-16  9:36       ` Yao, Jiewen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240402023125.4168-6-wenxing.hou@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox