]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/OpteeLib/Optee.c
BaseTools: create and use a standard shared variable for '*'
[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 /**
127 Does Standard SMC to OP-TEE in secure world.
128
129 @param[in] PhysicalArg Physical address of message to pass to secure world
130
131 @return 0 on success, secure world return code otherwise
132
133 **/
134 STATIC
135 UINT32
136 OpteeCallWithArg (
137 IN UINT64 PhysicalArg
138 )
139 {
140 ARM_SMC_ARGS ArmSmcArgs;
141
142 ZeroMem (&ArmSmcArgs, sizeof (ARM_SMC_ARGS));
143 ArmSmcArgs.Arg0 = OPTEE_SMC_CALL_WITH_ARG;
144 ArmSmcArgs.Arg1 = (UINT32)(PhysicalArg >> 32);
145 ArmSmcArgs.Arg2 = (UINT32)PhysicalArg;
146
147 while (TRUE) {
148 ArmCallSmc (&ArmSmcArgs);
149
150 if (ArmSmcArgs.Arg0 == OPTEE_SMC_RETURN_RPC_FOREIGN_INTERRUPT) {
151 //
152 // A foreign interrupt was raised while secure world was
153 // executing, since they are handled in UEFI a dummy RPC is
154 // performed to let UEFI take the interrupt through the normal
155 // vector.
156 //
157 ArmSmcArgs.Arg0 = OPTEE_SMC_RETURN_FROM_RPC;
158 } else {
159 break;
160 }
161 }
162
163 return ArmSmcArgs.Arg0;
164 }
165
166 STATIC
167 VOID
168 EfiGuidToRfc4122Uuid (
169 OUT RFC4122_UUID *Rfc4122Uuid,
170 IN EFI_GUID *Guid
171 )
172 {
173 Rfc4122Uuid->Data1 = SwapBytes32 (Guid->Data1);
174 Rfc4122Uuid->Data2 = SwapBytes16 (Guid->Data2);
175 Rfc4122Uuid->Data3 = SwapBytes16 (Guid->Data3);
176 CopyMem (Rfc4122Uuid->Data4, Guid->Data4, sizeof (Rfc4122Uuid->Data4));
177 }
178
179 EFI_STATUS
180 EFIAPI
181 OpteeOpenSession (
182 IN OUT OPTEE_OPEN_SESSION_ARG *OpenSessionArg
183 )
184 {
185 OPTEE_MESSAGE_ARG *MessageArg;
186
187 MessageArg = NULL;
188
189 if (OpteeSharedMemoryInformation.Base == 0) {
190 DEBUG ((DEBUG_WARN, "OP-TEE not initialized\n"));
191 return EFI_NOT_STARTED;
192 }
193
194 MessageArg = (OPTEE_MESSAGE_ARG *)OpteeSharedMemoryInformation.Base;
195 ZeroMem (MessageArg, sizeof (OPTEE_MESSAGE_ARG));
196
197 MessageArg->Command = OPTEE_MESSAGE_COMMAND_OPEN_SESSION;
198
199 //
200 // Initialize and add the meta parameters needed when opening a
201 // session.
202 //
203 MessageArg->Params[0].Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT |
204 OPTEE_MESSAGE_ATTRIBUTE_META;
205 MessageArg->Params[1].Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT |
206 OPTEE_MESSAGE_ATTRIBUTE_META;
207 EfiGuidToRfc4122Uuid (
208 (RFC4122_UUID *)&MessageArg->Params[0].Union.Value,
209 &OpenSessionArg->Uuid
210 );
211 ZeroMem (&MessageArg->Params[1].Union.Value, sizeof (EFI_GUID));
212 MessageArg->Params[1].Union.Value.C = OPTEE_LOGIN_PUBLIC;
213
214 MessageArg->NumParams = 2;
215
216 if (OpteeCallWithArg ((UINTN)MessageArg)) {
217 MessageArg->Return = OPTEE_ERROR_COMMUNICATION;
218 MessageArg->ReturnOrigin = OPTEE_ORIGIN_COMMUNICATION;
219 }
220
221 OpenSessionArg->Session = MessageArg->Session;
222 OpenSessionArg->Return = MessageArg->Return;
223 OpenSessionArg->ReturnOrigin = MessageArg->ReturnOrigin;
224
225 return EFI_SUCCESS;
226 }
227
228 EFI_STATUS
229 EFIAPI
230 OpteeCloseSession (
231 IN UINT32 Session
232 )
233 {
234 OPTEE_MESSAGE_ARG *MessageArg;
235
236 MessageArg = NULL;
237
238 if (OpteeSharedMemoryInformation.Base == 0) {
239 DEBUG ((DEBUG_WARN, "OP-TEE not initialized\n"));
240 return EFI_NOT_STARTED;
241 }
242
243 MessageArg = (OPTEE_MESSAGE_ARG *)OpteeSharedMemoryInformation.Base;
244 ZeroMem (MessageArg, sizeof (OPTEE_MESSAGE_ARG));
245
246 MessageArg->Command = OPTEE_MESSAGE_COMMAND_CLOSE_SESSION;
247 MessageArg->Session = Session;
248
249 OpteeCallWithArg ((UINTN)MessageArg);
250
251 return EFI_SUCCESS;
252 }
253
254 STATIC
255 EFI_STATUS
256 OpteeToMessageParam (
257 OUT OPTEE_MESSAGE_PARAM *MessageParams,
258 IN UINT32 NumParams,
259 IN OPTEE_MESSAGE_PARAM *InParams
260 )
261 {
262 UINT32 Idx;
263 UINTN ParamSharedMemoryAddress;
264 UINTN SharedMemorySize;
265 UINTN Size;
266
267 Size = (sizeof (OPTEE_MESSAGE_ARG) + sizeof (UINT64) - 1) &
268 ~(sizeof (UINT64) - 1);
269 ParamSharedMemoryAddress = OpteeSharedMemoryInformation.Base + Size;
270 SharedMemorySize = OpteeSharedMemoryInformation.Size - Size;
271
272 for (Idx = 0; Idx < NumParams; Idx++) {
273 CONST OPTEE_MESSAGE_PARAM *InParam;
274 OPTEE_MESSAGE_PARAM *MessageParam;
275 UINT32 Attribute;
276
277 InParam = InParams + Idx;
278 MessageParam = MessageParams + Idx;
279 Attribute = InParam->Attribute & OPTEE_MESSAGE_ATTRIBUTE_TYPE_MASK;
280
281 switch (Attribute) {
282 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE:
283 MessageParam->Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE;
284 ZeroMem (&MessageParam->Union, sizeof (MessageParam->Union));
285 break;
286
287 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT:
288 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_OUTPUT:
289 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INOUT:
290 MessageParam->Attribute = Attribute;
291 MessageParam->Union.Value.A = InParam->Union.Value.A;
292 MessageParam->Union.Value.B = InParam->Union.Value.B;
293 MessageParam->Union.Value.C = InParam->Union.Value.C;
294 break;
295
296 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INPUT:
297 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_OUTPUT:
298 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INOUT:
299 MessageParam->Attribute = Attribute;
300
301 if (InParam->Union.Memory.Size > SharedMemorySize) {
302 return EFI_OUT_OF_RESOURCES;
303 }
304
305 CopyMem (
306 (VOID *)ParamSharedMemoryAddress,
307 (VOID *)(UINTN)InParam->Union.Memory.BufferAddress,
308 InParam->Union.Memory.Size
309 );
310 MessageParam->Union.Memory.BufferAddress = (UINT64)ParamSharedMemoryAddress;
311 MessageParam->Union.Memory.Size = InParam->Union.Memory.Size;
312
313 Size = (InParam->Union.Memory.Size + sizeof (UINT64) - 1) &
314 ~(sizeof (UINT64) - 1);
315 ParamSharedMemoryAddress += Size;
316 SharedMemorySize -= Size;
317 break;
318
319 default:
320 return EFI_INVALID_PARAMETER;
321 }
322 }
323
324 return EFI_SUCCESS;
325 }
326
327 STATIC
328 EFI_STATUS
329 OpteeFromMessageParam (
330 OUT OPTEE_MESSAGE_PARAM *OutParams,
331 IN UINT32 NumParams,
332 IN OPTEE_MESSAGE_PARAM *MessageParams
333 )
334 {
335 UINT32 Idx;
336
337 for (Idx = 0; Idx < NumParams; Idx++) {
338 OPTEE_MESSAGE_PARAM *OutParam;
339 CONST OPTEE_MESSAGE_PARAM *MessageParam;
340 UINT32 Attribute;
341
342 OutParam = OutParams + Idx;
343 MessageParam = MessageParams + Idx;
344 Attribute = MessageParam->Attribute & OPTEE_MESSAGE_ATTRIBUTE_TYPE_MASK;
345
346 switch (Attribute) {
347 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE:
348 OutParam->Attribute = OPTEE_MESSAGE_ATTRIBUTE_TYPE_NONE;
349 ZeroMem (&OutParam->Union, sizeof (OutParam->Union));
350 break;
351
352 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INPUT:
353 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_OUTPUT:
354 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_VALUE_INOUT:
355 OutParam->Attribute = Attribute;
356 OutParam->Union.Value.A = MessageParam->Union.Value.A;
357 OutParam->Union.Value.B = MessageParam->Union.Value.B;
358 OutParam->Union.Value.C = MessageParam->Union.Value.C;
359 break;
360
361 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INPUT:
362 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_OUTPUT:
363 case OPTEE_MESSAGE_ATTRIBUTE_TYPE_MEMORY_INOUT:
364 OutParam->Attribute = Attribute;
365
366 if (MessageParam->Union.Memory.Size > OutParam->Union.Memory.Size) {
367 return EFI_BAD_BUFFER_SIZE;
368 }
369
370 CopyMem (
371 (VOID *)(UINTN)OutParam->Union.Memory.BufferAddress,
372 (VOID *)(UINTN)MessageParam->Union.Memory.BufferAddress,
373 MessageParam->Union.Memory.Size
374 );
375 OutParam->Union.Memory.Size = MessageParam->Union.Memory.Size;
376 break;
377
378 default:
379 return EFI_INVALID_PARAMETER;
380 }
381 }
382
383 return EFI_SUCCESS;
384 }
385
386 EFI_STATUS
387 EFIAPI
388 OpteeInvokeFunction (
389 IN OUT OPTEE_INVOKE_FUNCTION_ARG *InvokeFunctionArg
390 )
391 {
392 EFI_STATUS Status;
393 OPTEE_MESSAGE_ARG *MessageArg;
394
395 MessageArg = NULL;
396
397 if (OpteeSharedMemoryInformation.Base == 0) {
398 DEBUG ((DEBUG_WARN, "OP-TEE not initialized\n"));
399 return EFI_NOT_STARTED;
400 }
401
402 MessageArg = (OPTEE_MESSAGE_ARG *)OpteeSharedMemoryInformation.Base;
403 ZeroMem (MessageArg, sizeof (OPTEE_MESSAGE_ARG));
404
405 MessageArg->Command = OPTEE_MESSAGE_COMMAND_INVOKE_FUNCTION;
406 MessageArg->Function = InvokeFunctionArg->Function;
407 MessageArg->Session = InvokeFunctionArg->Session;
408
409 Status = OpteeToMessageParam (
410 MessageArg->Params,
411 OPTEE_MAX_CALL_PARAMS,
412 InvokeFunctionArg->Params
413 );
414 if (Status) {
415 return Status;
416 }
417
418 MessageArg->NumParams = OPTEE_MAX_CALL_PARAMS;
419
420 if (OpteeCallWithArg ((UINTN)MessageArg)) {
421 MessageArg->Return = OPTEE_ERROR_COMMUNICATION;
422 MessageArg->ReturnOrigin = OPTEE_ORIGIN_COMMUNICATION;
423 }
424
425 if (OpteeFromMessageParam (
426 InvokeFunctionArg->Params,
427 OPTEE_MAX_CALL_PARAMS,
428 MessageArg->Params
429 )) {
430 MessageArg->Return = OPTEE_ERROR_COMMUNICATION;
431 MessageArg->ReturnOrigin = OPTEE_ORIGIN_COMMUNICATION;
432 }
433
434 InvokeFunctionArg->Return = MessageArg->Return;
435 InvokeFunctionArg->ReturnOrigin = MessageArg->ReturnOrigin;
436
437 return EFI_SUCCESS;
438 }