audk/ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStandaloneMmLib.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

461 lines
13 KiB
C
Raw Normal View History

/** @file
File managing the MMU for ARMv8 architecture in S-EL0
Copyright (c) 2017 - 2024, Arm Limited. All rights reserved.<BR>
Copyright (c) 2021, Linaro Limited
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- [1] SPM based on the MM interface.
(https://trustedfirmware-a.readthedocs.io/en/latest/components/
secure-partition-manager-mm.html)
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
- [2] Arm Firmware Framework for Armv8-A, DEN0077, version 1.2
(https://developer.arm.com/documentation/den0077/latest/)
- [3] FF-A Memory Management Protocol, DEN0140, version 1.2
(https://developer.arm.com/documentation/den0140/latest/)
**/
#include <Uefi.h>
#include <IndustryStandard/ArmMmSvc.h>
#include <IndustryStandard/ArmFfaSvc.h>
#include <Library/ArmLib.h>
#include <Library/ArmMmuLib.h>
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
#include <Library/ArmFfaLib.h>
#include <Library/ArmSvcLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
/**
Utility function to determine whether ABIs in FF-A to set and get
memory permissions can be used. Ideally, this should be invoked once in the
library constructor and set a flag that can be used at runtime. However, the
StMM Core invokes this library before constructors are called and before the
StMM image itself is relocated.
@retval TRUE Use FF-A MemPerm ABIs.
@retval FALSE Use MM MemPerm ABIs.
**/
STATIC
BOOLEAN
EFIAPI
IsFfaMemoryAbiSupported (
IN VOID
)
{
EFI_STATUS Status;
UINT16 CurrentMajorVersion;
UINT16 CurrentMinorVersion;
Status = ArmFfaLibGetVersion (
ARM_FFA_MAJOR_VERSION,
ARM_FFA_MINOR_VERSION,
&CurrentMajorVersion,
&CurrentMinorVersion
);
if (EFI_ERROR (Status)) {
return FALSE;
}
return TRUE;
}
/**
Convert FFA return code to EFI_STATUS.
@param [in] SpmMmStatus SPM_MM return code
@retval EFI_STATUS correspond EFI_STATUS to SpmMmStatus
**/
STATIC
EFI_STATUS
SpmMmStatusToEfiStatus (
IN UINTN SpmMmStatus
)
{
switch (SpmMmStatus) {
case ARM_SPM_MM_RET_SUCCESS:
return EFI_SUCCESS;
case ARM_SPM_MM_RET_INVALID_PARAMS:
return EFI_INVALID_PARAMETER;
case ARM_SPM_MM_RET_DENIED:
return EFI_ACCESS_DENIED;
case ARM_SPM_MM_RET_NO_MEMORY:
return EFI_OUT_OF_RESOURCES;
default:
return EFI_UNSUPPORTED;
}
}
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
/** Send a request the target to get/set the memory permission.
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
@param [in] UseFfaAbis Use FF-A abis or not.
@param [in, out] SvcArgs Pointer to SVC arguments to send. On
return it contains the response parameters.
@param [out] RetVal Pointer to return the response value.
@retval EFI_SUCCESS Request successfull.
@retval EFI_INVALID_PARAMETER A parameter is invalid.
@retval EFI_NOT_READY Callee is busy or not in a state to handle
this request.
@retval EFI_UNSUPPORTED This function is not implemented by the
callee.
@retval EFI_ABORTED Message target ran into an unexpected error
and has aborted.
@retval EFI_ACCESS_DENIED Access denied.
@retval EFI_OUT_OF_RESOURCES Out of memory to perform operation.
**/
STATIC
EFI_STATUS
SendMemoryPermissionRequest (
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
IN BOOLEAN UseFfaAbis,
IN OUT ARM_SVC_ARGS *SvcArgs,
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
OUT INT32 *RetVal
)
{
if ((SvcArgs == NULL) || (RetVal == NULL)) {
return EFI_INVALID_PARAMETER;
}
ArmCallSvc (SvcArgs);
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
if (UseFfaAbis) {
if (IS_FID_FFA_ERROR (SvcArgs->Arg0)) {
return FfaStatusToEfiStatus (SvcArgs->Arg2);
}
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
*RetVal = SvcArgs->Arg2;
} else {
// Check error response from Callee.
// Bit 31 set means there is an error returned
// See [1], Section 13.5.5.1 MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 and
// Section 13.5.5.2 MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64.
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
if ((SvcArgs->Arg0 & BIT31) != 0) {
return SpmMmStatusToEfiStatus (SvcArgs->Arg0);
}
*RetVal = SvcArgs->Arg0;
}
return EFI_SUCCESS;
}
/** Request the permission attributes of a memory region from S-EL0.
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
@param [in] UseFfaAbis Use FF-A abis or not.
@param [in] BaseAddress Base address for the memory region.
@param [out] MemoryAttributes Pointer to return the memory attributes.
@retval EFI_SUCCESS Request successfull.
@retval EFI_INVALID_PARAMETER A parameter is invalid.
@retval EFI_NOT_READY Callee is busy or not in a state to handle
this request.
@retval EFI_UNSUPPORTED This function is not implemented by the
callee.
@retval EFI_ABORTED Message target ran into an unexpected error
and has aborted.
@retval EFI_ACCESS_DENIED Access denied.
@retval EFI_OUT_OF_RESOURCES Out of memory to perform operation.
**/
STATIC
EFI_STATUS
GetMemoryPermissions (
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
IN BOOLEAN UseFfaAbis,
IN EFI_PHYSICAL_ADDRESS BaseAddress,
OUT UINT32 *MemoryAttributes
)
{
EFI_STATUS Status;
INT32 Ret;
ARM_SVC_ARGS SvcArgs;
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
UINTN Fid;
if (MemoryAttributes == NULL) {
return EFI_INVALID_PARAMETER;
}
// Prepare the message parameters.
// See [1], Section 13.5.5.1 MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64.
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
// See [3], Section 2.8 FFA_MEM_PERM_GET
Fid = (UseFfaAbis) ? ARM_FID_FFA_MEM_PERM_GET : ARM_FID_SPM_MM_SP_GET_MEM_ATTRIBUTES;
ZeroMem (&SvcArgs, sizeof (ARM_SVC_ARGS));
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
SvcArgs.Arg0 = Fid;
SvcArgs.Arg1 = BaseAddress;
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
Status = SendMemoryPermissionRequest (UseFfaAbis, &SvcArgs, &Ret);
if (EFI_ERROR (Status)) {
*MemoryAttributes = 0;
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
} else {
*MemoryAttributes = Ret;
}
return Status;
}
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
/** Request the permission attributes of the S-EL0 memory region to be updated.
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
@param [in] UseFfaAbis Use FF-A abis or not.
@param [in] BaseAddress Base address for the memory region.
@param [in] Length Length of the memory region.
@param [in] Permissions Memory access controls attributes.
@retval EFI_SUCCESS Request successfull.
@retval EFI_INVALID_PARAMETER A parameter is invalid.
@retval EFI_NOT_READY Callee is busy or not in a state to handle
this request.
@retval EFI_UNSUPPORTED This function is not implemented by the
callee.
@retval EFI_ABORTED Message target ran into an unexpected error
and has aborted.
@retval EFI_ACCESS_DENIED Access denied.
@retval EFI_OUT_OF_RESOURCES Out of memory to perform operation.
**/
STATIC
EFI_STATUS
RequestMemoryPermissionChange (
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
IN BOOLEAN UseFfaAbis,
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length,
IN UINT32 Permissions
)
{
INT32 Ret;
ARM_SVC_ARGS SvcArgs;
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
UINTN Fid;
// Prepare the message parameters.
// See [1], Section 13.5.5.2 MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64.
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
// See [3], Section 2.9 FFA_MEM_PERM_SET
Fid = (UseFfaAbis) ? ARM_FID_FFA_MEM_PERM_SET : ARM_FID_SPM_MM_SP_SET_MEM_ATTRIBUTES;
ZeroMem (&SvcArgs, sizeof (ARM_SVC_ARGS));
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
SvcArgs.Arg0 = Fid;
SvcArgs.Arg1 = BaseAddress;
SvcArgs.Arg2 = EFI_SIZE_TO_PAGES (Length);
SvcArgs.Arg3 = Permissions;
return SendMemoryPermissionRequest (UseFfaAbis, &SvcArgs, &Ret);
}
EFI_STATUS
ArmSetMemoryRegionNoExec (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length
)
{
EFI_STATUS Status;
UINT32 MemoryAttributes;
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
UINT32 PermissionRequest;
BOOLEAN UseFfaAbis;
UINTN Size;
UseFfaAbis = IsFfaMemoryAbiSupported ();
Size = EFI_PAGE_SIZE;
while (Length > 0) {
Status = GetMemoryPermissions (UseFfaAbis, BaseAddress, &MemoryAttributes);
if (EFI_ERROR (Status)) {
break;
}
if (UseFfaAbis) {
PermissionRequest = ARM_FFA_SET_MEM_ATTR_MAKE_PERM_REQUEST (
MemoryAttributes,
ARM_FFA_SET_MEM_ATTR_CODE_PERM_XN
);
} else {
PermissionRequest = ARM_SPM_MM_SET_MEM_ATTR_MAKE_PERM_REQUEST (
MemoryAttributes,
ARM_SPM_MM_SET_MEM_ATTR_CODE_PERM_XN
);
}
if (Length < Size) {
Length = Size;
}
Status = RequestMemoryPermissionChange (
UseFfaAbis,
BaseAddress,
Size,
PermissionRequest
);
if (EFI_ERROR (Status)) {
return Status;
}
Length -= Size;
BaseAddress += Size;
} // while
return Status;
}
EFI_STATUS
ArmClearMemoryRegionNoExec (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length
)
{
EFI_STATUS Status;
UINT32 MemoryAttributes;
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
UINT32 PermissionRequest;
BOOLEAN UseFfaAbis;
UINTN Size;
UseFfaAbis = IsFfaMemoryAbiSupported ();
Size = EFI_PAGE_SIZE;
while (Length > 0) {
Status = GetMemoryPermissions (UseFfaAbis, BaseAddress, &MemoryAttributes);
if (EFI_ERROR (Status)) {
break;
}
if (UseFfaAbis) {
PermissionRequest = ARM_FFA_SET_MEM_ATTR_MAKE_PERM_REQUEST (
MemoryAttributes,
ARM_FFA_SET_MEM_ATTR_CODE_PERM_X
);
} else {
PermissionRequest = ARM_SPM_MM_SET_MEM_ATTR_MAKE_PERM_REQUEST (
MemoryAttributes,
ARM_SPM_MM_SET_MEM_ATTR_CODE_PERM_X
);
}
if (Length < Size) {
Length = Size;
}
Status = RequestMemoryPermissionChange (
UseFfaAbis,
BaseAddress,
Size,
PermissionRequest
);
if (EFI_ERROR (Status)) {
return Status;
}
Length -= Size;
BaseAddress += Size;
} // while
return Status;
}
EFI_STATUS
ArmSetMemoryRegionReadOnly (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length
)
{
EFI_STATUS Status;
UINT32 MemoryAttributes;
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
UINT32 PermissionRequest;
BOOLEAN UseFfaAbis;
UINTN Size;
UseFfaAbis = IsFfaMemoryAbiSupported ();
Size = EFI_PAGE_SIZE;
while (Length > 0) {
Status = GetMemoryPermissions (UseFfaAbis, BaseAddress, &MemoryAttributes);
if (EFI_ERROR (Status)) {
break;
}
if (UseFfaAbis) {
PermissionRequest = ARM_FFA_SET_MEM_ATTR_MAKE_PERM_REQUEST (
ARM_FFA_SET_MEM_ATTR_DATA_PERM_RO,
(MemoryAttributes >> ARM_FFA_SET_MEM_ATTR_CODE_PERM_SHIFT)
);
} else {
PermissionRequest = ARM_SPM_MM_SET_MEM_ATTR_MAKE_PERM_REQUEST (
ARM_SPM_MM_SET_MEM_ATTR_DATA_PERM_RO,
(MemoryAttributes >> ARM_SPM_MM_SET_MEM_ATTR_CODE_PERM_SHIFT)
);
}
if (Length < Size) {
Length = Size;
}
Status = RequestMemoryPermissionChange (
UseFfaAbis,
BaseAddress,
Size,
PermissionRequest
);
if (EFI_ERROR (Status)) {
return Status;
}
Length -= Size;
BaseAddress += Size;
} // while
return Status;
}
EFI_STATUS
ArmClearMemoryRegionReadOnly (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length
)
{
EFI_STATUS Status;
UINT32 MemoryAttributes;
UINT32 PermissionRequest;
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
BOOLEAN UseFfaAbis;
UINTN Size;
ArmPkg/Library: Update StandaloneMmuLib with FF-A v1.2 with page granulirty The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue with update the library with FF-A v1.2, get/set memory permission per page unit. Links: https://developer.arm.com/documentation/den0140/latest/ [0] Signed-off-by: Levi Yun <yeoreum.yun@arm.com>
2024-08-20 17:54:40 +02:00
UseFfaAbis = IsFfaMemoryAbiSupported ();
Size = EFI_PAGE_SIZE;
while (Length > 0) {
Status = GetMemoryPermissions (UseFfaAbis, BaseAddress, &MemoryAttributes);
if (EFI_ERROR (Status)) {
break;
}
if (UseFfaAbis) {
PermissionRequest = ARM_FFA_SET_MEM_ATTR_MAKE_PERM_REQUEST (
ARM_FFA_SET_MEM_ATTR_DATA_PERM_RW,
(MemoryAttributes >> ARM_FFA_SET_MEM_ATTR_CODE_PERM_SHIFT)
);
} else {
PermissionRequest = ARM_SPM_MM_SET_MEM_ATTR_MAKE_PERM_REQUEST (
ARM_SPM_MM_SET_MEM_ATTR_DATA_PERM_RW,
(MemoryAttributes >> ARM_SPM_MM_SET_MEM_ATTR_CODE_PERM_SHIFT)
);
}
if (Length < Size) {
Length = Size;
}
Status = RequestMemoryPermissionChange (
UseFfaAbis,
BaseAddress,
Size,
PermissionRequest
);
if (EFI_ERROR (Status)) {
return Status;
}
Length -= Size;
BaseAddress += Size;
} // while
return Status;
}