diff --git a/ArmPkg/Drivers/CpuPei/CpuPei.c b/ArmPkg/Drivers/CpuPei/CpuPei.c index 1c2b53100f..dd4c162414 100644 --- a/ArmPkg/Drivers/CpuPei/CpuPei.c +++ b/ArmPkg/Drivers/CpuPei/CpuPei.c @@ -95,7 +95,7 @@ SetMemoryPermissions ( return EFI_INVALID_PARAMETER; } - return ArmSetMemoryAttributes (BaseAddress, Length, Attributes, AttributeMask); + return ArmSetMemoryAttributes (BaseAddress, Length, Attributes, AttributeMask, 0); } STATIC CONST EDKII_MEMORY_ATTRIBUTE_PPI mMemoryAttributePpi = { diff --git a/ArmPkg/Include/Library/ArmMmuLib.h b/ArmPkg/Include/Library/ArmMmuLib.h index 49410a8829..b9d1b8b724 100644 --- a/ArmPkg/Include/Library/ArmMmuLib.h +++ b/ArmPkg/Include/Library/ArmMmuLib.h @@ -62,6 +62,7 @@ ArmReplaceLiveTranslationEntry ( @param[in] Length The size in bytes of the memory region. @param[in] Attributes Mask of memory attributes to set. @param[in] AttributeMask Mask of memory attributes to take into account. + @param[in] UserPageTable The base address of the User page table. @retval EFI_SUCCESS The attributes were set for the memory region. @retval EFI_INVALID_PARAMETER BaseAddress or Length is not suitably aligned. @@ -76,7 +77,8 @@ ArmSetMemoryAttributes ( IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, IN UINT64 Attributes, - IN UINT64 AttributeMask + IN UINT64 AttributeMask, + IN UINTN UserPageTable OPTIONAL ); #endif // ARM_MMU_LIB_H_ diff --git a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c index 11a4571dee..4379056ddf 100644 --- a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c +++ b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c @@ -496,6 +496,7 @@ GcdAttributeToPageAttribute ( @param[in] Length The size in bytes of the memory region. @param[in] Attributes Mask of memory attributes to set. @param[in] AttributeMask Mask of memory attributes to take into account. + @param[in] UserPageTable The base address of the User page table. @retval EFI_SUCCESS The attributes were set for the memory region. @retval EFI_INVALID_PARAMETER BaseAddress or Length is not suitably aligned. @@ -510,7 +511,8 @@ ArmSetMemoryAttributes ( IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, IN UINT64 Attributes, - IN UINT64 AttributeMask + IN UINT64 AttributeMask, + IN UINTN UserPageTable OPTIONAL ) { UINT64 PageAttributes; @@ -545,14 +547,25 @@ ArmSetMemoryAttributes ( } } - return UpdateRegionMapping ( - BaseAddress, - Length, - PageAttributes, - PageAttributeMask, - ArmGetTTBR0BaseAddress (), - TRUE - ); + if (UserPageTable == 0) { + return UpdateRegionMapping ( + BaseAddress, + Length, + PageAttributes, + PageAttributeMask, + ArmGetTTBR0BaseAddress (), + TRUE + ); + } else { + return UpdateRegionMapping ( + BaseAddress, + Length, + PageAttributes, + PageAttributeMask, + (UINT64 *)UserPageTable, + FALSE + ); + } } EFI_STATUS diff --git a/ArmPkg/Library/CpuArchLib/AArch64/Mmu.c b/ArmPkg/Library/CpuArchLib/AArch64/Mmu.c index 1805156e38..8c8c73d6bb 100644 --- a/ArmPkg/Library/CpuArchLib/AArch64/Mmu.c +++ b/ArmPkg/Library/CpuArchLib/AArch64/Mmu.c @@ -522,6 +522,7 @@ GetMemoryRegionRec ( updated to the end address of the retrieved region. @param[out] RegionLength The length of the retrieved memory region. @param[out] RegionAttributes The attributes of the retrieved memory region. + @param[in] UserPageTable The base address of the User page table. @retval EFI_STATUS Returns EFI_SUCCESS if the memory region is retrieved successfully, or the status of the @@ -535,7 +536,8 @@ EFI_STATUS GetMemoryRegion ( IN OUT UINTN *BaseAddress, OUT UINTN *RegionLength, - OUT UINTN *RegionAttributes + OUT UINTN *RegionAttributes, + IN UINTN UserPageTable OPTIONAL ) { EFI_STATUS Status; @@ -549,7 +551,12 @@ GetMemoryRegion ( return EFI_INVALID_PARAMETER; } - TranslationTable = ArmGetTTBR0BaseAddress (); + if (UserPageTable == 0) { + TranslationTable = ArmGetTTBR0BaseAddress (); + } else { + TranslationTable = (UINT64 *)UserPageTable; + } + // Initialize the output parameters. These paramaters are only valid if the // result is EFI_SUCCESS. diff --git a/ArmPkg/Library/CpuArchLib/CpuDxe.c b/ArmPkg/Library/CpuArchLib/CpuDxe.c index 44994be396..60ad91eaaf 100644 --- a/ArmPkg/Library/CpuArchLib/CpuDxe.c +++ b/ArmPkg/Library/CpuArchLib/CpuDxe.c @@ -218,7 +218,8 @@ EFI_CPU_ARCH_PROTOCOL mCpu = { CpuSetMemoryAttributes, 0, // NumberOfTimers 2048, // DmaBufferAlignment - CpuGetMemoryAttributes + CpuGetMemoryAttributes, + CpuSetUserMemoryAttributes }; STATIC @@ -293,7 +294,8 @@ RemapUnusedMemoryNx ( MemoryMapEntry->PhysicalStart, EFI_PAGES_TO_SIZE (MemoryMapEntry->NumberOfPages), EFI_MEMORY_XP, - EFI_MEMORY_XP + EFI_MEMORY_XP, + 0 ); } diff --git a/ArmPkg/Library/CpuArchLib/CpuDxe.h b/ArmPkg/Library/CpuArchLib/CpuDxe.h index 85e3a0adc0..af0df99a8c 100644 --- a/ArmPkg/Library/CpuArchLib/CpuDxe.h +++ b/ArmPkg/Library/CpuArchLib/CpuDxe.h @@ -104,6 +104,16 @@ CpuGetMemoryAttributes ( OUT UINT64 *Attributes ); +EFI_STATUS +EFIAPI +CpuSetUserMemoryAttributes ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN UINTN UserPageTable, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 EfiAttributes + ); + EFI_STATUS InitializeExceptions ( IN EFI_CPU_ARCH_PROTOCOL *Cpu @@ -124,7 +134,8 @@ EFI_STATUS GetMemoryRegion ( IN OUT UINTN *BaseAddress, OUT UINTN *RegionLength, - OUT UINTN *RegionAttributes + OUT UINTN *RegionAttributes, + IN UINTN UserPageTable OPTIONAL ); EFI_STATUS diff --git a/ArmPkg/Library/CpuArchLib/CpuMmuCommon.c b/ArmPkg/Library/CpuArchLib/CpuMmuCommon.c index c33c6bb6be..382692d46a 100644 --- a/ArmPkg/Library/CpuArchLib/CpuMmuCommon.c +++ b/ArmPkg/Library/CpuArchLib/CpuMmuCommon.c @@ -210,14 +210,14 @@ CpuSetMemoryAttributes ( // Get the region starting from 'BaseAddress' and its 'Attribute' RegionBaseAddress = BaseAddress; - Status = GetMemoryRegion (&RegionBaseAddress, &RegionLength, &RegionArmAttributes); + Status = GetMemoryRegion (&RegionBaseAddress, &RegionLength, &RegionArmAttributes, 0); // Data & Instruction Caches are flushed when we set new memory attributes. // So, we only set the attributes if the new region is different. if (EFI_ERROR (Status) || (RegionArmAttributes != ArmAttributes) || ((BaseAddress + Length) > (RegionBaseAddress + RegionLength))) { - return ArmSetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0); + return ArmSetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0, 0); } else { return EFI_SUCCESS; } @@ -237,7 +237,7 @@ CpuGetMemoryAttributes ( UINTN RegionArmAttributes; RegionBaseAddress = Address; - Status = GetMemoryRegion (&RegionBaseAddress, &RegionLength, &RegionArmAttributes); + Status = GetMemoryRegion (&RegionBaseAddress, &RegionLength, &RegionArmAttributes, 0); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; @@ -247,3 +247,43 @@ CpuGetMemoryAttributes ( return Status; } + +EFI_STATUS +EFIAPI +CpuSetUserMemoryAttributes ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN UINTN UserPageTable, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 EfiAttributes + ) +{ + EFI_STATUS Status; + UINTN ArmAttributes; + UINTN RegionBaseAddress; + UINTN RegionLength; + UINTN RegionArmAttributes; + + if ((BaseAddress & (SIZE_4KB - 1)) != 0) { + // Minimum granularity is SIZE_4KB (4KB on ARM) + DEBUG ((DEBUG_PAGE, "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum granularity is SIZE_4KB\n", BaseAddress, Length, EfiAttributes)); + return EFI_UNSUPPORTED; + } + + // Convert the 'Attribute' into ARM Attribute + ArmAttributes = EfiAttributeToArmAttribute (EfiAttributes); + + // Get the region starting from 'BaseAddress' and its 'Attribute' + RegionBaseAddress = BaseAddress; + Status = GetMemoryRegion (&RegionBaseAddress, &RegionLength, &RegionArmAttributes, UserPageTable); + + // Data & Instruction Caches are flushed when we set new memory attributes. + // So, we only set the attributes if the new region is different. + if (EFI_ERROR (Status) || (RegionArmAttributes != ArmAttributes) || + ((BaseAddress + Length) > (RegionBaseAddress + RegionLength))) + { + return ArmSetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0, UserPageTable); + } else { + return EFI_SUCCESS; + } +} diff --git a/ArmPkg/Library/CpuArchLib/MemoryAttribute.c b/ArmPkg/Library/CpuArchLib/MemoryAttribute.c index 16cc4ef474..f3455ed73b 100644 --- a/ArmPkg/Library/CpuArchLib/MemoryAttribute.c +++ b/ArmPkg/Library/CpuArchLib/MemoryAttribute.c @@ -107,7 +107,8 @@ GetMemoryAttributes ( Status = GetMemoryRegion ( &RegionAddress, &RegionLength, - &RegionAttributes + &RegionAttributes, + 0 ); DEBUG (( @@ -202,7 +203,7 @@ SetMemoryAttributes ( return EFI_UNSUPPORTED; } - return ArmSetMemoryAttributes (BaseAddress, Length, Attributes, Attributes); + return ArmSetMemoryAttributes (BaseAddress, Length, Attributes, Attributes, 0); } /** @@ -263,7 +264,7 @@ ClearMemoryAttributes ( return EFI_UNSUPPORTED; } - return ArmSetMemoryAttributes (BaseAddress, Length, 0, Attributes); + return ArmSetMemoryAttributes (BaseAddress, Length, 0, Attributes, 0); } EFI_MEMORY_ATTRIBUTE_PROTOCOL mMemoryAttribute = { diff --git a/ArmPkg/Library/OpteeLib/Optee.c b/ArmPkg/Library/OpteeLib/Optee.c index 3acf172b68..24d96a5cc6 100644 --- a/ArmPkg/Library/OpteeLib/Optee.c +++ b/ArmPkg/Library/OpteeLib/Optee.c @@ -90,6 +90,7 @@ OpteeSharedMemoryRemap ( PhysicalAddress, Size, EFI_MEMORY_WB | EFI_MEMORY_XP, + 0, 0 ); if (EFI_ERROR (Status)) {