blob: 2b02ee173620c5adc9fcce94e81ba8e91d7d39ea [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#ifndef ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_RESOURCE_DISPATCHER_H_
#define ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_RESOURCE_DISPATCHER_H_
#include <lib/zircon-internal/thread_annotations.h>
#include <sys/types.h>
#include <zircon/compiler.h>
#include <zircon/rights.h>
#include <zircon/syscalls/resource.h>
#include <zircon/types.h>
#include <array>
#include <fbl/intrusive_double_list.h>
#include <fbl/name.h>
#include <kernel/lockdep.h>
#include <kernel/mutex.h>
#include <object/dispatcher.h>
#include <object/handle.h>
#include <region-alloc/region-alloc.h>
class ResourceRecord;
class ResourceDispatcher final
: public SoloDispatcher<ResourceDispatcher, ZX_DEFAULT_RESOURCE_RIGHTS>,
public fbl::DoublyLinkedListable<ResourceDispatcher*> {
public:
static constexpr size_t kMaxRegionPoolSize = 64 << 10;
using ResourceList = fbl::DoublyLinkedList<ResourceDispatcher*>;
using RefPtr = fbl::RefPtr<ResourceDispatcher>;
struct ResourceStorage {
ResourceList resource_list;
ktl::array<RegionAllocator, ZX_RSRC_KIND_COUNT> rallocs;
};
// Creates ResourceDispatcher object representing access rights to a
// given region of address space from a particular address space allocator, or a root resource
// granted full access permissions. Only one instance of the root resource is created at boot.
static zx_status_t Create(KernelHandle<ResourceDispatcher>* handle, zx_rights_t* rights,
zx_rsrc_kind_t kind, uint64_t base, size_t size, uint32_t flags,
const char name[ZX_MAX_NAME_LEN], ResourceStorage* = nullptr);
// Creates ResourceDispatcher object representing access rights to all
// regions of address space for a ranged resource.
static zx_status_t CreateRangedRoot(KernelHandle<ResourceDispatcher>* handle, zx_rights_t* rights,
zx_rsrc_kind_t kind, const char name[ZX_MAX_NAME_LEN],
ResourceStorage* storage = nullptr);
// Initializes the static mmembers used for bookkeeping and storage.
static zx_status_t InitializeAllocator(zx_rsrc_kind_t kind, uint64_t base, size_t size,
ResourceStorage* = nullptr);
static void Dump();
template <typename T>
static zx_status_t ForEachResource(T func, ResourceStorage* storage = nullptr)
TA_EXCL(ResourcesLock::Get()) {
Guard<Mutex> guard{ResourcesLock::Get()};
return ForEachResourceLocked(func, (storage != nullptr) ? storage : &static_storage_);
}
bool IsRangedRoot(zx_rsrc_kind_t kind) const {
switch (kind_) {
case ZX_RSRC_KIND_ROOT:
return false;
}
return (kind_ == kind && base_ == 0 && size_ == 0);
}
zx_obj_type_t get_type() const final { return ZX_OBJ_TYPE_RESOURCE; }
// Returns a null-terminated name, or the empty string if set_name() has not
// been called.
void get_name(char out_name[ZX_MAX_NAME_LEN]) const final {
name_.get(ZX_MAX_NAME_LEN, out_name);
}
// Sets the name of the object. May truncate internally. |size| is the size
// of the buffer pointed to by |name|.
zx_status_t set_name(const char* name, size_t size) final { return name_.set(name, size); }
uint64_t get_base() const { return base_; }
size_t get_size() const { return size_; }
uint32_t get_kind() const { return kind_; }
uint32_t get_flags() const { return flags_; }
~ResourceDispatcher();
private:
ResourceDispatcher(zx_rsrc_kind_t kind, uint64_t base, size_t size, uint32_t flags,
RegionAllocator::Region::UPtr&& region, ResourceStorage* storage);
template <typename T>
static zx_status_t ForEachResourceLocked(T callback, ResourceStorage* storage)
TA_REQ(ResourcesLock::Get()) {
for (const auto& resource : storage->resource_list) {
zx_status_t status = callback(resource);
if (status != ZX_OK) {
return status;
}
}
return ZX_OK;
}
const zx_rsrc_kind_t kind_;
const uint64_t base_;
const size_t size_;
const uint32_t flags_;
ResourceList* resource_list_;
fbl::Name<ZX_MAX_NAME_LEN> name_;
RegionAllocator::Region::UPtr exclusive_region_;
// Static tracking data structures for physical address space allocations.
// Exclusive allocations are pulled out of the RegionAllocators, and all
// allocations are added to |static_resource_list_|. Shared allocations will
// check that no exclusive reservation exists, but then release the region
// back to the allocator. Likewise, exclusive allocations will check to
// ensure that the region has not already been allocated as a shared region
// by checking the static resource list.
DECLARE_SINGLETON_MUTEX(ResourcesLock);
static RegionAllocator::RegionPool::RefPtr region_pool_;
// A single global list is used for all resources so that root and hypervisor resources can
// still be tracked, and filtering can be done via client tools/commands when displaying
// the list is concerned.
static ResourceStorage static_storage_ TA_GUARDED(ResourcesLock::Get());
};
#endif // ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_RESOURCE_DISPATCHER_H_