ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/main_unix.cpp
Revision: 1.4
Committed: 2003-05-13T16:59:57Z (21 years, 4 months ago) by gbeauche
Branch: MAIN
Changes since 1.3: +22 -7 lines
Log Message:
Use vm_acquire/vm_acquire_fixed/vm_release API. Prepare use of SIGSEGV
handlers and instruction skippers. Fix test prior to including posix_sem.cpp.

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