]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/StandaloneMmMmuLib/AArch64/ArmMmuStandaloneMmLib.c
dd014beec8739b5b7ea06cee89df79b4467cca15
[mirror_edk2.git] / ArmPkg / Library / StandaloneMmMmuLib / AArch64 / ArmMmuStandaloneMmLib.c
1 /** @file
2 File managing the MMU for ARMv8 architecture in S-EL0
3
4 Copyright (c) 2017 - 2021, Arm Limited. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 @par Reference(s):
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)
13 **/
14
15 #include <Uefi.h>
16 #include <IndustryStandard/ArmMmSvc.h>
17 #include <IndustryStandard/ArmFfaSvc.h>
18
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>
26
27 /** Send memory permission request to target.
28
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.
32
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
36 this request.
37 @retval EFI_UNSUPPORTED This function is not implemented by the
38 callee.
39 @retval EFI_ABORTED Message target ran into an unexpected error
40 and has aborted.
41 @retval EFI_ACCESS_DENIED Access denied.
42 @retval EFI_OUT_OF_RESOURCES Out of memory to perform operation.
43 **/
44 STATIC
45 EFI_STATUS
46 SendMemoryPermissionRequest (
47 IN OUT ARM_SVC_ARGS *SvcArgs,
48 OUT INT32 *RetVal
49 )
50 {
51 if ((SvcArgs == NULL) || (RetVal == NULL)) {
52 return EFI_INVALID_PARAMETER;
53 }
54
55 ArmCallSvc (SvcArgs);
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
64 // callee.
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
69 // in Arg3
70 *RetVal = SvcArgs->Arg3;
71 } else {
72 // If Arg0 is not a Direct Response, that means we
73 // have an FF-A error. We need to check Arg2 for the
74 // FF-A error code.
75 // See [2], Table 10.8: FFA_ERROR encoding.
76 *RetVal = SvcArgs->Arg2;
77 switch (*RetVal) {
78 case ARM_FFA_SPM_RET_INVALID_PARAMETERS:
79 return EFI_INVALID_PARAMETER;
80
81 case ARM_FFA_SPM_RET_DENIED:
82 return EFI_ACCESS_DENIED;
83
84 case ARM_FFA_SPM_RET_NOT_SUPPORTED:
85 return EFI_UNSUPPORTED;
86
87 case ARM_FFA_SPM_RET_BUSY:
88 return EFI_NOT_READY;
89
90 case ARM_FFA_SPM_RET_ABORTED:
91 return EFI_ABORTED;
92
93 default:
94 // Undefined error code received.
95 ASSERT (0);
96 return EFI_INVALID_PARAMETER;
97 }
98 }
99 } else {
100 *RetVal = SvcArgs->Arg0;
101 }
102
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.
108 switch (*RetVal) {
109 case ARM_SVC_SPM_RET_NOT_SUPPORTED:
110 return EFI_UNSUPPORTED;
111
112 case ARM_SVC_SPM_RET_INVALID_PARAMS:
113 return EFI_INVALID_PARAMETER;
114
115 case ARM_SVC_SPM_RET_DENIED:
116 return EFI_ACCESS_DENIED;
117
118 case ARM_SVC_SPM_RET_NO_MEMORY:
119 return EFI_OUT_OF_RESOURCES;
120
121 default:
122 // Undefined error code received.
123 ASSERT (0);
124 return EFI_INVALID_PARAMETER;
125 }
126 }
127
128 return EFI_SUCCESS;
129 }
130
131 /** Request the permission attributes of a memory region from S-EL0.
132
133 @param [in] BaseAddress Base address for the memory region.
134 @param [out] MemoryAttributes Pointer to return the memory attributes.
135
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
139 this request.
140 @retval EFI_UNSUPPORTED This function is not implemented by the
141 callee.
142 @retval EFI_ABORTED Message target ran into an unexpected error
143 and has aborted.
144 @retval EFI_ACCESS_DENIED Access denied.
145 @retval EFI_OUT_OF_RESOURCES Out of memory to perform operation.
146 **/
147 STATIC
148 EFI_STATUS
149 GetMemoryPermissions (
150 IN EFI_PHYSICAL_ADDRESS BaseAddress,
151 OUT UINT32 *MemoryAttributes
152 )
153 {
154 EFI_STATUS Status;
155 INT32 Ret;
156 ARM_SVC_ARGS SvcArgs;
157
158 if (MemoryAttributes == NULL) {
159 return EFI_INVALID_PARAMETER;
160 }
161
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;
169 SvcArgs.Arg2 = 0;
170 SvcArgs.Arg3 = ARM_SVC_ID_SP_GET_MEM_ATTRIBUTES_AARCH64;
171 SvcArgs.Arg4 = BaseAddress;
172 } else {
173 SvcArgs.Arg0 = ARM_SVC_ID_SP_GET_MEM_ATTRIBUTES_AARCH64;
174 SvcArgs.Arg1 = BaseAddress;
175 SvcArgs.Arg2 = 0;
176 SvcArgs.Arg3 = 0;
177 }
178
179 Status = SendMemoryPermissionRequest (&SvcArgs, &Ret);
180 if (EFI_ERROR (Status)) {
181 *MemoryAttributes = 0;
182 return Status;
183 }
184
185 *MemoryAttributes = Ret;
186 return Status;
187 }
188
189 /** Set the permission attributes of a memory region from S-EL0.
190
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.
194
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
198 this request.
199 @retval EFI_UNSUPPORTED This function is not implemented by the
200 callee.
201 @retval EFI_ABORTED Message target ran into an unexpected error
202 and has aborted.
203 @retval EFI_ACCESS_DENIED Access denied.
204 @retval EFI_OUT_OF_RESOURCES Out of memory to perform operation.
205 **/
206 STATIC
207 EFI_STATUS
208 RequestMemoryPermissionChange (
209 IN EFI_PHYSICAL_ADDRESS BaseAddress,
210 IN UINT64 Length,
211 IN UINT32 Permissions
212 )
213 {
214 INT32 Ret;
215 ARM_SVC_ARGS SvcArgs;
216
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;
224 SvcArgs.Arg2 = 0;
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;
229 } else {
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;
234 }
235
236 return SendMemoryPermissionRequest (&SvcArgs, &Ret);
237 }
238
239 EFI_STATUS
240 ArmSetMemoryRegionNoExec (
241 IN EFI_PHYSICAL_ADDRESS BaseAddress,
242 IN UINT64 Length
243 )
244 {
245 EFI_STATUS Status;
246 UINT32 MemoryAttributes;
247 UINT32 CodePermission;
248
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 (
253 BaseAddress,
254 Length,
255 MemoryAttributes | CodePermission
256 );
257 }
258 return Status;
259 }
260
261 EFI_STATUS
262 ArmClearMemoryRegionNoExec (
263 IN EFI_PHYSICAL_ADDRESS BaseAddress,
264 IN UINT64 Length
265 )
266 {
267 EFI_STATUS Status;
268 UINT32 MemoryAttributes;
269 UINT32 CodePermission;
270
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 (
275 BaseAddress,
276 Length,
277 MemoryAttributes & ~CodePermission
278 );
279 }
280 return Status;
281 }
282
283 EFI_STATUS
284 ArmSetMemoryRegionReadOnly (
285 IN EFI_PHYSICAL_ADDRESS BaseAddress,
286 IN UINT64 Length
287 )
288 {
289 EFI_STATUS Status;
290 UINT32 MemoryAttributes;
291 UINT32 DataPermission;
292
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 (
297 BaseAddress,
298 Length,
299 MemoryAttributes | DataPermission
300 );
301 }
302 return Status;
303 }
304
305 EFI_STATUS
306 ArmClearMemoryRegionReadOnly (
307 IN EFI_PHYSICAL_ADDRESS BaseAddress,
308 IN UINT64 Length
309 )
310 {
311 EFI_STATUS Status;
312 UINT32 MemoryAttributes;
313 UINT32 PermissionRequest;
314
315 Status = GetMemoryPermissions (BaseAddress, &MemoryAttributes);
316 if (!EFI_ERROR (Status)) {
317 PermissionRequest = SET_MEM_ATTR_MAKE_PERM_REQUEST (SET_MEM_ATTR_DATA_PERM_RW,
318 MemoryAttributes);
319 return RequestMemoryPermissionChange (
320 BaseAddress,
321 Length,
322 PermissionRequest
323 );
324 }
325 return Status;
326 }