[PATCH v2 3/3] ArmPkg/CpuDxe: Implement EFI memory attributes protocol


Ard Biesheuvel
 

Expose the protocol introduced in v2.10 that permits the caller to
manage mapping permissions in the page tables.

Signed-off-by: Ard Biesheuvel <ardb@...>
---
ArmPkg/Drivers/CpuDxe/CpuDxe.c | 2 +
ArmPkg/Drivers/CpuDxe/CpuDxe.h | 3 +
ArmPkg/Drivers/CpuDxe/CpuDxe.inf | 2 +
ArmPkg/Drivers/CpuDxe/MemoryAttribute.c | 252 ++++++++++++++++++++
4 files changed, 259 insertions(+)

diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
index e6742f0a25fc..d04958e79e52 100644
--- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
@@ -244,6 +244,8 @@ CpuDxeInitialize (
&mCpuHandle,=0D
&gEfiCpuArchProtocolGuid,=0D
&mCpu,=0D
+ &gEfiMemoryAttributeProtocolGuid,=0D
+ &mMemoryAttribute,=0D
NULL=0D
);=0D
=0D
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
index 8933fa90c4ed..f45d2bc101a3 100644
--- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
@@ -30,9 +30,12 @@
#include <Protocol/Cpu.h>=0D
#include <Protocol/DebugSupport.h>=0D
#include <Protocol/LoadedImage.h>=0D
+#include <Protocol/MemoryAttribute.h>=0D
=0D
extern BOOLEAN mIsFlushingGCD;=0D
=0D
+extern EFI_MEMORY_ATTRIBUTE_PROTOCOL mMemoryAttribute;=0D
+=0D
/**=0D
This function registers and enables the handler specified by InterruptHa=
ndler for a processor=0D
interrupt or exception type specified by InterruptType. If InterruptHand=
ler is NULL, then the=0D
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/ArmPkg/Drivers/CpuDxe/CpuDx=
e.inf
index 10792b393fc8..e732e21cb94a 100644
--- a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
@@ -23,6 +23,7 @@ [Sources.Common]
CpuDxe.h=0D
CpuMmuCommon.c=0D
Exception.c=0D
+ MemoryAttribute.c=0D
=0D
[Sources.ARM]=0D
Arm/Mmu.c=0D
@@ -53,6 +54,7 @@ [LibraryClasses]
=0D
[Protocols]=0D
gEfiCpuArchProtocolGuid=0D
+ gEfiMemoryAttributeProtocolGuid=0D
=0D
[Guids]=0D
gEfiDebugImageInfoTableGuid=0D
diff --git a/ArmPkg/Drivers/CpuDxe/MemoryAttribute.c b/ArmPkg/Drivers/CpuDx=
e/MemoryAttribute.c
new file mode 100644
index 000000000000..827deb94dd99
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/MemoryAttribute.c
@@ -0,0 +1,252 @@
+/** @file=0D
+=0D
+ Copyright (c) 2023, Google LLC. All rights reserved.=0D
+=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#include "CpuDxe.h"=0D
+=0D
+/**=0D
+ This function retrieves the attributes of the memory region specified by=
=0D
+ BaseAddress and Length. If different attributes are got from different p=
art=0D
+ of the memory region, EFI_NO_MAPPING will be returned.=0D
+=0D
+ @param This The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.=0D
+ @param BaseAddress The physical address that is the start address=
of=0D
+ a memory region.=0D
+ @param Length The size in bytes of the memory region.=0D
+ @param Attributes Pointer to attributes returned.=0D
+=0D
+ @retval EFI_SUCCESS The attributes got for the memory region.=
=0D
+ @retval EFI_INVALID_PARAMETER Length is zero.=0D
+ Attributes is NULL.=0D
+ @retval EFI_NO_MAPPING Attributes are not consistent cross the me=
mory=0D
+ region.=0D
+ @retval EFI_UNSUPPORTED The processor does not support one or more=
=0D
+ bytes of the memory resource range specifi=
ed=0D
+ by BaseAddress and Length.=0D
+=0D
+**/=0D
+STATIC=0D
+EFI_STATUS=0D
+GetMemoryAttributes (=0D
+ IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,=0D
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,=0D
+ IN UINT64 Length,=0D
+ OUT UINT64 *Attributes=0D
+ )=0D
+{=0D
+ UINTN RegionAddress;=0D
+ UINTN RegionLength;=0D
+ UINTN RegionAttributes;=0D
+ UINTN Union;=0D
+ UINTN Intersection;=0D
+ EFI_STATUS Status;=0D
+=0D
+ if ((Length =3D=3D 0) || (Attributes =3D=3D NULL)) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ DEBUG ((DEBUG_INFO,=0D
+ "%a: BaseAddress =3D=3D 0x%lx, Length =3D=3D 0x%lx\n",=0D
+ __FUNCTION__,=0D
+ (UINTN)BaseAddress,=0D
+ (UINTN)Length=0D
+ ));=0D
+=0D
+ Union =3D 0;=0D
+ Intersection =3D MAX_UINTN;=0D
+=0D
+ for (RegionAddress =3D (UINTN)BaseAddress;=0D
+ RegionAddress < (UINTN)(BaseAddress + Length);=0D
+ RegionAddress +=3D RegionLength) {=0D
+=0D
+ Status =3D GetMemoryRegion (&RegionAddress,=0D
+ &RegionLength,=0D
+ &RegionAttributes=0D
+ );=0D
+=0D
+ DEBUG ((DEBUG_INFO,=0D
+ "%a: RegionAddress =3D=3D 0x%lx, RegionLength =3D=3D 0x%lx, Re=
gionAttributes =3D=3D 0x%lx\n",=0D
+ __FUNCTION__,=0D
+ RegionAddress,=0D
+ RegionLength,=0D
+ RegionAttributes=0D
+ ));=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return EFI_NO_MAPPING;=0D
+ }=0D
+=0D
+ Union |=3D RegionAttributes;=0D
+ Intersection &=3D RegionAttributes;=0D
+ }=0D
+=0D
+ DEBUG ((DEBUG_INFO,=0D
+ "%a: Union =3D=3D %lx, Intersection =3D=3D %lx\n",=0D
+ __FUNCTION__,=0D
+ Union,=0D
+ Intersection=0D
+ ));=0D
+=0D
+ if (Union !=3D Intersection) {=0D
+ return EFI_NO_MAPPING;=0D
+ }=0D
+=0D
+ *Attributes =3D PageAttributeToGcdAttribute (Union) & (EFI_MEMORY_RO | E=
FI_MEMORY_XP);=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ This function set given attributes of the memory region specified by=0D
+ BaseAddress and Length.=0D
+=0D
+ The valid Attributes is EFI_MEMORY_RP, EFI_MEMORY_XP, and EFI_MEMORY_RO.=
=0D
+=0D
+ @param This The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.=0D
+ @param BaseAddress The physical address that is the start address=
of=0D
+ a memory region.=0D
+ @param Length The size in bytes of the memory region.=0D
+ @param Attributes The bit mask of attributes to set for the memo=
ry=0D
+ region.=0D
+=0D
+ @retval EFI_SUCCESS The attributes were set for the memory reg=
ion.=0D
+ @retval EFI_INVALID_PARAMETER Length is zero.=0D
+ Attributes specified an illegal combinatio=
n of=0D
+ attributes that cannot be set together.=0D
+ @retval EFI_UNSUPPORTED The processor does not support one or more=
=0D
+ bytes of the memory resource range specifi=
ed=0D
+ by BaseAddress and Length.=0D
+ The bit mask of attributes is not supporte=
d for=0D
+ the memory resource range specified by=0D
+ BaseAddress and Length.=0D
+ @retval EFI_OUT_OF_RESOURCES Requested attributes cannot be applied due=
to=0D
+ lack of system resources.=0D
+ @retval EFI_ACCESS_DENIED Attributes for the requested memory region=
are=0D
+ controlled by system firmware and cannot b=
e=0D
+ updated via the protocol.=0D
+=0D
+**/=0D
+STATIC=0D
+EFI_STATUS=0D
+SetMemoryAttributes (=0D
+ IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,=0D
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,=0D
+ IN UINT64 Length,=0D
+ IN UINT64 Attributes=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+=0D
+ DEBUG ((DEBUG_INFO,=0D
+ "%a: BaseAddress =3D=3D 0x%lx, Length =3D=3D 0x%lx, Attributes =
=3D=3D 0x%lx\n",=0D
+ __FUNCTION__,=0D
+ (UINTN)BaseAddress,=0D
+ (UINTN)Length,=0D
+ (UINTN)Attributes=0D
+ ));=0D
+=0D
+ if ((Length =3D=3D 0) ||=0D
+ ((Attributes & ~(EFI_MEMORY_RO | EFI_MEMORY_RP | EFI_MEMORY_XP)) !=
=3D 0)) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ if ((Attributes & EFI_MEMORY_RP) !=3D 0) {=0D
+ return EFI_UNSUPPORTED;=0D
+ }=0D
+=0D
+ if ((Attributes & EFI_MEMORY_RO) !=3D 0) {=0D
+ Status =3D ArmSetMemoryRegionReadOnly (BaseAddress, Length);=0D
+ if (EFI_ERROR (Status)) {=0D
+ return EFI_UNSUPPORTED;=0D
+ }=0D
+ }=0D
+=0D
+ if ((Attributes & EFI_MEMORY_XP) !=3D 0) {=0D
+ Status =3D ArmSetMemoryRegionNoExec (BaseAddress, Length);=0D
+ if (EFI_ERROR (Status)) {=0D
+ return EFI_UNSUPPORTED;=0D
+ }=0D
+ }=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ This function clears given attributes of the memory region specified by=
=0D
+ BaseAddress and Length.=0D
+=0D
+ The valid Attributes is EFI_MEMORY_RP, EFI_MEMORY_XP, and EFI_MEMORY_RO.=
=0D
+=0D
+ @param This The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.=0D
+ @param BaseAddress The physical address that is the start address=
of=0D
+ a memory region.=0D
+ @param Length The size in bytes of the memory region.=0D
+ @param Attributes The bit mask of attributes to clear for the me=
mory=0D
+ region.=0D
+=0D
+ @retval EFI_SUCCESS The attributes were cleared for the memory=
region.=0D
+ @retval EFI_INVALID_PARAMETER Length is zero.=0D
+ Attributes specified an illegal combinatio=
n of=0D
+ attributes that cannot be cleared together=
.=0D
+ @retval EFI_UNSUPPORTED The processor does not support one or more=
=0D
+ bytes of the memory resource range specifi=
ed=0D
+ by BaseAddress and Length.=0D
+ The bit mask of attributes is not supporte=
d for=0D
+ the memory resource range specified by=0D
+ BaseAddress and Length.=0D
+ @retval EFI_OUT_OF_RESOURCES Requested attributes cannot be applied due=
to=0D
+ lack of system resources.=0D
+ @retval EFI_ACCESS_DENIED Attributes for the requested memory region=
are=0D
+ controlled by system firmware and cannot b=
e=0D
+ updated via the protocol.=0D
+=0D
+**/=0D
+STATIC=0D
+EFI_STATUS=0D
+ClearMemoryAttributes (=0D
+ IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,=0D
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,=0D
+ IN UINT64 Length,=0D
+ IN UINT64 Attributes=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+=0D
+ DEBUG ((DEBUG_INFO,=0D
+ "%a: BaseAddress =3D=3D 0x%lx, Length =3D=3D 0x%lx, Attributes =
=3D=3D 0x%lx\n",=0D
+ __FUNCTION__,=0D
+ (UINTN)BaseAddress,=0D
+ (UINTN)Length,=0D
+ (UINTN)Attributes=0D
+ ));=0D
+=0D
+ if ((Length =3D=3D 0) ||=0D
+ ((Attributes & ~(EFI_MEMORY_RO | EFI_MEMORY_RP | EFI_MEMORY_XP)) !=
=3D 0)) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ if ((Attributes & EFI_MEMORY_RO) !=3D 0) {=0D
+ Status =3D ArmClearMemoryRegionReadOnly (BaseAddress, Length);=0D
+ if (EFI_ERROR (Status)) {=0D
+ return EFI_UNSUPPORTED;=0D
+ }=0D
+ }=0D
+=0D
+ if ((Attributes & EFI_MEMORY_XP) !=3D 0) {=0D
+ Status =3D ArmClearMemoryRegionNoExec (BaseAddress, Length);=0D
+ if (EFI_ERROR (Status)) {=0D
+ return EFI_UNSUPPORTED;=0D
+ }=0D
+ }=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+EFI_MEMORY_ATTRIBUTE_PROTOCOL mMemoryAttribute =3D {=0D
+ GetMemoryAttributes,=0D
+ SetMemoryAttributes,=0D
+ ClearMemoryAttributes=0D
+};=0D
--=20
2.39.0