ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/main_unix.cpp
Revision: 1.23
Committed: 2004-01-04T18:35:21Z (20 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.22: +48 -5 lines
Log Message:
Emulated lmw/stmw with unaligned EA. e.g. for BBEdit under MacOS 8.6.
This may be due to some switch mode that needs to save r13 and upwards.
The faultive code seems to explicitly add 0xee to r1, which causes it to
be unaligned for upcoming lmw/stmw.

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * main_unix.cpp - Emulation core, Unix implementation
3     *
4     * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig
5     *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     /*
22     * NOTES:
23     *
24     * See main_beos.cpp for a description of the three operating modes.
25     *
26     * In addition to that, we have to handle the fact that the MacOS ABI
27     * is slightly different from the SysV ABI used by Linux:
28     * - Stack frames are different (e.g. LR is stored in 8(r1) under
29     * MacOS, but in 4(r1) under Linux)
30     * - There is no TOC under Linux; r2 is free for the user
31     * - r13 is used as a small data pointer under Linux (but appearently
32     * it is not used this way? To be sure, we specify -msdata=none
33     * in the Makefile)
34     * - As there is no TOC, there are also no TVECTs under Linux;
35     * function pointers point directly to the function code
36     * The Execute*() functions have to account for this. Additionally, we
37     * cannot simply call MacOS functions by getting their TVECT and jumping
38     * to it. Such calls are done via the call_macos*() functions in
39     * asm_linux.S that create a MacOS stack frame, load the TOC pointer
40     * and put the arguments into the right registers.
41     *
42     * As on the BeOS, we have to specify an alternate signal stack because
43     * interrupts (and, under Linux, Low Memory accesses) may occur when r1
44     * is pointing to the Kernel Data or to Low Memory. There is one
45     * problem, however, due to the alternate signal stack being global to
46     * all signal handlers. Consider the following scenario:
47     * - The main thread is executing some native PPC MacOS code in
48     * MODE_NATIVE, running on the MacOS stack (somewhere in the Mac RAM).
49     * - A SIGUSR2 interrupt occurs. The kernel switches to the signal
50     * stack and starts executing the SIGUSR2 signal handler.
51     * - The signal handler sees the MODE_NATIVE and calls ppc_interrupt()
52     * to handle a native interrupt.
53     * - ppc_interrupt() sets r1 to point to the Kernel Data and jumps to
54     * the nanokernel.
55     * - The nanokernel accesses a Low Memory global (most likely one of
56     * the XLMs), a SIGSEGV occurs.
57     * - The kernel sees that r1 does not point to the signal stack and
58     * switches to the signal stack again, thus overwriting the data that
59     * the SIGUSR2 handler put there.
60     * The same problem arises when calling ExecutePPC() inside the MODE_EMUL_OP
61     * interrupt handler.
62     *
63     * The solution is to set the signal stack to a second, "extra" stack
64     * inside the SIGUSR2 handler before entering the Nanokernel or calling
65     * ExecutePPC (or any function that might cause a mode switch). The signal
66     * stack is restored before exiting the SIGUSR2 handler.
67     *
68     * TODO:
69     * check if SIGSEGV handler works for all registers (including FP!)
70     */
71    
72     #include <unistd.h>
73     #include <fcntl.h>
74     #include <time.h>
75     #include <errno.h>
76     #include <stdio.h>
77     #include <stdlib.h>
78     #include <string.h>
79     #include <pthread.h>
80     #include <sys/mman.h>
81     #include <sys/ipc.h>
82     #include <sys/shm.h>
83     #include <signal.h>
84    
85     #include "sysdeps.h"
86     #include "main.h"
87     #include "version.h"
88     #include "prefs.h"
89     #include "prefs_editor.h"
90     #include "cpu_emulation.h"
91     #include "emul_op.h"
92     #include "xlowmem.h"
93     #include "xpram.h"
94     #include "timer.h"
95     #include "adb.h"
96     #include "sony.h"
97     #include "disk.h"
98     #include "cdrom.h"
99     #include "scsi.h"
100     #include "video.h"
101     #include "audio.h"
102     #include "ether.h"
103     #include "serial.h"
104     #include "clip.h"
105     #include "extfs.h"
106     #include "sys.h"
107     #include "macos_util.h"
108     #include "rom_patches.h"
109     #include "user_strings.h"
110 gbeauche 1.4 #include "vm_alloc.h"
111 gbeauche 1.5 #include "sigsegv.h"
112 gbeauche 1.15 #include "thunks.h"
113 cebix 1.1
114     #define DEBUG 0
115     #include "debug.h"
116    
117    
118     #include <X11/Xlib.h>
119    
120     #ifdef ENABLE_GTK
121     #include <gtk/gtk.h>
122     #endif
123    
124     #ifdef ENABLE_XF86_DGA
125     #include <X11/Xlib.h>
126     #include <X11/Xutil.h>
127     #include <X11/extensions/xf86dga.h>
128     #endif
129    
130     #ifdef ENABLE_MON
131     #include "mon.h"
132     #endif
133    
134    
135 gbeauche 1.23 // Enable emulation of unaligned lmw/stmw?
136     #define EMULATE_UNALIGNED_LOADSTORE_MULTIPLE 1
137    
138 cebix 1.1 // Enable Execute68k() safety checks?
139     #define SAFE_EXEC_68K 0
140    
141     // Interrupts in EMUL_OP mode?
142     #define INTERRUPTS_IN_EMUL_OP_MODE 1
143    
144     // Interrupts in native mode?
145     #define INTERRUPTS_IN_NATIVE_MODE 1
146    
147    
148     // Constants
149     const char ROM_FILE_NAME[] = "ROM";
150     const char ROM_FILE_NAME2[] = "Mac OS ROM";
151    
152 gbeauche 1.15 const uintptr RAM_BASE = 0x20000000; // Base address of RAM
153 cebix 1.1 const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack
154    
155    
156     #if !EMULATED_PPC
157     // Structure in which registers are saved in a signal handler;
158     // sigcontext->regs points to it
159     // (see arch/ppc/kernel/signal.c)
160     typedef struct {
161     uint32 u[4];
162     } __attribute((aligned(16))) vector128;
163     #include <linux/elf.h>
164    
165     struct sigregs {
166     elf_gregset_t gp_regs; // Identical to pt_regs
167     double fp_regs[ELF_NFPREG]; // f0..f31 and fpsrc
168     //more (uninteresting) stuff following here
169     };
170     #endif
171    
172    
173     // Global variables (exported)
174     #if !EMULATED_PPC
175     void *TOC; // Small data pointer (r13)
176     #endif
177     uint32 RAMBase; // Base address of Mac RAM
178     uint32 RAMSize; // Size of Mac RAM
179     uint32 KernelDataAddr; // Address of Kernel Data
180     uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM
181     uint32 PVR; // Theoretical PVR
182     int64 CPUClockSpeed; // Processor clock speed (Hz)
183     int64 BusClockSpeed; // Bus clock speed (Hz)
184    
185    
186     // Global variables
187 gbeauche 1.11 char *x_display_name = NULL; // X11 display name
188 cebix 1.1 Display *x_display = NULL; // X11 display handle
189 gbeauche 1.21 #ifdef X11_LOCK_TYPE
190     X11_LOCK_TYPE x_display_lock = X11_LOCK_INIT; // X11 display lock
191     #endif
192 cebix 1.1
193     static int zero_fd = 0; // FD of /dev/zero
194     static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped
195     static int kernel_area = -1; // SHM ID of Kernel Data area
196     static bool rom_area_mapped = false; // Flag: Mac ROM mmap()ped
197     static bool ram_area_mapped = false; // Flag: Mac RAM mmap()ped
198     static KernelData *kernel_data; // Pointer to Kernel Data
199     static EmulatorData *emulator_data;
200    
201     static uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes
202    
203     static bool nvram_thread_active = false; // Flag: NVRAM watchdog installed
204     static pthread_t nvram_thread; // NVRAM watchdog
205     static bool tick_thread_active = false; // Flag: MacOS thread installed
206     static pthread_t tick_thread; // 60Hz thread
207     static pthread_t emul_thread; // MacOS thread
208    
209     static bool ready_for_signals = false; // Handler installed, signals can be sent
210     static int64 num_segv = 0; // Number of handled SEGV signals
211    
212 gbeauche 1.6 static struct sigaction sigusr2_action; // Interrupt signal (of emulator thread)
213 gbeauche 1.20 #if EMULATED_PPC
214     static uintptr sig_stack = 0; // Stack for PowerPC interrupt routine
215     #else
216 cebix 1.1 static struct sigaction sigsegv_action; // Data access exception signal (of emulator thread)
217     static struct sigaction sigill_action; // Illegal instruction signal (of emulator thread)
218     static void *sig_stack = NULL; // Stack for signal handlers
219     static void *extra_stack = NULL; // Stack for SIGSEGV inside interrupt handler
220     static bool emul_thread_fatal = false; // Flag: MacOS thread crashed, tick thread shall dump debug output
221     static sigregs sigsegv_regs; // Register dump when crashed
222 gbeauche 1.23 static const char *crash_reason = NULL; // Reason of the crash (SIGSEGV, SIGBUS, SIGILL)
223 cebix 1.1 #endif
224    
225 gbeauche 1.18 uintptr SheepMem::zero_page = 0; // Address of ro page filled in with zeros
226 gbeauche 1.15 uintptr SheepMem::base = 0x60000000; // Address of SheepShaver data
227     uintptr SheepMem::top = 0; // Top of SheepShaver data (stack like storage)
228    
229 cebix 1.1
230     // Prototypes
231     static void Quit(void);
232     static void *emul_func(void *arg);
233     static void *nvram_func(void *arg);
234     static void *tick_func(void *arg);
235 gbeauche 1.8 #if EMULATED_PPC
236     static void sigusr2_handler(int sig);
237 gbeauche 1.13 extern void emul_ppc(uint32 start);
238     extern void init_emul_ppc(void);
239     extern void exit_emul_ppc(void);
240 gbeauche 1.8 #else
241 gbeauche 1.6 static void sigusr2_handler(int sig, sigcontext_struct *sc);
242 cebix 1.1 static void sigsegv_handler(int sig, sigcontext_struct *sc);
243     static void sigill_handler(int sig, sigcontext_struct *sc);
244     #endif
245    
246    
247     // From asm_linux.S
248 gbeauche 1.12 #if !EMULATED_PPC
249 cebix 1.1 extern "C" void *get_toc(void);
250     extern "C" void *get_sp(void);
251     extern "C" void flush_icache_range(void *start, void *end);
252     extern "C" void jump_to_rom(uint32 entry, uint32 context);
253     extern "C" void quit_emulator(void);
254     extern "C" void execute_68k(uint32 pc, M68kRegisters *r);
255     extern "C" void ppc_interrupt(uint32 entry, uint32 kernel_data);
256     extern "C" int atomic_add(int *var, int v);
257     extern "C" int atomic_and(int *var, int v);
258     extern "C" int atomic_or(int *var, int v);
259     extern void paranoia_check(void);
260 gbeauche 1.12 #endif
261    
262    
263     #if EMULATED_PPC
264     /*
265 gbeauche 1.20 * Return signal stack base
266     */
267    
268     uintptr SignalStackBase(void)
269     {
270     return sig_stack + SIG_STACK_SIZE;
271     }
272    
273    
274     /*
275 gbeauche 1.12 * Atomic operations
276     */
277    
278     #if HAVE_SPINLOCKS
279     static spinlock_t atomic_ops_lock = SPIN_LOCK_UNLOCKED;
280     #else
281     #define spin_lock(LOCK)
282     #define spin_unlock(LOCK)
283     #endif
284    
285     int atomic_add(int *var, int v)
286     {
287     spin_lock(&atomic_ops_lock);
288     int ret = *var;
289     *var += v;
290     spin_unlock(&atomic_ops_lock);
291     return ret;
292     }
293    
294     int atomic_and(int *var, int v)
295     {
296     spin_lock(&atomic_ops_lock);
297     int ret = *var;
298     *var &= v;
299     spin_unlock(&atomic_ops_lock);
300     return ret;
301     }
302    
303     int atomic_or(int *var, int v)
304     {
305     spin_lock(&atomic_ops_lock);
306     int ret = *var;
307     *var |= v;
308     spin_unlock(&atomic_ops_lock);
309     return ret;
310     }
311 cebix 1.1 #endif
312    
313    
314     /*
315     * Main program
316     */
317    
318     static void usage(const char *prg_name)
319     {
320     printf("Usage: %s [OPTION...]\n", prg_name);
321     printf("\nUnix options:\n");
322     printf(" --display STRING\n X display to use\n");
323     PrefsPrintUsage();
324     exit(0);
325     }
326    
327     int main(int argc, char **argv)
328     {
329     char str[256];
330     uint32 *boot_globs;
331     int16 i16;
332     int rom_fd;
333     FILE *proc_file;
334     const char *rom_path;
335     uint32 rom_size, actual;
336     uint8 *rom_tmp;
337     time_t now, expire;
338    
339     // Initialize variables
340     RAMBase = 0;
341     tzset();
342    
343     // Print some info
344     printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
345     printf(" %s\n", GetString(STR_ABOUT_TEXT2));
346    
347     #if !EMULATED_PPC
348     // Get TOC pointer
349     TOC = get_toc();
350     #endif
351    
352     #ifdef ENABLE_GTK
353     // Init GTK
354     gtk_set_locale();
355     gtk_init(&argc, &argv);
356     #endif
357    
358     // Read preferences
359     PrefsInit(argc, argv);
360    
361     // Parse command line arguments
362     for (int i=1; i<argc; i++) {
363     if (strcmp(argv[i], "--help") == 0) {
364     usage(argv[0]);
365     } else if (strcmp(argv[i], "--display") == 0) {
366     i++;
367     if (i < argc)
368     x_display_name = strdup(argv[i]);
369     } else if (argv[i][0] == '-') {
370     fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
371     usage(argv[0]);
372     }
373     }
374    
375     // Open display
376     x_display = XOpenDisplay(x_display_name);
377     if (x_display == NULL) {
378     char str[256];
379     sprintf(str, GetString(STR_NO_XSERVER_ERR), XDisplayName(x_display_name));
380     ErrorAlert(str);
381     goto quit;
382     }
383    
384     #if defined(ENABLE_XF86_DGA) && !defined(ENABLE_MON)
385     // Fork out, so we can return from fullscreen mode when things get ugly
386     XF86DGAForkApp(DefaultScreen(x_display));
387     #endif
388    
389     #ifdef ENABLE_MON
390     // Initialize mon
391     mon_init();
392     #endif
393    
394     // Get system info
395     PVR = 0x00040000; // Default: 604
396     CPUClockSpeed = 100000000; // Default: 100MHz
397     BusClockSpeed = 100000000; // Default: 100MHz
398     #if !EMULATED_PPC
399     proc_file = fopen("/proc/cpuinfo", "r");
400     if (proc_file) {
401     char line[256];
402     while(fgets(line, 255, proc_file)) {
403     // Read line
404     int len = strlen(line);
405     if (len == 0)
406     continue;
407     line[len-1] = 0;
408    
409     // Parse line
410     int i;
411     char value[256];
412     if (sscanf(line, "cpu : %s", value) == 1) {
413     if (strcmp(value, "601") == 0)
414     PVR = 0x00010000;
415     else if (strcmp(value, "603") == 0)
416     PVR = 0x00030000;
417     else if (strcmp(value, "604") == 0)
418     PVR = 0x00040000;
419     else if (strcmp(value, "603e") == 0)
420     PVR = 0x00060000;
421     else if (strcmp(value, "603ev") == 0)
422     PVR = 0x00070000;
423     else if (strcmp(value, "604e") == 0)
424     PVR = 0x00090000;
425     else if (strcmp(value, "604ev5") == 0)
426     PVR = 0x000a0000;
427     else if (strcmp(value, "750") == 0)
428     PVR = 0x00080000;
429     else if (strcmp(value, "821") == 0)
430     PVR = 0x00320000;
431     else if (strcmp(value, "860") == 0)
432     PVR = 0x00500000;
433     else
434     printf("WARNING: Unknown CPU type '%s', assuming 604\n", value);
435     }
436     if (sscanf(line, "clock : %dMHz", &i) == 1)
437     CPUClockSpeed = BusClockSpeed = i * 1000000;
438     }
439     fclose(proc_file);
440     } else {
441     sprintf(str, GetString(STR_PROC_CPUINFO_WARN), strerror(errno));
442     WarningAlert(str);
443     }
444     #endif
445     D(bug("PVR: %08x (assumed)\n", PVR));
446    
447     // Init system routines
448     SysInit();
449    
450     // Show preferences editor
451     if (!PrefsFindBool("nogui"))
452     if (!PrefsEditor())
453     goto quit;
454    
455     #if !EMULATED_PPC
456     // Check some things
457     paranoia_check();
458     #endif
459    
460     // Open /dev/zero
461     zero_fd = open("/dev/zero", O_RDWR);
462     if (zero_fd < 0) {
463     sprintf(str, GetString(STR_NO_DEV_ZERO_ERR), strerror(errno));
464     ErrorAlert(str);
465     goto quit;
466     }
467    
468     // Create Low Memory area (0x0000..0x3000)
469 gbeauche 1.4 if (vm_acquire_fixed((char *)0, 0x3000) < 0) {
470 cebix 1.1 sprintf(str, GetString(STR_LOW_MEM_MMAP_ERR), strerror(errno));
471     ErrorAlert(str);
472     goto quit;
473     }
474     lm_area_mapped = true;
475    
476     // Create areas for Kernel Data
477     kernel_area = shmget(IPC_PRIVATE, KERNEL_AREA_SIZE, 0600);
478     if (kernel_area == -1) {
479     sprintf(str, GetString(STR_KD_SHMGET_ERR), strerror(errno));
480     ErrorAlert(str);
481     goto quit;
482     }
483     if (shmat(kernel_area, (void *)KERNEL_DATA_BASE, 0) < 0) {
484     sprintf(str, GetString(STR_KD_SHMAT_ERR), strerror(errno));
485     ErrorAlert(str);
486     goto quit;
487     }
488     if (shmat(kernel_area, (void *)KERNEL_DATA2_BASE, 0) < 0) {
489     sprintf(str, GetString(STR_KD2_SHMAT_ERR), strerror(errno));
490     ErrorAlert(str);
491     goto quit;
492     }
493 gbeauche 1.15 kernel_data = (KernelData *)KERNEL_DATA_BASE;
494 cebix 1.1 emulator_data = &kernel_data->ed;
495 gbeauche 1.15 KernelDataAddr = KERNEL_DATA_BASE;
496 cebix 1.1 D(bug("Kernel Data at %p, Emulator Data at %p\n", kernel_data, emulator_data));
497    
498 gbeauche 1.8 // Create area for SheepShaver data
499 gbeauche 1.15 if (!SheepMem::Init()) {
500 gbeauche 1.8 sprintf(str, GetString(STR_SHEEP_MEM_MMAP_ERR), strerror(errno));
501     ErrorAlert(str);
502     goto quit;
503     }
504    
505 cebix 1.1 // Create area for Mac ROM
506 gbeauche 1.4 if (vm_acquire_fixed((char *)ROM_BASE, ROM_AREA_SIZE) < 0) {
507 cebix 1.1 sprintf(str, GetString(STR_ROM_MMAP_ERR), strerror(errno));
508     ErrorAlert(str);
509     goto quit;
510     }
511 gbeauche 1.6 #if !EMULATED_PPC || defined(__powerpc__)
512 gbeauche 1.4 if (vm_protect((char *)ROM_BASE, ROM_AREA_SIZE, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE) < 0) {
513     sprintf(str, GetString(STR_ROM_MMAP_ERR), strerror(errno));
514     ErrorAlert(str);
515     goto quit;
516     }
517     #endif
518 cebix 1.1 rom_area_mapped = true;
519     D(bug("ROM area at %08x\n", ROM_BASE));
520    
521     // Create area for Mac RAM
522     RAMSize = PrefsFindInt32("ramsize");
523     if (RAMSize < 8*1024*1024) {
524     WarningAlert(GetString(STR_SMALL_RAM_WARN));
525     RAMSize = 8*1024*1024;
526     }
527    
528 gbeauche 1.8 if (vm_acquire_fixed((char *)RAM_BASE, RAMSize) < 0) {
529 cebix 1.1 sprintf(str, GetString(STR_RAM_MMAP_ERR), strerror(errno));
530     ErrorAlert(str);
531     goto quit;
532     }
533 gbeauche 1.4 #if !EMULATED_PPC
534 gbeauche 1.8 if (vm_protect((char *)RAM_BASE, RAMSize, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE) < 0) {
535 gbeauche 1.4 sprintf(str, GetString(STR_RAM_MMAP_ERR), strerror(errno));
536     ErrorAlert(str);
537     goto quit;
538     }
539     #endif
540 gbeauche 1.8 RAMBase = RAM_BASE;
541 cebix 1.1 ram_area_mapped = true;
542     D(bug("RAM area at %08x\n", RAMBase));
543    
544     if (RAMBase > ROM_BASE) {
545     ErrorAlert(GetString(STR_RAM_HIGHER_THAN_ROM_ERR));
546     goto quit;
547     }
548    
549     // Load Mac ROM
550     rom_path = PrefsFindString("rom");
551     rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME, O_RDONLY);
552     if (rom_fd < 0) {
553     rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME2, O_RDONLY);
554     if (rom_fd < 0) {
555     ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
556     goto quit;
557     }
558     }
559     printf(GetString(STR_READING_ROM_FILE));
560     rom_size = lseek(rom_fd, 0, SEEK_END);
561     lseek(rom_fd, 0, SEEK_SET);
562     rom_tmp = new uint8[ROM_SIZE];
563     actual = read(rom_fd, (void *)rom_tmp, ROM_SIZE);
564     close(rom_fd);
565 gbeauche 1.3
566     // Decode Mac ROM
567     if (!DecodeROM(rom_tmp, actual)) {
568     if (rom_size != 4*1024*1024) {
569 cebix 1.1 ErrorAlert(GetString(STR_ROM_SIZE_ERR));
570     goto quit;
571     } else {
572     ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
573     goto quit;
574     }
575     }
576 gbeauche 1.3 delete[] rom_tmp;
577 cebix 1.1
578     // Load NVRAM
579     XPRAMInit();
580    
581     // Set boot volume
582 cebix 1.10 i16 = PrefsFindInt32("bootdrive");
583 cebix 1.1 XPRAM[0x1378] = i16 >> 8;
584     XPRAM[0x1379] = i16 & 0xff;
585 cebix 1.10 i16 = PrefsFindInt32("bootdriver");
586 cebix 1.1 XPRAM[0x137a] = i16 >> 8;
587     XPRAM[0x137b] = i16 & 0xff;
588    
589     // Create BootGlobs at top of Mac memory
590     memset((void *)(RAMBase + RAMSize - 4096), 0, 4096);
591     BootGlobsAddr = RAMBase + RAMSize - 0x1c;
592     boot_globs = (uint32 *)BootGlobsAddr;
593     boot_globs[-5] = htonl(RAMBase + RAMSize); // MemTop
594     boot_globs[0] = htonl(RAMBase); // First RAM bank
595     boot_globs[1] = htonl(RAMSize);
596     boot_globs[2] = htonl((uint32)-1); // End of bank table
597    
598 gbeauche 1.15 // Init thunks
599     if (!ThunksInit())
600     goto quit;
601    
602 cebix 1.1 // Init drivers
603     SonyInit();
604     DiskInit();
605     CDROMInit();
606     SCSIInit();
607    
608     // Init external file system
609     ExtFSInit();
610    
611 gbeauche 1.22 // Init ADB
612     ADBInit();
613    
614 cebix 1.1 // Init audio
615     AudioInit();
616    
617     // Init network
618     EtherInit();
619    
620     // Init serial ports
621     SerialInit();
622    
623     // Init Time Manager
624     TimerInit();
625    
626     // Init clipboard
627     ClipInit();
628    
629     // Init video
630     if (!VideoInit())
631     goto quit;
632    
633     // Install ROM patches
634     if (!PatchROM()) {
635     ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR));
636     goto quit;
637     }
638    
639     // Clear caches (as we loaded and patched code) and write protect ROM
640     #if !EMULATED_PPC
641     MakeExecutable(0, (void *)ROM_BASE, ROM_AREA_SIZE);
642     #endif
643 gbeauche 1.4 vm_protect((char *)ROM_BASE, ROM_AREA_SIZE, VM_PAGE_READ | VM_PAGE_EXECUTE);
644 cebix 1.1
645     // Initialize Kernel Data
646     memset(kernel_data, 0, sizeof(KernelData));
647     if (ROMType == ROMTYPE_NEWWORLD) {
648 gbeauche 1.15 uintptr of_dev_tree = SheepMem::Reserve(4 * sizeof(uint32));
649     memset((void *)of_dev_tree, 0, 4 * sizeof(uint32));
650     uintptr vector_lookup_tbl = SheepMem::Reserve(128);
651     uintptr vector_mask_tbl = SheepMem::Reserve(64);
652 cebix 1.1 memset((uint8 *)kernel_data + 0xb80, 0x3d, 0x80);
653 gbeauche 1.15 memset((void *)vector_lookup_tbl, 0, 128);
654     memset((void *)vector_mask_tbl, 0, 64);
655 cebix 1.1 kernel_data->v[0xb80 >> 2] = htonl(ROM_BASE);
656 gbeauche 1.15 kernel_data->v[0xb84 >> 2] = htonl(of_dev_tree); // OF device tree base
657     kernel_data->v[0xb90 >> 2] = htonl(vector_lookup_tbl);
658     kernel_data->v[0xb94 >> 2] = htonl(vector_mask_tbl);
659 cebix 1.1 kernel_data->v[0xb98 >> 2] = htonl(ROM_BASE); // OpenPIC base
660     kernel_data->v[0xbb0 >> 2] = htonl(0); // ADB base
661     kernel_data->v[0xc20 >> 2] = htonl(RAMSize);
662     kernel_data->v[0xc24 >> 2] = htonl(RAMSize);
663     kernel_data->v[0xc30 >> 2] = htonl(RAMSize);
664     kernel_data->v[0xc34 >> 2] = htonl(RAMSize);
665     kernel_data->v[0xc38 >> 2] = htonl(0x00010020);
666     kernel_data->v[0xc3c >> 2] = htonl(0x00200001);
667     kernel_data->v[0xc40 >> 2] = htonl(0x00010000);
668     kernel_data->v[0xc50 >> 2] = htonl(RAMBase);
669     kernel_data->v[0xc54 >> 2] = htonl(RAMSize);
670     kernel_data->v[0xf60 >> 2] = htonl(PVR);
671     kernel_data->v[0xf64 >> 2] = htonl(CPUClockSpeed);
672     kernel_data->v[0xf68 >> 2] = htonl(BusClockSpeed);
673     kernel_data->v[0xf6c >> 2] = htonl(CPUClockSpeed);
674     } else {
675     kernel_data->v[0xc80 >> 2] = htonl(RAMSize);
676     kernel_data->v[0xc84 >> 2] = htonl(RAMSize);
677     kernel_data->v[0xc90 >> 2] = htonl(RAMSize);
678     kernel_data->v[0xc94 >> 2] = htonl(RAMSize);
679     kernel_data->v[0xc98 >> 2] = htonl(0x00010020);
680     kernel_data->v[0xc9c >> 2] = htonl(0x00200001);
681     kernel_data->v[0xca0 >> 2] = htonl(0x00010000);
682     kernel_data->v[0xcb0 >> 2] = htonl(RAMBase);
683     kernel_data->v[0xcb4 >> 2] = htonl(RAMSize);
684     kernel_data->v[0xf80 >> 2] = htonl(PVR);
685     kernel_data->v[0xf84 >> 2] = htonl(CPUClockSpeed);
686     kernel_data->v[0xf88 >> 2] = htonl(BusClockSpeed);
687     kernel_data->v[0xf8c >> 2] = htonl(CPUClockSpeed);
688     }
689    
690     // Initialize extra low memory
691     D(bug("Initializing Low Memory...\n"));
692     memset(NULL, 0, 0x3000);
693     WriteMacInt32(XLM_SIGNATURE, FOURCC('B','a','a','h')); // Signature to detect SheepShaver
694 gbeauche 1.15 WriteMacInt32(XLM_KERNEL_DATA, KernelDataAddr); // For trap replacement routines
695 cebix 1.1 WriteMacInt32(XLM_PVR, PVR); // Theoretical PVR
696     WriteMacInt32(XLM_BUS_CLOCK, BusClockSpeed); // For DriverServicesLib patch
697     WriteMacInt16(XLM_EXEC_RETURN_OPCODE, M68K_EXEC_RETURN); // For Execute68k() (RTS from the executed 68k code will jump here and end 68k mode)
698 gbeauche 1.18 WriteMacInt32(XLM_ZERO_PAGE, SheepMem::ZeroPage()); // Pointer to read-only page with all bits set to 0
699 gbeauche 1.17 #if !EMULATED_PPC
700     WriteMacInt32(XLM_TOC, (uint32)TOC); // TOC pointer of emulator
701     #endif
702     WriteMacInt32(XLM_ETHER_INIT, NativeFunction(NATIVE_ETHER_INIT)); // DLPI ethernet driver functions
703 gbeauche 1.15 WriteMacInt32(XLM_ETHER_TERM, NativeFunction(NATIVE_ETHER_TERM));
704     WriteMacInt32(XLM_ETHER_OPEN, NativeFunction(NATIVE_ETHER_OPEN));
705     WriteMacInt32(XLM_ETHER_CLOSE, NativeFunction(NATIVE_ETHER_CLOSE));
706     WriteMacInt32(XLM_ETHER_WPUT, NativeFunction(NATIVE_ETHER_WPUT));
707     WriteMacInt32(XLM_ETHER_RSRV, NativeFunction(NATIVE_ETHER_RSRV));
708     WriteMacInt32(XLM_VIDEO_DOIO, NativeFunction(NATIVE_VIDEO_DO_DRIVER_IO));
709 cebix 1.1 D(bug("Low Memory initialized\n"));
710    
711     // Start 60Hz thread
712     tick_thread_active = (pthread_create(&tick_thread, NULL, tick_func, NULL) == 0);
713     D(bug("Tick thread installed (%ld)\n", tick_thread));
714    
715     // Start NVRAM watchdog thread
716     memcpy(last_xpram, XPRAM, XPRAM_SIZE);
717     nvram_thread_active = (pthread_create(&nvram_thread, NULL, nvram_func, NULL) == 0);
718     D(bug("NVRAM thread installed (%ld)\n", nvram_thread));
719    
720     #if !EMULATED_PPC
721     // Create and install stacks for signal handlers
722     sig_stack = malloc(SIG_STACK_SIZE);
723     D(bug("Signal stack at %p\n", sig_stack));
724     if (sig_stack == NULL) {
725     ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
726     goto quit;
727     }
728     extra_stack = malloc(SIG_STACK_SIZE);
729     D(bug("Extra stack at %p\n", extra_stack));
730     if (extra_stack == NULL) {
731     ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
732     goto quit;
733     }
734     struct sigaltstack new_stack;
735     new_stack.ss_sp = sig_stack;
736     new_stack.ss_flags = 0;
737     new_stack.ss_size = SIG_STACK_SIZE;
738     if (sigaltstack(&new_stack, NULL) < 0) {
739     sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno));
740     ErrorAlert(str);
741     goto quit;
742     }
743     #endif
744    
745     #if !EMULATED_PPC
746 gbeauche 1.23 // Install SIGSEGV and SIGBUS handlers
747 cebix 1.1 sigemptyset(&sigsegv_action.sa_mask); // Block interrupts during SEGV handling
748     sigaddset(&sigsegv_action.sa_mask, SIGUSR2);
749     sigsegv_action.sa_handler = (__sighandler_t)sigsegv_handler;
750     sigsegv_action.sa_flags = SA_ONSTACK;
751     sigsegv_action.sa_restorer = NULL;
752     if (sigaction(SIGSEGV, &sigsegv_action, NULL) < 0) {
753     sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno));
754     ErrorAlert(str);
755     goto quit;
756     }
757 gbeauche 1.23 if (sigaction(SIGBUS, &sigsegv_action, NULL) < 0) {
758     sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno));
759     ErrorAlert(str);
760     goto quit;
761     }
762 cebix 1.1
763     // Install SIGILL handler
764     sigemptyset(&sigill_action.sa_mask); // Block interrupts during ILL handling
765     sigaddset(&sigill_action.sa_mask, SIGUSR2);
766     sigill_action.sa_handler = (__sighandler_t)sigill_handler;
767     sigill_action.sa_flags = SA_ONSTACK;
768     sigill_action.sa_restorer = NULL;
769     if (sigaction(SIGILL, &sigill_action, NULL) < 0) {
770     sprintf(str, GetString(STR_SIGILL_INSTALL_ERR), strerror(errno));
771     ErrorAlert(str);
772     goto quit;
773     }
774 gbeauche 1.6 #endif
775 cebix 1.1
776     // Install interrupt signal handler
777     sigemptyset(&sigusr2_action.sa_mask);
778     sigusr2_action.sa_handler = (__sighandler_t)sigusr2_handler;
779 gbeauche 1.8 sigusr2_action.sa_flags = 0;
780     #if !EMULATED_PPC
781 cebix 1.1 sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART;
782 gbeauche 1.8 #endif
783 cebix 1.1 sigusr2_action.sa_restorer = NULL;
784     if (sigaction(SIGUSR2, &sigusr2_action, NULL) < 0) {
785     sprintf(str, GetString(STR_SIGUSR2_INSTALL_ERR), strerror(errno));
786     ErrorAlert(str);
787     goto quit;
788     }
789    
790     // Get my thread ID and execute MacOS thread function
791     emul_thread = pthread_self();
792     D(bug("MacOS thread is %ld\n", emul_thread));
793     emul_func(NULL);
794    
795     quit:
796     Quit();
797     return 0;
798     }
799    
800    
801     /*
802     * Cleanup and quit
803     */
804    
805     static void Quit(void)
806     {
807 gbeauche 1.13 #if EMULATED_PPC
808     // Exit PowerPC emulation
809     exit_emul_ppc();
810     #endif
811    
812 cebix 1.1 // Stop 60Hz thread
813     if (tick_thread_active) {
814     pthread_cancel(tick_thread);
815     pthread_join(tick_thread, NULL);
816     }
817    
818     // Stop NVRAM watchdog thread
819     if (nvram_thread_active) {
820     pthread_cancel(nvram_thread);
821     pthread_join(nvram_thread, NULL);
822     }
823    
824     #if !EMULATED_PPC
825 gbeauche 1.23 // Uninstall SIGSEGV and SIGBUS handlers
826 cebix 1.1 sigemptyset(&sigsegv_action.sa_mask);
827     sigsegv_action.sa_handler = SIG_DFL;
828     sigsegv_action.sa_flags = 0;
829     sigaction(SIGSEGV, &sigsegv_action, NULL);
830 gbeauche 1.23 sigaction(SIGBUS, &sigsegv_action, NULL);
831 cebix 1.1
832     // Uninstall SIGILL handler
833     sigemptyset(&sigill_action.sa_mask);
834     sigill_action.sa_handler = SIG_DFL;
835     sigill_action.sa_flags = 0;
836     sigaction(SIGILL, &sigill_action, NULL);
837     #endif
838    
839     // Save NVRAM
840     XPRAMExit();
841    
842     // Exit clipboard
843     ClipExit();
844    
845     // Exit Time Manager
846     TimerExit();
847    
848     // Exit serial
849     SerialExit();
850    
851     // Exit network
852     EtherExit();
853    
854     // Exit audio
855     AudioExit();
856 gbeauche 1.22
857     // Exit ADB
858     ADBExit();
859 cebix 1.1
860     // Exit video
861     VideoExit();
862    
863     // Exit external file system
864     ExtFSExit();
865    
866     // Exit drivers
867     SCSIExit();
868     CDROMExit();
869     DiskExit();
870     SonyExit();
871    
872 gbeauche 1.15 // Delete SheepShaver globals
873     SheepMem::Exit();
874    
875 cebix 1.1 // Delete RAM area
876     if (ram_area_mapped)
877 gbeauche 1.8 vm_release((char *)RAM_BASE, RAMSize);
878 cebix 1.1
879     // Delete ROM area
880     if (rom_area_mapped)
881 gbeauche 1.4 vm_release((char *)ROM_BASE, ROM_AREA_SIZE);
882 cebix 1.1
883     // Delete Kernel Data area
884     if (kernel_area >= 0) {
885     shmdt((void *)KERNEL_DATA_BASE);
886     shmdt((void *)KERNEL_DATA2_BASE);
887     shmctl(kernel_area, IPC_RMID, NULL);
888     }
889    
890     // Delete Low Memory area
891     if (lm_area_mapped)
892     munmap((char *)0x0000, 0x3000);
893    
894     // Close /dev/zero
895     if (zero_fd > 0)
896     close(zero_fd);
897    
898     // Exit system routines
899     SysExit();
900    
901     // Exit preferences
902     PrefsExit();
903    
904     #ifdef ENABLE_MON
905     // Exit mon
906     mon_exit();
907     #endif
908    
909     // Close X11 server connection
910     if (x_display)
911     XCloseDisplay(x_display);
912    
913     exit(0);
914     }
915    
916    
917     /*
918     * Jump into Mac ROM, start 680x0 emulator
919     */
920    
921     #if EMULATED_PPC
922     void jump_to_rom(uint32 entry)
923     {
924     init_emul_ppc();
925     emul_ppc(entry);
926     }
927     #endif
928    
929    
930     /*
931     * Emulator thread function
932     */
933    
934     static void *emul_func(void *arg)
935     {
936     // We're now ready to receive signals
937     ready_for_signals = true;
938    
939     // Decrease priority, so more time-critical things like audio will work better
940     nice(1);
941    
942     // Jump to ROM boot routine
943     D(bug("Jumping to ROM\n"));
944     #if EMULATED_PPC
945     jump_to_rom(ROM_BASE + 0x310000);
946     #else
947     jump_to_rom(ROM_BASE + 0x310000, (uint32)emulator_data);
948     #endif
949     D(bug("Returned from ROM\n"));
950    
951     // We're no longer ready to receive signals
952     ready_for_signals = false;
953     return NULL;
954     }
955    
956    
957     #if !EMULATED_PPC
958     /*
959     * Execute 68k subroutine (must be ended with RTS)
960     * This must only be called by the emul_thread when in EMUL_OP mode
961     * r->a[7] is unused, the routine runs on the caller's stack
962     */
963    
964     void Execute68k(uint32 pc, M68kRegisters *r)
965     {
966     #if SAFE_EXEC_68K
967     if (ReadMacInt32(XLM_RUN_MODE) != MODE_EMUL_OP)
968     printf("FATAL: Execute68k() not called from EMUL_OP mode\n");
969     if (!pthread_equal(pthread_self(), emul_thread))
970     printf("FATAL: Execute68k() not called from emul_thread\n");
971     #endif
972     execute_68k(pc, r);
973     }
974    
975    
976     /*
977     * Execute 68k A-Trap from EMUL_OP routine
978     * r->a[7] is unused, the routine runs on the caller's stack
979     */
980    
981     void Execute68kTrap(uint16 trap, M68kRegisters *r)
982     {
983     uint16 proc[2] = {trap, M68K_RTS};
984     Execute68k((uint32)proc, r);
985     }
986 gbeauche 1.7 #endif
987 cebix 1.1
988    
989     /*
990     * Quit emulator (cause return from jump_to_rom)
991     */
992    
993     void QuitEmulator(void)
994     {
995     #if EMULATED_PPC
996     Quit();
997     #else
998     quit_emulator();
999     #endif
1000     }
1001    
1002    
1003     /*
1004     * Pause/resume emulator
1005     */
1006    
1007     void PauseEmulator(void)
1008     {
1009     pthread_kill(emul_thread, SIGSTOP);
1010     }
1011    
1012     void ResumeEmulator(void)
1013     {
1014     pthread_kill(emul_thread, SIGCONT);
1015     }
1016    
1017    
1018     /*
1019     * Dump 68k registers
1020     */
1021    
1022     void Dump68kRegs(M68kRegisters *r)
1023     {
1024     // Display 68k registers
1025     for (int i=0; i<8; i++) {
1026     printf("d%d: %08x", i, r->d[i]);
1027     if (i == 3 || i == 7)
1028     printf("\n");
1029     else
1030     printf(", ");
1031     }
1032     for (int i=0; i<8; i++) {
1033     printf("a%d: %08x", i, r->a[i]);
1034     if (i == 3 || i == 7)
1035     printf("\n");
1036     else
1037     printf(", ");
1038     }
1039     }
1040    
1041    
1042     /*
1043     * Make code executable
1044     */
1045    
1046     void MakeExecutable(int dummy, void *start, uint32 length)
1047     {
1048 gbeauche 1.9 if (((uintptr)start >= ROM_BASE) && ((uintptr)start < (ROM_BASE + ROM_SIZE)))
1049 cebix 1.1 return;
1050 gbeauche 1.9 #if EMULATED_PPC
1051     FlushCodeCache((uintptr)start, (uintptr)start + length);
1052     #else
1053     flush_icache_range(start, (void *)((uintptr)start + length));
1054 cebix 1.1 #endif
1055     }
1056    
1057    
1058     /*
1059     * Patch things after system startup (gets called by disk driver accRun routine)
1060     */
1061    
1062     void PatchAfterStartup(void)
1063     {
1064 gbeauche 1.6 ExecuteNative(NATIVE_VIDEO_INSTALL_ACCEL);
1065 cebix 1.1 InstallExtFS();
1066     }
1067    
1068    
1069     /*
1070     * NVRAM watchdog thread (saves NVRAM every minute)
1071     */
1072    
1073     static void *nvram_func(void *arg)
1074     {
1075     struct timespec req = {60, 0}; // 1 minute
1076    
1077     for (;;) {
1078     pthread_testcancel();
1079     nanosleep(&req, NULL);
1080     pthread_testcancel();
1081     if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
1082     memcpy(last_xpram, XPRAM, XPRAM_SIZE);
1083     SaveXPRAM();
1084     }
1085     }
1086     return NULL;
1087     }
1088    
1089    
1090     /*
1091     * 60Hz thread (really 60.15Hz)
1092     */
1093    
1094     static void *tick_func(void *arg)
1095     {
1096     int tick_counter = 0;
1097     struct timespec req = {0, 16625000};
1098    
1099     for (;;) {
1100    
1101     // Wait
1102     nanosleep(&req, NULL);
1103    
1104     #if !EMULATED_PPC
1105     // Did we crash?
1106     if (emul_thread_fatal) {
1107    
1108     // Yes, dump registers
1109     pt_regs *r = (pt_regs *)&sigsegv_regs;
1110     char str[256];
1111 gbeauche 1.23 if (crash_reason == NULL)
1112     crash_reason = "SIGSEGV";
1113     sprintf(str, "%s\n"
1114 cebix 1.1 " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
1115     " xer %08lx cr %08lx \n"
1116     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
1117     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
1118     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
1119     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
1120     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
1121     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
1122     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
1123     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
1124 gbeauche 1.23 crash_reason,
1125 cebix 1.1 r->nip, r->link, r->ctr, r->msr,
1126     r->xer, r->ccr,
1127     r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3],
1128     r->gpr[4], r->gpr[5], r->gpr[6], r->gpr[7],
1129     r->gpr[8], r->gpr[9], r->gpr[10], r->gpr[11],
1130     r->gpr[12], r->gpr[13], r->gpr[14], r->gpr[15],
1131     r->gpr[16], r->gpr[17], r->gpr[18], r->gpr[19],
1132     r->gpr[20], r->gpr[21], r->gpr[22], r->gpr[23],
1133     r->gpr[24], r->gpr[25], r->gpr[26], r->gpr[27],
1134     r->gpr[28], r->gpr[29], r->gpr[30], r->gpr[31]);
1135     printf(str);
1136     VideoQuitFullScreen();
1137    
1138     #ifdef ENABLE_MON
1139     // Start up mon in real-mode
1140     printf("Welcome to the sheep factory.\n");
1141     char *arg[4] = {"mon", "-m", "-r", NULL};
1142     mon(3, arg);
1143     #endif
1144     return NULL;
1145     }
1146     #endif
1147    
1148     // Pseudo Mac 1Hz interrupt, update local time
1149     if (++tick_counter > 60) {
1150     tick_counter = 0;
1151     WriteMacInt32(0x20c, TimerDateTime());
1152     }
1153    
1154     // Trigger 60Hz interrupt
1155     if (ReadMacInt32(XLM_IRQ_NEST) == 0) {
1156     SetInterruptFlag(INTFLAG_VIA);
1157     TriggerInterrupt();
1158     }
1159     }
1160     return NULL;
1161     }
1162    
1163    
1164     /*
1165 cebix 1.2 * Pthread configuration
1166     */
1167    
1168     void Set_pthread_attr(pthread_attr_t *attr, int priority)
1169     {
1170 gbeauche 1.14 #ifdef HAVE_PTHREADS
1171     pthread_attr_init(attr);
1172     #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
1173     // Some of these only work for superuser
1174     if (geteuid() == 0) {
1175     pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
1176     pthread_attr_setschedpolicy(attr, SCHED_FIFO);
1177     struct sched_param fifo_param;
1178     fifo_param.sched_priority = ((sched_get_priority_min(SCHED_FIFO) +
1179     sched_get_priority_max(SCHED_FIFO)) / 2 +
1180     priority);
1181     pthread_attr_setschedparam(attr, &fifo_param);
1182     }
1183     if (pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM) != 0) {
1184     #ifdef PTHREAD_SCOPE_BOUND_NP
1185     // If system scope is not available (eg. we're not running
1186     // with CAP_SCHED_MGT capability on an SGI box), try bound
1187     // scope. It exposes pthread scheduling to the kernel,
1188     // without setting realtime priority.
1189     pthread_attr_setscope(attr, PTHREAD_SCOPE_BOUND_NP);
1190     #endif
1191     }
1192     #endif
1193     #endif
1194 cebix 1.2 }
1195    
1196    
1197     /*
1198 cebix 1.1 * Mutexes
1199     */
1200    
1201 gbeauche 1.7 #ifdef HAVE_PTHREADS
1202    
1203     struct B2_mutex {
1204     B2_mutex() {
1205     pthread_mutexattr_t attr;
1206     pthread_mutexattr_init(&attr);
1207     // Initialize the mutex for priority inheritance --
1208     // required for accurate timing.
1209     #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
1210     pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
1211     #endif
1212     #if defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE) && defined(PTHREAD_MUTEX_NORMAL)
1213     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
1214     #endif
1215     #ifdef HAVE_PTHREAD_MUTEXATTR_SETPSHARED
1216     pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
1217     #endif
1218     pthread_mutex_init(&m, &attr);
1219     pthread_mutexattr_destroy(&attr);
1220     }
1221     ~B2_mutex() {
1222     pthread_mutex_trylock(&m); // Make sure it's locked before
1223     pthread_mutex_unlock(&m); // unlocking it.
1224     pthread_mutex_destroy(&m);
1225     }
1226     pthread_mutex_t m;
1227     };
1228    
1229     B2_mutex *B2_create_mutex(void)
1230     {
1231     return new B2_mutex;
1232     }
1233    
1234     void B2_lock_mutex(B2_mutex *mutex)
1235     {
1236     pthread_mutex_lock(&mutex->m);
1237     }
1238    
1239     void B2_unlock_mutex(B2_mutex *mutex)
1240     {
1241     pthread_mutex_unlock(&mutex->m);
1242     }
1243    
1244     void B2_delete_mutex(B2_mutex *mutex)
1245     {
1246     delete mutex;
1247     }
1248    
1249     #else
1250    
1251 cebix 1.1 struct B2_mutex {
1252     int dummy;
1253     };
1254    
1255     B2_mutex *B2_create_mutex(void)
1256     {
1257     return new B2_mutex;
1258     }
1259    
1260     void B2_lock_mutex(B2_mutex *mutex)
1261     {
1262     }
1263    
1264     void B2_unlock_mutex(B2_mutex *mutex)
1265     {
1266     }
1267    
1268     void B2_delete_mutex(B2_mutex *mutex)
1269     {
1270     delete mutex;
1271     }
1272    
1273 gbeauche 1.7 #endif
1274    
1275 cebix 1.1
1276     /*
1277     * Trigger signal USR2 from another thread
1278     */
1279    
1280 gbeauche 1.8 #if !EMULATED_PPC || ASYNC_IRQ
1281 cebix 1.1 void TriggerInterrupt(void)
1282     {
1283     if (ready_for_signals)
1284     pthread_kill(emul_thread, SIGUSR2);
1285     }
1286 gbeauche 1.7 #endif
1287 cebix 1.1
1288    
1289     /*
1290     * Interrupt flags (must be handled atomically!)
1291     */
1292    
1293     volatile uint32 InterruptFlags = 0;
1294    
1295     void SetInterruptFlag(uint32 flag)
1296     {
1297     atomic_or((int *)&InterruptFlags, flag);
1298     }
1299    
1300     void ClearInterruptFlag(uint32 flag)
1301     {
1302     atomic_and((int *)&InterruptFlags, ~flag);
1303     }
1304    
1305    
1306     /*
1307     * Disable interrupts
1308     */
1309    
1310     void DisableInterrupt(void)
1311     {
1312 gbeauche 1.7 atomic_add((int *)XLM_IRQ_NEST, 1);
1313 cebix 1.1 }
1314    
1315    
1316     /*
1317     * Enable interrupts
1318     */
1319    
1320     void EnableInterrupt(void)
1321     {
1322 gbeauche 1.7 atomic_add((int *)XLM_IRQ_NEST, -1);
1323 cebix 1.1 }
1324    
1325    
1326     /*
1327     * USR2 handler
1328     */
1329    
1330 gbeauche 1.8 #if EMULATED_PPC
1331     static void sigusr2_handler(int sig)
1332     {
1333     #if ASYNC_IRQ
1334     extern void HandleInterrupt(void);
1335     HandleInterrupt();
1336     #endif
1337     }
1338     #else
1339 cebix 1.1 static void sigusr2_handler(int sig, sigcontext_struct *sc)
1340     {
1341     pt_regs *r = sc->regs;
1342    
1343     // Do nothing if interrupts are disabled
1344     if (*(int32 *)XLM_IRQ_NEST > 0)
1345     return;
1346    
1347     // Disable MacOS stack sniffer
1348     WriteMacInt32(0x110, 0);
1349    
1350     // Interrupt action depends on current run mode
1351     switch (ReadMacInt32(XLM_RUN_MODE)) {
1352     case MODE_68K:
1353     // 68k emulator active, trigger 68k interrupt level 1
1354     WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1);
1355     r->ccr |= ntohl(kernel_data->v[0x674 >> 2]);
1356     break;
1357    
1358     #if INTERRUPTS_IN_NATIVE_MODE
1359     case MODE_NATIVE:
1360     // 68k emulator inactive, in nanokernel?
1361     if (r->gpr[1] != KernelDataAddr) {
1362     // Prepare for 68k interrupt level 1
1363     WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1);
1364     WriteMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc, ReadMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc) | ntohl(kernel_data->v[0x674 >> 2]));
1365    
1366     // Execute nanokernel interrupt routine (this will activate the 68k emulator)
1367     atomic_add((int32 *)XLM_IRQ_NEST, 1);
1368     if (ROMType == ROMTYPE_NEWWORLD)
1369     ppc_interrupt(ROM_BASE + 0x312b1c, KernelDataAddr);
1370     else
1371     ppc_interrupt(ROM_BASE + 0x312a3c, KernelDataAddr);
1372     }
1373     break;
1374     #endif
1375    
1376     #if INTERRUPTS_IN_EMUL_OP_MODE
1377     case MODE_EMUL_OP:
1378     // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
1379     if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) {
1380    
1381     // Set extra stack for SIGSEGV handler
1382     struct sigaltstack new_stack;
1383     new_stack.ss_sp = extra_stack;
1384     new_stack.ss_flags = 0;
1385     new_stack.ss_size = SIG_STACK_SIZE;
1386     sigaltstack(&new_stack, NULL);
1387     #if 1
1388     // Execute full 68k interrupt routine
1389     M68kRegisters r;
1390     uint32 old_r25 = ReadMacInt32(XLM_68K_R25); // Save interrupt level
1391     WriteMacInt32(XLM_68K_R25, 0x21); // Execute with interrupt level 1
1392     static const uint16 proc[] = {
1393     0x3f3c, 0x0000, // move.w #$0000,-(sp) (fake format word)
1394     0x487a, 0x000a, // pea @1(pc) (return address)
1395     0x40e7, // move sr,-(sp) (saved SR)
1396     0x2078, 0x0064, // move.l $64,a0
1397     0x4ed0, // jmp (a0)
1398     M68K_RTS // @1
1399     };
1400     Execute68k((uint32)proc, &r);
1401     WriteMacInt32(XLM_68K_R25, old_r25); // Restore interrupt level
1402     #else
1403     // Only update cursor
1404     if (HasMacStarted()) {
1405     if (InterruptFlags & INTFLAG_VIA) {
1406     ClearInterruptFlag(INTFLAG_VIA);
1407     ADBInterrupt();
1408 gbeauche 1.17 ExecuteNative(NATIVE_VIDEO_VBL);
1409 cebix 1.1 }
1410     }
1411     #endif
1412     // Reset normal signal stack
1413     new_stack.ss_sp = sig_stack;
1414     new_stack.ss_flags = 0;
1415     new_stack.ss_size = SIG_STACK_SIZE;
1416     sigaltstack(&new_stack, NULL);
1417     }
1418     break;
1419     #endif
1420     }
1421     }
1422 gbeauche 1.8 #endif
1423 cebix 1.1
1424    
1425     /*
1426     * SIGSEGV handler
1427     */
1428    
1429 gbeauche 1.8 #if !EMULATED_PPC
1430 cebix 1.1 static void sigsegv_handler(int sig, sigcontext_struct *sc)
1431     {
1432     pt_regs *r = sc->regs;
1433 gbeauche 1.5
1434     // Get effective address
1435     uint32 addr = r->dar;
1436    
1437     #if ENABLE_VOSF
1438     // Handle screen fault.
1439     extern bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction);
1440     if (Screen_fault_handler((sigsegv_address_t)addr, (sigsegv_address_t)r->nip))
1441     return;
1442     #endif
1443    
1444 cebix 1.1 num_segv++;
1445    
1446     // Fault in Mac ROM or RAM?
1447     bool mac_fault = (r->nip >= ROM_BASE) && (r->nip < (ROM_BASE + ROM_AREA_SIZE)) || (r->nip >= RAMBase) && (r->nip < (RAMBase + RAMSize));
1448     if (mac_fault) {
1449    
1450     // "VM settings" during MacOS 8 installation
1451     if (r->nip == ROM_BASE + 0x488160 && r->gpr[20] == 0xf8000000) {
1452     r->nip += 4;
1453     r->gpr[8] = 0;
1454     return;
1455    
1456     // MacOS 8.5 installation
1457     } else if (r->nip == ROM_BASE + 0x488140 && r->gpr[16] == 0xf8000000) {
1458     r->nip += 4;
1459     r->gpr[8] = 0;
1460     return;
1461    
1462     // MacOS 8 serial drivers on startup
1463     } else if (r->nip == ROM_BASE + 0x48e080 && (r->gpr[8] == 0xf3012002 || r->gpr[8] == 0xf3012000)) {
1464     r->nip += 4;
1465     r->gpr[8] = 0;
1466     return;
1467    
1468     // MacOS 8.1 serial drivers on startup
1469     } else if (r->nip == ROM_BASE + 0x48c5e0 && (r->gpr[20] == 0xf3012002 || r->gpr[20] == 0xf3012000)) {
1470     r->nip += 4;
1471     return;
1472     } else if (r->nip == ROM_BASE + 0x4a10a0 && (r->gpr[20] == 0xf3012002 || r->gpr[20] == 0xf3012000)) {
1473     r->nip += 4;
1474     return;
1475     }
1476    
1477 gbeauche 1.5 // Get opcode and divide into fields
1478     uint32 opcode = *((uint32 *)r->nip);
1479     uint32 primop = opcode >> 26;
1480     uint32 exop = (opcode >> 1) & 0x3ff;
1481     uint32 ra = (opcode >> 16) & 0x1f;
1482     uint32 rb = (opcode >> 11) & 0x1f;
1483     uint32 rd = (opcode >> 21) & 0x1f;
1484     int32 imm = (int16)(opcode & 0xffff);
1485    
1486 cebix 1.1 // Analyze opcode
1487     enum {
1488     TYPE_UNKNOWN,
1489     TYPE_LOAD,
1490     TYPE_STORE
1491     } transfer_type = TYPE_UNKNOWN;
1492     enum {
1493     SIZE_UNKNOWN,
1494     SIZE_BYTE,
1495     SIZE_HALFWORD,
1496     SIZE_WORD
1497     } transfer_size = SIZE_UNKNOWN;
1498     enum {
1499     MODE_UNKNOWN,
1500     MODE_NORM,
1501     MODE_U,
1502     MODE_X,
1503     MODE_UX
1504     } addr_mode = MODE_UNKNOWN;
1505     switch (primop) {
1506     case 31:
1507     switch (exop) {
1508     case 23: // lwzx
1509     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1510     case 55: // lwzux
1511     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1512     case 87: // lbzx
1513     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1514     case 119: // lbzux
1515     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1516     case 151: // stwx
1517     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1518     case 183: // stwux
1519     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1520     case 215: // stbx
1521     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1522     case 247: // stbux
1523     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1524     case 279: // lhzx
1525     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1526     case 311: // lhzux
1527     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1528     case 343: // lhax
1529     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1530     case 375: // lhaux
1531     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1532     case 407: // sthx
1533     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1534     case 439: // sthux
1535     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1536     }
1537     break;
1538    
1539     case 32: // lwz
1540     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1541     case 33: // lwzu
1542     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1543     case 34: // lbz
1544     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1545     case 35: // lbzu
1546     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1547     case 36: // stw
1548     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1549     case 37: // stwu
1550     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1551     case 38: // stb
1552     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1553     case 39: // stbu
1554     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1555     case 40: // lhz
1556     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1557     case 41: // lhzu
1558     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1559     case 42: // lha
1560     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1561     case 43: // lhau
1562     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1563     case 44: // sth
1564     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1565     case 45: // sthu
1566     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1567 gbeauche 1.23 #if EMULATE_UNALIGNED_LOADSTORE_MULTIPLE
1568     case 46: // lmw
1569     if (sig == SIGBUS) {
1570     uint32 ea = (ra == 0 ? 0 : r->gpr[ra]) + imm;
1571     D(bug("WARNING: unaligned lmw to EA=%08x from IP=%08x\n", ea, r->nip));
1572     for (int i = rd; i <= 31; i++) {
1573     r->gpr[i] = ReadMacInt32(ea);
1574     ea += 4;
1575     }
1576     r->nip += 4;
1577     goto rti;
1578     }
1579     break;
1580     case 47: // stmw
1581     if (sig == SIGBUS) {
1582     uint32 ea = (ra == 0 ? 0 : r->gpr[ra]) + imm;
1583     D(bug("WARNING: unaligned stmw to EA=%08x from IP=%08x\n", ea, r->nip));
1584     for (int i = rd; i <= 31; i++) {
1585     WriteMacInt32(ea, r->gpr[i]);
1586     ea += 4;
1587     }
1588     r->nip += 4;
1589     goto rti;
1590     }
1591     break;
1592     #endif
1593 cebix 1.1 }
1594    
1595     // Ignore ROM writes
1596     if (transfer_type == TYPE_STORE && addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) {
1597     // D(bug("WARNING: %s write access to ROM at %08lx, pc %08lx\n", transfer_size == SIZE_BYTE ? "Byte" : transfer_size == SIZE_HALFWORD ? "Halfword" : "Word", addr, r->nip));
1598     if (addr_mode == MODE_U || addr_mode == MODE_UX)
1599     r->gpr[ra] = addr;
1600     r->nip += 4;
1601     goto rti;
1602     }
1603    
1604     // Ignore illegal memory accesses?
1605     if (PrefsFindBool("ignoresegv")) {
1606     if (addr_mode == MODE_U || addr_mode == MODE_UX)
1607     r->gpr[ra] = addr;
1608     if (transfer_type == TYPE_LOAD)
1609     r->gpr[rd] = 0;
1610     r->nip += 4;
1611     goto rti;
1612     }
1613    
1614     // In GUI mode, show error alert
1615     if (!PrefsFindBool("nogui")) {
1616     char str[256];
1617     if (transfer_type == TYPE_LOAD || transfer_type == TYPE_STORE)
1618     sprintf(str, GetString(STR_MEM_ACCESS_ERR), transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_HALFWORD ? "halfword" : "word", transfer_type == TYPE_LOAD ? GetString(STR_MEM_ACCESS_READ) : GetString(STR_MEM_ACCESS_WRITE), addr, r->nip, r->gpr[24], r->gpr[1]);
1619     else
1620     sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->nip, r->gpr[24], r->gpr[1], opcode);
1621     ErrorAlert(str);
1622     QuitEmulator();
1623     return;
1624     }
1625     }
1626    
1627     // For all other errors, jump into debugger (sort of...)
1628 gbeauche 1.23 crash_reason = (sig == SIGBUS) ? "SIGBUS" : "SIGSEGV";
1629 cebix 1.1 if (!ready_for_signals) {
1630 gbeauche 1.23 printf("%s\n");
1631 cebix 1.1 printf(" sigcontext %p, pt_regs %p\n", sc, r);
1632     printf(
1633     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
1634     " xer %08lx cr %08lx \n"
1635     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
1636     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
1637     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
1638     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
1639     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
1640     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
1641     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
1642     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
1643 gbeauche 1.23 crash_reason,
1644 cebix 1.1 r->nip, r->link, r->ctr, r->msr,
1645     r->xer, r->ccr,
1646     r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3],
1647     r->gpr[4], r->gpr[5], r->gpr[6], r->gpr[7],
1648     r->gpr[8], r->gpr[9], r->gpr[10], r->gpr[11],
1649     r->gpr[12], r->gpr[13], r->gpr[14], r->gpr[15],
1650     r->gpr[16], r->gpr[17], r->gpr[18], r->gpr[19],
1651     r->gpr[20], r->gpr[21], r->gpr[22], r->gpr[23],
1652     r->gpr[24], r->gpr[25], r->gpr[26], r->gpr[27],
1653     r->gpr[28], r->gpr[29], r->gpr[30], r->gpr[31]);
1654     exit(1);
1655     QuitEmulator();
1656     return;
1657     } else {
1658     // We crashed. Save registers, tell tick thread and loop forever
1659     sigsegv_regs = *(sigregs *)r;
1660     emul_thread_fatal = true;
1661     for (;;) ;
1662     }
1663     rti:;
1664     }
1665    
1666    
1667     /*
1668     * SIGILL handler
1669     */
1670    
1671     static void sigill_handler(int sig, sigcontext_struct *sc)
1672     {
1673     pt_regs *r = sc->regs;
1674     char str[256];
1675    
1676     // Fault in Mac ROM or RAM?
1677     bool mac_fault = (r->nip >= ROM_BASE) && (r->nip < (ROM_BASE + ROM_AREA_SIZE)) || (r->nip >= RAMBase) && (r->nip < (RAMBase + RAMSize));
1678     if (mac_fault) {
1679    
1680     // Get opcode and divide into fields
1681     uint32 opcode = *((uint32 *)r->nip);
1682     uint32 primop = opcode >> 26;
1683     uint32 exop = (opcode >> 1) & 0x3ff;
1684     uint32 ra = (opcode >> 16) & 0x1f;
1685     uint32 rb = (opcode >> 11) & 0x1f;
1686     uint32 rd = (opcode >> 21) & 0x1f;
1687     int32 imm = (int16)(opcode & 0xffff);
1688    
1689     switch (primop) {
1690     case 9: // POWER instructions
1691     case 22:
1692     power_inst: sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->nip, r->gpr[1], opcode);
1693     ErrorAlert(str);
1694     QuitEmulator();
1695     return;
1696    
1697     case 31:
1698     switch (exop) {
1699     case 83: // mfmsr
1700     r->gpr[rd] = 0xf072;
1701     r->nip += 4;
1702     goto rti;
1703    
1704     case 210: // mtsr
1705     case 242: // mtsrin
1706     case 306: // tlbie
1707     r->nip += 4;
1708     goto rti;
1709    
1710     case 339: { // mfspr
1711     int spr = ra | (rb << 5);
1712     switch (spr) {
1713     case 0: // MQ
1714     case 22: // DEC
1715     case 952: // MMCR0
1716     case 953: // PMC1
1717     case 954: // PMC2
1718     case 955: // SIA
1719     case 956: // MMCR1
1720     case 957: // PMC3
1721     case 958: // PMC4
1722     case 959: // SDA
1723     r->nip += 4;
1724     goto rti;
1725     case 25: // SDR1
1726     r->gpr[rd] = 0xdead001f;
1727     r->nip += 4;
1728     goto rti;
1729     case 287: // PVR
1730     r->gpr[rd] = PVR;
1731     r->nip += 4;
1732     goto rti;
1733     }
1734     break;
1735     }
1736    
1737     case 467: { // mtspr
1738     int spr = ra | (rb << 5);
1739     switch (spr) {
1740     case 0: // MQ
1741     case 22: // DEC
1742     case 275: // SPRG3
1743     case 528: // IBAT0U
1744     case 529: // IBAT0L
1745     case 530: // IBAT1U
1746     case 531: // IBAT1L
1747     case 532: // IBAT2U
1748     case 533: // IBAT2L
1749     case 534: // IBAT3U
1750     case 535: // IBAT3L
1751     case 536: // DBAT0U
1752     case 537: // DBAT0L
1753     case 538: // DBAT1U
1754     case 539: // DBAT1L
1755     case 540: // DBAT2U
1756     case 541: // DBAT2L
1757     case 542: // DBAT3U
1758     case 543: // DBAT3L
1759     case 952: // MMCR0
1760     case 953: // PMC1
1761     case 954: // PMC2
1762     case 955: // SIA
1763     case 956: // MMCR1
1764     case 957: // PMC3
1765     case 958: // PMC4
1766     case 959: // SDA
1767     r->nip += 4;
1768     goto rti;
1769     }
1770     break;
1771     }
1772    
1773     case 29: case 107: case 152: case 153: // POWER instructions
1774     case 184: case 216: case 217: case 248:
1775     case 264: case 277: case 331: case 360:
1776     case 363: case 488: case 531: case 537:
1777     case 541: case 664: case 665: case 696:
1778     case 728: case 729: case 760: case 920:
1779     case 921: case 952:
1780     goto power_inst;
1781     }
1782     }
1783    
1784     // In GUI mode, show error alert
1785     if (!PrefsFindBool("nogui")) {
1786     sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->nip, r->gpr[24], r->gpr[1], opcode);
1787     ErrorAlert(str);
1788     QuitEmulator();
1789     return;
1790     }
1791     }
1792    
1793     // For all other errors, jump into debugger (sort of...)
1794 gbeauche 1.23 crash_reason = "SIGILL";
1795 cebix 1.1 if (!ready_for_signals) {
1796 gbeauche 1.23 printf("%s\n");
1797 cebix 1.1 printf(" sigcontext %p, pt_regs %p\n", sc, r);
1798     printf(
1799     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
1800     " xer %08lx cr %08lx \n"
1801     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
1802     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
1803     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
1804     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
1805     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
1806     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
1807     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
1808     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
1809 gbeauche 1.23 crash_reason,
1810 cebix 1.1 r->nip, r->link, r->ctr, r->msr,
1811     r->xer, r->ccr,
1812     r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3],
1813     r->gpr[4], r->gpr[5], r->gpr[6], r->gpr[7],
1814     r->gpr[8], r->gpr[9], r->gpr[10], r->gpr[11],
1815     r->gpr[12], r->gpr[13], r->gpr[14], r->gpr[15],
1816     r->gpr[16], r->gpr[17], r->gpr[18], r->gpr[19],
1817     r->gpr[20], r->gpr[21], r->gpr[22], r->gpr[23],
1818     r->gpr[24], r->gpr[25], r->gpr[26], r->gpr[27],
1819     r->gpr[28], r->gpr[29], r->gpr[30], r->gpr[31]);
1820     exit(1);
1821     QuitEmulator();
1822     return;
1823     } else {
1824     // We crashed. Save registers, tell tick thread and loop forever
1825     sigsegv_regs = *(sigregs *)r;
1826     emul_thread_fatal = true;
1827     for (;;) ;
1828     }
1829     rti:;
1830     }
1831     #endif
1832 gbeauche 1.15
1833    
1834     /*
1835     * Helpers to share 32-bit addressable data with MacOS
1836     */
1837    
1838     bool SheepMem::Init(void)
1839     {
1840 gbeauche 1.20 const int page_size = getpagesize();
1841    
1842     // Allocate SheepShaver globals
1843 gbeauche 1.15 if (vm_acquire_fixed((char *)base, size) < 0)
1844     return false;
1845 gbeauche 1.18
1846 gbeauche 1.20 // Allocate page with all bits set to 0
1847 gbeauche 1.18 zero_page = base + size;
1848     if (vm_acquire_fixed((char *)zero_page, page_size) < 0)
1849     return false;
1850 gbeauche 1.19 memset((char *)zero_page, 0, page_size);
1851 gbeauche 1.18 if (vm_protect((char *)zero_page, page_size, VM_PAGE_READ) < 0)
1852     return false;
1853    
1854 gbeauche 1.20 #if EMULATED_PPC
1855     // Allocate alternate stack for PowerPC interrupt routine
1856     sig_stack = zero_page + page_size;
1857     if (vm_acquire_fixed((char *)sig_stack, SIG_STACK_SIZE) < 0)
1858     return false;
1859     #endif
1860    
1861 gbeauche 1.15 top = base + size;
1862     return true;
1863     }
1864    
1865     void SheepMem::Exit(void)
1866     {
1867 gbeauche 1.18 if (top) {
1868 gbeauche 1.20 const int page_size = getpagesize();
1869    
1870     // Delete SheepShaver globals
1871     vm_release((void *)base, size);
1872    
1873     // Delete zero page
1874     vm_release((void *)zero_page, page_size);
1875    
1876     #if EMULATED_PPC
1877     // Delete alternate stack for PowerPC interrupt routine
1878     vm_release((void *)sig_stack, SIG_STACK_SIZE);
1879     #endif
1880 gbeauche 1.18 }
1881 gbeauche 1.15 }
1882 cebix 1.1
1883    
1884     /*
1885     * Display alert
1886     */
1887    
1888     #ifdef ENABLE_GTK
1889     static void dl_destroyed(void)
1890     {
1891     gtk_main_quit();
1892     }
1893    
1894     static void dl_quit(GtkWidget *dialog)
1895     {
1896     gtk_widget_destroy(dialog);
1897     }
1898    
1899     void display_alert(int title_id, int prefix_id, int button_id, const char *text)
1900     {
1901     char str[256];
1902     sprintf(str, GetString(prefix_id), text);
1903    
1904     GtkWidget *dialog = gtk_dialog_new();
1905     gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id));
1906     gtk_container_border_width(GTK_CONTAINER(dialog), 5);
1907     gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
1908     gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL);
1909    
1910     GtkWidget *label = gtk_label_new(str);
1911     gtk_widget_show(label);
1912     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
1913    
1914     GtkWidget *button = gtk_button_new_with_label(GetString(button_id));
1915     gtk_widget_show(button);
1916     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
1917     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
1918     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1919     gtk_widget_grab_default(button);
1920     gtk_widget_show(dialog);
1921    
1922     gtk_main();
1923     }
1924     #endif
1925    
1926    
1927     /*
1928     * Display error alert
1929     */
1930    
1931     void ErrorAlert(const char *text)
1932     {
1933     #ifdef ENABLE_GTK
1934     if (PrefsFindBool("nogui") || x_display == NULL) {
1935     printf(GetString(STR_SHELL_ERROR_PREFIX), text);
1936     return;
1937     }
1938     VideoQuitFullScreen();
1939     display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text);
1940     #else
1941     printf(GetString(STR_SHELL_ERROR_PREFIX), text);
1942     #endif
1943     }
1944    
1945    
1946     /*
1947     * Display warning alert
1948     */
1949    
1950     void WarningAlert(const char *text)
1951     {
1952     #ifdef ENABLE_GTK
1953     if (PrefsFindBool("nogui") || x_display == NULL) {
1954     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
1955     return;
1956     }
1957     display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text);
1958     #else
1959     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
1960     #endif
1961     }
1962    
1963    
1964     /*
1965     * Display choice alert
1966     */
1967    
1968     bool ChoiceAlert(const char *text, const char *pos, const char *neg)
1969     {
1970     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
1971     return false; //!!
1972     }