ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/main_unix.cpp
Revision: 1.21
Committed: 2003-12-31T18:16:55Z (20 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.20: +3 -0 lines
Log Message:
Add fast X11 display locking routines based on spinlocks, or on pthreads
in the worst case. Optimize out GetScrap() case when we already own the
selection. i.e. make it smoother. Use our own XDisplay{Un,}Lock() routines.

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