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 <fbl/intrusive_double_list.h>
10 #include <fbl/macros.h>
11 #include <ktl/unique_ptr.h>
12 
13 #include "hw.h"
14 #include "iommu_page.h"
15 
16 namespace intel_iommu {
17 
18 class DeviceContext;
19 class IommuImpl;
20 
21 class ContextTableState : public fbl::DoublyLinkedListable<ktl::unique_ptr<ContextTableState>> {
22 public:
23     ~ContextTableState();
24 
25     // Create a ContextTableState for the given bus.
26     // If |extended| is true, then this will represent a reg::ExtendedContextTable,
27     // and the table will handle translations for, depending on |upper|, either the
28     // lower (dev<16) or upper half of this bus.
29     // If |extended| is false, this represents a reg::ContextTable.
30     static zx_status_t Create(uint8_t bus, bool extended, bool upper,
31                               IommuImpl* parent, volatile ds::RootEntrySubentry* root_entry,
32                               ktl::unique_ptr<ContextTableState>* table);
33 
34     // Check if this ContextTableState is for the given BDF
includes_bdf(ds::Bdf bdf)35     bool includes_bdf(ds::Bdf bdf) const {
36         if (bdf.bus() != bus_) {
37             return false;
38         }
39         if (!extended_) {
40             return true;
41         }
42         return (bdf.dev() >= 16) == upper_;
43     }
44 
45     // Create a new DeviceContext representing the given BDF, and give it the specified domain_id.
46     // It is a fatal error to try to create a context for a BDF that already has one.
47     zx_status_t CreateDeviceContext(ds::Bdf bdf, uint32_t domain_id,
48                                     DeviceContext** context);
49 
50     zx_status_t GetDeviceContext(ds::Bdf bdf, DeviceContext** context);
51 
52 private:
53     ContextTableState(uint8_t bus, bool extended, bool upper, IommuImpl* parent,
54                       volatile ds::RootEntrySubentry* root_entry, IommuPage page);
55 
56     DISALLOW_COPY_ASSIGN_AND_MOVE(ContextTableState);
57 
table()58     volatile ds::ContextTable* table() const {
59         DEBUG_ASSERT(!extended_);
60         return reinterpret_cast<volatile ds::ContextTable*>(page_.vaddr());
61     }
62 
extended_table()63     volatile ds::ExtendedContextTable* extended_table() const {
64         DEBUG_ASSERT(extended_);
65         return reinterpret_cast<volatile ds::ExtendedContextTable*>(page_.vaddr());
66     }
67 
68     // Pointer to IOMMU that owns this ContextTableState
69     IommuImpl* const parent_;
70     // Pointer to the half of the Root Table Entry that decodes to this
71     // ContextTable.
72     volatile ds::RootEntrySubentry* const root_entry_;
73 
74     // Page backing the ContextTable/ExtendedContextTable
75     const IommuPage page_;
76 
77     // List of device configurations beneath this ContextTable.
78     fbl::DoublyLinkedList<ktl::unique_ptr<DeviceContext>> devices_;
79 
80     const uint8_t bus_;
81     const bool extended_;
82     // Only valid if extended_ is true
83     const bool upper_;
84 };
85 
86 } // namespace intel_iommu
87