blob: 15dbc6515e2e14ae1ea9a8312d21ac323f67ac83 [file] [log] [blame]
// Copyright 2019 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 <lib/async/wait.h>
#include <lib/inspect/cpp/inspect.h>
#include <lib/zx/bti.h>
#include <lib/zx/event.h>
#include <zircon/limits.h>
#include <fbl/vector.h>
#include <region-alloc/region-alloc.h>
#include "allocator.h"
namespace sysmem_driver {
class ContiguousPooledMemoryAllocator : public MemoryAllocator {
ContiguousPooledMemoryAllocator(Owner* parent_device, const char* allocation_name,
inspect::Node* parent_node, uint64_t pool_id, uint64_t size,
bool is_cpu_accessible, bool is_ready, bool can_be_torn_down,
async_dispatcher_t* dispatcher = nullptr);
// Default to page alignment.
zx_status_t Init(uint32_t alignment_log2 = ZX_PAGE_SHIFT);
// TODO( Use this for VDEC.
// This uses a physical VMO as the parent VMO.
zx_status_t InitPhysical(zx_paddr_t paddr);
zx_status_t Allocate(uint64_t size, std::optional<std::string> name,
zx::vmo* parent_vmo) override;
zx_status_t SetupChildVmo(const zx::vmo& parent_vmo, const zx::vmo& child_vmo,
llcpp::fuchsia::sysmem2::SingleBufferSettings buffer_settings) override;
void Delete(zx::vmo parent_vmo) override;
bool is_empty() override {
// If the contiguous VMO has been marked as secure there's no way to unmark it as secure, so
// unbinding would never be safe.
return regions_.empty() && (can_be_torn_down_ || !is_ready_);
zx_status_t GetPhysicalMemoryInfo(uint64_t* base, uint64_t* size) override {
*base = start_;
*size = size_;
return ZX_OK;
void set_ready() override;
bool is_ready() override;
const zx::vmo& GetPoolVmoForTest() { return contiguous_vmo_; }
struct RegionData {
std::string name;
zx_koid_t koid;
inspect::Node node;
inspect::UintProperty size_property;
inspect::UintProperty koid_property;
RegionAllocator::Region::UPtr ptr;
zx_status_t InitCommon(zx::vmo local_contiguous_vmo);
void TraceObserverCallback(async_dispatcher_t* dispatcher, async::WaitBase* wait,
zx_status_t status, const zx_packet_signal_t* signal);
void DumpPoolStats();
void DumpPoolHighWaterMark();
void TracePoolSize(bool initial_trace);
Owner* const parent_device_{};
const char* const allocation_name_{};
const uint64_t pool_id_{};
char child_name_[ZX_MAX_NAME_LEN] = {};
zx::vmo contiguous_vmo_;
zx::pmt pool_pmt_;
RegionAllocator region_allocator_;
// From parent_vmo handle to std::unique_ptr<>
std::map<zx_handle_t, RegionData> regions_;
uint64_t start_{};
uint64_t size_{};
bool is_cpu_accessible_{};
bool is_ready_{};
// True if the allocator can be deleted after it's marked ready.
bool can_be_torn_down_{};
uint64_t high_water_mark_used_size_{};
uint64_t max_free_size_at_high_water_mark_{};
inspect::Node node_;
inspect::UintProperty size_property_;
inspect::UintProperty high_water_mark_property_;
inspect::UintProperty used_size_property_;
inspect::UintProperty allocations_failed_property_;
inspect::UintProperty last_allocation_failed_timestamp_ns_property_;
// Keeps track of how many allocations would have succeeded but failed due to fragmentation.
inspect::UintProperty allocations_failed_fragmentation_property_;
// This is the size of a the largest free contiguous region when high_water_mark_property_ was
// last modified. It can be used to determine how much space was wasted due to fragmentation.
inspect::UintProperty max_free_at_high_water_property_;
zx::event trace_observer_event_;
} // namespace sysmem_driver