blob: d7656f72b27ba0479923dd74862dcc08f10dd7a5 [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
#include <dev/iommu/dummy.h>
#include <err.h>
#include <fbl/ref_ptr.h>
#include <ktl/move.h>
#include <new>
#include <vm/vm.h>
#define INVALID_PADDR UINT64_MAX
DummyIommu::DummyIommu() {
}
zx_status_t DummyIommu::Create(ktl::unique_ptr<const uint8_t[]> desc, size_t desc_len,
fbl::RefPtr<Iommu>* out) {
if (desc_len != sizeof(zx_iommu_desc_dummy_t)) {
return ZX_ERR_INVALID_ARGS;
}
fbl::AllocChecker ac;
auto instance = fbl::AdoptRef<DummyIommu>(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<VmObject>& 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<paddr_t*>(ctx);
*paddr = pa;
return ZX_OK;
};
paddr_t paddr = INVALID_PADDR;
zx_status_t status = vmo->Lookup(offset, fbl::min<size_t>(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<VmObject>& 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<paddr_t*>(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;
}