--- SheepShaver/src/Unix/main_unix.cpp 2002/02/21 15:12:12 1.2 +++ SheepShaver/src/Unix/main_unix.cpp 2003/11/03 21:28:25 1.13 @@ -107,6 +107,8 @@ #include "macos_util.h" #include "rom_patches.h" #include "user_strings.h" +#include "vm_alloc.h" +#include "sigsegv.h" #define DEBUG 0 #include "debug.h" @@ -143,29 +145,10 @@ const char ROM_FILE_NAME[] = "ROM"; const char ROM_FILE_NAME2[] = "Mac OS ROM"; -const uint32 ROM_AREA_SIZE = 0x500000; // Size of ROM area -const uint32 ROM_END = ROM_BASE + ROM_SIZE; // End of ROM - -const uint32 KERNEL_DATA_BASE = 0x68ffe000; // Address of Kernel Data -const uint32 KERNEL_DATA2_BASE = 0x5fffe000; // Alternate address of Kernel Data -const uint32 KERNEL_AREA_SIZE = 0x2000; // Size of Kernel Data area - +const uint32 RAM_BASE = 0x20000000; // Base address of RAM const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack -// 68k Emulator Data -struct EmulatorData { - uint32 v[0x400]; -}; - - -// Kernel Data -struct KernelData { - uint32 v[0x400]; - EmulatorData ed; -}; - - #if !EMULATED_PPC // Structure in which registers are saved in a signal handler; // sigcontext->regs points to it @@ -189,6 +172,9 @@ 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 @@ -197,15 +183,15 @@ int64 BusClockSpeed; // Bus clock speed // Global variables -static char *x_display_name = NULL; // X11 display name +char *x_display_name = NULL; // X11 display name Display *x_display = NULL; // X11 display handle 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 static bool ram_area_mapped = false; // Flag: Mac RAM mmap()ped -static void *mmap_RAMBase = NULL; // Base address of mmap()ed RAM area static KernelData *kernel_data; // Pointer to Kernel Data static EmulatorData *emulator_data; @@ -220,8 +206,8 @@ static pthread_t emul_thread; // MacO static bool ready_for_signals = false; // Handler installed, signals can be sent static int64 num_segv = 0; // Number of handled SEGV signals -#if !EMULATED_PPC static struct sigaction sigusr2_action; // Interrupt signal (of emulator thread) +#if !EMULATED_PPC 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 @@ -236,7 +222,12 @@ static void Quit(void); static void *emul_func(void *arg); static void *nvram_func(void *arg); static void *tick_func(void *arg); -#if !EMULATED_PPC +#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); @@ -244,11 +235,7 @@ static void sigill_handler(int sig, sigc // From asm_linux.S -#if EMULATED_PPC -extern int atomic_add(int *var, int v); -extern int atomic_and(int *var, int v); -extern int atomic_or(int *var, int v); -#else +#if !EMULATED_PPC extern "C" void *get_toc(void); extern "C" void *get_sp(void); extern "C" void flush_icache_range(void *start, void *end); @@ -263,48 +250,45 @@ extern void paranoia_check(void); #endif -// Decode LZSS data -static void decode_lzss(const uint8 *src, uint8 *dest, int size) +#if EMULATED_PPC +/* + * Atomic operations + */ + +#if HAVE_SPINLOCKS +static spinlock_t atomic_ops_lock = SPIN_LOCK_UNLOCKED; +#else +#define spin_lock(LOCK) +#define spin_unlock(LOCK) +#endif + +int atomic_add(int *var, int v) { - char dict[0x1000]; - int run_mask = 0, dict_idx = 0xfee; - for (;;) { - if (run_mask < 0x100) { - // Start new run - if (--size < 0) - break; - run_mask = *src++ | 0xff00; - } - bool bit = run_mask & 1; - run_mask >>= 1; - if (bit) { - // Verbatim copy - if (--size < 0) - break; - int c = *src++; - dict[dict_idx++] = c; - *dest++ = c; - dict_idx &= 0xfff; - } else { - // Copy from dictionary - if (--size < 0) - break; - int idx = *src++; - if (--size < 0) - break; - int cnt = *src++; - idx |= (cnt << 4) & 0xf00; - cnt = (cnt & 0x0f) + 3; - while (cnt--) { - char c = dict[idx++]; - dict[dict_idx++] = c; - *dest++ = c; - idx &= 0xfff; - dict_idx &= 0xfff; - } - } - } + spin_lock(&atomic_ops_lock); + int ret = *var; + *var += v; + spin_unlock(&atomic_ops_lock); + return ret; +} + +int atomic_and(int *var, int v) +{ + spin_lock(&atomic_ops_lock); + int ret = *var; + *var &= v; + spin_unlock(&atomic_ops_lock); + return ret; +} + +int atomic_or(int *var, int v) +{ + spin_lock(&atomic_ops_lock); + int ret = *var; + *var |= v; + spin_unlock(&atomic_ops_lock); + return ret; } +#endif /* @@ -325,7 +309,6 @@ int main(int argc, char **argv) char str[256]; uint32 *boot_globs; int16 i16; - int drive, driver; int rom_fd; FILE *proc_file; const char *rom_path; @@ -335,7 +318,6 @@ int main(int argc, char **argv) // Initialize variables RAMBase = 0; - mmap_RAMBase = NULL; tzset(); // Print some info @@ -464,7 +446,7 @@ int main(int argc, char **argv) } // Create Low Memory area (0x0000..0x3000) - if (mmap((char *)0x0000, 0x3000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, zero_fd, 0) == (void *)-1) { + if (vm_acquire_fixed((char *)0, 0x3000) < 0) { sprintf(str, GetString(STR_LOW_MEM_MMAP_ERR), strerror(errno)); ErrorAlert(str); goto quit; @@ -493,12 +475,30 @@ int main(int argc, char **argv) KernelDataAddr = (uint32)kernel_data; 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) { + 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 (mmap((char *)ROM_BASE, ROM_AREA_SIZE, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, zero_fd, 0) == (void *)-1) { + if (vm_acquire_fixed((char *)ROM_BASE, ROM_AREA_SIZE) < 0) { + sprintf(str, GetString(STR_ROM_MMAP_ERR), strerror(errno)); + ErrorAlert(str); + goto quit; + } +#if !EMULATED_PPC || defined(__powerpc__) + 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); goto quit; } +#endif rom_area_mapped = true; D(bug("ROM area at %08x\n", ROM_BASE)); @@ -509,13 +509,19 @@ int main(int argc, char **argv) RAMSize = 8*1024*1024; } - mmap_RAMBase = mmap((void *)0x20000000, RAMSize, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, zero_fd, 0); - if (mmap_RAMBase == (void *)-1) { + if (vm_acquire_fixed((char *)RAM_BASE, RAMSize) < 0) { + sprintf(str, GetString(STR_RAM_MMAP_ERR), strerror(errno)); + ErrorAlert(str); + goto quit; + } +#if !EMULATED_PPC + if (vm_protect((char *)RAM_BASE, RAMSize, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE) < 0) { sprintf(str, GetString(STR_RAM_MMAP_ERR), strerror(errno)); ErrorAlert(str); goto quit; } - RAMBase = (uint32)mmap_RAMBase; +#endif + RAMBase = RAM_BASE; ram_area_mapped = true; D(bug("RAM area at %08x\n", RAMBase)); @@ -540,43 +546,10 @@ int main(int argc, char **argv) rom_tmp = new uint8[ROM_SIZE]; actual = read(rom_fd, (void *)rom_tmp, ROM_SIZE); close(rom_fd); - if (actual == ROM_SIZE) { - // Plain ROM image - memcpy((void *)ROM_BASE, rom_tmp, ROM_SIZE); - delete[] rom_tmp; - } else { - if (strncmp((char *)rom_tmp, "", 11) == 0) { - // CHRP compressed ROM image - D(bug("CHRP ROM image\n")); - uint32 lzss_offset, lzss_size; - - char *s = strstr((char *)rom_tmp, "constant lzss-offset"); - if (s == NULL) { - ErrorAlert(GetString(STR_ROM_SIZE_ERR)); - goto quit; - } - s -= 7; - if (sscanf(s, "%06x", &lzss_offset) != 1) { - ErrorAlert(GetString(STR_ROM_SIZE_ERR)); - goto quit; - } - s = strstr((char *)rom_tmp, "constant lzss-size"); - if (s == NULL) { - ErrorAlert(GetString(STR_ROM_SIZE_ERR)); - goto quit; - } - s -= 7; - if (sscanf(s, "%06x", &lzss_size) != 1) { - ErrorAlert(GetString(STR_ROM_SIZE_ERR)); - goto quit; - } - D(bug("Offset of compressed data: %08x\n", lzss_offset)); - D(bug("Size of compressed data: %08x\n", lzss_size)); - - D(bug("Uncompressing ROM...\n")); - decode_lzss(rom_tmp + lzss_offset, (uint8 *)ROM_BASE, lzss_size); - delete[] rom_tmp; - } else if (rom_size != 4*1024*1024) { + + // Decode Mac ROM + if (!DecodeROM(rom_tmp, actual)) { + if (rom_size != 4*1024*1024) { ErrorAlert(GetString(STR_ROM_SIZE_ERR)); goto quit; } else { @@ -584,15 +557,16 @@ int main(int argc, char **argv) goto quit; } } + delete[] rom_tmp; // Load NVRAM XPRAMInit(); // Set boot volume - drive = PrefsFindInt32("bootdrive"); + i16 = PrefsFindInt32("bootdrive"); XPRAM[0x1378] = i16 >> 8; XPRAM[0x1379] = i16 & 0xff; - driver = PrefsFindInt32("bootdriver"); + i16 = PrefsFindInt32("bootdriver"); XPRAM[0x137a] = i16 >> 8; XPRAM[0x137b] = i16 & 0xff; @@ -643,7 +617,7 @@ int main(int argc, char **argv) #if !EMULATED_PPC MakeExecutable(0, (void *)ROM_BASE, ROM_AREA_SIZE); #endif - mprotect((char *)ROM_BASE, ROM_AREA_SIZE, PROT_EXEC | PROT_READ); + vm_protect((char *)ROM_BASE, ROM_AREA_SIZE, VM_PAGE_READ | VM_PAGE_EXECUTE); // Initialize Kernel Data memset(kernel_data, 0, sizeof(KernelData)); @@ -697,7 +671,15 @@ int main(int argc, char **argv) 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 +#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); @@ -767,18 +749,21 @@ int main(int argc, char **argv) ErrorAlert(str); goto quit; } +#endif // 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_restorer = NULL; 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(); @@ -797,6 +782,11 @@ quit: static void Quit(void) { +#if EMULATED_PPC + // Exit PowerPC emulation + exit_emul_ppc(); +#endif + // Stop 60Hz thread if (tick_thread_active) { pthread_cancel(tick_thread); @@ -855,11 +845,11 @@ static void Quit(void) // Delete RAM area if (ram_area_mapped) - munmap(mmap_RAMBase, RAMSize); + vm_release((char *)RAM_BASE, RAMSize); // Delete ROM area if (rom_area_mapped) - munmap((char *)ROM_BASE, ROM_AREA_SIZE); + vm_release((char *)ROM_BASE, ROM_AREA_SIZE); // Delete Kernel Data area if (kernel_area >= 0) { @@ -900,8 +890,6 @@ static void Quit(void) */ #if EMULATED_PPC -extern void emul_ppc(uint32 start); -extern void init_emul_ppc(void); void jump_to_rom(uint32 entry) { init_emul_ppc(); @@ -966,7 +954,6 @@ void Execute68kTrap(uint16 trap, M68kReg uint16 proc[2] = {trap, M68K_RTS}; Execute68k((uint32)proc, r); } -#endif /* @@ -980,6 +967,7 @@ void ExecutePPC(void (*func)()) M68kRegisters r; Execute68k((uint32)&desc, &r); } +#endif /* @@ -1041,10 +1029,12 @@ void Dump68kRegs(M68kRegisters *r) void MakeExecutable(int dummy, void *start, uint32 length) { -#if !EMULATED_PPC - if (((uint32)start >= ROM_BASE) && ((uint32)start < (ROM_BASE + ROM_SIZE))) + if (((uintptr)start >= ROM_BASE) && ((uintptr)start < (ROM_BASE + ROM_SIZE))) return; - flush_icache_range(start, (void *)((uint32)start + length)); +#if EMULATED_PPC + FlushCodeCache((uintptr)start, (uintptr)start + length); +#else + flush_icache_range(start, (void *)((uintptr)start + length)); #endif } @@ -1055,7 +1045,11 @@ void MakeExecutable(int dummy, void *sta void PatchAfterStartup(void) { +#if EMULATED_PPC + ExecuteNative(NATIVE_VIDEO_INSTALL_ACCEL); +#else ExecutePPC(VideoInstallAccel); +#endif InstallExtFS(); } @@ -1166,6 +1160,56 @@ void Set_pthread_attr(pthread_attr_t *at * Mutexes */ +#ifdef HAVE_PTHREADS + +struct B2_mutex { + B2_mutex() { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + // Initialize the mutex for priority inheritance -- + // required for accurate timing. +#ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL + pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT); +#endif +#if defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE) && defined(PTHREAD_MUTEX_NORMAL) + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); +#endif +#ifdef HAVE_PTHREAD_MUTEXATTR_SETPSHARED + pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); +#endif + pthread_mutex_init(&m, &attr); + pthread_mutexattr_destroy(&attr); + } + ~B2_mutex() { + pthread_mutex_trylock(&m); // Make sure it's locked before + pthread_mutex_unlock(&m); // unlocking it. + pthread_mutex_destroy(&m); + } + pthread_mutex_t m; +}; + +B2_mutex *B2_create_mutex(void) +{ + return new B2_mutex; +} + +void B2_lock_mutex(B2_mutex *mutex) +{ + pthread_mutex_lock(&mutex->m); +} + +void B2_unlock_mutex(B2_mutex *mutex) +{ + pthread_mutex_unlock(&mutex->m); +} + +void B2_delete_mutex(B2_mutex *mutex) +{ + delete mutex; +} + +#else + struct B2_mutex { int dummy; }; @@ -1188,24 +1232,20 @@ void B2_delete_mutex(B2_mutex *mutex) delete mutex; } +#endif + /* * Trigger signal USR2 from another thread */ +#if !EMULATED_PPC || ASYNC_IRQ void TriggerInterrupt(void) { -#if EMULATED_PPC - WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1); -#else -#if 0 - WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1); -#else if (ready_for_signals) pthread_kill(emul_thread, SIGUSR2); -#endif -#endif } +#endif /* @@ -1245,11 +1285,19 @@ void EnableInterrupt(void) } -#if !EMULATED_PPC /* * 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) { pt_regs *r = sc->regs; @@ -1331,33 +1379,36 @@ static void sigusr2_handler(int sig, sig } break; #endif - } } +#endif /* * SIGSEGV handler */ +#if !EMULATED_PPC static void sigsegv_handler(int sig, sigcontext_struct *sc) { pt_regs *r = sc->regs; + + // Get effective address + 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)) + 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)); if (mac_fault) { - // Get opcode and divide into fields - uint32 opcode = *((uint32 *)r->nip); - uint32 primop = opcode >> 26; - uint32 exop = (opcode >> 1) & 0x3ff; - uint32 ra = (opcode >> 16) & 0x1f; - uint32 rb = (opcode >> 11) & 0x1f; - uint32 rd = (opcode >> 21) & 0x1f; - int32 imm = (int16)(opcode & 0xffff); - // "VM settings" during MacOS 8 installation if (r->nip == ROM_BASE + 0x488160 && r->gpr[20] == 0xf8000000) { r->nip += 4; @@ -1385,6 +1436,15 @@ static void sigsegv_handler(int sig, sig return; } + // Get opcode and divide into fields + uint32 opcode = *((uint32 *)r->nip); + uint32 primop = opcode >> 26; + uint32 exop = (opcode >> 1) & 0x3ff; + uint32 ra = (opcode >> 16) & 0x1f; + uint32 rb = (opcode >> 11) & 0x1f; + uint32 rd = (opcode >> 21) & 0x1f; + int32 imm = (int16)(opcode & 0xffff); + // Analyze opcode enum { TYPE_UNKNOWN, @@ -1468,27 +1528,6 @@ static void sigsegv_handler(int sig, sig transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break; } - // Calculate effective address - uint32 addr = 0; - switch (addr_mode) { - case MODE_X: - case MODE_UX: - if (ra == 0) - addr = r->gpr[rb]; - else - addr = r->gpr[ra] + r->gpr[rb]; - break; - case MODE_NORM: - case MODE_U: - if (ra == 0) - addr = (int32)(int16)imm; - else - addr = r->gpr[ra] + (int32)(int16)imm; - break; - default: - break; - } - // 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));