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)
This commit is contained in:
gbeauche 2005-02-27 21:52:06 +00:00
parent f29eb7dd1d
commit 663facbf97
9 changed files with 207 additions and 27 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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));