1 // Copyright 2016 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 <assert.h> 10 #include <fbl/array.h> 11 #include <fbl/canary.h> 12 #include <fbl/intrusive_double_list.h> 13 #include <fbl/macros.h> 14 #include <fbl/ref_counted.h> 15 #include <fbl/ref_ptr.h> 16 #include <kernel/mutex.h> 17 #include <lib/user_copy/user_ptr.h> 18 #include <list.h> 19 #include <stdint.h> 20 #include <vm/page_source.h> 21 #include <vm/pmm.h> 22 #include <vm/vm.h> 23 #include <vm/vm_aspace.h> 24 #include <vm/vm_object.h> 25 #include <vm/vm_page_list.h> 26 #include <zircon/thread_annotations.h> 27 #include <zircon/types.h> 28 29 // the main VM object type, holding a list of pages 30 class VmObjectPaged final : public VmObject { 31 public: 32 // |options_| is a bitmask of: 33 static constexpr uint32_t kResizable = (1u << 0); 34 static constexpr uint32_t kContiguous = (1u << 1); 35 36 static zx_status_t Create(uint32_t pmm_alloc_flags, 37 uint32_t options, 38 uint64_t size, fbl::RefPtr<VmObject>* vmo); 39 40 // Create a VMO backed by a contiguous range of physical memory. The 41 // returned vmo has all of its pages committed, and does not allow 42 // decommitting them. 43 static zx_status_t CreateContiguous(uint32_t pmm_alloc_flags, uint64_t size, 44 uint8_t alignment_log2, fbl::RefPtr<VmObject>* vmo); 45 46 static zx_status_t CreateFromROData(const void* data, size_t size, fbl::RefPtr<VmObject>* vmo); 47 48 static zx_status_t CreateExternal(fbl::RefPtr<PageSource> src, 49 uint64_t size, fbl::RefPtr<VmObject>* vmo); 50 51 zx_status_t Resize(uint64_t size) override; 52 zx_status_t ResizeLocked(uint64_t size) override TA_REQ(lock_); create_options()53 uint32_t create_options() const override { return options_; } size()54 uint64_t size() const override 55 // TODO: Figure out whether it's safe to lock here without causing 56 // any deadlocks. 57 TA_NO_THREAD_SAFETY_ANALYSIS { return size_; } is_paged()58 bool is_paged() const override { return true; } is_contiguous()59 bool is_contiguous() const override { return (options_ & kContiguous); } is_resizable()60 bool is_resizable() const override { return (options_ & kResizable); } 61 62 size_t AllocatedPagesInRange(uint64_t offset, uint64_t len) const override; 63 64 zx_status_t CommitRange(uint64_t offset, uint64_t len) override; 65 zx_status_t DecommitRange(uint64_t offset, uint64_t len) override; 66 67 zx_status_t Pin(uint64_t offset, uint64_t len) override; 68 void Unpin(uint64_t offset, uint64_t len) override; 69 70 zx_status_t Read(void* ptr, uint64_t offset, size_t len) override; 71 zx_status_t Write(const void* ptr, uint64_t offset, size_t len) override; 72 zx_status_t Lookup(uint64_t offset, uint64_t len, 73 vmo_lookup_fn_t lookup_fn, void* context) override; 74 75 zx_status_t ReadUser(user_out_ptr<void> ptr, uint64_t offset, size_t len) override; 76 zx_status_t WriteUser(user_in_ptr<const void> ptr, uint64_t offset, size_t len) override; 77 78 void Dump(uint depth, bool verbose) override; 79 80 zx_status_t InvalidateCache(const uint64_t offset, const uint64_t len) override; 81 zx_status_t CleanCache(const uint64_t offset, const uint64_t len) override; 82 zx_status_t CleanInvalidateCache(const uint64_t offset, const uint64_t len) override; 83 zx_status_t SyncCache(const uint64_t offset, const uint64_t len) override; 84 85 zx_status_t GetPageLocked(uint64_t offset, uint pf_flags, list_node* free_list, 86 vm_page_t**, paddr_t*) override 87 // Calls a Locked method of the parent, which confuses analysis. 88 TA_NO_THREAD_SAFETY_ANALYSIS; 89 90 zx_status_t CloneCOW(bool resizable, uint64_t offset, uint64_t size, bool copy_name, 91 fbl::RefPtr<VmObject>* clone_vmo) override 92 // Calls a Locked method of the child, which confuses analysis. 93 TA_NO_THREAD_SAFETY_ANALYSIS; 94 95 void RangeChangeUpdateFromParentLocked(uint64_t offset, uint64_t len) override 96 // Called under the parent's lock, which confuses analysis. 97 TA_NO_THREAD_SAFETY_ANALYSIS; 98 99 uint32_t GetMappingCachePolicy() const override; 100 zx_status_t SetMappingCachePolicy(const uint32_t cache_policy) override; 101 102 // maximum size of a VMO is one page less than the full 64bit range 103 static const uint64_t MAX_SIZE = ROUNDDOWN(UINT64_MAX, PAGE_SIZE); 104 105 private: 106 // private constructor (use Create()) 107 VmObjectPaged( 108 uint32_t options, uint32_t pmm_alloc_flags, uint64_t size, 109 fbl::RefPtr<VmObject> parent, fbl::RefPtr<PageSource> page_source); 110 111 // private destructor, only called from refptr 112 ~VmObjectPaged() override; 113 friend fbl::RefPtr<VmObjectPaged>; 114 115 DISALLOW_COPY_ASSIGN_AND_MOVE(VmObjectPaged); 116 117 // perform a cache maintenance operation against the vmo. 118 enum class CacheOpType { Invalidate, 119 Clean, 120 CleanInvalidate, 121 Sync 122 }; 123 zx_status_t CacheOp(const uint64_t offset, const uint64_t len, const CacheOpType type); 124 125 // add a page to the object 126 zx_status_t AddPage(vm_page_t* p, uint64_t offset); 127 zx_status_t AddPageLocked(vm_page_t* p, uint64_t offset) TA_REQ(lock_); 128 129 // internal page list routine 130 void AddPageToArray(size_t index, vm_page_t* p); 131 132 zx_status_t PinLocked(uint64_t offset, uint64_t len) TA_REQ(lock_); 133 void UnpinLocked(uint64_t offset, uint64_t len) TA_REQ(lock_); 134 135 // internal check if any pages in a range are pinned 136 bool AnyPagesPinnedLocked(uint64_t offset, size_t len) TA_REQ(lock_); 137 138 // internal read/write routine that takes a templated copy function to help share some code 139 template <typename T> 140 zx_status_t ReadWriteInternal(uint64_t offset, size_t len, bool write, T copyfunc); 141 142 // set our offset within our parent 143 zx_status_t SetParentOffsetLocked(uint64_t o) TA_REQ(lock_); 144 145 // members 146 const uint32_t options_; 147 uint64_t size_ TA_GUARDED(lock_) = 0; 148 uint64_t parent_offset_ TA_GUARDED(lock_) = 0; 149 uint32_t pmm_alloc_flags_ TA_GUARDED(lock_) = PMM_ALLOC_FLAG_ANY; 150 uint32_t cache_policy_ TA_GUARDED(lock_) = ARCH_MMU_FLAG_CACHED; 151 152 // The page source, if any. 153 const fbl::RefPtr<PageSource> page_source_; 154 155 // a tree of pages 156 VmPageList page_list_ TA_GUARDED(lock_); 157 }; 158