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#include "context_table_state.h" 8 9#include <zxcpp/new.h> 10#include <fbl/unique_ptr.h> 11 12#include "device_context.h" 13#include "hw.h" 14#include "iommu_impl.h" 15 16namespace intel_iommu { 17 18ContextTableState::ContextTableState(uint8_t bus, bool extended, bool upper, 19 IommuImpl* parent, volatile ds::RootEntrySubentry* root_entry, 20 IommuPage page) 21 : parent_(parent), root_entry_(root_entry), page_(fbl::move(page)), 22 bus_(bus), extended_(extended), upper_(upper) { 23} 24 25ContextTableState::~ContextTableState() { 26 ds::RootEntrySubentry entry; 27 entry.ReadFrom(root_entry_); 28 entry.set_present(0); 29 entry.WriteTo(root_entry_); 30 31 // When modifying a present (extended) root entry, we must serially 32 // invalidate the context-cache, the PASID-cache, then the IOTLB (see 33 // 6.2.2.1 "Context-Entry Programming Considerations" in the VT-d spec, 34 // Oct 2014 rev). 35 parent_->InvalidateContextCacheGlobal(); 36 // TODO(teisenbe): Invalidate the PASID cache once we support those 37 parent_->InvalidateIotlbGlobal(); 38} 39 40zx_status_t ContextTableState::Create(uint8_t bus, bool extended, bool upper, 41 IommuImpl* parent, volatile ds::RootEntrySubentry* root_entry, 42 fbl::unique_ptr<ContextTableState>* table) { 43 ds::RootEntrySubentry entry; 44 entry.ReadFrom(root_entry); 45 DEBUG_ASSERT(!entry.present()); 46 47 IommuPage page; 48 zx_status_t status = IommuPage::AllocatePage(&page); 49 if (status != ZX_OK) { 50 return status; 51 } 52 53 fbl::AllocChecker ac; 54 fbl::unique_ptr<ContextTableState> tbl(new (&ac) ContextTableState(bus, extended, upper, 55 parent, root_entry, 56 fbl::move(page))); 57 if (!ac.check()) { 58 return ZX_ERR_NO_MEMORY; 59 } 60 61 entry.set_present(1); 62 entry.set_context_table(tbl->page_.paddr() >> 12); 63 entry.WriteTo(root_entry); 64 65 *table = fbl::move(tbl); 66 return ZX_OK; 67} 68 69zx_status_t ContextTableState::CreateDeviceContext(ds::Bdf bdf, uint32_t domain_id, 70 DeviceContext** context) { 71 DEBUG_ASSERT(bus_ == bdf.bus()); 72 73 fbl::unique_ptr<DeviceContext> dev; 74 zx_status_t status; 75 if (extended_) { 76 DEBUG_ASSERT(upper_ == (bdf.dev() >= 16)); 77 volatile ds::ExtendedContextTable* tbl = extended_table(); 78 volatile ds::ExtendedContextEntry* entry = &tbl->entry[bdf.packed_dev_and_func() & 0x7f]; 79 status = DeviceContext::Create(bdf, domain_id, parent_, entry, &dev); 80 } else { 81 volatile ds::ContextTable* tbl = table(); 82 volatile ds::ContextEntry* entry = &tbl->entry[bdf.packed_dev_and_func()]; 83 status = DeviceContext::Create(bdf, domain_id, parent_, entry, &dev); 84 } 85 if (status != ZX_OK) { 86 return status; 87 } 88 89 *context = dev.get(); 90 devices_.push_back(fbl::move(dev)); 91 return ZX_OK; 92} 93 94zx_status_t ContextTableState::GetDeviceContext(ds::Bdf bdf, DeviceContext** context) { 95 for (auto& dev : devices_) { 96 if (dev.is_bdf(bdf)) { 97 *context = &dev; 98 return ZX_OK; 99 } 100 } 101 return ZX_ERR_NOT_FOUND; 102} 103 104} // namespace intel_iommu 105