mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-11-26 10:49:21 +00:00
- 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
This commit is contained in:
parent
673c53231f
commit
dae4fb627c
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 <sys/mman.h> defines MAP_ANON and mmap()'ing with MAP_ANON works */
|
||||
#undef HAVE_MMAP_ANON
|
||||
|
||||
/* Define if <sys/mman.h> 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:
|
||||
|
@ -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 <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
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
|
||||
]
|
||||
@ -346,9 +488,9 @@ AC_CACHE_CHECK("whether signal handlers need 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_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
|
||||
]
|
||||
@ -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
|
||||
])
|
||||
|
@ -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();
|
||||
|
@ -79,6 +79,21 @@ static bool sigsegv_do_install_handler(int sig);
|
||||
#define SIGSEGV_FAULT_ADDRESS scp->regs->dar
|
||||
#define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip
|
||||
#endif
|
||||
#if (defined(alpha) || defined(__alpha__))
|
||||
#include <asm/sigcontext.h>
|
||||
#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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#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
|
||||
|
@ -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;
|
||||
|
@ -56,6 +56,7 @@
|
||||
# include <fcntl.h>
|
||||
# include <sys/mman.h>
|
||||
# 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) {
|
||||
// Allocate memory for frame buffer (SIZE is extended to page-boundary)
|
||||
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);
|
||||
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;
|
||||
@ -822,22 +818,22 @@ static bool init_xf86_dga(int width, int height)
|
||||
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) {
|
||||
// Allocate memory for frame buffer (SIZE is extended to page-boundary)
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
258
BasiliskII/src/Unix/vm_alloc.cpp
Normal file
258
BasiliskII/src/Unix/vm_alloc.cpp
Normal file
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#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 <fcntl.h>
|
||||
#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
|
96
BasiliskII/src/Unix/vm_alloc.h
Normal file
96
BasiliskII/src/Unix/vm_alloc.h
Normal file
@ -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 <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#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 */
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user