diff --git a/BasiliskII/src/Unix/configure.ac b/BasiliskII/src/Unix/configure.ac index 4409ce89..ee05afc2 100644 --- a/BasiliskII/src/Unix/configure.ac +++ b/BasiliskII/src/Unix/configure.ac @@ -126,6 +126,7 @@ fi dnl Checks for libraries. AC_CHECK_LIB(posix4, sem_init) AC_CHECK_LIB(rt, timer_create) +AC_CHECK_LIB(rt, shm_open) dnl Do we need SDL? WANT_SDL=no @@ -702,6 +703,56 @@ AC_CACHE_CHECK([whether we can map Low Memory area 0x0000-0x2000], ] ) +dnl Check if we have POSIX shared memory support +AC_CACHE_CHECK([whether POSIX shared memory is working], + ac_cv_have_posix_shm, [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_RUN([ + #define HAVE_POSIX_SHM + #include "vm_alloc.cpp" + int main(void) { /* returns 0 if we have working POSIX shm */ + if (vm_init() < 0) exit(2); + char *m1 = (char *)vm_acquire(32768, VM_MAP_DEFAULT | VM_MAP_33BIT); + if (m1 == VM_MAP_FAILED) exit(3); + vm_exit(); exit(0); + } + ], ac_cv_have_posix_shm=yes, ac_cv_have_posix_shm=no, + dnl When cross-compiling, do not assume anything. + ac_cv_have_posix_shm="guessing no" + ) + AC_LANG_RESTORE + ] +) +AC_TRANSLATE_DEFINE(HAVE_POSIX_SHM, "$ac_cv_have_posix_shm", + [Define if your system supports POSIX shared memory.]) + +dnl Check if we have working 33-bit memory addressing +AC_CACHE_CHECK([whether 33-bit memory addressing is working], + ac_cv_have_33bit_addressing, [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_RUN([ + #define USE_33BIT_ADDRESSING 1 + #include "vm_alloc.cpp" + int main(void) { /* returns 0 if we have working 33-bit addressing */ + if (sizeof(void *) < 8) exit(1); + if (vm_init() < 0) exit(2); + char *m1 = (char *)vm_acquire(32768, VM_MAP_DEFAULT | VM_MAP_33BIT); + if (m1 == VM_MAP_FAILED) exit(3); + char *m2 = m1 + (1L << 32); + m1[0] = 0x12; if (m2[0] != 0x12) exit(4); + m2[0] = 0x34; if (m1[0] != 0x34) exit(5); + vm_exit(); exit(0); + } + ], ac_cv_have_33bit_addressing=yes, ac_cv_have_33bit_addressing=no, + dnl When cross-compiling, do not assume anything. + ac_cv_have_33bit_addressing="guessing no" + ) + AC_LANG_RESTORE + ] +) + dnl Check signal handlers need to be reinstalled AC_CACHE_CHECK([whether signal handlers need to be reinstalled], ac_cv_signal_need_reinstall, [ @@ -1028,6 +1079,7 @@ elif [[ "x$HAVE_GCC30" = "xyes" -a "x$HAVE_X86_64" = "xyes" ]]; then DEFINES="$DEFINES -DX86_64_ASSEMBLY -DOPTIMIZED_FLAGS" JITSRCS="cpuemu1_nf.cpp cpuemu2_nf.cpp cpuemu3_nf.cpp cpuemu4_nf.cpp cpuemu5_nf.cpp cpuemu6_nf.cpp cpuemu7_nf.cpp cpuemu8_nf.cpp $JITSRCS" CAN_JIT=yes + WANT_33BIT_ADDRESSING=yes fi elif [[ "x$HAVE_GCC27" = "xyes" -a "x$HAVE_SPARC" = "xyes" -a "x$HAVE_GAS" = "xyes" ]]; then dnl SPARC CPU @@ -1084,6 +1136,13 @@ else JITSRCS="" fi +dnl Use 33-bit memory addressing? +if [[ "$ac_cv_have_33bit_addressing:$WANT_33BIT_ADDRESSING" = "yes:yes" ]]; then + use_33bit_addressing=yes +fi +AC_TRANSLATE_DEFINE(USE_33BIT_ADDRESSING, "$use_33bit_addressing", + [Define to use 33-bit memory addressing on 64-bit JIT capable systems.]) + dnl Utility macro used by next two tests. dnl AC_EXAMINE_OBJECT(C source code, dnl commands examining object file, diff --git a/BasiliskII/src/Unix/main_unix.cpp b/BasiliskII/src/Unix/main_unix.cpp index 36ed8b6d..fe11b3a9 100644 --- a/BasiliskII/src/Unix/main_unix.cpp +++ b/BasiliskII/src/Unix/main_unix.cpp @@ -123,6 +123,7 @@ int CPUType; bool CPUIs68060; int FPUType; bool TwentyFourBitAddressing; +bool ThirtyThreeBitAddressing = false; // Global variables @@ -218,6 +219,21 @@ char *strdup(const char *s) } +/* + * Map memory that can be accessed from the Mac side + */ + +void *vm_acquire_mac(size_t size) +{ + void *m = vm_acquire(size, VM_MAP_DEFAULT | VM_MAP_33BIT); + if (m == NULL) { + ThirtyThreeBitAddressing = false; + m = vm_acquire(size); + } + return m; +} + + /* * SIGSEGV handler */ @@ -482,8 +498,12 @@ int main(int argc, char **argv) else #endif { - RAMBaseHost = (uint8 *)vm_acquire(RAMSize); - ROMBaseHost = (uint8 *)vm_acquire(0x100000); +#ifdef USE_33BIT_ADDRESSING + // Speculatively enables 33-bit addressing + ThirtyThreeBitAddressing = true; +#endif + RAMBaseHost = (uint8 *)vm_acquire_mac(RAMSize); + ROMBaseHost = (uint8 *)vm_acquire_mac(0x100000); if (RAMBaseHost == VM_MAP_FAILED || ROMBaseHost == VM_MAP_FAILED) { ErrorAlert(STR_NO_MEM_ERR); QuitEmulator(); diff --git a/BasiliskII/src/Unix/video_x.cpp b/BasiliskII/src/Unix/video_x.cpp index 53dea727..ae145797 100644 --- a/BasiliskII/src/Unix/video_x.cpp +++ b/BasiliskII/src/Unix/video_x.cpp @@ -192,6 +192,7 @@ static void *redraw_func(void *arg); // From main_unix.cpp extern char *x_display_name; extern Display *x_display; +extern void *vm_acquire_mac(size_t size); // From sys_unix.cpp extern void SysMountFirstFloppy(void); @@ -730,7 +731,7 @@ driver_window::driver_window(X11_monitor_desc &m) // Allocate memory for frame buffer (SIZE is extended to page-boundary) the_host_buffer = the_buffer_copy; the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line); - the_buffer = (uint8 *)vm_acquire(the_buffer_size); + the_buffer = (uint8 *)vm_acquire_mac(the_buffer_size); the_buffer_copy = (uint8 *)malloc(the_buffer_size); D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer)); #else @@ -1126,7 +1127,7 @@ driver_fbdev::driver_fbdev(X11_monitor_desc &m) : driver_dga(m) the_host_buffer = the_buffer; the_buffer_size = page_extend((height + 2) * bytes_per_row); the_buffer_copy = (uint8 *)malloc(the_buffer_size); - the_buffer = (uint8 *)vm_acquire(the_buffer_size); + the_buffer = (uint8 *)vm_acquire_mac(the_buffer_size); } #else use_vosf = false; @@ -1266,7 +1267,7 @@ driver_xf86dga::driver_xf86dga(X11_monitor_desc &m) the_host_buffer = the_buffer; the_buffer_size = page_extend((height + 2) * bytes_per_row); the_buffer_copy = (uint8 *)malloc(the_buffer_size); - the_buffer = (uint8 *)vm_acquire(the_buffer_size); + the_buffer = (uint8 *)vm_acquire_mac(the_buffer_size); } #else use_vosf = false; diff --git a/BasiliskII/src/Unix/vm_alloc.cpp b/BasiliskII/src/Unix/vm_alloc.cpp index 5db2aa30..2543917d 100644 --- a/BasiliskII/src/Unix/vm_alloc.cpp +++ b/BasiliskII/src/Unix/vm_alloc.cpp @@ -23,9 +23,15 @@ #include "config.h" #endif +#ifdef HAVE_FCNTL_H +#include +#endif + // TODO: Win32 VMs ? +#include #include #include +#include #include "vm_alloc.h" #ifdef HAVE_MACH_VM @@ -45,6 +51,12 @@ #ifndef MAP_32BIT #define MAP_32BIT 0 #endif +#ifndef MAP_ANON +#define MAP_ANON 0 +#endif +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS 0 +#endif #define MAP_EXTRA_FLAGS (MAP_32BIT) @@ -66,15 +78,83 @@ static char * next_address = (char *)MAP_BASE; #define map_flags (MAP_ANONYMOUS | MAP_EXTRA_FLAGS) #define zero_fd -1 #else -#ifdef HAVE_FCNTL_H -#include -#endif #define map_flags (MAP_EXTRA_FLAGS) static int zero_fd = -1; #endif #endif #endif +/* Utility functions for POSIX SHM handling. */ + +#ifdef USE_33BIT_ADDRESSING +struct shm_range_t { + const char *file; + void *base; + unsigned int size; + shm_range_t *next; +}; + +static shm_range_t *shm_ranges = NULL; + +static bool add_shm_range(const char *file, void *base, unsigned int size) +{ + shm_range_t *r = (shm_range_t *)malloc(sizeof(shm_range_t)); + if (r) { + r->file = file; + r->base = base; + r->size = size; + r->next = shm_ranges ? shm_ranges : NULL; + shm_ranges = r; + return true; + } + return false; +} + +static shm_range_t *find_shm_range(void *base, unsigned int size) +{ + for (shm_range_t *r = shm_ranges; r != NULL; r = r->next) + if (r->base == base && r->size == size) + return r; + return NULL; +} + +static bool remove_shm_range(shm_range_t *r) +{ + if (r) { + for (shm_range_t *p = shm_ranges; p != NULL; p = p->next) { + if (p->next == r) { + p->next = r->next; + free(r); + return true; + } + } + } + return false; +} + +static bool remove_shm_range(void *base, unsigned int size) +{ + remove_shm_range(find_shm_range(base, size)); +} +#endif + +/* Build a POSIX SHM memory segment file descriptor name. */ + +#ifdef USE_33BIT_ADDRESSING +static const char *build_shm_filename(void) +{ + static int id = 0; + static char filename[PATH_MAX]; + + int ret = snprintf(filename, sizeof(filename), "/BasiliskII-%d-shm-%d", getpid(), id); + if (ret == -1 || ret >= sizeof(filename)) + return NULL; + + id++; + return filename; +} +#endif + /* Translate generic VM map flags to host values. */ #ifdef HAVE_MMAP_VM @@ -136,9 +216,29 @@ void * vm_acquire(size_t size, int options) return VM_MAP_FAILED; #else #ifdef HAVE_MMAP_VM - const int extra_map_flags = translate_map_flags(options); + int fd = zero_fd; + int the_map_flags = translate_map_flags(options) | map_flags; - if ((addr = mmap((caddr_t)next_address, size, VM_PAGE_DEFAULT, extra_map_flags | map_flags, zero_fd, 0)) == (void *)MAP_FAILED) +#ifdef USE_33BIT_ADDRESSING + const char *shm_file = NULL; + if (sizeof(void *) == 8 && (options & VM_MAP_33BIT)) { + the_map_flags &= ~(MAP_PRIVATE | MAP_ANON | MAP_ANONYMOUS); + the_map_flags |= MAP_SHARED; + + if ((shm_file = build_shm_filename()) == NULL) + return VM_MAP_FAILED; + + if ((fd = shm_open(shm_file, O_RDWR | O_CREAT | O_EXCL, 0644)) < 0) + return VM_MAP_FAILED; + + if (ftruncate(fd, size) < 0) + return VM_MAP_FAILED; + + the_map_flags |= MAP_SHARED; + } +#endif + + if ((addr = mmap((caddr_t)next_address, size, VM_PAGE_DEFAULT, the_map_flags, fd, 0)) == (void *)MAP_FAILED) return VM_MAP_FAILED; // Sanity checks for 64-bit platforms @@ -150,6 +250,18 @@ void * vm_acquire(size_t size, int options) // Since I don't know the standard behavior of mmap(), zero-fill here if (memset(addr, 0, size) != addr) return VM_MAP_FAILED; + + // Remap to 33-bit space +#ifdef USE_33BIT_ADDRESSING + if (sizeof(void *) == 8 && (options & VM_MAP_33BIT)) { + if (!add_shm_range(strdup(shm_file), addr, size)) + return VM_MAP_FAILED; + + if (mmap((char *)addr + (1L << 32), size, VM_PAGE_DEFAULT, the_map_flags | MAP_FIXED, fd, 0) == (void *)MAP_FAILED) + return VM_MAP_FAILED; + close(fd); + } +#endif #else if ((addr = calloc(size, 1)) == 0) return VM_MAP_FAILED; @@ -220,6 +332,21 @@ int vm_release(void * addr, size_t size) #ifdef HAVE_MMAP_VM if (munmap((caddr_t)addr, size) != 0) return -1; + +#ifdef USE_33BIT_ADDRESSING + shm_range_t *r = find_shm_range(addr, size); + if (r) { + if (munmap((char *)r->base + (1L << 32), size) != 0) + return -1; + + if (shm_unlink(r->file) < 0) + return -1; + free((char *)r->file); + + if (!remove_shm_range(r)) + return -1; + } +#endif #else free(addr); #endif diff --git a/BasiliskII/src/Unix/vm_alloc.h b/BasiliskII/src/Unix/vm_alloc.h index ca34a8d1..41a7a5ed 100644 --- a/BasiliskII/src/Unix/vm_alloc.h +++ b/BasiliskII/src/Unix/vm_alloc.h @@ -52,6 +52,7 @@ extern "C" { #define VM_MAP_PRIVATE 0x02 #define VM_MAP_FIXED 0x04 #define VM_MAP_32BIT 0x08 +#define VM_MAP_33BIT 0x10 /* Default mapping options. */ #define VM_MAP_DEFAULT (VM_MAP_PRIVATE)