blob: 12fbb0e04524f60957151f3886197c0888de5286 [file] [log] [blame]
// Copyright 2017 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_BUS_TRANSACTION_INITIATOR_DISPATCHER_H_
#define ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_BUS_TRANSACTION_INITIATOR_DISPATCHER_H_
#include <sys/types.h>
#include <kernel/lockdep.h>
#include <object/dispatcher.h>
#include <object/handle.h>
#include <object/iommu_dispatcher.h>
#include <object/pinned_memory_token_dispatcher.h>
class Iommu;
class BusTransactionInitiatorDispatcher final
: public SoloDispatcher<BusTransactionInitiatorDispatcher, ZX_DEFAULT_BTI_RIGHTS> {
public:
static zx_status_t Create(fbl::RefPtr<IommuDispatcher> iommu, uint64_t bti_id,
KernelHandle<BusTransactionInitiatorDispatcher>* handle,
zx_rights_t* rights);
~BusTransactionInitiatorDispatcher() final;
zx_obj_type_t get_type() const final { return ZX_OBJ_TYPE_BTI; }
// Pins the given VMO range and returns an PinnedMemoryTokenDispatcher
// representing the pinned range.
//
// |mapped_addrs_count| must be either
// 1) If |compress_results|, |size|/|minimum_contiguity()|, rounded up, in which
// case each returned address represents a run of |minimum_contiguity()| bytes (with
// the exception of the last which may be short)
// 2) Otherwise, |size|/|PAGE_SIZE|, in which case each returned address represents a
// single page.
//
// Returns ZX_ERR_INVALID_ARGS if |offset| or |size| are not PAGE_SIZE aligned.
// Returns ZX_ERR_INVALID_ARGS if |perms| is not suitable to pass to the Iommu::Map() interface.
// Returns ZX_ERR_INVALID_ARGS if |mapped_addrs_count| is not exactly the
// value described above.
zx_status_t Pin(fbl::RefPtr<VmObject> vmo, uint64_t offset, uint64_t size, uint32_t perms,
KernelHandle<PinnedMemoryTokenDispatcher>* handle, zx_rights_t* rights);
// Releases all quarantined PMTs. The memory pins are released and the VMO
// references are dropped, so the underlying VMOs may be immediately destroyed, and the
// underlying physical memory may be reallocated.
void ReleaseQuarantine();
void on_zero_handles() final;
[[nodiscard]] zx_status_t set_name(const char* name, size_t len) final __NONNULL((2));
[[nodiscard]] zx_status_t get_name(char (&out_name)[ZX_MAX_NAME_LEN]) const final;
Iommu& iommu() const { return iommu_->iommu(); }
uint64_t bti_id() const { return bti_id_; }
// Pin will always be able to return addresses that are contiguous for at
// least this many bytes. E.g. if this returns 1MB, then a call to Pin()
// with a size of 2MB will return at most two physically-contiguous runs. If the size
// were 2.5MB, it will return at most three physically-contiguous runs.
uint64_t minimum_contiguity() const { return iommu().minimum_contiguity(bti_id_); }
// The number of bytes in the address space (UINT64_MAX if 2^64).
uint64_t aspace_size() const { return iommu().aspace_size(bti_id_); }
// The count of the pinned memory object tokens.
uint64_t pmo_count() const;
// The count of the quarantined pinned memory object tokens.
uint64_t quarantine_count() const;
protected:
friend PinnedMemoryTokenDispatcher;
// Used to register a PMT pointer during PMT construction
void AddPmoLocked(PinnedMemoryTokenDispatcher* pmt) TA_REQ(get_lock());
// Used to unregister a PMT pointer during PMT destruction
void RemovePmo(PinnedMemoryTokenDispatcher* pmt);
// Append |pmt| to the quarantine_ list. |pmt| is not removed from pinned_memory_.
// This will prevent its underlying VMO from being unpinned until the
// quarantine is cleared.
void Quarantine(fbl::RefPtr<PinnedMemoryTokenDispatcher> pmt) TA_EXCL(get_lock());
private:
enum class BtiPageLeakReason {
BtiClose,
PmtClose,
};
BusTransactionInitiatorDispatcher(fbl::RefPtr<IommuDispatcher> iommu, uint64_t bti_id);
void PrintQuarantineWarningLocked(BtiPageLeakReason reason) TA_REQ(get_lock());
const fbl::RefPtr<IommuDispatcher> iommu_;
const uint64_t bti_id_;
using PmoList = fbl::TaggedDoublyLinkedList<PinnedMemoryTokenDispatcher*, PmtListTag>;
using QuarantineList =
fbl::TaggedDoublyLinkedList<fbl::RefPtr<PinnedMemoryTokenDispatcher>, PmtQuarantineListTag>;
PmoList pinned_memory_ TA_GUARDED(get_lock());
QuarantineList quarantine_ TA_GUARDED(get_lock());
bool zero_handles_ TA_GUARDED(get_lock());
// The user-friendly BTI name. For debug purposes only.
fbl::Name<ZX_MAX_NAME_LEN> name_;
};
#endif // ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_BUS_TRANSACTION_INITIATOR_DISPATCHER_H_