2 File managing the MMU for ARMv8 architecture in S-EL0
4 Copyright (c) 2017 - 2021, Arm Limited. All rights reserved.<BR>
5 Copyright (c) 2021, Linaro Limited
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 - [1] SPM based on the MM interface.
10 (https://trustedfirmware-a.readthedocs.io/en/latest/components/
11 secure-partition-manager-mm.html)
12 - [2] Arm Firmware Framework for Armv8-A, DEN0077A, version 1.0
13 (https://developer.arm.com/documentation/den0077/a)
17 #include <IndustryStandard/ArmMmSvc.h>
18 #include <IndustryStandard/ArmFfaSvc.h>
20 #include <Library/ArmLib.h>
21 #include <Library/ArmMmuLib.h>
22 #include <Library/ArmSvcLib.h>
23 #include <Library/BaseLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/DebugLib.h>
26 #include <Library/PcdLib.h>
28 /** Send memory permission request to target.
30 @param [in, out] SvcArgs Pointer to SVC arguments to send. On
31 return it contains the response parameters.
32 @param [out] RetVal Pointer to return the response value.
34 @retval EFI_SUCCESS Request successfull.
35 @retval EFI_INVALID_PARAMETER A parameter is invalid.
36 @retval EFI_NOT_READY Callee is busy or not in a state to handle
38 @retval EFI_UNSUPPORTED This function is not implemented by the
40 @retval EFI_ABORTED Message target ran into an unexpected error
42 @retval EFI_ACCESS_DENIED Access denied.
43 @retval EFI_OUT_OF_RESOURCES Out of memory to perform operation.
47 SendMemoryPermissionRequest (
48 IN OUT ARM_SVC_ARGS
*SvcArgs
,
52 if ((SvcArgs
== NULL
) || (RetVal
== NULL
)) {
53 return EFI_INVALID_PARAMETER
;
57 if (FeaturePcdGet (PcdFfaEnable
)) {
58 // Get/Set memory attributes is an atomic call, with
59 // StandaloneMm at S-EL0 being the caller and the SPM
60 // core being the callee. Thus there won't be a
61 // FFA_INTERRUPT or FFA_SUCCESS response to the Direct
62 // Request sent above. This will have to be considered
63 // for other Direct Request calls which are not atomic
64 // We therefore check only for Direct Response by the
66 if (SvcArgs
->Arg0
== ARM_SVC_ID_FFA_MSG_SEND_DIRECT_RESP
) {
67 // A Direct Response means FF-A success
68 // Now check the payload for errors
69 // The callee sends back the return value
71 *RetVal
= SvcArgs
->Arg3
;
73 // If Arg0 is not a Direct Response, that means we
74 // have an FF-A error. We need to check Arg2 for the
76 // See [2], Table 10.8: FFA_ERROR encoding.
77 *RetVal
= SvcArgs
->Arg2
;
79 case ARM_FFA_SPM_RET_INVALID_PARAMETERS
:
80 return EFI_INVALID_PARAMETER
;
82 case ARM_FFA_SPM_RET_DENIED
:
83 return EFI_ACCESS_DENIED
;
85 case ARM_FFA_SPM_RET_NOT_SUPPORTED
:
86 return EFI_UNSUPPORTED
;
88 case ARM_FFA_SPM_RET_BUSY
:
91 case ARM_FFA_SPM_RET_ABORTED
:
95 // Undefined error code received.
97 return EFI_INVALID_PARAMETER
;
101 *RetVal
= SvcArgs
->Arg0
;
104 // Check error response from Callee.
105 if ((*RetVal
& BIT31
) != 0) {
106 // Bit 31 set means there is an error returned
107 // See [1], Section 13.5.5.1 MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 and
108 // Section 13.5.5.2 MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64.
110 case ARM_SVC_SPM_RET_NOT_SUPPORTED
:
111 return EFI_UNSUPPORTED
;
113 case ARM_SVC_SPM_RET_INVALID_PARAMS
:
114 return EFI_INVALID_PARAMETER
;
116 case ARM_SVC_SPM_RET_DENIED
:
117 return EFI_ACCESS_DENIED
;
119 case ARM_SVC_SPM_RET_NO_MEMORY
:
120 return EFI_OUT_OF_RESOURCES
;
123 // Undefined error code received.
125 return EFI_INVALID_PARAMETER
;
132 /** Request the permission attributes of a memory region from S-EL0.
134 @param [in] BaseAddress Base address for the memory region.
135 @param [out] MemoryAttributes Pointer to return the memory attributes.
137 @retval EFI_SUCCESS Request successfull.
138 @retval EFI_INVALID_PARAMETER A parameter is invalid.
139 @retval EFI_NOT_READY Callee is busy or not in a state to handle
141 @retval EFI_UNSUPPORTED This function is not implemented by the
143 @retval EFI_ABORTED Message target ran into an unexpected error
145 @retval EFI_ACCESS_DENIED Access denied.
146 @retval EFI_OUT_OF_RESOURCES Out of memory to perform operation.
150 GetMemoryPermissions (
151 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
152 OUT UINT32
*MemoryAttributes
157 ARM_SVC_ARGS SvcArgs
;
159 if (MemoryAttributes
== NULL
) {
160 return EFI_INVALID_PARAMETER
;
163 // Prepare the message parameters.
164 // See [1], Section 13.5.5.1 MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64.
165 ZeroMem (&SvcArgs
, sizeof (ARM_SVC_ARGS
));
166 if (FeaturePcdGet (PcdFfaEnable
)) {
167 // See [2], Section 10.2 FFA_MSG_SEND_DIRECT_REQ.
168 SvcArgs
.Arg0
= ARM_SVC_ID_FFA_MSG_SEND_DIRECT_REQ
;
169 SvcArgs
.Arg1
= ARM_FFA_DESTINATION_ENDPOINT_ID
;
171 SvcArgs
.Arg3
= ARM_SVC_ID_SP_GET_MEM_ATTRIBUTES
;
172 SvcArgs
.Arg4
= BaseAddress
;
174 SvcArgs
.Arg0
= ARM_SVC_ID_SP_GET_MEM_ATTRIBUTES
;
175 SvcArgs
.Arg1
= BaseAddress
;
180 Status
= SendMemoryPermissionRequest (&SvcArgs
, &Ret
);
181 if (EFI_ERROR (Status
)) {
182 *MemoryAttributes
= 0;
186 *MemoryAttributes
= Ret
;
190 /** Set the permission attributes of a memory region from S-EL0.
192 @param [in] BaseAddress Base address for the memory region.
193 @param [in] Length Length of the memory region.
194 @param [in] Permissions Memory access controls attributes.
196 @retval EFI_SUCCESS Request successfull.
197 @retval EFI_INVALID_PARAMETER A parameter is invalid.
198 @retval EFI_NOT_READY Callee is busy or not in a state to handle
200 @retval EFI_UNSUPPORTED This function is not implemented by the
202 @retval EFI_ABORTED Message target ran into an unexpected error
204 @retval EFI_ACCESS_DENIED Access denied.
205 @retval EFI_OUT_OF_RESOURCES Out of memory to perform operation.
209 RequestMemoryPermissionChange (
210 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
212 IN UINT32 Permissions
216 ARM_SVC_ARGS SvcArgs
;
218 // Prepare the message parameters.
219 // See [1], Section 13.5.5.2 MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64.
220 ZeroMem (&SvcArgs
, sizeof (ARM_SVC_ARGS
));
221 if (FeaturePcdGet (PcdFfaEnable
)) {
222 // See [2], Section 10.2 FFA_MSG_SEND_DIRECT_REQ.
223 SvcArgs
.Arg0
= ARM_SVC_ID_FFA_MSG_SEND_DIRECT_REQ
;
224 SvcArgs
.Arg1
= ARM_FFA_DESTINATION_ENDPOINT_ID
;
226 SvcArgs
.Arg3
= ARM_SVC_ID_SP_SET_MEM_ATTRIBUTES
;
227 SvcArgs
.Arg4
= BaseAddress
;
228 SvcArgs
.Arg5
= EFI_SIZE_TO_PAGES (Length
);
229 SvcArgs
.Arg6
= Permissions
;
231 SvcArgs
.Arg0
= ARM_SVC_ID_SP_SET_MEM_ATTRIBUTES
;
232 SvcArgs
.Arg1
= BaseAddress
;
233 SvcArgs
.Arg2
= EFI_SIZE_TO_PAGES (Length
);
234 SvcArgs
.Arg3
= Permissions
;
237 return SendMemoryPermissionRequest (&SvcArgs
, &Ret
);
241 ArmSetMemoryRegionNoExec (
242 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
247 UINT32 MemoryAttributes
;
248 UINT32 CodePermission
;
250 Status
= GetMemoryPermissions (BaseAddress
, &MemoryAttributes
);
251 if (!EFI_ERROR (Status
)) {
252 CodePermission
= SET_MEM_ATTR_CODE_PERM_XN
<< SET_MEM_ATTR_CODE_PERM_SHIFT
;
253 return RequestMemoryPermissionChange (
256 MemoryAttributes
| CodePermission
263 ArmClearMemoryRegionNoExec (
264 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
269 UINT32 MemoryAttributes
;
270 UINT32 CodePermission
;
272 Status
= GetMemoryPermissions (BaseAddress
, &MemoryAttributes
);
273 if (!EFI_ERROR (Status
)) {
274 CodePermission
= SET_MEM_ATTR_CODE_PERM_XN
<< SET_MEM_ATTR_CODE_PERM_SHIFT
;
275 return RequestMemoryPermissionChange (
278 MemoryAttributes
& ~CodePermission
285 ArmSetMemoryRegionReadOnly (
286 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
291 UINT32 MemoryAttributes
;
292 UINT32 DataPermission
;
294 Status
= GetMemoryPermissions (BaseAddress
, &MemoryAttributes
);
295 if (!EFI_ERROR (Status
)) {
296 DataPermission
= SET_MEM_ATTR_DATA_PERM_RO
<< SET_MEM_ATTR_DATA_PERM_SHIFT
;
297 return RequestMemoryPermissionChange (
300 MemoryAttributes
| DataPermission
307 ArmClearMemoryRegionReadOnly (
308 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
313 UINT32 MemoryAttributes
;
314 UINT32 PermissionRequest
;
316 Status
= GetMemoryPermissions (BaseAddress
, &MemoryAttributes
);
317 if (!EFI_ERROR (Status
)) {
318 PermissionRequest
= SET_MEM_ATTR_MAKE_PERM_REQUEST (SET_MEM_ATTR_DATA_PERM_RW
,
320 return RequestMemoryPermissionChange (