1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #pragma once
6
7 #include <zircon/assert.h>
8
9 #include "tee-smc.h"
10
11 #define __DEFINE_RPC_RESULT_ARG_6(type1, name1, type2, name2, type3, name3, type4, name4, \
12 type5, name5, type6, name6) \
13 alignas(alignof(decltype(zx_smc_parameters_t::func_id))) uint32_t func_id; \
14 alignas(alignof(decltype(zx_smc_parameters_t::arg1))) type1 name1; \
15 alignas(alignof(decltype(zx_smc_parameters_t::arg2))) type2 name2; \
16 alignas(alignof(decltype(zx_smc_parameters_t::arg3))) type3 name3; \
17 alignas(alignof(decltype(zx_smc_parameters_t::arg4))) type4 name4; \
18 alignas(alignof(decltype(zx_smc_parameters_t::arg5))) type5 name5; \
19 alignas(alignof(decltype(zx_smc_parameters_t::arg6))) type6 name6;
20
21 #define __DEFINE_RPC_RESULT_ARG_5(...) \
22 __DEFINE_RPC_RESULT_ARG_6(__VA_ARGS__, uint64_t, unused5)
23
24 #define __DEFINE_RPC_RESULT_ARG_4(...) \
25 __DEFINE_RPC_RESULT_ARG_5(__VA_ARGS__, uint64_t, unused4)
26
27 #define __DEFINE_RPC_RESULT_ARG_3(...) \
28 __DEFINE_RPC_RESULT_ARG_4(__VA_ARGS__, uint64_t, unused3)
29
30 #define __DEFINE_RPC_RESULT_ARG_2(...) \
31 __DEFINE_RPC_RESULT_ARG_3(__VA_ARGS__, uint64_t, unused2)
32
33 #define __DEFINE_RPC_RESULT_ARG_1(...) \
34 __DEFINE_RPC_RESULT_ARG_2(__VA_ARGS__, uint64_t, unused1)
35
36 #define __DEFINE_RPC_RESULT_ARG_0(...) \
37 __DEFINE_RPC_RESULT_ARG_1(uint64_t, unused0)
38
39 #define __CHECK_RPC_RESULT_OFFSETS_ARG_6(result_type, _1, name1, _2, name2, _3, name3, _4, name4, \
40 _5, name5, _6, name6) \
41 static_assert(offsetof(result_type, func_id) == offsetof(zx_smc_parameters_t, func_id), \
42 "func_id is not aligned with the offset of zx_smc_parameters_t::func_id"); \
43 static_assert(offsetof(result_type, name1) == offsetof(zx_smc_parameters_t, arg1), \
44 "name1 is not aligned with the offset of zx_smc_parameters_t::arg1"); \
45 static_assert(offsetof(result_type, name2) == offsetof(zx_smc_parameters_t, arg2), \
46 "name2 is not aligned with the offset of zx_smc_parameters_t::arg2"); \
47 static_assert(offsetof(result_type, name3) == offsetof(zx_smc_parameters_t, arg3), \
48 "name3 is not aligned with the offset of zx_smc_parameters_t::arg3"); \
49 static_assert(offsetof(result_type, name4) == offsetof(zx_smc_parameters_t, arg4), \
50 "name4 is not aligned with the offset of zx_smc_parameters_t::arg4"); \
51 static_assert(offsetof(result_type, name5) == offsetof(zx_smc_parameters_t, arg5), \
52 "name5 is not aligned with the offset of zx_smc_parameters_t::arg5"); \
53 static_assert(offsetof(result_type, name6) == offsetof(zx_smc_parameters_t, arg6), \
54 "name6 is not aligned with the offset of zx_smc_parameters_t::arg6");
55
56 #define __CHECK_RPC_RESULT_OFFSETS_ARG_5(...) \
57 __CHECK_RPC_RESULT_OFFSETS_ARG_6(__VA_ARGS__, uint64_t, unused5)
58
59 #define __CHECK_RPC_RESULT_OFFSETS_ARG_4(...) \
60 __CHECK_RPC_RESULT_OFFSETS_ARG_5(__VA_ARGS__, uint64_t, unused4)
61
62 #define __CHECK_RPC_RESULT_OFFSETS_ARG_3(...) \
63 __CHECK_RPC_RESULT_OFFSETS_ARG_4(__VA_ARGS__, uint64_t, unused3)
64
65 #define __CHECK_RPC_RESULT_OFFSETS_ARG_2(...) \
66 __CHECK_RPC_RESULT_OFFSETS_ARG_3(__VA_ARGS__, uint64_t, unused2)
67
68 #define __CHECK_RPC_RESULT_OFFSETS_ARG_1(...) \
69 __CHECK_RPC_RESULT_OFFSETS_ARG_2(__VA_ARGS__, uint64_t, unused1)
70
71 #define __CHECK_RPC_RESULT_OFFSETS_ARG_0(result_type, ...) \
72 __CHECK_RPC_RESULT_OFFSETS_ARG_1(result_type, uint64_t, unused0)
73
74 // Helper macro for defining a struct that is intended to overlay with a zx_smc_parameters_t. The
75 // zx_smc_parameters_t has six uint64_t members that are passed as arguments to an SMC call, but
76 // the values being used could actually int64_t, int32_t or uint32_t. It is dependent on the RPC
77 // function that was invoked. The macro allows for the definition of up to six members within the
78 // result type that should align with arg1-arg6. For examples, see the usages later in this file.
79 //
80 // Parameters:
81 // result_type: Name of the type to be defined.
82 // num_members: Number of arguments in the type to be defined.
83 // ...: List of types and names for the data members (see examples below).
84 #define DEFINE_RPC_RESULT_STRUCT(result_type, num_members, ...) \
85 static_assert(num_members <= 6, "RPC result structure must have no more than 6 members"); \
86 struct result_type { \
87 __DEFINE_RPC_RESULT_ARG_##num_members(__VA_ARGS__) \
88 }; \
89 static_assert(sizeof(result_type) <= sizeof(zx_smc_parameters_t), \
90 "result_type cannot be larger in size than zx_smc_parameters_t"); \
91 __CHECK_RPC_RESULT_OFFSETS_ARG_##num_members(result_type, __VA_ARGS__)
92
93 namespace optee {
94
95 //
96 // OP-TEE Return codes
97 //
98 // These are the possible return codes that could come back in x0 of the SMC call. OP-TEE allocates
99 // the upper 16 bits of the return code to designate whether the OP-TEE is initiating an RPC call
100 // that the non secure world must complete.
101 constexpr uint32_t kReturnOk = 0x0;
102 constexpr uint32_t kReturnEThreadLimit = 0x1;
103 constexpr uint32_t kReturnEBusy = 0x2;
104 constexpr uint32_t kReturnEResume = 0x3;
105 constexpr uint32_t kReturnEBadAddress = 0x4;
106 constexpr uint32_t kReturnEBadCommand = 0x5;
107 constexpr uint32_t kReturnENoMemory = 0x6;
108 constexpr uint32_t kReturnENotAvailable = 0x7;
109
110 constexpr uint32_t kReturnRpcPrefixMask = 0xFFFF0000;
111 constexpr uint32_t kReturnRpcPrefix = 0xFFFF0000;
112 constexpr uint32_t kReturnRpcFunctionMask = 0x0000FFFF;
113
114 // Helper function for identifying return codes that are actually an RPC initiating function. Care
115 // must be taken to ensure that we don't misidentify an SMC Unknown Function return code as an RPC
116 // return code, as the bits do overlap.
IsReturnRpc(uint32_t return_code)117 static constexpr bool IsReturnRpc(uint32_t return_code) {
118 return (return_code != tee_smc::kSmc32ReturnUnknownFunction) &&
119 ((return_code & kReturnRpcPrefixMask) == kReturnRpcPrefix);
120 }
121
122 // Helper function for getting the RPC function code from a return code.
123 // Note: only return codes containing the RPC prefix should be passed to this function. See
124 // optee::IsReturnRpc() for details.
GetRpcFunctionCode(uint32_t return_code)125 static constexpr uint32_t GetRpcFunctionCode(uint32_t return_code) {
126 ZX_DEBUG_ASSERT_MSG(IsReturnRpc(return_code), "Return code must contain the RPC prefix!");
127 return return_code & kReturnRpcFunctionMask;
128 }
129
130 //
131 // Function ID helpers
132 //
133 // The Function IDs for OP-TEE SMC calls only vary in the call type and the function number. The
134 // calling convention is always SMC32 and obviously it's always accessing the Trusted OS Service.
135 // These wrapper functions eliminate the need to specify those each time.
CreateFastOpteeFuncId(uint16_t func_num)136 static constexpr uint32_t CreateFastOpteeFuncId(uint16_t func_num) {
137 return tee_smc::CreateFunctionId(tee_smc::kFastCall,
138 tee_smc::kSmc32CallConv,
139 tee_smc::kTrustedOsService,
140 func_num);
141 }
142
CreateYieldOpteeFuncId(uint16_t func_num)143 static constexpr uint32_t CreateYieldOpteeFuncId(uint16_t func_num) {
144 return tee_smc::CreateFunctionId(tee_smc::kYieldingCall,
145 tee_smc::kSmc32CallConv,
146 tee_smc::kTrustedOsService,
147 func_num);
148 }
149
150 //
151 // OP-TEE API constants
152 //
153 // These constants represent the expected values to the Call UID and Revision general service
154 // queries for OP-TEE.
155 constexpr uint32_t kOpteeApiUid_0 = 0x384FB3E0;
156 constexpr uint32_t kOpteeApiUid_1 = 0xE7F811E3;
157 constexpr uint32_t kOpteeApiUid_2 = 0xAF630002;
158 constexpr uint32_t kOpteeApiUid_3 = 0xA5D5C51B;
159
160 constexpr uint32_t kOpteeApiRevisionMajor = 2;
161 constexpr uint32_t kOpteeApiRevisionMinor = 0;
162
163 //
164 // OP-TEE SMC Functions
165 //
166 // The below section defines the format for OP-TEE specific Secure Monitor Calls. For each OP-TEE
167 // function, there should be a function identifier and an expected result structure. The result
168 // structures are intended to be overlaid with the zx_smc_result_t structure that is populated
169 // by the SMC call. It should be noted that the zx_smc_result_t structure is made up of four 64
170 // bit values that represent the x0-x3 registers, but OP-TEE always uses the SMC32 calling
171 // convention. As such, fields in the result structures will only have 32 relevant bits.
172
173 //
174 // Get Trusted OS UUID (0x0000)
175 //
176 // Get the UUID of the Trusted OS. For OP-TEE, this should return OP-TEE's UUID.
177 //
178 // Parameters:
179 // arg1-6: Unused.
180 //
181 // Results:
182 // arg0: UUID Bytes 0:3
183 // arg1: UUID Bytes 4:7
184 // arg2: UUID Bytes 8:11
185 // arg3: UUID Bytes 12:15
186 constexpr uint32_t kGetOsUuidFuncId = CreateFastOpteeFuncId(0x0000);
187
188 DEFINE_SMC_RESULT_STRUCT(GetOsUuidResult, 4,
189 uint32_t, uuid_0,
190 uint32_t, uuid_1,
191 uint32_t, uuid_2,
192 uint32_t, uuid_3)
193
194 //
195 // Get Trusted OS Revision (0x0001)
196 //
197 // Get the revision number of the Trusted OS. Note that this is different from the revision of the
198 // Call API revision.
199 //
200 // Parameters:
201 // arg1-6: Unused.
202 //
203 // Results:
204 // arg0: Major version.
205 // arg1: Minor version
206 // arg2-3: Unused.
207 constexpr uint32_t kGetOsRevisionFuncId = CreateFastOpteeFuncId(0x0001);
208
209 DEFINE_SMC_RESULT_STRUCT(GetOsRevisionResult, 2,
210 uint32_t, major,
211 uint32_t, minor)
212
213 //
214 // Resume from RPC (0x0003)
215 //
216 // TODO(rjascani) - Document parameters and result values
217 constexpr uint32_t kReturnFromRpcFuncId = CreateYieldOpteeFuncId(0x0003);
218
219 //
220 // Call with Arguments (0x0004)
221 //
222 // TODO(rjascani) - Document parameters and result values
223 constexpr uint32_t kCallWithArgFuncId = CreateYieldOpteeFuncId(0x0004);
224
225 DEFINE_SMC_RESULT_STRUCT(CallWithArgResult, 4,
226 uint32_t, status,
227 uint32_t, arg1,
228 uint32_t, arg2,
229 uint32_t, arg3);
230
231 //
232 // Get Shared Memory Config (0x0007)
233 //
234 // TODO(rjascani) - Document parameters and result values
235 constexpr uint32_t kGetSharedMemConfigFuncId = CreateFastOpteeFuncId(0x0007);
236
237 DEFINE_SMC_RESULT_STRUCT(GetSharedMemConfigResult, 4,
238 int32_t, status,
239 uint32_t, start,
240 uint32_t, size,
241 uint32_t, settings)
242
243 //
244 // Exchange Capabilities (0x0009)
245 //
246 // Exchange capabilities between non-secure and secure world.
247 //
248 // Parameters:
249 // arg1: Non-secure world capabilities bitfield.
250 // arg2-6: Unused.
251 //
252 // Results:
253 // arg0: Status code indicating whether secure world can use non-secure capabilities.
254 // arg1: Secure world capabilities bitfield
255 // arg2-3: Unused.
256 constexpr uint32_t kExchangeCapabilitiesFuncId = CreateFastOpteeFuncId(0x0009);
257
258 constexpr uint32_t kNonSecureCapUniprocessor = (1 << 0);
259
260 constexpr uint32_t kSecureCapHasReservedSharedMem = (1 << 0);
261 constexpr uint32_t kSecureCapCanUsePrevUnregisteredSharedMem = (1 << 1);
262 constexpr uint32_t kSecureCapCanUseDynamicSharedMem = (1 << 2);
263
264 DEFINE_SMC_RESULT_STRUCT(ExchangeCapabilitiesResult, 2,
265 int32_t, status,
266 uint32_t, secure_world_capabilities)
267
268 //
269 // Disable Shared Memory Cache (0x000A)
270 //
271 // TODO(rjascani) - Document parameters and result values
272 constexpr uint32_t kDisableSharedMemCacheFuncId = CreateFastOpteeFuncId(0x000A);
273
274 DEFINE_SMC_RESULT_STRUCT(DisableSharedMemCacheResult, 3,
275 int32_t, status,
276 uint32_t, shared_mem_upper32,
277 uint32_t, shared_mem_lower32)
278
279 //
280 // Enable Shared Memory Cache (0x000B)
281 //
282 // TODO(rjascani) - Document parameters and result values
283 constexpr uint32_t kEnableSharedMemCacheFuncId = CreateFastOpteeFuncId(0x000B);
284
285 //
286 // OP-TEE RPC Functions
287 //
288 // The below section defines the format for OP-TEE specific RPC functions. An RPC function is an
289 // action the TEE OS is requesting the driver perform. After completing the requested action, the
290 // driver calls back into the TEE via another SMC with the parameters of the call containing the
291 // results. For each OP-TEE RPC function, there is a function identifier, a result structure
292 // (as input), and a params structure (as output).
293 //
294 // The function identifier determines which RPC function is being called by the TEE OS.
295 //
296 // The input result structure is a CallWithArgResult where the TEE OS passes the arguments for the
297 // RPC function. Each argument's significance is determined by the RPC function being called.
298 //
299 // The output params structure is a zx_smc_parameters_t with which to call the TEE OS back, once the
300 // requested RPC function has been completed.
301
302 //
303 // Allocate Memory (0x0000)
304 //
305 // Allocate shared memory for driver <-> TEE communication.
306 //
307 // Parameters:
308 // arg1: The size, in bytes, of requested memory.
309 // arg2: Unused.
310 // arg3: Unused.
311 //
312 // Results:
313 // arg1-2: The upper (arg1) and lower (arg2) 32-bit parts of a 64-bit physical pointer to the
314 // allocated memory. Value will be 0 if requested size was 0 or if memory allocation
315 // failed.
316 // arg3: Unused.
317 // arg4-5: The upper (arg4) and lower (arg5) 32-bit parts of a 64-bit identifier for the allocated
318 // memory. The value of the identifier is implementation-defined and is passed from the
319 // secure world via another RPC when the secure world wants to free the allocated memory
320 // region.
321 // arg6: Unused.
322 constexpr uint32_t kRpcFunctionIdAllocateMemory = 0x0;
323 DEFINE_SMC_RESULT_STRUCT(RpcFunctionAllocateMemoryArgs, 2,
324 int32_t, status,
325 uint32_t, size)
326 DEFINE_RPC_RESULT_STRUCT(RpcFunctionAllocateMemoryResult, 5,
327 uint32_t, phys_addr_upper32,
328 uint32_t, phys_addr_lower32,
329 uint64_t, __unused3,
330 uint32_t, mem_id_upper32,
331 uint32_t, mem_id_lower32)
332
333 //
334 // Free Memory (0x0002)
335 //
336 // Free shared memory previously allocated.
337 //
338 // Parameters:
339 // arg1-2: The upper (arg1) and lower (arg2) 32-bit parts of a 64-bit identifier for the memory to
340 // be freed. The value of the identifier is implementation-defined and determined during
341 // allocation.
342 // arg3: Unused.
343 //
344 // Results:
345 // arg1-6: Unused.
346 constexpr uint32_t kRpcFunctionIdFreeMemory = 0x2;
347 DEFINE_SMC_RESULT_STRUCT(RpcFunctionFreeMemoryArgs, 3,
348 int32_t, status,
349 uint32_t, mem_id_upper32,
350 uint32_t, mem_id_lower32)
351 DEFINE_RPC_RESULT_STRUCT(RpcFunctionFreeMemoryResult, 0)
352
353 //
354 // Deliver IRQ (0x0004)
355 //
356 // Deliver an IRQ to the rich environment.
357 //
358 // Parameters:
359 // arg1-3: Unused.
360 //
361 // Results:
362 // arg1-6: Unused.
363 constexpr uint32_t kRpcFunctionIdDeliverIrq = 0x4;
364 DEFINE_SMC_RESULT_STRUCT(RpcFunctionDeliverIrqArgs, 1,
365 int32_t, status)
366 DEFINE_RPC_RESULT_STRUCT(RpcFunctionDeliverIrqResult, 0)
367
368 //
369 // Execute Command (0x0004)
370 //
371 // Execute a command specified in the provided message.
372 //
373 // Parameters:
374 // arg1-2: The upper (arg1) and lower (arg2) 32-bit parts of a 64-bit identifier for the command
375 // message. The value of the identifier is implementation-defined and determined during
376 // allocation.
377 // arg3: Unused.
378 //
379 // Results:
380 // arg1-6: Unused.
381 constexpr uint32_t kRpcFunctionIdExecuteCommand = 0x5;
382 DEFINE_SMC_RESULT_STRUCT(RpcFunctionExecuteCommandsArgs, 3,
383 int32_t, status,
384 uint32_t, msg_mem_id_upper32,
385 uint32_t, msg_mem_id_lower32)
386 DEFINE_RPC_RESULT_STRUCT(RpcFunctionExecuteCommandsResult, 0)
387
388 typedef union {
389 CallWithArgResult generic;
390 RpcFunctionAllocateMemoryArgs allocate_memory;
391 RpcFunctionFreeMemoryArgs free_memory;
392 RpcFunctionDeliverIrqArgs deliver_irq;
393 RpcFunctionExecuteCommandsArgs execute_command;
394 } RpcFunctionArgs;
395
396 typedef union {
397 zx_smc_parameters_t generic;
398 RpcFunctionAllocateMemoryResult allocate_memory;
399 RpcFunctionFreeMemoryResult free_memory;
400 RpcFunctionDeliverIrqResult delivery_irq;
401 RpcFunctionExecuteCommandsResult execute_command;
402 } RpcFunctionResult;
403
404 enum SharedMemoryType : uint64_t {
405 // Memory that can be shared with a userspace application
406 kApplication = 0x0,
407
408 // Memory that can only be shared with the "kernel"
409 // "Kernel" means access up to the driver but not the userspace application, but does not
410 // translate strictly to "kernel space only" due to the microkernel nature of Zircon in Fuchsia.
411 kKernel = 0x1,
412
413 // Memory that is shared with "kernel" but can be exported to userspace
414 // "Kernel" means access up to the driver but not the userspace application, but does not
415 // translate strictly to "kernel space only" due to the microkernel nature of Zircon in Fuchsia.
416 kGlobal = 0x2
417 };
418
419 } // namespace optee
420