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
93namespace 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.
101constexpr uint32_t kReturnOk = 0x0;
102constexpr uint32_t kReturnEThreadLimit = 0x1;
103constexpr uint32_t kReturnEBusy = 0x2;
104constexpr uint32_t kReturnEResume = 0x3;
105constexpr uint32_t kReturnEBadAddress = 0x4;
106constexpr uint32_t kReturnEBadCommand = 0x5;
107constexpr uint32_t kReturnENoMemory = 0x6;
108constexpr uint32_t kReturnENotAvailable = 0x7;
109
110constexpr uint32_t kReturnRpcPrefixMask = 0xFFFF0000;
111constexpr uint32_t kReturnRpcPrefix = 0xFFFF0000;
112constexpr 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.
117static constexpr bool IsReturnRpc(uint32_t return_code) {
118    return (return_code != tee::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.
125static 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.
136static constexpr uint32_t CreateFastOpteeFuncId(uint16_t func_num) {
137    return tee::CreateFunctionId(tee::kFastCall,
138                                 tee::kSmc32CallConv,
139                                 tee::kTrustedOsService,
140                                 func_num);
141}
142
143static constexpr uint32_t CreateYieldOpteeFuncId(uint16_t func_num) {
144    return tee::CreateFunctionId(tee::kYieldingCall,
145                                 tee::kSmc32CallConv,
146                                 tee::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.
155constexpr uint32_t kOpteeApiUid_0 = 0x384FB3E0;
156constexpr uint32_t kOpteeApiUid_1 = 0xE7F811E3;
157constexpr uint32_t kOpteeApiUid_2 = 0xAF630002;
158constexpr uint32_t kOpteeApiUid_3 = 0xA5D5C51B;
159
160constexpr uint32_t kOpteeApiRevisionMajor = 2;
161constexpr 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
186constexpr uint32_t kGetOsUuidFuncId = CreateFastOpteeFuncId(0x0000);
187
188DEFINE_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
194constexpr uint8_t kOpteeOsUuid[] = {0x48, 0x61, 0x78, 0xE0, 0xE7, 0xF8, 0x11, 0xE3,
195                                    0xBC, 0x5E, 0x00, 0x02, 0xA5, 0xD5, 0xC5, 0x1B};
196
197//
198// Get Trusted OS Revision (0x0001)
199//
200// Get the revision number of the Trusted OS. Note that this is different from the revision of the
201// Call API revision.
202//
203// Parameters:
204// arg1-6:  Unused.
205//
206// Results:
207// arg0:    Major version.
208// arg1:    Minor version
209// arg2-3:  Unused.
210constexpr uint32_t kGetOsRevisionFuncId = CreateFastOpteeFuncId(0x0001);
211
212DEFINE_SMC_RESULT_STRUCT(GetOsRevisionResult, 2,
213                         uint32_t, major,
214                         uint32_t, minor)
215
216//
217// Resume from RPC (0x0003)
218//
219// TODO(rjascani) - Document parameters and result values
220constexpr uint32_t kReturnFromRpcFuncId = CreateYieldOpteeFuncId(0x0003);
221
222//
223// Call with Arguments (0x0004)
224//
225// TODO(rjascani) - Document parameters and result values
226constexpr uint32_t kCallWithArgFuncId = CreateYieldOpteeFuncId(0x0004);
227
228DEFINE_SMC_RESULT_STRUCT(CallWithArgResult, 4,
229                         uint32_t, status,
230                         uint32_t, arg1,
231                         uint32_t, arg2,
232                         uint32_t, arg3);
233
234//
235// Get Shared Memory Config (0x0007)
236//
237// TODO(rjascani) - Document parameters and result values
238constexpr uint32_t kGetSharedMemConfigFuncId = CreateFastOpteeFuncId(0x0007);
239
240DEFINE_SMC_RESULT_STRUCT(GetSharedMemConfigResult, 4,
241                         int32_t, status,
242                         uint32_t, start,
243                         uint32_t, size,
244                         uint32_t, settings)
245
246//
247// Exchange Capabilities (0x0009)
248//
249// Exchange capabilities between non-secure and secure world.
250//
251// Parameters:
252// arg1:    Non-secure world capabilities bitfield.
253// arg2-6:  Unused.
254//
255// Results:
256// arg0:    Status code indicating whether secure world can use non-secure capabilities.
257// arg1:    Secure world capabilities bitfield
258// arg2-3:  Unused.
259constexpr uint32_t kExchangeCapabilitiesFuncId = CreateFastOpteeFuncId(0x0009);
260
261constexpr uint32_t kNonSecureCapUniprocessor = (1 << 0);
262
263constexpr uint32_t kSecureCapHasReservedSharedMem = (1 << 0);
264constexpr uint32_t kSecureCapCanUsePrevUnregisteredSharedMem = (1 << 1);
265constexpr uint32_t kSecureCapCanUseDynamicSharedMem = (1 << 2);
266
267DEFINE_SMC_RESULT_STRUCT(ExchangeCapabilitiesResult, 2,
268                         int32_t, status,
269                         uint32_t, secure_world_capabilities)
270
271//
272// Disable Shared Memory Cache (0x000A)
273//
274// TODO(rjascani) - Document parameters and result values
275constexpr uint32_t kDisableSharedMemCacheFuncId = CreateFastOpteeFuncId(0x000A);
276
277DEFINE_SMC_RESULT_STRUCT(DisableSharedMemCacheResult, 3,
278                         int32_t, status,
279                         uint32_t, shared_mem_upper32,
280                         uint32_t, shared_mem_lower32)
281
282//
283// Enable Shared Memory Cache (0x000B)
284//
285// TODO(rjascani) - Document parameters and result values
286constexpr uint32_t kEnableSharedMemCacheFuncId = CreateFastOpteeFuncId(0x000B);
287
288//
289// OP-TEE RPC Functions
290//
291// The below section defines the format for OP-TEE specific RPC functions. An RPC function is an
292// action the TEE OS is requesting the driver perform. After completing the requested action, the
293// driver calls back into the TEE via another SMC with the parameters of the call containing the
294// results. For each OP-TEE RPC function, there is a function identifier, a result structure
295// (as input), and a params structure (as output).
296//
297// The function identifier determines which RPC function is being called by the TEE OS.
298//
299// The input result structure is a CallWithArgResult where the TEE OS passes the arguments for the
300// RPC function. Each argument's significance is determined by the RPC function being called.
301//
302// The output params structure is a zx_smc_parameters_t with which to call the TEE OS back, once the
303// requested RPC function has been completed.
304
305//
306// Allocate Memory (0x0000)
307//
308// Allocate shared memory for driver <-> TEE communication.
309//
310// Parameters:
311// arg1:    The size, in bytes, of requested memory.
312// arg2:    Unused.
313// arg3:    Unused.
314//
315// Results:
316// arg1-2:  The upper (arg1) and lower (arg2) 32-bit parts of a 64-bit physical pointer to the
317//          allocated memory. Value will be 0 if requested size was 0 or if memory allocation
318//          failed.
319// arg3:    Unused.
320// arg4-5:  The upper (arg4) and lower (arg5) 32-bit parts of a 64-bit identifier for the allocated
321//          memory. The value of the identifier is implementation-defined and is passed from the
322//          secure world via another RPC when the secure world wants to free the allocated memory
323//          region.
324// arg6:    Unused.
325constexpr uint32_t kRpcFunctionIdAllocateMemory = 0x0;
326DEFINE_SMC_RESULT_STRUCT(RpcFunctionAllocateMemoryArgs, 2,
327                         int32_t, status,
328                         uint32_t, size)
329DEFINE_RPC_RESULT_STRUCT(RpcFunctionAllocateMemoryResult, 5,
330                         uint32_t, phys_addr_upper32,
331                         uint32_t, phys_addr_lower32,
332                         uint64_t, __unused3,
333                         uint32_t, mem_id_upper32,
334                         uint32_t, mem_id_lower32)
335
336//
337// Free Memory (0x0002)
338//
339// Free shared memory previously allocated.
340//
341// Parameters:
342// arg1-2:  The upper (arg1) and lower (arg2) 32-bit parts of a 64-bit identifier for the memory to
343//          be freed. The value of the identifier is implementation-defined and determined during
344//          allocation.
345// arg3:    Unused.
346//
347// Results:
348// arg1-6:  Unused.
349constexpr uint32_t kRpcFunctionIdFreeMemory = 0x2;
350DEFINE_SMC_RESULT_STRUCT(RpcFunctionFreeMemoryArgs, 3,
351                         int32_t, status,
352                         uint32_t, mem_id_upper32,
353                         uint32_t, mem_id_lower32)
354DEFINE_RPC_RESULT_STRUCT(RpcFunctionFreeMemoryResult, 0)
355
356//
357// Deliver IRQ (0x0004)
358//
359// Deliver an IRQ to the rich environment.
360//
361// Parameters:
362// arg1-3:  Unused.
363//
364// Results:
365// arg1-6:  Unused.
366constexpr uint32_t kRpcFunctionIdDeliverIrq = 0x4;
367DEFINE_SMC_RESULT_STRUCT(RpcFunctionDeliverIrqArgs, 1,
368                         int32_t, status)
369DEFINE_RPC_RESULT_STRUCT(RpcFunctionDeliverIrqResult, 0)
370
371//
372// Execute Command (0x0004)
373//
374// Execute a command specified in the provided message.
375//
376// Parameters:
377// arg1-2:  The upper (arg1) and lower (arg2) 32-bit parts of a 64-bit identifier for the command
378//          message. The value of the identifier is implementation-defined and determined during
379//          allocation.
380// arg3:    Unused.
381//
382// Results:
383// arg1-6:  Unused.
384constexpr uint32_t kRpcFunctionIdExecuteCommand = 0x5;
385DEFINE_SMC_RESULT_STRUCT(RpcFunctionExecuteCommandsArgs, 3,
386                         int32_t, status,
387                         uint32_t, msg_mem_id_upper32,
388                         uint32_t, msg_mem_id_lower32)
389DEFINE_RPC_RESULT_STRUCT(RpcFunctionExecuteCommandsResult, 0)
390
391typedef union {
392    CallWithArgResult generic;
393    RpcFunctionAllocateMemoryArgs allocate_memory;
394    RpcFunctionFreeMemoryArgs free_memory;
395    RpcFunctionDeliverIrqArgs deliver_irq;
396    RpcFunctionExecuteCommandsArgs execute_command;
397} RpcFunctionArgs;
398
399typedef union {
400    zx_smc_parameters_t generic;
401    RpcFunctionAllocateMemoryResult allocate_memory;
402    RpcFunctionFreeMemoryResult free_memory;
403    RpcFunctionDeliverIrqResult delivery_irq;
404    RpcFunctionExecuteCommandsResult execute_command;
405} RpcFunctionResult;
406
407enum SharedMemoryType : uint64_t {
408    // Memory that can be shared with a userspace application
409    kApplication = 0x0,
410
411    // Memory that can only be shared with the "kernel"
412    // "Kernel" means access up to the driver but not the userspace application, but does not
413    // translate strictly to "kernel space only" due to the microkernel nature of Zircon in Fuchsia.
414    kKernel = 0x1,
415
416    // Memory that is shared with "kernel" but can be exported to userspace
417    // "Kernel" means access up to the driver but not the userspace application, but does not
418    // translate strictly to "kernel space only" due to the microkernel nature of Zircon in Fuchsia.
419    kGlobal = 0x2
420};
421
422} // namespace optee
423