| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "external_memory_allocator.h" |
| |
| #include <fbl/string_printf.h> |
| |
| #include "macros.h" |
| |
| namespace sysmem_driver { |
| ExternalMemoryAllocator::ExternalMemoryAllocator(MemoryAllocator::Owner* owner, |
| fidl::WireSharedClient<fuchsia_sysmem2::Heap> heap, |
| fuchsia_sysmem2::wire::HeapProperties properties) |
| : MemoryAllocator(owner->table_set(), properties), owner_(owner), heap_(std::move(heap)) { |
| node_ = owner->heap_node()->CreateChild( |
| fbl::StringPrintf("ExternalMemoryAllocator-%ld", id()).c_str()); |
| node_.CreateUint("id", id(), &properties_); |
| } |
| |
| ExternalMemoryAllocator::~ExternalMemoryAllocator() { ZX_DEBUG_ASSERT(is_empty()); } |
| |
| zx_status_t ExternalMemoryAllocator::Allocate(uint64_t size, std::optional<std::string> name, |
| zx::vmo* parent_vmo) { |
| auto result = heap_.sync()->AllocateVmo(size); |
| if (!result.ok() || result.value().s != ZX_OK) { |
| DRIVER_ERROR("HeapAllocate() failed - status: %d status2: %d", result.status(), |
| result.value().s); |
| // sanitize to ZX_ERR_NO_MEMORY regardless of why. |
| return ZX_ERR_NO_MEMORY; |
| } |
| zx::vmo result_vmo = std::move(result.value().vmo); |
| constexpr const char vmo_name[] = "Sysmem-external-heap"; |
| result_vmo.set_property(ZX_PROP_NAME, vmo_name, sizeof(vmo_name)); |
| *parent_vmo = std::move(result_vmo); |
| return ZX_OK; |
| } |
| |
| zx_status_t ExternalMemoryAllocator::SetupChildVmo( |
| const zx::vmo& parent_vmo, const zx::vmo& child_vmo, |
| fuchsia_sysmem2::wire::SingleBufferSettings buffer_settings) { |
| zx::vmo child_vmo_copy; |
| zx_status_t status = child_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &child_vmo_copy); |
| if (status != ZX_OK) { |
| DRIVER_ERROR("duplicate() failed - status: %d", status); |
| // sanitize to ZX_ERR_NO_MEMORY regardless of why. |
| status = ZX_ERR_NO_MEMORY; |
| return status; |
| } |
| |
| auto result = heap_.sync()->CreateResource(std::move(child_vmo_copy), std::move(buffer_settings)); |
| if (!result.ok() || result.value().s != ZX_OK) { |
| DRIVER_ERROR("HeapCreateResource() failed - status: %d status2: %d", result.status(), |
| result.value().s); |
| // sanitize to ZX_ERR_NO_MEMORY regardless of why. |
| return ZX_ERR_NO_MEMORY; |
| } |
| allocations_[parent_vmo.get()] = result.value().id; |
| return ZX_OK; |
| } |
| |
| void ExternalMemoryAllocator::Delete(zx::vmo parent_vmo) { |
| auto it = allocations_.find(parent_vmo.get()); |
| if (it == allocations_.end()) { |
| DRIVER_ERROR("Invalid allocation - vmo_handle: %d", parent_vmo.get()); |
| return; |
| } |
| auto id = it->second; |
| auto result = heap_.sync()->DestroyResource(id); |
| if (!result.ok()) { |
| DRIVER_ERROR("HeapDestroyResource() failed - status: %d", result.status()); |
| // fall-through - this can only fail because resource has |
| // already been destroyed. |
| } |
| allocations_.erase(it); |
| if (is_empty()) { |
| owner_->CheckForUnbind(); |
| } |
| // ~parent_vmo |
| } |
| |
| } // namespace sysmem_driver |