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 "shared-memory.h" 6 7#include <ddk/debug.h> 8#include <fbl/algorithm.h> 9#include <fbl/auto_call.h> 10#include <fbl/limits.h> 11 12namespace optee { 13 14SharedMemory::SharedMemory(zx_vaddr_t base_vaddr, zx_paddr_t base_paddr, RegionPtr region) 15 : base_vaddr_(base_vaddr), base_paddr_(base_paddr), region_(fbl::move(region)) {} 16 17zx_status_t SharedMemoryManager::Create(zx_paddr_t shared_mem_start, 18 size_t shared_mem_size, 19 fbl::unique_ptr<io_buffer_t> secure_world_memory, 20 fbl::unique_ptr<SharedMemoryManager>* out_manager) { 21 ZX_DEBUG_ASSERT(secure_world_memory != nullptr); 22 ZX_DEBUG_ASSERT(out_manager != nullptr); 23 24 auto io_buffer_cleanup = fbl::MakeAutoCall([io_buffer = secure_world_memory.get()]() { 25 io_buffer_release(io_buffer); 26 }); 27 28 // Round the start and end to the nearest page boundaries within the range and calculate a 29 // new size. 30 shared_mem_start = fbl::round_up(shared_mem_start, static_cast<uint32_t>(PAGE_SIZE)); 31 const zx_paddr_t shared_mem_end = fbl::round_down(shared_mem_start + shared_mem_size, 32 static_cast<uint32_t>(PAGE_SIZE)); 33 if (shared_mem_end <= shared_mem_start) { 34 zxlogf(ERROR, "optee: no shared memory available from secure world\n"); 35 return ZX_ERR_NO_RESOURCES; 36 } 37 shared_mem_size = shared_mem_end - shared_mem_start; 38 39 // The secure world shared memory exists within some subrange of the secure_world_memory. 40 // Get the addresses from the io_buffer and validate that the requested subrange is within 41 // the mmio range. 42 const zx_vaddr_t secure_world_vaddr = reinterpret_cast<zx_vaddr_t>(io_buffer_virt( 43 secure_world_memory.get())); 44 const zx_paddr_t secure_world_paddr = io_buffer_phys(secure_world_memory.get()); 45 const size_t secure_world_size = io_buffer_size(secure_world_memory.get(), 0); 46 47 if ((shared_mem_start < secure_world_paddr) || 48 (shared_mem_end > secure_world_paddr + secure_world_size)) { 49 zxlogf(ERROR, "optee: shared memory not within secure os memory\n"); 50 return ZX_ERR_INTERNAL; 51 } 52 53 if (shared_mem_size < 2 * kDriverPoolSize) { 54 zxlogf(ERROR, "optee: shared memory is not large enough\n"); 55 return ZX_ERR_NO_RESOURCES; 56 } 57 58 const zx_off_t shared_mem_offset = shared_mem_start - secure_world_paddr; 59 60 fbl::AllocChecker ac; 61 fbl::unique_ptr<SharedMemoryManager> manager(new (&ac) SharedMemoryManager( 62 secure_world_vaddr + shared_mem_offset, 63 secure_world_paddr + shared_mem_offset, 64 shared_mem_size, 65 fbl::move(secure_world_memory))); 66 67 if (!ac.check()) { 68 return ZX_ERR_NO_MEMORY; 69 } 70 71 // We've successfully created the Manager and it now owns the io_buffer memory 72 io_buffer_cleanup.cancel(); 73 74 *out_manager = fbl::move(manager); 75 return ZX_OK; 76} 77 78SharedMemoryManager::~SharedMemoryManager() { 79 io_buffer_release(secure_world_memory_.get()); 80} 81 82SharedMemoryManager::SharedMemoryManager(zx_vaddr_t base_vaddr, 83 zx_paddr_t base_paddr, 84 size_t total_size, 85 fbl::unique_ptr<io_buffer_t> secure_world_memory) 86 : secure_world_memory_(fbl::move(secure_world_memory)), 87 driver_pool_(base_vaddr, base_paddr, kDriverPoolSize), 88 client_pool_(base_vaddr + kDriverPoolSize, 89 base_paddr + kDriverPoolSize, 90 total_size - kDriverPoolSize) {} 91 92} // namespace optee 93