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