]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/OpteeLib/Optee.c
ArmPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / ArmPkg / Library / OpteeLib / Optee.c
CommitLineData
d65b78f1
SG
1/** @file\r
2 Api's to communicate with OP-TEE OS (Trusted OS based on ARM TrustZone) via\r
3 secure monitor calls.\r
4\r
5 Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>\r
6\r
4059386c 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
d65b78f1
SG
8\r
9**/\r
10\r
a0f01e8a 11#include <Library/ArmMmuLib.h>\r
d65b78f1 12#include <Library/ArmSmcLib.h>\r
a0f01e8a 13#include <Library/BaseMemoryLib.h>\r
d65b78f1 14#include <Library/BaseLib.h>\r
a0f01e8a 15#include <Library/DebugLib.h>\r
d65b78f1
SG
16#include <Library/OpteeLib.h>\r
17\r
18#include <IndustryStandard/ArmStdSmc.h>\r
a0f01e8a
SG
19#include <OpteeSmc.h>\r
20#include <Uefi.h>\r
21\r
22STATIC OPTEE_SHARED_MEMORY_INFORMATION OpteeSharedMemoryInformation = { 0 };\r
d65b78f1
SG
23\r
24/**\r
25 Check for OP-TEE presence.\r
26**/\r
27BOOLEAN\r
28EFIAPI\r
29IsOpteePresent (\r
30 VOID\r
31 )\r
32{\r
33 ARM_SMC_ARGS ArmSmcArgs;\r
34\r
a0f01e8a 35 ZeroMem (&ArmSmcArgs, sizeof (ARM_SMC_ARGS));\r
d65b78f1
SG
36 // Send a Trusted OS Calls UID command\r
37 ArmSmcArgs.Arg0 = ARM_SMC_ID_TOS_UID;\r
38 ArmCallSmc (&ArmSmcArgs);\r
39\r
40 if ((ArmSmcArgs.Arg0 == OPTEE_OS_UID0) &&\r
41 (ArmSmcArgs.Arg1 == OPTEE_OS_UID1) &&\r
42 (ArmSmcArgs.Arg2 == OPTEE_OS_UID2) &&\r
43 (ArmSmcArgs.Arg3 == OPTEE_OS_UID3)) {\r
44 return TRUE;\r
45 } else {\r
46 return FALSE;\r
47 }\r
48}\r
a0f01e8a
SG
49\r
50STATIC\r
51EFI_STATUS\r
52OpteeSharedMemoryRemap (\r
53 VOID\r
54 )\r
55{\r
56 ARM_SMC_ARGS ArmSmcArgs;\r
57 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
58 EFI_PHYSICAL_ADDRESS Start;\r
59 EFI_PHYSICAL_ADDRESS End;\r
60 EFI_STATUS Status;\r
61 UINTN Size;\r
62\r
63 ZeroMem (&ArmSmcArgs, sizeof (ARM_SMC_ARGS));\r
64 ArmSmcArgs.Arg0 = OPTEE_SMC_GET_SHARED_MEMORY_CONFIG;\r
65\r
66 ArmCallSmc (&ArmSmcArgs);\r
67 if (ArmSmcArgs.Arg0 != OPTEE_SMC_RETURN_OK) {\r
68 DEBUG ((DEBUG_WARN, "OP-TEE shared memory not supported\n"));\r
69 return EFI_UNSUPPORTED;\r
70 }\r
71\r
72 if (ArmSmcArgs.Arg3 != OPTEE_SMC_SHARED_MEMORY_CACHED) {\r
73 DEBUG ((DEBUG_WARN, "OP-TEE: Only normal cached shared memory supported\n"));\r
74 return EFI_UNSUPPORTED;\r
75 }\r
76\r
77 Start = (ArmSmcArgs.Arg1 + SIZE_4KB - 1) & ~(SIZE_4KB - 1);\r
78 End = (ArmSmcArgs.Arg1 + ArmSmcArgs.Arg2) & ~(SIZE_4KB - 1);\r
79 PhysicalAddress = Start;\r
80 Size = End - Start;\r
81\r
82 if (Size < SIZE_4KB) {\r
83 DEBUG ((DEBUG_WARN, "OP-TEE shared memory too small\n"));\r
84 return EFI_BUFFER_TOO_SMALL;\r
85 }\r
86\r
87 Status = ArmSetMemoryAttributes (PhysicalAddress, Size, EFI_MEMORY_WB);\r
88 if (EFI_ERROR (Status)) {\r
89 return Status;\r
90 }\r
91\r
92 OpteeSharedMemoryInformation.Base = (UINTN)PhysicalAddress;\r
93 OpteeSharedMemoryInformation.Size = Size;\r
94\r
95 return EFI_SUCCESS;\r
96}\r
97\r
98EFI_STATUS\r
99EFIAPI\r
100OpteeInit (\r
101 VOID\r
102 )\r
103{\r
104 EFI_STATUS Status;\r
105\r
106 if (!IsOpteePresent ()) {\r
107 DEBUG ((DEBUG_WARN, "OP-TEE not present\n"));\r
108 return EFI_UNSUPPORTED;\r
109 }\r
110\r
111 Status = OpteeSharedMemoryRemap ();\r
112 if (EFI_ERROR (Status)) {\r
113 DEBUG ((DEBUG_WARN, "OP-TEE shared memory remap failed\n"));\r
114 return Status;\r
115 }\r
116\r
117 return EFI_SUCCESS;\r
118}\r
119\r
088a5334
SG
120STATIC\r
121BOOLEAN\r
122IsOpteeSmcReturnRpc (\r
123 UINT32 Return\r
124 )\r
125{\r
126 return (Return != OPTEE_SMC_RETURN_UNKNOWN_FUNCTION) &&\r
127 ((Return & OPTEE_SMC_RETURN_RPC_PREFIX_MASK) ==\r
128 OPTEE_SMC_RETURN_RPC_PREFIX);\r
129}\r
130\r
a0f01e8a
SG
131/**\r
132 Does Standard SMC to OP-TEE in secure world.\r
133\r
134 @param[in] PhysicalArg Physical address of message to pass to secure world\r
135\r
136 @return 0 on success, secure world return code otherwise\r
137\r
138**/\r
139STATIC\r
140UINT32\r
141OpteeCallWithArg (\r
e40f8efb 142 IN UINT64 PhysicalArg\r
a0f01e8a
SG
143 )\r
144{\r
145 ARM_SMC_ARGS ArmSmcArgs;\r
146\r
147 ZeroMem (&ArmSmcArgs, sizeof (ARM_SMC_ARGS));\r
148 ArmSmcArgs.Arg0 = OPTEE_SMC_CALL_WITH_ARG;\r
149 ArmSmcArgs.Arg1 = (UINT32)(PhysicalArg >> 32);\r
150 ArmSmcArgs.Arg2 = (UINT32)PhysicalArg;\r
151\r
152 while (TRUE) {\r
153 ArmCallSmc (&ArmSmcArgs);\r
154\r
088a5334
SG
155 if (IsOpteeSmcReturnRpc (ArmSmcArgs.Arg0)) {\r
156 switch (ArmSmcArgs.Arg0) {\r
157 case OPTEE_SMC_RETURN_RPC_FOREIGN_INTERRUPT:\r
158 //\r
159 // A foreign interrupt was raised while secure world was\r
160 // executing, since they are handled in UEFI a dummy RPC is\r
161 // performed to let UEFI take the interrupt through the normal\r
162 // vector.\r
163 //\r
164 break;\r
165\r
166 default:\r
167 // Do nothing in case RPC is not implemented.\r
168 break;\r
169 }\r
170\r
a0f01e8a
SG
171 ArmSmcArgs.Arg0 = OPTEE_SMC_RETURN_FROM_RPC;\r
172 } else {\r
173 break;\r
174 }\r
175 }\r
176\r
177 return ArmSmcArgs.Arg0;\r
178}\r
179\r
180STATIC\r
181VOID\r
182EfiGuidToRfc4122Uuid (\r
183 OUT RFC4122_UUID *Rfc4122Uuid,\r
184 IN EFI_GUID *Guid\r
185 )\r
186{\r
187 Rfc4122Uuid->Data1 = SwapBytes32 (Guid->Data1);\r
188 Rfc4122Uuid->Data2 = SwapBytes16 (Guid->Data2);\r
189 Rfc4122Uuid->Data3 = SwapBytes16 (Guid->Data3);\r
190 CopyMem (Rfc4122Uuid->Data4, Guid->Data4, sizeof (Rfc4122Uuid->Data4));\r
191}\r
192\r
193EFI_STATUS\r
194EFIAPI\r
195OpteeOpenSession (\r
196 IN OUT OPTEE_OPEN_SESSION_ARG *OpenSessionArg\r
197 )\r
198{\r
199 OPTEE_MESSAGE_ARG *MessageArg;\r
200\r
201 MessageArg = NULL;\r
202\r
203 if (OpteeSharedMemoryInformation.Base == 0) {\r
204 DEBUG ((DEBUG_WARN, "OP-TEE not initialized\n"));\r
205 return EFI_NOT_STARTED;\r
206 }\r
207\r
208 MessageArg = (OPTEE_MESSAGE_ARG *)OpteeSharedMemoryInformation.Base;\r
209 ZeroMem (MessageArg, sizeof (OPTEE_MESSAGE_ARG));\r
210\r
211 MessageArg->Command = OPTEE_MESSAGE_COMMAND_OPEN_SESSION;\r
212\r
213 //\r
214 // Initialize and add the meta parameters needed when opening a\r
215 // session.\r
216 //\r
217 MessageArg->Params[0].Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT |\r
218 OPTEE_MESSAGE_ATTRIBUTE_META;\r
219 MessageArg->Params[1].Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT |\r
220 OPTEE_MESSAGE_ATTRIBUTE_META;\r
221 EfiGuidToRfc4122Uuid (\r
222 (RFC4122_UUID *)&MessageArg->Params[0].Union.Value,\r
223 &OpenSessionArg->Uuid\r
224 );\r
225 ZeroMem (&MessageArg->Params[1].Union.Value, sizeof (EFI_GUID));\r
226 MessageArg->Params[1].Union.Value.C = OPTEE_LOGIN_PUBLIC;\r
227\r
228 MessageArg->NumParams = 2;\r
229\r
e40f8efb 230 if (OpteeCallWithArg ((UINTN)MessageArg)) {\r
a0f01e8a
SG
231 MessageArg->Return = OPTEE_ERROR_COMMUNICATION;\r
232 MessageArg->ReturnOrigin = OPTEE_ORIGIN_COMMUNICATION;\r
233 }\r
234\r
235 OpenSessionArg->Session = MessageArg->Session;\r
236 OpenSessionArg->Return = MessageArg->Return;\r
237 OpenSessionArg->ReturnOrigin = MessageArg->ReturnOrigin;\r
238\r
239 return EFI_SUCCESS;\r
240}\r
241\r
242EFI_STATUS\r
243EFIAPI\r
244OpteeCloseSession (\r
245 IN UINT32 Session\r
246 )\r
247{\r
248 OPTEE_MESSAGE_ARG *MessageArg;\r
249\r
250 MessageArg = NULL;\r
251\r
252 if (OpteeSharedMemoryInformation.Base == 0) {\r
253 DEBUG ((DEBUG_WARN, "OP-TEE not initialized\n"));\r
254 return EFI_NOT_STARTED;\r
255 }\r
256\r
257 MessageArg = (OPTEE_MESSAGE_ARG *)OpteeSharedMemoryInformation.Base;\r
258 ZeroMem (MessageArg, sizeof (OPTEE_MESSAGE_ARG));\r
259\r
260 MessageArg->Command = OPTEE_MESSAGE_COMMAND_CLOSE_SESSION;\r
261 MessageArg->Session = Session;\r
262\r
e40f8efb 263 OpteeCallWithArg ((UINTN)MessageArg);\r
a0f01e8a
SG
264\r
265 return EFI_SUCCESS;\r
266}\r
267\r
268STATIC\r
269EFI_STATUS\r
270OpteeToMessageParam (\r
271 OUT OPTEE_MESSAGE_PARAM *MessageParams,\r
272 IN UINT32 NumParams,\r
273 IN OPTEE_MESSAGE_PARAM *InParams\r
274 )\r
275{\r
276 UINT32 Idx;\r
277 UINTN ParamSharedMemoryAddress;\r
278 UINTN SharedMemorySize;\r
279 UINTN Size;\r
280\r
281 Size = (sizeof (OPTEE_MESSAGE_ARG) + sizeof (UINT64) - 1) &\r
282 ~(sizeof (UINT64) - 1);\r
283 ParamSharedMemoryAddress = OpteeSharedMemoryInformation.Base + Size;\r
284 SharedMemorySize = OpteeSharedMemoryInformation.Size - Size;\r
285\r
286 for (Idx = 0; Idx < NumParams; Idx++) {\r
287 CONST OPTEE_MESSAGE_PARAM *InParam;\r
288 OPTEE_MESSAGE_PARAM *MessageParam;\r
289 UINT32 Attribute;\r
290\r
291 InParam = InParams + Idx;\r
292 MessageParam = MessageParams + Idx;\r
293 Attribute = InParam->Attribute & OPTEE_MESSAGE_ATTRIBUTE_TYPE_MASK;\r
294\r
295 switch (Attribute) {\r
296 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE:\r
297 MessageParam->Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE;\r
298 ZeroMem (&MessageParam->Union, sizeof (MessageParam->Union));\r
299 break;\r
300\r
301 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT:\r
302 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_OUTPUT:\r
303 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INOUT:\r
304 MessageParam->Attribute = Attribute;\r
305 MessageParam->Union.Value.A = InParam->Union.Value.A;\r
306 MessageParam->Union.Value.B = InParam->Union.Value.B;\r
307 MessageParam->Union.Value.C = InParam->Union.Value.C;\r
308 break;\r
309\r
310 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INPUT:\r
311 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_OUTPUT:\r
312 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INOUT:\r
313 MessageParam->Attribute = Attribute;\r
314\r
315 if (InParam->Union.Memory.Size > SharedMemorySize) {\r
316 return EFI_OUT_OF_RESOURCES;\r
317 }\r
318\r
319 CopyMem (\r
320 (VOID *)ParamSharedMemoryAddress,\r
e40f8efb 321 (VOID *)(UINTN)InParam->Union.Memory.BufferAddress,\r
a0f01e8a
SG
322 InParam->Union.Memory.Size\r
323 );\r
324 MessageParam->Union.Memory.BufferAddress = (UINT64)ParamSharedMemoryAddress;\r
325 MessageParam->Union.Memory.Size = InParam->Union.Memory.Size;\r
326\r
327 Size = (InParam->Union.Memory.Size + sizeof (UINT64) - 1) &\r
328 ~(sizeof (UINT64) - 1);\r
329 ParamSharedMemoryAddress += Size;\r
330 SharedMemorySize -= Size;\r
331 break;\r
332\r
333 default:\r
334 return EFI_INVALID_PARAMETER;\r
335 }\r
336 }\r
337\r
338 return EFI_SUCCESS;\r
339}\r
340\r
341STATIC\r
342EFI_STATUS\r
343OpteeFromMessageParam (\r
344 OUT OPTEE_MESSAGE_PARAM *OutParams,\r
345 IN UINT32 NumParams,\r
346 IN OPTEE_MESSAGE_PARAM *MessageParams\r
347 )\r
348{\r
349 UINT32 Idx;\r
350\r
351 for (Idx = 0; Idx < NumParams; Idx++) {\r
352 OPTEE_MESSAGE_PARAM *OutParam;\r
353 CONST OPTEE_MESSAGE_PARAM *MessageParam;\r
354 UINT32 Attribute;\r
355\r
356 OutParam = OutParams + Idx;\r
357 MessageParam = MessageParams + Idx;\r
358 Attribute = MessageParam->Attribute & OPTEE_MESSAGE_ATTRIBUTE_TYPE_MASK;\r
359\r
360 switch (Attribute) {\r
361 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE:\r
362 OutParam->Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE;\r
363 ZeroMem (&OutParam->Union, sizeof (OutParam->Union));\r
364 break;\r
365\r
366 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT:\r
367 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_OUTPUT:\r
368 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INOUT:\r
369 OutParam->Attribute = Attribute;\r
370 OutParam->Union.Value.A = MessageParam->Union.Value.A;\r
371 OutParam->Union.Value.B = MessageParam->Union.Value.B;\r
372 OutParam->Union.Value.C = MessageParam->Union.Value.C;\r
373 break;\r
374\r
375 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INPUT:\r
376 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_OUTPUT:\r
377 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INOUT:\r
378 OutParam->Attribute = Attribute;\r
379\r
380 if (MessageParam->Union.Memory.Size > OutParam->Union.Memory.Size) {\r
381 return EFI_BAD_BUFFER_SIZE;\r
382 }\r
383\r
384 CopyMem (\r
e40f8efb
SG
385 (VOID *)(UINTN)OutParam->Union.Memory.BufferAddress,\r
386 (VOID *)(UINTN)MessageParam->Union.Memory.BufferAddress,\r
a0f01e8a
SG
387 MessageParam->Union.Memory.Size\r
388 );\r
389 OutParam->Union.Memory.Size = MessageParam->Union.Memory.Size;\r
390 break;\r
391\r
392 default:\r
393 return EFI_INVALID_PARAMETER;\r
394 }\r
395 }\r
396\r
397 return EFI_SUCCESS;\r
398}\r
399\r
400EFI_STATUS\r
401EFIAPI\r
402OpteeInvokeFunction (\r
403 IN OUT OPTEE_INVOKE_FUNCTION_ARG *InvokeFunctionArg\r
404 )\r
405{\r
406 EFI_STATUS Status;\r
407 OPTEE_MESSAGE_ARG *MessageArg;\r
408\r
409 MessageArg = NULL;\r
410\r
411 if (OpteeSharedMemoryInformation.Base == 0) {\r
412 DEBUG ((DEBUG_WARN, "OP-TEE not initialized\n"));\r
413 return EFI_NOT_STARTED;\r
414 }\r
415\r
416 MessageArg = (OPTEE_MESSAGE_ARG *)OpteeSharedMemoryInformation.Base;\r
417 ZeroMem (MessageArg, sizeof (OPTEE_MESSAGE_ARG));\r
418\r
419 MessageArg->Command = OPTEE_MESSAGE_COMMAND_INVOKE_FUNCTION;\r
420 MessageArg->Function = InvokeFunctionArg->Function;\r
421 MessageArg->Session = InvokeFunctionArg->Session;\r
422\r
423 Status = OpteeToMessageParam (\r
424 MessageArg->Params,\r
425 OPTEE_MAX_CALL_PARAMS,\r
426 InvokeFunctionArg->Params\r
427 );\r
428 if (Status) {\r
429 return Status;\r
430 }\r
431\r
432 MessageArg->NumParams = OPTEE_MAX_CALL_PARAMS;\r
433\r
e40f8efb 434 if (OpteeCallWithArg ((UINTN)MessageArg)) {\r
a0f01e8a
SG
435 MessageArg->Return = OPTEE_ERROR_COMMUNICATION;\r
436 MessageArg->ReturnOrigin = OPTEE_ORIGIN_COMMUNICATION;\r
437 }\r
438\r
439 if (OpteeFromMessageParam (\r
440 InvokeFunctionArg->Params,\r
441 OPTEE_MAX_CALL_PARAMS,\r
442 MessageArg->Params\r
443 )) {\r
444 MessageArg->Return = OPTEE_ERROR_COMMUNICATION;\r
445 MessageArg->ReturnOrigin = OPTEE_ORIGIN_COMMUNICATION;\r
446 }\r
447\r
448 InvokeFunctionArg->Return = MessageArg->Return;\r
449 InvokeFunctionArg->ReturnOrigin = MessageArg->ReturnOrigin;\r
450\r
451 return EFI_SUCCESS;\r
452}\r