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#include <inttypes.h> 6#include <string.h> 7 8#include <ddk/binding.h> 9#include <ddk/debug.h> 10#include <ddk/device.h> 11#include <ddk/io-buffer.h> 12#include <fbl/alloc_checker.h> 13#include <fbl/auto_lock.h> 14#include <fbl/limits.h> 15#include <fbl/unique_ptr.h> 16 17#include "optee-client.h" 18#include "optee-controller.h" 19 20namespace optee { 21 22static bool IsOpteeApi(const tee::TrustedOsCallUidResult& returned_uid) { 23 return returned_uid.uid_0_3 == kOpteeApiUid_0 && 24 returned_uid.uid_4_7 == kOpteeApiUid_1 && 25 returned_uid.uid_8_11 == kOpteeApiUid_2 && 26 returned_uid.uid_12_15 == kOpteeApiUid_3; 27} 28 29static bool IsOpteeApiRevisionSupported(const tee::TrustedOsCallRevisionResult& returned_rev) { 30 // The cast is unfortunately necessary to mute a compiler warning about an unsigned expression 31 // always being greater than 0. 32 ZX_DEBUG_ASSERT(returned_rev.minor <= fbl::numeric_limits<int32_t>::max()); 33 return returned_rev.major == kOpteeApiRevisionMajor && 34 static_cast<int32_t>(returned_rev.minor) >= static_cast<int32_t>(kOpteeApiRevisionMinor); 35} 36 37zx_status_t OpteeController::ValidateApiUid() const { 38 static const zx_smc_parameters_t kGetApiFuncCall = tee::CreateSmcFunctionCall( 39 tee::kTrustedOsCallUidFuncId); 40 union { 41 zx_smc_result_t raw; 42 tee::TrustedOsCallUidResult uid; 43 } result; 44 zx_status_t status = zx_smc_call(secure_monitor_, &kGetApiFuncCall, &result.raw); 45 46 return status == ZX_OK 47 ? IsOpteeApi(result.uid) ? ZX_OK : ZX_ERR_NOT_FOUND 48 : status; 49} 50 51zx_status_t OpteeController::ValidateApiRevision() const { 52 static const zx_smc_parameters_t kGetApiRevisionFuncCall = tee::CreateSmcFunctionCall( 53 tee::kTrustedOsCallRevisionFuncId); 54 union { 55 zx_smc_result_t raw; 56 tee::TrustedOsCallRevisionResult revision; 57 } result; 58 zx_status_t status = zx_smc_call(secure_monitor_, &kGetApiRevisionFuncCall, &result.raw); 59 60 return status == ZX_OK 61 ? IsOpteeApiRevisionSupported(result.revision) ? ZX_OK : ZX_ERR_NOT_SUPPORTED 62 : status; 63} 64 65zx_status_t OpteeController::GetOsRevision() { 66 static const zx_smc_parameters_t kGetOsRevisionFuncCall = tee::CreateSmcFunctionCall( 67 kGetOsRevisionFuncId); 68 union { 69 zx_smc_result_t raw; 70 GetOsRevisionResult revision; 71 } result; 72 zx_status_t status = zx_smc_call(secure_monitor_, &kGetOsRevisionFuncCall, &result.raw); 73 74 if (status != ZX_OK) { 75 return status; 76 } 77 78 os_revision_.major = result.revision.major; 79 os_revision_.minor = result.revision.minor; 80 81 return ZX_OK; 82} 83 84zx_status_t OpteeController::ExchangeCapabilities() { 85 uint64_t nonsecure_world_capabilities = 0; 86 if (zx_system_get_num_cpus() == 1) { 87 nonsecure_world_capabilities |= kNonSecureCapUniprocessor; 88 } 89 90 const zx_smc_parameters_t func_call = tee::CreateSmcFunctionCall(kExchangeCapabilitiesFuncId, 91 nonsecure_world_capabilities); 92 union { 93 zx_smc_result_t raw; 94 ExchangeCapabilitiesResult response; 95 } result; 96 97 zx_status_t status = zx_smc_call(secure_monitor_, &func_call, &result.raw); 98 99 if (status != ZX_OK) { 100 return status; 101 } 102 103 if (result.response.status != kReturnOk) { 104 return ZX_ERR_INTERNAL; 105 } 106 107 secure_world_capabilities_ = result.response.secure_world_capabilities; 108 109 return ZX_OK; 110} 111 112zx_status_t OpteeController::InitializeSharedMemory() { 113 zx_paddr_t shared_mem_start; 114 size_t shared_mem_size; 115 zx_status_t status = DiscoverSharedMemoryConfig(&shared_mem_start, &shared_mem_size); 116 117 if (status != ZX_OK) { 118 zxlogf(ERROR, "optee: Unable to discover shared memory configuration\n"); 119 return status; 120 } 121 122 fbl::AllocChecker ac; 123 auto secure_world_memory = fbl::make_unique_checked<io_buffer_t>(&ac); 124 if (!ac.check()) { 125 return ZX_ERR_NO_MEMORY; 126 } 127 128 // The Secure World memory is located at a fixed physical address in RAM, so we have to request 129 // the platform device map the physical vmo for us. 130 // TODO(rjascani): This currently maps the entire range of the Secure OS memory because pdev 131 // doesn't currently have a way of only mapping a portion of it. OP-TEE tells us exactly the 132 // physical sub range to use. 133 static constexpr uint32_t kSecureWorldMemoryMmioIndex = 0; 134 status = pdev_map_mmio_buffer(&pdev_proto_, kSecureWorldMemoryMmioIndex, ZX_CACHE_POLICY_CACHED, 135 secure_world_memory.get()); 136 if (status != ZX_OK) { 137 zxlogf(ERROR, "optee: Unable to map secure world memory\n"); 138 return status; 139 } 140 141 status = SharedMemoryManager::Create(shared_mem_start, 142 shared_mem_size, 143 fbl::move(secure_world_memory), 144 &shared_memory_manager_); 145 146 if (status != ZX_OK) { 147 zxlogf(ERROR, "optee: Unable to initialaze SharedMemoryManager\n"); 148 return status; 149 } 150 151 return status; 152} 153 154zx_status_t OpteeController::DiscoverSharedMemoryConfig(zx_paddr_t* out_start_addr, 155 size_t* out_size) { 156 157 static const zx_smc_parameters_t func_call = tee::CreateSmcFunctionCall( 158 kGetSharedMemConfigFuncId); 159 160 union { 161 zx_smc_result_t raw; 162 GetSharedMemConfigResult response; 163 } result; 164 165 zx_status_t status = zx_smc_call(secure_monitor_, &func_call, &result.raw); 166 167 if (status != ZX_OK) { 168 return status; 169 } 170 171 if (result.response.status != kReturnOk) { 172 return ZX_ERR_INTERNAL; 173 } 174 175 *out_start_addr = result.response.start; 176 *out_size = result.response.size; 177 178 return status; 179} 180 181zx_status_t OpteeController::Bind() { 182 zx_status_t status = ZX_ERR_INTERNAL; 183 184 status = device_get_protocol(parent(), ZX_PROTOCOL_PLATFORM_DEV, &pdev_proto_); 185 if (status != ZX_OK) { 186 zxlogf(ERROR, "optee: Unable to get pdev protocol\n"); 187 return status; 188 } 189 190 // TODO(rjascani): Replace this with a real secure monitor only resource 191 secure_monitor_ = get_root_resource(); 192 193 // TODO(MTWN-140): Remove this once we have a tee core driver that will discover the TEE OS 194 status = ValidateApiUid(); 195 if (status != ZX_OK) { 196 zxlogf(ERROR, "optee: API UID does not match\n"); 197 return status; 198 } 199 200 status = ValidateApiRevision(); 201 if (status != ZX_OK) { 202 zxlogf(ERROR, "optee: API revision not supported\n"); 203 return status; 204 } 205 206 status = GetOsRevision(); 207 if (status != ZX_OK) { 208 zxlogf(ERROR, "optee: Unable to get Trusted OS revision\n"); 209 return status; 210 } 211 212 status = ExchangeCapabilities(); 213 if (status != ZX_OK) { 214 zxlogf(ERROR, "optee: Could not exchange capabilities\n"); 215 return status; 216 } 217 218 status = InitializeSharedMemory(); 219 if (status != ZX_OK) { 220 zxlogf(ERROR, "optee: Could not initialize shared memory\n"); 221 return status; 222 } 223 224 status = DdkAdd("optee-tz"); 225 if (status != ZX_OK) { 226 zxlogf(ERROR, "optee: Failed to add device\n"); 227 return status; 228 } 229 230 return status; 231} 232 233zx_status_t OpteeController::DdkOpen(zx_device_t** out_dev, uint32_t flags) { 234 // Create a new OpteeClient device and hand off client communication to it. 235 fbl::AllocChecker ac; 236 auto client = fbl::make_unique_checked<OpteeClient>(&ac, this); 237 238 if (!ac.check()) { 239 return ZX_ERR_NO_MEMORY; 240 } 241 242 zx_status_t status = client->DdkAdd("optee-client", DEVICE_ADD_INSTANCE); 243 if (status != ZX_OK) { 244 return status; 245 } 246 247 // devmgr is now in charge of the memory for the tee client 248 OpteeClient* client_ptr = client.release(); 249 *out_dev = client_ptr->zxdev(); 250 251 AddClient(client_ptr); 252 253 return ZX_OK; 254} 255 256void OpteeController::AddClient(OpteeClient* client) { 257 fbl::AutoLock lock(&clients_lock_); 258 clients_.push_back(client); 259} 260 261void OpteeController::CloseClients() { 262 fbl::AutoLock lock(&clients_lock_); 263 for (auto& client : clients_) { 264 client.MarkForClosing(); 265 } 266} 267 268void OpteeController::DdkUnbind() { 269 CloseClients(); 270 // Unpublish our device node. 271 DdkRemove(); 272} 273 274void OpteeController::DdkRelease() { 275 // devmgr has given up ownership, so we must clean ourself up. 276 delete this; 277} 278 279zx_status_t OpteeController::GetDescription(tee_ioctl_description_t* out_description, 280 size_t* out_size) const { 281 // The OP-TEE UUID does not vary and since we validated that the TEE is OP-TEE by checking 282 // the API UID, we can skip the OS UUID SMC call and just return the static UUID. 283 ::memcpy(out_description->os_uuid, &kOpteeOsUuid, TEE_IOCTL_UUID_SIZE); 284 out_description->os_revision = os_revision_; 285 out_description->is_global_platform_compliant = true; 286 287 *out_size = sizeof(*out_description); 288 289 return ZX_OK; 290} 291 292void OpteeController::RemoveClient(OpteeClient* client) { 293 fbl::AutoLock lock(&clients_lock_); 294 ZX_DEBUG_ASSERT(client != nullptr); 295 if (client->InContainer()) { 296 clients_.erase(*client); 297 } 298} 299 300uint32_t OpteeController::CallWithMessage(const Message& message, 301 RpcHandler rpc_handler) { 302 uint32_t return_value = tee::kSmc32ReturnUnknownFunction; 303 union { 304 zx_smc_parameters_t params; 305 RpcFunctionResult rpc_result; 306 } func_call; 307 func_call.params = tee::CreateSmcFunctionCall( 308 optee::kCallWithArgFuncId, 309 static_cast<uint32_t>(message.paddr() >> 32), 310 static_cast<uint32_t>(message.paddr())); 311 312 while (true) { 313 union { 314 zx_smc_result_t raw; 315 CallWithArgResult response; 316 RpcFunctionArgs rpc_args; 317 } result; 318 319 zx_status_t status = zx_smc_call(secure_monitor_, &func_call.params, &result.raw); 320 if (status != ZX_OK) { 321 zxlogf(ERROR, "optee: unable to invoke SMC\n"); 322 return return_value; 323 } 324 325 if (result.response.status == kReturnEThreadLimit) { 326 // TODO(rjascani): This should actually block until a thread is available. For now, 327 // just quit. 328 zxlogf(ERROR, "optee: hit thread limit, need to fix this\n"); 329 break; 330 } else if (optee::IsReturnRpc(result.response.status)) { 331 // TODO(godtamit): Remove this when all of RPC is implemented 332 zxlogf(INFO, 333 "optee: rpc call: %" PRIx32 " arg1: %" PRIx32 334 " arg2: %" PRIx32 " arg3: %" PRIx32 "\n", 335 result.response.status, 336 result.response.arg1, 337 result.response.arg2, 338 result.response.arg3); 339 status = rpc_handler(result.rpc_args, &func_call.rpc_result); 340 341 // TODO(godtamit): Re-evaluate whether ZX_DEBUG_ASSERT is necessary once all supported 342 // RPC commands are implemented 343 // 344 // Crash if we run into unsupported functionality 345 // Otherwise, if status != ZX_OK, we can still call the TEE with the response and let it 346 // clean up on its end. 347 ZX_DEBUG_ASSERT(status != ZX_ERR_NOT_SUPPORTED); 348 } else { 349 return_value = result.response.status; 350 break; 351 } 352 } 353 354 // TODO(godtamit): Remove after all of RPC is implemented 355 zxlogf(INFO, "optee: CallWithMessage returning %i\n", return_value); 356 return return_value; 357} 358} // namespace optee 359 360extern "C" zx_status_t optee_bind(void* ctx, zx_device_t* parent) { 361 fbl::AllocChecker ac; 362 auto tee = fbl::make_unique_checked<::optee::OpteeController>(&ac, parent); 363 364 if (!ac.check()) { 365 return ZX_ERR_NO_MEMORY; 366 } 367 368 auto status = tee->Bind(); 369 if (status == ZX_OK) { 370 // devmgr is now in charge of the memory for tee 371 __UNUSED auto ptr = tee.release(); 372 } 373 374 return status; 375} 376