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