1 // Copyright 2017 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 
7 #include <dev/iommu/dummy.h>
8 
9 #include <err.h>
10 #include <fbl/ref_ptr.h>
11 #include <ktl/move.h>
12 #include <new>
13 #include <vm/vm.h>
14 
15 #define INVALID_PADDR UINT64_MAX
16 
DummyIommu()17 DummyIommu::DummyIommu() {
18 }
19 
Create(ktl::unique_ptr<const uint8_t[]> desc,size_t desc_len,fbl::RefPtr<Iommu> * out)20 zx_status_t DummyIommu::Create(ktl::unique_ptr<const uint8_t[]> desc, size_t desc_len,
21                                fbl::RefPtr<Iommu>* out) {
22     if (desc_len != sizeof(zx_iommu_desc_dummy_t)) {
23         return ZX_ERR_INVALID_ARGS;
24     }
25 
26     fbl::AllocChecker ac;
27     auto instance = fbl::AdoptRef<DummyIommu>(new (&ac) DummyIommu());
28     if (!ac.check()) {
29         return ZX_ERR_NO_MEMORY;
30     }
31     *out = ktl::move(instance);
32     return ZX_OK;
33 }
34 
~DummyIommu()35 DummyIommu::~DummyIommu() {
36 }
37 
IsValidBusTxnId(uint64_t bus_txn_id) const38 bool DummyIommu::IsValidBusTxnId(uint64_t bus_txn_id) const {
39     return true;
40 }
41 
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)42 zx_status_t DummyIommu::Map(uint64_t bus_txn_id, const fbl::RefPtr<VmObject>& vmo,
43                             uint64_t offset, size_t size, uint32_t perms,
44                             dev_vaddr_t* vaddr, size_t* mapped_len) {
45     DEBUG_ASSERT(vaddr);
46     DEBUG_ASSERT(mapped_len);
47 
48     if (!IS_PAGE_ALIGNED(offset) || size == 0) {
49         return ZX_ERR_INVALID_ARGS;
50     }
51     if (perms & ~(IOMMU_FLAG_PERM_READ | IOMMU_FLAG_PERM_WRITE | IOMMU_FLAG_PERM_EXECUTE)) {
52         return ZX_ERR_INVALID_ARGS;
53     }
54     if (perms == 0) {
55         return ZX_ERR_INVALID_ARGS;
56     }
57     if (offset + size < offset || offset + size > vmo->size()) {
58         return ZX_ERR_OUT_OF_RANGE;
59     }
60 
61     auto lookup_fn = [](void* ctx, size_t offset, size_t index, paddr_t pa) {
62         paddr_t* paddr = static_cast<paddr_t*>(ctx);
63         *paddr = pa;
64         return ZX_OK;
65     };
66 
67     paddr_t paddr = INVALID_PADDR;
68     zx_status_t status = vmo->Lookup(offset, fbl::min<size_t>(PAGE_SIZE, size), lookup_fn, &paddr);
69     if (status != ZX_OK) {
70         return status;
71     }
72     if (paddr == INVALID_PADDR) {
73         return ZX_ERR_BAD_STATE;
74     }
75 
76     if (vmo->is_paged()) {
77         *vaddr = paddr;
78         *mapped_len = PAGE_SIZE;
79     } else {
80         *vaddr = paddr;
81         *mapped_len = ROUNDUP(size, PAGE_SIZE);
82     }
83     return ZX_OK;
84 }
85 
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)86 zx_status_t DummyIommu::MapContiguous(uint64_t bus_txn_id, const fbl::RefPtr<VmObject>& vmo,
87                                       uint64_t offset, size_t size, uint32_t perms,
88                                       dev_vaddr_t* vaddr, size_t* mapped_len) {
89     DEBUG_ASSERT(vaddr);
90     DEBUG_ASSERT(mapped_len);
91 
92     if (!IS_PAGE_ALIGNED(offset) || size == 0) {
93         return ZX_ERR_INVALID_ARGS;
94     }
95     if (perms & ~(IOMMU_FLAG_PERM_READ | IOMMU_FLAG_PERM_WRITE | IOMMU_FLAG_PERM_EXECUTE)) {
96         return ZX_ERR_INVALID_ARGS;
97     }
98     if (perms == 0) {
99         return ZX_ERR_INVALID_ARGS;
100     }
101     uint64_t end;
102     if (add_overflow(offset, size, &end) || end > vmo->size()) {
103         return ZX_ERR_OUT_OF_RANGE;
104     }
105 
106     if (!vmo->is_contiguous()) {
107         return ZX_ERR_NO_RESOURCES;
108     }
109 
110     auto lookup_fn = [](void* ctx, size_t offset, size_t index, paddr_t pa) {
111         paddr_t* paddr = static_cast<paddr_t*>(ctx);
112         *paddr = pa;
113         return ZX_OK;
114     };
115 
116     paddr_t paddr = INVALID_PADDR;
117     zx_status_t status = vmo->Lookup(offset, PAGE_SIZE, lookup_fn, &paddr);
118     if (status != ZX_OK) {
119         return status;
120     }
121     if (paddr == INVALID_PADDR) {
122         return ZX_ERR_BAD_STATE;
123     }
124 
125     *vaddr = paddr;
126     *mapped_len = size;
127     return ZX_OK;
128 }
129 
Unmap(uint64_t bus_txn_id,dev_vaddr_t vaddr,size_t size)130 zx_status_t DummyIommu::Unmap(uint64_t bus_txn_id, dev_vaddr_t vaddr, size_t size) {
131     if (!IS_PAGE_ALIGNED(vaddr) || !IS_PAGE_ALIGNED(size)) {
132         return ZX_ERR_INVALID_ARGS;
133     }
134     return ZX_OK;
135 }
136 
ClearMappingsForBusTxnId(uint64_t bus_txn_id)137 zx_status_t DummyIommu::ClearMappingsForBusTxnId(uint64_t bus_txn_id) {
138     return ZX_OK;
139 }
140 
minimum_contiguity(uint64_t bus_txn_id)141 uint64_t DummyIommu::minimum_contiguity(uint64_t bus_txn_id) {
142     return PAGE_SIZE;
143 }
144 
aspace_size(uint64_t bus_txn_id)145 uint64_t DummyIommu::aspace_size(uint64_t bus_txn_id) {
146     return UINT64_MAX;
147 }
148