1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "SharedMemoryPlatform.h"
11 #include <mach/vm_map.h>
12 #include <mach/mach_port.h>
14 # include <mach/vm_map.h>
15 # define mach_vm_address_t vm_address_t
16 # define mach_vm_map vm_map
17 # define mach_vm_read vm_read
18 # define mach_vm_region_recurse vm_region_recurse_64
19 # define mach_vm_size_t vm_size_t
21 # include <mach/mach_vm.h>
24 #include <sys/mman.h> // mprotect
27 #if defined(XP_MACOSX) && defined(__x86_64__)
31 #include "mozilla/IntegerPrintfMacros.h"
32 #include "mozilla/Printf.h"
35 # define LOG_ERROR(str, args...) \
37 mozilla::SmprintfPointer msg = mozilla::Smprintf(str, ##args); \
38 NS_WARNING(msg.get()); \
41 # define LOG_ERROR(str, args...) \
46 namespace mozilla::ipc::shared_memory
{
48 static inline void* toPointer(mach_vm_address_t aAddress
) {
49 return reinterpret_cast<void*>(static_cast<uintptr_t>(aAddress
));
52 static inline mach_vm_address_t
toVMAddress(void* aPointer
) {
53 return static_cast<mach_vm_address_t
>(reinterpret_cast<uintptr_t>(aPointer
));
56 static Maybe
<PlatformHandle
> CreateImpl(size_t aSize
, bool aFreezable
) {
57 memory_object_size_t memoryObjectSize
= round_page(aSize
);
58 PlatformHandle handle
;
61 mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize
, 0,
62 MAP_MEM_NAMED_CREATE
| VM_PROT_DEFAULT
,
63 getter_Transfers(handle
), MACH_PORT_NULL
);
64 if (kr
!= KERN_SUCCESS
|| memoryObjectSize
< round_page(aSize
)) {
65 LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", aSize
,
66 mach_error_string(kr
), kr
);
69 return Some(std::move(handle
));
72 bool Platform::Create(Handle
& aHandle
, size_t aSize
) {
73 if (auto ph
= CreateImpl(aSize
, false)) {
74 aHandle
.mHandle
= std::move(*ph
);
75 aHandle
.mSize
= aSize
;
81 bool Platform::CreateFreezable(FreezableHandle
& aHandle
, size_t aSize
) {
82 if (auto ph
= CreateImpl(aSize
, true)) {
83 aHandle
.mHandle
= std::move(*ph
);
84 aHandle
.mSize
= aSize
;
90 PlatformHandle
Platform::CloneHandle(const PlatformHandle
& aHandle
) {
91 return mozilla::RetainMachSendRight(aHandle
.get());
94 static Maybe
<void*> MapMemory(size_t aSize
, void* aFixedAddress
,
95 const mozilla::UniqueMachSendRight
& aPort
,
98 mach_vm_address_t address
= toVMAddress(aFixedAddress
);
100 vm_prot_t vmProtection
= VM_PROT_READ
;
102 vmProtection
|= VM_PROT_WRITE
;
105 kr
= mach_vm_map(mach_task_self(), &address
, round_page(aSize
), 0,
106 aFixedAddress
? VM_FLAGS_FIXED
: VM_FLAGS_ANYWHERE
,
107 aPort
.get(), 0, false, vmProtection
, vmProtection
,
109 if (kr
!= KERN_SUCCESS
) {
110 if (!aFixedAddress
) {
112 "Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
113 aSize
, mach_task_self(), mach_port_t(aPort
.get()),
114 mach_error_string(kr
), kr
);
119 if (aFixedAddress
&& aFixedAddress
!= toPointer(address
)) {
120 kr
= vm_deallocate(mach_task_self(), address
, aSize
);
121 if (kr
!= KERN_SUCCESS
) {
123 "Failed to unmap shared memory at unsuitable address "
124 "(%zu bytes) from %x, port %x. %s (%x)\n",
125 aSize
, mach_task_self(), mach_port_t(aPort
.get()),
126 mach_error_string(kr
), kr
);
131 return Some(toPointer(address
));
134 bool Platform::Freeze(FreezableHandle
& aHandle
) {
135 memory_object_size_t memoryObjectSize
= round_page(aHandle
.Size());
137 mozilla::UniqueMachSendRight port
;
139 // Temporarily map memory (as readonly) to get an address.
140 auto memory
= MapMemory(memoryObjectSize
, nullptr, aHandle
.mHandle
, true);
145 kern_return_t kr
= mach_make_memory_entry_64(
146 mach_task_self(), &memoryObjectSize
,
147 static_cast<memory_object_offset_t
>(reinterpret_cast<uintptr_t>(*memory
)),
148 VM_PROT_READ
, getter_Transfers(port
), MACH_PORT_NULL
);
150 // Immediately try to deallocate, regardless of success.
153 vm_deallocate(mach_task_self(), toVMAddress(*memory
), memoryObjectSize
);
154 if (kr
!= KERN_SUCCESS
) {
155 LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n",
156 mach_error_string(kr
), kr
);
160 if (kr
!= KERN_SUCCESS
|| memoryObjectSize
< round_page(aHandle
.Size())) {
161 LOG_ERROR("Failed to make memory entry (%llu bytes). %s (%x)\n",
162 aHandle
.Size(), mach_error_string(kr
), kr
);
166 aHandle
.mHandle
= std::move(port
);
171 Maybe
<void*> Platform::Map(const HandleBase
& aHandle
, void* aFixedAddress
,
173 return MapMemory(aHandle
.Size(), aFixedAddress
, aHandle
.mHandle
, aReadOnly
);
176 void Platform::Unmap(void* aMemory
, size_t aSize
) {
177 vm_address_t vm_address
= toVMAddress(aMemory
);
179 vm_deallocate(mach_task_self(), vm_address
, round_page(aSize
));
180 if (kr
!= KERN_SUCCESS
) {
181 LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n",
182 mach_error_string(kr
), kr
);
186 bool Platform::Protect(char* aAddr
, size_t aSize
, Access aAccess
) {
187 int flags
= PROT_NONE
;
188 if (aAccess
& AccessRead
) flags
|= PROT_READ
;
189 if (aAccess
& AccessWrite
) flags
|= PROT_WRITE
;
191 return 0 == mprotect(aAddr
, aSize
, flags
);
194 void* Platform::FindFreeAddressSpace(size_t aSize
) {
195 mach_vm_address_t address
= 0;
196 aSize
= round_page(aSize
);
197 if (mach_vm_map(mach_task_self(), &address
, aSize
, 0, VM_FLAGS_ANYWHERE
,
198 MEMORY_OBJECT_NULL
, 0, false, VM_PROT_NONE
, VM_PROT_NONE
,
199 VM_INHERIT_NONE
) != KERN_SUCCESS
||
200 vm_deallocate(mach_task_self(), address
, aSize
) != KERN_SUCCESS
) {
203 return toPointer(address
);
206 size_t Platform::PageSize() {
207 #if defined(XP_MACOSX) && defined(__x86_64__)
208 static std::atomic
<size_t> sPageSizeOverride
= 0;
210 if (sPageSizeOverride
== 0) {
211 if (PR_GetEnv("MOZ_SHMEM_PAGESIZE_16K")) {
212 sPageSizeOverride
= 16 * 1024;
214 sPageSizeOverride
= sysconf(_SC_PAGESIZE
);
217 return sPageSizeOverride
;
219 return sysconf(_SC_PAGESIZE
);
223 bool Platform::IsSafeToMap(const PlatformHandle
&) { return true; }
225 } // namespace mozilla::ipc::shared_memory