From 663facbf97667fe40f34093cf65f88bd7ca4a62c Mon Sep 17 00:00:00 2001 From: gbeauche <> Date: Sun, 27 Feb 2005 21:52:06 +0000 Subject: [PATCH] Fix native Linux/ppc with recent enough glibc that supports TLS; r2 is used in that case. Tell me if I broke other arches, e.g. r13 is no longer saved in Video and Ethernet stubs, though it seems to be OK. Colateral feature: SheepShaver should now run on Linux/ppc64 with relevant 32-bit runtime. Native Linux/ppc64 support is harder as low mem globals are 32-bit in mind and e.g. the TLS register there is %r13, %r2 is the TOC (PowerOpen/AIX ABI) --- SheepShaver/src/BeOS/sysdeps.h | 1 + SheepShaver/src/Unix/Linux/paranoia.cpp | 39 +++++++-- SheepShaver/src/Unix/main_unix.cpp | 51 +++++++++-- SheepShaver/src/Unix/ppc_asm.S | 108 +++++++++++++++++++++--- SheepShaver/src/Unix/ppc_asm.tmpl | 25 ++++++ SheepShaver/src/Unix/sysdeps.h | 1 + SheepShaver/src/include/main.h | 1 + SheepShaver/src/include/xlowmem.h | 1 + SheepShaver/src/main.cpp | 7 +- 9 files changed, 207 insertions(+), 27 deletions(-) diff --git a/SheepShaver/src/BeOS/sysdeps.h b/SheepShaver/src/BeOS/sysdeps.h index 003781e3..0118e37f 100644 --- a/SheepShaver/src/BeOS/sysdeps.h +++ b/SheepShaver/src/BeOS/sysdeps.h @@ -36,6 +36,7 @@ #ifdef __POWERPC__ #define EMULATED_PPC 0 #define WORDS_BIGENDIAN 1 +#define SYSTEM_CLOBBERS_R2 1 #else #define EMULATED_PPC 1 #undef WORDS_BIGENDIAN diff --git a/SheepShaver/src/Unix/Linux/paranoia.cpp b/SheepShaver/src/Unix/Linux/paranoia.cpp index 6c14083f..95cbd919 100644 --- a/SheepShaver/src/Unix/Linux/paranoia.cpp +++ b/SheepShaver/src/Unix/Linux/paranoia.cpp @@ -42,7 +42,9 @@ const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack // Prototypes extern "C" void *get_sp(void); -extern "C" void set_r2(uint32 val); +extern "C" void *get_r2(void); +extern "C" void set_r2(void *); +extern "C" void *get_r13(void); extern void paranoia_check(void); static void sigusr2_handler(int sig, sigcontext_struct *sc); @@ -57,6 +59,12 @@ static void *sig_sc_regs = NULL; static uint32 sig_r2 = 0; +int raise(int sig) +{ + // Reimplement to get rid of access to r2 (TLS pointer) + return kill(getpid(), sig); +} + void paranoia_check(void) { char str[256]; @@ -95,8 +103,14 @@ void paranoia_check(void) } // Raise SIGUSR2 - set_r2(0xaffebad5); + TOC = get_r2(); + R13 = get_r13(); + set_r2((void *)0xaffebad5); raise(SIGUSR2); + if (TOC != get_r2()) + err = 6; + if (R13 != get_r13()) + err = 7; // Check error code switch (err) { @@ -115,6 +129,11 @@ void paranoia_check(void) case 5: printf("FATAL: sc->regs->gpr[2] in signal handler (%08lx) doesn't have expected value (%08x)\n", (uint32)sig_r2, 0xaffebad5); break; + case 6: + printf("FATAL: signal handler failed to restore initial r2 value (%08x, was %08x)\n", (uint32)get_r2(), (uint32)TOC); + break; + case 7: + printf("FATAL: signal handler failed to restore initial r13 value (%08x, was %08x)\n", get_r13(), (uint32)R13); } if (err) { printf("Maybe you need a different kernel?\n"); @@ -135,34 +154,40 @@ static void sigusr2_handler(int sig, sigcontext_struct *sc) sig_sp = get_sp(); if (sig_sp < sig_stack || sig_sp >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) { err = 1; - return; + goto ret; } // Check whether r4 points to info on the stack sig_r4 = sc; if (sig_r4 < sig_stack || sig_r4 >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) { err = 2; - return; + goto ret; } // Check whether r4 looks like a sigcontext sig_sc_signal = sc->signal; if (sig_sc_signal != SIGUSR2) { err = 3; - return; + goto ret; } // Check whether sc->regs points to info on the stack sig_sc_regs = sc->regs; if (sig_sc_regs < sig_stack || sig_sc_regs >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) { err = 4; - return; + goto ret; } // Check whether r2 still holds the value we set it to sig_r2 = sc->regs->gpr[2]; if (sig_r2 != 0xaffebad5) { err = 5; - return; + goto ret; } + + // Restore pointer to Thread Local Storage + ret: +#ifdef SYSTEM_CLOBBERS_R2 + sc->regs->gpr[2] = (unsigned long)TOC; +#endif } diff --git a/SheepShaver/src/Unix/main_unix.cpp b/SheepShaver/src/Unix/main_unix.cpp index b0660e69..5510ce7d 100644 --- a/SheepShaver/src/Unix/main_unix.cpp +++ b/SheepShaver/src/Unix/main_unix.cpp @@ -27,12 +27,14 @@ * is slightly different from the SysV ABI used by Linux: * - Stack frames are different (e.g. LR is stored in 8(r1) under * MacOS, but in 4(r1) under Linux) - * - There is no TOC under Linux; r2 is free for the user + * - There is a pointer to Thread Local Storage (TLS) under Linux with + * recent enough glibc. This is r2 in 32-bit mode and r13 in + * 64-bit mode (PowerOpen/AIX ABI) * - r13 is used as a small data pointer under Linux (but appearently * it is not used this way? To be sure, we specify -msdata=none * in the Makefile) - * - As there is no TOC, there are also no TVECTs under Linux; - * function pointers point directly to the function code + * - There are no TVECTs under Linux; function pointers point + * directly to the function code * The Execute*() functions have to account for this. Additionally, we * cannot simply call MacOS functions by getting their TVECT and jumping * to it. Such calls are done via the call_macos*() functions in @@ -284,7 +286,8 @@ static inline void sig_stack_release(void) // Global variables (exported) #if !EMULATED_PPC -void *TOC; // Small data pointer (r13) +void *TOC; // Pointer to Thread Local Storage (r2) +void *R13; // Pointer to .sdata section (r13 under Linux) #endif uint32 RAMBase; // Base address of Mac RAM uint32 RAMSize; // Size of Mac RAM @@ -370,8 +373,11 @@ static void sigill_handler(int sig, siginfo_t *sip, void *scp); // From asm_linux.S #if !EMULATED_PPC -extern "C" void *get_toc(void); extern "C" void *get_sp(void); +extern "C" void *get_r2(void); +extern "C" void set_r2(void *); +extern "C" void *get_r13(void); +extern "C" void set_r13(void *); extern "C" void flush_icache_range(uint32 start, uint32 end); extern "C" void jump_to_rom(uint32 entry, uint32 context); extern "C" void quit_emulator(void); @@ -482,8 +488,14 @@ int main(int argc, char **argv) printf(" %s\n", GetString(STR_ABOUT_TEXT2)); #if !EMULATED_PPC +#ifdef SYSTEM_CLOBBERS_R2 // Get TOC pointer - TOC = get_toc(); + TOC = get_r2(); +#endif +#ifdef SYSTEM_CLOBBERS_R13 + // Get r13 register + R13 = get_r13(); +#endif #endif #ifdef ENABLE_GTK @@ -1607,6 +1619,15 @@ static void sigusr2_handler(int sig, siginfo_t *sip, void *scp) if (*(int32 *)XLM_IRQ_NEST > 0) return; +#ifdef SYSTEM_CLOBBERS_R2 + // Restore pointer to Thread Local Storage + set_r2(TOC); +#endif +#ifdef SYSTEM_CLOBBERS_R13 + // Restore pointer to .sdata section + set_r13(R13); +#endif + // Disable MacOS stack sniffer WriteMacInt32(0x110, 0); @@ -1697,6 +1718,15 @@ static void sigsegv_handler(int sig, siginfo_t *sip, void *scp) // Get effective address uint32 addr = r->dar(); +#ifdef SYSTEM_CLOBBERS_R2 + // Restore pointer to Thread Local Storage + set_r2(TOC); +#endif +#ifdef SYSTEM_CLOBBERS_R13 + // Restore pointer to .sdata section + set_r13(R13); +#endif + #if ENABLE_VOSF // Handle screen fault. extern bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction); @@ -1946,6 +1976,15 @@ static void sigill_handler(int sig, siginfo_t *sip, void *scp) machine_regs *r = MACHINE_REGISTERS(scp); char str[256]; +#ifdef SYSTEM_CLOBBERS_R2 + // Restore pointer to Thread Local Storage + set_r2(TOC); +#endif +#ifdef SYSTEM_CLOBBERS_R13 + // Restore pointer to .sdata section + set_r13(R13); +#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)); if (mac_fault) { diff --git a/SheepShaver/src/Unix/ppc_asm.S b/SheepShaver/src/Unix/ppc_asm.S index 4930b5d7..16829a02 100644 --- a/SheepShaver/src/Unix/ppc_asm.S +++ b/SheepShaver/src/Unix/ppc_asm.S @@ -24,16 +24,6 @@ #define SAVE_FP_EXEC_68K 1 -/* - * void *get_toc(void) - Get TOC pointer (small data pointer r13 under Linux) - */ - - ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(get_toc) -C_SYMBOL_NAME(get_toc): - mr r3,r13 - blr - - /* * void *get_sp(void) - Get stack pointer */ @@ -45,7 +35,17 @@ C_SYMBOL_NAME(get_sp): /* - * void set_r2(uint32 val {r3}) - Set r2 + * void *get_r2(void) - Get r2 + */ + + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(get_r2) +C_SYMBOL_NAME(get_r2): + mr r3,r2 + blr + + +/* + * void set_r2(void *val {r3}) - Set r2 */ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(set_r2) @@ -54,6 +54,25 @@ C_SYMBOL_NAME(set_r2): blr +/* + * void *get_r13(void) - Get r13 (small data pointer under Linux) + */ + + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(get_r13) +C_SYMBOL_NAME(get_r13): + mr r3,r13 + blr + +/* + * void set_r13(void *val {r3}) - Set r13 (small data pointer under Linux) + */ + + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(set_r13) +C_SYMBOL_NAME(set_r13): + mr r13,r3 + blr + + /* * void flush_icache_range(void *start {r3}, void *end {r3}) - Flush D and I cache */ @@ -225,6 +244,7 @@ C_SYMBOL_NAME(jump_to_rom): // Restore PowerPC registers lwz r1,XLM_EMUL_RETURN_STACK(0) + RESTORE_SYSTEM_R2 lmw r13,20(r1) lfd f14,20+19*4+0*8(r1) lfd f15,20+19*4+1*8(r1) @@ -361,6 +381,7 @@ C_SYMBOL_NAME(jump_to_rom): stw r0,16(r1) stw r2,12(r1) stwu r1,-(24+16*4+15*8)(r1) + RESTORE_SYSTEM_R2 // Save 68k registers (M68kRegisters) stw r8,24+0*4(r1) // d[0]..d[7] @@ -397,7 +418,8 @@ C_SYMBOL_NAME(jump_to_rom): stfd f0,24+16*4+14*8(r1) // Execute native routine - lwz r13,XLM_TOC(0) + RESTORE_SYSTEM_R2 + RESTORE_SYSTEM_R13 addi r3,r1,24 mr r4,r24 bl C_SYMBOL_NAME(EmulOp) @@ -573,7 +595,8 @@ ASM_MACRO_START prolog ASM_MACRO_END ASM_MACRO_START epilog - lwz r13,XLM_TOC(0) + RESTORE_SYSTEM_R2 + RESTORE_SYSTEM_R13 lwz r0,64+4(r1) mtlr r0 addi r1,r1,64 @@ -701,6 +724,7 @@ C_SYMBOL_NAME(get_resource): lwz r2,XLM_RES_LIB_TOC(0) mtctr r0 bctrl + RESTORE_SYSTEM_R2 stw r3,56+8(r1) // Save handle // Call CheckLoad @@ -732,6 +756,7 @@ C_SYMBOL_NAME(get_1_resource): lwz r2,XLM_RES_LIB_TOC(0) mtctr r0 bctrl + RESTORE_SYSTEM_R2 stw r3,56+8(r1) // Save handle // Call CheckLoad @@ -763,6 +788,7 @@ C_SYMBOL_NAME(get_ind_resource): lwz r2,XLM_RES_LIB_TOC(0) mtctr r0 bctrl + RESTORE_SYSTEM_R2 stw r3,56+8(r1) // Save handle // Call CheckLoad @@ -794,6 +820,7 @@ C_SYMBOL_NAME(get_1_ind_resource): lwz r2,XLM_RES_LIB_TOC(0) mtctr r0 bctrl + RESTORE_SYSTEM_R2 stw r3,56+8(r1) // Save handle // Call CheckLoad @@ -825,6 +852,7 @@ C_SYMBOL_NAME(r_get_resource): lwz r2,XLM_RES_LIB_TOC(0) mtctr r0 bctrl + RESTORE_SYSTEM_R2 stw r3,56+8(r1) // Save handle // Call CheckLoad @@ -888,3 +916,57 @@ C_SYMBOL_NAME(ppc_interrupt): // Enter nanokernel mtlr r3 blr + + +/* + * Glue for glibc with TLS support which clobbers r2 + * + * The following is derived from dietlibc and only provides + * pass-through to kernel syscalls. You also lose asynchronous + * cancellation support. + */ + +#if defined(__linux__) +#define __NR_getpid 20 +#define __NR__newselect 142 + +#define syscall_weak(name,wsym,sym) \ +.text; \ +.type wsym,@function; \ +.weak wsym; \ +wsym: ; \ +.type sym,@function; \ +.global sym; \ +sym: \ + li 0,__NR_##name; \ + b __unified_syscall + +#define syscall(name,sym) \ +.text; \ +.type sym,@function; \ +.global sym; \ +sym: \ + li 0,__NR_##name; \ + b __unified_syscall + + + .type __unified_syscall,@function +__unified_syscall: + sc + bnslr+ + stwu 1,-16(1) + mflr 0 + stw 0,20(1) + stw 3,12(1) + bl __errno_location + lwz 0,12(1) + stw 0,0(3) + lwz 0,20(1) + mtlr 0 + addi 1,1,16 + blr + +/* name weak symbol symbol */ +syscall( getpid, getpid) +syscall_weak( _newselect, select, __select) +#endif diff --git a/SheepShaver/src/Unix/ppc_asm.tmpl b/SheepShaver/src/Unix/ppc_asm.tmpl index 20de7e5f..29588c0f 100644 --- a/SheepShaver/src/Unix/ppc_asm.tmpl +++ b/SheepShaver/src/Unix/ppc_asm.tmpl @@ -1,3 +1,27 @@ +/* Define usage of "reserved" registers */ +#if defined(__linux__) +#define SYSTEM_CLOBBERS_R2 1 /* Pointer to Thread Local Storage */ +#define SYSTEM_CLOBBERS_R13 1 /* Pointer to .sdata section */ +#endif + +#ifdef __ASSEMBLY__ +/* Helper macros */ +#ifdef SYSTEM_CLOBBERS_R2 +#define RESTORE_SYSTEM_R2 lwz r2,XLM_TOC(0) +#define SAVE_SYSTEM_R2 stw r2,XLM_TOC(0) +#else +#define RESTORE_SYSTEM_R2 +#define SAVE_SYSTEM_R2 +#endif +#ifdef SYSTEM_CLOBBERS_R13 +#define RESTORE_SYSTEM_R13 lwz r13,XLM_R13(0) +#define SAVE_SYSTEM_R13 stw r13,XLM_R13(0) +#else +#define RESTORE_SYSTEM_R13 +#define SAVE_SYSTEM_R13 +#endif + +/* Apple assembler perticularities */ #if (defined(__APPLE__) && defined(__MACH__)) #define C_SYMBOL_NAME(NAME) _ ## NAME #define ASM_MACRO_END .endmacro @@ -87,3 +111,4 @@ #define f30 30 #define f31 31 #endif +#endif diff --git a/SheepShaver/src/Unix/sysdeps.h b/SheepShaver/src/Unix/sysdeps.h index 2f3e81fd..d0508e95 100644 --- a/SheepShaver/src/Unix/sysdeps.h +++ b/SheepShaver/src/Unix/sysdeps.h @@ -82,6 +82,7 @@ // Otherwise, use Direct Addressing mode if NATMEM_OFFSET is set #if !defined(EMULATED_PPC) #define REAL_ADDRESSING 1 +#include "ppc_asm.tmpl" #elif defined(__CYGWIN__) #define DIRECT_ADDRESSING 1 #define DIRECT_ADDRESSING_HACK 1 diff --git a/SheepShaver/src/include/main.h b/SheepShaver/src/include/main.h index 9e85376e..f5fe639c 100644 --- a/SheepShaver/src/include/main.h +++ b/SheepShaver/src/include/main.h @@ -23,6 +23,7 @@ // Global variables extern void *TOC; // TOC pointer +extern void *R13; // r13 register extern uint32 KernelDataAddr; // Address of Kernel Data extern uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM extern uint32 PVR; // Theoretical PVR diff --git a/SheepShaver/src/include/xlowmem.h b/SheepShaver/src/include/xlowmem.h index 1bb3a477..a4c2e2a1 100644 --- a/SheepShaver/src/include/xlowmem.h +++ b/SheepShaver/src/include/xlowmem.h @@ -47,6 +47,7 @@ #define XLM_R_GET_RESOURCE 0x2848 // Pointer to native RGetResource() routine #define XLM_EXEC_RETURN_OPCODE 0x284c // EXEC_RETURN opcode for Execute68k() #define XLM_ZERO_PAGE 0x2850 // Pointer to read-only page with all bits set to 0 +#define XLM_R13 0x2854 // Pointer to .sdata section (Linux) #define XLM_ETHER_INIT 0x28c0 // Pointer to ethernet InitStreamModule() function #define XLM_ETHER_TERM 0x28c4 // Pointer to ethernet TerminateStreamModule() function diff --git a/SheepShaver/src/main.cpp b/SheepShaver/src/main.cpp index efa96408..6a14308b 100644 --- a/SheepShaver/src/main.cpp +++ b/SheepShaver/src/main.cpp @@ -232,7 +232,12 @@ bool InitAll(void) WriteMacInt16(XLM_EXEC_RETURN_OPCODE, M68K_EXEC_RETURN); // For Execute68k() (RTS from the executed 68k code will jump here and end 68k mode) 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 +#ifdef SYSTEM_CLOBBERS_R2 + WriteMacInt32(XLM_TOC, (uint32)TOC); // TOC pointer of emulator +#endif +#ifdef SYSTEM_CLOBBERS_R13 + WriteMacInt32(XLM_R13, (uint32)R13); // TLS register +#endif #endif WriteMacInt32(XLM_ETHER_INIT, NativeFunction(NATIVE_ETHER_INIT)); // DLPI ethernet driver functions WriteMacInt32(XLM_ETHER_TERM, NativeFunction(NATIVE_ETHER_TERM));