1 // Copyright 2018 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 <bits.h>
10 #include <dev/interrupt.h>
11 #include <dev/iommu.h>
12 #include <fbl/intrusive_double_list.h>
13 #include <fbl/macros.h>
14 #include <fbl/mutex.h>
15 #include <hwreg/mmio.h>
16 #include <zircon/syscalls/iommu.h>
17 
18 #include "domain_allocator.h"
19 #include "hw.h"
20 #include "iommu_page.h"
21 
22 class VmMapping;
23 
24 namespace intel_iommu {
25 
26 class ContextTableState;
27 class DeviceContext;
28 
29 class IommuImpl final : public Iommu {
30 public:
31     static zx_status_t Create(ktl::unique_ptr<const uint8_t[]> desc, size_t desc_len,
32                               fbl::RefPtr<Iommu>* out);
33 
34     bool IsValidBusTxnId(uint64_t bus_txn_id) const final;
35 
36     zx_status_t Map(uint64_t bus_txn_id, const fbl::RefPtr<VmObject>& vmo,
37                     uint64_t offset, size_t size, uint32_t perms,
38                     dev_vaddr_t* vaddr, size_t* mapped_len) final;
39     zx_status_t MapContiguous(uint64_t bus_txn_id, const fbl::RefPtr<VmObject>& vmo,
40                               uint64_t offset, size_t size, uint32_t perms,
41                               dev_vaddr_t* vaddr, size_t* mapped_len) final;
42     zx_status_t Unmap(uint64_t bus_txn_id, dev_vaddr_t vaddr, size_t size) final;
43 
44     zx_status_t ClearMappingsForBusTxnId(uint64_t bus_txn_id) final;
45 
46     uint64_t minimum_contiguity(uint64_t bus_txn_id) final;
47     uint64_t aspace_size(uint64_t bus_txn_id) final;
48 
49     ~IommuImpl() final;
50 
51     // TODO(teisenbe): These should be const, but need to teach the register
52     // library about constness
caps()53     reg::Capability* caps() { return &caps_; }
extended_caps()54     reg::ExtendedCapability* extended_caps() { return &extended_caps_; }
55 
56     // Invalidate all context cache entries
57     void InvalidateContextCacheGlobal();
58     // Invalidate all context cache entries that are in the specified domain
59     void InvalidateContextCacheDomain(uint32_t domain_id);
60 
61     // Invalidate all IOTLB entries for all domains
62     void InvalidateIotlbGlobal();
63     // Invalidate all IOTLB entries for the specified domain
64     void InvalidateIotlbDomainAll(uint32_t domain_id);
65     void InvalidateIotlbDomainAllLocked(uint32_t domain_id) TA_REQ(lock_);
66 
67     // Invalidate the IOTLB entries for the specified translations.
68     // |pages_pow2| indicates how many pages should be invalidated (calculated
69     // as 2^|pages_pow2|).
70     void InvalidateIotlbPageLocked(uint32_t domain_id, dev_vaddr_t vaddr,
71                                    uint pages_pow2) TA_REQ(lock_);
72 
73 private:
74     DISALLOW_COPY_ASSIGN_AND_MOVE(IommuImpl);
75     IommuImpl(volatile void* register_base, ktl::unique_ptr<const uint8_t[]> desc,
76               size_t desc_len);
77 
decode_bus_txn_id(uint64_t bus_txn_id)78     static ds::Bdf decode_bus_txn_id(uint64_t bus_txn_id) {
79         ds::Bdf bdf;
80         bdf.set_bus(static_cast<uint16_t>(BITS_SHIFT(bus_txn_id, 15, 8)));
81         bdf.set_dev(static_cast<uint16_t>(BITS_SHIFT(bus_txn_id, 7, 3)));
82         bdf.set_func(static_cast<uint16_t>(BITS_SHIFT(bus_txn_id, 2, 0)));
83         return bdf;
84     }
85 
86     static zx_status_t ValidateIommuDesc(const ktl::unique_ptr<const uint8_t[]>& desc,
87                                          size_t desc_len);
88 
89     // Set up initial root structures and enable translation
90     zx_status_t Initialize();
91 
92     // Context cache invalidation
93     void InvalidateContextCacheGlobalLocked() TA_REQ(lock_);
94     void InvalidateContextCacheDomainLocked(uint32_t domain_id) TA_REQ(lock_);
95 
96     // IOTLB invalidation
97     void InvalidateIotlbGlobalLocked() TA_REQ(lock_);
98 
99     zx_status_t SetRootTablePointerLocked(paddr_t pa) TA_REQ(lock_);
100     zx_status_t SetTranslationEnableLocked(bool enabled, zx_time_t deadline) TA_REQ(lock_);
101     zx_status_t ConfigureFaultEventInterruptLocked() TA_REQ(lock_);
102 
103     // Process Reserved Memory Mapping Regions and set them up as pass-through.
104     zx_status_t EnableBiosReservedMappingsLocked() TA_REQ(lock_);
105 
106     void DisableFaultsLocked() TA_REQ(lock_);
107     static interrupt_eoi FaultHandler(void* ctx);
108     zx_status_t GetOrCreateContextTableLocked(ds::Bdf bdf, ContextTableState** tbl) TA_REQ(lock_);
109     zx_status_t GetOrCreateDeviceContextLocked(ds::Bdf bdf, DeviceContext** context) TA_REQ(lock_);
110 
111     // Utility for waiting until a register field changes to a value, timing out
112     // if the deadline elapses.  If deadline is ZX_TIME_INFINITE, then will never time
113     // out.  Can only return NO_ERROR and ERR_TIMED_OUT.
114     template <class RegType>
115     zx_status_t WaitForValueLocked(RegType* reg,
116                                    typename RegType::ValueType (RegType::*getter)() const,
117                                    typename RegType::ValueType value,
118                                    zx_time_t deadline) TA_REQ(lock_);
119 
root_table()120     volatile ds::RootTable* root_table() const TA_REQ(lock_) {
121         return reinterpret_cast<volatile ds::RootTable*>(root_table_page_.vaddr());
122     }
123 
124     fbl::Mutex lock_;
125 
126     // Descriptor of this hardware unit
127     ktl::unique_ptr<const uint8_t[]> desc_;
128     size_t desc_len_;
129 
130     // Location of the memory-mapped hardware register bank.
131     hwreg::RegisterIo mmio_ TA_GUARDED(lock_);
132 
133     // Interrupt allocation
134     msi_block_t irq_block_ TA_GUARDED(lock_);
135 
136     // In-memory root table
137     IommuPage root_table_page_ TA_GUARDED(lock_);
138     // List of allocated context tables
139     fbl::DoublyLinkedList<ktl::unique_ptr<ContextTableState>> context_tables_ TA_GUARDED(lock_);
140 
141     DomainAllocator domain_allocator_ TA_GUARDED(lock_);
142 
143     // A mask with bits set for each usable bit in an address with the largest allowed
144     // address width.  E.g., if the largest allowed width is 48-bit,
145     // max_guest_addr_mask will be 0xffff_ffff_ffff.
146     uint64_t max_guest_addr_mask_ TA_GUARDED(lock_) = 0;
147     uint32_t valid_pasid_mask_ TA_GUARDED(lock_) = 0;
148     uint32_t iotlb_reg_offset_ TA_GUARDED(lock_) = 0;
149     uint32_t fault_recording_reg_offset_ TA_GUARDED(lock_) = 0;
150     uint32_t num_fault_recording_reg_ TA_GUARDED(lock_) = 0;
151     bool supports_extended_context_ TA_GUARDED(lock_) = 0;
152 
153     reg::Capability caps_;
154     reg::ExtendedCapability extended_caps_;
155 };
156 
157 } // namespace intel_iommu
158