Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: runtime/vm/virtual_memory_fuchsia.cc

Issue 2652873002: Fuchsia: Implement memory region protections (Closed)
Patch Set: Format Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 12 matching lines...) Expand all
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 | MX_VM_FLAG_PERM_READ |
103 MX_VM_FLAG_PERM_WRITE | MX_VM_FLAG_PERM_EXECUTE; 217 MX_VM_FLAG_PERM_WRITE |
218 (executable ? MX_VM_FLAG_PERM_EXECUTE : 0);
104 uintptr_t mapped_addr; 219 uintptr_t mapped_addr;
105 status = mx_vmar_map(vmar, offset, vmo, 0, size, flags, &mapped_addr); 220 status = mx_vmar_map(vmar, offset, vmo, 0, size, flags, &mapped_addr);
106 if (status != NO_ERROR) { 221 if (status != NO_ERROR) {
107 mx_handle_close(vmo); 222 mx_handle_close(vmo);
108 LOG_ERR("mx_vmar_map(%ld, %ld, %u) failed: %s\n", offset, size, flags, 223 LOG_ERR("mx_vmar_map(%ld, %ld, %u) failed: %s\n", offset, size, flags,
109 mx_status_get_string(status)); 224 mx_status_get_string(status));
110 return false; 225 return false;
111 } 226 }
112 if (addr != mapped_addr) { 227 if (addr != mapped_addr) {
228 mx_handle_close(vmo);
113 LOG_ERR("mx_vmar_map: addr != mapped_addr: %lx != %lx\n", addr, 229 LOG_ERR("mx_vmar_map: addr != mapped_addr: %lx != %lx\n", addr,
114 mapped_addr); 230 mapped_addr);
115 return false; 231 return false;
116 } 232 }
233 mx_handle_close(vmo);
234 LOG_INFO("Commit(%lx, %ld, %s): success\n", addr, size,
235 executable ? "executable" : "");
117 return true; 236 return true;
118 } 237 }
119 238
120 239
121 bool VirtualMemory::Protect(void* address, intptr_t size, Protection mode) { 240 bool VirtualMemory::Protect(void* address, intptr_t size, Protection mode) {
241 ASSERT(Thread::Current()->IsMutatorThread() ||
242 Isolate::Current()->mutator_thread()->IsAtSafepoint());
243 const uword start_address = reinterpret_cast<uword>(address);
244 const uword end_address = start_address + size;
245 const uword page_address = Utils::RoundDown(start_address, PageSize());
246 mx_handle_t vmar = VmarList::LookupVmar(page_address);
247 ASSERT(vmar != MX_HANDLE_INVALID);
248 uint32_t prot = 0;
249 switch (mode) {
250 case kNoAccess:
251 // MG-426: mx_vmar_protect() requires at least on permission.
252 prot = MX_VM_FLAG_PERM_READ;
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 | MX_VM_FLAG_PERM_WRITE |
265 MX_VM_FLAG_PERM_EXECUTE;
266 break;
267 }
268 mx_status_t status =
269 mx_vmar_protect(vmar, page_address, end_address - page_address, prot);
270 if (status != NO_ERROR) {
271 LOG_ERR("mx_vmar_protect(%lx, %lx, %x) success: %s\n", page_address,
272 end_address - page_address, prot, mx_status_get_string(status));
273 return false;
274 }
275 LOG_INFO("mx_vmar_protect(%lx, %lx, %x) success\n", page_address,
276 end_address - page_address, prot);
122 return true; 277 return true;
123 } 278 }
124 279
125 } // namespace dart 280 } // namespace dart
126 281
127 #endif // defined(TARGET_OS_FUCHSIA) 282 #endif // defined(TARGET_OS_FUCHSIA)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698