mirror of https://github.com/acidanthera/audk.git
ArmPkg/CpuDxe: Implement EFI memory attributes protocol
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@kernel.org> Reviewed-by: Leif Lindholm <quic_llindhol@quicinc.com>
This commit is contained in:
parent
b977956a6c
commit
1c4dfadb46
|
@ -244,6 +244,8 @@ CpuDxeInitialize (
|
||||||
&mCpuHandle,
|
&mCpuHandle,
|
||||||
&gEfiCpuArchProtocolGuid,
|
&gEfiCpuArchProtocolGuid,
|
||||||
&mCpu,
|
&mCpu,
|
||||||
|
&gEfiMemoryAttributeProtocolGuid,
|
||||||
|
&mMemoryAttribute,
|
||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -30,9 +30,12 @@
|
||||||
#include <Protocol/Cpu.h>
|
#include <Protocol/Cpu.h>
|
||||||
#include <Protocol/DebugSupport.h>
|
#include <Protocol/DebugSupport.h>
|
||||||
#include <Protocol/LoadedImage.h>
|
#include <Protocol/LoadedImage.h>
|
||||||
|
#include <Protocol/MemoryAttribute.h>
|
||||||
|
|
||||||
extern BOOLEAN mIsFlushingGCD;
|
extern BOOLEAN mIsFlushingGCD;
|
||||||
|
|
||||||
|
extern EFI_MEMORY_ATTRIBUTE_PROTOCOL mMemoryAttribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This function registers and enables the handler specified by InterruptHandler for a processor
|
This function registers and enables the handler specified by InterruptHandler for a processor
|
||||||
interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
|
interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
CpuDxe.h
|
CpuDxe.h
|
||||||
CpuMmuCommon.c
|
CpuMmuCommon.c
|
||||||
Exception.c
|
Exception.c
|
||||||
|
MemoryAttribute.c
|
||||||
|
|
||||||
[Sources.ARM]
|
[Sources.ARM]
|
||||||
Arm/Mmu.c
|
Arm/Mmu.c
|
||||||
|
@ -53,6 +54,7 @@
|
||||||
|
|
||||||
[Protocols]
|
[Protocols]
|
||||||
gEfiCpuArchProtocolGuid
|
gEfiCpuArchProtocolGuid
|
||||||
|
gEfiMemoryAttributeProtocolGuid
|
||||||
|
|
||||||
[Guids]
|
[Guids]
|
||||||
gEfiDebugImageInfoTableGuid
|
gEfiDebugImageInfoTableGuid
|
||||||
|
|
|
@ -0,0 +1,319 @@
|
||||||
|
/** @file
|
||||||
|
|
||||||
|
Copyright (c) 2023, Google LLC. All rights reserved.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "CpuDxe.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check whether the provided memory range is covered by a single entry of type
|
||||||
|
EfiGcdSystemMemory in the GCD memory map.
|
||||||
|
|
||||||
|
@param BaseAddress The physical address that is the start address of
|
||||||
|
a memory region.
|
||||||
|
@param Length The size in bytes of the memory region.
|
||||||
|
|
||||||
|
@return Whether the region is system memory or not.
|
||||||
|
**/
|
||||||
|
STATIC
|
||||||
|
BOOLEAN
|
||||||
|
RegionIsSystemMemory (
|
||||||
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||||
|
IN UINT64 Length
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
|
||||||
|
EFI_PHYSICAL_ADDRESS GcdEndAddress;
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
|
||||||
|
if (EFI_ERROR (Status) ||
|
||||||
|
(GcdDescriptor.GcdMemoryType != EfiGcdMemoryTypeSystemMemory))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GcdEndAddress = GcdDescriptor.BaseAddress + GcdDescriptor.Length;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return TRUE if the GCD descriptor covers the range entirely
|
||||||
|
//
|
||||||
|
return GcdEndAddress >= (BaseAddress + Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function retrieves the attributes of the memory region specified by
|
||||||
|
BaseAddress and Length. If different attributes are obtained from different
|
||||||
|
parts 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.
|
||||||
|
|
||||||
|
**/
|
||||||
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
|
GetMemoryAttributes (
|
||||||
|
IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||||
|
IN UINT64 Length,
|
||||||
|
OUT UINT64 *Attributes
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINTN RegionAddress;
|
||||||
|
UINTN RegionLength;
|
||||||
|
UINTN RegionAttributes;
|
||||||
|
UINTN Union;
|
||||||
|
UINTN Intersection;
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
if ((Length == 0) || (Attributes == NULL)) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RegionIsSystemMemory (BaseAddress, Length)) {
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG ((
|
||||||
|
DEBUG_VERBOSE,
|
||||||
|
"%a: BaseAddress == 0x%lx, Length == 0x%lx\n",
|
||||||
|
__FUNCTION__,
|
||||||
|
BaseAddress,
|
||||||
|
Length
|
||||||
|
));
|
||||||
|
|
||||||
|
Union = 0;
|
||||||
|
Intersection = MAX_UINTN;
|
||||||
|
|
||||||
|
for (RegionAddress = (UINTN)BaseAddress;
|
||||||
|
RegionAddress < (UINTN)(BaseAddress + Length);
|
||||||
|
RegionAddress += RegionLength)
|
||||||
|
{
|
||||||
|
Status = GetMemoryRegion (
|
||||||
|
&RegionAddress,
|
||||||
|
&RegionLength,
|
||||||
|
&RegionAttributes
|
||||||
|
);
|
||||||
|
|
||||||
|
DEBUG ((
|
||||||
|
DEBUG_VERBOSE,
|
||||||
|
"%a: RegionAddress == 0x%lx, RegionLength == 0x%lx, RegionAttributes == 0x%lx\n",
|
||||||
|
__FUNCTION__,
|
||||||
|
(UINT64)RegionAddress,
|
||||||
|
(UINT64)RegionLength,
|
||||||
|
(UINT64)RegionAttributes
|
||||||
|
));
|
||||||
|
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return EFI_NO_MAPPING;
|
||||||
|
}
|
||||||
|
|
||||||
|
Union |= RegionAttributes;
|
||||||
|
Intersection &= RegionAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG ((
|
||||||
|
DEBUG_VERBOSE,
|
||||||
|
"%a: Union == %lx, Intersection == %lx\n",
|
||||||
|
__FUNCTION__,
|
||||||
|
(UINT64)Union,
|
||||||
|
(UINT64)Intersection
|
||||||
|
));
|
||||||
|
|
||||||
|
if (Union != Intersection) {
|
||||||
|
return EFI_NO_MAPPING;
|
||||||
|
}
|
||||||
|
|
||||||
|
*Attributes = RegionAttributeToGcdAttribute (Union);
|
||||||
|
*Attributes &= EFI_MEMORY_RP | EFI_MEMORY_RO | EFI_MEMORY_XP;
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
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.
|
||||||
|
|
||||||
|
**/
|
||||||
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
|
SetMemoryAttributes (
|
||||||
|
IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||||
|
IN UINT64 Length,
|
||||||
|
IN UINT64 Attributes
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
DEBUG ((
|
||||||
|
DEBUG_INFO,
|
||||||
|
"%a: BaseAddress == 0x%lx, Length == 0x%lx, Attributes == 0x%lx\n",
|
||||||
|
__FUNCTION__,
|
||||||
|
(UINTN)BaseAddress,
|
||||||
|
(UINTN)Length,
|
||||||
|
(UINTN)Attributes
|
||||||
|
));
|
||||||
|
|
||||||
|
if ((Length == 0) ||
|
||||||
|
((Attributes & ~(EFI_MEMORY_RO | EFI_MEMORY_RP | EFI_MEMORY_XP)) != 0))
|
||||||
|
{
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RegionIsSystemMemory (BaseAddress, Length)) {
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Attributes & EFI_MEMORY_RP) != 0) {
|
||||||
|
Status = ArmSetMemoryRegionNoAccess (BaseAddress, Length);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Attributes & EFI_MEMORY_RO) != 0) {
|
||||||
|
Status = ArmSetMemoryRegionReadOnly (BaseAddress, Length);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Attributes & EFI_MEMORY_XP) != 0) {
|
||||||
|
Status = ArmSetMemoryRegionNoExec (BaseAddress, Length);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
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.
|
||||||
|
|
||||||
|
**/
|
||||||
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
|
ClearMemoryAttributes (
|
||||||
|
IN EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||||
|
IN UINT64 Length,
|
||||||
|
IN UINT64 Attributes
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
DEBUG ((
|
||||||
|
DEBUG_INFO,
|
||||||
|
"%a: BaseAddress == 0x%lx, Length == 0x%lx, Attributes == 0x%lx\n",
|
||||||
|
__FUNCTION__,
|
||||||
|
(UINTN)BaseAddress,
|
||||||
|
(UINTN)Length,
|
||||||
|
(UINTN)Attributes
|
||||||
|
));
|
||||||
|
|
||||||
|
if ((Length == 0) ||
|
||||||
|
((Attributes & ~(EFI_MEMORY_RO | EFI_MEMORY_RP | EFI_MEMORY_XP)) != 0))
|
||||||
|
{
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RegionIsSystemMemory (BaseAddress, Length)) {
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Attributes & EFI_MEMORY_RP) != 0) {
|
||||||
|
Status = ArmClearMemoryRegionNoAccess (BaseAddress, Length);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Attributes & EFI_MEMORY_RO) != 0) {
|
||||||
|
Status = ArmClearMemoryRegionReadOnly (BaseAddress, Length);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Attributes & EFI_MEMORY_XP) != 0) {
|
||||||
|
Status = ArmClearMemoryRegionNoExec (BaseAddress, Length);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_MEMORY_ATTRIBUTE_PROTOCOL mMemoryAttribute = {
|
||||||
|
GetMemoryAttributes,
|
||||||
|
SetMemoryAttributes,
|
||||||
|
ClearMemoryAttributes
|
||||||
|
};
|
Loading…
Reference in New Issue