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