2013-07-18 08:20:33 +02:00
|
|
|
/** @file
|
|
|
|
*
|
|
|
|
* Copyright (c) 2013, ARM Limited. All rights reserved.
|
2017-02-09 08:20:30 +01:00
|
|
|
* Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
|
2013-07-18 08:20:33 +02:00
|
|
|
*
|
2019-04-04 01:03:18 +02:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause-Patent
|
2013-07-18 08:20:33 +02:00
|
|
|
*
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "CpuDxe.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
Searches memory descriptors covered by given memory range.
|
|
|
|
|
|
|
|
This function searches into the Gcd Memory Space for descriptors
|
|
|
|
(from StartIndex to EndIndex) that contains the memory range
|
|
|
|
specified by BaseAddress and Length.
|
|
|
|
|
|
|
|
@param MemorySpaceMap Gcd Memory Space Map as array.
|
|
|
|
@param NumberOfDescriptors Number of descriptors in map.
|
|
|
|
@param BaseAddress BaseAddress for the requested range.
|
|
|
|
@param Length Length for the requested range.
|
|
|
|
@param StartIndex Start index into the Gcd Memory Space Map.
|
|
|
|
@param EndIndex End index into the Gcd Memory Space Map.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Search successfully.
|
|
|
|
@retval EFI_NOT_FOUND The requested descriptors does not exist.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
SearchGcdMemorySpaces (
|
|
|
|
IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
|
|
|
|
IN UINTN NumberOfDescriptors,
|
|
|
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
|
|
|
IN UINT64 Length,
|
|
|
|
OUT UINTN *StartIndex,
|
|
|
|
OUT UINTN *EndIndex
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN Index;
|
|
|
|
|
|
|
|
*StartIndex = 0;
|
|
|
|
*EndIndex = 0;
|
|
|
|
for (Index = 0; Index < NumberOfDescriptors; Index++) {
|
|
|
|
if ((BaseAddress >= MemorySpaceMap[Index].BaseAddress) &&
|
|
|
|
(BaseAddress < (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length)))
|
|
|
|
{
|
|
|
|
*StartIndex = Index;
|
|
|
|
}
|
2021-12-05 23:53:50 +01:00
|
|
|
|
2013-07-18 08:20:33 +02:00
|
|
|
if (((BaseAddress + Length - 1) >= MemorySpaceMap[Index].BaseAddress) &&
|
|
|
|
((BaseAddress + Length - 1) < (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length)))
|
|
|
|
{
|
|
|
|
*EndIndex = Index;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
2021-12-05 23:53:50 +01:00
|
|
|
|
2013-07-18 08:20:33 +02:00
|
|
|
return EFI_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Sets the attributes for a specified range in Gcd Memory Space Map.
|
|
|
|
|
|
|
|
This function sets the attributes for a specified range in
|
|
|
|
Gcd Memory Space Map.
|
|
|
|
|
|
|
|
@param MemorySpaceMap Gcd Memory Space Map as array
|
|
|
|
@param NumberOfDescriptors Number of descriptors in map
|
|
|
|
@param BaseAddress BaseAddress for the range
|
|
|
|
@param Length Length for the range
|
|
|
|
@param Attributes Attributes to set
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Memory attributes set successfully
|
|
|
|
@retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
SetGcdMemorySpaceAttributes (
|
|
|
|
IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
|
|
|
|
IN UINTN NumberOfDescriptors,
|
|
|
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
|
|
|
IN UINT64 Length,
|
|
|
|
IN UINT64 Attributes
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN Index;
|
|
|
|
UINTN StartIndex;
|
|
|
|
UINTN EndIndex;
|
|
|
|
EFI_PHYSICAL_ADDRESS RegionStart;
|
|
|
|
UINT64 RegionLength;
|
|
|
|
|
|
|
|
DEBUG ((
|
|
|
|
DEBUG_GCD,
|
|
|
|
"SetGcdMemorySpaceAttributes[0x%lX; 0x%lX] = 0x%lX\n",
|
|
|
|
BaseAddress,
|
|
|
|
BaseAddress + Length,
|
|
|
|
Attributes
|
|
|
|
));
|
|
|
|
|
2013-08-19 19:33:31 +02:00
|
|
|
// We do not support a smaller granularity than 4KB on ARM Architecture
|
|
|
|
if ((Length & EFI_PAGE_MASK) != 0) {
|
|
|
|
DEBUG ((
|
|
|
|
DEBUG_WARN,
|
|
|
|
"Warning: We do not support smaller granularity than 4KB on ARM Architecture (passed length: 0x%lX).\n",
|
|
|
|
Length
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2013-07-18 08:20:33 +02:00
|
|
|
//
|
|
|
|
// Get all memory descriptors covered by the memory range
|
|
|
|
//
|
|
|
|
Status = SearchGcdMemorySpaces (
|
|
|
|
MemorySpaceMap,
|
|
|
|
NumberOfDescriptors,
|
|
|
|
BaseAddress,
|
|
|
|
Length,
|
|
|
|
&StartIndex,
|
|
|
|
&EndIndex
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Go through all related descriptors and set attributes accordingly
|
|
|
|
//
|
|
|
|
for (Index = StartIndex; Index <= EndIndex; Index++) {
|
|
|
|
if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
|
|
|
|
continue;
|
|
|
|
}
|
2021-12-05 23:53:50 +01:00
|
|
|
|
2013-07-18 08:20:33 +02:00
|
|
|
//
|
|
|
|
// Calculate the start and end address of the overlapping range
|
|
|
|
//
|
|
|
|
if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
|
|
|
|
RegionStart = BaseAddress;
|
|
|
|
} else {
|
|
|
|
RegionStart = MemorySpaceMap[Index].BaseAddress;
|
|
|
|
}
|
2021-12-05 23:53:50 +01:00
|
|
|
|
2013-07-18 08:20:33 +02:00
|
|
|
if ((BaseAddress + Length - 1) < (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length)) {
|
|
|
|
RegionLength = BaseAddress + Length - RegionStart;
|
|
|
|
} else {
|
|
|
|
RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;
|
|
|
|
}
|
2021-12-05 23:53:50 +01:00
|
|
|
|
2013-07-18 08:20:33 +02:00
|
|
|
//
|
|
|
|
// Set memory attributes according to MTRR attribute and the original attribute of descriptor
|
|
|
|
//
|
|
|
|
gDS->SetMemorySpaceAttributes (
|
|
|
|
RegionStart,
|
|
|
|
RegionLength,
|
|
|
|
(MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
This function modifies the attributes for the memory region specified by BaseAddress and
|
|
|
|
Length from their current attributes to the attributes specified by Attributes.
|
|
|
|
|
|
|
|
@param This The EFI_CPU_ARCH_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_ACCESS_DENIED The attributes for the memory resource range specified by
|
|
|
|
BaseAddress and Length cannot be modified.
|
|
|
|
@retval EFI_INVALID_PARAMETER Length is zero.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
|
|
|
|
the memory resource range.
|
|
|
|
@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 support for the memory resource
|
|
|
|
range specified by BaseAddress and Length.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
CpuSetMemoryAttributes (
|
|
|
|
IN EFI_CPU_ARCH_PROTOCOL *This,
|
|
|
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
|
|
|
IN UINT64 Length,
|
2013-08-19 19:38:39 +02:00
|
|
|
IN UINT64 EfiAttributes
|
2013-07-18 08:20:33 +02:00
|
|
|
)
|
|
|
|
{
|
2013-08-19 19:38:39 +02:00
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN ArmAttributes;
|
|
|
|
UINTN RegionBaseAddress;
|
|
|
|
UINTN RegionLength;
|
|
|
|
UINTN RegionArmAttributes;
|
2013-07-18 08:20:33 +02:00
|
|
|
|
2017-02-24 10:58:38 +01:00
|
|
|
if (mIsFlushingGCD) {
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2013-07-18 08:20:33 +02:00
|
|
|
if ((BaseAddress & (SIZE_4KB - 1)) != 0) {
|
|
|
|
// Minimum granularity is SIZE_4KB (4KB on ARM)
|
2019-02-06 16:39:35 +01:00
|
|
|
DEBUG ((DEBUG_PAGE, "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum granularity is SIZE_4KB\n", BaseAddress, Length, EfiAttributes));
|
2013-07-18 08:20:33 +02:00
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2013-08-19 19:38:39 +02:00
|
|
|
// 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);
|
|
|
|
|
|
|
|
// 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)))
|
|
|
|
{
|
ArmPkg/ArmMmuLib: Extend API to manage memory permissions better
Currently, ArmSetMemoryAttributes () takes a combination of
EFI_MEMORY_xx constants describing the memory type and permission
attributes that should be set on a region of memory. In cases where the
memory type is omitted, we assume that the memory permissions being set
are final, and that existing memory permissions can be discarded.
This is problematic, because we aim to map memory non-executable
(EFI_MEMORY_XP) by default, and only relax this requirement for code
regions that are mapped read-only (EFI_MEMORY_RO). Currently, setting
one permission clears the other, and so code managing these permissions
has to be aware of the existing permissions in order to be able to
preserve them, and this is not always tractable (e.g., the UEFI memory
attribute protocol implements an abstraction that promises to preserve
memory permissions that it is not operating on explicitly).
So let's add an AttributeMask parameter to ArmSetMemoryAttributes(),
which is permitted to be non-zero if no memory type is being provided,
in which case only memory permission attributes covered in the mask will
be affected by the update.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Oliver Smith-Denny <osde@linux.microsoft.com>
Reviewed-by: Michael Kubacki <michael.kubacki@microsoft.com>
2023-06-02 17:17:36 +02:00
|
|
|
return ArmSetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0);
|
2013-08-19 19:38:39 +02:00
|
|
|
} else {
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
2013-07-18 08:20:33 +02:00
|
|
|
}
|