Skip to content

Commit

Permalink
mapping: introduce mapmach.c
Browse files Browse the repository at this point in the history
On macOS there's a way to alias plain private anonymous mappings,
using mach_vm_remap, so let's use those. Those can then use RWX
protections without issue, unlike file-based shared memory mappings.
  • Loading branch information
bartoldeman committed Jul 12, 2023
1 parent 43af18c commit 8b39974
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/base/lib/mapping/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ include $(top_builddir)/Makefile.conf


#The C files, include files and dependancies here.
CFILES = mapping.c mapfile.c
CFILES = mapping.c mapfile.c mapashm.c
DEPENDS = $(CFILES:.c=.d)
HFILES =

Expand Down
141 changes: 141 additions & 0 deletions src/base/lib/mapping/mapashm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

/*
* Purpose: memory mapping library, anon-SHM backend.
*
* Authors: Stas Sergeev, Bart Oldeman.
*/

#if defined(__linux__) || defined(__APPLE__)

#include <string.h>
#include <sys/mman.h>

#ifdef __APPLE__
#include <mach/mach_init.h>
#include <mach/mach_vm.h>
#endif

#include "dosemu_debug.h"
#include "mapping.h"

/* ------------------------------------------------------------ */

static void *alias_mapping_ashm(int cap, void *target, size_t mapsize, int protect, void *source)
{
int flags;
#ifdef __APPLE__
mach_vm_address_t targetaddr;
vm_prot_t cur, max;

if (target != (void *)-1) {
flags = VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE;
targetaddr = (vm_address_t)target;
} else {
flags = VM_FLAGS_ANYWHERE;
targetaddr = (vm_address_t)NULL;
}
if (mach_vm_remap(mach_task_self(), &targetaddr, mapsize, 0, flags,
mach_task_self(), (mach_vm_address_t)source, FALSE, &cur, &max, VM_INHERIT_NONE)
!= KERN_SUCCESS)
return MAP_FAILED;

target = (void *)targetaddr;
#else
flags = MREMAP_MAYMOVE;
if (target != (void *)-1)
flags |= MREMAP_FIXED;
else
target = NULL;
target = mremap(source, 0, mapsize, flags, target);
if (target == MAP_FAILED) return MAP_FAILED;
#endif
mprotect(target, mapsize, protect);
return target;
}

static int open_mapping_ashm(int cap)
{
if (cap) Q_printf("MAPPING: open, cap=%s\n",
decode_mapping_cap(cap));
return 1;
}

static void close_mapping_ashm(int cap)
{
Q_printf("MAPPING: close, cap=%s\n", decode_mapping_cap(cap));
}

static void *alloc_mapping_ashm(int cap, size_t mapsize, void *target)
{
int fixed = 0;

Q__printf("MAPPING: alloc, cap=%s, mapsize=%zx\n", cap, mapsize);
if (target != (void *)-1)
fixed = MAP_FIXED;
else
target = NULL;
return mmap(target, mapsize, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS | fixed, -1, 0);
}

static void free_mapping_ashm(int cap, void *addr, size_t mapsize)
/* NOTE: addr needs to be the same as what was supplied by alloc_mapping_ashm */
{
Q__printf("MAPPING: free, cap=%s, addr=%p, mapsize=%zx\n",
cap, addr, mapsize);
munmap(addr, mapsize);
}

static void *resize_mapping_ashm(int cap, void *addr, size_t oldsize, size_t newsize)
{
void *ret = addr;
Q__printf("MAPPING: resize, cap=%s, addr=%p, oldsize=%zx, newsize=%zx\n",
cap, addr, oldsize, newsize);

if (newsize < oldsize) {
#ifdef HAVE_MREMAP
ret = mremap(addr, oldsize, newsize, 0);
assert(ret == addr);
#else
/* ensure page-aligned */
assert(!(oldsize & (PAGE_SIZE - 1)));
assert(!(newsize & (PAGE_SIZE - 1)));
if (munmap((unsigned char *)addr + newsize, oldsize - newsize) == -1)
ret = MAP_FAILED;
#endif
} else if (newsize > oldsize) {
ret = alloc_mapping_ashm(cap, newsize, NULL);
if (ret != MAP_FAILED) {
memcpy(ret, addr, oldsize);
free_mapping_ashm(cap, addr, oldsize);
}
}
return ret;
}

struct mappingdrivers mappingdriver_ashm = {
"mapashm",
"anonymous non-expandable shared memory mapping",
open_mapping_ashm,
close_mapping_ashm,
alloc_mapping_ashm,
free_mapping_ashm,
resize_mapping_ashm,
alias_mapping_ashm
};
#endif
6 changes: 6 additions & 0 deletions src/base/lib/mapping/mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,14 @@ static struct mappingdrivers *mappingdrv[] = {
#ifdef HAVE_MEMFD_CREATE
&mappingdriver_mshm, /* first try memfd mmap */
#endif
#ifdef __APPLE__
&mappingdriver_ashm, /* on Mac first try private anon-mmap + mach_vm_remap */
#endif
#ifdef HAVE_SHM_OPEN
&mappingdriver_shm, /* then shm_open which is usually broken */
#endif
#ifdef __linux__
&mappingdriver_ashm, /* then anon-shared-mmap */
#endif
&mappingdriver_file, /* and then a temp file */
};
Expand Down
1 change: 1 addition & 0 deletions src/include/mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ char *decode_mapping_cap(int cap);
extern struct mappingdrivers mappingdriver_shm;
extern struct mappingdrivers mappingdriver_mshm;
extern struct mappingdrivers mappingdriver_file;
extern struct mappingdrivers mappingdriver_ashm;

extern int have_mremap_fixed;

Expand Down

0 comments on commit 8b39974

Please sign in to comment.