From dae4fb627cc748fdddaf0777c1b6725f0a018f57 Mon Sep 17 00:00:00 2001 From: gbeauche <> Date: Tue, 26 Jun 2001 22:35:42 +0000 Subject: [PATCH] - added SIGSEGV support for Linux/Alpha (to be checked), Darwin/PPC - added uniform virtual memory allocation (supports mmap(), vm_allocate(), or fallbacks to malloc()/free()) - cleaned up memory allocation in main_unix.cpp --- BasiliskII/TODO | 3 +- BasiliskII/src/Unix/Makefile.in | 2 +- BasiliskII/src/Unix/acconfig.h | 12 ++ BasiliskII/src/Unix/configure.in | 246 ++++++++++++++++----- BasiliskII/src/Unix/main_unix.cpp | 113 ++++------ BasiliskII/src/Unix/sigsegv.cpp | 143 ++++++++++++- BasiliskII/src/Unix/video_vosf.h | 19 +- BasiliskII/src/Unix/video_x.cpp | 62 +++--- BasiliskII/src/Unix/vm_alloc.cpp | 258 +++++++++++++++++++++++ BasiliskII/src/Unix/vm_alloc.h | 96 +++++++++ BasiliskII/src/uae_cpu/basilisk_glue.cpp | 5 +- BasiliskII/src/uae_cpu/memory.h | 3 +- 12 files changed, 778 insertions(+), 184 deletions(-) create mode 100644 BasiliskII/src/Unix/vm_alloc.cpp create mode 100644 BasiliskII/src/Unix/vm_alloc.h diff --git a/BasiliskII/TODO b/BasiliskII/TODO index d09314d9..a5914a23 100644 --- a/BasiliskII/TODO +++ b/BasiliskII/TODO @@ -2,6 +2,8 @@ Bugs: - System 7.1 with Quadra900 ModelID (1MB ROM): 0x108 gets strange value - Real memory addressing: something is still wrong in the Unix part, though it works under Linux/i386 +- VOSF does not work with Darwin/X11. Probably due to a combination of + select()/signals/sigsegv handling/vm_protect() General: - Sony: rdVerify, Tag Buffer @@ -35,7 +37,6 @@ BeOS: - Last sound buffer is not played Unix: -- video_vosf.h: check correctness of {15,16,24 bpp} blitters on big endian systems - clip_unix.cpp: clip Unix->Basilisk - clip_unix.cpp: use X selections instead of cut buffer - sys_unix.cpp: SysFormat(), SysIsFixedDisk(), SysIsDiskInserted(), prevent/allow diff --git a/BasiliskII/src/Unix/Makefile.in b/BasiliskII/src/Unix/Makefile.in index 1b8a4adc..2bf7385f 100644 --- a/BasiliskII/src/Unix/Makefile.in +++ b/BasiliskII/src/Unix/Makefile.in @@ -33,7 +33,7 @@ SRCS = ../main.cpp main_unix.cpp ../prefs.cpp ../prefs_items.cpp prefs_unix.cpp ../emul_op.cpp ../macos_util.cpp ../xpram.cpp xpram_unix.cpp ../timer.cpp \ timer_unix.cpp clip_unix.cpp ../adb.cpp ../serial.cpp ../ether.cpp \ ../sony.cpp ../disk.cpp ../cdrom.cpp ../scsi.cpp ../video.cpp video_blit.cpp \ - video_x.cpp sigsegv.cpp ../audio.cpp ../extfs.cpp extfs_unix.cpp \ + video_x.cpp vm_alloc.cpp sigsegv.cpp ../audio.cpp ../extfs.cpp extfs_unix.cpp \ ../user_strings.cpp user_strings_unix.cpp \ $(SYSSRCS) $(CPUSRCS) APP = BasiliskII diff --git a/BasiliskII/src/Unix/acconfig.h b/BasiliskII/src/Unix/acconfig.h index 8f1a34e6..9b002dea 100644 --- a/BasiliskII/src/Unix/acconfig.h +++ b/BasiliskII/src/Unix/acconfig.h @@ -56,6 +56,18 @@ /* Define if we know a hack to replace siginfo_t::si_addr member */ #undef HAVE_SIGCONTEXT_SUBTERFUGE +/* Define if your system has a working vm_allocate()-based memory allocator */ +#undef HAVE_MACH_VM + +/* Define if your system has a working mmap()-based memory allocator */ +#undef HAVE_MMAP_VM + +/* Define if defines MAP_ANON and mmap()'ing with MAP_ANON works */ +#undef HAVE_MMAP_ANON + +/* Define if defines MAP_ANONYMOUS and mmap()'ing with MAP_ANONYMOUS works */ +#undef HAVE_MMAP_ANONYMOUS + /* Leave that blank line there!! Autoheader needs it. If you're adding to this file, keep in mind: diff --git a/BasiliskII/src/Unix/configure.in b/BasiliskII/src/Unix/configure.in index d259e4f3..21367af8 100644 --- a/BasiliskII/src/Unix/configure.in +++ b/BasiliskII/src/Unix/configure.in @@ -52,7 +52,8 @@ case "$target_os" in netbsd*) OS_TYPE=netbsd;; freebsd*) OS_TYPE=freebsd;; solaris*) OS_TYPE=solaris;; - *) OS_TYPE=`echo $target_os | sed -e 's/-/_/' | sed -e 's/\./_/'`;; + darwin*) OS_TYPE=darwin;; + *) OS_TYPE=`echo $target_os | sed -e 's/-/_/g' | sed -e 's/\./_/g'`;; esac DEFINES="$DEFINES -DOS_$OS_TYPE" @@ -66,7 +67,7 @@ case "$target_cpu" in m68k* ) CPU_TYPE=m68k HAVE_M68K=yes;; sparc* ) CPU_TYPE=sparc HAVE_SPARC=yes;; powerpc* ) CPU_TYPE=powerpc HAVE_POWERPC=yes;; - *) CPU_TYPE=`echo $target_cpu | sed -e 's/-/_/'`;; + *) CPU_TYPE=`echo $target_cpu | sed -e 's/-/_/g'`;; esac DEFINES="$DEFINES -DCPU_$CPU_TYPE" @@ -191,7 +192,7 @@ fi dnl Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS(unistd.h fcntl.h sys/time.h) +AC_CHECK_HEADERS(unistd.h fcntl.h sys/time.h sys/mman.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_BIGENDIAN @@ -213,6 +214,11 @@ dnl Checks for library functions. AC_CHECK_FUNCS(strdup cfmakeraw) AC_CHECK_FUNCS(clock_gettime timer_create) AC_CHECK_FUNCS(sigaction signal) +AC_CHECK_FUNCS(mmap mprotect munmap) +AC_CHECK_FUNCS(vm_allocate vm_deallocate vm_protect) + +dnl Darwin seems to define mach_task_self() instead of task_self(). +AC_CHECK_FUNCS(mach_task_self task_self) dnl Select system-dependant source files. SERIALSRC=serial_unix.cpp @@ -297,33 +303,169 @@ dnl to be put into the config.h file dnl $1 -- the macro to define dnl $2 -- the value to translate AC_DEFUN(AC_TRANSLATE_DEFINE, [ - if [[ "x$2" = "xyes" ]]; then + if [[ "x$2" = "xyes" -o "x$2" = "xguessing yes" ]]; then AC_DEFINE($1) fi ]) +dnl Various checks if the system supports vm_allocate() and the like functions. +have_mach_vm=no +if [[ "x$ac_cv_func_vm_allocate" = "xyes" -a "x$ac_cv_func_vm_deallocate" = "xyes" -a \ + "x$ac_cv_func_vm_protect" = "xyes" ]]; then + have_mach_vm=yes +fi +AC_TRANSLATE_DEFINE(HAVE_MACH_VM, "$have_mach_vm") + +dnl Check that vm_allocate(), vm_protect() work +if [[ "x$have_mach_vm" = "xyes" ]]; then + +AC_CACHE_CHECK("whether vm_protect works", + ac_cv_vm_protect_works, [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_cv_vm_protect_works=yes + dnl First the tests that should segfault + for test_def in NONE_READ NONE_WRITE READ_WRITE; do + AC_TRY_RUN([ + #define CONFIGURE_TEST_VM_MAP + #define TEST_VM_PROT_$test_def + #include "vm_alloc.cpp" + ], ac_cv_vm_protect_works=no, rm -f core, + dnl When cross-compiling, do not assume anything + ac_cv_vm_protect_works="guessing no" + ) + done + AC_TRY_RUN([ + #define CONFIGURE_TEST_VM_MAP + #define TEST_VM_PROT_RDWR_WRITE + #include "vm_alloc.cpp" + ], , ac_cv_vm_protect_works=no, + dnl When cross-compiling, do not assume anything + ac_cv_vm_protect_works="guessing no" + ) + AC_LANG_RESTORE + ] +) + +dnl Remove support for vm_allocate() if vm_protect() does not work +if [[ "x$have_mach_vm" = "xyes" ]]; then + case $ac_cv_vm_protect_works in + *yes) have_mach_vm=yes;; + *no) have_mach_vm=no;; + esac +fi +AC_TRANSLATE_DEFINE(HAVE_MACH_VM, "$have_mach_vm") + +fi dnl HAVE_MACH_VM + +dnl Various checks if the system supports mmap() and the like functions. +dnl ... and Mach memory allocators are not supported +have_mmap_vm=no +if [[ "x$ac_cv_func_mmap" = "xyes" -a "x$ac_cv_func_munmap" = "xyes" -a \ + "x$ac_cv_func_mprotect" = "xyes" ]]; then + if [[ "x$have_mach_vm" = "xno" ]]; then + have_mmap_vm=yes + fi +fi +AC_TRANSLATE_DEFINE(HAVE_MMAP_VM, "$have_mmap_vm") + +dnl Check that mmap() and associated functions work. +if [[ "x$have_mmap_vm" = "xyes" ]]; then + +dnl Check if we have a working anonymous mmap() +AC_CACHE_CHECK("whether mmap supports MAP_ANON", + ac_cv_mmap_anon, [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_RUN([ + #define HAVE_MMAP_ANON + #define CONFIGURE_TEST_VM_MAP + #define TEST_VM_MMAP_ANON + #include "vm_alloc.cpp" + ], ac_cv_mmap_anon=yes, ac_cv_mmap_anon=no, + dnl When cross-compiling, do not assume anything. + ac_cv_mmap_anon="guessing no" + ) + AC_LANG_RESTORE + ] +) +AC_TRANSLATE_DEFINE(HAVE_MMAP_ANON, "$ac_cv_mmap_anon") + +AC_CACHE_CHECK("whether mmap supports MAP_ANONYMOUS", + ac_cv_mmap_anonymous, [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_RUN([ + #define HAVE_MMAP_ANONYMOUS + #define CONFIGURE_TEST_VM_MAP + #define TEST_VM_MMAP_ANON + #include "vm_alloc.cpp" + ], ac_cv_mmap_anonymous=yes, ac_cv_mmap_anonymous=no, + dnl When cross-compiling, do not assume anything. + ac_cv_mmap_anonymous="guessing no" + ) + AC_LANG_RESTORE + ] +) +AC_TRANSLATE_DEFINE(HAVE_MMAP_ANONYMOUS, "$ac_cv_mmap_anonymous") + +AC_CACHE_CHECK("whether mprotect works", + ac_cv_mprotect_works, [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_cv_mprotect_works=yes + dnl First the tests that should segfault + for test_def in NONE_READ NONE_WRITE READ_WRITE; do + AC_TRY_RUN([ + #define CONFIGURE_TEST_VM_MAP + #define TEST_VM_PROT_$test_def + #include "vm_alloc.cpp" + ], ac_cv_mprotect_works=no, rm -f core, + dnl When cross-compiling, do not assume anything + ac_cv_mprotect_works="guessing no" + ) + done + AC_TRY_RUN([ + #define CONFIGURE_TEST_VM_MAP + #define TEST_VM_PROT_RDWR_WRITE + #include "vm_alloc.cpp" + ], , ac_cv_mprotect_works=no, + dnl When cross-compiling, do not assume anything + ac_cv_mprotect_works="guessing no" + ) + AC_LANG_RESTORE + ] +) + +dnl Remove support for mmap() if mprotect() does not work +if [[ "x$have_mmap_vm" = "xyes" ]]; then + case $ac_cv_mprotect_works in + *yes) have_mmap_vm=yes;; + *no) have_mmap_vm=no;; + esac +fi +AC_TRANSLATE_DEFINE(HAVE_MMAP_VM, $have_mmap_vm) + +fi dnl HAVE_MMAP_VM + dnl Check if we can mmap 0x2000 bytes from 0x0000 AC_CACHE_CHECK("whether we can map Low Memory area 0x0000-0x2000", ac_cv_can_map_lm, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ - #include - #include - #include - - int main() - { int zero_fd; char * lm; - if ((zero_fd = open("/dev/zero", O_RDWR)) < 0) exit(1); - if ((lm = (char *)mmap((caddr_t)0x0000, 0x2000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, zero_fd, 0)) == MAP_FAILED) exit(1); - lm[0] = 0x12; - munmap(lm, 0x2000); - close(zero_fd); - exit(0); + #include "vm_alloc.cpp" + int main(void) { /* returns 0 if we could map the lowmem globals */ + volatile char * lm; + if (vm_init() < 0) exit(1); + if ((lm = (volatile char *)vm_acquire_fixed(0, 0x2000)) == VM_MAP_FAILED) exit(1); + lm[0] = 'z'; + if (vm_release((char *)lm, 0x2000) < 0) exit(1); + vm_exit(); exit(0); } - ], - [ac_cv_can_map_lm=yes], - [ac_cv_can_map_lm=no] + ], ac_cv_can_map_lm=yes, ac_cv_can_map_lm=no, + dnl When cross-compiling, do not assume anything. + ac_cv_can_map_lm="guessing no" ) AC_LANG_RESTORE ] @@ -331,27 +473,27 @@ AC_CACHE_CHECK("whether we can map Low Memory area 0x0000-0x2000", dnl Check signal handlers need to be reinstalled AC_CACHE_CHECK("whether signal handlers need to be reinstalled", - ac_cv_signal_need_reinstall, [ - AC_LANG_SAVE - AC_LANG_CPLUSPLUS - AC_TRY_RUN([ - #include - #ifdef HAVE_UNISTD_H - #include - #endif - #include - static int handled_signal = 0; - RETSIGTYPE sigusr1_handler(int) { handled_signal++; } - int main(void) { /* returns 0 if signals need not to be reinstalled */ - signal(SIGUSR1, sigusr1_handler); raise(SIGUSR1); raise(SIGUSR1); - exit(handled_signal == 2); - } - ], - [ac_cv_signal_need_reinstall=yes], - [ac_cv_signal_need_reinstall=no] - ) - AC_LANG_RESTORE - ] + ac_cv_signal_need_reinstall, [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_RUN([ + #include + #ifdef HAVE_UNISTD_H + #include + #endif + #include + static int handled_signal = 0; + RETSIGTYPE sigusr1_handler(int) { handled_signal++; } + int main(void) { /* returns 0 if signals need not to be reinstalled */ + signal(SIGUSR1, sigusr1_handler); raise(SIGUSR1); raise(SIGUSR1); + exit(handled_signal == 2); + } + ], ac_cv_signal_need_reinstall=yes, ac_cv_signal_need_reinstall=no, + dnl When cross-compiling, do not assume anything. + ac_cv_signal_need_reinstall="guessing yes" + ) + AC_LANG_RESTORE + ] ) AC_TRANSLATE_DEFINE(SIGNAL_NEED_REINSTALL, "$ac_cv_signal_need_reinstall") @@ -379,9 +521,9 @@ AC_CACHE_CHECK("whether sigaction handlers need to be reinstalled", mysignal(SIGUSR1, sigusr1_handler); raise(SIGUSR1); raise(SIGUSR1); exit(handled_signal == 2); } - ], - [ac_cv_sigaction_need_reinstall=yes], - [ac_cv_sigaction_need_reinstall=no] + ], ac_cv_sigaction_need_reinstall=yes, ac_cv_sigaction_need_reinstall=no, + dnl When cross-compiling, do not assume anything. + ac_cv_sigaction_need_reinstall="guessing yes" ) AC_LANG_RESTORE ] @@ -395,11 +537,12 @@ AC_CACHE_CHECK("whether your system supports extended signal handlers", AC_LANG_CPLUSPLUS AC_TRY_RUN([ #define HAVE_SIGINFO_T 1 - #define CONFIGURE_TEST + #define CONFIGURE_TEST_SIGSEGV_RECOVERY + #include "vm_alloc.cpp" #include "sigsegv.cpp" - ], - [ac_cv_have_extended_signals=yes], - [ac_cv_have_extended_signals=no] + ], ac_cv_have_extended_signals=yes, ac_cv_have_extended_signals=no, + dnl When cross-compiling, do not assume anything. + ac_cv_have_extended_signals=no ) AC_LANG_RESTORE ] @@ -414,11 +557,12 @@ if [[ "x$ac_cv_have_extended_signals" = "xno" ]]; then AC_LANG_CPLUSPLUS AC_TRY_RUN([ #define HAVE_SIGCONTEXT_SUBTERFUGE 1 - #define CONFIGURE_TEST + #define CONFIGURE_TEST_SIGSEGV_RECOVERY + #include "vm_alloc.cpp" #include "sigsegv.cpp" - ], - [ac_cv_have_sigcontext_hack=yes], - [ac_cv_have_sigcontext_hack=no] + ], ac_cv_have_sigcontext_hack=yes, ac_cv_have_sigcontext_hack=no, + dnl When cross-compiling, do not assume anything. + ac_cv_have_sigcontext_hack=no ) AC_LANG_RESTORE ]) diff --git a/BasiliskII/src/Unix/main_unix.cpp b/BasiliskII/src/Unix/main_unix.cpp index ac6a8cc6..393f3bea 100644 --- a/BasiliskII/src/Unix/main_unix.cpp +++ b/BasiliskII/src/Unix/main_unix.cpp @@ -71,6 +71,7 @@ struct sigstate { #include "user_strings.h" #include "version.h" #include "main.h" +#include "vm_alloc.h" #ifdef ENABLE_MON # include "mon.h" @@ -108,7 +109,6 @@ bool TwentyFourBitAddressing; char *x_display_name = NULL; // X11 display name Display *x_display = NULL; // X11 display handle -static int zero_fd = -1; // FD of /dev/zero static uint8 last_xpram[256]; // Buffer for monitoring XPRAM changes #ifdef HAVE_PTHREADS @@ -154,11 +154,6 @@ static void sigint_handler(...); #if REAL_ADDRESSING static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped -static bool memory_mapped_from_zero = false; // Flag: Could allocate RAM area from 0 -#endif - -#if REAL_ADDRESSING || DIRECT_ADDRESSING -static uint32 mapped_ram_rom_size; // Total size of mmap()ed RAM/ROM area #endif @@ -272,14 +267,6 @@ int main(int argc, char **argv) if (!PrefsEditor()) QuitEmulator(); - // Open /dev/zero - zero_fd = open("/dev/zero", O_RDWR); - if (zero_fd < 0) { - sprintf(str, GetString(STR_NO_DEV_ZERO_ERR), strerror(errno)); - ErrorAlert(str); - QuitEmulator(); - } - // Read RAM size RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary if (RAMSize < 1024*1024) { @@ -288,32 +275,37 @@ int main(int argc, char **argv) } #if REAL_ADDRESSING || DIRECT_ADDRESSING - const uint32 page_size = getpagesize(); - const uint32 page_mask = page_size - 1; - const uint32 aligned_ram_size = (RAMSize + page_mask) & ~page_mask; - mapped_ram_rom_size = aligned_ram_size + 0x100000; + RAMSize = RAMSize & -getpagesize(); // Round down to page boundary #endif + + // Initialize VM system + vm_init(); #if REAL_ADDRESSING - // Try to allocate the complete address space from zero - // gb-- the Solaris manpage about mmap(2) states that using MAP_FIXED - // implies undefined behaviour for further use of sbrk(), malloc(), etc. - // cebix-- on NetBSD/m68k, this causes a segfault + // Flag: RAM and ROM are contigously allocated from address 0 + bool memory_mapped_from_zero = false; + + // Under Solaris/SPARC and NetBSD/m68k, Basilisk II is known to crash + // when trying to map a too big chunk of memory starting at address 0 #if defined(OS_solaris) || defined(OS_netbsd) - // Anyway, it doesn't work... - if (0) { + const bool can_map_all_memory = false; #else - if (mmap((caddr_t)0x0000, mapped_ram_rom_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, zero_fd, 0) != MAP_FAILED) { + const bool can_map_all_memory = true; #endif + + // Try to allocate all memory from 0x0000, if it is not known to crash + if (can_map_all_memory && (vm_acquire_fixed(0, RAMSize + 0x100000) == 0)) { D(bug("Could allocate RAM and ROM from 0x0000\n")); memory_mapped_from_zero = true; } - // Create Low Memory area (0x0000..0x2000) - else if (mmap((char *)0x0000, 0x2000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, zero_fd, 0) != MAP_FAILED) { + + // Otherwise, just create the Low Memory area (0x0000..0x2000) + else if (vm_acquire_fixed(0, 0x2000) == 0) { D(bug("Could allocate the Low Memory globals\n")); lm_area_mapped = true; } - // Exit on error + + // Exit on failure else { sprintf(str, GetString(STR_LOW_MEM_MMAP_ERR), strerror(errno)); ErrorAlert(str); @@ -323,8 +315,8 @@ int main(int argc, char **argv) #if USE_SCRATCHMEM_SUBTERFUGE // Allocate scratch memory - ScratchMem = (uint8 *)malloc(SCRATCH_MEM_SIZE); - if (ScratchMem == NULL) { + ScratchMem = (uint8 *)vm_acquire(SCRATCH_MEM_SIZE); + if (ScratchMem == VM_MAP_FAILED) { ErrorAlert(GetString(STR_NO_MEM_ERR)); QuitEmulator(); } @@ -332,41 +324,29 @@ int main(int argc, char **argv) #endif // Create areas for Mac RAM and ROM -#if REAL_ADDRESSING || DIRECT_ADDRESSING - // gb-- Overkill, needs to be cleaned up. Probably explode it for either - // real or direct addressing mode. #if REAL_ADDRESSING if (memory_mapped_from_zero) { RAMBaseHost = (uint8 *)0; - ROMBaseHost = RAMBaseHost + aligned_ram_size; + ROMBaseHost = RAMBaseHost + RAMSize; } else #endif { - RAMBaseHost = (uint8 *)mmap(0, mapped_ram_rom_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zero_fd, 0); - if (RAMBaseHost == (uint8 *)MAP_FAILED) { + RAMBaseHost = (uint8 *)vm_acquire(RAMSize); + ROMBaseHost = (uint8 *)vm_acquire(0x100000); + if (RAMBaseHost == VM_MAP_FAILED || ROMBaseHost == VM_MAP_FAILED) { ErrorAlert(GetString(STR_NO_MEM_ERR)); QuitEmulator(); } - ROMBaseHost = RAMBaseHost + aligned_ram_size; } -#else - RAMBaseHost = (uint8 *)malloc(RAMSize); - ROMBaseHost = (uint8 *)malloc(0x100000); - if (RAMBaseHost == NULL || ROMBaseHost == NULL) { - ErrorAlert(GetString(STR_NO_MEM_ERR)); - QuitEmulator(); - } -#endif #if DIRECT_ADDRESSING - // Initialize MEMBaseDiff now so that Host2MacAddr in the Video module - // will return correct results + // RAMBaseMac shall always be zero + MEMBaseDiff = (uintptr)RAMBaseHost; RAMBaseMac = 0; - ROMBaseMac = RAMBaseMac + aligned_ram_size; - InitMEMBaseDiff(RAMBaseHost, RAMBaseMac); + ROMBaseMac = Host2MacAddr(ROMBaseHost); #endif -#if REAL_ADDRESSING // && !EMULATED_68K +#if REAL_ADDRESSING RAMBaseMac = (uint32)RAMBaseHost; ROMBaseMac = (uint32)ROMBaseHost; #endif @@ -623,31 +603,19 @@ void QuitEmulator(void) ExitAll(); // Free ROM/RAM areas -#if REAL_ADDRESSING - if (memory_mapped_from_zero) - munmap((caddr_t)0x0000, mapped_ram_rom_size); - else -#endif -#if REAL_ADDRESSING || DIRECT_ADDRESSING - if (RAMBaseHost != (uint8 *)MAP_FAILED) { - munmap((caddr_t)RAMBaseHost, mapped_ram_rom_size); + if (RAMBaseHost != VM_MAP_FAILED) { + vm_release(RAMBaseHost, RAMSize); RAMBaseHost = NULL; } -#else - if (ROMBaseHost) { - free(ROMBaseHost); + if (ROMBaseHost != VM_MAP_FAILED) { + vm_release(ROMBaseHost, 0x100000); ROMBaseHost = NULL; } - if (RAMBaseHost) { - free(RAMBaseHost); - RAMBaseHost = NULL; - } -#endif #if USE_SCRATCHMEM_SUBTERFUGE // Delete scratch memory area - if (ScratchMem) { - free((void *)(ScratchMem - SCRATCH_MEM_SIZE/2)); + if (ScratchMem != (uint8 *)VM_MAP_FAILED) { + vm_release((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE); ScratchMem = NULL; } #endif @@ -655,12 +623,11 @@ void QuitEmulator(void) #if REAL_ADDRESSING // Delete Low Memory area if (lm_area_mapped) - munmap((char *)0x0000, 0x2000); + vm_release(0, 0x2000); #endif - - // Close /dev/zero - if (zero_fd > 0) - close(zero_fd); + + // Exit VM wrappers + vm_exit(); // Exit system routines SysExit(); diff --git a/BasiliskII/src/Unix/sigsegv.cpp b/BasiliskII/src/Unix/sigsegv.cpp index 03f09ae2..ec96d2c2 100644 --- a/BasiliskII/src/Unix/sigsegv.cpp +++ b/BasiliskII/src/Unix/sigsegv.cpp @@ -70,15 +70,30 @@ static bool sigsegv_do_install_handler(int sig); #endif #if (defined(sparc) || defined(__sparc__)) #include -#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext* scp, char* addr +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char* addr #define SIGSEGV_FAULT_ADDRESS addr #endif #if (defined(powerpc) || defined(__powerpc__)) #include -#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext* scp +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp #define SIGSEGV_FAULT_ADDRESS scp->regs->dar #define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip #endif +#if (defined(alpha) || defined(__alpha__)) +#include +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp +#define SIGSEGV_FAULT_ADDRESS get_fault_address(scp) +#define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc + +// From Boehm's GC 6.0alpha8 +static sigsegv_address_t get_fault_address(struct sigcontext *scp) +{ + unsigned int instruction = *((unsigned int *)(scp->sc_pc)); + unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f]; + fault_address += (signed long)(signed short)(instruction & 0xffff); + return (sigsegv_address_t)fault_address; +} +#endif #endif // Irix 5 or 6 on MIPS @@ -132,6 +147,114 @@ static bool sigsegv_do_install_handler(int sig); #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS) #endif #endif + +// MacOS X +#if defined(__APPLE__) && defined(__MACH__) +#if (defined(ppc) || defined(__ppc__)) +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp +#define SIGSEGV_FAULT_ADDRESS get_fault_address(scp) +#define SIGSEGV_FAULT_INSTRUCTION scp->sc_ir +#define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS) + +// From Boehm's GC 6.0alpha8 +#define EXTRACT_OP1(iw) (((iw) & 0xFC000000) >> 26) +#define EXTRACT_OP2(iw) (((iw) & 0x000007FE) >> 1) +#define EXTRACT_REGA(iw) (((iw) & 0x001F0000) >> 16) +#define EXTRACT_REGB(iw) (((iw) & 0x03E00000) >> 21) +#define EXTRACT_REGC(iw) (((iw) & 0x0000F800) >> 11) +#define EXTRACT_DISP(iw) ((short *) &(iw))[1] + +static sigsegv_address_t get_fault_address(struct sigcontext *scp) +{ + unsigned int instr = *((unsigned int *) scp->sc_ir); + unsigned int * regs = &((unsigned int *) scp->sc_regs)[2]; + int disp = 0, tmp; + unsigned int baseA = 0, baseB = 0; + unsigned int addr, alignmask = 0xFFFFFFFF; + + switch(EXTRACT_OP1(instr)) { + case 38: /* stb */ + case 39: /* stbu */ + case 54: /* stfd */ + case 55: /* stfdu */ + case 52: /* stfs */ + case 53: /* stfsu */ + case 44: /* sth */ + case 45: /* sthu */ + case 47: /* stmw */ + case 36: /* stw */ + case 37: /* stwu */ + tmp = EXTRACT_REGA(instr); + if(tmp > 0) + baseA = regs[tmp]; + disp = EXTRACT_DISP(instr); + break; + case 31: + switch(EXTRACT_OP2(instr)) { + case 86: /* dcbf */ + case 54: /* dcbst */ + case 1014: /* dcbz */ + case 247: /* stbux */ + case 215: /* stbx */ + case 759: /* stfdux */ + case 727: /* stfdx */ + case 983: /* stfiwx */ + case 695: /* stfsux */ + case 663: /* stfsx */ + case 918: /* sthbrx */ + case 439: /* sthux */ + case 407: /* sthx */ + case 661: /* stswx */ + case 662: /* stwbrx */ + case 150: /* stwcx. */ + case 183: /* stwux */ + case 151: /* stwx */ + case 135: /* stvebx */ + case 167: /* stvehx */ + case 199: /* stvewx */ + case 231: /* stvx */ + case 487: /* stvxl */ + tmp = EXTRACT_REGA(instr); + if(tmp > 0) + baseA = regs[tmp]; + baseB = regs[EXTRACT_REGC(instr)]; + /* determine Altivec alignment mask */ + switch(EXTRACT_OP2(instr)) { + case 167: /* stvehx */ + alignmask = 0xFFFFFFFE; + break; + case 199: /* stvewx */ + alignmask = 0xFFFFFFFC; + break; + case 231: /* stvx */ + alignmask = 0xFFFFFFF0; + break; + case 487: /* stvxl */ + alignmask = 0xFFFFFFF0; + break; + } + break; + case 725: /* stswi */ + tmp = EXTRACT_REGA(instr); + if(tmp > 0) + baseA = regs[tmp]; + break; + default: /* ignore instruction */ + return 0; + break; + } + break; + default: /* ignore instruction */ + return 0; + break; + } + + addr = (baseA + baseB) + disp; + addr &= alignmask; + return (sigsegv_address_t)addr; +} +#endif +#endif #endif // Fallbacks @@ -243,12 +366,12 @@ void sigsegv_deinstall_handler(void) * Test program used for configure/test */ -#ifdef CONFIGURE_TEST +#ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY #include #include -#include #include #include +#include "vm_alloc.h" static int page_size; static volatile char * page = 0; @@ -259,20 +382,21 @@ static bool sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_addres handler_called++; if ((fault_address - 123) != page) exit(1); - if (mprotect((char *)((unsigned long)fault_address & -page_size), page_size, PROT_READ | PROT_WRITE) != 0) + if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0) exit(1); return true; } int main(void) { - int zero_fd = open("/dev/zero", O_RDWR); - if (zero_fd < 0) + if (vm_init() < 0) return 1; page_size = getpagesize(); - page = (char *)mmap(0, page_size, PROT_READ, MAP_PRIVATE, zero_fd, 0); - if (page == MAP_FAILED) + if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED) + return 1; + + if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0) return 1; if (!sigsegv_install_handler(sigsegv_test_handler)) @@ -284,6 +408,7 @@ int main(void) if (handler_called != 1) return 1; + vm_exit(); return 0; } #endif diff --git a/BasiliskII/src/Unix/video_vosf.h b/BasiliskII/src/Unix/video_vosf.h index 77e71220..4b5c6fdc 100644 --- a/BasiliskII/src/Unix/video_vosf.h +++ b/BasiliskII/src/Unix/video_vosf.h @@ -28,21 +28,14 @@ * Page-aligned memory allocation */ -// Align on page boundaries -static uintptr align_on_page_boundary(uintptr size) +// Extend size to page boundary +static uint32 page_extend(uint32 size) { const uint32 page_size = getpagesize(); const uint32 page_mask = page_size - 1; return (size + page_mask) & ~page_mask; } -// Allocate memory on page boundary -static void * allocate_framebuffer(uint32 size, uint8 * hint = 0) -{ - // Remind that the system can allocate at 0x00000000... - return mmap((caddr_t)hint, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zero_fd, 0); -} - // Screen fault handler static bool screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction) { @@ -55,10 +48,10 @@ static bool screen_fault_handler(sigsegv_address_t fault_address, sigsegv_addres */ if ((addr >= mainBuffer.memStart) && (addr < mainBuffer.memEnd)) { const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits; - caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1)); + caddr_t page_ad = (caddr_t)(addr & -mainBuffer.pageSize); LOCK_VOSF; PFLAG_SET(page); - mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE); + vm_protect((char *)page_ad, mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE); mainBuffer.dirty = true; UNLOCK_VOSF; return true; @@ -127,7 +120,7 @@ static inline void update_display_window_vosf(void) // Make the dirty pages read-only again const int32 offset = first_page << mainBuffer.pageBits; const uint32 length = (page - first_page) << mainBuffer.pageBits; - mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ); + vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ); // There is at least one line to update const int y1 = mainBuffer.pageInfo[first_page].top; @@ -185,7 +178,7 @@ static inline void update_display_dga_vosf(void) // Make the dirty pages read-only again const int32 offset = first_page << mainBuffer.pageBits; const uint32 length = (page - first_page) << mainBuffer.pageBits; - mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ); + vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ); // I am sure that y2 >= y1 and depth != 1 const int y1 = mainBuffer.pageInfo[first_page].top; diff --git a/BasiliskII/src/Unix/video_x.cpp b/BasiliskII/src/Unix/video_x.cpp index d250f012..38c5b955 100644 --- a/BasiliskII/src/Unix/video_x.cpp +++ b/BasiliskII/src/Unix/video_x.cpp @@ -56,6 +56,7 @@ # include # include # include "sigsegv.h" +# include "vm_alloc.h" #endif #include "cpu_emulation.h" @@ -187,9 +188,9 @@ struct ScreenPageInfo { }; struct ScreenInfo { - uint32 memBase; // Real start address - uint32 memStart; // Start address aligned to page boundary - uint32 memEnd; // Address of one-past-the-end of the screen + uintptr memBase; // Real start address + uintptr memStart; // Start address aligned to page boundary + uintptr memEnd; // Address of one-past-the-end of the screen uint32 memLength; // Length of the memory addressed by the screen pages uint32 pageSize; // Size of a page @@ -544,15 +545,11 @@ static bool init_window(int width, int height) } #ifdef ENABLE_VOSF - // Allocate a page-aligned chunk of memory for frame buffer - the_buffer_size = align_on_page_boundary((aligned_height + 2) * img->bytes_per_line); + // Allocate memory for frame buffer (SIZE is extended to page-boundary) the_host_buffer = the_buffer_copy; - - the_buffer_copy = (uint8 *)allocate_framebuffer(the_buffer_size); - memset(the_buffer_copy, 0, the_buffer_size); - - the_buffer = (uint8 *)allocate_framebuffer(the_buffer_size); - memset(the_buffer, 0, the_buffer_size); + the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line); + the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size); + the_buffer = (uint8 *)vm_acquire(the_buffer_size); #else // Allocate memory for frame buffer the_buffer = (uint8 *)malloc((aligned_height + 2) * img->bytes_per_line); @@ -721,12 +718,11 @@ static bool init_fbdev_dga(char *in_fb_name) use_vosf = Screen_blitter_init(&visualInfo, true); if (use_vosf) { - the_host_buffer = the_buffer; - the_buffer_size = align_on_page_boundary((height + 2) * bytes_per_row); - the_buffer_copy = (uint8 *)malloc(the_buffer_size); - memset(the_buffer_copy, 0, the_buffer_size); - the_buffer = (uint8 *)allocate_framebuffer(the_buffer_size); - memset(the_buffer, 0, the_buffer_size); + // Allocate memory for frame buffer (SIZE is extended to page-boundary) + the_host_buffer = the_buffer; + the_buffer_size = page_extend((height + 2) * bytes_per_row); + the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size); + the_buffer = (uint8 *)vm_acquire(the_buffer_size); } #else use_vosf = false; @@ -821,23 +817,23 @@ static bool init_xf86_dga(int width, int height) bytes_per_row *= 4; break; } - + +#ifdef VIDEO_VOSF #if REAL_ADDRESSING || DIRECT_ADDRESSING // Screen_blitter_init() returns TRUE if VOSF is mandatory // i.e. the framebuffer update function is not Blit_Copy_Raw use_vosf = Screen_blitter_init(&visualInfo, true); if (use_vosf) { - the_host_buffer = the_buffer; - the_buffer_size = align_on_page_boundary((height + 2) * bytes_per_row); - the_buffer_copy = (uint8 *)malloc(the_buffer_size); - memset(the_buffer_copy, 0, the_buffer_size); - the_buffer = (uint8 *)allocate_framebuffer(the_buffer_size); - memset(the_buffer, 0, the_buffer_size); + // Allocate memory for frame buffer (SIZE is extended to page-boundary) + the_host_buffer = the_buffer; + the_buffer_size = page_extend((height + 2) * bytes_per_row); + the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size); + the_buffer = (uint8 *)vm_acquire(the_buffer_size); } -#elif defined(ENABLE_VOSF) - // The UAE memory handlers will already handle color conversion, if needed. +#else use_vosf = false; +#endif #endif set_video_monitor(width, height, bytes_per_row, true); @@ -926,9 +922,9 @@ bool VideoInitBuffer() const uint32 page_size = getpagesize(); const uint32 page_mask = page_size - 1; - mainBuffer.memBase = (uint32) the_buffer; + mainBuffer.memBase = (uintptr) the_buffer; // Align the frame buffer on page boundary - mainBuffer.memStart = (uint32)((((unsigned long) the_buffer) + page_mask) & ~page_mask); + mainBuffer.memStart = (uintptr)((((unsigned long) the_buffer) + page_mask) & ~page_mask); mainBuffer.memLength = the_buffer_size; mainBuffer.memEnd = mainBuffer.memStart + mainBuffer.memLength; @@ -976,7 +972,7 @@ bool VideoInitBuffer() } // We can now write-protect the frame buffer - if (mprotect((caddr_t)mainBuffer.memStart, mainBuffer.memLength, PROT_READ) != 0) + if (vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ) != 0) return false; } #endif @@ -1260,13 +1256,13 @@ void VideoExit(void) } #ifdef ENABLE_VOSF else { - if (the_buffer != (uint8 *)MAP_FAILED) { - munmap((caddr_t)the_buffer, the_buffer_size); + if (the_buffer != (uint8 *)VM_MAP_FAILED) { + vm_release(the_buffer, the_buffer_size); the_buffer = 0; } - if (the_buffer_copy != (uint8 *)MAP_FAILED) { - munmap((caddr_t)the_buffer_copy, the_buffer_size); + if (the_buffer_copy != (uint8 *)VM_MAP_FAILED) { + vm_release(the_buffer_copy, the_buffer_size); the_buffer_copy = 0; } } diff --git a/BasiliskII/src/Unix/vm_alloc.cpp b/BasiliskII/src/Unix/vm_alloc.cpp new file mode 100644 index 00000000..71dc61d2 --- /dev/null +++ b/BasiliskII/src/Unix/vm_alloc.cpp @@ -0,0 +1,258 @@ +/* + * vm_alloc.cpp - Wrapper to various virtual memory allocation schemes + * (supports mmap, vm_allocate or fallbacks to malloc) + * + * Basilisk II (C) 1997-2001 Christian Bauer + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// TODO: Win32 VMs ? +#include +#include +#include "vm_alloc.h" + +#ifdef HAVE_MACH_VM +#ifndef HAVE_MACH_TASK_SELF +#ifdef HAVE_TASK_SELF +#define mach_task_self task_self +#else +#error "No task_self(), you lose." +#endif +#endif +#endif + +#ifdef HAVE_MMAP_VM +#ifdef HAVE_MMAP_ANON +#define map_flags (MAP_PRIVATE | MAP_ANON) +#define zero_fd -1 +#else +#ifdef HAVE_MMAP_ANONYMOUS +#define map_flags (MAP_PRIVATE | MAP_ANONYMOUS) +#define zero_fd -1 +#else +#ifdef HAVE_FCNTL_H +#include +#endif +#define map_flags (MAP_PRIVATE) +static int zero_fd = -1; +#endif +#endif +#endif + +/* Initialize the VM system. Returns 0 if successful, -1 for errors. */ + +int vm_init(void) +{ +#ifdef HAVE_MMAP_VM +#ifndef zero_fd + zero_fd = open("/dev/zero", O_RDWR); + if (zero_fd < 0) + return -1; +#endif +#endif + return 0; +} + +/* Deallocate all internal data used to wrap virtual memory allocators. */ + +void vm_exit(void) +{ +#ifdef HAVE_MMAP_VM +#ifndef zero_fd + close(zero_fd); +#endif +#endif +} + +/* Allocate zero-filled memory of SIZE bytes. The mapping is private + and default protection bits are read / write. The return value + is the actual mapping address chosen or VM_MAP_FAILED for errors. */ + +void * vm_acquire(size_t size) +{ + void * addr; + +#ifdef HAVE_MACH_VM + // vm_allocate() returns a zero-filled memory region + if (vm_allocate(mach_task_self(), (vm_address_t *)&addr, size, TRUE) != KERN_SUCCESS) + return VM_MAP_FAILED; +#else +#ifdef HAVE_MMAP_VM + if ((addr = mmap(0, size, VM_PAGE_DEFAULT, map_flags, zero_fd, 0)) == MAP_FAILED) + return VM_MAP_FAILED; + + // Since I don't know the standard behavior of mmap(), zero-fill here + if (memset(addr, 0, size) != addr) + return VM_MAP_FAILED; +#else + if ((addr = calloc(size, 1)) == 0) + return VM_MAP_FAILED; + + // Omit changes for protections because they are not supported in this mode + return addr; +#endif +#endif + + // Explicitely protect the newly mapped region here because on some systems, + // say MacOS X, mmap() doesn't honour the requested protection flags. + if (vm_protect(addr, size, VM_PAGE_DEFAULT) != 0) + return VM_MAP_FAILED; + + return addr; +} + +/* Allocate zero-filled memory at exactly ADDR (which must be page-aligned). + Retuns 0 if successful, -1 on errors. */ + +int vm_acquire_fixed(void * addr, size_t size) +{ +#ifdef HAVE_MACH_VM + // vm_allocate() returns a zero-filled memory region + if (vm_allocate(mach_task_self(), (vm_address_t *)&addr, size, 0) != KERN_SUCCESS) + return -1; +#else +#ifdef HAVE_MMAP_VM + if (mmap(addr, size, VM_PAGE_DEFAULT, map_flags | MAP_FIXED, zero_fd, 0) == MAP_FAILED) + return -1; + + // Since I don't know the standard behavior of mmap(), zero-fill here + if (memset(0, 0, size) != 0) + return -1; +#else + // Unsupported + return -1; +#endif +#endif + + // Explicitely protect the newly mapped region here because on some systems, + // say MacOS X, mmap() doesn't honour the requested protection flags. + if (vm_protect(0, size, VM_PAGE_DEFAULT) != 0) + return -1; + + return 0; +} + +/* Deallocate any mapping for the region starting at ADDR and extending + LEN bytes. Returns 0 if successful, -1 on errors. */ + +int vm_release(void * addr, size_t size) +{ +#ifdef HAVE_MACH_VM + int ret_code = vm_deallocate(mach_task_self(), (vm_address_t)addr, size); + return ret_code == KERN_SUCCESS ? 0 : -1; +#else +#ifdef HAVE_MMAP_VM + int ret_code = munmap(addr, size); + return ret_code == 0 ? 0 : -1; +#else + free(addr); + return 0; +#endif +#endif +} + +/* Change the memory protection of the region starting at ADDR and + extending LEN bytes to PROT. Returns 0 if successful, -1 for errors. */ + +int vm_protect(void * addr, size_t size, int prot) +{ +#ifdef HAVE_MACH_VM + int ret_code = vm_protect(mach_task_self(), (vm_address_t)addr, size, 0, prot); + return ret_code == KERN_SUCCESS ? 0 : -1; +#else +#ifdef HAVE_MMAP_VM + int ret_code = mprotect(addr, size, prot); + return ret_code == 0 ? 0 : -1; +#else + // Unsupported + return -1; +#endif +#endif +} + +#ifdef CONFIGURE_TEST_VM_MAP +/* Tests covered here: + - TEST_VM_PROT_* program slices actually succeeds when a crash occurs + - TEST_VM_MAP_ANON* program slices succeeds when it could be compiled +*/ +int main(void) +{ + vm_init(); + +#define page_align(address) ((char *)((unsigned long)(address) & -page_size)) + unsigned long page_size = getpagesize(); + + const int area_size = 6 * page_size; + volatile char * area = (volatile char *) vm_acquire(area_size); + volatile char * fault_address = area + (page_size * 7) / 2; + +#if defined(TEST_VM_MMAP_ANON) || defined(TEST_VM_MMAP_ANONYMOUS) + if (area == VM_MAP_FAILED) + return 1; + + if (vm_release((char *)area, area_size) < 0) + return 1; + + return 0; +#endif + +#if defined(TEST_VM_PROT_NONE_READ) || defined(TEST_VM_PROT_NONE_WRITE) + if (area == VM_MAP_FAILED) + return 0; + + if (vm_protect(page_align(fault_address), page_size, VM_PAGE_NOACCESS) < 0) + return 0; +#endif + +#if defined(TEST_VM_PROT_RDWR_WRITE) + if (area == VM_MAP_FAILED) + return 1; + + if (vm_protect(page_align(fault_address), page_size, VM_PAGE_READ) < 0) + return 1; + + if (vm_protect(page_align(fault_address), page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0) + return 1; +#endif + +#if defined(TEST_VM_PROT_READ_WRITE) + if (vm_protect(page_align(fault_address), page_size, VM_PAGE_READ) < 0) + return 0; +#endif + +#if defined(TEST_VM_PROT_NONE_READ) + // this should cause a core dump + char foo = *fault_address; + return 0; +#endif + +#if defined(TEST_VM_PROT_NONE_WRITE) || defined(TEST_VM_PROT_READ_WRITE) + // this should cause a core dump + *fault_address = 'z'; + return 0; +#endif + +#if defined(TEST_VM_PROT_RDWR_WRITE) + // this should not cause a core dump + *fault_address = 'z'; + return 0; +#endif +} +#endif diff --git a/BasiliskII/src/Unix/vm_alloc.h b/BasiliskII/src/Unix/vm_alloc.h new file mode 100644 index 00000000..1616b1af --- /dev/null +++ b/BasiliskII/src/Unix/vm_alloc.h @@ -0,0 +1,96 @@ +/* + * vm_alloc.h - Wrapper to various virtual memory allocation schemes + * (supports mmap, vm_allocate or fallbacks to malloc) + * + * Basilisk II (C) 1997-2001 Christian Bauer + * + * 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 + */ + +// TODO: Win32 VM ? +#ifndef VM_ALLOC_H +#define VM_ALLOC_H + +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +/* Return value of `vm_acquire' in case of an error. */ +#ifdef HAVE_MACH_VM +#define VM_MAP_FAILED ((void *)-1) +#else +#ifdef HAVE_MMAP_VM +#define VM_MAP_FAILED ((void *)-1) +#else +#define VM_MAP_FAILED 0 +#endif +#endif + +/* Protection bits. */ +#ifdef HAVE_MACH_VM +#define VM_PAGE_NOACCESS VM_PROT_NONE +#define VM_PAGE_READ VM_PROT_READ +#define VM_PAGE_WRITE VM_PROT_WRITE +#define VM_PAGE_EXECUTE VM_PROT_EXECUTE +#else +#ifdef HAVE_MMAP_VM +#define VM_PAGE_NOACCESS PROT_NONE +#define VM_PAGE_READ PROT_READ +#define VM_PAGE_WRITE PROT_WRITE +#define VM_PAGE_EXECUTE PROT_EXEC +#else +#define VM_PAGE_NOACCESS 0x0 +#define VM_PAGE_READ 0x1 +#define VM_PAGE_WRITE 0x2 +#define VM_PAGE_EXECUTE 0x4 +#endif +#endif + +/* Default protection bits. */ +#define VM_PAGE_DEFAULT (VM_PAGE_READ | VM_PAGE_WRITE) + +/* Initialize the VM system. Returns 0 if successful, -1 for errors. */ + +extern int vm_init(void); + +/* Deallocate all internal data used to wrap virtual memory allocators. */ + +extern void vm_exit(void); + +/* Allocate zero-filled memory of SIZE bytes. The mapping is private + and default protection bits are read / write. The return value + is the actual mapping address chosen or VM_MAP_FAILED for errors. */ + +extern void * vm_acquire(size_t size); + +/* Allocate zero-filled memory at exactly ADDR (which must be page-aligned). + Returns 0 if successful, -1 on errors. */ + +extern int vm_acquire_fixed(void * addr, size_t size); + +/* Deallocate any mapping for the region starting at ADDR and extending + LEN bytes. Returns 0 if successful, -1 on errors. */ + +extern int vm_release(void * addr, size_t size); + +/* Change the memory protection of the region starting at ADDR and + extending LEN bytes to PROT. Returns 0 if successful, -1 for errors. */ + +extern int vm_protect(void * addr, size_t size, int prot); + +#endif /* VM_ALLOC_H */ diff --git a/BasiliskII/src/uae_cpu/basilisk_glue.cpp b/BasiliskII/src/uae_cpu/basilisk_glue.cpp index 3a54de76..b3f3ea3b 100644 --- a/BasiliskII/src/uae_cpu/basilisk_glue.cpp +++ b/BasiliskII/src/uae_cpu/basilisk_glue.cpp @@ -64,7 +64,10 @@ bool Init680x0(void) RAMBaseMac = (uint32)RAMBaseHost; ROMBaseMac = (uint32)ROMBaseHost; #elif DIRECT_ADDRESSING - InitMEMBaseDiff(RAMBaseHost, RAMBaseMac); + // Mac address space = host address space minus constant offset (MEMBaseDiff) + // NOTE: MEMBaseDiff is set in main_unix.cpp/main() + RAMBaseMac = 0; + ROMBaseMac = Host2MacAddr(ROMBaseHost); #else // Initialize UAE memory banks RAMBaseMac = 0; diff --git a/BasiliskII/src/uae_cpu/memory.h b/BasiliskII/src/uae_cpu/memory.h index efe22034..eceea651 100644 --- a/BasiliskII/src/uae_cpu/memory.h +++ b/BasiliskII/src/uae_cpu/memory.h @@ -113,16 +113,15 @@ extern void byteput(uaecptr addr, uae_u32 b); #endif /* !DIRECT_ADDRESSING && !REAL_ADDRESSING */ #if REAL_ADDRESSING +const uintptr MEMBaseDiff = 0; #define do_get_real_address(a) ((uae_u8 *)(a)) #define do_get_virtual_address(a) ((uae_u32)(a)) -#define InitMEMBaseDiff(va, ra) do { } while (0) #endif /* REAL_ADDRESSING */ #if DIRECT_ADDRESSING extern uintptr MEMBaseDiff; #define do_get_real_address(a) ((uae_u8 *)(a) + MEMBaseDiff) #define do_get_virtual_address(a) ((uae_u32)(a) - MEMBaseDiff) -#define InitMEMBaseDiff(va, ra) (MEMBaseDiff = (uintptr)(va) - (uintptr)(ra)) #endif /* DIRECT_ADDRESSING */ #if REAL_ADDRESSING || DIRECT_ADDRESSING