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 22class VmMapping; 23 24namespace intel_iommu { 25 26class ContextTableState; 27class DeviceContext; 28 29class IommuImpl final : public Iommu { 30public: 31 static zx_status_t Create(fbl::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 53 reg::Capability* caps() { return &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 73private: 74 DISALLOW_COPY_ASSIGN_AND_MOVE(IommuImpl); 75 IommuImpl(volatile void* register_base, fbl::unique_ptr<const uint8_t[]> desc, 76 size_t desc_len); 77 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 fbl::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 void 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 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 fbl::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<fbl::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