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 #pragma once
8 
9 #include <kernel/mutex.h>
10 #include <fbl/intrusive_double_list.h>
11 #include <fbl/ref_counted.h>
12 #include <fbl/ref_ptr.h>
13 #include <vm/vm_object.h>
14 #include <zircon/thread_annotations.h>
15 
16 #include <stdbool.h>
17 #include <sys/types.h>
18 #include <inttypes.h>
19 
20 #define IOMMU_FLAG_PERM_READ    (1<<0)
21 #define IOMMU_FLAG_PERM_WRITE   (1<<1)
22 #define IOMMU_FLAG_PERM_EXECUTE (1<<2)
23 
24 // Type used to refer to virtual addresses presented to a device by the IOMMU.
25 typedef uint64_t dev_vaddr_t;
26 
27 class Iommu : public fbl::RefCounted<Iommu>,
28               public fbl::DoublyLinkedListable<fbl::RefPtr<Iommu>> {
29 public:
30     // Check if |bus_txn_id| is valid for this IOMMU (i.e. could be used
31     // to configure a device).
32     virtual bool IsValidBusTxnId(uint64_t bus_txn_id) const = 0;
33 
34     // Grant the device identified by |bus_txn_id| access to the range of
35     // pages given by [offset, offset + size) in |vmo|.  The base of the
36     // mapped range is returned via |vaddr|.  The number of bytes mapped is
37     // returned via |mapped_len|. |vaddr| and |mapped_len| must not be NULL.
38     //
39     // |mapped_len| may be more than |size|, in the event that |size| is
40     // not page-aligned.  |mapped_len| will always be page-aligned.
41     //
42     // The memory in the given range of |vmo| MUST have been pinned before
43     // calling this function, and if this function returns ZX_OK,
44     // MUST NOT be unpinned until after Unmap() is called on the returned range.
45     //
46     // |perms| defines the access permissions, using the IOMMU_FLAG_PERM_*
47     // flags.
48     //
49     // If |size| is no more than |minimum_contiguity()|, this will never return
50     // a partial mapping.
51     //
52     // Returns ZX_ERR_INVALID_ARGS if:
53     //  |size| is zero.
54     //  |offset| is not aligned to PAGE_SIZE
55     // Returns ZX_ERR_OUT_OF_RANGE if [offset, offset + size) is not a valid range in |vmo|.
56     // Returns ZX_ERR_NOT_FOUND if |bus_txn_id| is not valid.
57     // Returns ZX_ERR_NO_RESOURCES if the mapping could not be made due to lack
58     // of an available address range.
59     virtual zx_status_t Map(uint64_t bus_txn_id, const fbl::RefPtr<VmObject>& vmo,
60                             uint64_t offset, size_t size, uint32_t perms,
61                             dev_vaddr_t* vaddr, size_t* mapped_len) = 0;
62 
63     // Same as Map, but with additional guarantee that this will never return a
64     // partial mapping.  It will either return a single contiguous mapping or
65     // return a failure.
66     virtual zx_status_t MapContiguous(uint64_t bus_txn_id, const fbl::RefPtr<VmObject>& vmo,
67                                       uint64_t offset, size_t size, uint32_t perms,
68                                       dev_vaddr_t* vaddr, size_t* mapped_len) = 0;
69 
70     // Revoke access to the range of addresses [vaddr, vaddr + size) for the
71     // device identified by |bus_txn_id|.
72     //
73     // Returns ZX_ERR_INVALID_ARGS if:
74     //  |size| is not a multiple of PAGE_SIZE
75     //  |vaddr| is not aligned to PAGE_SIZE
76     // Returns ZX_ERR_NOT_FOUND if |bus_txn_id| is not valid.
77     virtual zx_status_t Unmap(uint64_t bus_txn_id, dev_vaddr_t vaddr, size_t size) = 0;
78 
79     // Remove all mappings for |bus_txn_id|.
80     // Returns ZX_ERR_NOT_FOUND if |bus_txn_id| is not valid.
81     virtual zx_status_t ClearMappingsForBusTxnId(uint64_t bus_txn_id) = 0;
82 
83     // Returns the number of bytes that Map() can guarantee, upon success, to find
84     // a contiguous address range for.  This function is only returns meaningful
85     // values if |IsValidBusTxnId(bus_txn_id)|.
86     virtual uint64_t minimum_contiguity(uint64_t bus_txn_id) = 0;
87 
88     // Returns the total size of the space the addresses are mapped into.  This
89     // function is only returns meaningful values if |IsValidBusTxnId(bus_txn_id)|.
90     virtual uint64_t aspace_size(uint64_t bus_txn_id) = 0;
91 
~Iommu()92     virtual ~Iommu() { }
93 };
94