--- SheepShaver/src/Unix/main_unix.cpp 2005/03/28 09:50:58 1.62 +++ SheepShaver/src/Unix/main_unix.cpp 2011/12/30 17:38:39 1.98 @@ -1,7 +1,7 @@ /* * main_unix.cpp - Emulation core, Unix implementation * - * SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig + * SheepShaver (C) 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 @@ -67,17 +67,12 @@ * 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? + * Note that POSIX standard says you can't modify the alternate + * signal stack while the process is executing on it. There is a + * hackaround though: we install a trampoline SIGUSR2 handler that + * sets up an alternate stack itself and calls the real handler. + * Then, when we call sigaltstack() there, we no longer get an EPERM, + * i.e. it now works. * * TODO: * check if SIGSEGV handler works for all registers (including FP!) @@ -94,6 +89,7 @@ #include #include #include +#include #include #include "sysdeps.h" @@ -114,6 +110,8 @@ #include "user_strings.h" #include "vm_alloc.h" #include "sigsegv.h" +#include "sigregs.h" +#include "rpc.h" #define DEBUG 0 #include "debug.h" @@ -138,7 +136,7 @@ #ifdef ENABLE_XF86_DGA #include #include -#include +#include #endif #ifdef ENABLE_MON @@ -158,139 +156,30 @@ // 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"; -#if REAL_ADDRESSING -const uintptr RAM_BASE = 0x20000000; // Base address of RAM -#else +#if !REAL_ADDRESSING // FIXME: needs to be >= 0x04000000 const uintptr RAM_BASE = 0x10000000; // Base address of RAM #endif -const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack - - -#if !EMULATED_PPC -struct sigregs { - 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(__NetBSD__) -#include -#define MACHINE_REGISTERS(scp) ((machine_regs *)&(((ucontext_t *)scp)->uc_mcontext)) - -struct machine_regs : public mcontext_t -{ - long & cr() { return __gregs[_REG_CR]; } - uint32 cr() const { return __gregs[_REG_CR]; } - uint32 lr() const { return __gregs[_REG_LR]; } - uint32 ctr() const { return __gregs[_REG_CTR]; } - uint32 xer() const { return __gregs[_REG_XER]; } - uint32 msr() const { return __gregs[_REG_MSR]; } - uint32 dar() const { return (uint32)(((siginfo_t *)(((unsigned long)this) - offsetof(ucontext_t, uc_mcontext))) - 1)->si_addr; } /* HACK */ - long & pc() { return __gregs[_REG_PC]; } - uint32 pc() const { return __gregs[_REG_PC]; } - long & gpr(int i) { return __gregs[_REG_R0 + i]; } - uint32 gpr(int i) const { return __gregs[_REG_R0 + 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 int sig_stack_acquire(void) -{ - if (sig_stack_id >= SIG_STACK_COUNT) { - printf("FATAL: signal stack overflow\n"); - return -1; - } - return sigaltstack(&sig_stacks[sig_stack_id++], NULL); -} - -static inline int sig_stack_release(void) -{ - if (sig_stack_id <= 0) { - printf("FATAL: signal stack underflow\n"); - return -1; - } - return sigaltstack(&sig_stacks[--sig_stack_id], NULL); -} +const uintptr ROM_BASE = 0x40800000; // Base address of ROM +#if REAL_ADDRESSING +const uint32 ROM_ALIGNMENT = 0x100000; // ROM must be aligned to a 1MB boundary #endif +const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack // Global variables (exported) #if !EMULATED_PPC -void *TOC; // Pointer to Thread Local Storage (r2) -void *R13; // Pointer to .sdata section (r13 under Linux) +void *TOC = NULL; // Pointer to Thread Local Storage (r2) +void *R13 = NULL; // Pointer to .sdata section (r13 under Linux) #endif uint32 RAMBase; // Base address of Mac RAM uint32 RAMSize; // Size of Mac RAM +uint32 ROMBase; // Base address of Mac ROM uint32 KernelDataAddr; // Address of Kernel Data uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM uint32 DRCacheAddr; // Address of DR Cache @@ -340,11 +229,16 @@ static uintptr sig_stack = 0; // Stac #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 stack_t sig_stack; // Stack for signal handlers +static stack_t extra_stack; // 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 +static rpc_connection_t *gui_connection = NULL; // RPC connection to the GUI +static const char *gui_connection_path = NULL; // GUI connection identifier + 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 @@ -363,9 +257,10 @@ static void *tick_func(void *arg); extern void emul_ppc(uint32 start); extern void init_emul_ppc(void); extern void exit_emul_ppc(void); -sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t); +sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip); #else -static void sigusr2_handler(int sig, siginfo_t *sip, void *scp); +extern "C" void sigusr2_handler_init(int sig, siginfo_t *sip, void *scp); +extern "C" 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 @@ -445,7 +340,12 @@ int atomic_or(int *var, int v) * Memory management helpers */ -static inline int vm_mac_acquire(uint32 addr, uint32 size) +static inline uint8 *vm_mac_acquire(uint32 size) +{ + return (uint8 *)vm_acquire(size); +} + +static inline int vm_mac_acquire_fixed(uint32 addr, uint32 size) { return vm_acquire_fixed(Mac2HostAddr(addr), size); } @@ -469,156 +369,32 @@ static void usage(const char *prg_name) exit(0); } -int main(int argc, char **argv) +static bool valid_vmdir(const char *path) { - char str[256]; - int rom_fd; - FILE *proc_file; - const char *rom_path; - uint32 rom_size, actual; - uint8 *rom_tmp; - time_t now, expire; - - // Initialize variables - RAMBase = 0; - tzset(); - - // Print some info - printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR); - printf(" %s\n", GetString(STR_ABOUT_TEXT2)); - -#if !EMULATED_PPC -#ifdef SYSTEM_CLOBBERS_R2 - // Get TOC pointer - TOC = get_r2(); -#endif -#ifdef SYSTEM_CLOBBERS_R13 - // Get r13 register - R13 = get_r13(); -#endif -#endif - -#ifdef ENABLE_GTK - // Init GTK - gtk_set_locale(); - gtk_init(&argc, &argv); -#endif - - // Read preferences - PrefsInit(argc, argv); - - // Parse command line arguments - for (int i=1; i suffix_len && !strncmp(path + len - suffix_len, ".sheepvm", suffix_len)) { + struct stat d; + if (!stat(path, &d) && S_ISDIR(d.st_mode)) { + return true; } } + return false; +} -#ifdef USE_SDL - // Initialize SDL system - int sdl_flags = 0; -#ifdef USE_SDL_VIDEO - sdl_flags |= SDL_INIT_VIDEO; -#endif -#ifdef USE_SDL_AUDIO - sdl_flags |= SDL_INIT_AUDIO; -#endif - assert(sdl_flags != 0); - if (SDL_Init(sdl_flags) == -1) { - char str[256]; - sprintf(str, "Could not initialize SDL: %s.\n", SDL_GetError()); - ErrorAlert(str); - goto quit; - } - atexit(SDL_Quit); -#endif - -#ifndef USE_SDL_VIDEO - // Open display - x_display = XOpenDisplay(x_display_name); - if (x_display == NULL) { - char str[256]; - sprintf(str, GetString(STR_NO_XSERVER_ERR), XDisplayName(x_display_name)); - ErrorAlert(str); - goto quit; - } - -#if defined(ENABLE_XF86_DGA) && !defined(ENABLE_MON) - // Fork out, so we can return from fullscreen mode when things get ugly - XF86DGAForkApp(DefaultScreen(x_display)); -#endif -#endif - -#ifdef ENABLE_MON - // Initialize mon - mon_init(); -#endif - -#if !EMULATED_PPC - // Create and install stacks for signal handlers - 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; - } - if (sig_stack_acquire() < 0) { - sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno)); - ErrorAlert(str); - goto quit; - } -#endif - +static void get_system_info(void) +{ #if !EMULATED_PPC - // Install SIGSEGV and SIGBUS handlers - sigemptyset(&sigsegv_action.sa_mask); // Block interrupts during SEGV handling - sigaddset(&sigsegv_action.sa_mask, SIGUSR2); - 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; - } -#else - // Install SIGSEGV handler for CPU emulator - if (!sigsegv_install_handler(sigsegv_handler)) { - sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno)); - ErrorAlert(str); - goto quit; - } + FILE *proc_file; #endif - // Initialize VM system - vm_init(); - - // Get system info PVR = 0x00040000; // Default: 604 CPUClockSpeed = 100000000; // Default: 100MHz BusClockSpeed = 100000000; // Default: 100MHz TimebaseSpeed = 25000000; // Default: 25MHz + #if EMULATED_PPC PVR = 0x000c0000; // Default: 7400 (with AltiVec) #elif defined(__APPLE__) && defined(__MACH__) @@ -653,6 +429,7 @@ int main(int argc, char **argv) } fclose(proc_file); } else { + char str[256]; sprintf(str, GetString(STR_PROC_CPUINFO_WARN), strerror(errno)); WarningAlert(str); } @@ -697,6 +474,7 @@ int main(int argc, char **argv) { 0xffff0000, 0x80010000, "7455" }, { 0xffff0000, 0x80020000, "7457" }, { 0xffff0000, 0x80030000, "7447A" }, + { 0xffff0000, 0x80040000, "7448" }, { 0x7fff0000, 0x00810000, "82xx" }, { 0x7fff0000, 0x00820000, "8280" }, { 0xffff0000, 0x00400000, "Power3 (630)" }, @@ -705,6 +483,13 @@ int main(int argc, char **argv) { 0xffff0000, 0x00370000, "S-star" }, { 0xffff0000, 0x00350000, "Power4" }, { 0xffff0000, 0x00390000, "PPC970" }, + { 0xffff0000, 0x003c0000, "PPC970FX" }, + { 0xffff0000, 0x00440000, "PPC970MP" }, + { 0xffff0000, 0x003a0000, "POWER5 (gr)" }, + { 0xffff0000, 0x003b0000, "POWER5+ (gs)" }, + { 0xffff0000, 0x003e0000, "POWER6" }, + { 0xffff0000, 0x00700000, "Cell Broadband Engine" }, + { 0x7fff0000, 0x00900000, "PA6T" }, { 0, 0, 0 } }; @@ -718,8 +503,9 @@ int main(int argc, char **argv) // Parse line int i; + float f; char value[256]; - if (sscanf(line, "cpu : %[0-9A-Za-a]", value) == 1) { + if (sscanf(line, "cpu : %[^,]", value) == 1) { // Search by name const char *cpu_name = NULL; for (int i = 0; cpu_specs[i].pvr_mask != 0; i++) { @@ -734,7 +520,9 @@ int main(int argc, char **argv) else printf("Found a PowerPC %s processor\n", cpu_name); } - if (sscanf(line, "clock : %dMHz", &i) == 1) + if (sscanf(line, "clock : %fMHz", &f) == 1) + CPUClockSpeed = BusClockSpeed = ((int64)f) * 1000000; + else if (sscanf(line, "clock : %dMHz", &i) == 1) CPUClockSpeed = BusClockSpeed = i * 1000000; } fclose(proc_file); @@ -773,16 +561,276 @@ int main(int argc, char **argv) closedir(cpus_dir); } #endif + // Remap any newer G4/G5 processor to plain G4 for compatibility switch (PVR >> 16) { case 0x8000: // 7450 case 0x8001: // 7455 case 0x8002: // 7457 + case 0x8003: // 7447A + case 0x8004: // 7448 case 0x0039: // 970 + case 0x003c: // 970FX + case 0x0044: // 970MP PVR = 0x000c0000; // 7400 break; } D(bug("PVR: %08x (assumed)\n", PVR)); +} + +static bool load_mac_rom(void) +{ + uint32 rom_size, actual; + uint8 *rom_tmp; + const char *rom_path = PrefsFindString("rom"); + int rom_fd = open(rom_path && *rom_path ? rom_path : ROM_FILE_NAME, O_RDONLY); + if (rom_fd < 0) { + rom_fd = open(ROM_FILE_NAME2, O_RDONLY); + if (rom_fd < 0) { + ErrorAlert(GetString(STR_NO_ROM_FILE_ERR)); + return false; + } + } + printf("%s", GetString(STR_READING_ROM_FILE)); + rom_size = lseek(rom_fd, 0, SEEK_END); + lseek(rom_fd, 0, SEEK_SET); + rom_tmp = new uint8[ROM_SIZE]; + actual = read(rom_fd, (void *)rom_tmp, ROM_SIZE); + close(rom_fd); + + // Decode Mac ROM + if (!DecodeROM(rom_tmp, actual)) { + if (rom_size != 4*1024*1024) { + ErrorAlert(GetString(STR_ROM_SIZE_ERR)); + return false; + } else { + ErrorAlert(GetString(STR_ROM_FILE_READ_ERR)); + return false; + } + } + delete[] rom_tmp; + return true; +} + +static bool install_signal_handlers(void) +{ + char str[256]; +#if !EMULATED_PPC + // Create and install stacks for signal handlers + sig_stack.ss_sp = malloc(SIG_STACK_SIZE); + D(bug("Signal stack at %p\n", sig_stack.ss_sp)); + if (sig_stack.ss_sp == NULL) { + ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); + return false; + } + sig_stack.ss_flags = 0; + sig_stack.ss_size = SIG_STACK_SIZE; + if (sigaltstack(&sig_stack, NULL) < 0) { + sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno)); + ErrorAlert(str); + return false; + } + extra_stack.ss_sp = malloc(SIG_STACK_SIZE); + D(bug("Extra stack at %p\n", extra_stack.ss_sp)); + if (extra_stack.ss_sp == NULL) { + ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); + return false; + } + extra_stack.ss_flags = 0; + extra_stack.ss_size = SIG_STACK_SIZE; + + // Install SIGSEGV and SIGBUS handlers + sigemptyset(&sigsegv_action.sa_mask); // Block interrupts during SEGV handling + sigaddset(&sigsegv_action.sa_mask, SIGUSR2); + 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_SIG_INSTALL_ERR), "SIGSEGV", strerror(errno)); + ErrorAlert(str); + return false; + } + if (sigaction(SIGBUS, &sigsegv_action, NULL) < 0) { + sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGBUS", strerror(errno)); + ErrorAlert(str); + return false; + } +#else + // Install SIGSEGV handler for CPU emulator + if (!sigsegv_install_handler(sigsegv_handler)) { + sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGSEGV", strerror(errno)); + ErrorAlert(str); + return false; + } +#endif + return true; +} + +static bool init_sdl() +{ + int sdl_flags = 0; +#ifdef USE_SDL_VIDEO + sdl_flags |= SDL_INIT_VIDEO; +#endif +#ifdef USE_SDL_AUDIO + sdl_flags |= SDL_INIT_AUDIO; +#endif + assert(sdl_flags != 0); + +#ifdef USE_SDL_VIDEO + // Don't let SDL block the screensaver + setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", TRUE); + + // Make SDL pass through command-clicks and option-clicks unaltered + setenv("SDL_HAS3BUTTONMOUSE", "1", TRUE); +#endif + + if (SDL_Init(sdl_flags) == -1) { + char str[256]; + sprintf(str, "Could not initialize SDL: %s.\n", SDL_GetError()); + ErrorAlert(str); + return false; + } + atexit(SDL_Quit); + + // Don't let SDL catch SIGINT and SIGTERM signals + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + return true; +} + +int main(int argc, char **argv) +{ + char str[256]; + bool memory_mapped_from_zero, ram_rom_areas_contiguous; + const char *vmdir = NULL; + + // Initialize variables + RAMBase = 0; + tzset(); + + // Print some info + printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR); + printf(" %s\n", GetString(STR_ABOUT_TEXT2)); + +#if !EMULATED_PPC +#ifdef SYSTEM_CLOBBERS_R2 + // Get TOC pointer + TOC = get_r2(); +#endif +#ifdef SYSTEM_CLOBBERS_R13 + // Get r13 register + R13 = get_r13(); +#endif +#endif + + // Parse command line arguments + for (int i=1; i i) { + k -= i; + for (int j=i+k; j ROM_BASE) { - ErrorAlert(GetString(STR_RAM_HIGHER_THAN_ROM_ERR)); + if (RAMBase > KernelDataAddr) { + ErrorAlert(GetString(STR_RAM_AREA_TOO_HIGH_ERR)); goto quit; } - - // Load Mac ROM - rom_path = PrefsFindString("rom"); - rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME, O_RDONLY); - if (rom_fd < 0) { - rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME2, O_RDONLY); - if (rom_fd < 0) { - ErrorAlert(GetString(STR_NO_ROM_FILE_ERR)); - goto quit; - } - } - printf(GetString(STR_READING_ROM_FILE)); - rom_size = lseek(rom_fd, 0, SEEK_END); - lseek(rom_fd, 0, SEEK_SET); - rom_tmp = new uint8[ROM_SIZE]; - actual = read(rom_fd, (void *)rom_tmp, ROM_SIZE); - close(rom_fd); - // Decode Mac ROM - if (!DecodeROM(rom_tmp, actual)) { - if (rom_size != 4*1024*1024) { - ErrorAlert(GetString(STR_ROM_SIZE_ERR)); - goto quit; - } else { - ErrorAlert(GetString(STR_ROM_FILE_READ_ERR)); + // Create area for Mac ROM + if (!ram_rom_areas_contiguous) { + if (vm_mac_acquire_fixed(ROM_BASE, ROM_AREA_SIZE) < 0) { + sprintf(str, GetString(STR_ROM_MMAP_ERR), strerror(errno)); + ErrorAlert(str); goto quit; } + ROMBase = ROM_BASE; + ROMBaseHost = Mac2HostAddr(ROMBase); } - delete[] rom_tmp; +#if !EMULATED_PPC + if (vm_protect(ROMBaseHost, ROM_AREA_SIZE, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE) < 0) { + sprintf(str, GetString(STR_ROM_MMAP_ERR), strerror(errno)); + ErrorAlert(str); + goto quit; + } +#endif + rom_area_mapped = true; + D(bug("ROM area at %p (%08x)\n", ROMBaseHost, ROMBase)); + + if (RAMBase > ROMBase) { + ErrorAlert(GetString(STR_RAM_HIGHER_THAN_ROM_ERR)); + goto quit; + } + + // Load Mac ROM + if (!load_mac_rom()) + goto quit; // Initialize everything - if (!InitAll()) + if (!InitAll(vmdir)) goto quit; D(bug("Initialization complete\n")); // Clear caches (as we loaded and patched code) and write protect ROM #if !EMULATED_PPC - flush_icache_range(ROM_BASE, ROM_BASE + ROM_AREA_SIZE); + flush_icache_range(ROMBase, ROMBase + ROM_AREA_SIZE); #endif vm_protect(ROMBaseHost, ROM_AREA_SIZE, VM_PAGE_READ | VM_PAGE_EXECUTE); @@ -961,7 +1017,7 @@ int main(int argc, char **argv) sigill_action.sa_restorer = NULL; #endif if (sigaction(SIGILL, &sigill_action, NULL) < 0) { - sprintf(str, GetString(STR_SIGILL_INSTALL_ERR), strerror(errno)); + sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGILL", strerror(errno)); ErrorAlert(str); goto quit; } @@ -970,13 +1026,13 @@ int main(int argc, char **argv) #if !EMULATED_PPC // Install interrupt signal handler sigemptyset(&sigusr2_action.sa_mask); - sigusr2_action.sa_sigaction = sigusr2_handler; + sigusr2_action.sa_sigaction = sigusr2_handler_init; 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)); + sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGUSR2", strerror(errno)); ErrorAlert(str); goto quit; } @@ -1033,11 +1089,10 @@ static void Quit(void) 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); - } + if (sig_stack.ss_sp) + free(sig_stack.ss_sp); + if (extra_stack.ss_sp) + free(extra_stack.ss_sp); #endif // Deinitialize everything @@ -1048,11 +1103,11 @@ static void Quit(void) // Delete RAM area if (ram_area_mapped) - vm_mac_release(RAM_BASE, RAMSize); + vm_mac_release(RAMBase, RAMSize); // Delete ROM area if (rom_area_mapped) - vm_mac_release(ROM_BASE, ROM_AREA_SIZE); + vm_mac_release(ROMBase, ROM_AREA_SIZE); // Delete DR cache areas if (dr_emulator_area_mapped) @@ -1088,6 +1143,12 @@ static void Quit(void) XCloseDisplay(x_display); #endif + // Notify GUI we are about to leave + if (gui_connection) { + if (rpc_method_invoke(gui_connection, RPC_METHOD_EXIT, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR) + rpc_method_wait_for_reply(gui_connection, RPC_TYPE_INVALID); + } + exit(0); } @@ -1096,65 +1157,29 @@ static void Quit(void) * Initialize Kernel Data segments */ -#if defined(__CYGWIN__) -#define WIN32_LEAN_AND_MEAN -#include - -static HANDLE kernel_handle; // Shared memory handle for Kernel Data -static DWORD allocation_granule; // Minimum size of allocateable are (64K) -static DWORD kernel_area_size; // Size of Kernel Data area -#endif - static bool kernel_data_init(void) { char str[256]; -#ifdef _WIN32 - SYSTEM_INFO si; - GetSystemInfo(&si); - allocation_granule = si.dwAllocationGranularity; - kernel_area_size = (KERNEL_AREA_SIZE + allocation_granule - 1) & -allocation_granule; - - char rcs[10]; - LPVOID kernel_addr; - kernel_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, kernel_area_size, NULL); - if (kernel_handle == NULL) { - sprintf(rcs, "%d", GetLastError()); - sprintf(str, GetString(STR_KD_SHMGET_ERR), rcs); - ErrorAlert(str); - return false; - } - kernel_addr = (LPVOID)Mac2HostAddr(KERNEL_DATA_BASE & -allocation_granule); - if (MapViewOfFileEx(kernel_handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kernel_area_size, kernel_addr) != kernel_addr) { - sprintf(rcs, "%d", GetLastError()); - sprintf(str, GetString(STR_KD_SHMAT_ERR), rcs); - ErrorAlert(str); - return false; - } - kernel_addr = (LPVOID)Mac2HostAddr(KERNEL_DATA2_BASE & -allocation_granule); - if (MapViewOfFileEx(kernel_handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kernel_area_size, kernel_addr) != kernel_addr) { - sprintf(rcs, "%d", GetLastError()); - sprintf(str, GetString(STR_KD2_SHMAT_ERR), rcs); - ErrorAlert(str); - return false; - } -#else - kernel_area = shmget(IPC_PRIVATE, KERNEL_AREA_SIZE, 0600); + uint32 kernel_area_size = (KERNEL_AREA_SIZE + SHMLBA - 1) & -SHMLBA; + + kernel_area = shmget(IPC_PRIVATE, kernel_area_size, 0600); if (kernel_area == -1) { sprintf(str, GetString(STR_KD_SHMGET_ERR), strerror(errno)); ErrorAlert(str); return false; } - if (shmat(kernel_area, Mac2HostAddr(KERNEL_DATA_BASE), 0) < 0) { + void *kernel_addr = Mac2HostAddr(KERNEL_DATA_BASE & -SHMLBA); + if (shmat(kernel_area, kernel_addr, 0) != kernel_addr) { sprintf(str, GetString(STR_KD_SHMAT_ERR), strerror(errno)); ErrorAlert(str); return false; } - if (shmat(kernel_area, Mac2HostAddr(KERNEL_DATA2_BASE), 0) < 0) { + kernel_addr = Mac2HostAddr(KERNEL_DATA2_BASE & -SHMLBA); + if (shmat(kernel_area, kernel_addr, 0) != kernel_addr) { sprintf(str, GetString(STR_KD2_SHMAT_ERR), strerror(errno)); ErrorAlert(str); return false; } -#endif return true; } @@ -1165,19 +1190,11 @@ static bool kernel_data_init(void) static void kernel_data_exit(void) { -#ifdef _WIN32 - if (kernel_handle) { - UnmapViewOfFile(Mac2HostAddr(KERNEL_DATA_BASE & -allocation_granule)); - UnmapViewOfFile(Mac2HostAddr(KERNEL_DATA2_BASE & -allocation_granule)); - CloseHandle(kernel_handle); - } -#else if (kernel_area >= 0) { - shmdt(Mac2HostAddr(KERNEL_DATA_BASE)); - shmdt(Mac2HostAddr(KERNEL_DATA2_BASE)); + shmdt(Mac2HostAddr(KERNEL_DATA_BASE & -SHMLBA)); + shmdt(Mac2HostAddr(KERNEL_DATA2_BASE & -SHMLBA)); shmctl(kernel_area, IPC_RMID, NULL); } -#endif } @@ -1209,9 +1226,9 @@ static void *emul_func(void *arg) // Jump to ROM boot routine D(bug("Jumping to ROM\n")); #if EMULATED_PPC - jump_to_rom(ROM_BASE + 0x310000); + jump_to_rom(ROMBase + 0x310000); #else - jump_to_rom(ROM_BASE + 0x310000, (uint32)emulator_data); + jump_to_rom(ROMBase + 0x310000, (uint32)emulator_data); #endif D(bug("Returned from ROM\n")); @@ -1297,7 +1314,7 @@ void Dump68kRegs(M68kRegisters *r) void MakeExecutable(int dummy, uint32 start, uint32 length) { - if ((start >= ROM_BASE) && (start < (ROM_BASE + ROM_SIZE))) + if ((start >= ROMBase) && (start < (ROMBase + ROM_SIZE))) return; #if EMULATED_PPC FlushCodeCache(start, start + length); @@ -1410,7 +1427,7 @@ static void *tick_func(void *arg) } uint64 end = GetTicks_usec(); - D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start))); + D(bug("%lld ticks in %lld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start))); return NULL; } @@ -1534,8 +1551,10 @@ void B2_delete_mutex(B2_mutex *mutex) #if !EMULATED_PPC void TriggerInterrupt(void) { - if (ready_for_signals) + if (ready_for_signals) { + idle_resume(); pthread_kill(emul_thread, SIGUSR2); + } } #endif @@ -1590,19 +1609,10 @@ void EnableInterrupt(void) */ #if !EMULATED_PPC -static void sigusr2_handler(int sig, siginfo_t *sip, void *scp) +void sigusr2_handler(int sig, siginfo_t *sip, void *scp) { machine_regs *r = MACHINE_REGISTERS(scp); -#ifdef USE_SDL_VIDEO - // We must fill in the events queue in the same thread that did call SDL_SetVideoMode() - SDL_PumpEvents(); -#endif - - // Do nothing if interrupts are disabled - if (*(int32 *)XLM_IRQ_NEST > 0) - return; - #ifdef SYSTEM_CLOBBERS_R2 // Restore pointer to Thread Local Storage set_r2(TOC); @@ -1612,6 +1622,15 @@ static void sigusr2_handler(int sig, sig set_r13(R13); #endif +#ifdef USE_SDL_VIDEO + // We must fill in the events queue in the same thread that did call SDL_SetVideoMode() + SDL_PumpEvents(); +#endif + + // Do nothing if interrupts are disabled + if (*(int32 *)XLM_IRQ_NEST > 0) + return; + // Disable MacOS stack sniffer WriteMacInt32(0x110, 0); @@ -1628,8 +1647,8 @@ static void sigusr2_handler(int sig, sig // 68k emulator inactive, in nanokernel? if (r->gpr(1) != KernelDataAddr) { - // Set extra stack for nested interrupts - sig_stack_acquire(); + // Set extra stack for SIGSEGV handler + sigaltstack(&extra_stack, NULL); // Prepare for 68k interrupt level 1 WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1); @@ -1638,12 +1657,12 @@ static void sigusr2_handler(int sig, sig // Execute nanokernel interrupt routine (this will activate the 68k emulator) DisableInterrupt(); if (ROMType == ROMTYPE_NEWWORLD) - ppc_interrupt(ROM_BASE + 0x312b1c, KernelDataAddr); + ppc_interrupt(ROMBase + 0x312b1c, KernelDataAddr); else - ppc_interrupt(ROM_BASE + 0x312a3c, KernelDataAddr); + ppc_interrupt(ROMBase + 0x312a3c, KernelDataAddr); - // Reset normal signal stack - sig_stack_release(); + // Reset normal stack + sigaltstack(&sig_stack, NULL); } break; #endif @@ -1654,7 +1673,7 @@ static void sigusr2_handler(int sig, sig if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) { // Set extra stack for SIGSEGV handler - sig_stack_acquire(); + sigaltstack(&extra_stack, NULL); #if 1 // Execute full 68k interrupt routine M68kRegisters r; @@ -1680,8 +1699,8 @@ static void sigusr2_handler(int sig, sig } } #endif - // Reset normal signal stack - sig_stack_release(); + // Reset normal stack + sigaltstack(&sig_stack, NULL); } break; #endif @@ -1712,41 +1731,46 @@ static void sigsegv_handler(int sig, sig #endif #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->pc())) + // Handle screen fault +#if SIGSEGV_CHECK_VERSION(1,0,0) + sigsegv_info_t si; + si.addr = (sigsegv_address_t)addr; + si.pc = (sigsegv_address_t)r->pc(); +#endif + extern bool Screen_fault_handler(sigsegv_info_t *sip); + if (Screen_fault_handler(&si)) return; #endif num_segv++; // Fault in Mac ROM or RAM or DR Cache? - bool mac_fault = (r->pc() >= ROM_BASE) && (r->pc() < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc() >= RAMBase) && (r->pc() < (RAMBase + RAMSize)) || (r->pc() >= DR_CACHE_BASE && r->pc() < (DR_CACHE_BASE + DR_CACHE_SIZE)); + bool mac_fault = (r->pc() >= ROMBase) && (r->pc() < (ROMBase + ROM_AREA_SIZE)) || (r->pc() >= RAMBase) && (r->pc() < (RAMBase + RAMSize)) || (r->pc() >= DR_CACHE_BASE && r->pc() < (DR_CACHE_BASE + DR_CACHE_SIZE)); if (mac_fault) { // "VM settings" during MacOS 8 installation - if (r->pc() == ROM_BASE + 0x488160 && r->gpr(20) == 0xf8000000) { + if (r->pc() == ROMBase + 0x488160 && r->gpr(20) == 0xf8000000) { r->pc() += 4; r->gpr(8) = 0; return; // MacOS 8.5 installation - } else if (r->pc() == ROM_BASE + 0x488140 && r->gpr(16) == 0xf8000000) { + } else if (r->pc() == ROMBase + 0x488140 && r->gpr(16) == 0xf8000000) { r->pc() += 4; r->gpr(8) = 0; return; // MacOS 8 serial drivers on startup - } else if (r->pc() == ROM_BASE + 0x48e080 && (r->gpr(8) == 0xf3012002 || r->gpr(8) == 0xf3012000)) { + } else if (r->pc() == ROMBase + 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->pc() == ROM_BASE + 0x48c5e0 && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) { + } else if (r->pc() == ROMBase + 0x48c5e0 && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) { r->pc() += 4; return; - } else if (r->pc() == ROM_BASE + 0x4a10a0 && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) { + } else if (r->pc() == ROMBase + 0x4a10a0 && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) { r->pc() += 4; return; @@ -1879,7 +1903,7 @@ static void sigsegv_handler(int sig, sig // 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 >= ROMBase && addr < ROMBase + 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) @@ -1970,7 +1994,7 @@ static void sigill_handler(int sig, sigi #endif // Fault in Mac ROM or RAM? - bool mac_fault = (r->pc() >= ROM_BASE) && (r->pc() < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc() >= RAMBase) && (r->pc() < (RAMBase + RAMSize)); + bool mac_fault = (r->pc() >= ROMBase) && (r->pc() < (ROMBase + ROM_AREA_SIZE)) || (r->pc() >= RAMBase) && (r->pc() < (RAMBase + RAMSize)); if (mac_fault) { // Get opcode and divide into fields @@ -2138,7 +2162,7 @@ bool SheepMem::Init(void) // Allocate SheepShaver globals proc = base; - if (vm_mac_acquire(base, size) < 0) + if (vm_mac_acquire_fixed(base, size) < 0) return false; // Allocate page with all bits set to 0, right in the middle @@ -2151,7 +2175,7 @@ bool SheepMem::Init(void) #if EMULATED_PPC // Allocate alternate stack for PowerPC interrupt routine sig_stack = base + size; - if (vm_mac_acquire(sig_stack, SIG_STACK_SIZE) < 0) + if (vm_mac_acquire_fixed(sig_stack, SIG_STACK_SIZE) < 0) return false; #endif @@ -2222,6 +2246,11 @@ void display_alert(int title_id, int pre void ErrorAlert(const char *text) { + if (gui_connection) { + if (rpc_method_invoke(gui_connection, RPC_METHOD_ERROR_ALERT, RPC_TYPE_STRING, text, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR && + rpc_method_wait_for_reply(gui_connection, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR) + return; + } #if defined(ENABLE_GTK) && !defined(USE_SDL_VIDEO) if (PrefsFindBool("nogui") || x_display == NULL) { printf(GetString(STR_SHELL_ERROR_PREFIX), text); @@ -2241,6 +2270,11 @@ void ErrorAlert(const char *text) void WarningAlert(const char *text) { + if (gui_connection) { + if (rpc_method_invoke(gui_connection, RPC_METHOD_WARNING_ALERT, RPC_TYPE_STRING, text, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR && + rpc_method_wait_for_reply(gui_connection, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR) + return; + } #if defined(ENABLE_GTK) && !defined(USE_SDL_VIDEO) if (PrefsFindBool("nogui") || x_display == NULL) { printf(GetString(STR_SHELL_WARNING_PREFIX), text);