From: "Taylor Beebe" <t@taylorbeebe.com>
To: devel@edk2.groups.io
Cc: Jian J Wang <jian.j.wang@intel.com>,
Liming Gao <gaoliming@byosoft.com.cn>,
Dandan Bi <dandan.bi@intel.com>
Subject: [PATCH 03/14] MdeModulePkg: Add Phase-Specific MemoryProtectionHobLib Implementations
Date: Tue, 11 Jul 2023 16:52:40 -0700 [thread overview]
Message-ID: <e485459b6efb1e49591c6f3011d9da14746c52bc.1689101263.git.t@taylorbeebe.com> (raw)
In-Reply-To: <cover.1689101263.git.t@taylorbeebe.com>
From: Taylor Beebe <tabeebe@microsoft.com>
Add DXE, SMM, and STANDALONE MM implementations of the
MemoryProtectionHobLib.
Signed-off-by: Taylor Beebe <t@taylorbeebe.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Dandan Bi <dandan.bi@intel.com>
---
.../DxeMemoryProtectionHobLib.c | 132 ++++++++++++++++++
.../DxeMemoryProtectionHobLib.inf | 34 +++++
.../MmCommonMemoryProtectionHobLib.c | 89 ++++++++++++
.../SmmMemoryProtectionHobLib.c | 37 +++++
.../SmmMemoryProtectionHobLib.inf | 35 +++++
.../StandaloneMmMemoryProtectionHobLib.c | 37 +++++
.../StandaloneMmMemoryProtectionHobLib.inf | 36 +++++
MdeModulePkg/MdeModulePkg.dsc | 3 +
8 files changed, 403 insertions(+)
create mode 100644 MdeModulePkg/Library/MemoryProtectionHobLib/DxeMemoryProtectionHobLib.c
create mode 100644 MdeModulePkg/Library/MemoryProtectionHobLib/DxeMemoryProtectionHobLib.inf
create mode 100644 MdeModulePkg/Library/MemoryProtectionHobLib/MmCommonMemoryProtectionHobLib.c
create mode 100644 MdeModulePkg/Library/MemoryProtectionHobLib/SmmMemoryProtectionHobLib.c
create mode 100644 MdeModulePkg/Library/MemoryProtectionHobLib/SmmMemoryProtectionHobLib.inf
create mode 100644 MdeModulePkg/Library/MemoryProtectionHobLib/StandaloneMmMemoryProtectionHobLib.c
create mode 100644 MdeModulePkg/Library/MemoryProtectionHobLib/StandaloneMmMemoryProtectionHobLib.inf
diff --git a/MdeModulePkg/Library/MemoryProtectionHobLib/DxeMemoryProtectionHobLib.c b/MdeModulePkg/Library/MemoryProtectionHobLib/DxeMemoryProtectionHobLib.c
new file mode 100644
index 0000000000..fde568fcee
--- /dev/null
+++ b/MdeModulePkg/Library/MemoryProtectionHobLib/DxeMemoryProtectionHobLib.c
@@ -0,0 +1,132 @@
+/** @file
+Library fills out gDxeMps global
+
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <Pi/PiMultiPhase.h>
+#include <Uefi/UefiMultiPhase.h>
+
+#include <Library/DxeMemoryProtectionHobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseMemoryLib.h>
+
+DXE_MEMORY_PROTECTION_SETTINGS gDxeMps;
+
+/**
+ This function checks the memory protection settings and provides warnings of settings conflicts.
+ For compatibility, this logic will only ever turn off protections to create consistency,
+ never turn others on.
+**/
+VOID
+DxeMemoryProtectionSettingsConsistencyCheck (
+ VOID
+ )
+{
+ if ((gDxeMps.HeapGuard.PoolGuardEnabled || gDxeMps.HeapGuard.PageGuardEnabled) &&
+ gDxeMps.HeapGuard.FreedMemoryGuardEnabled)
+ {
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: - HeapGuard.FreedMemoryGuardEnabled and "
+ "UEFI HeapGuard.PoolGuardEnabled/HeapGuard.PageGuardEnabled "
+ "cannot be active at the same time. Setting all three to ZERO in "
+ "the memory protection settings global.\n",
+ __func__
+ ));
+ ASSERT (
+ !(gDxeMps.HeapGuard.FreedMemoryGuardEnabled &&
+ (gDxeMps.HeapGuard.PoolGuardEnabled || gDxeMps.HeapGuard.PageGuardEnabled))
+ );
+ gDxeMps.HeapGuard.PoolGuardEnabled = FALSE;
+ gDxeMps.HeapGuard.PageGuardEnabled = FALSE;
+ gDxeMps.HeapGuard.FreedMemoryGuardEnabled = FALSE;
+ }
+
+ if (DXE_MPS_IS_ANY_MEMORY_TYPE_ACTIVE (&gDxeMps.PoolGuard) &&
+ (!(gDxeMps.HeapGuard.PoolGuardEnabled)))
+ {
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: - PoolGuard protections are active "
+ "but HeapGuard.PoolGuardEnabled is inactive.\n",
+ __func__
+ ));
+ }
+
+ if (DXE_MPS_IS_ANY_MEMORY_TYPE_ACTIVE (&gDxeMps.PageGuard) &&
+ (!(gDxeMps.HeapGuard.PageGuardEnabled)))
+ {
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: - PageGuard protections are active "
+ "but HeapGuard.PageGuardEnabled is inactive\n",
+ __func__
+ ));
+ }
+
+ if (gDxeMps.ExecutionProtection.EnabledForType[EfiBootServicesData] !=
+ gDxeMps.ExecutionProtection.EnabledForType[EfiConventionalMemory])
+ {
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: - EfiBootServicesData and EfiConventionalMemory must have the same "
+ "ExecutionProtection value. Setting both to ZERO in the memory protection "
+ "settings global.\n",
+ __func__
+ ));
+ ASSERT (
+ gDxeMps.ExecutionProtection.EnabledForType[EfiBootServicesData] ==
+ gDxeMps.ExecutionProtection.EnabledForType[EfiConventionalMemory]
+ );
+ gDxeMps.ExecutionProtection.EnabledForType[EfiBootServicesData] = FALSE;
+ gDxeMps.ExecutionProtection.EnabledForType[EfiConventionalMemory] = FALSE;
+ }
+}
+
+/**
+ Populates gDxeMps global with the data present in the HOB. If the HOB entry does not exist,
+ this constructor will zero the memory protection settings.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+**/
+EFI_STATUS
+EFIAPI
+DxeMemoryProtectionHobLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ VOID *Ptr;
+ DXE_MEMORY_PROTECTION_SETTINGS *DxeMps;
+
+ Ptr = GetFirstGuidHob (&gDxeMemoryProtectionSettingsGuid);
+
+ //
+ // Cache the Memory Protection Settings HOB entry
+ //
+ if (Ptr != NULL) {
+ DxeMps = (DXE_MEMORY_PROTECTION_SETTINGS *)GET_GUID_HOB_DATA (Ptr);
+ if (!DXE_MPS_IS_STRUCT_VALID (DxeMps)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: - Version number of the DXE Memory Protection Settings HOB is invalid!\n",
+ __func__
+ ));
+ ASSERT (DXE_MPS_IS_STRUCT_VALID (DxeMps));
+ ZeroMem (&gDxeMps, sizeof (gDxeMps));
+ return EFI_SUCCESS;
+ }
+
+ CopyMem (&gDxeMps, DxeMps, sizeof (DXE_MEMORY_PROTECTION_SETTINGS));
+ DxeMemoryProtectionSettingsConsistencyCheck ();
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Library/MemoryProtectionHobLib/DxeMemoryProtectionHobLib.inf b/MdeModulePkg/Library/MemoryProtectionHobLib/DxeMemoryProtectionHobLib.inf
new file mode 100644
index 0000000000..57ca55446b
--- /dev/null
+++ b/MdeModulePkg/Library/MemoryProtectionHobLib/DxeMemoryProtectionHobLib.inf
@@ -0,0 +1,34 @@
+## @file
+# DXE library instance to support platform-specific global controls for all memory protections.
+#
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeMemoryProtectionHobLib
+ FILE_GUID = f497f7de-b9ab-4b9f-807e-89778922542d
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DxeMemoryProtectionHobLib|DXE_DRIVER DXE_CORE UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = DxeMemoryProtectionHobLibConstructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources]
+ DxeMemoryProtectionHobLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ HobLib
+ DebugLib
+ BaseMemoryLib
+
+[Guids]
+ gDxeMemoryProtectionSettingsGuid
diff --git a/MdeModulePkg/Library/MemoryProtectionHobLib/MmCommonMemoryProtectionHobLib.c b/MdeModulePkg/Library/MemoryProtectionHobLib/MmCommonMemoryProtectionHobLib.c
new file mode 100644
index 0000000000..73f4b0cd88
--- /dev/null
+++ b/MdeModulePkg/Library/MemoryProtectionHobLib/MmCommonMemoryProtectionHobLib.c
@@ -0,0 +1,89 @@
+/** @file
+Library fills out gMmMps global
+
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <Pi/PiMultiPhase.h>
+#include <Uefi/UefiMultiPhase.h>
+
+#include <Library/MmMemoryProtectionHobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseMemoryLib.h>
+
+MM_MEMORY_PROTECTION_SETTINGS gMmMps;
+
+/**
+ This function checks the memory protection settings and provides warnings of settings conflicts.
+ For compatibility, this logic will only ever turn off protections to create consistency,
+ never turn others on.
+**/
+VOID
+MmMemoryProtectionSettingsConsistencyCheck (
+ VOID
+ )
+{
+ if (MM_MPS_IS_ANY_MEMORY_TYPE_ACTIVE (&gMmMps.PoolGuard) &&
+ (!gMmMps.HeapGuard.PoolGuardEnabled))
+ {
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: - PoolGuard protections are active "
+ "but HeapGuard.PoolGuardEnabled is inactive.\n",
+ __func__
+ ));
+ }
+
+ if (MM_MPS_IS_ANY_MEMORY_TYPE_ACTIVE (&gMmMps.PageGuard) &&
+ (!gMmMps.HeapGuard.PageGuardEnabled))
+ {
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: - PageGuard protections are active "
+ "but HeapGuard.PageGuardEnabled is inactive\n",
+ __func__
+ ));
+ }
+}
+
+/**
+ Abstraction layer for library constructor of Standalone MM and SMM instances.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+**/
+EFI_STATUS
+EFIAPI
+MmMemoryProtectionHobLibConstructorCommon (
+ VOID
+ )
+{
+ VOID *Ptr;
+ MM_MEMORY_PROTECTION_SETTINGS *MmMps;
+
+ Ptr = GetFirstGuidHob (&gMmMemoryProtectionSettingsGuid);
+
+ //
+ // Cache the Memory Protection Settings HOB entry
+ //
+ if (Ptr != NULL) {
+ MmMps = (MM_MEMORY_PROTECTION_SETTINGS *)GET_GUID_HOB_DATA (Ptr);
+ if (!MM_MPS_IS_STRUCT_VALID (MmMps)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: - Version number of the MM Memory Protection Settings HOB is invalid!\n",
+ __func__
+ ));
+ ASSERT (MM_MPS_IS_STRUCT_VALID (MmMps));
+ ZeroMem (&gMmMps, sizeof (gMmMps));
+ return EFI_SUCCESS;
+ }
+
+ CopyMem (&gMmMps, MmMps, sizeof (MM_MEMORY_PROTECTION_SETTINGS));
+ MmMemoryProtectionSettingsConsistencyCheck ();
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Library/MemoryProtectionHobLib/SmmMemoryProtectionHobLib.c b/MdeModulePkg/Library/MemoryProtectionHobLib/SmmMemoryProtectionHobLib.c
new file mode 100644
index 0000000000..fffc90a721
--- /dev/null
+++ b/MdeModulePkg/Library/MemoryProtectionHobLib/SmmMemoryProtectionHobLib.c
@@ -0,0 +1,37 @@
+/** @file
+Library fills out gMmMps global
+
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiSmm.h>
+
+/**
+ Abstraction layer for library constructor of Standalone MM and SMM instances.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+**/
+EFI_STATUS
+EFIAPI
+MmMemoryProtectionHobLibConstructorCommon (
+ VOID
+ );
+
+/**
+ Library constructor of SMM instance.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+**/
+EFI_STATUS
+EFIAPI
+SmmMemoryProtectionHobLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return MmMemoryProtectionHobLibConstructorCommon ();
+}
diff --git a/MdeModulePkg/Library/MemoryProtectionHobLib/SmmMemoryProtectionHobLib.inf b/MdeModulePkg/Library/MemoryProtectionHobLib/SmmMemoryProtectionHobLib.inf
new file mode 100644
index 0000000000..4651158bd4
--- /dev/null
+++ b/MdeModulePkg/Library/MemoryProtectionHobLib/SmmMemoryProtectionHobLib.inf
@@ -0,0 +1,35 @@
+## @file
+# SMM library instance to support platform-specific global controls for all memory protections.
+#
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmMemoryProtectionHobLib
+ FILE_GUID = dc9666f4-917f-400d-8026-2b3beeeff195
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MmMemoryProtectionHobLib|SMM_CORE DXE_SMM_DRIVER
+ CONSTRUCTOR = SmmMemoryProtectionHobLibConstructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources]
+ MmCommonMemoryProtectionHobLib.c
+ SmmMemoryProtectionHobLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ HobLib
+ DebugLib
+ BaseMemoryLib
+
+[Guids]
+ gMmMemoryProtectionSettingsGuid
diff --git a/MdeModulePkg/Library/MemoryProtectionHobLib/StandaloneMmMemoryProtectionHobLib.c b/MdeModulePkg/Library/MemoryProtectionHobLib/StandaloneMmMemoryProtectionHobLib.c
new file mode 100644
index 0000000000..3fd8b9f259
--- /dev/null
+++ b/MdeModulePkg/Library/MemoryProtectionHobLib/StandaloneMmMemoryProtectionHobLib.c
@@ -0,0 +1,37 @@
+/** @file
+Library fills out gMmMps global
+
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiMm.h>
+
+/**
+ Abstraction layer for library constructor of Standalone MM and SMM instances.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+**/
+EFI_STATUS
+EFIAPI
+MmMemoryProtectionHobLibConstructorCommon (
+ VOID
+ );
+
+/**
+ Library constructor of Standalone MM instance.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI MM System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+**/
+EFI_STATUS
+EFIAPI
+StandaloneMmMemoryProtectionHobLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *SystemTable
+ )
+{
+ return MmMemoryProtectionHobLibConstructorCommon ();
+}
diff --git a/MdeModulePkg/Library/MemoryProtectionHobLib/StandaloneMmMemoryProtectionHobLib.inf b/MdeModulePkg/Library/MemoryProtectionHobLib/StandaloneMmMemoryProtectionHobLib.inf
new file mode 100644
index 0000000000..3cadb5ec6e
--- /dev/null
+++ b/MdeModulePkg/Library/MemoryProtectionHobLib/StandaloneMmMemoryProtectionHobLib.inf
@@ -0,0 +1,36 @@
+## @file
+# SMM library instance to support platform-specific global controls for all memory protections.
+#
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = StandaloneMmMemoryProtectionHobLib
+ FILE_GUID = C0A0D9C4-A249-483A-86EA-D73146D397B3
+ MODULE_TYPE = MM_CORE_STANDALONE
+ PI_SPECIFICATION_VERSION = 0x00010032
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MmMemoryProtectionHobLib|MM_CORE_STANDALONE MM_STANDALONE
+ CONSTRUCTOR = StandaloneMmMemoryProtectionHobLibConstructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources]
+ MmCommonMemoryProtectionHobLib.c
+ StandaloneMmMemoryProtectionHobLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ HobLib
+ DebugLib
+ BaseMemoryLib
+
+[Guids]
+ gMmMemoryProtectionSettingsGuid
diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index 3fad493c7f..ec3c8913ad 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -237,6 +237,9 @@
MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf
MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf
+ MdeModulePkg/Library/MemoryProtectionHobLib/DxeMemoryProtectionHobLib.inf
+ MdeModulePkg/Library/MemoryProtectionHobLib/SmmMemoryProtectionHobLib.inf
+ MdeModulePkg/Library/MemoryProtectionHobLib/StandaloneMmMemoryProtectionHobLib.inf
MdeModulePkg/Library/MemoryProtectionHobLibNull/DxeMemoryProtectionHobLibNull.inf
MdeModulePkg/Library/MemoryProtectionHobLibNull/MmMemoryProtectionHobLibNull.inf
MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.inf
--
2.41.0.windows.2
next prev parent reply other threads:[~2023-07-11 23:53 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-07-11 23:52 [PATCH 00/14] Implement Dynamic Memory Protections Taylor Beebe
2023-07-11 23:52 ` [PATCH 01/14] MdeModulePkg: Add DXE and MM Memory Protection Settings Definitions Taylor Beebe
2023-07-11 23:52 ` [PATCH 02/14] MdeModulePkg: Add MemoryProtectionHobLib Definitions and NULL Libs Taylor Beebe
2023-07-11 23:52 ` Taylor Beebe [this message]
2023-07-11 23:52 ` [PATCH 04/14] OvmfPkg: Create the memory protection settings HOB Taylor Beebe
2023-07-11 23:52 ` [PATCH 05/14] ArmVirtPkg: Create " Taylor Beebe
2023-07-11 23:52 ` [PATCH 06/14] ArmPkg: Update to use memory protection HOB Taylor Beebe
2023-07-11 23:52 ` [PATCH 07/14] EmulatorPkg: " Taylor Beebe
2023-07-11 23:52 ` [PATCH 08/14] MdeModulePkg: " Taylor Beebe
2023-07-11 23:52 ` [PATCH 09/14] OvmfPkg: " Taylor Beebe
2023-07-11 23:52 ` [PATCH 10/14] UefiCpuPkg: " Taylor Beebe
2023-07-11 23:52 ` [PATCH 11/14] UefiPayloadPkg: " Taylor Beebe
2023-07-11 23:52 ` [PATCH 12/14] OvmfPkg: Delete Memory Protection PCDs Taylor Beebe
2023-07-11 23:52 ` [PATCH 14/14] MdeModulePkg: " Taylor Beebe
2023-07-11 23:52 ` Taylor Beebe
[not found] ` <1770F551E2E594C0.16575@groups.io>
2023-07-12 0:01 ` [edk2-devel] " Taylor Beebe
2023-07-12 10:05 ` [PATCH 00/14] Implement Dynamic Memory Protections Gerd Hoffmann
2023-07-12 21:54 ` Taylor Beebe
2023-07-17 11:14 ` [edk2-devel] " Gerd Hoffmann
2023-07-17 16:15 ` Pedro Falcato
2023-07-17 16:25 ` Ard Biesheuvel
2023-07-17 16:49 ` Pedro Falcato
2023-07-18 2:45 ` Taylor Beebe
2023-07-18 6:11 ` Ni, Ray
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=e485459b6efb1e49591c6f3011d9da14746c52bc.1689101263.git.t@taylorbeebe.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