From 4d9a4f62cfc8d04f822edb8f3467ba2de45a16de Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 8 Oct 2015 18:52:16 +0000 Subject: [PATCH] ArmPkg/ArmLib MMU: add functions to set/clear RO and XN bits on regions Use the refactored UpdateRegionMapping () to traverse the translation tables, splitting block entries along the way if required, and apply a mask + or on each to set or clear the PXN/UXN/XN or RO bits. For now, the 32-bit ARM versions remain unimplemented. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18587 6f19259b-4bc3-4df7-8a09-765794883524 --- ArmPkg/Include/Library/ArmLib.h | 24 ++++++ ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c | 90 ++++++++++++++++++++++ ArmPkg/Library/ArmLib/ArmV7/ArmV7Mmu.c | 36 +++++++++ 3 files changed, 150 insertions(+) diff --git a/ArmPkg/Include/Library/ArmLib.h b/ArmPkg/Include/Library/ArmLib.h index c83a5a7f1b..b4768841bd 100644 --- a/ArmPkg/Include/Library/ArmLib.h +++ b/ArmPkg/Include/Library/ArmLib.h @@ -661,4 +661,28 @@ ArmUnsetCpuActlrBit ( IN UINTN Bits ); +RETURN_STATUS +ArmSetMemoryRegionNoExec ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +RETURN_STATUS +ArmClearMemoryRegionNoExec ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +RETURN_STATUS +ArmSetMemoryRegionReadOnly ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +RETURN_STATUS +ArmClearMemoryRegionReadOnly ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + #endif // __ARM_LIB__ diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c b/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c index 60f5cf188d..e40c09ae96 100644 --- a/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c @@ -512,6 +512,96 @@ SetMemoryAttributes ( return RETURN_SUCCESS; } +STATIC +RETURN_STATUS +SetMemoryRegionAttribute ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes, + IN UINT64 BlockEntryMask + ) +{ + RETURN_STATUS Status; + UINT64 *RootTable; + + RootTable = ArmGetTTBR0BaseAddress (); + + Status = UpdateRegionMapping (RootTable, BaseAddress, Length, Attributes, BlockEntryMask); + if (RETURN_ERROR (Status)) { + return Status; + } + + // Invalidate all TLB entries so changes are synced + ArmInvalidateTlb (); + + return RETURN_SUCCESS; +} + +RETURN_STATUS +ArmSetMemoryRegionNoExec ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + UINT64 Val; + + if (ArmReadCurrentEL () == AARCH64_EL1) { + Val = TT_PXN_MASK | TT_UXN_MASK; + } else { + Val = TT_XN_MASK; + } + + return SetMemoryRegionAttribute ( + BaseAddress, + Length, + Val, + ~TT_ADDRESS_MASK_BLOCK_ENTRY); +} + +RETURN_STATUS +ArmClearMemoryRegionNoExec ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + UINT64 Mask; + + // XN maps to UXN in the EL1&0 translation regime + Mask = ~(TT_ADDRESS_MASK_BLOCK_ENTRY | TT_PXN_MASK | TT_XN_MASK); + + return SetMemoryRegionAttribute ( + BaseAddress, + Length, + 0, + Mask); +} + +RETURN_STATUS +ArmSetMemoryRegionReadOnly ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + return SetMemoryRegionAttribute ( + BaseAddress, + Length, + TT_AP_RO_RO, + ~TT_ADDRESS_MASK_BLOCK_ENTRY); +} + +RETURN_STATUS +ArmClearMemoryRegionReadOnly ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + return SetMemoryRegionAttribute ( + BaseAddress, + Length, + TT_AP_NO_RO, + ~(TT_ADDRESS_MASK_BLOCK_ENTRY | TT_AP_MASK)); +} + RETURN_STATUS EFIAPI ArmConfigureMmu ( diff --git a/ArmPkg/Library/ArmLib/ArmV7/ArmV7Mmu.c b/ArmPkg/Library/ArmLib/ArmV7/ArmV7Mmu.c index d035ff3caa..1287dfb1a9 100644 --- a/ArmPkg/Library/ArmLib/ArmV7/ArmV7Mmu.c +++ b/ArmPkg/Library/ArmLib/ArmV7/ArmV7Mmu.c @@ -301,3 +301,39 @@ ArmConfigureMmu ( ArmEnableMmu(); return RETURN_SUCCESS; } + +RETURN_STATUS +ArmSetMemoryRegionNoExec ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + return RETURN_UNSUPPORTED; +} + +RETURN_STATUS +ArmClearMemoryRegionNoExec ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + return RETURN_UNSUPPORTED; +} + +RETURN_STATUS +ArmSetMemoryRegionReadOnly ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + return RETURN_UNSUPPORTED; +} + +RETURN_STATUS +ArmClearMemoryRegionReadOnly ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + return RETURN_UNSUPPORTED; +} -- 2.39.2