65 |
|
* ExecutePPC (or any function that might cause a mode switch). The signal |
66 |
|
* stack is restored before exiting the SIGUSR2 handler. |
67 |
|
* |
68 |
+ |
* There is apparently another problem when processing signals. In |
69 |
+ |
* fullscreen mode, we get quick updates of the mouse position. This |
70 |
+ |
* causes an increased number of calls to TriggerInterrupt(). And, |
71 |
+ |
* since IRQ_NEST is not fully handled atomically, nested calls to |
72 |
+ |
* ppc_interrupt() may cause stack corruption to eventually crash the |
73 |
+ |
* emulator. |
74 |
+ |
* |
75 |
+ |
* FIXME: |
76 |
+ |
* The current solution is to allocate another signal stack when |
77 |
+ |
* processing ppc_interrupt(). However, it may be better to detect |
78 |
+ |
* the INTFLAG_ADB case and handle it specifically with some extra mutex? |
79 |
+ |
* |
80 |
|
* TODO: |
81 |
|
* check if SIGSEGV handler works for all registers (including FP!) |
82 |
|
*/ |
156 |
|
// Interrupts in native mode? |
157 |
|
#define INTERRUPTS_IN_NATIVE_MODE 1 |
158 |
|
|
159 |
+ |
// Number of alternate stacks for signal handlers? |
160 |
+ |
#define SIG_STACK_COUNT 4 |
161 |
+ |
|
162 |
|
|
163 |
|
// Constants |
164 |
|
const char ROM_FILE_NAME[] = "ROM"; |
233 |
|
for (int i = 0; i < 32; i++) |
234 |
|
srp->gpr[i] = mrp->gpr(i); |
235 |
|
} |
236 |
+ |
|
237 |
+ |
static struct sigaltstack sig_stacks[SIG_STACK_COUNT]; // Stacks for signal handlers |
238 |
+ |
static int sig_stack_id = 0; // Stack slot currently used |
239 |
+ |
|
240 |
+ |
static inline void sig_stack_acquire(void) |
241 |
+ |
{ |
242 |
+ |
if (++sig_stack_id == SIG_STACK_COUNT) { |
243 |
+ |
printf("FATAL: signal stack overflow\n"); |
244 |
+ |
return; |
245 |
+ |
} |
246 |
+ |
sigaltstack(&sig_stacks[sig_stack_id], NULL); |
247 |
+ |
} |
248 |
+ |
|
249 |
+ |
static inline void sig_stack_release(void) |
250 |
+ |
{ |
251 |
+ |
if (--sig_stack_id < 0) { |
252 |
+ |
printf("FATAL: signal stack underflow\n"); |
253 |
+ |
return; |
254 |
+ |
} |
255 |
+ |
sigaltstack(&sig_stacks[sig_stack_id], NULL); |
256 |
+ |
} |
257 |
|
#endif |
258 |
|
|
259 |
|
|
302 |
|
#else |
303 |
|
static struct sigaction sigsegv_action; // Data access exception signal (of emulator thread) |
304 |
|
static struct sigaction sigill_action; // Illegal instruction signal (of emulator thread) |
269 |
– |
static void *sig_stack = NULL; // Stack for signal handlers |
270 |
– |
static void *extra_stack = NULL; // Stack for SIGSEGV inside interrupt handler |
305 |
|
static bool emul_thread_fatal = false; // Flag: MacOS thread crashed, tick thread shall dump debug output |
306 |
|
static sigregs sigsegv_regs; // Register dump when crashed |
307 |
|
static const char *crash_reason = NULL; // Reason of the crash (SIGSEGV, SIGBUS, SIGILL) |
843 |
|
|
844 |
|
#if !EMULATED_PPC |
845 |
|
// Create and install stacks for signal handlers |
846 |
< |
sig_stack = malloc(SIG_STACK_SIZE); |
847 |
< |
D(bug("Signal stack at %p\n", sig_stack)); |
848 |
< |
if (sig_stack == NULL) { |
849 |
< |
ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); |
850 |
< |
goto quit; |
851 |
< |
} |
852 |
< |
extra_stack = malloc(SIG_STACK_SIZE); |
853 |
< |
D(bug("Extra stack at %p\n", extra_stack)); |
854 |
< |
if (extra_stack == NULL) { |
855 |
< |
ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); |
822 |
< |
goto quit; |
846 |
> |
for (int i = 0; i < SIG_STACK_COUNT; i++) { |
847 |
> |
void *sig_stack = malloc(SIG_STACK_SIZE); |
848 |
> |
D(bug("Signal stack %d at %p\n", i, sig_stack)); |
849 |
> |
if (sig_stack == NULL) { |
850 |
> |
ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); |
851 |
> |
goto quit; |
852 |
> |
} |
853 |
> |
sig_stacks[i].ss_sp = sig_stack; |
854 |
> |
sig_stacks[i].ss_flags = 0; |
855 |
> |
sig_stacks[i].ss_size = SIG_STACK_SIZE; |
856 |
|
} |
857 |
< |
struct sigaltstack new_stack; |
858 |
< |
new_stack.ss_sp = sig_stack; |
826 |
< |
new_stack.ss_flags = 0; |
827 |
< |
new_stack.ss_size = SIG_STACK_SIZE; |
828 |
< |
if (sigaltstack(&new_stack, NULL) < 0) { |
857 |
> |
sig_stack_id = 0; |
858 |
> |
if (sigaltstack(&sig_stacks[0], NULL) < 0) { |
859 |
|
sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno)); |
860 |
|
ErrorAlert(str); |
861 |
|
goto quit; |
959 |
|
sigill_action.sa_handler = SIG_DFL; |
960 |
|
sigill_action.sa_flags = 0; |
961 |
|
sigaction(SIGILL, &sigill_action, NULL); |
962 |
+ |
|
963 |
+ |
// Delete stacks for signal handlers |
964 |
+ |
for (int i = 0; i < SIG_STACK_COUNT; i++) { |
965 |
+ |
void *sig_stack = sig_stacks[i].ss_sp; |
966 |
+ |
if (sig_stack) |
967 |
+ |
free(sig_stack); |
968 |
+ |
} |
969 |
|
#endif |
970 |
|
|
971 |
|
// Save NVRAM |
1494 |
|
case MODE_NATIVE: |
1495 |
|
// 68k emulator inactive, in nanokernel? |
1496 |
|
if (r->gpr(1) != KernelDataAddr) { |
1497 |
+ |
|
1498 |
+ |
// Set extra stack for nested interrupts |
1499 |
+ |
sig_stack_acquire(); |
1500 |
+ |
|
1501 |
|
// Prepare for 68k interrupt level 1 |
1502 |
|
WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1); |
1503 |
|
WriteMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc, ReadMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc) | ntohl(kernel_data->v[0x674 >> 2])); |
1504 |
|
|
1505 |
|
// Execute nanokernel interrupt routine (this will activate the 68k emulator) |
1506 |
< |
atomic_add((int32 *)XLM_IRQ_NEST, 1); |
1506 |
> |
DisableInterrupt(); |
1507 |
|
if (ROMType == ROMTYPE_NEWWORLD) |
1508 |
|
ppc_interrupt(ROM_BASE + 0x312b1c, KernelDataAddr); |
1509 |
|
else |
1510 |
|
ppc_interrupt(ROM_BASE + 0x312a3c, KernelDataAddr); |
1511 |
+ |
|
1512 |
+ |
// Reset normal signal stack |
1513 |
+ |
sig_stack_release(); |
1514 |
|
} |
1515 |
|
break; |
1516 |
|
#endif |
1521 |
|
if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) { |
1522 |
|
|
1523 |
|
// Set extra stack for SIGSEGV handler |
1524 |
< |
struct sigaltstack new_stack; |
1481 |
< |
new_stack.ss_sp = extra_stack; |
1482 |
< |
new_stack.ss_flags = 0; |
1483 |
< |
new_stack.ss_size = SIG_STACK_SIZE; |
1484 |
< |
sigaltstack(&new_stack, NULL); |
1524 |
> |
sig_stack_acquire(); |
1525 |
|
#if 1 |
1526 |
|
// Execute full 68k interrupt routine |
1527 |
|
M68kRegisters r; |
1548 |
|
} |
1549 |
|
#endif |
1550 |
|
// Reset normal signal stack |
1551 |
< |
new_stack.ss_sp = sig_stack; |
1512 |
< |
new_stack.ss_flags = 0; |
1513 |
< |
new_stack.ss_size = SIG_STACK_SIZE; |
1514 |
< |
sigaltstack(&new_stack, NULL); |
1551 |
> |
sig_stack_release(); |
1552 |
|
} |
1553 |
|
break; |
1554 |
|
#endif |