• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Platform-specific code for MacOS goes here. Code shared between iOS and
6 // macOS is in platform-darwin.cc, while the POSIX-compatible are in in
7 // platform-posix.cc.
8 
9 #include <mach/mach.h>
10 #include <mach/mach_vm.h>
11 #include <mach/vm_map.h>
12 
13 #include "src/base/platform/platform.h"
14 
15 namespace v8 {
16 namespace base {
17 
18 namespace {
19 
GetVMProtFromMemoryPermission(OS::MemoryPermission access)20 vm_prot_t GetVMProtFromMemoryPermission(OS::MemoryPermission access) {
21   switch (access) {
22     case OS::MemoryPermission::kNoAccess:
23     case OS::MemoryPermission::kNoAccessWillJitLater:
24       return VM_PROT_NONE;
25     case OS::MemoryPermission::kRead:
26       return VM_PROT_READ;
27     case OS::MemoryPermission::kReadWrite:
28       return VM_PROT_READ | VM_PROT_WRITE;
29     case OS::MemoryPermission::kReadWriteExecute:
30       return VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
31     case OS::MemoryPermission::kReadExecute:
32       return VM_PROT_READ | VM_PROT_EXECUTE;
33   }
34   UNREACHABLE();
35 }
36 
mach_vm_map_wrapper(mach_vm_address_t * address,mach_vm_size_t size,int flags,mach_port_t port,memory_object_offset_t offset,vm_prot_t prot)37 kern_return_t mach_vm_map_wrapper(mach_vm_address_t* address,
38                                   mach_vm_size_t size, int flags,
39                                   mach_port_t port,
40                                   memory_object_offset_t offset,
41                                   vm_prot_t prot) {
42   vm_prot_t current_prot = prot;
43   vm_prot_t maximum_prot = current_prot;
44   return mach_vm_map(mach_task_self(), address, size, 0, flags, port, offset,
45                      FALSE, current_prot, maximum_prot, VM_INHERIT_NONE);
46 }
47 
48 }  // namespace
49 
50 // static
CreateSharedMemoryHandleForTesting(size_t size)51 PlatformSharedMemoryHandle OS::CreateSharedMemoryHandleForTesting(size_t size) {
52   mach_vm_size_t vm_size = size;
53   mach_port_t port;
54   kern_return_t kr = mach_make_memory_entry_64(
55       mach_task_self(), &vm_size, 0,
56       MAP_MEM_NAMED_CREATE | VM_PROT_READ | VM_PROT_WRITE, &port,
57       MACH_PORT_NULL);
58   if (kr != KERN_SUCCESS) return kInvalidSharedMemoryHandle;
59   return SharedMemoryHandleFromMachMemoryEntry(port);
60 }
61 
62 // static
DestroySharedMemoryHandle(PlatformSharedMemoryHandle handle)63 void OS::DestroySharedMemoryHandle(PlatformSharedMemoryHandle handle) {
64   DCHECK_NE(kInvalidSharedMemoryHandle, handle);
65   mach_port_t port = MachMemoryEntryFromSharedMemoryHandle(handle);
66   CHECK_EQ(KERN_SUCCESS, mach_port_deallocate(mach_task_self(), port));
67 }
68 
69 // static
AllocateShared(void * hint,size_t size,MemoryPermission access,PlatformSharedMemoryHandle handle,uint64_t offset)70 void* OS::AllocateShared(void* hint, size_t size, MemoryPermission access,
71                          PlatformSharedMemoryHandle handle, uint64_t offset) {
72   DCHECK_EQ(0, size % AllocatePageSize());
73 
74   mach_vm_address_t addr = reinterpret_cast<mach_vm_address_t>(hint);
75   vm_prot_t prot = GetVMProtFromMemoryPermission(access);
76   mach_port_t shared_mem_port = MachMemoryEntryFromSharedMemoryHandle(handle);
77   kern_return_t kr = mach_vm_map_wrapper(&addr, size, VM_FLAGS_FIXED,
78                                          shared_mem_port, offset, prot);
79 
80   if (kr != KERN_SUCCESS) {
81     // Retry without hint.
82     kr = mach_vm_map_wrapper(&addr, size, VM_FLAGS_ANYWHERE, shared_mem_port,
83                              offset, prot);
84   }
85 
86   if (kr != KERN_SUCCESS) return nullptr;
87   return reinterpret_cast<void*>(addr);
88 }
89 
90 // static
RemapPages(const void * address,size_t size,void * new_address,MemoryPermission access)91 bool OS::RemapPages(const void* address, size_t size, void* new_address,
92                     MemoryPermission access) {
93   DCHECK(IsAligned(reinterpret_cast<uintptr_t>(address), AllocatePageSize()));
94   DCHECK(
95       IsAligned(reinterpret_cast<uintptr_t>(new_address), AllocatePageSize()));
96   DCHECK(IsAligned(size, AllocatePageSize()));
97 
98   vm_prot_t cur_protection = GetVMProtFromMemoryPermission(access);
99   vm_prot_t max_protection;
100   // Asks the kernel to remap *on top* of an existing mapping, rather than
101   // copying the data.
102   int flags = VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE;
103   mach_vm_address_t target = reinterpret_cast<mach_vm_address_t>(new_address);
104   kern_return_t ret =
105       mach_vm_remap(mach_task_self(), &target, size, 0, flags, mach_task_self(),
106                     reinterpret_cast<mach_vm_address_t>(address), FALSE,
107                     &cur_protection, &max_protection, VM_INHERIT_NONE);
108 
109   if (ret != KERN_SUCCESS) return false;
110 
111   // Did we get the address we wanted?
112   CHECK_EQ(new_address, reinterpret_cast<void*>(target));
113 
114   return true;
115 }
116 
AllocateShared(void * address,size_t size,OS::MemoryPermission access,PlatformSharedMemoryHandle handle,uint64_t offset)117 bool AddressSpaceReservation::AllocateShared(void* address, size_t size,
118                                              OS::MemoryPermission access,
119                                              PlatformSharedMemoryHandle handle,
120                                              uint64_t offset) {
121   DCHECK(Contains(address, size));
122 
123   vm_prot_t prot = GetVMProtFromMemoryPermission(access);
124   mach_vm_address_t addr = reinterpret_cast<mach_vm_address_t>(address);
125   mach_port_t shared_mem_port = MachMemoryEntryFromSharedMemoryHandle(handle);
126   kern_return_t kr =
127       mach_vm_map_wrapper(&addr, size, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
128                           shared_mem_port, offset, prot);
129   return kr == KERN_SUCCESS;
130 }
131 
132 }  // namespace base
133 }  // namespace v8
134