blob: ac7aabde3dbf48dbc917cf1288e144f26b61e72f [file] [log] [blame]
// 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