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