mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-12-25 17:29:19 +00:00
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:
parent
f29eb7dd1d
commit
663facbf97
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
#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));
|
||||
|
Loading…
Reference in New Issue
Block a user