[pve-devel] [PATCH edk2-firmware] add patch to revert addition of EFI memory attributes protocol for x86_64
Fiona Ebner
f.ebner at proxmox.com
Thu Mar 27 12:53:09 CET 2025
Because of a long-standing bug in shim [0], booting will fail for
distibutions that do not include the fix yet, like Rocky Linux 9.5
and other CentOS-based distibutions. This is cased by the addition
of the EFI_MEMORY_ATTRIBUTE_PROTOCOL in edk2 commit efaa102d00
("UefiCpuPkg: Produce EFI memory attributes protocol") for x86_64.
Even with the fix in shim, issues in commonly shipped versions of GRUB
remain [1].
This is relatively recent, i.e. in the edk2-stable202502 tag, and
since current non-minor distributions are still affected, revert the
problematic commit for now.
Once issues are less common in distributions, an option to support
disabling it (via fw_cfg on the QEMU command line) can still be added
[1]. Then, it can also be nicely documented as a known issue while
giving users guidance.
There already is a similar patch for ARM [2] inherited from the Debian
upstream version.
The problematic commit is EFI_MEMORY_ATTRIBUTE_PROTOCOL was added for x86_64 recently in the
edk2-stable202502 tag. Since current non-minor distributions are still
affected, a revert is done for now.
[0]: https://github.com/rhboot/shim/commit/c7b305152802c8db688605654f75e1195def9fd6
[1]: https://github.com/tianocore/edk2/pull/10667
[2]: ./debian/patches/ArmVirtPkg-disable-the-EFI_MEMORY_ATTRIBUTE-protocol.patch
Signed-off-by: Fiona Ebner <f.ebner at proxmox.com>
---
...g-Produce-EFI-memory-attributes-prot.patch | 368 ++++++++++++++++++
debian/patches/series | 1 +
2 files changed, 369 insertions(+)
create mode 100644 debian/patches/Revert-UefiCpuPkg-Produce-EFI-memory-attributes-prot.patch
diff --git a/debian/patches/Revert-UefiCpuPkg-Produce-EFI-memory-attributes-prot.patch b/debian/patches/Revert-UefiCpuPkg-Produce-EFI-memory-attributes-prot.patch
new file mode 100644
index 0000000..40942f3
--- /dev/null
+++ b/debian/patches/Revert-UefiCpuPkg-Produce-EFI-memory-attributes-prot.patch
@@ -0,0 +1,368 @@
+Description: Revert "UefiCpuPkg: Produce EFI memory attributes protocol"
+ Because of a long-standing bug in shim [0], booting will fail for distributions
+ that do not include the fix yet, like Rocky Linux 9.5. Temporarily disable the
+ EFI_MEMORY_ATTRIBUTE_PROTOCOL again. There already is a similar patch for ARM:
+ ArmVirtPkg-disable-the-EFI_MEMORY_ATTRIBUTE-protocol.patch
+ [0]: https://github.com/rhboot/shim/commit/c7b305152802c8db688605654f75e1195def9fd6
+Author: Fiona Ebner <f.ebner at proxmox.com>
+Last-Update: 2025-03-27
+
+diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.c b/UefiCpuPkg/CpuDxe/CpuDxe.c
+index 472de55180..bf03978710 100644
+--- a/UefiCpuPkg/CpuDxe/CpuDxe.c
++++ b/UefiCpuPkg/CpuDxe/CpuDxe.c
+@@ -1033,11 +1033,6 @@ InitializeCpu (
+ );
+ ASSERT_EFI_ERROR (Status);
+
+- //
+- // Install EFI memory attribute Protocol
+- //
+- InstallEfiMemoryAttributeProtocol (mCpuHandle);
+-
+ //
+ // Refresh GCD memory space map according to MTRR value.
+ //
+diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf
+index b2954ba234..fca74c44b3 100644
+--- a/UefiCpuPkg/CpuDxe/CpuDxe.inf
++++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf
+@@ -75,7 +75,6 @@
+
+ [Protocols]
+ gEfiCpuArchProtocolGuid ## PRODUCES
+- gEfiMemoryAttributeProtocolGuid ## PRODUCES
+ gEfiMpServiceProtocolGuid ## PRODUCES
+ gEfiSmmBase2ProtocolGuid ## SOMETIMES_CONSUMES
+
+diff --git a/UefiCpuPkg/CpuDxe/CpuPageTable.c b/UefiCpuPkg/CpuDxe/CpuPageTable.c
+index 9a519bcb7e..c5bf2285ac 100644
+--- a/UefiCpuPkg/CpuDxe/CpuPageTable.c
++++ b/UefiCpuPkg/CpuDxe/CpuPageTable.c
+@@ -1436,298 +1436,3 @@ InitializePageTableLib (
+
+ return;
+ }
+-
+-/**
+- This function set given attributes of the memory region specified by
+- BaseAddress and Length.
+- The valid Attributes is EFI_MEMORY_RP, EFI_MEMORY_XP, and EFI_MEMORY_RO.
+-
+- @param This The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.
+- @param BaseAddress The physical address that is the start address of
+- a memory region.
+- @param Length The size in bytes of the memory region.
+- @param Attributes The bit mask of attributes to set for the memory
+- region.
+-
+- @retval EFI_SUCCESS The attributes were set for the memory region.
+- @retval EFI_INVALID_PARAMETER Length is zero.
+- Attributes specified an illegal combination of
+- attributes that cannot be set together.
+- @retval EFI_UNSUPPORTED The processor does not support one or more
+- bytes of the memory resource range specified
+- by BaseAddress and Length.
+- The bit mask of attributes is not supported for
+- the memory resource range specified by
+- BaseAddress and Length.
+- @retval EFI_OUT_OF_RESOURCES Requested attributes cannot be applied due to lack of
+- system resources.
+- @retval EFI_ACCESS_DENIED Attributes for the requested memory region are
+- controlled by system firmware and cannot be updated
+- via the protocol.
+-**/
+-EFI_STATUS
+-EFIAPI
+-EfiSetMemoryAttributes (
+- IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
+- IN EFI_PHYSICAL_ADDRESS BaseAddress,
+- IN UINT64 Length,
+- IN UINT64 Attributes
+- )
+-{
+- RETURN_STATUS Status;
+- BOOLEAN IsModified;
+- BOOLEAN IsSplitted;
+-
+- DEBUG ((DEBUG_VERBOSE, "%a: 0x%lx - 0x%lx (0x%lx)\n", __func__, BaseAddress, Length, Attributes));
+-
+- if (Attributes == 0) {
+- DEBUG ((DEBUG_ERROR, "%a: Error - Attributes == 0\n", __func__));
+- return EFI_INVALID_PARAMETER;
+- }
+-
+- if ((Attributes & ~EFI_MEMORY_ACCESS_MASK) != 0) {
+- DEBUG ((DEBUG_ERROR, "%a: Error - Attributes(0x%lx) invalid\n", __func__, Attributes));
+- return EFI_INVALID_PARAMETER;
+- }
+-
+- if (Length == 0) {
+- DEBUG ((DEBUG_ERROR, "%a: Length is 0!\n", __func__));
+- return RETURN_INVALID_PARAMETER;
+- }
+-
+- Status = ConvertMemoryPageAttributes (NULL, BaseAddress, Length, Attributes, PageActionSet, NULL, &IsSplitted, &IsModified);
+- if (!EFI_ERROR (Status)) {
+- if (IsModified) {
+- //
+- // Flush TLB as last step.
+- //
+- // Note: Since APs will always init CR3 register in HLT loop mode or do
+- // TLB flush in MWAIT loop mode, there's no need to flush TLB for them
+- // here.
+- //
+- CpuFlushTlb ();
+- }
+- } else {
+- DEBUG ((DEBUG_ERROR, "%a: Failed in ConvertMemoryPageAttributes (%r)\n", __func__, Status));
+- }
+-
+- return Status;
+-}
+-
+-/**
+- This function clears given attributes of the memory region specified by
+- BaseAddress and Length.
+- The valid Attributes is EFI_MEMORY_RP, EFI_MEMORY_XP, and EFI_MEMORY_RO.
+- @param This The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.
+- @param BaseAddress The physical address that is the start address of
+- a memory region.
+- @param Length The size in bytes of the memory region.
+- @param Attributes The bit mask of attributes to clear for the memory
+- region.
+-
+- @retval EFI_SUCCESS The attributes were cleared for the memory region.
+- @retval EFI_INVALID_PARAMETER Length is zero.
+- Attributes specified an illegal combination of
+- attributes that cannot be cleared together.
+- @retval EFI_UNSUPPORTED The processor does not support one or more
+- bytes of the memory resource range specified
+- by BaseAddress and Length.
+- The bit mask of attributes is not supported for
+- the memory resource range specified by
+- BaseAddress and Length.
+- @retval EFI_OUT_OF_RESOURCES Requested attributes cannot be applied due to lack of
+- system resources.
+- @retval EFI_ACCESS_DENIED Attributes for the requested memory region are
+- controlled by system firmware and cannot be updated
+- via the protocol.
+-**/
+-EFI_STATUS
+-EFIAPI
+-EfiClearMemoryAttributes (
+- IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
+- IN EFI_PHYSICAL_ADDRESS BaseAddress,
+- IN UINT64 Length,
+- IN UINT64 Attributes
+- )
+-{
+- RETURN_STATUS Status;
+- BOOLEAN IsModified;
+- BOOLEAN IsSplitted;
+-
+- DEBUG ((DEBUG_VERBOSE, "%a: 0x%lx - 0x%lx (0x%lx)\n", __func__, BaseAddress, Length, Attributes));
+-
+- if (Attributes == 0) {
+- DEBUG ((DEBUG_ERROR, "%a: Error - Attributes == 0\n", __func__));
+- return EFI_INVALID_PARAMETER;
+- }
+-
+- if ((Attributes & ~EFI_MEMORY_ACCESS_MASK) != 0) {
+- DEBUG ((DEBUG_ERROR, "%a: Error - Attributes(0x%lx) invalid\n", __func__, Attributes));
+- return EFI_INVALID_PARAMETER;
+- }
+-
+- if (Length == 0) {
+- DEBUG ((DEBUG_ERROR, "%a: Length is 0!\n", __func__));
+- return RETURN_INVALID_PARAMETER;
+- }
+-
+- Status = ConvertMemoryPageAttributes (NULL, BaseAddress, Length, Attributes, PageActionClear, NULL, &IsSplitted, &IsModified);
+- if (!EFI_ERROR (Status)) {
+- if (IsModified) {
+- //
+- // Flush TLB as last step.
+- //
+- // Note: Since APs will always init CR3 register in HLT loop mode or do
+- // TLB flush in MWAIT loop mode, there's no need to flush TLB for them
+- // here.
+- //
+- CpuFlushTlb ();
+- }
+- } else {
+- DEBUG ((DEBUG_ERROR, "%a: Failed in ConvertMemoryPageAttributes (%r)\n", __func__, Status));
+- }
+-
+- return Status;
+-}
+-
+-/**
+- This function retrieves the attributes of the memory region specified by
+- BaseAddress and Length. If different attributes are got from different part
+- of the memory region, EFI_NO_MAPPING will be returned.
+-
+- @param This The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.
+- @param BaseAddress The physical address that is the start address of
+- a memory region.
+- @param Length The size in bytes of the memory region.
+- @param Attributes Pointer to attributes returned.
+-
+- @retval EFI_SUCCESS The attributes got for the memory region.
+- @retval EFI_INVALID_PARAMETER Length is zero.
+- Attributes is NULL.
+- @retval EFI_NO_MAPPING Attributes are not consistent cross the memory
+- region.
+- @retval EFI_UNSUPPORTED The processor does not support one or more
+- bytes of the memory resource range specified
+- by BaseAddress and Length.
+-**/
+-EFI_STATUS
+-EFIAPI
+-EfiGetMemoryAttributes (
+- IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
+- IN EFI_PHYSICAL_ADDRESS BaseAddress,
+- IN UINT64 Length,
+- OUT UINT64 *Attributes
+- )
+-{
+- PAGE_TABLE_LIB_PAGING_CONTEXT CurrentPagingContext;
+- EFI_PHYSICAL_ADDRESS Address;
+- UINT64 *PageEntry;
+- UINT64 MemAttr;
+- PAGE_ATTRIBUTE PageAttr;
+- INT64 Size;
+- UINT64 AddressEncMask;
+-
+- DEBUG ((DEBUG_VERBOSE, "%a: 0x%lx - 0x%lx\n", __func__, BaseAddress, Length));
+-
+- if (!IS_ALIGNED (BaseAddress, EFI_PAGE_SIZE)) {
+- DEBUG ((DEBUG_ERROR, "%a: BaseAddress(0x%lx) is not aligned!\n", __func__, BaseAddress));
+- return EFI_UNSUPPORTED;
+- }
+-
+- if (!IS_ALIGNED (Length, EFI_PAGE_SIZE)) {
+- DEBUG ((DEBUG_ERROR, "%a: Length(0x%lx) is not aligned!\n", __func__, Length));
+- return EFI_UNSUPPORTED;
+- }
+-
+- if (Length == 0) {
+- DEBUG ((DEBUG_ERROR, "%a: Length is 0!\n", __func__));
+- return RETURN_INVALID_PARAMETER;
+- }
+-
+- if (Attributes == NULL) {
+- DEBUG ((DEBUG_ERROR, "%a: Attributes is NULL\n", __func__));
+- return EFI_INVALID_PARAMETER;
+- }
+-
+- Size = (INT64)Length;
+- MemAttr = (UINT64)-1;
+-
+- // Make sure AddressEncMask is contained to smallest supported address field.
+- //
+- AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+-
+- GetCurrentPagingContext (&CurrentPagingContext);
+-
+- do {
+- PageEntry = GetPageTableEntry (&CurrentPagingContext, BaseAddress, &PageAttr);
+- if ((PageEntry == NULL) || (PageAttr == PageNone)) {
+- return EFI_UNSUPPORTED;
+- }
+-
+- //
+- // If the memory range is cross page table boundary, make sure they
+- // share the same attribute. Return EFI_NO_MAPPING if not.
+- //
+- *Attributes = GetAttributesFromPageEntry (PageEntry);
+- if ((MemAttr != (UINT64)-1) && (*Attributes != MemAttr)) {
+- return EFI_NO_MAPPING;
+- }
+-
+- switch (PageAttr) {
+- case Page4K:
+- Address = *PageEntry & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64;
+- Size -= (EFI_PAGE_SIZE - (BaseAddress - Address));
+- BaseAddress += (EFI_PAGE_SIZE - (BaseAddress - Address));
+- break;
+-
+- case Page2M:
+- Address = *PageEntry & ~AddressEncMask & PAGING_2M_ADDRESS_MASK_64;
+- Size -= SIZE_2MB - (BaseAddress - Address);
+- BaseAddress += SIZE_2MB - (BaseAddress - Address);
+- break;
+-
+- case Page1G:
+- Address = *PageEntry & ~AddressEncMask & PAGING_1G_ADDRESS_MASK_64;
+- Size -= SIZE_1GB - (BaseAddress - Address);
+- BaseAddress += SIZE_1GB - (BaseAddress - Address);
+- break;
+-
+- default:
+- return EFI_UNSUPPORTED;
+- }
+-
+- MemAttr = *Attributes;
+- } while (Size > 0);
+-
+- DEBUG ((DEBUG_VERBOSE, "%a: Attributes is 0x%lx\n", __func__, *Attributes));
+-
+- return EFI_SUCCESS;
+-}
+-
+-EFI_MEMORY_ATTRIBUTE_PROTOCOL mMemoryAttributeProtocol = {
+- EfiGetMemoryAttributes,
+- EfiSetMemoryAttributes,
+- EfiClearMemoryAttributes,
+-};
+-
+-/**
+- Install Efi Memory Attribute Protocol.
+-
+- @param Handle A pointer to the EFI_HANDLE on which the interface is to be installed
+-
+-**/
+-VOID
+-InstallEfiMemoryAttributeProtocol (
+- IN EFI_HANDLE Handle
+- )
+-{
+- EFI_STATUS Status;
+-
+- Status = gBS->InstallMultipleProtocolInterfaces (
+- &Handle,
+- &gEfiMemoryAttributeProtocolGuid,
+- &mMemoryAttributeProtocol,
+- NULL
+- );
+- ASSERT_EFI_ERROR (Status);
+-}
+diff --git a/UefiCpuPkg/CpuDxe/CpuPageTable.h b/UefiCpuPkg/CpuDxe/CpuPageTable.h
+index f2694452f5..607e936b8a 100644
+--- a/UefiCpuPkg/CpuDxe/CpuPageTable.h
++++ b/UefiCpuPkg/CpuDxe/CpuPageTable.h
+@@ -10,7 +10,6 @@
+ #define _PAGE_TABLE_LIB_H_
+
+ #include <IndustryStandard/PeImage.h>
+-#include <Protocol/MemoryAttribute.h>
+
+ #define PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PSE BIT0
+ #define PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE BIT1
+@@ -154,15 +153,4 @@ GetPagingDetails (
+ OUT UINT32 **Attributes OPTIONAL
+ );
+
+-/**
+- Install Efi Memory Attribute Protocol.
+-
+- @param Handle A pointer to the EFI_HANDLE on which the interface is to be installed
+-
+-**/
+-VOID
+-InstallEfiMemoryAttributeProtocol (
+- IN EFI_HANDLE Handle
+- );
+-
+ #endif
diff --git a/debian/patches/series b/debian/patches/series
index c18b4e8..45b3050 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -3,3 +3,4 @@ brotlicompress-disable.diff
x64-baseline-abi.patch
Revert-ArmVirtPkg-make-EFI_LOADER_DATA-non-executabl.patch
ArmVirtPkg-disable-the-EFI_MEMORY_ATTRIBUTE-protocol.patch
+Revert-UefiCpuPkg-Produce-EFI-memory-attributes-prot.patch
--
2.39.5
More information about the pve-devel
mailing list