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 <fbl/unique_ptr.h> 12#include <fbl/vector.h> 13#include <region-alloc/region-alloc.h> 14#include <vm/vm_object.h> 15 16#include "hw.h" 17#include "second_level_pt.h" 18 19namespace intel_iommu { 20 21class IommuImpl; 22 23class DeviceContext : public fbl::DoublyLinkedListable<fbl::unique_ptr<DeviceContext>> { 24public: 25 ~DeviceContext(); 26 27 // Create a new DeviceContext representing the given BDF. It is a fatal error 28 // to try to create a context for a BDF that already has one. 29 static zx_status_t Create(ds::Bdf bdf, uint32_t domain_id, IommuImpl* parent, 30 volatile ds::ExtendedContextEntry* context_entry, 31 fbl::unique_ptr<DeviceContext>* device); 32 static zx_status_t Create(ds::Bdf bdf, uint32_t domain_id, IommuImpl* parent, 33 volatile ds::ContextEntry* context_entry, 34 fbl::unique_ptr<DeviceContext>* device); 35 36 // Check if this DeviceContext is for the given BDF 37 bool is_bdf(ds::Bdf bdf) const { 38 return bdf_ == bdf; 39 } 40 41 uint32_t domain_id() const { return domain_id_; } 42 43 uint64_t minimum_contiguity() const; 44 uint64_t aspace_size() const; 45 46 // Use the second-level translation table to map the host pages in the given 47 // range on |vmo| to the guest's address |*virt_paddr|. |size| is in bytes. 48 // |mapped_len| may be larger than |size|, if |size| was not page-aligned. 49 // 50 // If |map_contiguous| is false, this function may return a partial mapping, 51 // in which case |mapped_len| will indicate how many bytes were actually mapped. 52 // 53 // If |map_contiguous| is true, this function will never return a partial 54 // mapping, and |mapped_len| should be equal to |size|. 55 zx_status_t SecondLevelMap(const fbl::RefPtr<VmObject>& vmo, 56 uint64_t offset, size_t size, uint32_t perms, 57 bool map_contiguous, paddr_t* virt_paddr, size_t* mapped_len); 58 zx_status_t SecondLevelUnmap(paddr_t virt_paddr, size_t size); 59 60 // Use the second-level translation table to identity-map the given range of 61 // host pages. 62 zx_status_t SecondLevelMapIdentity(paddr_t base, size_t size, uint32_t perms); 63 64private: 65 DeviceContext(ds::Bdf bdf, uint32_t domain_id, IommuImpl* parent, 66 volatile ds::ExtendedContextEntry* context_entry); 67 DeviceContext(ds::Bdf bdf, uint32_t domain_id, IommuImpl* parent, 68 volatile ds::ContextEntry* context_entry); 69 70 DISALLOW_COPY_ASSIGN_AND_MOVE(DeviceContext); 71 72 // Shared initialization code for the two public Create() methods 73 zx_status_t InitCommon(); 74 75 // Map a VMO which may consist of discontiguous physical pages. If 76 // |map_contiguous| is true, this must either map the whole requested range 77 // contiguously, or fail. If |map_contiguous| is false, it may return 78 // success with a partial mapping. 79 zx_status_t SecondLevelMapDiscontiguous(const fbl::RefPtr<VmObject>& vmo, 80 uint64_t offset, size_t size, uint flags, 81 bool map_contiguous, paddr_t* virt_paddr, 82 size_t* mapped_len); 83 84 // Map a VMO which consists of contiguous physical pages. Currently we assume 85 // that all contiguous VMOs should be mapped as a contiguous range, so this 86 // function will not return a partial mapping. 87 zx_status_t SecondLevelMapContiguous(const fbl::RefPtr<VmObject>& vmo, 88 uint64_t offset, size_t size, uint flags, 89 paddr_t* virt_paddr, size_t* mapped_len); 90 91 IommuImpl* const parent_; 92 union { 93 volatile ds::ExtendedContextEntry* const extended_context_entry_; 94 volatile ds::ContextEntry* const context_entry_; 95 }; 96 97 // Page tables used for translating requests-without-PASID and for nested 98 // translation of requests-with-PASID. 99 SecondLevelPageTable second_level_pt_; 100 RegionAllocator region_alloc_; 101 // TODO(teisenbe): Use a better data structure for these. If the region 102 // nodes were intrusive, we wouldn't need to have a resizable array for this 103 // and we could have cheaper removal. We can fix this up when it's a 104 // problem though. 105 fbl::Vector<fbl::unique_ptr<const RegionAllocator::Region>> allocated_regions_; 106 107 const ds::Bdf bdf_; 108 const bool extended_; 109 const uint32_t domain_id_; 110}; 111 112} // namespace intel_iommu 113