--- SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp 2004/11/22 22:04:38 1.53 +++ SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp 2012/06/16 02:16:40 1.77 @@ -1,7 +1,7 @@ /* * sheepshaver_glue.cpp - Glue Kheperix CPU to SheepShaver CPU engine interface * - * SheepShaver (C) 1997-2004 Christian Bauer and Marc Hellwig + * SheepShaver (C) 1997-2008 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 @@ -58,6 +58,10 @@ #define DEBUG 0 #include "debug.h" +extern "C" { +#include "dis-asm.h" +} + // Emulation time statistics #ifndef EMUL_TIME_STATS #define EMUL_TIME_STATS 0 @@ -89,13 +93,11 @@ extern uintptr SignalStackBase(); // From rsrc_patches.cpp extern "C" void check_load_invoc(uint32 type, int16 id, uint32 h); +extern "C" void named_check_load_invoc(uint32 type, uint32 name, uint32 h); // PowerPC EmulOp to exit from emulation looop const uint32 POWERPC_EXEC_RETURN = POWERPC_EMUL_OP | 1; -// Enable interrupt routine safety checks? -#define SAFE_INTERRUPT_PPC 1 - // Enable Execute68k() safety checks? #define SAFE_EXEC_68K 1 @@ -120,12 +122,6 @@ static uint8 *emul_op_trampoline; static uint8 *native_op_trampoline; #endif -// JIT Compiler enabled? -static inline bool enable_jit_p() -{ - return PrefsFindBool("jit"); -} - /** * PowerPC emulator glue with special 'sheep' opcodes @@ -142,21 +138,6 @@ class sheepshaver_cpu void init_decoder(); void execute_sheep(uint32 opcode); - // CPU context to preserve on interrupt - class interrupt_context { - uint32 gpr[32]; - uint32 pc; - uint32 lr; - uint32 ctr; - uint32 cr; - uint32 xer; - sheepshaver_cpu *cpu; - const char *where; - public: - interrupt_context(sheepshaver_cpu *_cpu, const char *_where); - ~interrupt_context(); - }; - public: // Constructor @@ -192,48 +173,19 @@ public: // Handle MacOS interrupt void interrupt(uint32 entry); - void handle_interrupt(); // Make sure the SIGSEGV handler can access CPU registers - friend sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t); + friend sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip); }; -// Memory allocator returning areas aligned on 16-byte boundaries -void *operator new(size_t size) -{ - void *p; - -#if defined(HAVE_POSIX_MEMALIGN) - if (posix_memalign(&p, 16, size) != 0) - throw std::bad_alloc(); -#elif defined(HAVE_MEMALIGN) - p = memalign(16, size); -#elif defined(HAVE_VALLOC) - p = valloc(size); // page-aligned! -#else - /* XXX: handle padding ourselves */ - p = malloc(size); -#endif - - return p; -} - -void operator delete(void *p) -{ -#if defined(HAVE_MEMALIGN) || defined(HAVE_VALLOC) -#if defined(__GLIBC__) - // this is known to work only with GNU libc - free(p); -#endif -#else - free(p); -#endif -} - sheepshaver_cpu::sheepshaver_cpu() - : powerpc_cpu(enable_jit_p()) { init_decoder(); + +#if PPC_ENABLE_JIT + if (PrefsFindBool("jit")) + enable_jit(); +#endif } void sheepshaver_cpu::init_decoder() @@ -241,7 +193,6 @@ void sheepshaver_cpu::init_decoder() static const instr_info_t sheep_ii_table[] = { { "sheep", (execute_pmf)&sheepshaver_cpu::execute_sheep, - NULL, PPC_I(SHEEP), D_form, 6, 0, CFLOW_JUMP | CFLOW_TRAP } @@ -278,7 +229,7 @@ void sheepshaver_cpu::execute_emul_op(ui for (int i = 0; i < 7; i++) r68.a[i] = gpr(16 + i); r68.a[7] = gpr(1); - uint32 saved_cr = get_cr() & CR_field<2>::mask(); + uint32 saved_cr = get_cr() & 0xff9fffff; // mask_operand::compute(11, 8) uint32 saved_xer = get_xer(); EmulOp(&r68, gpr(24), emul_op); set_cr(saved_cr); @@ -386,6 +337,7 @@ int sheepshaver_cpu::compile1(codegen_co status = COMPILE_CODE_OK; break; } +#endif case NATIVE_CHECK_LOAD_INVOC: dg.gen_load_T0_GPR(3); dg.gen_load_T1_GPR(4); @@ -394,18 +346,48 @@ int sheepshaver_cpu::compile1(codegen_co dg.gen_invoke_T0_T1_T2((void (*)(uint32, uint32, uint32))check_load_invoc); status = COMPILE_CODE_OK; break; -#endif - case NATIVE_BITBLT: + case NATIVE_NAMED_CHECK_LOAD_INVOC: + dg.gen_load_T0_GPR(3); + dg.gen_load_T1_GPR(4); + dg.gen_load_T2_GPR(5); + dg.gen_invoke_T0_T1_T2((void (*)(uint32, uint32, uint32))named_check_load_invoc); + status = COMPILE_CODE_OK; + break; + case NATIVE_NQD_SYNC_HOOK: + dg.gen_load_T0_GPR(3); + dg.gen_invoke_T0_ret_T0((uint32 (*)(uint32))NQD_sync_hook); + dg.gen_store_T0_GPR(3); + status = COMPILE_CODE_OK; + break; + case NATIVE_NQD_BITBLT_HOOK: + dg.gen_load_T0_GPR(3); + dg.gen_invoke_T0_ret_T0((uint32 (*)(uint32))NQD_bitblt_hook); + dg.gen_store_T0_GPR(3); + status = COMPILE_CODE_OK; + break; + case NATIVE_NQD_FILLRECT_HOOK: + dg.gen_load_T0_GPR(3); + dg.gen_invoke_T0_ret_T0((uint32 (*)(uint32))NQD_fillrect_hook); + dg.gen_store_T0_GPR(3); + status = COMPILE_CODE_OK; + break; + case NATIVE_NQD_UNKNOWN_HOOK: + dg.gen_load_T0_GPR(3); + dg.gen_invoke_T0_ret_T0((uint32 (*)(uint32))NQD_unknown_hook); + dg.gen_store_T0_GPR(3); + status = COMPILE_CODE_OK; + break; + case NATIVE_NQD_BITBLT: dg.gen_load_T0_GPR(3); dg.gen_invoke_T0((void (*)(uint32))NQD_bitblt); status = COMPILE_CODE_OK; break; - case NATIVE_INVRECT: + case NATIVE_NQD_INVRECT: dg.gen_load_T0_GPR(3); dg.gen_invoke_T0((void (*)(uint32))NQD_invrect); status = COMPILE_CODE_OK; break; - case NATIVE_FILLRECT: + case NATIVE_NQD_FILLRECT: dg.gen_load_T0_GPR(3); dg.gen_invoke_T0((void (*)(uint32))NQD_fillrect); status = COMPILE_CODE_OK; @@ -416,8 +398,8 @@ int sheepshaver_cpu::compile1(codegen_co if (!FN_field::test(opcode)) cg_context.done_compile = false; else { - dg.gen_load_A0_LR(); - dg.gen_set_PC_A0(); + dg.gen_load_T0_LR_aligned(); + dg.gen_set_PC_T0(); cg_context.done_compile = true; } break; @@ -427,8 +409,8 @@ int sheepshaver_cpu::compile1(codegen_co if (!FN_field::test(opcode)) dg.gen_set_PC_im(cg_context.pc + 4); else { - dg.gen_load_A0_LR(); - dg.gen_set_PC_A0(); + dg.gen_load_T0_LR_aligned(); + dg.gen_set_PC_T0(); } dg.gen_mov_32_T0_im(selector); dg.gen_jmp(native_op_trampoline); @@ -473,46 +455,6 @@ int sheepshaver_cpu::compile1(codegen_co } #endif -// CPU context to preserve on interrupt -sheepshaver_cpu::interrupt_context::interrupt_context(sheepshaver_cpu *_cpu, const char *_where) -{ -#if SAFE_INTERRUPT_PPC >= 2 - cpu = _cpu; - where = _where; - - // Save interrupt context - memcpy(&gpr[0], &cpu->gpr(0), sizeof(gpr)); - pc = cpu->pc(); - lr = cpu->lr(); - ctr = cpu->ctr(); - cr = cpu->get_cr(); - xer = cpu->get_xer(); -#endif -} - -sheepshaver_cpu::interrupt_context::~interrupt_context() -{ -#if SAFE_INTERRUPT_PPC >= 2 - // Check whether CPU context was preserved by interrupt - if (memcmp(&gpr[0], &cpu->gpr(0), sizeof(gpr)) != 0) { - printf("FATAL: %s: interrupt clobbers registers\n", where); - for (int i = 0; i < 32; i++) - if (gpr[i] != cpu->gpr(i)) - printf(" r%d: %08x -> %08x\n", i, gpr[i], cpu->gpr(i)); - } - if (pc != cpu->pc()) - printf("FATAL: %s: interrupt clobbers PC\n", where); - if (lr != cpu->lr()) - printf("FATAL: %s: interrupt clobbers LR\n", where); - if (ctr != cpu->ctr()) - printf("FATAL: %s: interrupt clobbers CTR\n", where); - if (cr != cpu->get_cr()) - printf("FATAL: %s: interrupt clobbers CR\n", where); - if (xer != cpu->get_xer()) - printf("FATAL: %s: interrupt clobbers XER\n", where); -#endif -} - // Handle MacOS interrupt void sheepshaver_cpu::interrupt(uint32 entry) { @@ -521,13 +463,6 @@ void sheepshaver_cpu::interrupt(uint32 e const clock_t interrupt_start = clock(); #endif -#if SAFE_INTERRUPT_PPC - static int depth = 0; - if (depth != 0) - printf("FATAL: sheepshaver_cpu::interrupt() called more than once: %d\n", depth); - depth++; -#endif - // Save program counters and branch registers uint32 saved_pc = pc(); uint32 saved_lr = lr(); @@ -581,10 +516,6 @@ void sheepshaver_cpu::interrupt(uint32 e #if EMUL_TIME_STATS interrupt_time += (clock() - interrupt_start); #endif - -#if SAFE_INTERRUPT_PPC - depth--; -#endif } // Execute 68k routine @@ -799,20 +730,38 @@ static void dump_log(void) ppc_cpu->dump_log(); } -/* - * Initialize CPU emulation - */ +static int read_mem(bfd_vma memaddr, bfd_byte *myaddr, int length, struct disassemble_info *info) +{ + Mac2Host_memcpy(myaddr, memaddr, length); + return 0; +} + +static void dump_disassembly(const uint32 pc, const int prefix_count, const int suffix_count) +{ + struct disassemble_info info; + INIT_DISASSEMBLE_INFO(info, stderr, fprintf); + info.read_memory_func = read_mem; + + const int count = prefix_count + suffix_count + 1; + const uint32 base_addr = pc - prefix_count * 4; + for (int i = 0; i < count; i++) { + const bfd_vma addr = base_addr + i * 4; + fprintf(stderr, "%s0x%8llx: ", addr == pc ? " >" : " ", addr); + print_insn_ppc(addr, &info); + fprintf(stderr, "\n"); + } +} -sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction) +sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip) { #if ENABLE_VOSF // Handle screen fault - extern bool Screen_fault_handler(sigsegv_address_t, sigsegv_address_t); - if (Screen_fault_handler(fault_address, fault_instruction)) + extern bool Screen_fault_handler(sigsegv_info_t *sip); + if (Screen_fault_handler(sip)) return SIGSEGV_RETURN_SUCCESS; #endif - const uintptr addr = (uintptr)fault_address; + const uintptr addr = (uintptr)sigsegv_get_fault_address(sip); #if HAVE_SIGSEGV_SKIP_INSTRUCTION // Ignore writes to ROM if ((addr - (uintptr)ROMBaseHost) < ROM_SIZE) @@ -823,25 +772,25 @@ sigsegv_return_t sigsegv_handler(sigsegv const uint32 pc = cpu->pc(); // Fault in Mac ROM or RAM? - bool mac_fault = (pc >= ROM_BASE) && (pc < (ROM_BASE + ROM_AREA_SIZE)) || (pc >= RAMBase) && (pc < (RAMBase + RAMSize)) || (pc >= DR_CACHE_BASE && pc < (DR_CACHE_BASE + DR_CACHE_SIZE)); + bool mac_fault = (pc >= ROMBase) && (pc < (ROMBase + ROM_AREA_SIZE)) || (pc >= RAMBase) && (pc < (RAMBase + RAMSize)) || (pc >= DR_CACHE_BASE && pc < (DR_CACHE_BASE + DR_CACHE_SIZE)); if (mac_fault) { // "VM settings" during MacOS 8 installation - if (pc == ROM_BASE + 0x488160 && cpu->gpr(20) == 0xf8000000) + if (pc == ROMBase + 0x488160 && cpu->gpr(20) == 0xf8000000) return SIGSEGV_RETURN_SKIP_INSTRUCTION; // MacOS 8.5 installation - else if (pc == ROM_BASE + 0x488140 && cpu->gpr(16) == 0xf8000000) + else if (pc == ROMBase + 0x488140 && cpu->gpr(16) == 0xf8000000) return SIGSEGV_RETURN_SKIP_INSTRUCTION; // MacOS 8 serial drivers on startup - else if (pc == ROM_BASE + 0x48e080 && (cpu->gpr(8) == 0xf3012002 || cpu->gpr(8) == 0xf3012000)) + else if (pc == ROMBase + 0x48e080 && (cpu->gpr(8) == 0xf3012002 || cpu->gpr(8) == 0xf3012000)) return SIGSEGV_RETURN_SKIP_INSTRUCTION; // MacOS 8.1 serial drivers on startup - else if (pc == ROM_BASE + 0x48c5e0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000)) + else if (pc == ROMBase + 0x48c5e0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000)) return SIGSEGV_RETURN_SKIP_INSTRUCTION; - else if (pc == ROM_BASE + 0x4a10a0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000)) + else if (pc == ROMBase + 0x4a10a0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000)) return SIGSEGV_RETURN_SKIP_INSTRUCTION; // MacOS 8.6 serial drivers on startup (with DR Cache and OldWorld ROM) @@ -862,17 +811,23 @@ sigsegv_return_t sigsegv_handler(sigsegv #error "FIXME: You don't have the capability to skip instruction within signal handlers" #endif - printf("SIGSEGV\n"); - printf(" pc %p\n", fault_instruction); - printf(" ea %p\n", fault_address); + fprintf(stderr, "SIGSEGV\n"); + fprintf(stderr, " pc %p\n", sigsegv_get_fault_instruction_address(sip)); + fprintf(stderr, " ea %p\n", sigsegv_get_fault_address(sip)); dump_registers(); ppc_cpu->dump_log(); + dump_disassembly(pc, 8, 8); + enter_mon(); QuitEmulator(); return SIGSEGV_RETURN_FAILURE; } +/* + * Initialize CPU emulation + */ + void init_emul_ppc(void) { // Get pointer to KernelData in host address space @@ -880,7 +835,7 @@ void init_emul_ppc(void) // Initialize main CPU emulator ppc_cpu = new sheepshaver_cpu(); - ppc_cpu->set_register(powerpc_registers::GPR(3), any_register((uint32)ROM_BASE + 0x30d000)); + ppc_cpu->set_register(powerpc_registers::GPR(3), any_register((uint32)ROMBase + 0x30d000)); ppc_cpu->set_register(powerpc_registers::GPR(4), any_register(KernelDataAddr + 0x1000)); WriteMacInt32(XLM_RUN_MODE, MODE_68K); @@ -928,6 +883,7 @@ void exit_emul_ppc(void) #endif delete ppc_cpu; + ppc_cpu = NULL; } #if PPC_ENABLE_JIT && PPC_REENTRANT_JIT @@ -975,6 +931,7 @@ void emul_ppc(uint32 entry) void TriggerInterrupt(void) { + idle_resume(); #if 0 WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1); #else @@ -984,7 +941,7 @@ void TriggerInterrupt(void) #endif } -void sheepshaver_cpu::handle_interrupt(void) +void HandleInterrupt(powerpc_registers *r) { #ifdef USE_SDL_VIDEO // We must fill in the events queue in the same thread that did call SDL_SetVideoMode() @@ -995,29 +952,23 @@ void sheepshaver_cpu::handle_interrupt(v if (int32(ReadMacInt32(XLM_IRQ_NEST)) > 0) return; - // Current interrupt nest level - static int interrupt_depth = 0; - ++interrupt_depth; + // Update interrupt count #if EMUL_TIME_STATS interrupt_count++; #endif - // Disable MacOS stack sniffer - WriteMacInt32(0x110, 0); - // Interrupt action depends on current run mode switch (ReadMacInt32(XLM_RUN_MODE)) { case MODE_68K: // 68k emulator active, trigger 68k interrupt level 1 WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1); - set_cr(get_cr() | tswap32(kernel_data->v[0x674 >> 2])); + r->cr.set(r->cr.get() | tswap32(kernel_data->v[0x674 >> 2])); break; #if INTERRUPTS_IN_NATIVE_MODE case MODE_NATIVE: // 68k emulator inactive, in nanokernel? - if (gpr(1) != KernelDataAddr && interrupt_depth == 1) { - interrupt_context ctx(this, "PowerPC mode"); + if (r->gpr[1] != KernelDataAddr) { // Prepare for 68k interrupt level 1 WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1); @@ -1028,9 +979,9 @@ void sheepshaver_cpu::handle_interrupt(v // Execute nanokernel interrupt routine (this will activate the 68k emulator) DisableInterrupt(); if (ROMType == ROMTYPE_NEWWORLD) - ppc_cpu->interrupt(ROM_BASE + 0x312b1c); + ppc_cpu->interrupt(ROMBase + 0x312b1c); else - ppc_cpu->interrupt(ROM_BASE + 0x312a3c); + ppc_cpu->interrupt(ROMBase + 0x312a3c); } break; #endif @@ -1039,7 +990,6 @@ void sheepshaver_cpu::handle_interrupt(v case MODE_EMUL_OP: // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0 if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) { - interrupt_context ctx(this, "68k mode"); #if EMUL_TIME_STATS const clock_t interrupt_start = clock(); #endif @@ -1076,17 +1026,8 @@ void sheepshaver_cpu::handle_interrupt(v break; #endif } - - // We are done with this interrupt - --interrupt_depth; } -static void get_resource(void); -static void get_1_resource(void); -static void get_ind_resource(void); -static void get_1_ind_resource(void); -static void r_get_resource(void); - // Execute NATIVE_OP routine void sheepshaver_cpu::execute_native_op(uint32 selector) { @@ -1108,7 +1049,18 @@ void sheepshaver_cpu::execute_native_op( case NATIVE_VIDEO_DO_DRIVER_IO: gpr(3) = (int32)(int16)VideoDoDriverIO(gpr(3), gpr(4), gpr(5), gpr(6), gpr(7)); break; -#ifdef WORDS_BIGENDIAN + case NATIVE_ETHER_AO_GET_HWADDR: + AO_get_ethernet_address(gpr(3)); + break; + case NATIVE_ETHER_AO_ADD_MULTI: + AO_enable_multicast(gpr(3)); + break; + case NATIVE_ETHER_AO_DEL_MULTI: + AO_disable_multicast(gpr(3)); + break; + case NATIVE_ETHER_AO_SEND_PACKET: + AO_transmit_packet(gpr(3)); + break; case NATIVE_ETHER_IRQ: EtherIRQ(); break; @@ -1130,28 +1082,25 @@ void sheepshaver_cpu::execute_native_op( case NATIVE_ETHER_RSRV: gpr(3) = ether_rsrv((queue_t *)gpr(3)); break; -#else - case NATIVE_ETHER_INIT: - // FIXME: needs more complicated thunks - gpr(3) = false; - break; -#endif - case NATIVE_SYNC_HOOK: + case NATIVE_NQD_SYNC_HOOK: gpr(3) = NQD_sync_hook(gpr(3)); break; - case NATIVE_BITBLT_HOOK: + case NATIVE_NQD_UNKNOWN_HOOK: + gpr(3) = NQD_unknown_hook(gpr(3)); + break; + case NATIVE_NQD_BITBLT_HOOK: gpr(3) = NQD_bitblt_hook(gpr(3)); break; - case NATIVE_BITBLT: + case NATIVE_NQD_BITBLT: NQD_bitblt(gpr(3)); break; - case NATIVE_FILLRECT_HOOK: + case NATIVE_NQD_FILLRECT_HOOK: gpr(3) = NQD_fillrect_hook(gpr(3)); break; - case NATIVE_INVRECT: + case NATIVE_NQD_INVRECT: NQD_invrect(gpr(3)); break; - case NATIVE_FILLRECT: + case NATIVE_NQD_FILLRECT: NQD_fillrect(gpr(3)); break; case NATIVE_SERIAL_NOTHING: @@ -1175,27 +1124,29 @@ void sheepshaver_cpu::execute_native_op( break; } case NATIVE_GET_RESOURCE: + get_resource(ReadMacInt32(XLM_GET_RESOURCE)); + break; case NATIVE_GET_1_RESOURCE: + get_resource(ReadMacInt32(XLM_GET_1_RESOURCE)); + break; case NATIVE_GET_IND_RESOURCE: + get_resource(ReadMacInt32(XLM_GET_IND_RESOURCE)); + break; case NATIVE_GET_1_IND_RESOURCE: - case NATIVE_R_GET_RESOURCE: { - typedef void (*GetResourceCallback)(void); - static const GetResourceCallback get_resource_callbacks[] = { - ::get_resource, - ::get_1_resource, - ::get_ind_resource, - ::get_1_ind_resource, - ::r_get_resource - }; - get_resource_callbacks[selector - NATIVE_GET_RESOURCE](); + get_resource(ReadMacInt32(XLM_GET_1_IND_RESOURCE)); + break; + case NATIVE_R_GET_RESOURCE: + get_resource(ReadMacInt32(XLM_R_GET_RESOURCE)); break; - } case NATIVE_MAKE_EXECUTABLE: MakeExecutable(0, gpr(4), gpr(5)); break; case NATIVE_CHECK_LOAD_INVOC: check_load_invoc(gpr(3), gpr(4), gpr(5)); break; + case NATIVE_NAMED_CHECK_LOAD_INVOC: + named_check_load_invoc(gpr(3), gpr(4), gpr(5)); + break; default: printf("FATAL: NATIVE_OP called with bogus selector %d\n", selector); QuitEmulator(); @@ -1282,32 +1233,3 @@ uint32 call_macos7(uint32 tvect, uint32 const uint32 args[] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7 }; return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args); } - -/* - * Resource Manager thunks - */ - -void get_resource(void) -{ - ppc_cpu->get_resource(ReadMacInt32(XLM_GET_RESOURCE)); -} - -void get_1_resource(void) -{ - ppc_cpu->get_resource(ReadMacInt32(XLM_GET_1_RESOURCE)); -} - -void get_ind_resource(void) -{ - ppc_cpu->get_resource(ReadMacInt32(XLM_GET_IND_RESOURCE)); -} - -void get_1_ind_resource(void) -{ - ppc_cpu->get_resource(ReadMacInt32(XLM_GET_1_IND_RESOURCE)); -} - -void r_get_resource(void) -{ - ppc_cpu->get_resource(ReadMacInt32(XLM_R_GET_RESOURCE)); -}