]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/StandaloneMmMmuLib/AArch64/ArmMmuStandaloneMmLib.c
ArmPkg: Allow FF-A calls to set memory region's attributes
[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 *
6 * SPDX-License-Identifier: BSD-2-Clause-Patent
7 *
8 **/
9
10 #include <Uefi.h>
11 #include <IndustryStandard/ArmMmSvc.h>
12 #include <IndustryStandard/ArmFfaSvc.h>
13
14 #include <Library/ArmLib.h>
15 #include <Library/ArmMmuLib.h>
16 #include <Library/ArmSvcLib.h>
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/PcdLib.h>
21
22 STATIC
23 EFI_STATUS
24 GetMemoryPermissions (
25 IN EFI_PHYSICAL_ADDRESS BaseAddress,
26 OUT UINT32 *MemoryAttributes
27 )
28 {
29 INT32 Ret;
30 ARM_SVC_ARGS GetMemoryPermissionsSvcArgs;
31 BOOLEAN FfaEnabled;
32
33 ZeroMem (&GetMemoryPermissionsSvcArgs, sizeof (ARM_SVC_ARGS));
34
35 FfaEnabled = FeaturePcdGet (PcdFfaEnable);
36 if (FfaEnabled) {
37 GetMemoryPermissionsSvcArgs.Arg0 = ARM_SVC_ID_FFA_MSG_SEND_DIRECT_REQ_AARCH64;
38 GetMemoryPermissionsSvcArgs.Arg1 = ARM_FFA_DESTINATION_ENDPOINT_ID;
39 GetMemoryPermissionsSvcArgs.Arg2 = 0;
40 GetMemoryPermissionsSvcArgs.Arg3 = ARM_SVC_ID_SP_GET_MEM_ATTRIBUTES_AARCH64;
41 GetMemoryPermissionsSvcArgs.Arg4 = BaseAddress;
42 } else {
43 GetMemoryPermissionsSvcArgs.Arg0 = ARM_SVC_ID_SP_GET_MEM_ATTRIBUTES_AARCH64;
44 GetMemoryPermissionsSvcArgs.Arg1 = BaseAddress;
45 GetMemoryPermissionsSvcArgs.Arg2 = 0;
46 GetMemoryPermissionsSvcArgs.Arg3 = 0;
47 }
48
49 *MemoryAttributes = 0;
50 ArmCallSvc (&GetMemoryPermissionsSvcArgs);
51 if (FfaEnabled) {
52 // Getting memory attributes is an atomic call, with
53 // StandaloneMm at S-EL0 being the caller and the SPM
54 // core being the callee. Thus there won't be a
55 // FFA_INTERRUPT or FFA_SUCCESS response to the Direct
56 // Request sent above. This will have to be considered
57 // for other Direct Request calls which are not atomic
58 // We therefore check only for Direct Response by the
59 // callee.
60 if (GetMemoryPermissionsSvcArgs.Arg0 !=
61 ARM_SVC_ID_FFA_MSG_SEND_DIRECT_RESP_AARCH64) {
62 // If Arg0 is not a Direct Response, that means we
63 // have an FF-A error. We need to check Arg2 for the
64 // FF-A error code.
65 Ret = GetMemoryPermissionsSvcArgs.Arg2;
66 switch (Ret) {
67 case ARM_FFA_SPM_RET_INVALID_PARAMETERS:
68
69 return EFI_INVALID_PARAMETER;
70
71 case ARM_FFA_SPM_RET_DENIED:
72 return EFI_NOT_READY;
73
74 case ARM_FFA_SPM_RET_NOT_SUPPORTED:
75 return EFI_UNSUPPORTED;
76
77 case ARM_FFA_SPM_RET_BUSY:
78 return EFI_NOT_READY;
79
80 case ARM_FFA_SPM_RET_ABORTED:
81 return EFI_ABORTED;
82 }
83 } else if (GetMemoryPermissionsSvcArgs.Arg0 ==
84 ARM_SVC_ID_FFA_MSG_SEND_DIRECT_RESP_AARCH64) {
85 // A Direct Response means FF-A success
86 // Now check the payload for errors
87 // The callee sends back the return value
88 // in Arg3
89 Ret = GetMemoryPermissionsSvcArgs.Arg3;
90 }
91 } else {
92 Ret = GetMemoryPermissionsSvcArgs.Arg0;
93 }
94
95 if (Ret & BIT31) {
96 // Bit 31 set means there is an error retured
97 switch (Ret) {
98 case ARM_SVC_SPM_RET_INVALID_PARAMS:
99 return EFI_INVALID_PARAMETER;
100
101 case ARM_SVC_SPM_RET_NOT_SUPPORTED:
102 return EFI_UNSUPPORTED;
103 }
104 } else {
105 *MemoryAttributes = Ret;
106 }
107
108 return EFI_SUCCESS;
109 }
110
111 STATIC
112 EFI_STATUS
113 RequestMemoryPermissionChange (
114 IN EFI_PHYSICAL_ADDRESS BaseAddress,
115 IN UINT64 Length,
116 IN UINTN Permissions
117 )
118 {
119 INT32 Ret;
120 BOOLEAN FfaEnabled;
121 ARM_SVC_ARGS ChangeMemoryPermissionsSvcArgs;
122
123 ZeroMem (&ChangeMemoryPermissionsSvcArgs, sizeof (ARM_SVC_ARGS));
124
125 FfaEnabled = FeaturePcdGet (PcdFfaEnable);
126
127 if (FfaEnabled) {
128 ChangeMemoryPermissionsSvcArgs.Arg0 = ARM_SVC_ID_FFA_MSG_SEND_DIRECT_REQ_AARCH64;
129 ChangeMemoryPermissionsSvcArgs.Arg1 = ARM_FFA_DESTINATION_ENDPOINT_ID;
130 ChangeMemoryPermissionsSvcArgs.Arg2 = 0;
131 ChangeMemoryPermissionsSvcArgs.Arg3 = ARM_SVC_ID_SP_SET_MEM_ATTRIBUTES_AARCH64;
132 ChangeMemoryPermissionsSvcArgs.Arg4 = BaseAddress;
133 ChangeMemoryPermissionsSvcArgs.Arg5 = EFI_SIZE_TO_PAGES (Length);
134 ChangeMemoryPermissionsSvcArgs.Arg6 = Permissions;
135 } else {
136 ChangeMemoryPermissionsSvcArgs.Arg0 = ARM_SVC_ID_SP_SET_MEM_ATTRIBUTES_AARCH64;
137 ChangeMemoryPermissionsSvcArgs.Arg1 = BaseAddress;
138 ChangeMemoryPermissionsSvcArgs.Arg2 = EFI_SIZE_TO_PAGES (Length);
139 ChangeMemoryPermissionsSvcArgs.Arg3 = Permissions;
140 }
141
142 ArmCallSvc (&ChangeMemoryPermissionsSvcArgs);
143
144 if (FfaEnabled) {
145 // Setting memory attributes is an atomic call, with
146 // StandaloneMm at S-EL0 being the caller and the SPM
147 // core being the callee. Thus there won't be a
148 // FFA_INTERRUPT or FFA_SUCCESS response to the Direct
149 // Request sent above. This will have to be considered
150 // for other Direct Request calls which are not atomic
151 // We therefore check only for Direct Response by the
152 // callee.
153 if (ChangeMemoryPermissionsSvcArgs.Arg0 !=
154 ARM_SVC_ID_FFA_MSG_SEND_DIRECT_RESP_AARCH64) {
155 // If Arg0 is not a Direct Response, that means we
156 // have an FF-A error. We need to check Arg2 for the
157 // FF-A error code.
158 Ret = ChangeMemoryPermissionsSvcArgs.Arg2;
159 switch (Ret) {
160 case ARM_FFA_SPM_RET_INVALID_PARAMETERS:
161 return EFI_INVALID_PARAMETER;
162
163 case ARM_FFA_SPM_RET_DENIED:
164 return EFI_NOT_READY;
165
166 case ARM_FFA_SPM_RET_NOT_SUPPORTED:
167 return EFI_UNSUPPORTED;
168
169 case ARM_FFA_SPM_RET_BUSY:
170 return EFI_NOT_READY;
171
172 case ARM_FFA_SPM_RET_ABORTED:
173 return EFI_ABORTED;
174 }
175 } else if (ChangeMemoryPermissionsSvcArgs.Arg0 ==
176 ARM_SVC_ID_FFA_MSG_SEND_DIRECT_RESP_AARCH64) {
177 // A Direct Response means FF-A success
178 // Now check the payload for errors
179 // The callee sends back the return value
180 // in Arg3
181 Ret = ChangeMemoryPermissionsSvcArgs.Arg3;
182 }
183 } else {
184 Ret = ChangeMemoryPermissionsSvcArgs.Arg0;
185 }
186
187 switch (Ret) {
188 case ARM_SVC_SPM_RET_NOT_SUPPORTED:
189 return EFI_UNSUPPORTED;
190
191 case ARM_SVC_SPM_RET_INVALID_PARAMS:
192 return EFI_INVALID_PARAMETER;
193
194 case ARM_SVC_SPM_RET_DENIED:
195 return EFI_ACCESS_DENIED;
196
197 case ARM_SVC_SPM_RET_NO_MEMORY:
198 return EFI_BAD_BUFFER_SIZE;
199 }
200
201 return EFI_SUCCESS;
202 }
203
204 EFI_STATUS
205 ArmSetMemoryRegionNoExec (
206 IN EFI_PHYSICAL_ADDRESS BaseAddress,
207 IN UINT64 Length
208 )
209 {
210 EFI_STATUS Status;
211 UINT32 MemoryAttributes;
212 UINT32 CodePermission;
213
214 Status = GetMemoryPermissions (BaseAddress, &MemoryAttributes);
215 if (Status != EFI_INVALID_PARAMETER) {
216 CodePermission = SET_MEM_ATTR_CODE_PERM_XN << SET_MEM_ATTR_CODE_PERM_SHIFT;
217 return RequestMemoryPermissionChange (
218 BaseAddress,
219 Length,
220 MemoryAttributes | CodePermission
221 );
222 }
223 return EFI_INVALID_PARAMETER;
224 }
225
226 EFI_STATUS
227 ArmClearMemoryRegionNoExec (
228 IN EFI_PHYSICAL_ADDRESS BaseAddress,
229 IN UINT64 Length
230 )
231 {
232 EFI_STATUS Status;
233 UINT32 MemoryAttributes;
234 UINT32 CodePermission;
235
236 Status = GetMemoryPermissions (BaseAddress, &MemoryAttributes);
237 if (Status != EFI_INVALID_PARAMETER) {
238 CodePermission = SET_MEM_ATTR_CODE_PERM_XN << SET_MEM_ATTR_CODE_PERM_SHIFT;
239 return RequestMemoryPermissionChange (
240 BaseAddress,
241 Length,
242 MemoryAttributes & ~CodePermission
243 );
244 }
245 return EFI_INVALID_PARAMETER;
246 }
247
248 EFI_STATUS
249 ArmSetMemoryRegionReadOnly (
250 IN EFI_PHYSICAL_ADDRESS BaseAddress,
251 IN UINT64 Length
252 )
253 {
254 EFI_STATUS Status;
255 UINT32 MemoryAttributes;
256 UINT32 DataPermission;
257
258 Status = GetMemoryPermissions (BaseAddress, &MemoryAttributes);
259 if (Status != EFI_INVALID_PARAMETER) {
260 DataPermission = SET_MEM_ATTR_DATA_PERM_RO << SET_MEM_ATTR_DATA_PERM_SHIFT;
261 return RequestMemoryPermissionChange (
262 BaseAddress,
263 Length,
264 MemoryAttributes | DataPermission
265 );
266 }
267 return EFI_INVALID_PARAMETER;
268 }
269
270 EFI_STATUS
271 ArmClearMemoryRegionReadOnly (
272 IN EFI_PHYSICAL_ADDRESS BaseAddress,
273 IN UINT64 Length
274 )
275 {
276 EFI_STATUS Status;
277 UINT32 MemoryAttributes;
278 UINT32 PermissionRequest;
279
280 Status = GetMemoryPermissions (BaseAddress, &MemoryAttributes);
281 if (Status != EFI_INVALID_PARAMETER) {
282 PermissionRequest = SET_MEM_ATTR_MAKE_PERM_REQUEST (SET_MEM_ATTR_DATA_PERM_RW,
283 MemoryAttributes);
284 return RequestMemoryPermissionChange (
285 BaseAddress,
286 Length,
287 PermissionRequest
288 );
289 }
290 return EFI_INVALID_PARAMETER;
291 }