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 <inttypes.h>
8
9#include <zircon/syscalls/smc.h>
10
11#define __DEFINE_SMC_RESULT_ARG_4(type0, name0, type1, name1, type2, name2, type3, name3) \
12    alignas(alignof(decltype(zx_smc_result_t::arg0))) type0 name0;                        \
13    alignas(alignof(decltype(zx_smc_result_t::arg1))) type1 name1;                        \
14    alignas(alignof(decltype(zx_smc_result_t::arg2))) type2 name2;                        \
15    alignas(alignof(decltype(zx_smc_result_t::arg3))) type3 name3;
16
17#define __DEFINE_SMC_RESULT_ARG_3(...) \
18    __DEFINE_SMC_RESULT_ARG_4(__VA_ARGS__, uint64_t, unused3)
19
20#define __DEFINE_SMC_RESULT_ARG_2(...) \
21    __DEFINE_SMC_RESULT_ARG_3(__VA_ARGS__, uint64_t, unused2)
22
23#define __DEFINE_SMC_RESULT_ARG_1(...) \
24    __DEFINE_SMC_RESULT_ARG_2(__VA_ARGS__, uint64_t, unused1)
25
26#define __CHECK_SMC_RESULT_OFFSETS_ARG_4(result_type, _0, name0, _1, name1, _2, name2, _3, name3) \
27    static_assert(offsetof(result_type, name0) == offsetof(zx_smc_result_t, arg0),                \
28                  "name0 is not aligned with the offset of zx_smc_result_t::arg0");               \
29    static_assert(offsetof(result_type, name1) == offsetof(zx_smc_result_t, arg1),                \
30                  "name1 is not aligned with the offset of zx_smc_result_t::arg1");               \
31    static_assert(offsetof(result_type, name2) == offsetof(zx_smc_result_t, arg2),                \
32                  "name2 is not aligned with the offset of zx_smc_result_t::arg2");               \
33    static_assert(offsetof(result_type, name3) == offsetof(zx_smc_result_t, arg3),                \
34                  "name3 is not aligned with the offset of zx_smc_result_t::arg3");
35
36#define __CHECK_SMC_RESULT_OFFSETS_ARG_3(...) \
37    __CHECK_SMC_RESULT_OFFSETS_ARG_4(__VA_ARGS__, uint64_t, unused3)
38
39#define __CHECK_SMC_RESULT_OFFSETS_ARG_2(...) \
40    __CHECK_SMC_RESULT_OFFSETS_ARG_3(__VA_ARGS__, uint64_t, unused2)
41
42#define __CHECK_SMC_RESULT_OFFSETS_ARG_1(...) \
43    __CHECK_SMC_RESULT_OFFSETS_ARG_2(__VA_ARGS__, uint64_t, unused1)
44
45// Helper macro for defining a struct that is intended to overlay with a zx_smc_result_t. The
46// zx_smc_result_t has four uint64_t members that are read from registers x0-x3 on the SMC return,
47// but the values returned could actually int64_t, int32_t or uint32_t. It is dependent on the SMC
48// function that was invoked and the return code in x0. The macro allows for the definition of up
49// to four members within the result type that should align with arg0-arg3. For examples, see the
50// usages later in this file.
51//
52// Parameters:
53// result_type - Name of the type to be defined
54// num_members - Number of data members in the type to be defined
55// ... - List of types and names for the data members (see examples below)
56#define DEFINE_SMC_RESULT_STRUCT(result_type, num_members, ...)                               \
57    static_assert(num_members > 0, "SMC result structure must have more than 0 members");     \
58    static_assert(num_members <= 4, "SMC result structure must have no more than 4 members"); \
59    struct result_type {                                                                      \
60        __DEFINE_SMC_RESULT_ARG_##num_members(__VA_ARGS__)                                    \
61    };                                                                                        \
62    static_assert(sizeof(result_type) == sizeof(zx_smc_result_t),                             \
63                  "result_type must be the same size of zx_smc_result_t");                    \
64    __CHECK_SMC_RESULT_OFFSETS_ARG_##num_members(result_type, __VA_ARGS__)
65
66namespace tee {
67
68enum CallType : uint8_t {
69    kYieldingCall = 0,
70    kFastCall = 1,
71};
72
73enum CallConvention : uint8_t {
74    kSmc32CallConv = 0,
75    kSmc64CallConv = 1,
76};
77
78enum Service : uint8_t {
79    kArchService = 0x00,
80    kCpuService = 0x01,
81    kSipService = 0x02,
82    kOemService = 0x03,
83    kStandardService = 0x04,
84    kTrustedOsService = 0x32,
85    kTrustedOsServiceEnd = 0x3F,
86};
87
88constexpr uint8_t kCallTypeMask = 0x01;
89constexpr uint8_t kCallTypeShift = 31;
90constexpr uint8_t kCallConvMask = 0x01;
91constexpr uint8_t kCallConvShift = 30;
92constexpr uint8_t kServiceMask = 0x3F;
93constexpr uint8_t kServiceShift = 24;
94
95constexpr uint64_t kSmc64ReturnUnknownFunction = static_cast<uint64_t>(-1);
96constexpr uint32_t kSmc32ReturnUnknownFunction = static_cast<uint32_t>(-1);
97
98static constexpr uint32_t CreateFunctionId(CallType call_type,
99                                           CallConvention call_conv,
100                                           Service service,
101                                           uint16_t function_num) {
102    return (((call_type & kCallTypeMask) << kCallTypeShift) |
103            ((call_conv & kCallConvMask) << kCallConvShift) |
104            ((service & kServiceMask) << kServiceShift) |
105            function_num);
106}
107
108// C++ wrapper function for constructing a zx_smc_parameters_t object. Most of the arguments are
109// rarely used, so this defaults everything other than the function id to 0. Most of the function
110// calls are also constant, so they should be populated at compile time if possible.
111static constexpr zx_smc_parameters_t CreateSmcFunctionCall(
112    uint32_t func_id,
113    uint64_t arg1 = 0, uint64_t arg2 = 0, uint64_t arg3 = 0,
114    uint64_t arg4 = 0, uint64_t arg5 = 0, uint64_t arg6 = 0,
115    uint16_t client_id = 0, uint16_t secure_os_id = 0) {
116    return {func_id, arg1, arg2, arg3, arg4, arg5, arg6, client_id, secure_os_id};
117}
118
119//
120// Call Count Query (0xFF00)
121//
122// Returns a 32-bit count of the available service calls. The count includes both 32 and 64
123// calling convention service calls and both fast and yielding calls.
124//
125// Parameters:
126// arg1..arg6 - not used
127//
128// Results:
129// arg0 - call count
130// arg1..arg3 - not used
131constexpr uint32_t kTrustedOsCallCountFuncId = CreateFunctionId(kFastCall,
132                                                                kSmc32CallConv,
133                                                                kTrustedOsServiceEnd,
134                                                                0xFF00);
135
136DEFINE_SMC_RESULT_STRUCT(TrustedOsCallCountResult, 1, uint32_t, call_count);
137
138//
139// Call UID Query (0xFF01)
140//
141// Returns a unique identifier of the service provider.
142//
143// Parameters:
144// arg1..arg6 - not used
145//
146// Results:
147// arg0 - UID Bytes 0:3
148// arg1 - UID Bytes 4:7
149// arg2 - UID Bytes 8:11
150// arg3 - UID Bytes 12:15
151constexpr uint32_t kTrustedOsCallUidFuncId = CreateFunctionId(kFastCall,
152                                                              kSmc32CallConv,
153                                                              kTrustedOsServiceEnd,
154                                                              0xFF01);
155
156DEFINE_SMC_RESULT_STRUCT(TrustedOsCallUidResult, 4,
157                         uint32_t, uid_0_3,
158                         uint32_t, uid_4_7,
159                         uint32_t, uid_8_11,
160                         uint32_t, uid_12_15);
161
162//
163// Call Revision Query (0xFF03)
164//
165// Returns revision details of the service. Different major version values indicate a possible
166// incompatibility between SMC/HVC APIs, for the affected range.
167//
168// For two revisions, A and B, where the major version values are identical, and the minor version
169// value of revision B is greater than the minor version value of revision B, every SMC/HVC
170// instruction in the affected range that works in revision A must also work in revision B, with a
171// compatible effect.
172//
173// Parameters:
174// arg1..arg6 - not used
175//
176// Results:
177// arg0 - major version
178// arg1 - minor version
179// arg2..3 - not used
180constexpr uint32_t kTrustedOsCallRevisionFuncId = CreateFunctionId(kFastCall,
181                                                                   kSmc32CallConv,
182                                                                   kTrustedOsServiceEnd,
183                                                                   0xFF03);
184
185DEFINE_SMC_RESULT_STRUCT(TrustedOsCallRevisionResult, 2,
186                         uint32_t, major,
187                         uint32_t, minor);
188
189} // namespace tee
190