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