blob: 1c796cda2a08290e5d4968c4e697e1b9ece0b609 [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
#pragma once
#include <dev/iommu.h>
#include <err.h>
#include <fbl/array.h>
#include <fbl/canary.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/ref_ptr.h>
#include <object/dispatcher.h>
#include <zircon/rights.h>
#include <sys/types.h>
class BusTransactionInitiatorDispatcher;
class VmObject;
class PinnedMemoryTokenDispatcher final : public SoloDispatcher,
public fbl::DoublyLinkedListable<PinnedMemoryTokenDispatcher*> {
public:
~PinnedMemoryTokenDispatcher();
zx_obj_type_t get_type() const final { return ZX_OBJ_TYPE_PMT; }
bool has_state_tracker() const final { return false; }
void on_zero_handles() final;
// Traits to belong in the BTI's list.
struct PinnedMemoryTokenListTraits {
static fbl::DoublyLinkedListNodeState<PinnedMemoryTokenDispatcher*>& node_state(
PinnedMemoryTokenDispatcher& obj) {
return obj.dll_pmt_;
}
};
using QuarantineListNodeState = fbl::DoublyLinkedListNodeState<
fbl::RefPtr<PinnedMemoryTokenDispatcher>>;
struct QuarantineListTraits {
static QuarantineListNodeState& node_state(
PinnedMemoryTokenDispatcher& obj) {
return obj.dll_quarantine_;
}
};
// Mark this PMT as unpinned. When on_zero_handles() runs, this PMT will
// be removed from its BTI rather than moved to the quarantine.
void MarkUnpinned();
// |mapped_addrs_count| must be either
// 1) If |compress_results|, |size_|/|bti_.minimum_contiguity()|, rounded up, in which
// case each returned address represents a run of |bti_.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 |mapped_addrs_count| is not exactly the value described above.
zx_status_t EncodeAddrs(bool compress_results, dev_vaddr_t* mapped_addrs, size_t mapped_addrs_count);
// Returns the number of bytes pinned by the PMT.
uint64_t size() const { return size_; }
protected:
friend BusTransactionInitiatorDispatcher;
// Pin memory in |vmo|'s range [offset, offset+size) on behalf of |bti|,
// with permissions specified by |perms|. |perms| should be flags suitable
// for the Iommu::Map() interface. Must be created under the BTI
// dispatcher's lock.
static zx_status_t Create(fbl::RefPtr<BusTransactionInitiatorDispatcher> bti,
fbl::RefPtr<VmObject> vmo, size_t offset,
size_t size, uint32_t perms,
fbl::RefPtr<Dispatcher>* dispatcher,
zx_rights_t* rights);
private:
PinnedMemoryTokenDispatcher(fbl::RefPtr<BusTransactionInitiatorDispatcher> bti,
fbl::RefPtr<VmObject> vmo, size_t offset, size_t size,
bool is_contiguous,
fbl::Array<dev_vaddr_t> mapped_addrs);
DISALLOW_COPY_ASSIGN_AND_MOVE(PinnedMemoryTokenDispatcher);
zx_status_t MapIntoIommu(uint32_t perms);
zx_status_t UnmapFromIommuLocked() TA_REQ(get_lock());
void InvalidateMappedAddrsLocked() TA_REQ(get_lock());
fbl::Canary<fbl::magic("PMT_")> canary_;
// The containing BTI holds a list of all its PMTs, including those which are quarantined.
fbl::DoublyLinkedListNodeState<PinnedMemoryTokenDispatcher*> dll_pmt_;
// The containing BTI holds a list of all its quarantined PMTs.
QuarantineListNodeState dll_quarantine_;
const fbl::RefPtr<VmObject> vmo_;
const uint64_t offset_;
const uint64_t size_;
const bool is_contiguous_;
// Set to true by MarkUnpinned()
bool explicitly_unpinned_ TA_GUARDED(get_lock()) = false;
const fbl::RefPtr<BusTransactionInitiatorDispatcher> bti_;
const fbl::Array<dev_vaddr_t> mapped_addrs_ TA_GUARDED(get_lock());
};