--- SheepShaver/src/Unix/main_unix.cpp 2003/11/03 21:28:25 1.13 +++ SheepShaver/src/Unix/main_unix.cpp 2004/05/20 12:33:57 1.35 @@ -1,7 +1,7 @@ /* * main_unix.cpp - Emulation core, Unix implementation * - * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * SheepShaver (C) 1997-2004 Christian Bauer and Marc Hellwig * * 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 @@ -65,6 +65,18 @@ * ExecutePPC (or any function that might cause a mode switch). The signal * stack is restored before exiting the SIGUSR2 handler. * + * There is apparently another problem when processing signals. In + * fullscreen mode, we get quick updates of the mouse position. This + * causes an increased number of calls to TriggerInterrupt(). And, + * since IRQ_NEST is not fully handled atomically, nested calls to + * ppc_interrupt() may cause stack corruption to eventually crash the + * emulator. + * + * FIXME: + * The current solution is to allocate another signal stack when + * processing ppc_interrupt(). However, it may be better to detect + * the INTFLAG_ADB case and handle it specifically with some extra mutex? + * * TODO: * check if SIGSEGV handler works for all registers (including FP!) */ @@ -109,6 +121,7 @@ #include "user_strings.h" #include "vm_alloc.h" #include "sigsegv.h" +#include "thunks.h" #define DEBUG 0 #include "debug.h" @@ -131,6 +144,9 @@ #endif +// Enable emulation of unaligned lmw/stmw? +#define EMULATE_UNALIGNED_LOADSTORE_MULTIPLE 1 + // Enable Execute68k() safety checks? #define SAFE_EXEC_68K 0 @@ -140,31 +156,106 @@ // Interrupts in native mode? #define INTERRUPTS_IN_NATIVE_MODE 1 +// Number of alternate stacks for signal handlers? +#define SIG_STACK_COUNT 4 + // Constants const char ROM_FILE_NAME[] = "ROM"; const char ROM_FILE_NAME2[] = "Mac OS ROM"; -const uint32 RAM_BASE = 0x20000000; // Base address of RAM +const uintptr RAM_BASE = 0x20000000; // Base address of RAM const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack #if !EMULATED_PPC -// Structure in which registers are saved in a signal handler; -// sigcontext->regs points to it -// (see arch/ppc/kernel/signal.c) -typedef struct { - uint32 u[4]; -} __attribute((aligned(16))) vector128; -#include - struct sigregs { - elf_gregset_t gp_regs; // Identical to pt_regs - double fp_regs[ELF_NFPREG]; // f0..f31 and fpsrc - //more (uninteresting) stuff following here + uint32 nip; + uint32 link; + uint32 ctr; + uint32 msr; + uint32 xer; + uint32 ccr; + uint32 gpr[32]; +}; + +#if defined(__linux__) +#include +#define MACHINE_REGISTERS(scp) ((machine_regs *)(((ucontext_t *)scp)->uc_mcontext.regs)) + +struct machine_regs : public pt_regs +{ + u_long & cr() { return pt_regs::ccr; } + uint32 cr() const { return pt_regs::ccr; } + uint32 lr() const { return pt_regs::link; } + uint32 ctr() const { return pt_regs::ctr; } + uint32 xer() const { return pt_regs::xer; } + uint32 msr() const { return pt_regs::msr; } + uint32 dar() const { return pt_regs::dar; } + u_long & pc() { return pt_regs::nip; } + uint32 pc() const { return pt_regs::nip; } + u_long & gpr(int i) { return pt_regs::gpr[i]; } + uint32 gpr(int i) const { return pt_regs::gpr[i]; } +}; +#endif + +#if defined(__APPLE__) && defined(__MACH__) +#include +extern "C" int sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss); + +#include +#define MACHINE_REGISTERS(scp) ((machine_regs *)(((ucontext_t *)scp)->uc_mcontext)) + +struct machine_regs : public mcontext +{ + uint32 & cr() { return ss.cr; } + uint32 cr() const { return ss.cr; } + uint32 lr() const { return ss.lr; } + uint32 ctr() const { return ss.ctr; } + uint32 xer() const { return ss.xer; } + uint32 msr() const { return ss.srr1; } + uint32 dar() const { return es.dar; } + uint32 & pc() { return ss.srr0; } + uint32 pc() const { return ss.srr0; } + uint32 & gpr(int i) { return (&ss.r0)[i]; } + uint32 gpr(int i) const { return (&ss.r0)[i]; } }; #endif +static void build_sigregs(sigregs *srp, machine_regs *mrp) +{ + srp->nip = mrp->pc(); + srp->link = mrp->lr(); + srp->ctr = mrp->ctr(); + srp->msr = mrp->msr(); + srp->xer = mrp->xer(); + srp->ccr = mrp->cr(); + for (int i = 0; i < 32; i++) + srp->gpr[i] = mrp->gpr(i); +} + +static struct sigaltstack sig_stacks[SIG_STACK_COUNT]; // Stacks for signal handlers +static int sig_stack_id = 0; // Stack slot currently used + +static inline void sig_stack_acquire(void) +{ + if (++sig_stack_id == SIG_STACK_COUNT) { + printf("FATAL: signal stack overflow\n"); + return; + } + sigaltstack(&sig_stacks[sig_stack_id], NULL); +} + +static inline void sig_stack_release(void) +{ + if (--sig_stack_id < 0) { + printf("FATAL: signal stack underflow\n"); + return; + } + sigaltstack(&sig_stacks[sig_stack_id], NULL); +} +#endif + // Global variables (exported) #if !EMULATED_PPC @@ -172,9 +263,6 @@ void *TOC; // Small data pointer (r13 #endif uint32 RAMBase; // Base address of Mac RAM uint32 RAMSize; // Size of Mac RAM -uint32 SheepStack1Base; // SheepShaver first alternate stack base -uint32 SheepStack2Base; // SheepShaver second alternate stack base -uint32 SheepThunksBase; // SheepShaver thunks base uint32 KernelDataAddr; // Address of Kernel Data uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM uint32 PVR; // Theoretical PVR @@ -185,9 +273,11 @@ int64 BusClockSpeed; // Bus clock speed // Global variables char *x_display_name = NULL; // X11 display name Display *x_display = NULL; // X11 display handle +#ifdef X11_LOCK_TYPE +X11_LOCK_TYPE x_display_lock = X11_LOCK_INIT; // X11 display lock +#endif static int zero_fd = 0; // FD of /dev/zero -static bool sheep_area_mapped = false; // Flag: SheepShaver data area mmap()ed static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped static int kernel_area = -1; // SHM ID of Kernel Data area static bool rom_area_mapped = false; // Flag: Mac ROM mmap()ped @@ -207,15 +297,21 @@ static bool ready_for_signals = false; static int64 num_segv = 0; // Number of handled SEGV signals static struct sigaction sigusr2_action; // Interrupt signal (of emulator thread) -#if !EMULATED_PPC +#if EMULATED_PPC +static uintptr sig_stack = 0; // Stack for PowerPC interrupt routine +#else static struct sigaction sigsegv_action; // Data access exception signal (of emulator thread) static struct sigaction sigill_action; // Illegal instruction signal (of emulator thread) -static void *sig_stack = NULL; // Stack for signal handlers -static void *extra_stack = NULL; // Stack for SIGSEGV inside interrupt handler static bool emul_thread_fatal = false; // Flag: MacOS thread crashed, tick thread shall dump debug output static sigregs sigsegv_regs; // Register dump when crashed +static const char *crash_reason = NULL; // Reason of the crash (SIGSEGV, SIGBUS, SIGILL) #endif +uint32 SheepMem::page_size; // Size of a native page +uintptr SheepMem::zero_page = 0; // Address of ro page filled in with zeros +uintptr SheepMem::base = 0x60000000; // Address of SheepShaver data +uintptr SheepMem::top = 0; // Top of SheepShaver data (stack like storage) + // Prototypes static void Quit(void); @@ -223,14 +319,13 @@ static void *emul_func(void *arg); static void *nvram_func(void *arg); static void *tick_func(void *arg); #if EMULATED_PPC -static void sigusr2_handler(int sig); extern void emul_ppc(uint32 start); extern void init_emul_ppc(void); extern void exit_emul_ppc(void); #else -static void sigusr2_handler(int sig, sigcontext_struct *sc); -static void sigsegv_handler(int sig, sigcontext_struct *sc); -static void sigill_handler(int sig, sigcontext_struct *sc); +static void sigusr2_handler(int sig, siginfo_t *sip, void *scp); +static void sigsegv_handler(int sig, siginfo_t *sip, void *scp); +static void sigill_handler(int sig, siginfo_t *sip, void *scp); #endif @@ -252,6 +347,16 @@ extern void paranoia_check(void); #if EMULATED_PPC /* + * Return signal stack base + */ + +uintptr SignalStackBase(void) +{ + return sig_stack + SIG_STACK_SIZE; +} + + +/* * Atomic operations */ @@ -375,7 +480,9 @@ int main(int argc, char **argv) PVR = 0x00040000; // Default: 604 CPUClockSpeed = 100000000; // Default: 100MHz BusClockSpeed = 100000000; // Default: 100MHz -#if !EMULATED_PPC +#if EMULATED_PPC + PVR = 0x000c0000; // Default: 7400 (with AltiVec) +#else proc_file = fopen("/proc/cpuinfo", "r"); if (proc_file) { char line[256]; @@ -389,7 +496,7 @@ int main(int argc, char **argv) // Parse line int i; char value[256]; - if (sscanf(line, "cpu : %s", value) == 1) { + if (sscanf(line, "cpu : %[0-9A-Za-a]", value) == 1) { if (strcmp(value, "601") == 0) PVR = 0x00010000; else if (strcmp(value, "603") == 0) @@ -410,6 +517,10 @@ int main(int argc, char **argv) PVR = 0x00320000; else if (strcmp(value, "860") == 0) PVR = 0x00500000; + else if (strcmp(value, "7400") == 0) + PVR = 0x000c0000; + else if (strcmp(value, "7410") == 0) + PVR = 0x800c0000; else printf("WARNING: Unknown CPU type '%s', assuming 604\n", value); } @@ -421,6 +532,15 @@ int main(int argc, char **argv) sprintf(str, GetString(STR_PROC_CPUINFO_WARN), strerror(errno)); WarningAlert(str); } + + // Get actual bus frequency + proc_file = fopen("/proc/device-tree/clock-frequency", "r"); + if (proc_file) { + union { uint8 b[4]; uint32 l; } value; + if (fread(value.b, sizeof(value), 1, proc_file) == 1) + BusClockSpeed = value.l; + fclose(proc_file); + } #endif D(bug("PVR: %08x (assumed)\n", PVR)); @@ -445,6 +565,7 @@ int main(int argc, char **argv) goto quit; } +#ifndef PAGEZERO_HACK // Create Low Memory area (0x0000..0x3000) if (vm_acquire_fixed((char *)0, 0x3000) < 0) { sprintf(str, GetString(STR_LOW_MEM_MMAP_ERR), strerror(errno)); @@ -452,6 +573,7 @@ int main(int argc, char **argv) goto quit; } lm_area_mapped = true; +#endif // Create areas for Kernel Data kernel_area = shmget(IPC_PRIVATE, KERNEL_AREA_SIZE, 0600); @@ -470,21 +592,17 @@ int main(int argc, char **argv) ErrorAlert(str); goto quit; } - kernel_data = (KernelData *)0x68ffe000; + kernel_data = (KernelData *)KERNEL_DATA_BASE; emulator_data = &kernel_data->ed; - KernelDataAddr = (uint32)kernel_data; + KernelDataAddr = KERNEL_DATA_BASE; D(bug("Kernel Data at %p, Emulator Data at %p\n", kernel_data, emulator_data)); // Create area for SheepShaver data - if (vm_acquire_fixed((char *)SHEEP_BASE, SHEEP_SIZE) < 0) { + if (!SheepMem::Init()) { sprintf(str, GetString(STR_SHEEP_MEM_MMAP_ERR), strerror(errno)); ErrorAlert(str); goto quit; } - SheepStack1Base = SHEEP_BASE + 0x10000; - SheepStack2Base = SheepStack1Base + 0x10000; - SheepThunksBase = SheepStack2Base + 0x1000; - sheep_area_mapped = true; // Create area for Mac ROM if (vm_acquire_fixed((char *)ROM_BASE, ROM_AREA_SIZE) < 0) { @@ -492,7 +610,7 @@ int main(int argc, char **argv) ErrorAlert(str); goto quit; } -#if !EMULATED_PPC || defined(__powerpc__) +#if !EMULATED_PPC if (vm_protect((char *)ROM_BASE, ROM_AREA_SIZE, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE) < 0) { sprintf(str, GetString(STR_ROM_MMAP_ERR), strerror(errno)); ErrorAlert(str); @@ -562,6 +680,36 @@ int main(int argc, char **argv) // Load NVRAM XPRAMInit(); + // Load XPRAM default values if signature not found + if (XPRAM[0x130c] != 0x4e || XPRAM[0x130d] != 0x75 + || XPRAM[0x130e] != 0x4d || XPRAM[0x130f] != 0x63) { + D(bug("Loading XPRAM default values\n")); + memset(XPRAM + 0x1300, 0, 0x100); + XPRAM[0x130c] = 0x4e; // "NuMc" signature + XPRAM[0x130d] = 0x75; + XPRAM[0x130e] = 0x4d; + XPRAM[0x130f] = 0x63; + XPRAM[0x1301] = 0x80; // InternalWaitFlags = DynWait (don't wait for SCSI devices upon bootup) + XPRAM[0x1310] = 0xa8; // Standard PRAM values + XPRAM[0x1311] = 0x00; + XPRAM[0x1312] = 0x00; + XPRAM[0x1313] = 0x22; + XPRAM[0x1314] = 0xcc; + XPRAM[0x1315] = 0x0a; + XPRAM[0x1316] = 0xcc; + XPRAM[0x1317] = 0x0a; + XPRAM[0x131c] = 0x00; + XPRAM[0x131d] = 0x02; + XPRAM[0x131e] = 0x63; + XPRAM[0x131f] = 0x00; + XPRAM[0x1308] = 0x13; + XPRAM[0x1309] = 0x88; + XPRAM[0x130a] = 0x00; + XPRAM[0x130b] = 0xcc; + XPRAM[0x1376] = 0x00; // OSDefault = MacOS + XPRAM[0x1377] = 0x01; + } + // Set boot volume i16 = PrefsFindInt32("bootdrive"); XPRAM[0x1378] = i16 >> 8; @@ -579,6 +727,10 @@ int main(int argc, char **argv) boot_globs[1] = htonl(RAMSize); boot_globs[2] = htonl((uint32)-1); // End of bank table + // Init thunks + if (!ThunksInit()) + goto quit; + // Init drivers SonyInit(); DiskInit(); @@ -588,6 +740,9 @@ int main(int argc, char **argv) // Init external file system ExtFSInit(); + // Init ADB + ADBInit(); + // Init audio AudioInit(); @@ -622,16 +777,17 @@ int main(int argc, char **argv) // Initialize Kernel Data memset(kernel_data, 0, sizeof(KernelData)); if (ROMType == ROMTYPE_NEWWORLD) { - static uint32 of_dev_tree[4] = {0, 0, 0, 0}; - static uint8 vector_lookup_tbl[128]; - static uint8 vector_mask_tbl[64]; + uintptr of_dev_tree = SheepMem::Reserve(4 * sizeof(uint32)); + memset((void *)of_dev_tree, 0, 4 * sizeof(uint32)); + uintptr vector_lookup_tbl = SheepMem::Reserve(128); + uintptr vector_mask_tbl = SheepMem::Reserve(64); memset((uint8 *)kernel_data + 0xb80, 0x3d, 0x80); - memset(vector_lookup_tbl, 0, 128); - memset(vector_mask_tbl, 0, 64); + memset((void *)vector_lookup_tbl, 0, 128); + memset((void *)vector_mask_tbl, 0, 64); kernel_data->v[0xb80 >> 2] = htonl(ROM_BASE); - kernel_data->v[0xb84 >> 2] = htonl((uint32)of_dev_tree); // OF device tree base - kernel_data->v[0xb90 >> 2] = htonl((uint32)vector_lookup_tbl); - kernel_data->v[0xb94 >> 2] = htonl((uint32)vector_mask_tbl); + kernel_data->v[0xb84 >> 2] = htonl(of_dev_tree); // OF device tree base + kernel_data->v[0xb90 >> 2] = htonl(vector_lookup_tbl); + kernel_data->v[0xb94 >> 2] = htonl(vector_mask_tbl); kernel_data->v[0xb98 >> 2] = htonl(ROM_BASE); // OpenPIC base kernel_data->v[0xbb0 >> 2] = htonl(0); // ADB base kernel_data->v[0xc20 >> 2] = htonl(RAMSize); @@ -644,9 +800,9 @@ int main(int argc, char **argv) kernel_data->v[0xc50 >> 2] = htonl(RAMBase); kernel_data->v[0xc54 >> 2] = htonl(RAMSize); kernel_data->v[0xf60 >> 2] = htonl(PVR); - kernel_data->v[0xf64 >> 2] = htonl(CPUClockSpeed); - kernel_data->v[0xf68 >> 2] = htonl(BusClockSpeed); - kernel_data->v[0xf6c >> 2] = htonl(CPUClockSpeed); + kernel_data->v[0xf64 >> 2] = htonl(CPUClockSpeed); // clock-frequency + kernel_data->v[0xf68 >> 2] = htonl(BusClockSpeed); // bus-frequency + kernel_data->v[0xf6c >> 2] = htonl(BusClockSpeed / 4); // timebase-frequency } else { kernel_data->v[0xc80 >> 2] = htonl(RAMSize); kernel_data->v[0xc84 >> 2] = htonl(RAMSize); @@ -658,37 +814,30 @@ int main(int argc, char **argv) kernel_data->v[0xcb0 >> 2] = htonl(RAMBase); kernel_data->v[0xcb4 >> 2] = htonl(RAMSize); kernel_data->v[0xf80 >> 2] = htonl(PVR); - kernel_data->v[0xf84 >> 2] = htonl(CPUClockSpeed); - kernel_data->v[0xf88 >> 2] = htonl(BusClockSpeed); - kernel_data->v[0xf8c >> 2] = htonl(CPUClockSpeed); + kernel_data->v[0xf84 >> 2] = htonl(CPUClockSpeed); // clock-frequency + kernel_data->v[0xf88 >> 2] = htonl(BusClockSpeed); // bus-frequency + kernel_data->v[0xf8c >> 2] = htonl(BusClockSpeed / 4); // timebase-frequency } // Initialize extra low memory D(bug("Initializing Low Memory...\n")); memset(NULL, 0, 0x3000); WriteMacInt32(XLM_SIGNATURE, FOURCC('B','a','a','h')); // Signature to detect SheepShaver - WriteMacInt32(XLM_KERNEL_DATA, (uint32)kernel_data); // For trap replacement routines + WriteMacInt32(XLM_KERNEL_DATA, KernelDataAddr); // For trap replacement routines WriteMacInt32(XLM_PVR, PVR); // Theoretical PVR WriteMacInt32(XLM_BUS_CLOCK, BusClockSpeed); // For DriverServicesLib patch WriteMacInt16(XLM_EXEC_RETURN_OPCODE, M68K_EXEC_RETURN); // For Execute68k() (RTS from the executed 68k code will jump here and end 68k mode) -#if EMULATED_PPC - WriteMacInt32(XLM_ETHER_INIT, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_INIT)); - WriteMacInt32(XLM_ETHER_TERM, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_TERM)); - WriteMacInt32(XLM_ETHER_OPEN, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_OPEN)); - WriteMacInt32(XLM_ETHER_CLOSE, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_CLOSE)); - WriteMacInt32(XLM_ETHER_WPUT, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_WPUT)); - WriteMacInt32(XLM_ETHER_RSRV, POWERPC_NATIVE_OP_FUNC(NATIVE_ETHER_RSRV)); - WriteMacInt32(XLM_VIDEO_DOIO, POWERPC_NATIVE_OP_FUNC(NATIVE_VIDEO_DO_DRIVER_IO)); -#else - WriteMacInt32(XLM_TOC, (uint32)TOC); // TOC pointer of emulator - WriteMacInt32(XLM_ETHER_INIT, (uint32)InitStreamModule); // DLPI ethernet driver functions - WriteMacInt32(XLM_ETHER_TERM, (uint32)TerminateStreamModule); - WriteMacInt32(XLM_ETHER_OPEN, (uint32)ether_open); - WriteMacInt32(XLM_ETHER_CLOSE, (uint32)ether_close); - WriteMacInt32(XLM_ETHER_WPUT, (uint32)ether_wput); - WriteMacInt32(XLM_ETHER_RSRV, (uint32)ether_rsrv); - WriteMacInt32(XLM_VIDEO_DOIO, (uint32)VideoDoDriverIO); + WriteMacInt32(XLM_ZERO_PAGE, SheepMem::ZeroPage()); // Pointer to read-only page with all bits set to 0 +#if !EMULATED_PPC + WriteMacInt32(XLM_TOC, (uint32)TOC); // TOC pointer of emulator #endif + WriteMacInt32(XLM_ETHER_INIT, NativeFunction(NATIVE_ETHER_INIT)); // DLPI ethernet driver functions + WriteMacInt32(XLM_ETHER_TERM, NativeFunction(NATIVE_ETHER_TERM)); + WriteMacInt32(XLM_ETHER_OPEN, NativeFunction(NATIVE_ETHER_OPEN)); + WriteMacInt32(XLM_ETHER_CLOSE, NativeFunction(NATIVE_ETHER_CLOSE)); + WriteMacInt32(XLM_ETHER_WPUT, NativeFunction(NATIVE_ETHER_WPUT)); + WriteMacInt32(XLM_ETHER_RSRV, NativeFunction(NATIVE_ETHER_RSRV)); + WriteMacInt32(XLM_VIDEO_DOIO, NativeFunction(NATIVE_VIDEO_DO_DRIVER_IO)); D(bug("Low Memory initialized\n")); // Start 60Hz thread @@ -702,23 +851,19 @@ int main(int argc, char **argv) #if !EMULATED_PPC // Create and install stacks for signal handlers - sig_stack = malloc(SIG_STACK_SIZE); - D(bug("Signal stack at %p\n", sig_stack)); - if (sig_stack == NULL) { - ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); - goto quit; - } - extra_stack = malloc(SIG_STACK_SIZE); - D(bug("Extra stack at %p\n", extra_stack)); - if (extra_stack == NULL) { - ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); - goto quit; + for (int i = 0; i < SIG_STACK_COUNT; i++) { + void *sig_stack = malloc(SIG_STACK_SIZE); + D(bug("Signal stack %d at %p\n", i, sig_stack)); + if (sig_stack == NULL) { + ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); + goto quit; + } + sig_stacks[i].ss_sp = sig_stack; + sig_stacks[i].ss_flags = 0; + sig_stacks[i].ss_size = SIG_STACK_SIZE; } - struct sigaltstack new_stack; - new_stack.ss_sp = sig_stack; - new_stack.ss_flags = 0; - new_stack.ss_size = SIG_STACK_SIZE; - if (sigaltstack(&new_stack, NULL) < 0) { + sig_stack_id = 0; + if (sigaltstack(&sig_stacks[0], NULL) < 0) { sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno)); ErrorAlert(str); goto quit; @@ -726,24 +871,33 @@ int main(int argc, char **argv) #endif #if !EMULATED_PPC - // Install SIGSEGV handler + // Install SIGSEGV and SIGBUS handlers sigemptyset(&sigsegv_action.sa_mask); // Block interrupts during SEGV handling sigaddset(&sigsegv_action.sa_mask, SIGUSR2); - sigsegv_action.sa_handler = (__sighandler_t)sigsegv_handler; - sigsegv_action.sa_flags = SA_ONSTACK; + sigsegv_action.sa_sigaction = sigsegv_handler; + sigsegv_action.sa_flags = SA_ONSTACK | SA_SIGINFO; +#ifdef HAVE_SIGNAL_SA_RESTORER sigsegv_action.sa_restorer = NULL; +#endif if (sigaction(SIGSEGV, &sigsegv_action, NULL) < 0) { sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno)); ErrorAlert(str); goto quit; } + if (sigaction(SIGBUS, &sigsegv_action, NULL) < 0) { + sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno)); + ErrorAlert(str); + goto quit; + } // Install SIGILL handler sigemptyset(&sigill_action.sa_mask); // Block interrupts during ILL handling sigaddset(&sigill_action.sa_mask, SIGUSR2); - sigill_action.sa_handler = (__sighandler_t)sigill_handler; - sigill_action.sa_flags = SA_ONSTACK; + sigill_action.sa_sigaction = sigill_handler; + sigill_action.sa_flags = SA_ONSTACK | SA_SIGINFO; +#ifdef HAVE_SIGNAL_SA_RESTORER sigill_action.sa_restorer = NULL; +#endif if (sigaction(SIGILL, &sigill_action, NULL) < 0) { sprintf(str, GetString(STR_SIGILL_INSTALL_ERR), strerror(errno)); ErrorAlert(str); @@ -751,19 +905,20 @@ int main(int argc, char **argv) } #endif +#if !EMULATED_PPC // Install interrupt signal handler sigemptyset(&sigusr2_action.sa_mask); - sigusr2_action.sa_handler = (__sighandler_t)sigusr2_handler; - sigusr2_action.sa_flags = 0; -#if !EMULATED_PPC - sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART; -#endif + sigusr2_action.sa_sigaction = sigusr2_handler; + sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO; +#ifdef HAVE_SIGNAL_SA_RESTORER sigusr2_action.sa_restorer = NULL; +#endif if (sigaction(SIGUSR2, &sigusr2_action, NULL) < 0) { sprintf(str, GetString(STR_SIGUSR2_INSTALL_ERR), strerror(errno)); ErrorAlert(str); goto quit; } +#endif // Get my thread ID and execute MacOS thread function emul_thread = pthread_self(); @@ -800,17 +955,25 @@ static void Quit(void) } #if !EMULATED_PPC - // Uninstall SIGSEGV handler + // Uninstall SIGSEGV and SIGBUS handlers sigemptyset(&sigsegv_action.sa_mask); sigsegv_action.sa_handler = SIG_DFL; sigsegv_action.sa_flags = 0; sigaction(SIGSEGV, &sigsegv_action, NULL); + sigaction(SIGBUS, &sigsegv_action, NULL); // Uninstall SIGILL handler sigemptyset(&sigill_action.sa_mask); sigill_action.sa_handler = SIG_DFL; sigill_action.sa_flags = 0; sigaction(SIGILL, &sigill_action, NULL); + + // Delete stacks for signal handlers + for (int i = 0; i < SIG_STACK_COUNT; i++) { + void *sig_stack = sig_stacks[i].ss_sp; + if (sig_stack) + free(sig_stack); + } #endif // Save NVRAM @@ -831,6 +994,9 @@ static void Quit(void) // Exit audio AudioExit(); + // Exit ADB + ADBExit(); + // Exit video VideoExit(); @@ -843,6 +1009,12 @@ static void Quit(void) DiskExit(); SonyExit(); + // Delete thunks + ThunksExit(); + + // Delete SheepShaver globals + SheepMem::Exit(); + // Delete RAM area if (ram_area_mapped) vm_release((char *)RAM_BASE, RAMSize); @@ -954,19 +1126,6 @@ void Execute68kTrap(uint16 trap, M68kReg uint16 proc[2] = {trap, M68K_RTS}; Execute68k((uint32)proc, r); } - - -/* - * Execute PPC code from EMUL_OP routine (real mode switch) - */ - -void ExecutePPC(void (*func)()) -{ - uint32 tvect[2] = {(uint32)func, 0}; // Fake TVECT - RoutineDescriptor desc = BUILD_PPC_ROUTINE_DESCRIPTOR(0, tvect); - M68kRegisters r; - Execute68k((uint32)&desc, &r); -} #endif @@ -1045,11 +1204,7 @@ void MakeExecutable(int dummy, void *sta void PatchAfterStartup(void) { -#if EMULATED_PPC ExecuteNative(NATIVE_VIDEO_INSTALL_ACCEL); -#else - ExecutePPC(VideoInstallAccel); -#endif InstallExtFS(); } @@ -1094,9 +1249,11 @@ static void *tick_func(void *arg) if (emul_thread_fatal) { // Yes, dump registers - pt_regs *r = (pt_regs *)&sigsegv_regs; + sigregs *r = &sigsegv_regs; char str[256]; - sprintf(str, "SIGSEGV\n" + if (crash_reason == NULL) + crash_reason = "SIGSEGV"; + sprintf(str, "%s\n" " pc %08lx lr %08lx ctr %08lx msr %08lx\n" " xer %08lx cr %08lx \n" " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n" @@ -1107,6 +1264,7 @@ static void *tick_func(void *arg) " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n" " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n" " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n", + crash_reason, r->nip, r->link, r->ctr, r->msr, r->xer, r->ccr, r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3], @@ -1152,7 +1310,30 @@ static void *tick_func(void *arg) void Set_pthread_attr(pthread_attr_t *attr, int priority) { - // nothing to do +#ifdef HAVE_PTHREADS + pthread_attr_init(attr); +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + // Some of these only work for superuser + if (geteuid() == 0) { + pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_setschedpolicy(attr, SCHED_FIFO); + struct sched_param fifo_param; + fifo_param.sched_priority = ((sched_get_priority_min(SCHED_FIFO) + + sched_get_priority_max(SCHED_FIFO)) / 2 + + priority); + pthread_attr_setschedparam(attr, &fifo_param); + } + if (pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM) != 0) { +#ifdef PTHREAD_SCOPE_BOUND_NP + // If system scope is not available (eg. we're not running + // with CAP_SCHED_MGT capability on an SGI box), try bound + // scope. It exposes pthread scheduling to the kernel, + // without setting realtime priority. + pthread_attr_setscope(attr, PTHREAD_SCOPE_BOUND_NP); +#endif + } +#endif +#endif } @@ -1239,7 +1420,7 @@ void B2_delete_mutex(B2_mutex *mutex) * Trigger signal USR2 from another thread */ -#if !EMULATED_PPC || ASYNC_IRQ +#if !EMULATED_PPC void TriggerInterrupt(void) { if (ready_for_signals) @@ -1289,18 +1470,10 @@ void EnableInterrupt(void) * USR2 handler */ -#if EMULATED_PPC -static void sigusr2_handler(int sig) -{ -#if ASYNC_IRQ - extern void HandleInterrupt(void); - HandleInterrupt(); -#endif -} -#else -static void sigusr2_handler(int sig, sigcontext_struct *sc) +#if !EMULATED_PPC +static void sigusr2_handler(int sig, siginfo_t *sip, void *scp) { - pt_regs *r = sc->regs; + machine_regs *r = MACHINE_REGISTERS(scp); // Do nothing if interrupts are disabled if (*(int32 *)XLM_IRQ_NEST > 0) @@ -1314,23 +1487,30 @@ static void sigusr2_handler(int sig, sig case MODE_68K: // 68k emulator active, trigger 68k interrupt level 1 WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1); - r->ccr |= ntohl(kernel_data->v[0x674 >> 2]); + r->cr() |= ntohl(kernel_data->v[0x674 >> 2]); break; #if INTERRUPTS_IN_NATIVE_MODE case MODE_NATIVE: // 68k emulator inactive, in nanokernel? - if (r->gpr[1] != KernelDataAddr) { + if (r->gpr(1) != KernelDataAddr) { + + // Set extra stack for nested interrupts + sig_stack_acquire(); + // Prepare for 68k interrupt level 1 WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1); WriteMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc, ReadMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc) | ntohl(kernel_data->v[0x674 >> 2])); // Execute nanokernel interrupt routine (this will activate the 68k emulator) - atomic_add((int32 *)XLM_IRQ_NEST, 1); + DisableInterrupt(); if (ROMType == ROMTYPE_NEWWORLD) ppc_interrupt(ROM_BASE + 0x312b1c, KernelDataAddr); else ppc_interrupt(ROM_BASE + 0x312a3c, KernelDataAddr); + + // Reset normal signal stack + sig_stack_release(); } break; #endif @@ -1341,11 +1521,7 @@ static void sigusr2_handler(int sig, sig if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) { // Set extra stack for SIGSEGV handler - struct sigaltstack new_stack; - new_stack.ss_sp = extra_stack; - new_stack.ss_flags = 0; - new_stack.ss_size = SIG_STACK_SIZE; - sigaltstack(&new_stack, NULL); + sig_stack_acquire(); #if 1 // Execute full 68k interrupt routine M68kRegisters r; @@ -1367,15 +1543,12 @@ static void sigusr2_handler(int sig, sig if (InterruptFlags & INTFLAG_VIA) { ClearInterruptFlag(INTFLAG_VIA); ADBInterrupt(); - ExecutePPC(VideoVBL); + ExecuteNative(NATIVE_VIDEO_VBL); } } #endif // Reset normal signal stack - new_stack.ss_sp = sig_stack; - new_stack.ss_flags = 0; - new_stack.ss_size = SIG_STACK_SIZE; - sigaltstack(&new_stack, NULL); + sig_stack_release(); } break; #endif @@ -1389,55 +1562,55 @@ static void sigusr2_handler(int sig, sig */ #if !EMULATED_PPC -static void sigsegv_handler(int sig, sigcontext_struct *sc) +static void sigsegv_handler(int sig, siginfo_t *sip, void *scp) { - pt_regs *r = sc->regs; + machine_regs *r = MACHINE_REGISTERS(scp); // Get effective address - uint32 addr = r->dar; + uint32 addr = r->dar(); #if ENABLE_VOSF // Handle screen fault. extern bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction); - if (Screen_fault_handler((sigsegv_address_t)addr, (sigsegv_address_t)r->nip)) + if (Screen_fault_handler((sigsegv_address_t)addr, (sigsegv_address_t)r->pc())) return; #endif num_segv++; // Fault in Mac ROM or RAM? - bool mac_fault = (r->nip >= ROM_BASE) && (r->nip < (ROM_BASE + ROM_AREA_SIZE)) || (r->nip >= RAMBase) && (r->nip < (RAMBase + RAMSize)); + bool mac_fault = (r->pc() >= ROM_BASE) && (r->pc() < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc() >= RAMBase) && (r->pc() < (RAMBase + RAMSize)); if (mac_fault) { // "VM settings" during MacOS 8 installation - if (r->nip == ROM_BASE + 0x488160 && r->gpr[20] == 0xf8000000) { - r->nip += 4; - r->gpr[8] = 0; + if (r->pc() == ROM_BASE + 0x488160 && r->gpr(20) == 0xf8000000) { + r->pc() += 4; + r->gpr(8) = 0; return; // MacOS 8.5 installation - } else if (r->nip == ROM_BASE + 0x488140 && r->gpr[16] == 0xf8000000) { - r->nip += 4; - r->gpr[8] = 0; + } else if (r->pc() == ROM_BASE + 0x488140 && r->gpr(16) == 0xf8000000) { + r->pc() += 4; + r->gpr(8) = 0; return; // MacOS 8 serial drivers on startup - } else if (r->nip == ROM_BASE + 0x48e080 && (r->gpr[8] == 0xf3012002 || r->gpr[8] == 0xf3012000)) { - r->nip += 4; - r->gpr[8] = 0; + } else if (r->pc() == ROM_BASE + 0x48e080 && (r->gpr(8) == 0xf3012002 || r->gpr(8) == 0xf3012000)) { + r->pc() += 4; + r->gpr(8) = 0; return; // MacOS 8.1 serial drivers on startup - } else if (r->nip == ROM_BASE + 0x48c5e0 && (r->gpr[20] == 0xf3012002 || r->gpr[20] == 0xf3012000)) { - r->nip += 4; + } else if (r->pc() == ROM_BASE + 0x48c5e0 && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) { + r->pc() += 4; return; - } else if (r->nip == ROM_BASE + 0x4a10a0 && (r->gpr[20] == 0xf3012002 || r->gpr[20] == 0xf3012000)) { - r->nip += 4; + } else if (r->pc() == ROM_BASE + 0x4a10a0 && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) { + r->pc() += 4; return; } // Get opcode and divide into fields - uint32 opcode = *((uint32 *)r->nip); + uint32 opcode = *((uint32 *)r->pc()); uint32 primop = opcode >> 26; uint32 exop = (opcode >> 1) & 0x3ff; uint32 ra = (opcode >> 16) & 0x1f; @@ -1526,24 +1699,52 @@ static void sigsegv_handler(int sig, sig transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break; case 45: // sthu transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break; +#if EMULATE_UNALIGNED_LOADSTORE_MULTIPLE + case 46: // lmw + if ((addr % 4) != 0) { + uint32 ea = addr; + D(bug("WARNING: unaligned lmw to EA=%08x from IP=%08x\n", ea, r->pc())); + for (int i = rd; i <= 31; i++) { + r->gpr(i) = ReadMacInt32(ea); + ea += 4; + } + r->pc() += 4; + goto rti; + } + break; + case 47: // stmw + if ((addr % 4) != 0) { + uint32 ea = addr; + D(bug("WARNING: unaligned stmw to EA=%08x from IP=%08x\n", ea, r->pc())); + for (int i = rd; i <= 31; i++) { + WriteMacInt32(ea, r->gpr(i)); + ea += 4; + } + r->pc() += 4; + goto rti; + } + break; +#endif } - // Ignore ROM writes - if (transfer_type == TYPE_STORE && addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) { -// D(bug("WARNING: %s write access to ROM at %08lx, pc %08lx\n", transfer_size == SIZE_BYTE ? "Byte" : transfer_size == SIZE_HALFWORD ? "Halfword" : "Word", addr, r->nip)); + // Ignore ROM writes (including to the zero page, which is read-only) + if (transfer_type == TYPE_STORE && + ((addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) || + (addr >= SheepMem::ZeroPage() && addr < SheepMem::ZeroPage() + SheepMem::PageSize()))) { +// D(bug("WARNING: %s write access to ROM at %08lx, pc %08lx\n", transfer_size == SIZE_BYTE ? "Byte" : transfer_size == SIZE_HALFWORD ? "Halfword" : "Word", addr, r->pc())); if (addr_mode == MODE_U || addr_mode == MODE_UX) - r->gpr[ra] = addr; - r->nip += 4; + r->gpr(ra) = addr; + r->pc() += 4; goto rti; } // Ignore illegal memory accesses? if (PrefsFindBool("ignoresegv")) { if (addr_mode == MODE_U || addr_mode == MODE_UX) - r->gpr[ra] = addr; + r->gpr(ra) = addr; if (transfer_type == TYPE_LOAD) - r->gpr[rd] = 0; - r->nip += 4; + r->gpr(rd) = 0; + r->pc() += 4; goto rti; } @@ -1551,9 +1752,9 @@ static void sigsegv_handler(int sig, sig if (!PrefsFindBool("nogui")) { char str[256]; if (transfer_type == TYPE_LOAD || transfer_type == TYPE_STORE) - sprintf(str, GetString(STR_MEM_ACCESS_ERR), transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_HALFWORD ? "halfword" : "word", transfer_type == TYPE_LOAD ? GetString(STR_MEM_ACCESS_READ) : GetString(STR_MEM_ACCESS_WRITE), addr, r->nip, r->gpr[24], r->gpr[1]); + sprintf(str, GetString(STR_MEM_ACCESS_ERR), transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_HALFWORD ? "halfword" : "word", transfer_type == TYPE_LOAD ? GetString(STR_MEM_ACCESS_READ) : GetString(STR_MEM_ACCESS_WRITE), addr, r->pc(), r->gpr(24), r->gpr(1)); else - sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->nip, r->gpr[24], r->gpr[1], opcode); + sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc(), r->gpr(24), r->gpr(1), opcode); ErrorAlert(str); QuitEmulator(); return; @@ -1561,9 +1762,10 @@ static void sigsegv_handler(int sig, sig } // For all other errors, jump into debugger (sort of...) + crash_reason = (sig == SIGBUS) ? "SIGBUS" : "SIGSEGV"; if (!ready_for_signals) { - printf("SIGSEGV\n"); - printf(" sigcontext %p, pt_regs %p\n", sc, r); + printf("%s\n"); + printf(" sigcontext %p, machine_regs %p\n", scp, r); printf( " pc %08lx lr %08lx ctr %08lx msr %08lx\n" " xer %08lx cr %08lx \n" @@ -1575,22 +1777,23 @@ static void sigsegv_handler(int sig, sig " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n" " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n" " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n", - r->nip, r->link, r->ctr, r->msr, - r->xer, r->ccr, - r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3], - r->gpr[4], r->gpr[5], r->gpr[6], r->gpr[7], - r->gpr[8], r->gpr[9], r->gpr[10], r->gpr[11], - r->gpr[12], r->gpr[13], r->gpr[14], r->gpr[15], - r->gpr[16], r->gpr[17], r->gpr[18], r->gpr[19], - r->gpr[20], r->gpr[21], r->gpr[22], r->gpr[23], - r->gpr[24], r->gpr[25], r->gpr[26], r->gpr[27], - r->gpr[28], r->gpr[29], r->gpr[30], r->gpr[31]); + crash_reason, + r->pc(), r->lr(), r->ctr(), r->msr(), + r->xer(), r->cr(), + r->gpr(0), r->gpr(1), r->gpr(2), r->gpr(3), + r->gpr(4), r->gpr(5), r->gpr(6), r->gpr(7), + r->gpr(8), r->gpr(9), r->gpr(10), r->gpr(11), + r->gpr(12), r->gpr(13), r->gpr(14), r->gpr(15), + r->gpr(16), r->gpr(17), r->gpr(18), r->gpr(19), + r->gpr(20), r->gpr(21), r->gpr(22), r->gpr(23), + r->gpr(24), r->gpr(25), r->gpr(26), r->gpr(27), + r->gpr(28), r->gpr(29), r->gpr(30), r->gpr(31)); exit(1); QuitEmulator(); return; } else { // We crashed. Save registers, tell tick thread and loop forever - sigsegv_regs = *(sigregs *)r; + build_sigregs(&sigsegv_regs, r); emul_thread_fatal = true; for (;;) ; } @@ -1602,17 +1805,17 @@ rti:; * SIGILL handler */ -static void sigill_handler(int sig, sigcontext_struct *sc) +static void sigill_handler(int sig, siginfo_t *sip, void *scp) { - pt_regs *r = sc->regs; + machine_regs *r = MACHINE_REGISTERS(scp); char str[256]; // Fault in Mac ROM or RAM? - bool mac_fault = (r->nip >= ROM_BASE) && (r->nip < (ROM_BASE + ROM_AREA_SIZE)) || (r->nip >= RAMBase) && (r->nip < (RAMBase + RAMSize)); + bool mac_fault = (r->pc() >= ROM_BASE) && (r->pc() < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc() >= RAMBase) && (r->pc() < (RAMBase + RAMSize)); if (mac_fault) { // Get opcode and divide into fields - uint32 opcode = *((uint32 *)r->nip); + uint32 opcode = *((uint32 *)r->pc()); uint32 primop = opcode >> 26; uint32 exop = (opcode >> 1) & 0x3ff; uint32 ra = (opcode >> 16) & 0x1f; @@ -1623,7 +1826,7 @@ static void sigill_handler(int sig, sigc switch (primop) { case 9: // POWER instructions case 22: -power_inst: sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->nip, r->gpr[1], opcode); +power_inst: sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->pc(), r->gpr(1), opcode); ErrorAlert(str); QuitEmulator(); return; @@ -1631,14 +1834,14 @@ power_inst: sprintf(str, GetString(STR_ case 31: switch (exop) { case 83: // mfmsr - r->gpr[rd] = 0xf072; - r->nip += 4; + r->gpr(rd) = 0xf072; + r->pc() += 4; goto rti; case 210: // mtsr case 242: // mtsrin case 306: // tlbie - r->nip += 4; + r->pc() += 4; goto rti; case 339: { // mfspr @@ -1654,15 +1857,15 @@ power_inst: sprintf(str, GetString(STR_ case 957: // PMC3 case 958: // PMC4 case 959: // SDA - r->nip += 4; + r->pc() += 4; goto rti; case 25: // SDR1 - r->gpr[rd] = 0xdead001f; - r->nip += 4; + r->gpr(rd) = 0xdead001f; + r->pc() += 4; goto rti; case 287: // PVR - r->gpr[rd] = PVR; - r->nip += 4; + r->gpr(rd) = PVR; + r->pc() += 4; goto rti; } break; @@ -1698,7 +1901,7 @@ power_inst: sprintf(str, GetString(STR_ case 957: // PMC3 case 958: // PMC4 case 959: // SDA - r->nip += 4; + r->pc() += 4; goto rti; } break; @@ -1717,7 +1920,7 @@ power_inst: sprintf(str, GetString(STR_ // In GUI mode, show error alert if (!PrefsFindBool("nogui")) { - sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->nip, r->gpr[24], r->gpr[1], opcode); + sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc(), r->gpr(24), r->gpr(1), opcode); ErrorAlert(str); QuitEmulator(); return; @@ -1725,9 +1928,10 @@ power_inst: sprintf(str, GetString(STR_ } // For all other errors, jump into debugger (sort of...) + crash_reason = "SIGILL"; if (!ready_for_signals) { - printf("SIGILL\n"); - printf(" sigcontext %p, pt_regs %p\n", sc, r); + printf("%s\n"); + printf(" sigcontext %p, machine_regs %p\n", scp, r); printf( " pc %08lx lr %08lx ctr %08lx msr %08lx\n" " xer %08lx cr %08lx \n" @@ -1739,22 +1943,23 @@ power_inst: sprintf(str, GetString(STR_ " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n" " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n" " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n", - r->nip, r->link, r->ctr, r->msr, - r->xer, r->ccr, - r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3], - r->gpr[4], r->gpr[5], r->gpr[6], r->gpr[7], - r->gpr[8], r->gpr[9], r->gpr[10], r->gpr[11], - r->gpr[12], r->gpr[13], r->gpr[14], r->gpr[15], - r->gpr[16], r->gpr[17], r->gpr[18], r->gpr[19], - r->gpr[20], r->gpr[21], r->gpr[22], r->gpr[23], - r->gpr[24], r->gpr[25], r->gpr[26], r->gpr[27], - r->gpr[28], r->gpr[29], r->gpr[30], r->gpr[31]); + crash_reason, + r->pc(), r->lr(), r->ctr(), r->msr(), + r->xer(), r->cr(), + r->gpr(0), r->gpr(1), r->gpr(2), r->gpr(3), + r->gpr(4), r->gpr(5), r->gpr(6), r->gpr(7), + r->gpr(8), r->gpr(9), r->gpr(10), r->gpr(11), + r->gpr(12), r->gpr(13), r->gpr(14), r->gpr(15), + r->gpr(16), r->gpr(17), r->gpr(18), r->gpr(19), + r->gpr(20), r->gpr(21), r->gpr(22), r->gpr(23), + r->gpr(24), r->gpr(25), r->gpr(26), r->gpr(27), + r->gpr(28), r->gpr(29), r->gpr(30), r->gpr(31)); exit(1); QuitEmulator(); return; } else { // We crashed. Save registers, tell tick thread and loop forever - sigsegv_regs = *(sigregs *)r; + build_sigregs(&sigsegv_regs, r); emul_thread_fatal = true; for (;;) ; } @@ -1764,6 +1969,55 @@ rti:; /* + * Helpers to share 32-bit addressable data with MacOS + */ + +bool SheepMem::Init(void) +{ + // Size of a native page + page_size = getpagesize(); + + // Allocate SheepShaver globals + if (vm_acquire_fixed((char *)base, size) < 0) + return false; + + // Allocate page with all bits set to 0 + zero_page = base + size; + if (vm_acquire_fixed((char *)zero_page, page_size) < 0) + return false; + memset((char *)zero_page, 0, page_size); + if (vm_protect((char *)zero_page, page_size, VM_PAGE_READ) < 0) + return false; + +#if EMULATED_PPC + // Allocate alternate stack for PowerPC interrupt routine + sig_stack = zero_page + page_size; + if (vm_acquire_fixed((char *)sig_stack, SIG_STACK_SIZE) < 0) + return false; +#endif + + top = base + size; + return true; +} + +void SheepMem::Exit(void) +{ + if (top) { + // Delete SheepShaver globals + vm_release((void *)base, size); + + // Delete zero page + vm_release((void *)zero_page, page_size); + +#if EMULATED_PPC + // Delete alternate stack for PowerPC interrupt routine + vm_release((void *)sig_stack, SIG_STACK_SIZE); +#endif + } +} + + +/* * Display alert */