2 File managing the MMU for ARMv8 architecture in S-EL0
4 Copyright (c) 2017 - 2021, Arm Limited. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
8 - [1] SPM based on the MM interface.
9 (https://trustedfirmware-a.readthedocs.io/en/latest/components/
10 secure-partition-manager-mm.html)
11 - [2] Arm Firmware Framework for Armv8-A, DEN0077A, version 1.0
12 (https://developer.arm.com/documentation/den0077/a)
16 #include <IndustryStandard/ArmMmSvc.h>
17 #include <IndustryStandard/ArmFfaSvc.h>
19 #include <Library/ArmLib.h>
20 #include <Library/ArmMmuLib.h>
21 #include <Library/ArmSvcLib.h>
22 #include <Library/BaseLib.h>
23 #include <Library/BaseMemoryLib.h>
24 #include <Library/DebugLib.h>
25 #include <Library/PcdLib.h>
27 /** Send memory permission request to target.
29 @param [in, out] SvcArgs Pointer to SVC arguments to send. On
30 return it contains the response parameters.
31 @param [out] RetVal Pointer to return the response value.
33 @retval EFI_SUCCESS Request successfull.
34 @retval EFI_INVALID_PARAMETER A parameter is invalid.
35 @retval EFI_NOT_READY Callee is busy or not in a state to handle
37 @retval EFI_UNSUPPORTED This function is not implemented by the
39 @retval EFI_ABORTED Message target ran into an unexpected error
41 @retval EFI_ACCESS_DENIED Access denied.
42 @retval EFI_OUT_OF_RESOURCES Out of memory to perform operation.
46 SendMemoryPermissionRequest (
47 IN OUT ARM_SVC_ARGS
*SvcArgs
,
51 if ((SvcArgs
== NULL
) || (RetVal
== NULL
)) {
52 return EFI_INVALID_PARAMETER
;
56 if (FeaturePcdGet (PcdFfaEnable
)) {
57 // Get/Set memory attributes is an atomic call, with
58 // StandaloneMm at S-EL0 being the caller and the SPM
59 // core being the callee. Thus there won't be a
60 // FFA_INTERRUPT or FFA_SUCCESS response to the Direct
61 // Request sent above. This will have to be considered
62 // for other Direct Request calls which are not atomic
63 // We therefore check only for Direct Response by the
65 if (SvcArgs
->Arg0
== ARM_SVC_ID_FFA_MSG_SEND_DIRECT_RESP_AARCH64
) {
66 // A Direct Response means FF-A success
67 // Now check the payload for errors
68 // The callee sends back the return value
70 *RetVal
= SvcArgs
->Arg3
;
72 // If Arg0 is not a Direct Response, that means we
73 // have an FF-A error. We need to check Arg2 for the
75 // See [2], Table 10.8: FFA_ERROR encoding.
76 *RetVal
= SvcArgs
->Arg2
;
78 case ARM_FFA_SPM_RET_INVALID_PARAMETERS
:
79 return EFI_INVALID_PARAMETER
;
81 case ARM_FFA_SPM_RET_DENIED
:
82 return EFI_ACCESS_DENIED
;
84 case ARM_FFA_SPM_RET_NOT_SUPPORTED
:
85 return EFI_UNSUPPORTED
;
87 case ARM_FFA_SPM_RET_BUSY
:
90 case ARM_FFA_SPM_RET_ABORTED
:
94 // Undefined error code received.
96 return EFI_INVALID_PARAMETER
;
100 *RetVal
= SvcArgs
->Arg0
;
103 // Check error response from Callee.
104 if ((*RetVal
& BIT31
) != 0) {
105 // Bit 31 set means there is an error returned
106 // See [1], Section 13.5.5.1 MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 and
107 // Section 13.5.5.2 MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64.
109 case ARM_SVC_SPM_RET_NOT_SUPPORTED
:
110 return EFI_UNSUPPORTED
;
112 case ARM_SVC_SPM_RET_INVALID_PARAMS
:
113 return EFI_INVALID_PARAMETER
;
115 case ARM_SVC_SPM_RET_DENIED
:
116 return EFI_ACCESS_DENIED
;
118 case ARM_SVC_SPM_RET_NO_MEMORY
:
119 return EFI_OUT_OF_RESOURCES
;
122 // Undefined error code received.
124 return EFI_INVALID_PARAMETER
;
131 /** Request the permission attributes of a memory region from S-EL0.
133 @param [in] BaseAddress Base address for the memory region.
134 @param [out] MemoryAttributes Pointer to return the memory attributes.
136 @retval EFI_SUCCESS Request successfull.
137 @retval EFI_INVALID_PARAMETER A parameter is invalid.
138 @retval EFI_NOT_READY Callee is busy or not in a state to handle
140 @retval EFI_UNSUPPORTED This function is not implemented by the
142 @retval EFI_ABORTED Message target ran into an unexpected error
144 @retval EFI_ACCESS_DENIED Access denied.
145 @retval EFI_OUT_OF_RESOURCES Out of memory to perform operation.
149 GetMemoryPermissions (
150 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
151 OUT UINT32
*MemoryAttributes
156 ARM_SVC_ARGS SvcArgs
;
158 if (MemoryAttributes
== NULL
) {
159 return EFI_INVALID_PARAMETER
;
162 // Prepare the message parameters.
163 // See [1], Section 13.5.5.1 MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64.
164 ZeroMem (&SvcArgs
, sizeof (ARM_SVC_ARGS
));
165 if (FeaturePcdGet (PcdFfaEnable
)) {
166 // See [2], Section 10.2 FFA_MSG_SEND_DIRECT_REQ.
167 SvcArgs
.Arg0
= ARM_SVC_ID_FFA_MSG_SEND_DIRECT_REQ_AARCH64
;
168 SvcArgs
.Arg1
= ARM_FFA_DESTINATION_ENDPOINT_ID
;
170 SvcArgs
.Arg3
= ARM_SVC_ID_SP_GET_MEM_ATTRIBUTES_AARCH64
;
171 SvcArgs
.Arg4
= BaseAddress
;
173 SvcArgs
.Arg0
= ARM_SVC_ID_SP_GET_MEM_ATTRIBUTES_AARCH64
;
174 SvcArgs
.Arg1
= BaseAddress
;
179 Status
= SendMemoryPermissionRequest (&SvcArgs
, &Ret
);
180 if (EFI_ERROR (Status
)) {
181 *MemoryAttributes
= 0;
185 *MemoryAttributes
= Ret
;
189 /** Set the permission attributes of a memory region from S-EL0.
191 @param [in] BaseAddress Base address for the memory region.
192 @param [in] Length Length of the memory region.
193 @param [in] Permissions Memory access controls attributes.
195 @retval EFI_SUCCESS Request successfull.
196 @retval EFI_INVALID_PARAMETER A parameter is invalid.
197 @retval EFI_NOT_READY Callee is busy or not in a state to handle
199 @retval EFI_UNSUPPORTED This function is not implemented by the
201 @retval EFI_ABORTED Message target ran into an unexpected error
203 @retval EFI_ACCESS_DENIED Access denied.
204 @retval EFI_OUT_OF_RESOURCES Out of memory to perform operation.
208 RequestMemoryPermissionChange (
209 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
211 IN UINT32 Permissions
215 ARM_SVC_ARGS SvcArgs
;
217 // Prepare the message parameters.
218 // See [1], Section 13.5.5.2 MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64.
219 ZeroMem (&SvcArgs
, sizeof (ARM_SVC_ARGS
));
220 if (FeaturePcdGet (PcdFfaEnable
)) {
221 // See [2], Section 10.2 FFA_MSG_SEND_DIRECT_REQ.
222 SvcArgs
.Arg0
= ARM_SVC_ID_FFA_MSG_SEND_DIRECT_REQ_AARCH64
;
223 SvcArgs
.Arg1
= ARM_FFA_DESTINATION_ENDPOINT_ID
;
225 SvcArgs
.Arg3
= ARM_SVC_ID_SP_SET_MEM_ATTRIBUTES_AARCH64
;
226 SvcArgs
.Arg4
= BaseAddress
;
227 SvcArgs
.Arg5
= EFI_SIZE_TO_PAGES (Length
);
228 SvcArgs
.Arg6
= Permissions
;
230 SvcArgs
.Arg0
= ARM_SVC_ID_SP_SET_MEM_ATTRIBUTES_AARCH64
;
231 SvcArgs
.Arg1
= BaseAddress
;
232 SvcArgs
.Arg2
= EFI_SIZE_TO_PAGES (Length
);
233 SvcArgs
.Arg3
= Permissions
;
236 return SendMemoryPermissionRequest (&SvcArgs
, &Ret
);
240 ArmSetMemoryRegionNoExec (
241 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
246 UINT32 MemoryAttributes
;
247 UINT32 CodePermission
;
249 Status
= GetMemoryPermissions (BaseAddress
, &MemoryAttributes
);
250 if (!EFI_ERROR (Status
)) {
251 CodePermission
= SET_MEM_ATTR_CODE_PERM_XN
<< SET_MEM_ATTR_CODE_PERM_SHIFT
;
252 return RequestMemoryPermissionChange (
255 MemoryAttributes
| CodePermission
262 ArmClearMemoryRegionNoExec (
263 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
268 UINT32 MemoryAttributes
;
269 UINT32 CodePermission
;
271 Status
= GetMemoryPermissions (BaseAddress
, &MemoryAttributes
);
272 if (!EFI_ERROR (Status
)) {
273 CodePermission
= SET_MEM_ATTR_CODE_PERM_XN
<< SET_MEM_ATTR_CODE_PERM_SHIFT
;
274 return RequestMemoryPermissionChange (
277 MemoryAttributes
& ~CodePermission
284 ArmSetMemoryRegionReadOnly (
285 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
290 UINT32 MemoryAttributes
;
291 UINT32 DataPermission
;
293 Status
= GetMemoryPermissions (BaseAddress
, &MemoryAttributes
);
294 if (!EFI_ERROR (Status
)) {
295 DataPermission
= SET_MEM_ATTR_DATA_PERM_RO
<< SET_MEM_ATTR_DATA_PERM_SHIFT
;
296 return RequestMemoryPermissionChange (
299 MemoryAttributes
| DataPermission
306 ArmClearMemoryRegionReadOnly (
307 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
312 UINT32 MemoryAttributes
;
313 UINT32 PermissionRequest
;
315 Status
= GetMemoryPermissions (BaseAddress
, &MemoryAttributes
);
316 if (!EFI_ERROR (Status
)) {
317 PermissionRequest
= SET_MEM_ATTR_MAKE_PERM_REQUEST (SET_MEM_ATTR_DATA_PERM_RW
,
319 return RequestMemoryPermissionChange (