// 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 #include #include #include #include #include #include #define INVALID_PADDR UINT64_MAX DummyIommu::DummyIommu() { } zx_status_t DummyIommu::Create(ktl::unique_ptr desc, size_t desc_len, fbl::RefPtr* out) { if (desc_len != sizeof(zx_iommu_desc_dummy_t)) { return ZX_ERR_INVALID_ARGS; } fbl::AllocChecker ac; auto instance = fbl::AdoptRef(new (&ac) DummyIommu()); if (!ac.check()) { return ZX_ERR_NO_MEMORY; } *out = ktl::move(instance); return ZX_OK; } DummyIommu::~DummyIommu() { } bool DummyIommu::IsValidBusTxnId(uint64_t bus_txn_id) const { return true; } zx_status_t DummyIommu::Map(uint64_t bus_txn_id, const fbl::RefPtr& vmo, uint64_t offset, size_t size, uint32_t perms, dev_vaddr_t* vaddr, size_t* mapped_len) { DEBUG_ASSERT(vaddr); DEBUG_ASSERT(mapped_len); if (!IS_PAGE_ALIGNED(offset) || size == 0) { return ZX_ERR_INVALID_ARGS; } if (perms & ~(IOMMU_FLAG_PERM_READ | IOMMU_FLAG_PERM_WRITE | IOMMU_FLAG_PERM_EXECUTE)) { return ZX_ERR_INVALID_ARGS; } if (perms == 0) { return ZX_ERR_INVALID_ARGS; } if (offset + size < offset || offset + size > vmo->size()) { return ZX_ERR_OUT_OF_RANGE; } auto lookup_fn = [](void* ctx, size_t offset, size_t index, paddr_t pa) { paddr_t* paddr = static_cast(ctx); *paddr = pa; return ZX_OK; }; paddr_t paddr = INVALID_PADDR; zx_status_t status = vmo->Lookup(offset, fbl::min(PAGE_SIZE, size), lookup_fn, &paddr); if (status != ZX_OK) { return status; } if (paddr == INVALID_PADDR) { return ZX_ERR_BAD_STATE; } if (vmo->is_paged()) { *vaddr = paddr; *mapped_len = PAGE_SIZE; } else { *vaddr = paddr; *mapped_len = ROUNDUP(size, PAGE_SIZE); } return ZX_OK; } zx_status_t DummyIommu::MapContiguous(uint64_t bus_txn_id, const fbl::RefPtr& vmo, uint64_t offset, size_t size, uint32_t perms, dev_vaddr_t* vaddr, size_t* mapped_len) { DEBUG_ASSERT(vaddr); DEBUG_ASSERT(mapped_len); if (!IS_PAGE_ALIGNED(offset) || size == 0) { return ZX_ERR_INVALID_ARGS; } if (perms & ~(IOMMU_FLAG_PERM_READ | IOMMU_FLAG_PERM_WRITE | IOMMU_FLAG_PERM_EXECUTE)) { return ZX_ERR_INVALID_ARGS; } if (perms == 0) { return ZX_ERR_INVALID_ARGS; } uint64_t end; if (add_overflow(offset, size, &end) || end > vmo->size()) { return ZX_ERR_OUT_OF_RANGE; } if (!vmo->is_contiguous()) { return ZX_ERR_NO_RESOURCES; } auto lookup_fn = [](void* ctx, size_t offset, size_t index, paddr_t pa) { paddr_t* paddr = static_cast(ctx); *paddr = pa; return ZX_OK; }; paddr_t paddr = INVALID_PADDR; zx_status_t status = vmo->Lookup(offset, PAGE_SIZE, lookup_fn, &paddr); if (status != ZX_OK) { return status; } if (paddr == INVALID_PADDR) { return ZX_ERR_BAD_STATE; } *vaddr = paddr; *mapped_len = size; return ZX_OK; } zx_status_t DummyIommu::Unmap(uint64_t bus_txn_id, dev_vaddr_t vaddr, size_t size) { if (!IS_PAGE_ALIGNED(vaddr) || !IS_PAGE_ALIGNED(size)) { return ZX_ERR_INVALID_ARGS; } return ZX_OK; } zx_status_t DummyIommu::ClearMappingsForBusTxnId(uint64_t bus_txn_id) { return ZX_OK; } uint64_t DummyIommu::minimum_contiguity(uint64_t bus_txn_id) { return PAGE_SIZE; } uint64_t DummyIommu::aspace_size(uint64_t bus_txn_id) { return UINT64_MAX; }