ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/main_unix.cpp
Revision: 1.53
Committed: 2004-11-22T21:33:32Z (19 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.52: +137 -52 lines
Log Message:
New SheepShaver globals layout, move ZeroPage into the middle. Since it is
a read-only page, it can also be used to detect overlaps between Procedure
space and Data space.

Provide native Windows implementation of shared MacOS KernelData allocation.
This is moved under main() so that to avoid a weird linking error. This native
implementation is independent of Cygwin IPC (and possible background server)

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * main_unix.cpp - Emulation core, Unix implementation
3     *
4 cebix 1.25 * SheepShaver (C) 1997-2004 Christian Bauer and Marc Hellwig
5 cebix 1.1 *
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 gbeauche 1.33 * There is apparently another problem when processing signals. In
69     * fullscreen mode, we get quick updates of the mouse position. This
70     * causes an increased number of calls to TriggerInterrupt(). And,
71     * since IRQ_NEST is not fully handled atomically, nested calls to
72     * ppc_interrupt() may cause stack corruption to eventually crash the
73     * emulator.
74     *
75     * FIXME:
76     * The current solution is to allocate another signal stack when
77     * processing ppc_interrupt(). However, it may be better to detect
78     * the INTFLAG_ADB case and handle it specifically with some extra mutex?
79     *
80 cebix 1.1 * TODO:
81     * check if SIGSEGV handler works for all registers (including FP!)
82     */
83    
84     #include <unistd.h>
85     #include <fcntl.h>
86     #include <time.h>
87     #include <errno.h>
88     #include <stdio.h>
89     #include <stdlib.h>
90     #include <string.h>
91     #include <pthread.h>
92     #include <sys/mman.h>
93     #include <sys/ipc.h>
94     #include <sys/shm.h>
95     #include <signal.h>
96    
97     #include "sysdeps.h"
98     #include "main.h"
99     #include "version.h"
100     #include "prefs.h"
101     #include "prefs_editor.h"
102     #include "cpu_emulation.h"
103     #include "emul_op.h"
104     #include "xlowmem.h"
105     #include "xpram.h"
106     #include "timer.h"
107     #include "adb.h"
108     #include "sony.h"
109     #include "disk.h"
110     #include "cdrom.h"
111     #include "scsi.h"
112     #include "video.h"
113     #include "audio.h"
114     #include "ether.h"
115     #include "serial.h"
116     #include "clip.h"
117     #include "extfs.h"
118     #include "sys.h"
119     #include "macos_util.h"
120     #include "rom_patches.h"
121     #include "user_strings.h"
122 gbeauche 1.4 #include "vm_alloc.h"
123 gbeauche 1.5 #include "sigsegv.h"
124 gbeauche 1.15 #include "thunks.h"
125 cebix 1.1
126     #define DEBUG 0
127     #include "debug.h"
128    
129    
130 gbeauche 1.47 #ifdef HAVE_DIRENT_H
131     #include <dirent.h>
132     #endif
133    
134 gbeauche 1.42 #ifdef USE_SDL
135     #include <SDL.h>
136     #endif
137    
138     #ifndef USE_SDL_VIDEO
139 cebix 1.1 #include <X11/Xlib.h>
140 gbeauche 1.42 #endif
141 cebix 1.1
142     #ifdef ENABLE_GTK
143     #include <gtk/gtk.h>
144     #endif
145    
146     #ifdef ENABLE_XF86_DGA
147     #include <X11/Xlib.h>
148     #include <X11/Xutil.h>
149     #include <X11/extensions/xf86dga.h>
150     #endif
151    
152     #ifdef ENABLE_MON
153     #include "mon.h"
154     #endif
155    
156    
157 gbeauche 1.23 // Enable emulation of unaligned lmw/stmw?
158     #define EMULATE_UNALIGNED_LOADSTORE_MULTIPLE 1
159    
160 cebix 1.1 // Enable Execute68k() safety checks?
161     #define SAFE_EXEC_68K 0
162    
163     // Interrupts in EMUL_OP mode?
164     #define INTERRUPTS_IN_EMUL_OP_MODE 1
165    
166     // Interrupts in native mode?
167     #define INTERRUPTS_IN_NATIVE_MODE 1
168    
169 gbeauche 1.33 // Number of alternate stacks for signal handlers?
170     #define SIG_STACK_COUNT 4
171    
172 cebix 1.1
173     // Constants
174     const char ROM_FILE_NAME[] = "ROM";
175     const char ROM_FILE_NAME2[] = "Mac OS ROM";
176    
177 gbeauche 1.52 #if REAL_ADDRESSING
178 gbeauche 1.15 const uintptr RAM_BASE = 0x20000000; // Base address of RAM
179 gbeauche 1.52 #else
180     // FIXME: needs to be >= 0x04000000
181     const uintptr RAM_BASE = 0x10000000; // Base address of RAM
182     #endif
183 cebix 1.1 const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack
184    
185    
186     #if !EMULATED_PPC
187 gbeauche 1.26 struct sigregs {
188     uint32 nip;
189     uint32 link;
190     uint32 ctr;
191     uint32 msr;
192     uint32 xer;
193     uint32 ccr;
194     uint32 gpr[32];
195     };
196 cebix 1.1
197 gbeauche 1.26 #if defined(__linux__)
198 gbeauche 1.28 #include <sys/ucontext.h>
199     #define MACHINE_REGISTERS(scp) ((machine_regs *)(((ucontext_t *)scp)->uc_mcontext.regs))
200    
201 gbeauche 1.26 struct machine_regs : public pt_regs
202     {
203     u_long & cr() { return pt_regs::ccr; }
204     uint32 cr() const { return pt_regs::ccr; }
205     uint32 lr() const { return pt_regs::link; }
206     uint32 ctr() const { return pt_regs::ctr; }
207     uint32 xer() const { return pt_regs::xer; }
208     uint32 msr() const { return pt_regs::msr; }
209     uint32 dar() const { return pt_regs::dar; }
210     u_long & pc() { return pt_regs::nip; }
211     uint32 pc() const { return pt_regs::nip; }
212     u_long & gpr(int i) { return pt_regs::gpr[i]; }
213     uint32 gpr(int i) const { return pt_regs::gpr[i]; }
214 cebix 1.1 };
215 gbeauche 1.28 #endif
216    
217     #if defined(__APPLE__) && defined(__MACH__)
218     #include <sys/signal.h>
219     extern "C" int sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
220 gbeauche 1.26
221     #include <sys/ucontext.h>
222 gbeauche 1.28 #define MACHINE_REGISTERS(scp) ((machine_regs *)(((ucontext_t *)scp)->uc_mcontext))
223 gbeauche 1.26
224     struct machine_regs : public mcontext
225     {
226     uint32 & cr() { return ss.cr; }
227     uint32 cr() const { return ss.cr; }
228     uint32 lr() const { return ss.lr; }
229     uint32 ctr() const { return ss.ctr; }
230     uint32 xer() const { return ss.xer; }
231     uint32 msr() const { return ss.srr1; }
232     uint32 dar() const { return es.dar; }
233     uint32 & pc() { return ss.srr0; }
234     uint32 pc() const { return ss.srr0; }
235     uint32 & gpr(int i) { return (&ss.r0)[i]; }
236     uint32 gpr(int i) const { return (&ss.r0)[i]; }
237     };
238     #endif
239    
240     static void build_sigregs(sigregs *srp, machine_regs *mrp)
241     {
242     srp->nip = mrp->pc();
243     srp->link = mrp->lr();
244     srp->ctr = mrp->ctr();
245     srp->msr = mrp->msr();
246     srp->xer = mrp->xer();
247     srp->ccr = mrp->cr();
248     for (int i = 0; i < 32; i++)
249     srp->gpr[i] = mrp->gpr(i);
250     }
251 gbeauche 1.33
252     static struct sigaltstack sig_stacks[SIG_STACK_COUNT]; // Stacks for signal handlers
253     static int sig_stack_id = 0; // Stack slot currently used
254    
255     static inline void sig_stack_acquire(void)
256     {
257     if (++sig_stack_id == SIG_STACK_COUNT) {
258     printf("FATAL: signal stack overflow\n");
259     return;
260     }
261     sigaltstack(&sig_stacks[sig_stack_id], NULL);
262     }
263    
264     static inline void sig_stack_release(void)
265     {
266     if (--sig_stack_id < 0) {
267     printf("FATAL: signal stack underflow\n");
268     return;
269     }
270     sigaltstack(&sig_stacks[sig_stack_id], NULL);
271     }
272 cebix 1.1 #endif
273    
274    
275     // Global variables (exported)
276     #if !EMULATED_PPC
277     void *TOC; // Small data pointer (r13)
278     #endif
279     uint32 RAMBase; // Base address of Mac RAM
280     uint32 RAMSize; // Size of Mac RAM
281     uint32 KernelDataAddr; // Address of Kernel Data
282     uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM
283 gbeauche 1.36 uint32 DRCacheAddr; // Address of DR Cache
284 cebix 1.1 uint32 PVR; // Theoretical PVR
285     int64 CPUClockSpeed; // Processor clock speed (Hz)
286     int64 BusClockSpeed; // Bus clock speed (Hz)
287 gbeauche 1.47 int64 TimebaseSpeed; // Timebase clock speed (Hz)
288 gbeauche 1.52 uint8 *RAMBaseHost; // Base address of Mac RAM (host address space)
289     uint8 *ROMBaseHost; // Base address of Mac ROM (host address space)
290 cebix 1.1
291    
292     // Global variables
293 gbeauche 1.42 #ifndef USE_SDL_VIDEO
294 gbeauche 1.11 char *x_display_name = NULL; // X11 display name
295 cebix 1.1 Display *x_display = NULL; // X11 display handle
296 gbeauche 1.21 #ifdef X11_LOCK_TYPE
297     X11_LOCK_TYPE x_display_lock = X11_LOCK_INIT; // X11 display lock
298     #endif
299 gbeauche 1.42 #endif
300 cebix 1.1
301     static int zero_fd = 0; // FD of /dev/zero
302     static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped
303     static int kernel_area = -1; // SHM ID of Kernel Data area
304     static bool rom_area_mapped = false; // Flag: Mac ROM mmap()ped
305     static bool ram_area_mapped = false; // Flag: Mac RAM mmap()ped
306 gbeauche 1.36 static bool dr_cache_area_mapped = false; // Flag: Mac DR Cache mmap()ped
307     static bool dr_emulator_area_mapped = false;// Flag: Mac DR Emulator mmap()ped
308 cebix 1.1 static KernelData *kernel_data; // Pointer to Kernel Data
309     static EmulatorData *emulator_data;
310    
311     static uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes
312    
313     static bool nvram_thread_active = false; // Flag: NVRAM watchdog installed
314 gbeauche 1.40 static volatile bool nvram_thread_cancel; // Flag: Cancel NVRAM thread
315 cebix 1.1 static pthread_t nvram_thread; // NVRAM watchdog
316     static bool tick_thread_active = false; // Flag: MacOS thread installed
317 gbeauche 1.40 static volatile bool tick_thread_cancel; // Flag: Cancel 60Hz thread
318 cebix 1.1 static pthread_t tick_thread; // 60Hz thread
319     static pthread_t emul_thread; // MacOS thread
320    
321     static bool ready_for_signals = false; // Handler installed, signals can be sent
322     static int64 num_segv = 0; // Number of handled SEGV signals
323    
324 gbeauche 1.6 static struct sigaction sigusr2_action; // Interrupt signal (of emulator thread)
325 gbeauche 1.20 #if EMULATED_PPC
326     static uintptr sig_stack = 0; // Stack for PowerPC interrupt routine
327     #else
328 cebix 1.1 static struct sigaction sigsegv_action; // Data access exception signal (of emulator thread)
329     static struct sigaction sigill_action; // Illegal instruction signal (of emulator thread)
330     static bool emul_thread_fatal = false; // Flag: MacOS thread crashed, tick thread shall dump debug output
331     static sigregs sigsegv_regs; // Register dump when crashed
332 gbeauche 1.23 static const char *crash_reason = NULL; // Reason of the crash (SIGSEGV, SIGBUS, SIGILL)
333 cebix 1.1 #endif
334    
335 gbeauche 1.31 uint32 SheepMem::page_size; // Size of a native page
336 gbeauche 1.18 uintptr SheepMem::zero_page = 0; // Address of ro page filled in with zeros
337 gbeauche 1.15 uintptr SheepMem::base = 0x60000000; // Address of SheepShaver data
338 gbeauche 1.53 uintptr SheepMem::proc; // Bottom address of SheepShave procedures
339     uintptr SheepMem::data; // Top of SheepShaver data (stack like storage)
340 gbeauche 1.15
341 cebix 1.1
342     // Prototypes
343 gbeauche 1.53 static bool kernel_data_init(void);
344     static void kernel_data_exit(void);
345 cebix 1.1 static void Quit(void);
346     static void *emul_func(void *arg);
347     static void *nvram_func(void *arg);
348     static void *tick_func(void *arg);
349 gbeauche 1.8 #if EMULATED_PPC
350 gbeauche 1.13 extern void emul_ppc(uint32 start);
351     extern void init_emul_ppc(void);
352     extern void exit_emul_ppc(void);
353 gbeauche 1.43 sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t);
354 gbeauche 1.8 #else
355 gbeauche 1.26 static void sigusr2_handler(int sig, siginfo_t *sip, void *scp);
356     static void sigsegv_handler(int sig, siginfo_t *sip, void *scp);
357     static void sigill_handler(int sig, siginfo_t *sip, void *scp);
358 cebix 1.1 #endif
359    
360    
361     // From asm_linux.S
362 gbeauche 1.12 #if !EMULATED_PPC
363 cebix 1.1 extern "C" void *get_toc(void);
364     extern "C" void *get_sp(void);
365     extern "C" void flush_icache_range(void *start, void *end);
366     extern "C" void jump_to_rom(uint32 entry, uint32 context);
367     extern "C" void quit_emulator(void);
368     extern "C" void execute_68k(uint32 pc, M68kRegisters *r);
369     extern "C" void ppc_interrupt(uint32 entry, uint32 kernel_data);
370     extern "C" int atomic_add(int *var, int v);
371     extern "C" int atomic_and(int *var, int v);
372     extern "C" int atomic_or(int *var, int v);
373     extern void paranoia_check(void);
374 gbeauche 1.12 #endif
375    
376    
377     #if EMULATED_PPC
378     /*
379 gbeauche 1.20 * Return signal stack base
380     */
381    
382     uintptr SignalStackBase(void)
383     {
384     return sig_stack + SIG_STACK_SIZE;
385     }
386    
387    
388     /*
389 gbeauche 1.12 * Atomic operations
390     */
391    
392     #if HAVE_SPINLOCKS
393     static spinlock_t atomic_ops_lock = SPIN_LOCK_UNLOCKED;
394     #else
395     #define spin_lock(LOCK)
396     #define spin_unlock(LOCK)
397     #endif
398    
399     int atomic_add(int *var, int v)
400     {
401     spin_lock(&atomic_ops_lock);
402     int ret = *var;
403     *var += v;
404     spin_unlock(&atomic_ops_lock);
405     return ret;
406     }
407    
408     int atomic_and(int *var, int v)
409     {
410     spin_lock(&atomic_ops_lock);
411     int ret = *var;
412     *var &= v;
413     spin_unlock(&atomic_ops_lock);
414     return ret;
415     }
416    
417     int atomic_or(int *var, int v)
418     {
419     spin_lock(&atomic_ops_lock);
420     int ret = *var;
421     *var |= v;
422     spin_unlock(&atomic_ops_lock);
423     return ret;
424     }
425 cebix 1.1 #endif
426    
427    
428     /*
429 gbeauche 1.53 * Memory management helpers
430     */
431    
432     static inline int vm_mac_acquire(uint32 addr, uint32 size)
433     {
434     return vm_acquire_fixed(Mac2HostAddr(addr), size);
435     }
436    
437     static inline int vm_mac_release(uint32 addr, uint32 size)
438     {
439     return vm_release(Mac2HostAddr(addr), size);
440     }
441    
442    
443     /*
444 cebix 1.1 * Main program
445     */
446    
447     static void usage(const char *prg_name)
448     {
449     printf("Usage: %s [OPTION...]\n", prg_name);
450     printf("\nUnix options:\n");
451     printf(" --display STRING\n X display to use\n");
452     PrefsPrintUsage();
453     exit(0);
454     }
455    
456     int main(int argc, char **argv)
457     {
458     char str[256];
459     int16 i16;
460     int rom_fd;
461     FILE *proc_file;
462     const char *rom_path;
463     uint32 rom_size, actual;
464     uint8 *rom_tmp;
465     time_t now, expire;
466    
467     // Initialize variables
468     RAMBase = 0;
469     tzset();
470    
471     // Print some info
472     printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
473     printf(" %s\n", GetString(STR_ABOUT_TEXT2));
474    
475     #if !EMULATED_PPC
476     // Get TOC pointer
477     TOC = get_toc();
478     #endif
479    
480     #ifdef ENABLE_GTK
481     // Init GTK
482     gtk_set_locale();
483     gtk_init(&argc, &argv);
484     #endif
485    
486     // Read preferences
487     PrefsInit(argc, argv);
488    
489     // Parse command line arguments
490     for (int i=1; i<argc; i++) {
491     if (strcmp(argv[i], "--help") == 0) {
492     usage(argv[0]);
493 gbeauche 1.42 #ifndef USE_SDL_VIDEO
494 cebix 1.1 } else if (strcmp(argv[i], "--display") == 0) {
495     i++;
496     if (i < argc)
497     x_display_name = strdup(argv[i]);
498 gbeauche 1.42 #endif
499 cebix 1.1 } else if (argv[i][0] == '-') {
500     fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
501     usage(argv[0]);
502     }
503     }
504    
505 gbeauche 1.42 #ifdef USE_SDL
506     // Initialize SDL system
507     int sdl_flags = 0;
508     #ifdef USE_SDL_VIDEO
509     sdl_flags |= SDL_INIT_VIDEO;
510     #endif
511 gbeauche 1.51 #ifdef USE_SDL_AUDIO
512     sdl_flags |= SDL_INIT_AUDIO;
513     #endif
514 gbeauche 1.42 assert(sdl_flags != 0);
515     if (SDL_Init(sdl_flags) == -1) {
516     char str[256];
517     sprintf(str, "Could not initialize SDL: %s.\n", SDL_GetError());
518     ErrorAlert(str);
519     goto quit;
520     }
521     atexit(SDL_Quit);
522     #endif
523    
524     #ifndef USE_SDL_VIDEO
525 cebix 1.1 // Open display
526     x_display = XOpenDisplay(x_display_name);
527     if (x_display == NULL) {
528     char str[256];
529     sprintf(str, GetString(STR_NO_XSERVER_ERR), XDisplayName(x_display_name));
530     ErrorAlert(str);
531     goto quit;
532     }
533    
534     #if defined(ENABLE_XF86_DGA) && !defined(ENABLE_MON)
535     // Fork out, so we can return from fullscreen mode when things get ugly
536     XF86DGAForkApp(DefaultScreen(x_display));
537     #endif
538 gbeauche 1.42 #endif
539 cebix 1.1
540     #ifdef ENABLE_MON
541     // Initialize mon
542     mon_init();
543     #endif
544    
545 gbeauche 1.43 #if !EMULATED_PPC
546 gbeauche 1.44 // Create and install stacks for signal handlers
547     for (int i = 0; i < SIG_STACK_COUNT; i++) {
548     void *sig_stack = malloc(SIG_STACK_SIZE);
549     D(bug("Signal stack %d at %p\n", i, sig_stack));
550     if (sig_stack == NULL) {
551     ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
552     goto quit;
553     }
554     sig_stacks[i].ss_sp = sig_stack;
555     sig_stacks[i].ss_flags = 0;
556     sig_stacks[i].ss_size = SIG_STACK_SIZE;
557     }
558     sig_stack_id = 0;
559     if (sigaltstack(&sig_stacks[0], NULL) < 0) {
560     sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno));
561     ErrorAlert(str);
562     goto quit;
563     }
564     #endif
565    
566     #if !EMULATED_PPC
567 gbeauche 1.43 // Install SIGSEGV and SIGBUS handlers
568     sigemptyset(&sigsegv_action.sa_mask); // Block interrupts during SEGV handling
569     sigaddset(&sigsegv_action.sa_mask, SIGUSR2);
570     sigsegv_action.sa_sigaction = sigsegv_handler;
571     sigsegv_action.sa_flags = SA_ONSTACK | SA_SIGINFO;
572     #ifdef HAVE_SIGNAL_SA_RESTORER
573     sigsegv_action.sa_restorer = NULL;
574     #endif
575     if (sigaction(SIGSEGV, &sigsegv_action, NULL) < 0) {
576     sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno));
577     ErrorAlert(str);
578     goto quit;
579     }
580     if (sigaction(SIGBUS, &sigsegv_action, NULL) < 0) {
581     sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno));
582     ErrorAlert(str);
583     goto quit;
584     }
585     #else
586     // Install SIGSEGV handler for CPU emulator
587     if (!sigsegv_install_handler(sigsegv_handler)) {
588     sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno));
589     ErrorAlert(str);
590     goto quit;
591     }
592     #endif
593    
594     // Initialize VM system
595     vm_init();
596    
597 cebix 1.1 // Get system info
598     PVR = 0x00040000; // Default: 604
599     CPUClockSpeed = 100000000; // Default: 100MHz
600     BusClockSpeed = 100000000; // Default: 100MHz
601 gbeauche 1.47 TimebaseSpeed = 25000000; // Default: 25MHz
602 gbeauche 1.30 #if EMULATED_PPC
603     PVR = 0x000c0000; // Default: 7400 (with AltiVec)
604 gbeauche 1.39 #elif defined(__APPLE__) && defined(__MACH__)
605     proc_file = popen("ioreg -c IOPlatformDevice", "r");
606     if (proc_file) {
607     char line[256];
608     bool powerpc_node = false;
609     while (fgets(line, sizeof(line) - 1, proc_file)) {
610     // Read line
611     int len = strlen(line);
612     if (len == 0)
613     continue;
614     line[len - 1] = 0;
615    
616     // Parse line
617     if (strstr(line, "o PowerPC,"))
618     powerpc_node = true;
619     else if (powerpc_node) {
620     uint32 value;
621     char head[256];
622     if (sscanf(line, "%[ |]\"cpu-version\" = <%x>", head, &value) == 2)
623     PVR = value;
624     else if (sscanf(line, "%[ |]\"clock-frequency\" = <%x>", head, &value) == 2)
625     CPUClockSpeed = value;
626     else if (sscanf(line, "%[ |]\"bus-frequency\" = <%x>", head, &value) == 2)
627     BusClockSpeed = value;
628 gbeauche 1.48 else if (sscanf(line, "%[ |]\"timebase-frequency\" = <%x>", head, &value) == 2)
629     TimebaseSpeed = value;
630 gbeauche 1.39 else if (strchr(line, '}'))
631     powerpc_node = false;
632     }
633     }
634     fclose(proc_file);
635     } else {
636     sprintf(str, GetString(STR_PROC_CPUINFO_WARN), strerror(errno));
637     WarningAlert(str);
638     }
639 gbeauche 1.30 #else
640 cebix 1.1 proc_file = fopen("/proc/cpuinfo", "r");
641     if (proc_file) {
642 gbeauche 1.50 // CPU specs from Linux kernel
643     // TODO: make it more generic with features (e.g. AltiVec) and
644     // cache information and friends for NameRegistry
645     static const struct {
646     uint32 pvr_mask;
647     uint32 pvr_value;
648     const char *cpu_name;
649     }
650     cpu_specs[] = {
651     { 0xffff0000, 0x00010000, "601" },
652     { 0xffff0000, 0x00030000, "603" },
653     { 0xffff0000, 0x00060000, "603e" },
654     { 0xffff0000, 0x00070000, "603ev" },
655     { 0xffff0000, 0x00040000, "604" },
656     { 0xfffff000, 0x00090000, "604e" },
657     { 0xffff0000, 0x00090000, "604r" },
658     { 0xffff0000, 0x000a0000, "604ev" },
659     { 0xffffffff, 0x00084202, "740/750" },
660     { 0xfffff000, 0x00083000, "745/755" },
661     { 0xfffffff0, 0x00080100, "750CX" },
662     { 0xfffffff0, 0x00082200, "750CX" },
663     { 0xfffffff0, 0x00082210, "750CXe" },
664     { 0xffffff00, 0x70000100, "750FX" },
665     { 0xffffffff, 0x70000200, "750FX" },
666     { 0xffff0000, 0x70000000, "750FX" },
667     { 0xffff0000, 0x70020000, "750GX" },
668     { 0xffff0000, 0x00080000, "740/750" },
669     { 0xffffffff, 0x000c1101, "7400 (1.1)" },
670     { 0xffff0000, 0x000c0000, "7400" },
671     { 0xffff0000, 0x800c0000, "7410" },
672     { 0xffffffff, 0x80000200, "7450" },
673     { 0xffffffff, 0x80000201, "7450" },
674     { 0xffff0000, 0x80000000, "7450" },
675     { 0xffffff00, 0x80010100, "7455" },
676     { 0xffffffff, 0x80010200, "7455" },
677     { 0xffff0000, 0x80010000, "7455" },
678     { 0xffff0000, 0x80020000, "7457" },
679     { 0xffff0000, 0x80030000, "7447A" },
680     { 0x7fff0000, 0x00810000, "82xx" },
681     { 0x7fff0000, 0x00820000, "8280" },
682     { 0xffff0000, 0x00400000, "Power3 (630)" },
683     { 0xffff0000, 0x00410000, "Power3 (630+)" },
684     { 0xffff0000, 0x00360000, "I-star" },
685     { 0xffff0000, 0x00370000, "S-star" },
686     { 0xffff0000, 0x00350000, "Power4" },
687     { 0xffff0000, 0x00390000, "PPC970" },
688     { 0, 0, 0 }
689     };
690    
691 cebix 1.1 char line[256];
692     while(fgets(line, 255, proc_file)) {
693     // Read line
694     int len = strlen(line);
695     if (len == 0)
696     continue;
697     line[len-1] = 0;
698    
699     // Parse line
700     int i;
701     char value[256];
702 gbeauche 1.29 if (sscanf(line, "cpu : %[0-9A-Za-a]", value) == 1) {
703 gbeauche 1.50 // Search by name
704     const char *cpu_name = NULL;
705     for (int i = 0; cpu_specs[i].pvr_mask != 0; i++) {
706     if (strcmp(cpu_specs[i].cpu_name, value) == 0) {
707     cpu_name = cpu_specs[i].cpu_name;
708     PVR = cpu_specs[i].pvr_value;
709     break;
710     }
711     }
712     if (cpu_name == NULL)
713     printf("WARNING: Unknown CPU type '%s', assuming 604\n", value);
714 cebix 1.1 else
715 gbeauche 1.50 printf("Found a PowerPC %s processor\n", cpu_name);
716 cebix 1.1 }
717     if (sscanf(line, "clock : %dMHz", &i) == 1)
718     CPUClockSpeed = BusClockSpeed = i * 1000000;
719     }
720     fclose(proc_file);
721     } else {
722     sprintf(str, GetString(STR_PROC_CPUINFO_WARN), strerror(errno));
723     WarningAlert(str);
724     }
725 gbeauche 1.34
726     // Get actual bus frequency
727     proc_file = fopen("/proc/device-tree/clock-frequency", "r");
728     if (proc_file) {
729     union { uint8 b[4]; uint32 l; } value;
730     if (fread(value.b, sizeof(value), 1, proc_file) == 1)
731     BusClockSpeed = value.l;
732     fclose(proc_file);
733     }
734 gbeauche 1.47
735     // Get actual timebase frequency
736     TimebaseSpeed = BusClockSpeed / 4;
737     DIR *cpus_dir;
738     if ((cpus_dir = opendir("/proc/device-tree/cpus")) != NULL) {
739     struct dirent *cpu_entry;
740     while ((cpu_entry = readdir(cpus_dir)) != NULL) {
741     if (strstr(cpu_entry->d_name, "PowerPC,") == cpu_entry->d_name) {
742     char timebase_freq_node[256];
743     sprintf(timebase_freq_node, "/proc/device-tree/cpus/%s/timebase-frequency", cpu_entry->d_name);
744     proc_file = fopen(timebase_freq_node, "r");
745     if (proc_file) {
746     union { uint8 b[4]; uint32 l; } value;
747     if (fread(value.b, sizeof(value), 1, proc_file) == 1)
748     TimebaseSpeed = value.l;
749     fclose(proc_file);
750     }
751     }
752     }
753     closedir(cpus_dir);
754     }
755 cebix 1.1 #endif
756 gbeauche 1.49 // Remap any newer G4/G5 processor to plain G4 for compatibility
757     switch (PVR >> 16) {
758     case 0x8000: // 7450
759     case 0x8001: // 7455
760     case 0x8002: // 7457
761     case 0x0039: // 970
762     PVR = 0x000c0000; // 7400
763     break;
764     }
765 cebix 1.1 D(bug("PVR: %08x (assumed)\n", PVR));
766    
767     // Init system routines
768     SysInit();
769    
770     // Show preferences editor
771     if (!PrefsFindBool("nogui"))
772     if (!PrefsEditor())
773     goto quit;
774    
775     #if !EMULATED_PPC
776     // Check some things
777     paranoia_check();
778     #endif
779    
780     // Open /dev/zero
781     zero_fd = open("/dev/zero", O_RDWR);
782     if (zero_fd < 0) {
783     sprintf(str, GetString(STR_NO_DEV_ZERO_ERR), strerror(errno));
784     ErrorAlert(str);
785     goto quit;
786     }
787    
788 gbeauche 1.26 #ifndef PAGEZERO_HACK
789 cebix 1.1 // Create Low Memory area (0x0000..0x3000)
790 gbeauche 1.53 if (vm_mac_acquire(0, 0x3000) < 0) {
791 cebix 1.1 sprintf(str, GetString(STR_LOW_MEM_MMAP_ERR), strerror(errno));
792     ErrorAlert(str);
793     goto quit;
794     }
795     lm_area_mapped = true;
796 gbeauche 1.26 #endif
797 cebix 1.1
798     // Create areas for Kernel Data
799 gbeauche 1.53 if (!kernel_data_init())
800 cebix 1.1 goto quit;
801 gbeauche 1.53 kernel_data = (KernelData *)Mac2HostAddr(KERNEL_DATA_BASE);
802 cebix 1.1 emulator_data = &kernel_data->ed;
803 gbeauche 1.15 KernelDataAddr = KERNEL_DATA_BASE;
804 gbeauche 1.52 D(bug("Kernel Data at %p (%08x)\n", kernel_data, KERNEL_DATA_BASE));
805     D(bug("Emulator Data at %p (%08x)\n", emulator_data, KERNEL_DATA_BASE + offsetof(KernelData, ed)));
806 cebix 1.1
807 gbeauche 1.36 // Create area for DR Cache
808 gbeauche 1.53 if (vm_mac_acquire(DR_EMULATOR_BASE, DR_EMULATOR_SIZE) < 0) {
809 gbeauche 1.36 sprintf(str, GetString(STR_DR_EMULATOR_MMAP_ERR), strerror(errno));
810     ErrorAlert(str);
811     goto quit;
812     }
813     dr_emulator_area_mapped = true;
814 gbeauche 1.53 if (vm_mac_acquire(DR_CACHE_BASE, DR_CACHE_SIZE) < 0) {
815 gbeauche 1.36 sprintf(str, GetString(STR_DR_CACHE_MMAP_ERR), strerror(errno));
816     ErrorAlert(str);
817     goto quit;
818     }
819     dr_cache_area_mapped = true;
820 gbeauche 1.38 #if !EMULATED_PPC
821     if (vm_protect((char *)DR_CACHE_BASE, DR_CACHE_SIZE, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE) < 0) {
822     sprintf(str, GetString(STR_DR_CACHE_MMAP_ERR), strerror(errno));
823     ErrorAlert(str);
824     goto quit;
825     }
826     #endif
827 gbeauche 1.36 DRCacheAddr = DR_CACHE_BASE;
828     D(bug("DR Cache at %p\n", DRCacheAddr));
829    
830 gbeauche 1.8 // Create area for SheepShaver data
831 gbeauche 1.15 if (!SheepMem::Init()) {
832 gbeauche 1.8 sprintf(str, GetString(STR_SHEEP_MEM_MMAP_ERR), strerror(errno));
833     ErrorAlert(str);
834     goto quit;
835     }
836    
837 cebix 1.1 // Create area for Mac ROM
838 gbeauche 1.53 if (vm_mac_acquire(ROM_BASE, ROM_AREA_SIZE) < 0) {
839 cebix 1.1 sprintf(str, GetString(STR_ROM_MMAP_ERR), strerror(errno));
840     ErrorAlert(str);
841     goto quit;
842     }
843 gbeauche 1.53 ROMBaseHost = Mac2HostAddr(ROM_BASE);
844 gbeauche 1.27 #if !EMULATED_PPC
845 gbeauche 1.52 if (vm_protect(ROMBaseHost, ROM_AREA_SIZE, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE) < 0) {
846 gbeauche 1.4 sprintf(str, GetString(STR_ROM_MMAP_ERR), strerror(errno));
847     ErrorAlert(str);
848     goto quit;
849     }
850     #endif
851 cebix 1.1 rom_area_mapped = true;
852 gbeauche 1.52 D(bug("ROM area at %p (%08x)\n", ROMBaseHost, ROM_BASE));
853 cebix 1.1
854     // Create area for Mac RAM
855     RAMSize = PrefsFindInt32("ramsize");
856     if (RAMSize < 8*1024*1024) {
857     WarningAlert(GetString(STR_SMALL_RAM_WARN));
858     RAMSize = 8*1024*1024;
859     }
860    
861 gbeauche 1.53 if (vm_mac_acquire(RAM_BASE, RAMSize) < 0) {
862 cebix 1.1 sprintf(str, GetString(STR_RAM_MMAP_ERR), strerror(errno));
863     ErrorAlert(str);
864     goto quit;
865     }
866 gbeauche 1.53 RAMBaseHost = Mac2HostAddr(RAM_BASE);
867 gbeauche 1.4 #if !EMULATED_PPC
868 gbeauche 1.52 if (vm_protect(RAMBaseHost, RAMSize, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE) < 0) {
869 gbeauche 1.4 sprintf(str, GetString(STR_RAM_MMAP_ERR), strerror(errno));
870     ErrorAlert(str);
871     goto quit;
872     }
873     #endif
874 gbeauche 1.8 RAMBase = RAM_BASE;
875 cebix 1.1 ram_area_mapped = true;
876 gbeauche 1.52 D(bug("RAM area at %p (%08x)\n", RAMBaseHost, RAMBase));
877 cebix 1.1
878     if (RAMBase > ROM_BASE) {
879     ErrorAlert(GetString(STR_RAM_HIGHER_THAN_ROM_ERR));
880     goto quit;
881     }
882    
883     // Load Mac ROM
884     rom_path = PrefsFindString("rom");
885     rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME, O_RDONLY);
886     if (rom_fd < 0) {
887     rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME2, O_RDONLY);
888     if (rom_fd < 0) {
889     ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
890     goto quit;
891     }
892     }
893     printf(GetString(STR_READING_ROM_FILE));
894     rom_size = lseek(rom_fd, 0, SEEK_END);
895     lseek(rom_fd, 0, SEEK_SET);
896     rom_tmp = new uint8[ROM_SIZE];
897     actual = read(rom_fd, (void *)rom_tmp, ROM_SIZE);
898     close(rom_fd);
899 gbeauche 1.3
900     // Decode Mac ROM
901     if (!DecodeROM(rom_tmp, actual)) {
902     if (rom_size != 4*1024*1024) {
903 cebix 1.1 ErrorAlert(GetString(STR_ROM_SIZE_ERR));
904     goto quit;
905     } else {
906     ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
907     goto quit;
908     }
909     }
910 gbeauche 1.3 delete[] rom_tmp;
911 cebix 1.1
912     // Load NVRAM
913     XPRAMInit();
914    
915 gbeauche 1.32 // Load XPRAM default values if signature not found
916     if (XPRAM[0x130c] != 0x4e || XPRAM[0x130d] != 0x75
917     || XPRAM[0x130e] != 0x4d || XPRAM[0x130f] != 0x63) {
918     D(bug("Loading XPRAM default values\n"));
919     memset(XPRAM + 0x1300, 0, 0x100);
920     XPRAM[0x130c] = 0x4e; // "NuMc" signature
921     XPRAM[0x130d] = 0x75;
922     XPRAM[0x130e] = 0x4d;
923     XPRAM[0x130f] = 0x63;
924     XPRAM[0x1301] = 0x80; // InternalWaitFlags = DynWait (don't wait for SCSI devices upon bootup)
925     XPRAM[0x1310] = 0xa8; // Standard PRAM values
926     XPRAM[0x1311] = 0x00;
927     XPRAM[0x1312] = 0x00;
928     XPRAM[0x1313] = 0x22;
929     XPRAM[0x1314] = 0xcc;
930     XPRAM[0x1315] = 0x0a;
931     XPRAM[0x1316] = 0xcc;
932     XPRAM[0x1317] = 0x0a;
933     XPRAM[0x131c] = 0x00;
934     XPRAM[0x131d] = 0x02;
935     XPRAM[0x131e] = 0x63;
936     XPRAM[0x131f] = 0x00;
937     XPRAM[0x1308] = 0x13;
938     XPRAM[0x1309] = 0x88;
939     XPRAM[0x130a] = 0x00;
940     XPRAM[0x130b] = 0xcc;
941     XPRAM[0x1376] = 0x00; // OSDefault = MacOS
942     XPRAM[0x1377] = 0x01;
943     }
944    
945 cebix 1.1 // Set boot volume
946 cebix 1.10 i16 = PrefsFindInt32("bootdrive");
947 cebix 1.1 XPRAM[0x1378] = i16 >> 8;
948     XPRAM[0x1379] = i16 & 0xff;
949 cebix 1.10 i16 = PrefsFindInt32("bootdriver");
950 cebix 1.1 XPRAM[0x137a] = i16 >> 8;
951     XPRAM[0x137b] = i16 & 0xff;
952    
953     // Create BootGlobs at top of Mac memory
954 gbeauche 1.52 memset(RAMBaseHost + RAMSize - 4096, 0, 4096);
955 cebix 1.1 BootGlobsAddr = RAMBase + RAMSize - 0x1c;
956 gbeauche 1.52 WriteMacInt32(BootGlobsAddr - 5 * 4, RAMBase + RAMSize); // MemTop
957     WriteMacInt32(BootGlobsAddr + 0 * 4, RAMBase); // First RAM bank
958     WriteMacInt32(BootGlobsAddr + 1 * 4, RAMSize);
959     WriteMacInt32(BootGlobsAddr + 2 * 4, (uint32)-1); // End of bank table
960 cebix 1.1
961 gbeauche 1.15 // Init thunks
962     if (!ThunksInit())
963     goto quit;
964    
965 cebix 1.1 // Init drivers
966     SonyInit();
967     DiskInit();
968     CDROMInit();
969     SCSIInit();
970    
971     // Init external file system
972     ExtFSInit();
973    
974 gbeauche 1.22 // Init ADB
975     ADBInit();
976    
977 cebix 1.1 // Init audio
978     AudioInit();
979    
980     // Init network
981     EtherInit();
982    
983     // Init serial ports
984     SerialInit();
985    
986     // Init Time Manager
987     TimerInit();
988    
989     // Init clipboard
990     ClipInit();
991    
992     // Init video
993     if (!VideoInit())
994     goto quit;
995    
996     // Install ROM patches
997     if (!PatchROM()) {
998     ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR));
999     goto quit;
1000     }
1001    
1002     // Clear caches (as we loaded and patched code) and write protect ROM
1003     #if !EMULATED_PPC
1004 gbeauche 1.52 MakeExecutable(0, ROM_BASE, ROM_AREA_SIZE);
1005 cebix 1.1 #endif
1006 gbeauche 1.52 vm_protect(ROMBaseHost, ROM_AREA_SIZE, VM_PAGE_READ | VM_PAGE_EXECUTE);
1007 cebix 1.1
1008     // Initialize Kernel Data
1009     memset(kernel_data, 0, sizeof(KernelData));
1010     if (ROMType == ROMTYPE_NEWWORLD) {
1011 gbeauche 1.52 uint32 of_dev_tree = SheepMem::Reserve(4 * sizeof(uint32));
1012     Mac_memset(of_dev_tree, 0, 4 * sizeof(uint32));
1013     uint32 vector_lookup_tbl = SheepMem::Reserve(128);
1014     uint32 vector_mask_tbl = SheepMem::Reserve(64);
1015 cebix 1.1 memset((uint8 *)kernel_data + 0xb80, 0x3d, 0x80);
1016 gbeauche 1.52 Mac_memset(vector_lookup_tbl, 0, 128);
1017     Mac_memset(vector_mask_tbl, 0, 64);
1018 cebix 1.1 kernel_data->v[0xb80 >> 2] = htonl(ROM_BASE);
1019 gbeauche 1.15 kernel_data->v[0xb84 >> 2] = htonl(of_dev_tree); // OF device tree base
1020     kernel_data->v[0xb90 >> 2] = htonl(vector_lookup_tbl);
1021     kernel_data->v[0xb94 >> 2] = htonl(vector_mask_tbl);
1022 cebix 1.1 kernel_data->v[0xb98 >> 2] = htonl(ROM_BASE); // OpenPIC base
1023     kernel_data->v[0xbb0 >> 2] = htonl(0); // ADB base
1024     kernel_data->v[0xc20 >> 2] = htonl(RAMSize);
1025     kernel_data->v[0xc24 >> 2] = htonl(RAMSize);
1026     kernel_data->v[0xc30 >> 2] = htonl(RAMSize);
1027     kernel_data->v[0xc34 >> 2] = htonl(RAMSize);
1028     kernel_data->v[0xc38 >> 2] = htonl(0x00010020);
1029     kernel_data->v[0xc3c >> 2] = htonl(0x00200001);
1030     kernel_data->v[0xc40 >> 2] = htonl(0x00010000);
1031     kernel_data->v[0xc50 >> 2] = htonl(RAMBase);
1032     kernel_data->v[0xc54 >> 2] = htonl(RAMSize);
1033     kernel_data->v[0xf60 >> 2] = htonl(PVR);
1034 gbeauche 1.34 kernel_data->v[0xf64 >> 2] = htonl(CPUClockSpeed); // clock-frequency
1035     kernel_data->v[0xf68 >> 2] = htonl(BusClockSpeed); // bus-frequency
1036 gbeauche 1.47 kernel_data->v[0xf6c >> 2] = htonl(TimebaseSpeed); // timebase-frequency
1037 cebix 1.1 } else {
1038     kernel_data->v[0xc80 >> 2] = htonl(RAMSize);
1039     kernel_data->v[0xc84 >> 2] = htonl(RAMSize);
1040     kernel_data->v[0xc90 >> 2] = htonl(RAMSize);
1041     kernel_data->v[0xc94 >> 2] = htonl(RAMSize);
1042     kernel_data->v[0xc98 >> 2] = htonl(0x00010020);
1043     kernel_data->v[0xc9c >> 2] = htonl(0x00200001);
1044     kernel_data->v[0xca0 >> 2] = htonl(0x00010000);
1045     kernel_data->v[0xcb0 >> 2] = htonl(RAMBase);
1046     kernel_data->v[0xcb4 >> 2] = htonl(RAMSize);
1047     kernel_data->v[0xf80 >> 2] = htonl(PVR);
1048 gbeauche 1.34 kernel_data->v[0xf84 >> 2] = htonl(CPUClockSpeed); // clock-frequency
1049     kernel_data->v[0xf88 >> 2] = htonl(BusClockSpeed); // bus-frequency
1050 gbeauche 1.47 kernel_data->v[0xf8c >> 2] = htonl(TimebaseSpeed); // timebase-frequency
1051 cebix 1.1 }
1052    
1053     // Initialize extra low memory
1054     D(bug("Initializing Low Memory...\n"));
1055 gbeauche 1.52 Mac_memset(0, 0, 0x3000);
1056 cebix 1.1 WriteMacInt32(XLM_SIGNATURE, FOURCC('B','a','a','h')); // Signature to detect SheepShaver
1057 gbeauche 1.15 WriteMacInt32(XLM_KERNEL_DATA, KernelDataAddr); // For trap replacement routines
1058 cebix 1.1 WriteMacInt32(XLM_PVR, PVR); // Theoretical PVR
1059     WriteMacInt32(XLM_BUS_CLOCK, BusClockSpeed); // For DriverServicesLib patch
1060     WriteMacInt16(XLM_EXEC_RETURN_OPCODE, M68K_EXEC_RETURN); // For Execute68k() (RTS from the executed 68k code will jump here and end 68k mode)
1061 gbeauche 1.18 WriteMacInt32(XLM_ZERO_PAGE, SheepMem::ZeroPage()); // Pointer to read-only page with all bits set to 0
1062 gbeauche 1.17 #if !EMULATED_PPC
1063     WriteMacInt32(XLM_TOC, (uint32)TOC); // TOC pointer of emulator
1064     #endif
1065     WriteMacInt32(XLM_ETHER_INIT, NativeFunction(NATIVE_ETHER_INIT)); // DLPI ethernet driver functions
1066 gbeauche 1.15 WriteMacInt32(XLM_ETHER_TERM, NativeFunction(NATIVE_ETHER_TERM));
1067     WriteMacInt32(XLM_ETHER_OPEN, NativeFunction(NATIVE_ETHER_OPEN));
1068     WriteMacInt32(XLM_ETHER_CLOSE, NativeFunction(NATIVE_ETHER_CLOSE));
1069     WriteMacInt32(XLM_ETHER_WPUT, NativeFunction(NATIVE_ETHER_WPUT));
1070     WriteMacInt32(XLM_ETHER_RSRV, NativeFunction(NATIVE_ETHER_RSRV));
1071     WriteMacInt32(XLM_VIDEO_DOIO, NativeFunction(NATIVE_VIDEO_DO_DRIVER_IO));
1072 cebix 1.1 D(bug("Low Memory initialized\n"));
1073    
1074     // Start 60Hz thread
1075 gbeauche 1.40 tick_thread_cancel = false;
1076 cebix 1.1 tick_thread_active = (pthread_create(&tick_thread, NULL, tick_func, NULL) == 0);
1077     D(bug("Tick thread installed (%ld)\n", tick_thread));
1078    
1079     // Start NVRAM watchdog thread
1080     memcpy(last_xpram, XPRAM, XPRAM_SIZE);
1081 gbeauche 1.40 nvram_thread_cancel = false;
1082 cebix 1.1 nvram_thread_active = (pthread_create(&nvram_thread, NULL, nvram_func, NULL) == 0);
1083     D(bug("NVRAM thread installed (%ld)\n", nvram_thread));
1084    
1085     #if !EMULATED_PPC
1086     // Install SIGILL handler
1087     sigemptyset(&sigill_action.sa_mask); // Block interrupts during ILL handling
1088     sigaddset(&sigill_action.sa_mask, SIGUSR2);
1089 gbeauche 1.26 sigill_action.sa_sigaction = sigill_handler;
1090     sigill_action.sa_flags = SA_ONSTACK | SA_SIGINFO;
1091     #ifdef HAVE_SIGNAL_SA_RESTORER
1092 cebix 1.1 sigill_action.sa_restorer = NULL;
1093 gbeauche 1.26 #endif
1094 cebix 1.1 if (sigaction(SIGILL, &sigill_action, NULL) < 0) {
1095     sprintf(str, GetString(STR_SIGILL_INSTALL_ERR), strerror(errno));
1096     ErrorAlert(str);
1097     goto quit;
1098     }
1099 gbeauche 1.6 #endif
1100 cebix 1.1
1101 gbeauche 1.26 #if !EMULATED_PPC
1102 cebix 1.1 // Install interrupt signal handler
1103     sigemptyset(&sigusr2_action.sa_mask);
1104 gbeauche 1.26 sigusr2_action.sa_sigaction = sigusr2_handler;
1105     sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
1106     #ifdef HAVE_SIGNAL_SA_RESTORER
1107     sigusr2_action.sa_restorer = NULL;
1108 gbeauche 1.8 #endif
1109 cebix 1.1 if (sigaction(SIGUSR2, &sigusr2_action, NULL) < 0) {
1110     sprintf(str, GetString(STR_SIGUSR2_INSTALL_ERR), strerror(errno));
1111     ErrorAlert(str);
1112     goto quit;
1113     }
1114 gbeauche 1.26 #endif
1115 cebix 1.1
1116     // Get my thread ID and execute MacOS thread function
1117     emul_thread = pthread_self();
1118     D(bug("MacOS thread is %ld\n", emul_thread));
1119     emul_func(NULL);
1120    
1121     quit:
1122     Quit();
1123     return 0;
1124     }
1125    
1126    
1127     /*
1128     * Cleanup and quit
1129     */
1130    
1131     static void Quit(void)
1132     {
1133 gbeauche 1.13 #if EMULATED_PPC
1134     // Exit PowerPC emulation
1135     exit_emul_ppc();
1136     #endif
1137    
1138 cebix 1.1 // Stop 60Hz thread
1139     if (tick_thread_active) {
1140 gbeauche 1.40 tick_thread_cancel = true;
1141 cebix 1.1 pthread_cancel(tick_thread);
1142     pthread_join(tick_thread, NULL);
1143     }
1144    
1145     // Stop NVRAM watchdog thread
1146     if (nvram_thread_active) {
1147 gbeauche 1.40 nvram_thread_cancel = true;
1148 cebix 1.1 pthread_cancel(nvram_thread);
1149     pthread_join(nvram_thread, NULL);
1150     }
1151    
1152     #if !EMULATED_PPC
1153 gbeauche 1.23 // Uninstall SIGSEGV and SIGBUS handlers
1154 cebix 1.1 sigemptyset(&sigsegv_action.sa_mask);
1155     sigsegv_action.sa_handler = SIG_DFL;
1156     sigsegv_action.sa_flags = 0;
1157     sigaction(SIGSEGV, &sigsegv_action, NULL);
1158 gbeauche 1.23 sigaction(SIGBUS, &sigsegv_action, NULL);
1159 cebix 1.1
1160     // Uninstall SIGILL handler
1161     sigemptyset(&sigill_action.sa_mask);
1162     sigill_action.sa_handler = SIG_DFL;
1163     sigill_action.sa_flags = 0;
1164     sigaction(SIGILL, &sigill_action, NULL);
1165 gbeauche 1.33
1166     // Delete stacks for signal handlers
1167     for (int i = 0; i < SIG_STACK_COUNT; i++) {
1168     void *sig_stack = sig_stacks[i].ss_sp;
1169     if (sig_stack)
1170     free(sig_stack);
1171     }
1172 cebix 1.1 #endif
1173    
1174     // Save NVRAM
1175     XPRAMExit();
1176    
1177     // Exit clipboard
1178     ClipExit();
1179    
1180     // Exit Time Manager
1181     TimerExit();
1182    
1183     // Exit serial
1184     SerialExit();
1185    
1186     // Exit network
1187     EtherExit();
1188    
1189     // Exit audio
1190     AudioExit();
1191 gbeauche 1.22
1192     // Exit ADB
1193     ADBExit();
1194 cebix 1.1
1195     // Exit video
1196     VideoExit();
1197    
1198     // Exit external file system
1199     ExtFSExit();
1200    
1201     // Exit drivers
1202     SCSIExit();
1203     CDROMExit();
1204     DiskExit();
1205     SonyExit();
1206    
1207 gbeauche 1.24 // Delete thunks
1208     ThunksExit();
1209    
1210 gbeauche 1.15 // Delete SheepShaver globals
1211     SheepMem::Exit();
1212    
1213 cebix 1.1 // Delete RAM area
1214     if (ram_area_mapped)
1215 gbeauche 1.53 vm_mac_release(RAM_BASE, RAMSize);
1216 cebix 1.1
1217     // Delete ROM area
1218     if (rom_area_mapped)
1219 gbeauche 1.53 vm_mac_release(ROM_BASE, ROM_AREA_SIZE);
1220 cebix 1.1
1221 gbeauche 1.36 // Delete DR cache areas
1222     if (dr_emulator_area_mapped)
1223 gbeauche 1.53 vm_mac_release(DR_EMULATOR_BASE, DR_EMULATOR_SIZE);
1224 gbeauche 1.36 if (dr_cache_area_mapped)
1225 gbeauche 1.53 vm_mac_release(DR_CACHE_BASE, DR_CACHE_SIZE);
1226 gbeauche 1.36
1227 cebix 1.1 // Delete Kernel Data area
1228 gbeauche 1.53 kernel_data_exit();
1229 cebix 1.1
1230     // Delete Low Memory area
1231     if (lm_area_mapped)
1232 gbeauche 1.53 vm_mac_release(0, 0x3000);
1233 cebix 1.1
1234     // Close /dev/zero
1235     if (zero_fd > 0)
1236     close(zero_fd);
1237    
1238     // Exit system routines
1239     SysExit();
1240    
1241     // Exit preferences
1242     PrefsExit();
1243    
1244     #ifdef ENABLE_MON
1245     // Exit mon
1246     mon_exit();
1247     #endif
1248    
1249     // Close X11 server connection
1250 gbeauche 1.42 #ifndef USE_SDL_VIDEO
1251 cebix 1.1 if (x_display)
1252     XCloseDisplay(x_display);
1253 gbeauche 1.42 #endif
1254 cebix 1.1
1255     exit(0);
1256     }
1257    
1258    
1259     /*
1260 gbeauche 1.53 * Initialize Kernel Data segments
1261     */
1262    
1263     #if defined(__CYGWIN__)
1264     #define WIN32_LEAN_AND_MEAN
1265     #include <windows.h>
1266    
1267     static HANDLE kernel_handle; // Shared memory handle for Kernel Data
1268     static DWORD allocation_granule; // Minimum size of allocateable are (64K)
1269     static DWORD kernel_area_size; // Size of Kernel Data area
1270     #endif
1271    
1272     static bool kernel_data_init(void)
1273     {
1274     #ifdef _WIN32
1275     SYSTEM_INFO si;
1276     GetSystemInfo(&si);
1277     allocation_granule = si.dwAllocationGranularity;
1278     kernel_area_size = (KERNEL_AREA_SIZE + allocation_granule - 1) & -allocation_granule;
1279    
1280     char rcs[10];
1281     char str[256];
1282     LPVOID kernel_addr;
1283     kernel_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, kernel_area_size, NULL);
1284     if (kernel_handle == NULL) {
1285     sprintf(rcs, "%d", GetLastError());
1286     sprintf(str, GetString(STR_KD_SHMGET_ERR), rcs);
1287     ErrorAlert(str);
1288     return false;
1289     }
1290     kernel_addr = (LPVOID)Mac2HostAddr(KERNEL_DATA_BASE & -allocation_granule);
1291     if (MapViewOfFileEx(kernel_handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kernel_area_size, kernel_addr) != kernel_addr) {
1292     sprintf(rcs, "%d", GetLastError());
1293     sprintf(str, GetString(STR_KD_SHMAT_ERR), rcs);
1294     ErrorAlert(str);
1295     return false;
1296     }
1297     kernel_addr = (LPVOID)Mac2HostAddr(KERNEL_DATA2_BASE & -allocation_granule);
1298     if (MapViewOfFileEx(kernel_handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kernel_area_size, kernel_addr) != kernel_addr) {
1299     sprintf(rcs, "%d", GetLastError());
1300     sprintf(str, GetString(STR_KD2_SHMAT_ERR), rcs);
1301     ErrorAlert(str);
1302     return false;
1303     }
1304     #else
1305     kernel_area = shmget(IPC_PRIVATE, KERNEL_AREA_SIZE, 0600);
1306     if (kernel_area == -1) {
1307     sprintf(str, GetString(STR_KD_SHMGET_ERR), strerror(errno));
1308     ErrorAlert(str);
1309     return false;
1310     }
1311     if (shmat(kernel_area, Mac2HostAddr(KERNEL_DATA_BASE), 0) < 0) {
1312     sprintf(str, GetString(STR_KD_SHMAT_ERR), strerror(errno));
1313     ErrorAlert(str);
1314     return false;
1315     }
1316     if (shmat(kernel_area, Mac2HostAddr(KERNEL_DATA2_BASE), 0) < 0) {
1317     sprintf(str, GetString(STR_KD2_SHMAT_ERR), strerror(errno));
1318     ErrorAlert(str);
1319     return false;
1320     }
1321     #endif
1322     return true;
1323     }
1324    
1325    
1326     /*
1327     * Deallocate Kernel Data segments
1328     */
1329    
1330     static void kernel_data_exit(void)
1331     {
1332     #ifdef _WIN32
1333     if (kernel_handle) {
1334     UnmapViewOfFile(Mac2HostAddr(KERNEL_DATA_BASE & -allocation_granule));
1335     UnmapViewOfFile(Mac2HostAddr(KERNEL_DATA2_BASE & -allocation_granule));
1336     CloseHandle(kernel_handle);
1337     }
1338     #else
1339     if (kernel_area >= 0) {
1340     shmdt(Mac2HostAddr(KERNEL_DATA_BASE));
1341     shmdt(Mac2HostAddr(KERNEL_DATA2_BASE));
1342     shmctl(kernel_area, IPC_RMID, NULL);
1343     }
1344     #endif
1345     }
1346    
1347    
1348     /*
1349 cebix 1.1 * Jump into Mac ROM, start 680x0 emulator
1350     */
1351    
1352     #if EMULATED_PPC
1353     void jump_to_rom(uint32 entry)
1354     {
1355     init_emul_ppc();
1356     emul_ppc(entry);
1357     }
1358     #endif
1359    
1360    
1361     /*
1362     * Emulator thread function
1363     */
1364    
1365     static void *emul_func(void *arg)
1366     {
1367     // We're now ready to receive signals
1368     ready_for_signals = true;
1369    
1370     // Decrease priority, so more time-critical things like audio will work better
1371     nice(1);
1372    
1373     // Jump to ROM boot routine
1374     D(bug("Jumping to ROM\n"));
1375     #if EMULATED_PPC
1376     jump_to_rom(ROM_BASE + 0x310000);
1377     #else
1378     jump_to_rom(ROM_BASE + 0x310000, (uint32)emulator_data);
1379     #endif
1380     D(bug("Returned from ROM\n"));
1381    
1382     // We're no longer ready to receive signals
1383     ready_for_signals = false;
1384     return NULL;
1385     }
1386    
1387    
1388     #if !EMULATED_PPC
1389     /*
1390     * Execute 68k subroutine (must be ended with RTS)
1391     * This must only be called by the emul_thread when in EMUL_OP mode
1392     * r->a[7] is unused, the routine runs on the caller's stack
1393     */
1394    
1395     void Execute68k(uint32 pc, M68kRegisters *r)
1396     {
1397     #if SAFE_EXEC_68K
1398     if (ReadMacInt32(XLM_RUN_MODE) != MODE_EMUL_OP)
1399     printf("FATAL: Execute68k() not called from EMUL_OP mode\n");
1400     if (!pthread_equal(pthread_self(), emul_thread))
1401     printf("FATAL: Execute68k() not called from emul_thread\n");
1402     #endif
1403     execute_68k(pc, r);
1404     }
1405    
1406    
1407     /*
1408     * Execute 68k A-Trap from EMUL_OP routine
1409     * r->a[7] is unused, the routine runs on the caller's stack
1410     */
1411    
1412     void Execute68kTrap(uint16 trap, M68kRegisters *r)
1413     {
1414     uint16 proc[2] = {trap, M68K_RTS};
1415     Execute68k((uint32)proc, r);
1416     }
1417 gbeauche 1.7 #endif
1418 cebix 1.1
1419    
1420     /*
1421     * Quit emulator (cause return from jump_to_rom)
1422     */
1423    
1424     void QuitEmulator(void)
1425     {
1426     #if EMULATED_PPC
1427     Quit();
1428     #else
1429     quit_emulator();
1430     #endif
1431     }
1432    
1433    
1434     /*
1435     * Pause/resume emulator
1436     */
1437    
1438     void PauseEmulator(void)
1439     {
1440     pthread_kill(emul_thread, SIGSTOP);
1441     }
1442    
1443     void ResumeEmulator(void)
1444     {
1445     pthread_kill(emul_thread, SIGCONT);
1446     }
1447    
1448    
1449     /*
1450     * Dump 68k registers
1451     */
1452    
1453     void Dump68kRegs(M68kRegisters *r)
1454     {
1455     // Display 68k registers
1456     for (int i=0; i<8; i++) {
1457     printf("d%d: %08x", i, r->d[i]);
1458     if (i == 3 || i == 7)
1459     printf("\n");
1460     else
1461     printf(", ");
1462     }
1463     for (int i=0; i<8; i++) {
1464     printf("a%d: %08x", i, r->a[i]);
1465     if (i == 3 || i == 7)
1466     printf("\n");
1467     else
1468     printf(", ");
1469     }
1470     }
1471    
1472    
1473     /*
1474     * Make code executable
1475     */
1476    
1477 gbeauche 1.52 void MakeExecutable(int dummy, uint32 start, uint32 length)
1478 cebix 1.1 {
1479 gbeauche 1.52 if ((start >= ROM_BASE) && (start < (ROM_BASE + ROM_SIZE)))
1480 cebix 1.1 return;
1481 gbeauche 1.9 #if EMULATED_PPC
1482 gbeauche 1.52 FlushCodeCache(start, start + length);
1483 gbeauche 1.9 #else
1484 gbeauche 1.52 flush_icache_range(start, (void *)(start + length));
1485 cebix 1.1 #endif
1486     }
1487    
1488    
1489     /*
1490     * Patch things after system startup (gets called by disk driver accRun routine)
1491     */
1492    
1493     void PatchAfterStartup(void)
1494     {
1495 gbeauche 1.6 ExecuteNative(NATIVE_VIDEO_INSTALL_ACCEL);
1496 cebix 1.1 InstallExtFS();
1497     }
1498    
1499    
1500     /*
1501     * NVRAM watchdog thread (saves NVRAM every minute)
1502     */
1503    
1504 gbeauche 1.40 static void nvram_watchdog(void)
1505     {
1506     if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
1507     memcpy(last_xpram, XPRAM, XPRAM_SIZE);
1508     SaveXPRAM();
1509     }
1510     }
1511    
1512 cebix 1.1 static void *nvram_func(void *arg)
1513     {
1514 gbeauche 1.40 while (!nvram_thread_cancel) {
1515     for (int i=0; i<60 && !nvram_thread_cancel; i++)
1516     Delay_usec(999999); // Only wait 1 second so we quit promptly when nvram_thread_cancel becomes true
1517     nvram_watchdog();
1518 cebix 1.1 }
1519     return NULL;
1520     }
1521    
1522    
1523     /*
1524     * 60Hz thread (really 60.15Hz)
1525     */
1526    
1527     static void *tick_func(void *arg)
1528     {
1529     int tick_counter = 0;
1530 gbeauche 1.40 uint64 start = GetTicks_usec();
1531     int64 ticks = 0;
1532     uint64 next = GetTicks_usec();
1533 cebix 1.1
1534 gbeauche 1.40 while (!tick_thread_cancel) {
1535 cebix 1.1
1536     // Wait
1537 gbeauche 1.40 next += 16625;
1538     int64 delay = next - GetTicks_usec();
1539     if (delay > 0)
1540     Delay_usec(delay);
1541     else if (delay < -16625)
1542     next = GetTicks_usec();
1543     ticks++;
1544 cebix 1.1
1545     #if !EMULATED_PPC
1546     // Did we crash?
1547     if (emul_thread_fatal) {
1548    
1549     // Yes, dump registers
1550 gbeauche 1.26 sigregs *r = &sigsegv_regs;
1551 cebix 1.1 char str[256];
1552 gbeauche 1.23 if (crash_reason == NULL)
1553     crash_reason = "SIGSEGV";
1554     sprintf(str, "%s\n"
1555 cebix 1.1 " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
1556     " xer %08lx cr %08lx \n"
1557     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
1558     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
1559     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
1560     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
1561     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
1562     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
1563     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
1564     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
1565 gbeauche 1.23 crash_reason,
1566 cebix 1.1 r->nip, r->link, r->ctr, r->msr,
1567     r->xer, r->ccr,
1568     r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3],
1569     r->gpr[4], r->gpr[5], r->gpr[6], r->gpr[7],
1570     r->gpr[8], r->gpr[9], r->gpr[10], r->gpr[11],
1571     r->gpr[12], r->gpr[13], r->gpr[14], r->gpr[15],
1572     r->gpr[16], r->gpr[17], r->gpr[18], r->gpr[19],
1573     r->gpr[20], r->gpr[21], r->gpr[22], r->gpr[23],
1574     r->gpr[24], r->gpr[25], r->gpr[26], r->gpr[27],
1575     r->gpr[28], r->gpr[29], r->gpr[30], r->gpr[31]);
1576     printf(str);
1577     VideoQuitFullScreen();
1578    
1579     #ifdef ENABLE_MON
1580     // Start up mon in real-mode
1581     printf("Welcome to the sheep factory.\n");
1582     char *arg[4] = {"mon", "-m", "-r", NULL};
1583     mon(3, arg);
1584     #endif
1585     return NULL;
1586     }
1587     #endif
1588    
1589     // Pseudo Mac 1Hz interrupt, update local time
1590     if (++tick_counter > 60) {
1591     tick_counter = 0;
1592     WriteMacInt32(0x20c, TimerDateTime());
1593     }
1594    
1595     // Trigger 60Hz interrupt
1596     if (ReadMacInt32(XLM_IRQ_NEST) == 0) {
1597     SetInterruptFlag(INTFLAG_VIA);
1598     TriggerInterrupt();
1599     }
1600     }
1601 gbeauche 1.40
1602     uint64 end = GetTicks_usec();
1603     D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
1604 cebix 1.1 return NULL;
1605     }
1606    
1607    
1608     /*
1609 cebix 1.2 * Pthread configuration
1610     */
1611    
1612     void Set_pthread_attr(pthread_attr_t *attr, int priority)
1613     {
1614 gbeauche 1.14 #ifdef HAVE_PTHREADS
1615     pthread_attr_init(attr);
1616     #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
1617     // Some of these only work for superuser
1618     if (geteuid() == 0) {
1619     pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
1620     pthread_attr_setschedpolicy(attr, SCHED_FIFO);
1621     struct sched_param fifo_param;
1622     fifo_param.sched_priority = ((sched_get_priority_min(SCHED_FIFO) +
1623     sched_get_priority_max(SCHED_FIFO)) / 2 +
1624     priority);
1625     pthread_attr_setschedparam(attr, &fifo_param);
1626     }
1627     if (pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM) != 0) {
1628     #ifdef PTHREAD_SCOPE_BOUND_NP
1629     // If system scope is not available (eg. we're not running
1630     // with CAP_SCHED_MGT capability on an SGI box), try bound
1631     // scope. It exposes pthread scheduling to the kernel,
1632     // without setting realtime priority.
1633     pthread_attr_setscope(attr, PTHREAD_SCOPE_BOUND_NP);
1634     #endif
1635     }
1636     #endif
1637     #endif
1638 cebix 1.2 }
1639    
1640    
1641     /*
1642 cebix 1.1 * Mutexes
1643     */
1644    
1645 gbeauche 1.7 #ifdef HAVE_PTHREADS
1646    
1647     struct B2_mutex {
1648     B2_mutex() {
1649     pthread_mutexattr_t attr;
1650     pthread_mutexattr_init(&attr);
1651     // Initialize the mutex for priority inheritance --
1652     // required for accurate timing.
1653 gbeauche 1.53 #if defined(HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL) && !defined(__CYGWIN__)
1654 gbeauche 1.7 pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
1655     #endif
1656     #if defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE) && defined(PTHREAD_MUTEX_NORMAL)
1657     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
1658     #endif
1659     #ifdef HAVE_PTHREAD_MUTEXATTR_SETPSHARED
1660     pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
1661     #endif
1662     pthread_mutex_init(&m, &attr);
1663     pthread_mutexattr_destroy(&attr);
1664     }
1665     ~B2_mutex() {
1666     pthread_mutex_trylock(&m); // Make sure it's locked before
1667     pthread_mutex_unlock(&m); // unlocking it.
1668     pthread_mutex_destroy(&m);
1669     }
1670     pthread_mutex_t m;
1671     };
1672    
1673     B2_mutex *B2_create_mutex(void)
1674     {
1675     return new B2_mutex;
1676     }
1677    
1678     void B2_lock_mutex(B2_mutex *mutex)
1679     {
1680     pthread_mutex_lock(&mutex->m);
1681     }
1682    
1683     void B2_unlock_mutex(B2_mutex *mutex)
1684     {
1685     pthread_mutex_unlock(&mutex->m);
1686     }
1687    
1688     void B2_delete_mutex(B2_mutex *mutex)
1689     {
1690     delete mutex;
1691     }
1692    
1693     #else
1694    
1695 cebix 1.1 struct B2_mutex {
1696     int dummy;
1697     };
1698    
1699     B2_mutex *B2_create_mutex(void)
1700     {
1701     return new B2_mutex;
1702     }
1703    
1704     void B2_lock_mutex(B2_mutex *mutex)
1705     {
1706     }
1707    
1708     void B2_unlock_mutex(B2_mutex *mutex)
1709     {
1710     }
1711    
1712     void B2_delete_mutex(B2_mutex *mutex)
1713     {
1714     delete mutex;
1715     }
1716    
1717 gbeauche 1.7 #endif
1718    
1719 cebix 1.1
1720     /*
1721     * Trigger signal USR2 from another thread
1722     */
1723    
1724 gbeauche 1.35 #if !EMULATED_PPC
1725 cebix 1.1 void TriggerInterrupt(void)
1726     {
1727     if (ready_for_signals)
1728     pthread_kill(emul_thread, SIGUSR2);
1729     }
1730 gbeauche 1.7 #endif
1731 cebix 1.1
1732    
1733     /*
1734     * Interrupt flags (must be handled atomically!)
1735     */
1736    
1737     volatile uint32 InterruptFlags = 0;
1738    
1739     void SetInterruptFlag(uint32 flag)
1740     {
1741     atomic_or((int *)&InterruptFlags, flag);
1742     }
1743    
1744     void ClearInterruptFlag(uint32 flag)
1745     {
1746     atomic_and((int *)&InterruptFlags, ~flag);
1747     }
1748    
1749    
1750     /*
1751     * Disable interrupts
1752     */
1753    
1754     void DisableInterrupt(void)
1755     {
1756 gbeauche 1.41 #if EMULATED_PPC
1757     WriteMacInt32(XLM_IRQ_NEST, int32(ReadMacInt32(XLM_IRQ_NEST)) + 1);
1758     #else
1759 gbeauche 1.7 atomic_add((int *)XLM_IRQ_NEST, 1);
1760 gbeauche 1.41 #endif
1761 cebix 1.1 }
1762    
1763    
1764     /*
1765     * Enable interrupts
1766     */
1767    
1768     void EnableInterrupt(void)
1769     {
1770 gbeauche 1.41 #if EMULATED_PPC
1771     WriteMacInt32(XLM_IRQ_NEST, int32(ReadMacInt32(XLM_IRQ_NEST)) - 1);
1772     #else
1773 gbeauche 1.7 atomic_add((int *)XLM_IRQ_NEST, -1);
1774 gbeauche 1.41 #endif
1775 cebix 1.1 }
1776    
1777    
1778     /*
1779     * USR2 handler
1780     */
1781    
1782 gbeauche 1.35 #if !EMULATED_PPC
1783 gbeauche 1.26 static void sigusr2_handler(int sig, siginfo_t *sip, void *scp)
1784 cebix 1.1 {
1785 gbeauche 1.26 machine_regs *r = MACHINE_REGISTERS(scp);
1786 cebix 1.1
1787 gbeauche 1.42 #ifdef USE_SDL_VIDEO
1788     // We must fill in the events queue in the same thread that did call SDL_SetVideoMode()
1789     SDL_PumpEvents();
1790     #endif
1791    
1792 cebix 1.1 // Do nothing if interrupts are disabled
1793     if (*(int32 *)XLM_IRQ_NEST > 0)
1794     return;
1795    
1796     // Disable MacOS stack sniffer
1797     WriteMacInt32(0x110, 0);
1798    
1799     // Interrupt action depends on current run mode
1800     switch (ReadMacInt32(XLM_RUN_MODE)) {
1801     case MODE_68K:
1802     // 68k emulator active, trigger 68k interrupt level 1
1803     WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1);
1804 gbeauche 1.26 r->cr() |= ntohl(kernel_data->v[0x674 >> 2]);
1805 cebix 1.1 break;
1806    
1807     #if INTERRUPTS_IN_NATIVE_MODE
1808     case MODE_NATIVE:
1809     // 68k emulator inactive, in nanokernel?
1810 gbeauche 1.26 if (r->gpr(1) != KernelDataAddr) {
1811 gbeauche 1.33
1812     // Set extra stack for nested interrupts
1813     sig_stack_acquire();
1814    
1815 cebix 1.1 // Prepare for 68k interrupt level 1
1816     WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1);
1817     WriteMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc, ReadMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc) | ntohl(kernel_data->v[0x674 >> 2]));
1818    
1819     // Execute nanokernel interrupt routine (this will activate the 68k emulator)
1820 gbeauche 1.33 DisableInterrupt();
1821 cebix 1.1 if (ROMType == ROMTYPE_NEWWORLD)
1822     ppc_interrupt(ROM_BASE + 0x312b1c, KernelDataAddr);
1823     else
1824     ppc_interrupt(ROM_BASE + 0x312a3c, KernelDataAddr);
1825 gbeauche 1.33
1826     // Reset normal signal stack
1827     sig_stack_release();
1828 cebix 1.1 }
1829     break;
1830     #endif
1831    
1832     #if INTERRUPTS_IN_EMUL_OP_MODE
1833     case MODE_EMUL_OP:
1834     // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
1835     if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) {
1836    
1837     // Set extra stack for SIGSEGV handler
1838 gbeauche 1.33 sig_stack_acquire();
1839 cebix 1.1 #if 1
1840     // Execute full 68k interrupt routine
1841     M68kRegisters r;
1842     uint32 old_r25 = ReadMacInt32(XLM_68K_R25); // Save interrupt level
1843     WriteMacInt32(XLM_68K_R25, 0x21); // Execute with interrupt level 1
1844     static const uint16 proc[] = {
1845     0x3f3c, 0x0000, // move.w #$0000,-(sp) (fake format word)
1846     0x487a, 0x000a, // pea @1(pc) (return address)
1847     0x40e7, // move sr,-(sp) (saved SR)
1848     0x2078, 0x0064, // move.l $64,a0
1849     0x4ed0, // jmp (a0)
1850     M68K_RTS // @1
1851     };
1852     Execute68k((uint32)proc, &r);
1853     WriteMacInt32(XLM_68K_R25, old_r25); // Restore interrupt level
1854     #else
1855     // Only update cursor
1856     if (HasMacStarted()) {
1857     if (InterruptFlags & INTFLAG_VIA) {
1858     ClearInterruptFlag(INTFLAG_VIA);
1859     ADBInterrupt();
1860 gbeauche 1.17 ExecuteNative(NATIVE_VIDEO_VBL);
1861 cebix 1.1 }
1862     }
1863     #endif
1864     // Reset normal signal stack
1865 gbeauche 1.33 sig_stack_release();
1866 cebix 1.1 }
1867     break;
1868     #endif
1869     }
1870     }
1871 gbeauche 1.8 #endif
1872 cebix 1.1
1873    
1874     /*
1875     * SIGSEGV handler
1876     */
1877    
1878 gbeauche 1.8 #if !EMULATED_PPC
1879 gbeauche 1.26 static void sigsegv_handler(int sig, siginfo_t *sip, void *scp)
1880 cebix 1.1 {
1881 gbeauche 1.26 machine_regs *r = MACHINE_REGISTERS(scp);
1882 gbeauche 1.5
1883     // Get effective address
1884 gbeauche 1.26 uint32 addr = r->dar();
1885 gbeauche 1.5
1886     #if ENABLE_VOSF
1887     // Handle screen fault.
1888     extern bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction);
1889 gbeauche 1.26 if (Screen_fault_handler((sigsegv_address_t)addr, (sigsegv_address_t)r->pc()))
1890 gbeauche 1.5 return;
1891     #endif
1892    
1893 cebix 1.1 num_segv++;
1894    
1895 gbeauche 1.37 // Fault in Mac ROM or RAM or DR Cache?
1896     bool mac_fault = (r->pc() >= ROM_BASE) && (r->pc() < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc() >= RAMBase) && (r->pc() < (RAMBase + RAMSize)) || (r->pc() >= DR_CACHE_BASE && r->pc() < (DR_CACHE_BASE + DR_CACHE_SIZE));
1897 cebix 1.1 if (mac_fault) {
1898    
1899     // "VM settings" during MacOS 8 installation
1900 gbeauche 1.26 if (r->pc() == ROM_BASE + 0x488160 && r->gpr(20) == 0xf8000000) {
1901     r->pc() += 4;
1902     r->gpr(8) = 0;
1903 cebix 1.1 return;
1904    
1905     // MacOS 8.5 installation
1906 gbeauche 1.26 } else if (r->pc() == ROM_BASE + 0x488140 && r->gpr(16) == 0xf8000000) {
1907     r->pc() += 4;
1908     r->gpr(8) = 0;
1909 cebix 1.1 return;
1910    
1911     // MacOS 8 serial drivers on startup
1912 gbeauche 1.26 } else if (r->pc() == ROM_BASE + 0x48e080 && (r->gpr(8) == 0xf3012002 || r->gpr(8) == 0xf3012000)) {
1913     r->pc() += 4;
1914     r->gpr(8) = 0;
1915 cebix 1.1 return;
1916    
1917     // MacOS 8.1 serial drivers on startup
1918 gbeauche 1.26 } else if (r->pc() == ROM_BASE + 0x48c5e0 && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) {
1919     r->pc() += 4;
1920 cebix 1.1 return;
1921 gbeauche 1.26 } else if (r->pc() == ROM_BASE + 0x4a10a0 && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) {
1922     r->pc() += 4;
1923 cebix 1.1 return;
1924 gbeauche 1.37
1925     // MacOS 8.6 serial drivers on startup (with DR Cache and OldWorld ROM)
1926     } else if ((r->pc() - DR_CACHE_BASE) < DR_CACHE_SIZE && (r->gpr(16) == 0xf3012002 || r->gpr(16) == 0xf3012000)) {
1927     r->pc() += 4;
1928     return;
1929     } else if ((r->pc() - DR_CACHE_BASE) < DR_CACHE_SIZE && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) {
1930     r->pc() += 4;
1931     return;
1932 cebix 1.1 }
1933    
1934 gbeauche 1.5 // Get opcode and divide into fields
1935 gbeauche 1.26 uint32 opcode = *((uint32 *)r->pc());
1936 gbeauche 1.5 uint32 primop = opcode >> 26;
1937     uint32 exop = (opcode >> 1) & 0x3ff;
1938     uint32 ra = (opcode >> 16) & 0x1f;
1939     uint32 rb = (opcode >> 11) & 0x1f;
1940     uint32 rd = (opcode >> 21) & 0x1f;
1941     int32 imm = (int16)(opcode & 0xffff);
1942    
1943 cebix 1.1 // Analyze opcode
1944     enum {
1945     TYPE_UNKNOWN,
1946     TYPE_LOAD,
1947     TYPE_STORE
1948     } transfer_type = TYPE_UNKNOWN;
1949     enum {
1950     SIZE_UNKNOWN,
1951     SIZE_BYTE,
1952     SIZE_HALFWORD,
1953     SIZE_WORD
1954     } transfer_size = SIZE_UNKNOWN;
1955     enum {
1956     MODE_UNKNOWN,
1957     MODE_NORM,
1958     MODE_U,
1959     MODE_X,
1960     MODE_UX
1961     } addr_mode = MODE_UNKNOWN;
1962     switch (primop) {
1963     case 31:
1964     switch (exop) {
1965     case 23: // lwzx
1966     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1967     case 55: // lwzux
1968     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1969     case 87: // lbzx
1970     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1971     case 119: // lbzux
1972     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1973     case 151: // stwx
1974     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1975     case 183: // stwux
1976     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1977     case 215: // stbx
1978     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1979     case 247: // stbux
1980     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1981     case 279: // lhzx
1982     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1983     case 311: // lhzux
1984     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1985     case 343: // lhax
1986     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1987     case 375: // lhaux
1988     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1989     case 407: // sthx
1990     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1991     case 439: // sthux
1992     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1993     }
1994     break;
1995    
1996     case 32: // lwz
1997     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1998     case 33: // lwzu
1999     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
2000     case 34: // lbz
2001     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
2002     case 35: // lbzu
2003     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
2004     case 36: // stw
2005     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
2006     case 37: // stwu
2007     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
2008     case 38: // stb
2009     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
2010     case 39: // stbu
2011     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
2012     case 40: // lhz
2013     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
2014     case 41: // lhzu
2015     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
2016     case 42: // lha
2017     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
2018     case 43: // lhau
2019     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
2020     case 44: // sth
2021     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
2022     case 45: // sthu
2023     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
2024 gbeauche 1.23 #if EMULATE_UNALIGNED_LOADSTORE_MULTIPLE
2025     case 46: // lmw
2026 gbeauche 1.27 if ((addr % 4) != 0) {
2027     uint32 ea = addr;
2028 gbeauche 1.26 D(bug("WARNING: unaligned lmw to EA=%08x from IP=%08x\n", ea, r->pc()));
2029 gbeauche 1.23 for (int i = rd; i <= 31; i++) {
2030 gbeauche 1.26 r->gpr(i) = ReadMacInt32(ea);
2031 gbeauche 1.23 ea += 4;
2032     }
2033 gbeauche 1.26 r->pc() += 4;
2034 gbeauche 1.23 goto rti;
2035     }
2036     break;
2037     case 47: // stmw
2038 gbeauche 1.27 if ((addr % 4) != 0) {
2039     uint32 ea = addr;
2040 gbeauche 1.26 D(bug("WARNING: unaligned stmw to EA=%08x from IP=%08x\n", ea, r->pc()));
2041 gbeauche 1.23 for (int i = rd; i <= 31; i++) {
2042 gbeauche 1.26 WriteMacInt32(ea, r->gpr(i));
2043 gbeauche 1.23 ea += 4;
2044     }
2045 gbeauche 1.26 r->pc() += 4;
2046 gbeauche 1.23 goto rti;
2047     }
2048     break;
2049     #endif
2050 cebix 1.1 }
2051    
2052 gbeauche 1.31 // Ignore ROM writes (including to the zero page, which is read-only)
2053     if (transfer_type == TYPE_STORE &&
2054     ((addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) ||
2055     (addr >= SheepMem::ZeroPage() && addr < SheepMem::ZeroPage() + SheepMem::PageSize()))) {
2056 gbeauche 1.26 // 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->pc()));
2057 cebix 1.1 if (addr_mode == MODE_U || addr_mode == MODE_UX)
2058 gbeauche 1.26 r->gpr(ra) = addr;
2059     r->pc() += 4;
2060 cebix 1.1 goto rti;
2061     }
2062    
2063     // Ignore illegal memory accesses?
2064     if (PrefsFindBool("ignoresegv")) {
2065     if (addr_mode == MODE_U || addr_mode == MODE_UX)
2066 gbeauche 1.26 r->gpr(ra) = addr;
2067 cebix 1.1 if (transfer_type == TYPE_LOAD)
2068 gbeauche 1.26 r->gpr(rd) = 0;
2069     r->pc() += 4;
2070 cebix 1.1 goto rti;
2071     }
2072    
2073     // In GUI mode, show error alert
2074     if (!PrefsFindBool("nogui")) {
2075     char str[256];
2076     if (transfer_type == TYPE_LOAD || transfer_type == TYPE_STORE)
2077 gbeauche 1.26 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->pc(), r->gpr(24), r->gpr(1));
2078 cebix 1.1 else
2079 gbeauche 1.26 sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc(), r->gpr(24), r->gpr(1), opcode);
2080 cebix 1.1 ErrorAlert(str);
2081     QuitEmulator();
2082     return;
2083     }
2084     }
2085    
2086     // For all other errors, jump into debugger (sort of...)
2087 gbeauche 1.23 crash_reason = (sig == SIGBUS) ? "SIGBUS" : "SIGSEGV";
2088 cebix 1.1 if (!ready_for_signals) {
2089 gbeauche 1.23 printf("%s\n");
2090 gbeauche 1.26 printf(" sigcontext %p, machine_regs %p\n", scp, r);
2091 cebix 1.1 printf(
2092     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
2093     " xer %08lx cr %08lx \n"
2094     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
2095     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
2096     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
2097     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
2098     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
2099     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
2100     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
2101     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
2102 gbeauche 1.23 crash_reason,
2103 gbeauche 1.26 r->pc(), r->lr(), r->ctr(), r->msr(),
2104     r->xer(), r->cr(),
2105     r->gpr(0), r->gpr(1), r->gpr(2), r->gpr(3),
2106     r->gpr(4), r->gpr(5), r->gpr(6), r->gpr(7),
2107     r->gpr(8), r->gpr(9), r->gpr(10), r->gpr(11),
2108     r->gpr(12), r->gpr(13), r->gpr(14), r->gpr(15),
2109     r->gpr(16), r->gpr(17), r->gpr(18), r->gpr(19),
2110     r->gpr(20), r->gpr(21), r->gpr(22), r->gpr(23),
2111     r->gpr(24), r->gpr(25), r->gpr(26), r->gpr(27),
2112     r->gpr(28), r->gpr(29), r->gpr(30), r->gpr(31));
2113 cebix 1.1 exit(1);
2114     QuitEmulator();
2115     return;
2116     } else {
2117     // We crashed. Save registers, tell tick thread and loop forever
2118 gbeauche 1.26 build_sigregs(&sigsegv_regs, r);
2119 cebix 1.1 emul_thread_fatal = true;
2120     for (;;) ;
2121     }
2122     rti:;
2123     }
2124    
2125    
2126     /*
2127     * SIGILL handler
2128     */
2129    
2130 gbeauche 1.26 static void sigill_handler(int sig, siginfo_t *sip, void *scp)
2131 cebix 1.1 {
2132 gbeauche 1.26 machine_regs *r = MACHINE_REGISTERS(scp);
2133 cebix 1.1 char str[256];
2134    
2135     // Fault in Mac ROM or RAM?
2136 gbeauche 1.26 bool mac_fault = (r->pc() >= ROM_BASE) && (r->pc() < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc() >= RAMBase) && (r->pc() < (RAMBase + RAMSize));
2137 cebix 1.1 if (mac_fault) {
2138    
2139     // Get opcode and divide into fields
2140 gbeauche 1.26 uint32 opcode = *((uint32 *)r->pc());
2141 cebix 1.1 uint32 primop = opcode >> 26;
2142     uint32 exop = (opcode >> 1) & 0x3ff;
2143     uint32 ra = (opcode >> 16) & 0x1f;
2144     uint32 rb = (opcode >> 11) & 0x1f;
2145     uint32 rd = (opcode >> 21) & 0x1f;
2146     int32 imm = (int16)(opcode & 0xffff);
2147    
2148     switch (primop) {
2149     case 9: // POWER instructions
2150     case 22:
2151 gbeauche 1.26 power_inst: sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->pc(), r->gpr(1), opcode);
2152 cebix 1.1 ErrorAlert(str);
2153     QuitEmulator();
2154     return;
2155    
2156     case 31:
2157     switch (exop) {
2158     case 83: // mfmsr
2159 gbeauche 1.26 r->gpr(rd) = 0xf072;
2160     r->pc() += 4;
2161 cebix 1.1 goto rti;
2162    
2163     case 210: // mtsr
2164     case 242: // mtsrin
2165     case 306: // tlbie
2166 gbeauche 1.26 r->pc() += 4;
2167 cebix 1.1 goto rti;
2168    
2169     case 339: { // mfspr
2170     int spr = ra | (rb << 5);
2171     switch (spr) {
2172     case 0: // MQ
2173     case 22: // DEC
2174     case 952: // MMCR0
2175     case 953: // PMC1
2176     case 954: // PMC2
2177     case 955: // SIA
2178     case 956: // MMCR1
2179     case 957: // PMC3
2180     case 958: // PMC4
2181     case 959: // SDA
2182 gbeauche 1.26 r->pc() += 4;
2183 cebix 1.1 goto rti;
2184     case 25: // SDR1
2185 gbeauche 1.26 r->gpr(rd) = 0xdead001f;
2186     r->pc() += 4;
2187 cebix 1.1 goto rti;
2188     case 287: // PVR
2189 gbeauche 1.26 r->gpr(rd) = PVR;
2190     r->pc() += 4;
2191 cebix 1.1 goto rti;
2192     }
2193     break;
2194     }
2195    
2196     case 467: { // mtspr
2197     int spr = ra | (rb << 5);
2198     switch (spr) {
2199     case 0: // MQ
2200     case 22: // DEC
2201     case 275: // SPRG3
2202     case 528: // IBAT0U
2203     case 529: // IBAT0L
2204     case 530: // IBAT1U
2205     case 531: // IBAT1L
2206     case 532: // IBAT2U
2207     case 533: // IBAT2L
2208     case 534: // IBAT3U
2209     case 535: // IBAT3L
2210     case 536: // DBAT0U
2211     case 537: // DBAT0L
2212     case 538: // DBAT1U
2213     case 539: // DBAT1L
2214     case 540: // DBAT2U
2215     case 541: // DBAT2L
2216     case 542: // DBAT3U
2217     case 543: // DBAT3L
2218     case 952: // MMCR0
2219     case 953: // PMC1
2220     case 954: // PMC2
2221     case 955: // SIA
2222     case 956: // MMCR1
2223     case 957: // PMC3
2224     case 958: // PMC4
2225     case 959: // SDA
2226 gbeauche 1.26 r->pc() += 4;
2227 cebix 1.1 goto rti;
2228     }
2229     break;
2230     }
2231    
2232     case 29: case 107: case 152: case 153: // POWER instructions
2233     case 184: case 216: case 217: case 248:
2234     case 264: case 277: case 331: case 360:
2235     case 363: case 488: case 531: case 537:
2236     case 541: case 664: case 665: case 696:
2237     case 728: case 729: case 760: case 920:
2238     case 921: case 952:
2239     goto power_inst;
2240     }
2241     }
2242    
2243     // In GUI mode, show error alert
2244     if (!PrefsFindBool("nogui")) {
2245 gbeauche 1.26 sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc(), r->gpr(24), r->gpr(1), opcode);
2246 cebix 1.1 ErrorAlert(str);
2247     QuitEmulator();
2248     return;
2249     }
2250     }
2251    
2252     // For all other errors, jump into debugger (sort of...)
2253 gbeauche 1.23 crash_reason = "SIGILL";
2254 cebix 1.1 if (!ready_for_signals) {
2255 gbeauche 1.23 printf("%s\n");
2256 gbeauche 1.26 printf(" sigcontext %p, machine_regs %p\n", scp, r);
2257 cebix 1.1 printf(
2258     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
2259     " xer %08lx cr %08lx \n"
2260     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
2261     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
2262     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
2263     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
2264     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
2265     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
2266     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
2267     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
2268 gbeauche 1.23 crash_reason,
2269 gbeauche 1.26 r->pc(), r->lr(), r->ctr(), r->msr(),
2270     r->xer(), r->cr(),
2271     r->gpr(0), r->gpr(1), r->gpr(2), r->gpr(3),
2272     r->gpr(4), r->gpr(5), r->gpr(6), r->gpr(7),
2273     r->gpr(8), r->gpr(9), r->gpr(10), r->gpr(11),
2274     r->gpr(12), r->gpr(13), r->gpr(14), r->gpr(15),
2275     r->gpr(16), r->gpr(17), r->gpr(18), r->gpr(19),
2276     r->gpr(20), r->gpr(21), r->gpr(22), r->gpr(23),
2277     r->gpr(24), r->gpr(25), r->gpr(26), r->gpr(27),
2278     r->gpr(28), r->gpr(29), r->gpr(30), r->gpr(31));
2279 cebix 1.1 exit(1);
2280     QuitEmulator();
2281     return;
2282     } else {
2283     // We crashed. Save registers, tell tick thread and loop forever
2284 gbeauche 1.26 build_sigregs(&sigsegv_regs, r);
2285 cebix 1.1 emul_thread_fatal = true;
2286     for (;;) ;
2287     }
2288     rti:;
2289     }
2290     #endif
2291 gbeauche 1.15
2292    
2293     /*
2294     * Helpers to share 32-bit addressable data with MacOS
2295     */
2296    
2297     bool SheepMem::Init(void)
2298     {
2299 gbeauche 1.31 // Size of a native page
2300     page_size = getpagesize();
2301 gbeauche 1.20
2302     // Allocate SheepShaver globals
2303 gbeauche 1.53 proc = base;
2304     if (vm_mac_acquire(base, size) < 0)
2305 gbeauche 1.15 return false;
2306 gbeauche 1.18
2307 gbeauche 1.53 // Allocate page with all bits set to 0, right in the middle
2308     // This is also used to catch undesired overlaps between proc and data areas
2309     zero_page = proc + (size / 2);
2310     Mac_memset(zero_page, 0, page_size);
2311     if (vm_protect(Mac2HostAddr(zero_page), page_size, VM_PAGE_READ) < 0)
2312 gbeauche 1.18 return false;
2313    
2314 gbeauche 1.20 #if EMULATED_PPC
2315     // Allocate alternate stack for PowerPC interrupt routine
2316 gbeauche 1.53 sig_stack = base + size;
2317     if (vm_mac_acquire(sig_stack, SIG_STACK_SIZE) < 0)
2318 gbeauche 1.20 return false;
2319     #endif
2320    
2321 gbeauche 1.53 data = base + size;
2322 gbeauche 1.15 return true;
2323     }
2324    
2325     void SheepMem::Exit(void)
2326     {
2327 gbeauche 1.53 if (data) {
2328 gbeauche 1.20 // Delete SheepShaver globals
2329 gbeauche 1.53 vm_mac_release(base, size);
2330 gbeauche 1.20
2331     #if EMULATED_PPC
2332     // Delete alternate stack for PowerPC interrupt routine
2333 gbeauche 1.53 vm_mac_release(sig_stack, SIG_STACK_SIZE);
2334 gbeauche 1.20 #endif
2335 gbeauche 1.18 }
2336 gbeauche 1.15 }
2337 cebix 1.1
2338    
2339     /*
2340     * Display alert
2341     */
2342    
2343     #ifdef ENABLE_GTK
2344     static void dl_destroyed(void)
2345     {
2346     gtk_main_quit();
2347     }
2348    
2349     static void dl_quit(GtkWidget *dialog)
2350     {
2351     gtk_widget_destroy(dialog);
2352     }
2353    
2354     void display_alert(int title_id, int prefix_id, int button_id, const char *text)
2355     {
2356     char str[256];
2357     sprintf(str, GetString(prefix_id), text);
2358    
2359     GtkWidget *dialog = gtk_dialog_new();
2360     gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id));
2361     gtk_container_border_width(GTK_CONTAINER(dialog), 5);
2362     gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
2363     gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL);
2364    
2365     GtkWidget *label = gtk_label_new(str);
2366     gtk_widget_show(label);
2367     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
2368    
2369     GtkWidget *button = gtk_button_new_with_label(GetString(button_id));
2370     gtk_widget_show(button);
2371     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
2372     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
2373     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2374     gtk_widget_grab_default(button);
2375     gtk_widget_show(dialog);
2376    
2377     gtk_main();
2378     }
2379     #endif
2380    
2381    
2382     /*
2383     * Display error alert
2384     */
2385    
2386     void ErrorAlert(const char *text)
2387     {
2388 gbeauche 1.42 #if defined(ENABLE_GTK) && !defined(USE_SDL_VIDEO)
2389 cebix 1.1 if (PrefsFindBool("nogui") || x_display == NULL) {
2390     printf(GetString(STR_SHELL_ERROR_PREFIX), text);
2391     return;
2392     }
2393     VideoQuitFullScreen();
2394     display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text);
2395     #else
2396     printf(GetString(STR_SHELL_ERROR_PREFIX), text);
2397     #endif
2398     }
2399    
2400    
2401     /*
2402     * Display warning alert
2403     */
2404    
2405     void WarningAlert(const char *text)
2406     {
2407 gbeauche 1.42 #if defined(ENABLE_GTK) && !defined(USE_SDL_VIDEO)
2408 cebix 1.1 if (PrefsFindBool("nogui") || x_display == NULL) {
2409     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
2410     return;
2411     }
2412     display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text);
2413     #else
2414     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
2415     #endif
2416     }
2417    
2418    
2419     /*
2420     * Display choice alert
2421     */
2422    
2423     bool ChoiceAlert(const char *text, const char *pos, const char *neg)
2424     {
2425     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
2426     return false; //!!
2427     }