67 |
|
* ExecutePPC (or any function that might cause a mode switch). The signal |
68 |
|
* stack is restored before exiting the SIGUSR2 handler. |
69 |
|
* |
70 |
< |
* There is apparently another problem when processing signals. In |
71 |
< |
* fullscreen mode, we get quick updates of the mouse position. This |
72 |
< |
* causes an increased number of calls to TriggerInterrupt(). And, |
73 |
< |
* since IRQ_NEST is not fully handled atomically, nested calls to |
74 |
< |
* ppc_interrupt() may cause stack corruption to eventually crash the |
75 |
< |
* emulator. |
76 |
< |
* |
77 |
< |
* FIXME: |
78 |
< |
* The current solution is to allocate another signal stack when |
79 |
< |
* processing ppc_interrupt(). However, it may be better to detect |
80 |
< |
* the INTFLAG_ADB case and handle it specifically with some extra mutex? |
70 |
> |
* Note that POSIX standard says you can't modify the alternate |
71 |
> |
* signal stack while the process is executing on it. There is a |
72 |
> |
* hackaround though: we install a trampoline SIGUSR2 handler that |
73 |
> |
* sets up an alternate stack itself and calls the real handler. |
74 |
> |
* Then, when we call sigaltstack() there, we no longer get an EPERM, |
75 |
> |
* i.e. it now works. |
76 |
|
* |
77 |
|
* TODO: |
78 |
|
* check if SIGSEGV handler works for all registers (including FP!) |
109 |
|
#include "user_strings.h" |
110 |
|
#include "vm_alloc.h" |
111 |
|
#include "sigsegv.h" |
112 |
+ |
#include "sigregs.h" |
113 |
|
|
114 |
|
#define DEBUG 0 |
115 |
|
#include "debug.h" |
154 |
|
// Interrupts in native mode? |
155 |
|
#define INTERRUPTS_IN_NATIVE_MODE 1 |
156 |
|
|
161 |
– |
// Number of alternate stacks for signal handlers? |
162 |
– |
#define SIG_STACK_COUNT 4 |
163 |
– |
|
157 |
|
|
158 |
|
// Constants |
159 |
|
const char ROM_FILE_NAME[] = "ROM"; |
168 |
|
const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack |
169 |
|
|
170 |
|
|
178 |
– |
#if !EMULATED_PPC |
179 |
– |
struct sigregs { |
180 |
– |
uint32 nip; |
181 |
– |
uint32 link; |
182 |
– |
uint32 ctr; |
183 |
– |
uint32 msr; |
184 |
– |
uint32 xer; |
185 |
– |
uint32 ccr; |
186 |
– |
uint32 gpr[32]; |
187 |
– |
}; |
188 |
– |
|
189 |
– |
#if defined(__linux__) |
190 |
– |
#include <sys/ucontext.h> |
191 |
– |
#define MACHINE_REGISTERS(scp) ((machine_regs *)(((ucontext_t *)scp)->uc_mcontext.regs)) |
192 |
– |
|
193 |
– |
struct machine_regs : public pt_regs |
194 |
– |
{ |
195 |
– |
u_long & cr() { return pt_regs::ccr; } |
196 |
– |
uint32 cr() const { return pt_regs::ccr; } |
197 |
– |
uint32 lr() const { return pt_regs::link; } |
198 |
– |
uint32 ctr() const { return pt_regs::ctr; } |
199 |
– |
uint32 xer() const { return pt_regs::xer; } |
200 |
– |
uint32 msr() const { return pt_regs::msr; } |
201 |
– |
uint32 dar() const { return pt_regs::dar; } |
202 |
– |
u_long & pc() { return pt_regs::nip; } |
203 |
– |
uint32 pc() const { return pt_regs::nip; } |
204 |
– |
u_long & gpr(int i) { return pt_regs::gpr[i]; } |
205 |
– |
uint32 gpr(int i) const { return pt_regs::gpr[i]; } |
206 |
– |
}; |
207 |
– |
#endif |
208 |
– |
|
209 |
– |
#if defined(__NetBSD__) |
210 |
– |
#include <sys/ucontext.h> |
211 |
– |
#define MACHINE_REGISTERS(scp) ((machine_regs *)&(((ucontext_t *)scp)->uc_mcontext)) |
212 |
– |
|
213 |
– |
struct machine_regs : public mcontext_t |
214 |
– |
{ |
215 |
– |
long & cr() { return __gregs[_REG_CR]; } |
216 |
– |
uint32 cr() const { return __gregs[_REG_CR]; } |
217 |
– |
uint32 lr() const { return __gregs[_REG_LR]; } |
218 |
– |
uint32 ctr() const { return __gregs[_REG_CTR]; } |
219 |
– |
uint32 xer() const { return __gregs[_REG_XER]; } |
220 |
– |
uint32 msr() const { return __gregs[_REG_MSR]; } |
221 |
– |
uint32 dar() const { return (uint32)(((siginfo_t *)(((unsigned long)this) - offsetof(ucontext_t, uc_mcontext))) - 1)->si_addr; } /* HACK */ |
222 |
– |
long & pc() { return __gregs[_REG_PC]; } |
223 |
– |
uint32 pc() const { return __gregs[_REG_PC]; } |
224 |
– |
long & gpr(int i) { return __gregs[_REG_R0 + i]; } |
225 |
– |
uint32 gpr(int i) const { return __gregs[_REG_R0 + i]; } |
226 |
– |
}; |
227 |
– |
#endif |
228 |
– |
|
229 |
– |
#if defined(__APPLE__) && defined(__MACH__) |
230 |
– |
#include <sys/signal.h> |
231 |
– |
extern "C" int sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss); |
232 |
– |
|
233 |
– |
#include <sys/ucontext.h> |
234 |
– |
#define MACHINE_REGISTERS(scp) ((machine_regs *)(((ucontext_t *)scp)->uc_mcontext)) |
235 |
– |
|
236 |
– |
struct machine_regs : public mcontext |
237 |
– |
{ |
238 |
– |
uint32 & cr() { return ss.cr; } |
239 |
– |
uint32 cr() const { return ss.cr; } |
240 |
– |
uint32 lr() const { return ss.lr; } |
241 |
– |
uint32 ctr() const { return ss.ctr; } |
242 |
– |
uint32 xer() const { return ss.xer; } |
243 |
– |
uint32 msr() const { return ss.srr1; } |
244 |
– |
uint32 dar() const { return es.dar; } |
245 |
– |
uint32 & pc() { return ss.srr0; } |
246 |
– |
uint32 pc() const { return ss.srr0; } |
247 |
– |
uint32 & gpr(int i) { return (&ss.r0)[i]; } |
248 |
– |
uint32 gpr(int i) const { return (&ss.r0)[i]; } |
249 |
– |
}; |
250 |
– |
#endif |
251 |
– |
|
252 |
– |
static void build_sigregs(sigregs *srp, machine_regs *mrp) |
253 |
– |
{ |
254 |
– |
srp->nip = mrp->pc(); |
255 |
– |
srp->link = mrp->lr(); |
256 |
– |
srp->ctr = mrp->ctr(); |
257 |
– |
srp->msr = mrp->msr(); |
258 |
– |
srp->xer = mrp->xer(); |
259 |
– |
srp->ccr = mrp->cr(); |
260 |
– |
for (int i = 0; i < 32; i++) |
261 |
– |
srp->gpr[i] = mrp->gpr(i); |
262 |
– |
} |
263 |
– |
|
264 |
– |
static struct sigaltstack sig_stacks[SIG_STACK_COUNT]; // Stacks for signal handlers |
265 |
– |
static int sig_stack_id = 0; // Stack slot currently used |
266 |
– |
|
267 |
– |
static inline int sig_stack_acquire(void) |
268 |
– |
{ |
269 |
– |
if (sig_stack_id >= SIG_STACK_COUNT) { |
270 |
– |
printf("FATAL: signal stack overflow\n"); |
271 |
– |
return -1; |
272 |
– |
} |
273 |
– |
return sigaltstack(&sig_stacks[sig_stack_id++], NULL); |
274 |
– |
} |
275 |
– |
|
276 |
– |
static inline int sig_stack_release(void) |
277 |
– |
{ |
278 |
– |
if (sig_stack_id <= 0) { |
279 |
– |
printf("FATAL: signal stack underflow\n"); |
280 |
– |
return -1; |
281 |
– |
} |
282 |
– |
return sigaltstack(&sig_stacks[--sig_stack_id], NULL); |
283 |
– |
} |
284 |
– |
#endif |
285 |
– |
|
286 |
– |
|
171 |
|
// Global variables (exported) |
172 |
|
#if !EMULATED_PPC |
173 |
< |
void *TOC; // Pointer to Thread Local Storage (r2) |
174 |
< |
void *R13; // Pointer to .sdata section (r13 under Linux) |
173 |
> |
void *TOC = NULL; // Pointer to Thread Local Storage (r2) |
174 |
> |
void *R13 = NULL; // Pointer to .sdata section (r13 under Linux) |
175 |
|
#endif |
176 |
|
uint32 RAMBase; // Base address of Mac RAM |
177 |
|
uint32 RAMSize; // Size of Mac RAM |
224 |
|
#else |
225 |
|
static struct sigaction sigsegv_action; // Data access exception signal (of emulator thread) |
226 |
|
static struct sigaction sigill_action; // Illegal instruction signal (of emulator thread) |
227 |
+ |
static struct sigaltstack sig_stack; // Stack for signal handlers |
228 |
+ |
static struct sigaltstack extra_stack; // Stack for SIGSEGV inside interrupt handler |
229 |
|
static bool emul_thread_fatal = false; // Flag: MacOS thread crashed, tick thread shall dump debug output |
230 |
|
static sigregs sigsegv_regs; // Register dump when crashed |
231 |
|
static const char *crash_reason = NULL; // Reason of the crash (SIGSEGV, SIGBUS, SIGILL) |
251 |
|
extern void exit_emul_ppc(void); |
252 |
|
sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t); |
253 |
|
#else |
254 |
< |
static void sigusr2_handler(int sig, siginfo_t *sip, void *scp); |
254 |
> |
extern "C" void sigusr2_handler_init(int sig, siginfo_t *sip, void *scp); |
255 |
> |
extern "C" void sigusr2_handler(int sig, siginfo_t *sip, void *scp); |
256 |
|
static void sigsegv_handler(int sig, siginfo_t *sip, void *scp); |
257 |
|
static void sigill_handler(int sig, siginfo_t *sip, void *scp); |
258 |
|
#endif |
452 |
|
|
453 |
|
#if !EMULATED_PPC |
454 |
|
// Create and install stacks for signal handlers |
455 |
< |
for (int i = 0; i < SIG_STACK_COUNT; i++) { |
456 |
< |
void *sig_stack = malloc(SIG_STACK_SIZE); |
457 |
< |
D(bug("Signal stack %d at %p\n", i, sig_stack)); |
458 |
< |
if (sig_stack == NULL) { |
459 |
< |
ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); |
573 |
< |
goto quit; |
574 |
< |
} |
575 |
< |
sig_stacks[i].ss_sp = sig_stack; |
576 |
< |
sig_stacks[i].ss_flags = 0; |
577 |
< |
sig_stacks[i].ss_size = SIG_STACK_SIZE; |
455 |
> |
sig_stack.ss_sp = malloc(SIG_STACK_SIZE); |
456 |
> |
D(bug("Signal stack at %p\n", sig_stack.ss_sp)); |
457 |
> |
if (sig_stack.ss_sp == NULL) { |
458 |
> |
ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); |
459 |
> |
goto quit; |
460 |
|
} |
461 |
< |
if (sig_stack_acquire() < 0) { |
461 |
> |
sig_stack.ss_flags = 0; |
462 |
> |
sig_stack.ss_size = SIG_STACK_SIZE; |
463 |
> |
if (sigaltstack(&sig_stack, NULL) < 0) { |
464 |
|
sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno)); |
465 |
|
ErrorAlert(str); |
466 |
|
goto quit; |
467 |
|
} |
468 |
+ |
extra_stack.ss_sp = malloc(SIG_STACK_SIZE); |
469 |
+ |
D(bug("Extra stack at %p\n", extra_stack.ss_sp)); |
470 |
+ |
if (extra_stack.ss_sp == NULL) { |
471 |
+ |
ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); |
472 |
+ |
goto quit; |
473 |
+ |
} |
474 |
+ |
extra_stack.ss_flags = 0; |
475 |
+ |
extra_stack.ss_size = SIG_STACK_SIZE; |
476 |
|
#endif |
477 |
|
|
478 |
|
#if !EMULATED_PPC |
671 |
|
case 0x8000: // 7450 |
672 |
|
case 0x8001: // 7455 |
673 |
|
case 0x8002: // 7457 |
674 |
+ |
case 0x8003: // 7447A |
675 |
|
case 0x0039: // 970 |
676 |
|
PVR = 0x000c0000; // 7400 |
677 |
|
break; |
864 |
|
#if !EMULATED_PPC |
865 |
|
// Install interrupt signal handler |
866 |
|
sigemptyset(&sigusr2_action.sa_mask); |
867 |
< |
sigusr2_action.sa_sigaction = sigusr2_handler; |
867 |
> |
sigusr2_action.sa_sigaction = sigusr2_handler_init; |
868 |
|
sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO; |
869 |
|
#ifdef HAVE_SIGNAL_SA_RESTORER |
870 |
|
sigusr2_action.sa_restorer = NULL; |
927 |
|
sigaction(SIGILL, &sigill_action, NULL); |
928 |
|
|
929 |
|
// Delete stacks for signal handlers |
930 |
< |
for (int i = 0; i < SIG_STACK_COUNT; i++) { |
931 |
< |
void *sig_stack = sig_stacks[i].ss_sp; |
932 |
< |
if (sig_stack) |
933 |
< |
free(sig_stack); |
1041 |
< |
} |
930 |
> |
if (sig_stack.ss_sp) |
931 |
> |
free(sig_stack.ss_sp); |
932 |
> |
if (extra_stack.ss_sp) |
933 |
> |
free(extra_stack.ss_sp); |
934 |
|
#endif |
935 |
|
|
936 |
|
// Deinitialize everything |
1303 |
|
} |
1304 |
|
|
1305 |
|
uint64 end = GetTicks_usec(); |
1306 |
< |
D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start))); |
1306 |
> |
D(bug("%lld ticks in %lld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start))); |
1307 |
|
return NULL; |
1308 |
|
} |
1309 |
|
|
1427 |
|
#if !EMULATED_PPC |
1428 |
|
void TriggerInterrupt(void) |
1429 |
|
{ |
1430 |
< |
if (ready_for_signals) |
1430 |
> |
if (ready_for_signals) { |
1431 |
> |
idle_resume(); |
1432 |
|
pthread_kill(emul_thread, SIGUSR2); |
1433 |
+ |
} |
1434 |
|
} |
1435 |
|
#endif |
1436 |
|
|
1485 |
|
*/ |
1486 |
|
|
1487 |
|
#if !EMULATED_PPC |
1488 |
< |
static void sigusr2_handler(int sig, siginfo_t *sip, void *scp) |
1488 |
> |
void sigusr2_handler(int sig, siginfo_t *sip, void *scp) |
1489 |
|
{ |
1490 |
|
machine_regs *r = MACHINE_REGISTERS(scp); |
1491 |
|
|
1598 |
– |
#ifdef USE_SDL_VIDEO |
1599 |
– |
// We must fill in the events queue in the same thread that did call SDL_SetVideoMode() |
1600 |
– |
SDL_PumpEvents(); |
1601 |
– |
#endif |
1602 |
– |
|
1603 |
– |
// Do nothing if interrupts are disabled |
1604 |
– |
if (*(int32 *)XLM_IRQ_NEST > 0) |
1605 |
– |
return; |
1606 |
– |
|
1492 |
|
#ifdef SYSTEM_CLOBBERS_R2 |
1493 |
|
// Restore pointer to Thread Local Storage |
1494 |
|
set_r2(TOC); |
1498 |
|
set_r13(R13); |
1499 |
|
#endif |
1500 |
|
|
1501 |
+ |
#ifdef USE_SDL_VIDEO |
1502 |
+ |
// We must fill in the events queue in the same thread that did call SDL_SetVideoMode() |
1503 |
+ |
SDL_PumpEvents(); |
1504 |
+ |
#endif |
1505 |
+ |
|
1506 |
+ |
// Do nothing if interrupts are disabled |
1507 |
+ |
if (*(int32 *)XLM_IRQ_NEST > 0) |
1508 |
+ |
return; |
1509 |
+ |
|
1510 |
|
// Disable MacOS stack sniffer |
1511 |
|
WriteMacInt32(0x110, 0); |
1512 |
|
|
1523 |
|
// 68k emulator inactive, in nanokernel? |
1524 |
|
if (r->gpr(1) != KernelDataAddr) { |
1525 |
|
|
1526 |
< |
// Set extra stack for nested interrupts |
1527 |
< |
sig_stack_acquire(); |
1526 |
> |
// Set extra stack for SIGSEGV handler |
1527 |
> |
sigaltstack(&extra_stack, NULL); |
1528 |
|
|
1529 |
|
// Prepare for 68k interrupt level 1 |
1530 |
|
WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1); |
1537 |
|
else |
1538 |
|
ppc_interrupt(ROM_BASE + 0x312a3c, KernelDataAddr); |
1539 |
|
|
1540 |
< |
// Reset normal signal stack |
1541 |
< |
sig_stack_release(); |
1540 |
> |
// Reset normal stack |
1541 |
> |
sigaltstack(&sig_stack, NULL); |
1542 |
|
} |
1543 |
|
break; |
1544 |
|
#endif |
1549 |
|
if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) { |
1550 |
|
|
1551 |
|
// Set extra stack for SIGSEGV handler |
1552 |
< |
sig_stack_acquire(); |
1552 |
> |
sigaltstack(&extra_stack, NULL); |
1553 |
|
#if 1 |
1554 |
|
// Execute full 68k interrupt routine |
1555 |
|
M68kRegisters r; |
1575 |
|
} |
1576 |
|
} |
1577 |
|
#endif |
1578 |
< |
// Reset normal signal stack |
1579 |
< |
sig_stack_release(); |
1578 |
> |
// Reset normal stack |
1579 |
> |
sigaltstack(&sig_stack, NULL); |
1580 |
|
} |
1581 |
|
break; |
1582 |
|
#endif |