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