Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_OS_FUCHSIA) | 6 #if defined(TARGET_OS_FUCHSIA) |
| 7 | 7 |
| 8 #include "vm/virtual_memory.h" | 8 #include "vm/virtual_memory.h" |
| 9 | 9 |
| 10 #include <magenta/status.h> | 10 #include <magenta/status.h> |
| 11 #include <magenta/syscalls.h> | 11 #include <magenta/syscalls.h> |
| 12 #include <sys/mman.h> | 12 #include <sys/mman.h> |
| 13 #include <unistd.h> | 13 #include <unistd.h> |
| 14 | 14 |
| 15 #include "platform/assert.h" | 15 #include "platform/assert.h" |
| 16 #include "vm/allocation.h" | |
| 17 #include "vm/growable_array.h" | |
| 16 #include "vm/isolate.h" | 18 #include "vm/isolate.h" |
| 19 #include "vm/lockers.h" | |
| 17 #include "vm/memory_region.h" | 20 #include "vm/memory_region.h" |
| 18 #include "vm/os.h" | 21 #include "vm/os.h" |
| 22 #include "vm/os_thread.h" | |
| 19 | 23 |
| 20 // #define VIRTUAL_MEMORY_LOGGING 1 | 24 // #define VIRTUAL_MEMORY_LOGGING 1 |
| 21 #if defined(VIRTUAL_MEMORY_LOGGING) | 25 #if defined(VIRTUAL_MEMORY_LOGGING) |
| 22 #define LOG_ERR(msg, ...) \ | 26 #define LOG_ERR(msg, ...) \ |
| 23 OS::PrintErr("VMVM: %s:%d: " msg, __FILE__, __LINE__, ##__VA_ARGS__) | 27 OS::PrintErr("VMVM: %s:%d: " msg, __FILE__, __LINE__, ##__VA_ARGS__) |
| 24 #define LOG_INFO(msg, ...) \ | 28 #define LOG_INFO(msg, ...) \ |
| 25 OS::Print("VMVM: %s:%d: " msg, __FILE__, __LINE__, ##__VA_ARGS__) | 29 OS::Print("VMVM: %s:%d: " msg, __FILE__, __LINE__, ##__VA_ARGS__) |
| 26 #else | 30 #else |
| 27 #define LOG_ERR(msg, ...) | 31 #define LOG_ERR(msg, ...) |
| 28 #define LOG_INFO(msg, ...) | 32 #define LOG_INFO(msg, ...) |
| 29 #endif // defined(VIRTUAL_MEMORY_LOGGING) | 33 #endif // defined(VIRTUAL_MEMORY_LOGGING) |
| 30 | 34 |
| 31 namespace dart { | 35 namespace dart { |
| 32 | 36 |
| 37 // The Magenta system call to protect memory regions (mx_vmar_protect) takes a | |
| 38 // VM area (vmar) handle as first argument. We call VirtualMemory::Protect() | |
| 39 // from the memory freelist code in vm/freelist.cc where the vmar handle is not | |
| 40 // available. Additionally, there is no mx_vmar system call to retrieve a handle | |
| 41 // for the leaf vmar given an address. Thus, when memory protections are | |
| 42 // enabled, we maintain a sorted list of our leaf vmar handles that we can | |
| 43 // query by address in calls to VirtualMemory::Protect(). | |
| 44 class VmarList : public AllStatic { | |
| 45 public: | |
| 46 static void AddVmar(mx_handle_t vmar, uword addr, intptr_t size); | |
| 47 static void RemoveVmar(uword addr); | |
| 48 static mx_handle_t LookupVmar(uword addr); | |
| 49 | |
| 50 private: | |
| 51 static intptr_t LookupVmarIndexLocked(uword addr); | |
| 52 | |
| 53 struct VmarListElement { | |
| 54 mx_handle_t vmar; | |
| 55 uword addr; | |
| 56 intptr_t size; | |
| 57 }; | |
| 58 | |
| 59 static Mutex* vmar_array_lock_; | |
| 60 static MallocGrowableArray<VmarListElement> vmar_array_; | |
| 61 }; | |
| 62 | |
| 63 Mutex* VmarList::vmar_array_lock_ = new Mutex(); | |
| 64 MallocGrowableArray<VmarList::VmarListElement> VmarList::vmar_array_; | |
| 65 | |
| 66 void VmarList::AddVmar(mx_handle_t vmar, uword addr, intptr_t size) { | |
| 67 MutexLocker ml(vmar_array_lock_); | |
| 68 LOG_INFO("AddVmar(%d, %lx, %ld)\n", vmar, addr, size); | |
| 69 // Sorted insert in increasing order. | |
| 70 const intptr_t length = vmar_array_.length(); | |
| 71 intptr_t idx; | |
| 72 for (idx = 0; idx < length; idx++) { | |
| 73 const VmarListElement& m = vmar_array_.At(idx); | |
| 74 if (m.addr >= addr) { | |
| 75 break; | |
| 76 } | |
| 77 } | |
| 78 #if defined(DEBUG) | |
| 79 if ((length > 0) && (idx < (length - 1))) { | |
| 80 const VmarListElement& m = vmar_array_.At(idx); | |
| 81 ASSERT(m.addr != addr); | |
| 82 } | |
| 83 #endif | |
| 84 LOG_INFO("AddVmar(%d, %lx, %ld) at index = %ld\n", vmar, addr, size, idx); | |
| 85 VmarListElement new_mapping; | |
| 86 new_mapping.vmar = vmar; | |
| 87 new_mapping.addr = addr; | |
| 88 new_mapping.size = size; | |
| 89 vmar_array_.InsertAt(idx, new_mapping); | |
| 90 } | |
| 91 | |
| 92 | |
| 93 intptr_t VmarList::LookupVmarIndexLocked(uword addr) { | |
| 94 // Binary search for the vmar containing addr. | |
| 95 intptr_t imin = 0; | |
| 96 intptr_t imax = vmar_array_.length(); | |
| 97 while (imax >= imin) { | |
| 98 const intptr_t imid = ((imax - imin) / 2) + imin; | |
| 99 const VmarListElement& mapping = vmar_array_.At(imid); | |
| 100 if ((mapping.addr + mapping.size) <= addr) { | |
| 101 imin = imid + 1; | |
| 102 } else if (mapping.addr > addr) { | |
| 103 imax = imid - 1; | |
| 104 } else { | |
| 105 return imid; | |
| 106 } | |
| 107 } | |
| 108 return -1; | |
| 109 } | |
| 110 | |
| 111 | |
| 112 mx_handle_t VmarList::LookupVmar(uword addr) { | |
| 113 MutexLocker ml(vmar_array_lock_); | |
| 114 LOG_INFO("LookupVmar(%lx)\n", addr); | |
| 115 const intptr_t idx = LookupVmarIndexLocked(addr); | |
| 116 if (idx == -1) { | |
| 117 LOG_ERR("LookupVmar(%lx) NOT FOUND\n", addr); | |
| 118 return MX_HANDLE_INVALID; | |
| 119 } | |
| 120 LOG_INFO("LookupVmar(%lx) found at %ld\n", addr, idx); | |
| 121 return vmar_array_[idx].vmar; | |
| 122 } | |
| 123 | |
| 124 | |
| 125 void VmarList::RemoveVmar(uword addr) { | |
| 126 MutexLocker ml(vmar_array_lock_); | |
| 127 LOG_INFO("RemoveVmar(%lx)\n", addr); | |
| 128 const intptr_t idx = LookupVmarIndexLocked(addr); | |
| 129 ASSERT(idx != -1); | |
| 130 #if defined(DEBUG) | |
| 131 mx_handle_t vmar = vmar_array_[idx].vmar; | |
| 132 #endif | |
| 133 // Swap idx to the end, and then RemoveLast() | |
| 134 const intptr_t length = vmar_array_.length(); | |
| 135 for (intptr_t i = idx; i < length - 1; i++) { | |
| 136 vmar_array_.Swap(i, i + 1); | |
| 137 } | |
| 138 #if defined(DEBUG) | |
| 139 const VmarListElement& mapping = vmar_array_.Last(); | |
| 140 ASSERT(mapping.vmar == vmar); | |
| 141 #endif | |
| 142 vmar_array_.RemoveLast(); | |
| 143 } | |
| 144 | |
| 145 | |
| 33 uword VirtualMemory::page_size_ = 0; | 146 uword VirtualMemory::page_size_ = 0; |
| 34 | 147 |
| 35 | 148 |
| 36 void VirtualMemory::InitOnce() { | 149 void VirtualMemory::InitOnce() { |
| 37 page_size_ = getpagesize(); | 150 page_size_ = getpagesize(); |
| 38 } | 151 } |
| 39 | 152 |
| 40 | 153 |
| 41 VirtualMemory* VirtualMemory::ReserveInternal(intptr_t size) { | 154 VirtualMemory* VirtualMemory::ReserveInternal(intptr_t size) { |
| 42 mx_handle_t vmar = MX_HANDLE_INVALID; | 155 mx_handle_t vmar = MX_HANDLE_INVALID; |
| 43 uword addr = 0; | 156 uword addr = 0; |
| 44 const uint32_t flags = MX_VM_FLAG_COMPACT | MX_VM_FLAG_CAN_MAP_SPECIFIC | | 157 const uint32_t flags = MX_VM_FLAG_COMPACT | MX_VM_FLAG_CAN_MAP_SPECIFIC | |
| 45 MX_VM_FLAG_CAN_MAP_READ | MX_VM_FLAG_CAN_MAP_WRITE | | 158 MX_VM_FLAG_CAN_MAP_READ | MX_VM_FLAG_CAN_MAP_WRITE | |
| 46 MX_VM_FLAG_CAN_MAP_EXECUTE; | 159 MX_VM_FLAG_CAN_MAP_EXECUTE; |
| 47 mx_status_t status = | 160 mx_status_t status = |
| 48 mx_vmar_allocate(mx_vmar_root_self(), 0, size, flags, &vmar, &addr); | 161 mx_vmar_allocate(mx_vmar_root_self(), 0, size, flags, &vmar, &addr); |
| 49 if (status != NO_ERROR) { | 162 if (status != NO_ERROR) { |
| 50 LOG_ERR("mx_vmar_allocate(size = %ld) failed: %s\n", size, | 163 LOG_ERR("mx_vmar_allocate(size = %ld) failed: %s\n", size, |
| 51 mx_status_get_string(status)); | 164 mx_status_get_string(status)); |
| 52 return NULL; | 165 return NULL; |
| 53 } | 166 } |
| 54 | 167 VmarList::AddVmar(vmar, addr, size); |
| 55 MemoryRegion region(reinterpret_cast<void*>(addr), size); | 168 MemoryRegion region(reinterpret_cast<void*>(addr), size); |
| 56 return new VirtualMemory(region, vmar); | 169 return new VirtualMemory(region, vmar); |
| 57 } | 170 } |
| 58 | 171 |
| 59 | 172 |
| 60 VirtualMemory::~VirtualMemory() { | 173 VirtualMemory::~VirtualMemory() { |
| 61 if (!embedder_allocated()) { | 174 if (!embedder_allocated()) { |
| 62 mx_handle_t vmar = static_cast<mx_handle_t>(handle()); | 175 mx_handle_t vmar = static_cast<mx_handle_t>(handle()); |
| 63 mx_status_t status = mx_vmar_destroy(vmar); | 176 mx_status_t status = mx_vmar_destroy(vmar); |
| 64 if (status != NO_ERROR) { | 177 if (status != NO_ERROR) { |
| 65 LOG_ERR("mx_vmar_destroy failed: %s\n", mx_status_get_string(status)); | 178 LOG_ERR("mx_vmar_destroy failed: %s\n", mx_status_get_string(status)); |
| 66 } | 179 } |
| 67 status = mx_handle_close(vmar); | 180 status = mx_handle_close(vmar); |
| 68 if (status != NO_ERROR) { | 181 if (status != NO_ERROR) { |
| 69 LOG_ERR("mx_handle_close failed: %s\n", mx_status_get_string(status)); | 182 LOG_ERR("mx_handle_close failed: %s\n", mx_status_get_string(status)); |
| 70 } | 183 } |
| 184 VmarList::RemoveVmar(start()); | |
| 71 } | 185 } |
| 72 } | 186 } |
| 73 | 187 |
| 74 | 188 |
| 75 bool VirtualMemory::FreeSubSegment(int32_t handle, | 189 bool VirtualMemory::FreeSubSegment(int32_t handle, |
| 76 void* address, | 190 void* address, |
| 77 intptr_t size) { | 191 intptr_t size) { |
| 78 mx_handle_t vmar = static_cast<mx_handle_t>(handle); | 192 mx_handle_t vmar = static_cast<mx_handle_t>(handle); |
| 79 mx_status_t status = | 193 mx_status_t status = |
| 80 mx_vmar_unmap(vmar, reinterpret_cast<uintptr_t>(address), size); | 194 mx_vmar_unmap(vmar, reinterpret_cast<uintptr_t>(address), size); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 92 mx_handle_t vmo = MX_HANDLE_INVALID; | 206 mx_handle_t vmo = MX_HANDLE_INVALID; |
| 93 mx_status_t status = mx_vmo_create(size, 0u, &vmo); | 207 mx_status_t status = mx_vmo_create(size, 0u, &vmo); |
| 94 if (status != NO_ERROR) { | 208 if (status != NO_ERROR) { |
| 95 LOG_ERR("mx_vmo_create(%ld) failed: %s\n", size, | 209 LOG_ERR("mx_vmo_create(%ld) failed: %s\n", size, |
| 96 mx_status_get_string(status)); | 210 mx_status_get_string(status)); |
| 97 return false; | 211 return false; |
| 98 } | 212 } |
| 99 | 213 |
| 100 mx_handle_t vmar = static_cast<mx_handle_t>(handle()); | 214 mx_handle_t vmar = static_cast<mx_handle_t>(handle()); |
| 101 const size_t offset = addr - start(); | 215 const size_t offset = addr - start(); |
| 102 const uint32_t flags = MX_VM_FLAG_SPECIFIC | MX_VM_FLAG_PERM_READ | | 216 const uint32_t flags = MX_VM_FLAG_SPECIFIC | |
| 103 MX_VM_FLAG_PERM_WRITE | MX_VM_FLAG_PERM_EXECUTE; | 217 MX_VM_FLAG_PERM_READ | |
| 218 MX_VM_FLAG_PERM_WRITE | | |
| 219 (executable ? MX_VM_FLAG_PERM_EXECUTE : 0); | |
| 104 uintptr_t mapped_addr; | 220 uintptr_t mapped_addr; |
| 105 status = mx_vmar_map(vmar, offset, vmo, 0, size, flags, &mapped_addr); | 221 status = mx_vmar_map(vmar, offset, vmo, 0, size, flags, &mapped_addr); |
| 106 if (status != NO_ERROR) { | 222 if (status != NO_ERROR) { |
| 107 mx_handle_close(vmo); | 223 mx_handle_close(vmo); |
| 108 LOG_ERR("mx_vmar_map(%ld, %ld, %u) failed: %s\n", offset, size, flags, | 224 LOG_ERR("mx_vmar_map(%ld, %ld, %u) failed: %s\n", offset, size, flags, |
| 109 mx_status_get_string(status)); | 225 mx_status_get_string(status)); |
| 110 return false; | 226 return false; |
| 111 } | 227 } |
| 112 if (addr != mapped_addr) { | 228 if (addr != mapped_addr) { |
| 229 mx_handle_close(vmo); | |
| 113 LOG_ERR("mx_vmar_map: addr != mapped_addr: %lx != %lx\n", addr, | 230 LOG_ERR("mx_vmar_map: addr != mapped_addr: %lx != %lx\n", addr, |
| 114 mapped_addr); | 231 mapped_addr); |
| 115 return false; | 232 return false; |
| 116 } | 233 } |
| 234 mx_handle_close(vmo); | |
| 235 LOG_INFO("Commit(%lx, %ld, %s): success\n", | |
| 236 addr, size, executable ? "executable" : ""); | |
| 117 return true; | 237 return true; |
| 118 } | 238 } |
| 119 | 239 |
| 120 | 240 |
| 121 bool VirtualMemory::Protect(void* address, intptr_t size, Protection mode) { | 241 bool VirtualMemory::Protect(void* address, intptr_t size, Protection mode) { |
| 242 ASSERT(Thread::Current()->IsMutatorThread() || | |
| 243 Isolate::Current()->mutator_thread()->IsAtSafepoint()); | |
| 244 const uword start_address = reinterpret_cast<uword>(address); | |
| 245 const uword end_address = start_address + size; | |
| 246 const uword page_address = Utils::RoundDown(start_address, PageSize()); | |
| 247 mx_handle_t vmar = VmarList::LookupVmar(page_address); | |
| 248 ASSERT(vmar != MX_HANDLE_INVALID); | |
| 249 uint32_t prot = 0; | |
| 250 switch (mode) { | |
| 251 case kNoAccess: | |
| 252 prot = MX_VM_FLAG_PERM_READ; | |
|
rmacnak
2017/01/25 01:46:19
I would expect "0", but the wording of the syscall
zra
2017/01/25 05:44:03
Not clear if it is a bug, or simply not yet implem
| |
| 253 break; | |
| 254 case kReadOnly: | |
| 255 prot = MX_VM_FLAG_PERM_READ; | |
| 256 break; | |
| 257 case kReadWrite: | |
| 258 prot = MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE; | |
| 259 break; | |
| 260 case kReadExecute: | |
| 261 prot = MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_EXECUTE; | |
| 262 break; | |
| 263 case kReadWriteExecute: | |
| 264 prot = MX_VM_FLAG_PERM_READ | | |
| 265 MX_VM_FLAG_PERM_WRITE | | |
| 266 MX_VM_FLAG_PERM_EXECUTE; | |
| 267 break; | |
| 268 } | |
| 269 mx_status_t status = | |
| 270 mx_vmar_protect(vmar, page_address, end_address - page_address, prot); | |
| 271 if (status != NO_ERROR) { | |
| 272 LOG_ERR("mx_vmar_protect(%lx, %lx, %x) success: %s\n", | |
| 273 page_address, end_address - page_address, | |
| 274 prot, mx_status_get_string(status)); | |
| 275 return false; | |
| 276 } | |
| 277 LOG_INFO("mx_vmar_protect(%lx, %lx, %x) success\n", | |
| 278 page_address, end_address - page_address, prot); | |
| 122 return true; | 279 return true; |
| 123 } | 280 } |
| 124 | 281 |
| 125 } // namespace dart | 282 } // namespace dart |
| 126 | 283 |
| 127 #endif // defined(TARGET_OS_FUCHSIA) | 284 #endif // defined(TARGET_OS_FUCHSIA) |
| OLD | NEW |