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