diff --git a/src/base/lib/mapping/Makefile b/src/base/lib/mapping/Makefile index 12b160ad8..6bb2f7dd0 100644 --- a/src/base/lib/mapping/Makefile +++ b/src/base/lib/mapping/Makefile @@ -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 = diff --git a/src/base/lib/mapping/mapashm.c b/src/base/lib/mapping/mapashm.c new file mode 100644 index 000000000..aeb361bc9 --- /dev/null +++ b/src/base/lib/mapping/mapashm.c @@ -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 +#include + +#ifdef __APPLE__ +#include +#include +#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 diff --git a/src/base/lib/mapping/mapping.c b/src/base/lib/mapping/mapping.c index 2c1a4ed7a..3856ff9ed 100644 --- a/src/base/lib/mapping/mapping.c +++ b/src/base/lib/mapping/mapping.c @@ -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 */ }; diff --git a/src/include/mapping.h b/src/include/mapping.h index 5fa069d71..89898bb3a 100644 --- a/src/include/mapping.h +++ b/src/include/mapping.h @@ -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;