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!) |
153 |
|
// Interrupts in native mode? |
154 |
|
#define INTERRUPTS_IN_NATIVE_MODE 1 |
155 |
|
|
161 |
– |
// Number of alternate stacks for signal handlers? |
162 |
– |
#define SIG_STACK_COUNT 4 |
163 |
– |
|
156 |
|
|
157 |
|
// Constants |
158 |
|
const char ROM_FILE_NAME[] = "ROM"; |
252 |
|
for (int i = 0; i < 32; i++) |
253 |
|
srp->gpr[i] = mrp->gpr(i); |
254 |
|
} |
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 |
– |
} |
255 |
|
#endif |
256 |
|
|
257 |
|
|
311 |
|
#else |
312 |
|
static struct sigaction sigsegv_action; // Data access exception signal (of emulator thread) |
313 |
|
static struct sigaction sigill_action; // Illegal instruction signal (of emulator thread) |
314 |
+ |
static struct sigaltstack sig_stack; // Stack for signal handlers |
315 |
+ |
static struct sigaltstack extra_stack; // Stack for SIGSEGV inside interrupt handler |
316 |
|
static bool emul_thread_fatal = false; // Flag: MacOS thread crashed, tick thread shall dump debug output |
317 |
|
static sigregs sigsegv_regs; // Register dump when crashed |
318 |
|
static const char *crash_reason = NULL; // Reason of the crash (SIGSEGV, SIGBUS, SIGILL) |
338 |
|
extern void exit_emul_ppc(void); |
339 |
|
sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t); |
340 |
|
#else |
341 |
< |
static void sigusr2_handler(int sig, siginfo_t *sip, void *scp); |
341 |
> |
extern "C" void sigusr2_handler_init(int sig, siginfo_t *sip, void *scp); |
342 |
> |
extern "C" void sigusr2_handler(int sig, siginfo_t *sip, void *scp); |
343 |
|
static void sigsegv_handler(int sig, siginfo_t *sip, void *scp); |
344 |
|
static void sigill_handler(int sig, siginfo_t *sip, void *scp); |
345 |
|
#endif |
539 |
|
|
540 |
|
#if !EMULATED_PPC |
541 |
|
// Create and install stacks for signal handlers |
542 |
< |
for (int i = 0; i < SIG_STACK_COUNT; i++) { |
543 |
< |
void *sig_stack = malloc(SIG_STACK_SIZE); |
544 |
< |
D(bug("Signal stack %d at %p\n", i, sig_stack)); |
545 |
< |
if (sig_stack == NULL) { |
546 |
< |
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; |
542 |
> |
sig_stack.ss_sp = malloc(SIG_STACK_SIZE); |
543 |
> |
D(bug("Signal stack at %p\n", sig_stack.ss_sp)); |
544 |
> |
if (sig_stack.ss_sp == NULL) { |
545 |
> |
ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); |
546 |
> |
goto quit; |
547 |
|
} |
548 |
< |
if (sig_stack_acquire() < 0) { |
548 |
> |
sig_stack.ss_flags = 0; |
549 |
> |
sig_stack.ss_size = SIG_STACK_SIZE; |
550 |
> |
if (sigaltstack(&sig_stack, NULL) < 0) { |
551 |
|
sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno)); |
552 |
|
ErrorAlert(str); |
553 |
|
goto quit; |
554 |
|
} |
555 |
+ |
extra_stack.ss_sp = malloc(SIG_STACK_SIZE); |
556 |
+ |
D(bug("Extra stack at %p\n", extra_stack.ss_sp)); |
557 |
+ |
if (extra_stack.ss_sp == NULL) { |
558 |
+ |
ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); |
559 |
+ |
goto quit; |
560 |
+ |
} |
561 |
+ |
extra_stack.ss_flags = 0; |
562 |
+ |
extra_stack.ss_size = SIG_STACK_SIZE; |
563 |
|
#endif |
564 |
|
|
565 |
|
#if !EMULATED_PPC |
950 |
|
#if !EMULATED_PPC |
951 |
|
// Install interrupt signal handler |
952 |
|
sigemptyset(&sigusr2_action.sa_mask); |
953 |
< |
sigusr2_action.sa_sigaction = sigusr2_handler; |
953 |
> |
sigusr2_action.sa_sigaction = sigusr2_handler_init; |
954 |
|
sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO; |
955 |
|
#ifdef HAVE_SIGNAL_SA_RESTORER |
956 |
|
sigusr2_action.sa_restorer = NULL; |
1013 |
|
sigaction(SIGILL, &sigill_action, NULL); |
1014 |
|
|
1015 |
|
// Delete stacks for signal handlers |
1016 |
< |
for (int i = 0; i < SIG_STACK_COUNT; i++) { |
1017 |
< |
void *sig_stack = sig_stacks[i].ss_sp; |
1018 |
< |
if (sig_stack) |
1019 |
< |
free(sig_stack); |
1041 |
< |
} |
1016 |
> |
if (sig_stack.ss_sp) |
1017 |
> |
free(sig_stack.ss_sp); |
1018 |
> |
if (extra_stack.ss_sp) |
1019 |
> |
free(extra_stack.ss_sp); |
1020 |
|
#endif |
1021 |
|
|
1022 |
|
// Deinitialize everything |
1569 |
|
*/ |
1570 |
|
|
1571 |
|
#if !EMULATED_PPC |
1572 |
< |
static void sigusr2_handler(int sig, siginfo_t *sip, void *scp) |
1572 |
> |
void sigusr2_handler(int sig, siginfo_t *sip, void *scp) |
1573 |
|
{ |
1574 |
|
machine_regs *r = MACHINE_REGISTERS(scp); |
1575 |
|
|
1607 |
|
// 68k emulator inactive, in nanokernel? |
1608 |
|
if (r->gpr(1) != KernelDataAddr) { |
1609 |
|
|
1610 |
< |
// Set extra stack for nested interrupts |
1611 |
< |
sig_stack_acquire(); |
1610 |
> |
// Set extra stack for SIGSEGV handler |
1611 |
> |
sigaltstack(&extra_stack, NULL); |
1612 |
|
|
1613 |
|
// Prepare for 68k interrupt level 1 |
1614 |
|
WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1); |
1621 |
|
else |
1622 |
|
ppc_interrupt(ROM_BASE + 0x312a3c, KernelDataAddr); |
1623 |
|
|
1624 |
< |
// Reset normal signal stack |
1625 |
< |
sig_stack_release(); |
1624 |
> |
// Reset normal stack |
1625 |
> |
sigaltstack(&sig_stack, NULL); |
1626 |
|
} |
1627 |
|
break; |
1628 |
|
#endif |
1633 |
|
if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) { |
1634 |
|
|
1635 |
|
// Set extra stack for SIGSEGV handler |
1636 |
< |
sig_stack_acquire(); |
1636 |
> |
sigaltstack(&extra_stack, NULL); |
1637 |
|
#if 1 |
1638 |
|
// Execute full 68k interrupt routine |
1639 |
|
M68kRegisters r; |
1659 |
|
} |
1660 |
|
} |
1661 |
|
#endif |
1662 |
< |
// Reset normal signal stack |
1663 |
< |
sig_stack_release(); |
1662 |
> |
// Reset normal stack |
1663 |
> |
sigaltstack(&sig_stack, NULL); |
1664 |
|
} |
1665 |
|
break; |
1666 |
|
#endif |