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 <ddk/debug.h> 6#include <fbl/string_buffer.h> 7#include <fbl/string_piece.h> 8#include <fbl/type_support.h> 9#include <lib/zx/vmo.h> 10#include <tee-client-api/tee-client-types.h> 11 12#include "optee-client.h" 13#include "optee-smc.h" 14 15namespace { 16// RFC 4122 specification dictates a UUID is of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 17constexpr const char* kUuidNameFormat = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; 18constexpr size_t kUuidNameLength = 36; 19 20constexpr const char kFirmwarePathPrefix[] = "/boot/lib/firmware/"; 21constexpr const char kTaFileExtension[] = ".ta"; 22 23// The length of a path to a trusted app consists of the path prefix, the UUID, and file extension 24// Subtracting 1 from sizeof(char[])s to account for the terminating null character. 25constexpr size_t kTaPathLength = (sizeof(kFirmwarePathPrefix) - 1u) + 26 kUuidNameLength + 27 (sizeof(kTaFileExtension) - 1u); 28 29template <typename SRC_T, typename DST_T> 30static constexpr typename fbl::enable_if< 31 fbl::is_unsigned_integer<SRC_T>::value && 32 fbl::is_unsigned_integer<DST_T>::value>::type 33SplitInto32BitParts(SRC_T src, DST_T* dst_hi, DST_T* dst_lo) { 34 static_assert(sizeof(SRC_T) == 8, "Type SRC_T should be 64 bits!"); 35 static_assert(sizeof(DST_T) >= 4, "Type DST_T should be at least 32 bits!"); 36 ZX_DEBUG_ASSERT(dst_hi != nullptr); 37 ZX_DEBUG_ASSERT(dst_lo != nullptr); 38 *dst_hi = static_cast<DST_T>(src >> 32); 39 *dst_lo = static_cast<DST_T>(static_cast<uint32_t>(src)); 40} 41 42template <typename SRC_T, typename DST_T> 43static constexpr typename fbl::enable_if< 44 fbl::is_unsigned_integer<SRC_T>::value && 45 fbl::is_unsigned_integer<DST_T>::value>::type 46JoinFrom32BitParts(SRC_T src_hi, SRC_T src_lo, DST_T* dst) { 47 static_assert(sizeof(SRC_T) >= 4, "Type SRC_T should be at least 32 bits!"); 48 static_assert(sizeof(DST_T) >= 8, "Type DST_T should be at least 64-bits!"); 49 ZX_DEBUG_ASSERT(dst != nullptr); 50 *dst = (static_cast<DST_T>(src_hi) << 32) | static_cast<DST_T>(static_cast<uint32_t>(src_lo)); 51} 52 53// Builds a UUID string from a TEEC_UUID, formatting as per the RFC 4122 specification. 54static fbl::StringBuffer<kUuidNameLength> BuildUuidString(const TEEC_UUID& ta_uuid) { 55 fbl::StringBuffer<kUuidNameLength> buf; 56 57 buf.AppendPrintf(kUuidNameFormat, 58 ta_uuid.timeLow, 59 ta_uuid.timeMid, 60 ta_uuid.timeHiAndVersion, 61 ta_uuid.clockSeqAndNode[0], 62 ta_uuid.clockSeqAndNode[1], 63 ta_uuid.clockSeqAndNode[2], 64 ta_uuid.clockSeqAndNode[3], 65 ta_uuid.clockSeqAndNode[4], 66 ta_uuid.clockSeqAndNode[5], 67 ta_uuid.clockSeqAndNode[6], 68 ta_uuid.clockSeqAndNode[7]); 69 return buf; 70} 71 72// Builds the expected path to a trusted application, given its UUID string. 73static fbl::StringBuffer<kTaPathLength> BuildTaPath(const fbl::StringPiece& uuid_str) { 74 fbl::StringBuffer<kTaPathLength> buf; 75 76 buf.Append(kFirmwarePathPrefix); 77 buf.Append(uuid_str); 78 buf.Append(kTaFileExtension); 79 80 return buf; 81} 82}; // namespace 83 84namespace optee { 85zx_status_t OpteeClient::DdkClose(uint32_t flags) { 86 controller_->RemoveClient(this); 87 return ZX_OK; 88} 89 90void OpteeClient::DdkRelease() { 91 // devmgr has given up ownership, so we must clean ourself up. 92 delete this; 93} 94 95zx_status_t OpteeClient::DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, void* out_buf, 96 size_t out_len, size_t* out_actual) { 97 if (needs_to_close_) { 98 return ZX_ERR_PEER_CLOSED; 99 } 100 101 switch (op) { 102 case IOCTL_TEE_GET_DESCRIPTION: { 103 if ((out_buf == nullptr) || (out_len != sizeof(tee_ioctl_description_t)) || 104 (out_actual == nullptr)) { 105 return ZX_ERR_INVALID_ARGS; 106 } 107 108 return controller_->GetDescription(reinterpret_cast<tee_ioctl_description_t*>(out_buf), 109 out_actual); 110 } 111 case IOCTL_TEE_OPEN_SESSION: { 112 if ((in_buf == nullptr) || (in_len != sizeof(tee_ioctl_session_request_t)) || 113 (out_buf == nullptr) || (out_len != sizeof(tee_ioctl_session_t)) || 114 (out_actual == nullptr)) { 115 return ZX_ERR_INVALID_ARGS; 116 } 117 118 return OpenSession(reinterpret_cast<const tee_ioctl_session_request_t*>(in_buf), 119 reinterpret_cast<tee_ioctl_session_t*>(out_buf), 120 out_actual); 121 } 122 } 123 124 return ZX_ERR_NOT_SUPPORTED; 125} 126 127zx_status_t OpteeClient::OpenSession(const tee_ioctl_session_request_t* session_request, 128 tee_ioctl_session_t* out_session, 129 size_t* out_actual) { 130 ZX_DEBUG_ASSERT(session_request != nullptr); 131 ZX_DEBUG_ASSERT(out_session != nullptr); 132 ZX_DEBUG_ASSERT(out_actual != nullptr); 133 *out_actual = 0; 134 135 UuidView trusted_app{session_request->trusted_app, TEE_IOCTL_UUID_SIZE}; 136 UuidView client_app{session_request->client_app, TEE_IOCTL_UUID_SIZE}; 137 138 fbl::Array<MessageParam> params; 139 zx_status_t status = ConvertIoctlParamsToOpteeParams(session_request->params, 140 session_request->num_params, 141 ¶ms); 142 if (status != ZX_OK) { 143 zxlogf(ERROR, "optee: invalid ioctl parameters\n"); 144 out_session->return_code = TEEC_ERROR_BAD_PARAMETERS; 145 out_session->return_origin = TEEC_ORIGIN_COMMS; 146 return status; 147 } 148 149 OpenSessionMessage message(controller_->driver_pool(), 150 trusted_app, 151 client_app, 152 session_request->client_login, 153 session_request->cancel_id, 154 params); 155 156 *out_actual = sizeof(*out_session); 157 uint32_t call_code = 158 controller_->CallWithMessage(message, fbl::BindMember(this, &OpteeClient::HandleRpc)); 159 if (call_code != kReturnOk) { 160 out_session->return_code = TEEC_ERROR_COMMUNICATION; 161 out_session->return_origin = TEEC_ORIGIN_COMMS; 162 return status; 163 } 164 165 // TODO(rjascani): Create session object from session id 166 out_session->session_id = message.session_id(); 167 out_session->return_code = message.return_code(); 168 out_session->return_origin = message.return_origin(); 169 // TODO(godtamit): Remove this when all of RPC is implemented 170 zxlogf(INFO, 171 "session ID is 0x%x, return code is 0x%x, return origin is 0x%x\n", 172 out_session->session_id, 173 out_session->return_code, 174 out_session->return_origin); 175 176 return ZX_OK; 177} 178 179zx_status_t OpteeClient::ConvertIoctlParamsToOpteeParams( 180 const tee_ioctl_param_t* params, 181 size_t num_params, 182 fbl::Array<MessageParam>* out_optee_params) { 183 ZX_DEBUG_ASSERT(params != nullptr); 184 ZX_DEBUG_ASSERT(out_optee_params != nullptr); 185 186 fbl::Array<MessageParam> optee_params(new MessageParam[num_params], num_params); 187 188 for (size_t i = 0; i < num_params; ++i) { 189 const tee_ioctl_param_t& ioctl_param = params[i]; 190 MessageParam& optee_param = optee_params[i]; 191 192 switch (ioctl_param.type) { 193 case TEE_PARAM_TYPE_NONE: 194 optee_param.attribute = MessageParam::kAttributeTypeNone; 195 optee_param.payload.value.generic.a = 0; 196 optee_param.payload.value.generic.b = 0; 197 optee_param.payload.value.generic.c = 0; 198 break; 199 case TEE_PARAM_TYPE_VALUE_INPUT: 200 optee_param.attribute = MessageParam::kAttributeTypeValueInput; 201 optee_param.payload.value.generic.a = ioctl_param.a; 202 optee_param.payload.value.generic.b = ioctl_param.b; 203 optee_param.payload.value.generic.c = ioctl_param.c; 204 break; 205 case TEE_PARAM_TYPE_VALUE_OUTPUT: 206 optee_param.attribute = MessageParam::kAttributeTypeValueOutput; 207 optee_param.payload.value.generic.a = ioctl_param.a; 208 optee_param.payload.value.generic.b = ioctl_param.b; 209 optee_param.payload.value.generic.c = ioctl_param.c; 210 break; 211 case TEE_PARAM_TYPE_VALUE_INOUT: 212 optee_param.attribute = MessageParam::kAttributeTypeValueInOut; 213 optee_param.payload.value.generic.a = ioctl_param.a; 214 optee_param.payload.value.generic.b = ioctl_param.b; 215 optee_param.payload.value.generic.c = ioctl_param.c; 216 break; 217 case TEE_PARAM_TYPE_MEMREF_INPUT: 218 case TEE_PARAM_TYPE_MEMREF_OUTPUT: 219 case TEE_PARAM_TYPE_MEMREF_INOUT: 220 // TODO(rjascani): Add support for memory references 221 return ZX_ERR_NOT_SUPPORTED; 222 break; 223 default: 224 return ZX_ERR_INVALID_ARGS; 225 } 226 } 227 228 *out_optee_params = fbl::move(optee_params); 229 return ZX_OK; 230} 231 232template <typename SharedMemoryPoolTraits> 233zx_status_t OpteeClient::AllocateSharedMemory(size_t size, 234 SharedMemoryPool<SharedMemoryPoolTraits>* memory_pool, 235 zx_paddr_t* out_phys_addr, 236 uint64_t* out_mem_id) { 237 ZX_DEBUG_ASSERT(memory_pool != nullptr); 238 ZX_DEBUG_ASSERT(out_phys_addr != nullptr); 239 ZX_DEBUG_ASSERT(out_mem_id != nullptr); 240 241 // Set these to 0 and overwrite, if necessary, on success path 242 *out_phys_addr = 0; 243 *out_mem_id = 0; 244 245 if (size == 0) { 246 return ZX_ERR_INVALID_ARGS; 247 } 248 249 fbl::unique_ptr<SharedMemory> sh_mem; 250 zx_status_t status = memory_pool->Allocate(size, &sh_mem); 251 if (status != ZX_OK) { 252 return status; 253 } 254 255 *out_phys_addr = sh_mem->paddr(); 256 257 // Track the new piece of allocated SharedMemory in the list 258 allocated_shared_memory_.push_back(fbl::move(sh_mem)); 259 260 // TODO(godtamit): Move away from memory addresses as memory identifiers 261 // 262 // Make the memory identifier the address of the SharedMemory object 263 auto sh_mem_addr = reinterpret_cast<uintptr_t>(&allocated_shared_memory_.back()); 264 *out_mem_id = static_cast<uint64_t>(sh_mem_addr); 265 266 // TODO(godtamit): Remove when all RPC is done 267 zxlogf(INFO, 268 "optee: allocated shared memory at physical addr 0x%" PRIuPTR 269 " with id 0x%" PRIu64 "\n", 270 *out_phys_addr, 271 *out_mem_id); 272 273 return status; 274} 275 276zx_status_t OpteeClient::FreeSharedMemory(uint64_t mem_id) { 277 // Check if client owns memory that matches the memory id 278 SharedMemoryList::iterator mem_iter = FindSharedMemory(mem_id); 279 if (mem_iter == allocated_shared_memory_.end()) { 280 return ZX_ERR_NOT_FOUND; 281 } 282 283 // Destructor of SharedMemory will automatically free block back into pool 284 // 285 // TODO(godtamit): Remove mem_to_free and logging when all of RPC is implemented 286 __UNUSED auto mem_to_free = allocated_shared_memory_.erase(mem_iter); 287 zxlogf(INFO, 288 "optee: successfully freed shared memory at phys 0x%" PRIuPTR "\n", 289 mem_to_free->paddr()); 290 291 return ZX_OK; 292} 293 294OpteeClient::SharedMemoryList::iterator OpteeClient::FindSharedMemory(uint64_t mem_id) { 295 // TODO(godtamit): Move away from memory addresses as memory identifiers 296 auto mem_id_ptr_val = static_cast<uintptr_t>(mem_id); 297 return allocated_shared_memory_.find_if( 298 [mem_id_ptr_val](auto& item) { 299 return mem_id_ptr_val == reinterpret_cast<uintptr_t>(&item); 300 }); 301} 302 303zx_status_t OpteeClient::HandleRpc(const RpcFunctionArgs& args, RpcFunctionResult* out_result) { 304 zx_status_t status; 305 uint32_t func_code = GetRpcFunctionCode(args.generic.status); 306 307 switch (func_code) { 308 case kRpcFunctionIdAllocateMemory: 309 status = HandleRpcAllocateMemory(args.allocate_memory, &out_result->allocate_memory); 310 break; 311 case kRpcFunctionIdFreeMemory: 312 status = HandleRpcFreeMemory(args.free_memory, &out_result->free_memory); 313 break; 314 case kRpcFunctionIdDeliverIrq: 315 // TODO(godtamit): Remove when all of RPC is implemented 316 zxlogf(INFO, "optee: delivering IRQ\n"); 317 // Foreign interrupt detected while in the secure world 318 // Zircon handles this so just mark the RPC as handled 319 status = ZX_OK; 320 break; 321 case kRpcFunctionIdExecuteCommand: 322 status = HandleRpcCommand(args.execute_command, &out_result->execute_command); 323 break; 324 default: 325 status = ZX_ERR_NOT_SUPPORTED; 326 break; 327 } 328 329 // Set the function to return from RPC 330 out_result->generic.func_id = optee::kReturnFromRpcFuncId; 331 332 return status; 333} 334 335zx_status_t OpteeClient::HandleRpcAllocateMemory(const RpcFunctionAllocateMemoryArgs& args, 336 RpcFunctionAllocateMemoryResult* out_result) { 337 ZX_DEBUG_ASSERT(out_result != nullptr); 338 339 zx_paddr_t paddr; 340 uint64_t mem_id; 341 342 zx_status_t status = AllocateSharedMemory(static_cast<size_t>(args.size), 343 controller_->driver_pool(), 344 &paddr, 345 &mem_id); 346 // If allocation failed, AllocateSharedMemory sets paddr and mem_id to 0. Continue with packing 347 // those values into the result regardless. 348 349 // Put the physical address of allocated memory in the args 350 SplitInto32BitParts(paddr, &out_result->phys_addr_upper32, &out_result->phys_addr_lower32); 351 352 // Pack the memory identifier in the args 353 SplitInto32BitParts(mem_id, &out_result->mem_id_upper32, &out_result->mem_id_lower32); 354 355 return status; 356} 357 358zx_status_t OpteeClient::HandleRpcFreeMemory(const RpcFunctionFreeMemoryArgs& args, 359 RpcFunctionFreeMemoryResult* out_result) { 360 ZX_DEBUG_ASSERT(out_result != nullptr); 361 362 uint64_t mem_id; 363 JoinFrom32BitParts(args.mem_id_upper32, args.mem_id_lower32, &mem_id); 364 365 return FreeSharedMemory(mem_id); 366} 367 368zx_status_t OpteeClient::HandleRpcCommand(const RpcFunctionExecuteCommandsArgs& args, 369 RpcFunctionExecuteCommandsResult* out_result) { 370 uint64_t mem_id; 371 JoinFrom32BitParts(args.msg_mem_id_upper32, args.msg_mem_id_lower32, &mem_id); 372 373 // Make sure memory where message is stored is valid 374 // This dispatcher method only checks that the memory needed for the header is valid. Commands 375 // that require more memory than just the header will need to do further memory checks. 376 SharedMemoryList::iterator mem_iter = FindSharedMemory(mem_id); 377 if (mem_iter == allocated_shared_memory_.end()) { 378 zxlogf(ERROR, "optee: invalid shared memory region passed into RPC command!\n"); 379 return ZX_ERR_INVALID_ARGS; 380 } else if (mem_iter->size() < sizeof(MessageHeader)) { 381 zxlogf(ERROR, 382 "optee: shared memory region passed into RPC command is too small\n"); 383 return ZX_ERR_INVALID_ARGS; 384 } 385 386 // Read message header from shared memory 387 SharedMemory& msg_mem = *mem_iter; 388 RpcMessage message(&msg_mem); 389 if (!message.is_valid()) { 390 return ZX_ERR_INVALID_ARGS; 391 } 392 393 switch (message.command()) { 394 case RpcMessage::Command::kLoadTa: { 395 LoadTaRpcMessage load_ta_msg(fbl::move(message)); 396 if (!load_ta_msg.is_valid()) { 397 return ZX_ERR_INVALID_ARGS; 398 } 399 return HandleRpcCommandLoadTa(&load_ta_msg); 400 } 401 case RpcMessage::Command::kAccessFileSystem: 402 zxlogf(ERROR, "optee: RPC command to access file system recognized but not implemented\n"); 403 return ZX_ERR_NOT_SUPPORTED; 404 case RpcMessage::Command::kGetTime: 405 zxlogf(ERROR, "optee: RPC command to access file system recognized but not implemented\n"); 406 return ZX_ERR_NOT_SUPPORTED; 407 case RpcMessage::Command::kWaitQueue: 408 zxlogf(ERROR, "optee: RPC command wait queue recognized but not implemented\n"); 409 return ZX_ERR_NOT_SUPPORTED; 410 case RpcMessage::Command::kSuspend: 411 zxlogf(ERROR, "optee: RPC command to suspend recognized but not implemented\n"); 412 return ZX_ERR_NOT_SUPPORTED; 413 case RpcMessage::Command::kAllocateMemory: 414 return HandleRpcCommandAllocateMemory(&message); 415 case RpcMessage::Command::kFreeMemory: 416 return HandleRpcCommandFreeMemory(&message); 417 case RpcMessage::Command::kPerformSocketIo: 418 zxlogf(ERROR, "optee: RPC command to perform socket IO recognized but not implemented\n"); 419 message.set_return_origin(TEEC_ORIGIN_COMMS); 420 message.set_return_code(TEEC_ERROR_NOT_SUPPORTED); 421 return ZX_OK; 422 case RpcMessage::Command::kAccessReplayProtectedMemoryBlock: 423 case RpcMessage::Command::kAccessSqlFileSystem: 424 case RpcMessage::Command::kLoadGprof: 425 zxlogf(INFO, "optee: received unsupported RPC command\n"); 426 message.set_return_origin(TEEC_ORIGIN_COMMS); 427 message.set_return_code(TEEC_ERROR_NOT_SUPPORTED); 428 return ZX_OK; 429 default: 430 zxlogf(ERROR, 431 "optee: unrecognized command passed to RPC 0x%" PRIu32 "\n", 432 message.command()); 433 message.set_return_origin(TEEC_ORIGIN_COMMS); 434 message.set_return_code(TEEC_ERROR_NOT_SUPPORTED); 435 return ZX_ERR_NOT_SUPPORTED; 436 } 437} 438 439zx_status_t OpteeClient::HandleRpcCommandLoadTa(LoadTaRpcMessage* message) { 440 ZX_DEBUG_ASSERT(message->is_valid()); 441 442 // Mark that the return code will originate from driver 443 message->set_return_origin(TEEC_ORIGIN_COMMS); 444 445 if (message->memory_reference_offset() >= message->memory_reference_size() && 446 message->memory_reference_offset() > 0) { 447 zxlogf(ERROR, "optee: RPC command received a memory offset out of bounds!\n"); 448 message->set_return_code(TEEC_ERROR_BAD_PARAMETERS); 449 return ZX_ERR_INVALID_ARGS; 450 } 451 452 // The amount of memory available for loading the TA 453 uint64_t mem_usable_size = message->memory_reference_size() - 454 message->memory_reference_offset(); 455 456 // Try to find the SharedMemory based on the memory id 457 uint8_t* out_ta_mem; // Where to write the TA in memory 458 459 if (message->memory_reference_id() != 0) { 460 SharedMemoryList::iterator out_mem_iter = FindSharedMemory(message->memory_reference_id()); 461 if (out_mem_iter == allocated_shared_memory_.end()) { 462 // Valid memory reference could not be found and TEE is not querying size 463 zxlogf(ERROR, 464 "optee: received invalid memory reference from TEE command to load TA!\n"); 465 message->set_return_code(TEEC_ERROR_BAD_PARAMETERS); 466 return ZX_ERR_INVALID_ARGS; 467 } else if (mem_usable_size > out_mem_iter->size()) { 468 // The TEE is claiming the memory reference given is larger than it actually is 469 // We want to catch this in case TEE is buggy 470 zxlogf(ERROR, 471 "optee: TEE claimed a memory reference's size is larger than the real memory" 472 "size!\n"); 473 message->set_return_code(TEEC_ERROR_BAD_PARAMETERS); 474 return ZX_ERR_INVALID_ARGS; 475 } 476 477 out_ta_mem = reinterpret_cast<uint8_t*>(out_mem_iter->vaddr() + 478 message->memory_reference_offset()); 479 } else { 480 // TEE is just querying size of TA, so it sent a memory identifier of 0 481 ZX_DEBUG_ASSERT(message->memory_reference_offset() == 0); 482 ZX_DEBUG_ASSERT(message->memory_reference_size() == 0); 483 484 out_ta_mem = nullptr; 485 } 486 487 auto ta_name = BuildUuidString(message->ta_uuid()); 488 auto ta_path = BuildTaPath(ta_name.ToStringPiece()); 489 490 // Load the trusted app into a VMO 491 size_t ta_size; 492 zx::vmo ta_vmo; 493 zx_status_t status = load_firmware(controller_->zxdev(), 494 ta_path.data(), 495 ta_vmo.reset_and_get_address(), 496 &ta_size); 497 498 if (status != ZX_OK) { 499 if (status == ZX_ERR_NOT_FOUND) { 500 zxlogf(ERROR, "optee: could not find trusted app %s!\n", ta_path.data()); 501 message->set_return_code(TEEC_ERROR_ITEM_NOT_FOUND); 502 } else { 503 zxlogf(ERROR, "optee: error loading trusted app %s!\n", ta_path.data()); 504 message->set_return_code(TEEC_ERROR_GENERIC); 505 } 506 507 return status; 508 } else if (ta_size == 0) { 509 zxlogf(ERROR, "optee: loaded trusted app %s with unexpected size!\n", ta_path.data()); 510 message->set_return_code(TEEC_ERROR_GENERIC); 511 return status; 512 } 513 514 message->set_output_ta_size(static_cast<uint64_t>(ta_size)); 515 516 if (out_ta_mem == nullptr) { 517 // TEE is querying the size of the TA 518 message->set_return_code(TEEC_SUCCESS); 519 return ZX_OK; 520 } else if (ta_size > mem_usable_size) { 521 // TEE provided too small of a memory region to write TA into 522 message->set_return_code(TEEC_ERROR_SHORT_BUFFER); 523 return ZX_OK; 524 } 525 526 // TODO(godtamit): in the future, we may want to register the memory as shared and use its VMO, 527 // so we don't have to do a copy of the TA 528 status = ta_vmo.read(out_ta_mem, 0, ta_size); 529 if (status != ZX_OK) { 530 zxlogf(ERROR, "optee: failed to copy trusted app from VMO to shared memory!\n"); 531 message->set_return_code(TEEC_ERROR_GENERIC); 532 return status; 533 } 534 535 if (ta_size < mem_usable_size) { 536 // Clear out the rest of the memory after the TA 537 uint8_t* ta_end = out_ta_mem + ta_size; 538 memset(ta_end, 0, mem_usable_size - ta_size); 539 } 540 541 message->set_return_code(TEEC_SUCCESS); 542 return ZX_OK; 543} 544 545zx_status_t OpteeClient::HandleRpcCommandAllocateMemory(RpcMessage* message) { 546 // Mark that the return code will originate from driver 547 message->set_return_origin(TEEC_ORIGIN_COMMS); 548 549 MessageParamList params = message->params(); 550 if (params.size() != 1) { 551 zxlogf(ERROR, 552 "optee: RPC command to allocate shared memory received a bad number of parameters!" 553 "\n"); 554 message->set_return_code(TEEC_ERROR_BAD_PARAMETERS); 555 return ZX_ERR_INVALID_ARGS; 556 } 557 558 // The first parameter outlines the specifications of the memory to be allocated 559 const MessageParam& memory_specs_param = params[0]; 560 if (memory_specs_param.attribute != MessageParam::AttributeType::kAttributeTypeValueInput) { 561 zxlogf(ERROR, 562 "optee: RPC command to allocate shared memory received an unexpected parameter type!" 563 "\n"); 564 message->set_return_code(TEEC_ERROR_BAD_PARAMETERS); 565 return ZX_ERR_INVALID_ARGS; 566 } 567 568 // The first parameter in the Message specifies what kind of memory to allocate and how much 569 auto& mem_specs = memory_specs_param.payload.value.allocate_memory_specs; 570 switch (mem_specs.memory_type) { 571 case SharedMemoryType::kApplication: 572 case SharedMemoryType::kKernel: 573 break; 574 case SharedMemoryType::kGlobal: 575 zxlogf(ERROR, "optee: implementation currently does not support global shared memory!\n"); 576 return ZX_ERR_NOT_SUPPORTED; 577 default: 578 zxlogf(ERROR, 579 "optee: cannot allocate unknown memory type %" PRIu64 "\n", mem_specs.memory_type); 580 message->set_return_code(TEEC_ERROR_BAD_PARAMETERS); 581 return ZX_ERR_INVALID_ARGS; 582 } 583 584 zx_paddr_t paddr; 585 uint64_t mem_id; 586 zx_status_t status = AllocateSharedMemory(static_cast<size_t>(mem_specs.memory_size), 587 controller_->client_pool(), 588 &paddr, 589 &mem_id); 590 if (status != ZX_OK) { 591 if (status == ZX_ERR_NO_MEMORY) { 592 message->set_return_code(TEEC_ERROR_OUT_OF_MEMORY); 593 } else { 594 message->set_return_code(TEEC_ERROR_GENERIC); 595 } 596 597 return status; 598 } 599 600 // The first parameter in the Message gets reused to output the result of the allocated memory 601 MessageParam& out_memory_result_param = params[0]; 602 out_memory_result_param.attribute = MessageParam::AttributeType::kAttributeTypeTempMemOutput; 603 604 MessageParam::TemporaryMemory& out_temp_mem = out_memory_result_param.payload.temporary_memory; 605 out_temp_mem.size = mem_specs.memory_size; 606 out_temp_mem.buffer = static_cast<uint64_t>(paddr); 607 out_temp_mem.shared_memory_reference = mem_id; 608 609 message->set_return_code(TEEC_SUCCESS); 610 611 return status; 612} 613 614zx_status_t OpteeClient::HandleRpcCommandFreeMemory(RpcMessage* message) { 615 // Mark that the return code will originate from driver 616 message->set_return_origin(TEEC_ORIGIN_COMMS); 617 618 MessageParamList params = message->params(); 619 if (params.size() != 1) { 620 zxlogf(ERROR, 621 "optee: RPC command to free shared memory received a bad number of parameters!\n"); 622 message->set_return_code(TEEC_ERROR_BAD_PARAMETERS); 623 return ZX_ERR_INVALID_ARGS; 624 } 625 626 // The first parameter outlines the specifications of the memory to be freed 627 const MessageParam& memory_specs_param = params[0]; 628 if (memory_specs_param.attribute != MessageParam::AttributeType::kAttributeTypeValueInput) { 629 zxlogf(ERROR, 630 "optee: RPC command to free shared memory received an unexpected parameter type!\n"); 631 message->set_return_code(TEEC_ERROR_BAD_PARAMETERS); 632 return ZX_ERR_INVALID_ARGS; 633 } 634 635 auto& mem_specs = memory_specs_param.payload.value.free_memory_specs; 636 switch (mem_specs.memory_type) { 637 case SharedMemoryType::kApplication: 638 case SharedMemoryType::kKernel: 639 break; 640 case SharedMemoryType::kGlobal: 641 zxlogf(ERROR, "optee: implementation currently does not support global shared memory!\n"); 642 return ZX_ERR_NOT_SUPPORTED; 643 default: 644 zxlogf(ERROR, 645 "optee: cannot free unknown memory type %" PRIu64 "\n", mem_specs.memory_type); 646 message->set_return_code(TEEC_ERROR_BAD_PARAMETERS); 647 return ZX_ERR_INVALID_ARGS; 648 } 649 650 zx_status_t status = FreeSharedMemory(mem_specs.memory_id); 651 if (status != ZX_OK) { 652 if (status == ZX_ERR_NOT_FOUND) { 653 message->set_return_code(TEEC_ERROR_ITEM_NOT_FOUND); 654 } else { 655 message->set_return_code(TEEC_ERROR_GENERIC); 656 } 657 658 return status; 659 } 660 661 message->set_return_code(TEEC_SUCCESS); 662 return status; 663} 664 665} // namespace optee 666