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