ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/main_unix.cpp
Revision: 1.65
Committed: 2005-06-28T16:47:32Z (19 years, 4 months ago) by gbeauche
Branch: MAIN
Changes since 1.64: +39 -61 lines
Log Message:
The alternate stack trick never worked as you can't modify an active stack.
i.e. it returned EPERM and ran into stack corruption to eventually crash the
emulator. This is noticeable in !hw_mac_cursor_accl mode (e.g. fullscreen DGA).

In order to the sigalstack() to be effective, we must kludge the kernel to
think it's running on another stack. In practise, we provide another stack
for the SIGUSR2 handler. sigusr2_handler_init() fulfills that purpose.

I hope this fixes remaining issues forever. At some point, I had multiple
*_init() handlers in case this is necessary.

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * main_unix.cpp - Emulation core, Unix implementation
3     *
4 gbeauche 1.58 * SheepShaver (C) 1997-2005 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 gbeauche 1.60 * - There is a pointer to Thread Local Storage (TLS) under Linux with
31     * recent enough glibc. This is r2 in 32-bit mode and r13 in
32     * 64-bit mode (PowerOpen/AIX ABI)
33 cebix 1.1 * - r13 is used as a small data pointer under Linux (but appearently
34     * it is not used this way? To be sure, we specify -msdata=none
35     * in the Makefile)
36 gbeauche 1.60 * - There are no TVECTs under Linux; function pointers point
37     * directly to the function code
38 cebix 1.1 * The Execute*() functions have to account for this. Additionally, we
39     * cannot simply call MacOS functions by getting their TVECT and jumping
40     * to it. Such calls are done via the call_macos*() functions in
41     * asm_linux.S that create a MacOS stack frame, load the TOC pointer
42     * and put the arguments into the right registers.
43     *
44     * As on the BeOS, we have to specify an alternate signal stack because
45     * interrupts (and, under Linux, Low Memory accesses) may occur when r1
46     * is pointing to the Kernel Data or to Low Memory. There is one
47     * problem, however, due to the alternate signal stack being global to
48     * all signal handlers. Consider the following scenario:
49     * - The main thread is executing some native PPC MacOS code in
50     * MODE_NATIVE, running on the MacOS stack (somewhere in the Mac RAM).
51     * - A SIGUSR2 interrupt occurs. The kernel switches to the signal
52     * stack and starts executing the SIGUSR2 signal handler.
53     * - The signal handler sees the MODE_NATIVE and calls ppc_interrupt()
54     * to handle a native interrupt.
55     * - ppc_interrupt() sets r1 to point to the Kernel Data and jumps to
56     * the nanokernel.
57     * - The nanokernel accesses a Low Memory global (most likely one of
58     * the XLMs), a SIGSEGV occurs.
59     * - The kernel sees that r1 does not point to the signal stack and
60     * switches to the signal stack again, thus overwriting the data that
61     * the SIGUSR2 handler put there.
62     * The same problem arises when calling ExecutePPC() inside the MODE_EMUL_OP
63     * interrupt handler.
64     *
65     * The solution is to set the signal stack to a second, "extra" stack
66     * inside the SIGUSR2 handler before entering the Nanokernel or calling
67     * ExecutePPC (or any function that might cause a mode switch). The signal
68     * stack is restored before exiting the SIGUSR2 handler.
69     *
70 gbeauche 1.65 * Note that POSIX standard says you can't modify the alternate
71     * signal stack while the process is executing on it. There is a
72     * hackaround though: we install a trampoline SIGUSR2 handler that
73     * sets up an alternate stack itself and calls the real handler.
74     * Then, when we call sigaltstack() there, we no longer get an EPERM,
75     * i.e. it now works.
76 gbeauche 1.33 *
77 cebix 1.1 * TODO:
78     * check if SIGSEGV handler works for all registers (including FP!)
79     */
80    
81     #include <unistd.h>
82     #include <fcntl.h>
83     #include <time.h>
84     #include <errno.h>
85     #include <stdio.h>
86     #include <stdlib.h>
87     #include <string.h>
88     #include <pthread.h>
89     #include <sys/mman.h>
90     #include <sys/ipc.h>
91     #include <sys/shm.h>
92     #include <signal.h>
93    
94     #include "sysdeps.h"
95     #include "main.h"
96     #include "version.h"
97     #include "prefs.h"
98     #include "prefs_editor.h"
99     #include "cpu_emulation.h"
100     #include "emul_op.h"
101     #include "xlowmem.h"
102     #include "xpram.h"
103     #include "timer.h"
104     #include "adb.h"
105     #include "video.h"
106     #include "sys.h"
107     #include "macos_util.h"
108     #include "rom_patches.h"
109     #include "user_strings.h"
110 gbeauche 1.4 #include "vm_alloc.h"
111 gbeauche 1.5 #include "sigsegv.h"
112 cebix 1.1
113     #define DEBUG 0
114     #include "debug.h"
115    
116    
117 gbeauche 1.47 #ifdef HAVE_DIRENT_H
118     #include <dirent.h>
119     #endif
120    
121 gbeauche 1.42 #ifdef USE_SDL
122     #include <SDL.h>
123     #endif
124    
125     #ifndef USE_SDL_VIDEO
126 cebix 1.1 #include <X11/Xlib.h>
127 gbeauche 1.42 #endif
128 cebix 1.1
129     #ifdef ENABLE_GTK
130     #include <gtk/gtk.h>
131     #endif
132    
133     #ifdef ENABLE_XF86_DGA
134     #include <X11/Xlib.h>
135     #include <X11/Xutil.h>
136     #include <X11/extensions/xf86dga.h>
137     #endif
138    
139     #ifdef ENABLE_MON
140     #include "mon.h"
141     #endif
142    
143    
144 gbeauche 1.23 // Enable emulation of unaligned lmw/stmw?
145     #define EMULATE_UNALIGNED_LOADSTORE_MULTIPLE 1
146    
147 cebix 1.1 // Enable Execute68k() safety checks?
148     #define SAFE_EXEC_68K 0
149    
150     // Interrupts in EMUL_OP mode?
151     #define INTERRUPTS_IN_EMUL_OP_MODE 1
152    
153     // Interrupts in native mode?
154     #define INTERRUPTS_IN_NATIVE_MODE 1
155    
156    
157     // Constants
158     const char ROM_FILE_NAME[] = "ROM";
159     const char ROM_FILE_NAME2[] = "Mac OS ROM";
160    
161 gbeauche 1.52 #if REAL_ADDRESSING
162 gbeauche 1.15 const uintptr RAM_BASE = 0x20000000; // Base address of RAM
163 gbeauche 1.52 #else
164     // FIXME: needs to be >= 0x04000000
165     const uintptr RAM_BASE = 0x10000000; // Base address of RAM
166     #endif
167 cebix 1.1 const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack
168    
169    
170     #if !EMULATED_PPC
171 gbeauche 1.26 struct sigregs {
172     uint32 nip;
173     uint32 link;
174     uint32 ctr;
175     uint32 msr;
176     uint32 xer;
177     uint32 ccr;
178     uint32 gpr[32];
179     };
180 cebix 1.1
181 gbeauche 1.26 #if defined(__linux__)
182 gbeauche 1.28 #include <sys/ucontext.h>
183     #define MACHINE_REGISTERS(scp) ((machine_regs *)(((ucontext_t *)scp)->uc_mcontext.regs))
184    
185 gbeauche 1.26 struct machine_regs : public pt_regs
186     {
187     u_long & cr() { return pt_regs::ccr; }
188     uint32 cr() const { return pt_regs::ccr; }
189     uint32 lr() const { return pt_regs::link; }
190     uint32 ctr() const { return pt_regs::ctr; }
191     uint32 xer() const { return pt_regs::xer; }
192     uint32 msr() const { return pt_regs::msr; }
193     uint32 dar() const { return pt_regs::dar; }
194     u_long & pc() { return pt_regs::nip; }
195     uint32 pc() const { return pt_regs::nip; }
196     u_long & gpr(int i) { return pt_regs::gpr[i]; }
197     uint32 gpr(int i) const { return pt_regs::gpr[i]; }
198 cebix 1.1 };
199 gbeauche 1.28 #endif
200    
201 gbeauche 1.59 #if defined(__NetBSD__)
202     #include <sys/ucontext.h>
203     #define MACHINE_REGISTERS(scp) ((machine_regs *)&(((ucontext_t *)scp)->uc_mcontext))
204    
205     struct machine_regs : public mcontext_t
206     {
207     long & cr() { return __gregs[_REG_CR]; }
208     uint32 cr() const { return __gregs[_REG_CR]; }
209     uint32 lr() const { return __gregs[_REG_LR]; }
210     uint32 ctr() const { return __gregs[_REG_CTR]; }
211     uint32 xer() const { return __gregs[_REG_XER]; }
212     uint32 msr() const { return __gregs[_REG_MSR]; }
213     uint32 dar() const { return (uint32)(((siginfo_t *)(((unsigned long)this) - offsetof(ucontext_t, uc_mcontext))) - 1)->si_addr; } /* HACK */
214     long & pc() { return __gregs[_REG_PC]; }
215     uint32 pc() const { return __gregs[_REG_PC]; }
216     long & gpr(int i) { return __gregs[_REG_R0 + i]; }
217     uint32 gpr(int i) const { return __gregs[_REG_R0 + i]; }
218     };
219     #endif
220    
221 gbeauche 1.28 #if defined(__APPLE__) && defined(__MACH__)
222     #include <sys/signal.h>
223     extern "C" int sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
224 gbeauche 1.26
225     #include <sys/ucontext.h>
226 gbeauche 1.28 #define MACHINE_REGISTERS(scp) ((machine_regs *)(((ucontext_t *)scp)->uc_mcontext))
227 gbeauche 1.26
228     struct machine_regs : public mcontext
229     {
230     uint32 & cr() { return ss.cr; }
231     uint32 cr() const { return ss.cr; }
232     uint32 lr() const { return ss.lr; }
233     uint32 ctr() const { return ss.ctr; }
234     uint32 xer() const { return ss.xer; }
235     uint32 msr() const { return ss.srr1; }
236     uint32 dar() const { return es.dar; }
237     uint32 & pc() { return ss.srr0; }
238     uint32 pc() const { return ss.srr0; }
239     uint32 & gpr(int i) { return (&ss.r0)[i]; }
240     uint32 gpr(int i) const { return (&ss.r0)[i]; }
241     };
242     #endif
243    
244     static void build_sigregs(sigregs *srp, machine_regs *mrp)
245     {
246     srp->nip = mrp->pc();
247     srp->link = mrp->lr();
248     srp->ctr = mrp->ctr();
249     srp->msr = mrp->msr();
250     srp->xer = mrp->xer();
251     srp->ccr = mrp->cr();
252     for (int i = 0; i < 32; i++)
253     srp->gpr[i] = mrp->gpr(i);
254     }
255 cebix 1.1 #endif
256    
257    
258     // Global variables (exported)
259     #if !EMULATED_PPC
260 gbeauche 1.64 void *TOC = NULL; // Pointer to Thread Local Storage (r2)
261     void *R13 = NULL; // Pointer to .sdata section (r13 under Linux)
262 cebix 1.1 #endif
263     uint32 RAMBase; // Base address of Mac RAM
264     uint32 RAMSize; // Size of Mac RAM
265     uint32 KernelDataAddr; // Address of Kernel Data
266     uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM
267 gbeauche 1.36 uint32 DRCacheAddr; // Address of DR Cache
268 cebix 1.1 uint32 PVR; // Theoretical PVR
269     int64 CPUClockSpeed; // Processor clock speed (Hz)
270     int64 BusClockSpeed; // Bus clock speed (Hz)
271 gbeauche 1.47 int64 TimebaseSpeed; // Timebase clock speed (Hz)
272 gbeauche 1.52 uint8 *RAMBaseHost; // Base address of Mac RAM (host address space)
273     uint8 *ROMBaseHost; // Base address of Mac ROM (host address space)
274 cebix 1.1
275    
276     // Global variables
277 gbeauche 1.42 #ifndef USE_SDL_VIDEO
278 gbeauche 1.11 char *x_display_name = NULL; // X11 display name
279 cebix 1.1 Display *x_display = NULL; // X11 display handle
280 gbeauche 1.21 #ifdef X11_LOCK_TYPE
281     X11_LOCK_TYPE x_display_lock = X11_LOCK_INIT; // X11 display lock
282     #endif
283 gbeauche 1.42 #endif
284 cebix 1.1
285     static int zero_fd = 0; // FD of /dev/zero
286     static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped
287     static int kernel_area = -1; // SHM ID of Kernel Data area
288     static bool rom_area_mapped = false; // Flag: Mac ROM mmap()ped
289     static bool ram_area_mapped = false; // Flag: Mac RAM mmap()ped
290 gbeauche 1.36 static bool dr_cache_area_mapped = false; // Flag: Mac DR Cache mmap()ped
291     static bool dr_emulator_area_mapped = false;// Flag: Mac DR Emulator mmap()ped
292 cebix 1.1 static KernelData *kernel_data; // Pointer to Kernel Data
293     static EmulatorData *emulator_data;
294    
295     static uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes
296    
297     static bool nvram_thread_active = false; // Flag: NVRAM watchdog installed
298 gbeauche 1.40 static volatile bool nvram_thread_cancel; // Flag: Cancel NVRAM thread
299 cebix 1.1 static pthread_t nvram_thread; // NVRAM watchdog
300     static bool tick_thread_active = false; // Flag: MacOS thread installed
301 gbeauche 1.40 static volatile bool tick_thread_cancel; // Flag: Cancel 60Hz thread
302 cebix 1.1 static pthread_t tick_thread; // 60Hz thread
303     static pthread_t emul_thread; // MacOS thread
304    
305     static bool ready_for_signals = false; // Handler installed, signals can be sent
306     static int64 num_segv = 0; // Number of handled SEGV signals
307    
308 gbeauche 1.6 static struct sigaction sigusr2_action; // Interrupt signal (of emulator thread)
309 gbeauche 1.20 #if EMULATED_PPC
310     static uintptr sig_stack = 0; // Stack for PowerPC interrupt routine
311     #else
312 cebix 1.1 static struct sigaction sigsegv_action; // Data access exception signal (of emulator thread)
313     static struct sigaction sigill_action; // Illegal instruction signal (of emulator thread)
314 gbeauche 1.65 static struct sigaltstack sig_stack; // Stack for signal handlers
315     static struct sigaltstack extra_stack; // Stack for SIGSEGV inside interrupt handler
316 cebix 1.1 static bool emul_thread_fatal = false; // Flag: MacOS thread crashed, tick thread shall dump debug output
317     static sigregs sigsegv_regs; // Register dump when crashed
318 gbeauche 1.23 static const char *crash_reason = NULL; // Reason of the crash (SIGSEGV, SIGBUS, SIGILL)
319 cebix 1.1 #endif
320    
321 gbeauche 1.31 uint32 SheepMem::page_size; // Size of a native page
322 gbeauche 1.18 uintptr SheepMem::zero_page = 0; // Address of ro page filled in with zeros
323 gbeauche 1.15 uintptr SheepMem::base = 0x60000000; // Address of SheepShaver data
324 gbeauche 1.53 uintptr SheepMem::proc; // Bottom address of SheepShave procedures
325     uintptr SheepMem::data; // Top of SheepShaver data (stack like storage)
326 gbeauche 1.15
327 cebix 1.1
328     // Prototypes
329 gbeauche 1.53 static bool kernel_data_init(void);
330     static void kernel_data_exit(void);
331 cebix 1.1 static void Quit(void);
332     static void *emul_func(void *arg);
333     static void *nvram_func(void *arg);
334     static void *tick_func(void *arg);
335 gbeauche 1.8 #if EMULATED_PPC
336 gbeauche 1.13 extern void emul_ppc(uint32 start);
337     extern void init_emul_ppc(void);
338     extern void exit_emul_ppc(void);
339 gbeauche 1.43 sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t);
340 gbeauche 1.8 #else
341 gbeauche 1.65 extern "C" void sigusr2_handler_init(int sig, siginfo_t *sip, void *scp);
342     extern "C" void sigusr2_handler(int sig, siginfo_t *sip, void *scp);
343 gbeauche 1.26 static void sigsegv_handler(int sig, siginfo_t *sip, void *scp);
344     static void sigill_handler(int sig, siginfo_t *sip, void *scp);
345 cebix 1.1 #endif
346    
347    
348     // From asm_linux.S
349 gbeauche 1.12 #if !EMULATED_PPC
350 cebix 1.1 extern "C" void *get_sp(void);
351 gbeauche 1.60 extern "C" void *get_r2(void);
352     extern "C" void set_r2(void *);
353     extern "C" void *get_r13(void);
354     extern "C" void set_r13(void *);
355 gbeauche 1.57 extern "C" void flush_icache_range(uint32 start, uint32 end);
356 cebix 1.1 extern "C" void jump_to_rom(uint32 entry, uint32 context);
357     extern "C" void quit_emulator(void);
358     extern "C" void execute_68k(uint32 pc, M68kRegisters *r);
359     extern "C" void ppc_interrupt(uint32 entry, uint32 kernel_data);
360     extern "C" int atomic_add(int *var, int v);
361     extern "C" int atomic_and(int *var, int v);
362     extern "C" int atomic_or(int *var, int v);
363     extern void paranoia_check(void);
364 gbeauche 1.12 #endif
365    
366    
367     #if EMULATED_PPC
368     /*
369 gbeauche 1.20 * Return signal stack base
370     */
371    
372     uintptr SignalStackBase(void)
373     {
374     return sig_stack + SIG_STACK_SIZE;
375     }
376    
377    
378     /*
379 gbeauche 1.12 * Atomic operations
380     */
381    
382     #if HAVE_SPINLOCKS
383     static spinlock_t atomic_ops_lock = SPIN_LOCK_UNLOCKED;
384     #else
385     #define spin_lock(LOCK)
386     #define spin_unlock(LOCK)
387     #endif
388    
389     int atomic_add(int *var, int v)
390     {
391     spin_lock(&atomic_ops_lock);
392     int ret = *var;
393     *var += v;
394     spin_unlock(&atomic_ops_lock);
395     return ret;
396     }
397    
398     int atomic_and(int *var, int v)
399     {
400     spin_lock(&atomic_ops_lock);
401     int ret = *var;
402     *var &= v;
403     spin_unlock(&atomic_ops_lock);
404     return ret;
405     }
406    
407     int atomic_or(int *var, int v)
408     {
409     spin_lock(&atomic_ops_lock);
410     int ret = *var;
411     *var |= v;
412     spin_unlock(&atomic_ops_lock);
413     return ret;
414     }
415 cebix 1.1 #endif
416    
417    
418     /*
419 gbeauche 1.53 * Memory management helpers
420     */
421    
422     static inline int vm_mac_acquire(uint32 addr, uint32 size)
423     {
424     return vm_acquire_fixed(Mac2HostAddr(addr), size);
425     }
426    
427     static inline int vm_mac_release(uint32 addr, uint32 size)
428     {
429     return vm_release(Mac2HostAddr(addr), size);
430     }
431    
432    
433     /*
434 cebix 1.1 * Main program
435     */
436    
437     static void usage(const char *prg_name)
438     {
439     printf("Usage: %s [OPTION...]\n", prg_name);
440     printf("\nUnix options:\n");
441     printf(" --display STRING\n X display to use\n");
442     PrefsPrintUsage();
443     exit(0);
444     }
445    
446     int main(int argc, char **argv)
447     {
448     char str[256];
449     int rom_fd;
450     FILE *proc_file;
451     const char *rom_path;
452     uint32 rom_size, actual;
453     uint8 *rom_tmp;
454     time_t now, expire;
455    
456     // Initialize variables
457     RAMBase = 0;
458     tzset();
459    
460     // Print some info
461     printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
462     printf(" %s\n", GetString(STR_ABOUT_TEXT2));
463    
464     #if !EMULATED_PPC
465 gbeauche 1.60 #ifdef SYSTEM_CLOBBERS_R2
466 cebix 1.1 // Get TOC pointer
467 gbeauche 1.60 TOC = get_r2();
468     #endif
469     #ifdef SYSTEM_CLOBBERS_R13
470     // Get r13 register
471     R13 = get_r13();
472     #endif
473 cebix 1.1 #endif
474    
475     #ifdef ENABLE_GTK
476     // Init GTK
477     gtk_set_locale();
478     gtk_init(&argc, &argv);
479     #endif
480    
481     // Read preferences
482     PrefsInit(argc, argv);
483    
484     // Parse command line arguments
485     for (int i=1; i<argc; i++) {
486     if (strcmp(argv[i], "--help") == 0) {
487     usage(argv[0]);
488 gbeauche 1.42 #ifndef USE_SDL_VIDEO
489 cebix 1.1 } else if (strcmp(argv[i], "--display") == 0) {
490     i++;
491     if (i < argc)
492     x_display_name = strdup(argv[i]);
493 gbeauche 1.42 #endif
494 cebix 1.1 } else if (argv[i][0] == '-') {
495     fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
496     usage(argv[0]);
497     }
498     }
499    
500 gbeauche 1.42 #ifdef USE_SDL
501     // Initialize SDL system
502     int sdl_flags = 0;
503     #ifdef USE_SDL_VIDEO
504     sdl_flags |= SDL_INIT_VIDEO;
505     #endif
506 gbeauche 1.51 #ifdef USE_SDL_AUDIO
507     sdl_flags |= SDL_INIT_AUDIO;
508     #endif
509 gbeauche 1.42 assert(sdl_flags != 0);
510     if (SDL_Init(sdl_flags) == -1) {
511     char str[256];
512     sprintf(str, "Could not initialize SDL: %s.\n", SDL_GetError());
513     ErrorAlert(str);
514     goto quit;
515     }
516     atexit(SDL_Quit);
517     #endif
518    
519     #ifndef USE_SDL_VIDEO
520 cebix 1.1 // Open display
521     x_display = XOpenDisplay(x_display_name);
522     if (x_display == NULL) {
523     char str[256];
524     sprintf(str, GetString(STR_NO_XSERVER_ERR), XDisplayName(x_display_name));
525     ErrorAlert(str);
526     goto quit;
527     }
528    
529     #if defined(ENABLE_XF86_DGA) && !defined(ENABLE_MON)
530     // Fork out, so we can return from fullscreen mode when things get ugly
531     XF86DGAForkApp(DefaultScreen(x_display));
532     #endif
533 gbeauche 1.42 #endif
534 cebix 1.1
535     #ifdef ENABLE_MON
536     // Initialize mon
537     mon_init();
538     #endif
539    
540 gbeauche 1.43 #if !EMULATED_PPC
541 gbeauche 1.44 // Create and install stacks for signal handlers
542 gbeauche 1.65 sig_stack.ss_sp = malloc(SIG_STACK_SIZE);
543     D(bug("Signal stack at %p\n", sig_stack.ss_sp));
544     if (sig_stack.ss_sp == NULL) {
545     ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
546     goto quit;
547 gbeauche 1.44 }
548 gbeauche 1.65 sig_stack.ss_flags = 0;
549     sig_stack.ss_size = SIG_STACK_SIZE;
550     if (sigaltstack(&sig_stack, NULL) < 0) {
551 gbeauche 1.44 sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno));
552     ErrorAlert(str);
553     goto quit;
554     }
555 gbeauche 1.65 extra_stack.ss_sp = malloc(SIG_STACK_SIZE);
556     D(bug("Extra stack at %p\n", extra_stack.ss_sp));
557     if (extra_stack.ss_sp == NULL) {
558     ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
559     goto quit;
560     }
561     extra_stack.ss_flags = 0;
562     extra_stack.ss_size = SIG_STACK_SIZE;
563 gbeauche 1.44 #endif
564    
565     #if !EMULATED_PPC
566 gbeauche 1.43 // Install SIGSEGV and SIGBUS handlers
567     sigemptyset(&sigsegv_action.sa_mask); // Block interrupts during SEGV handling
568     sigaddset(&sigsegv_action.sa_mask, SIGUSR2);
569     sigsegv_action.sa_sigaction = sigsegv_handler;
570     sigsegv_action.sa_flags = SA_ONSTACK | SA_SIGINFO;
571     #ifdef HAVE_SIGNAL_SA_RESTORER
572     sigsegv_action.sa_restorer = NULL;
573     #endif
574     if (sigaction(SIGSEGV, &sigsegv_action, NULL) < 0) {
575     sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno));
576     ErrorAlert(str);
577     goto quit;
578     }
579     if (sigaction(SIGBUS, &sigsegv_action, NULL) < 0) {
580     sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno));
581     ErrorAlert(str);
582     goto quit;
583     }
584     #else
585     // Install SIGSEGV handler for CPU emulator
586     if (!sigsegv_install_handler(sigsegv_handler)) {
587     sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno));
588     ErrorAlert(str);
589     goto quit;
590     }
591     #endif
592    
593     // Initialize VM system
594     vm_init();
595    
596 cebix 1.1 // Get system info
597     PVR = 0x00040000; // Default: 604
598     CPUClockSpeed = 100000000; // Default: 100MHz
599     BusClockSpeed = 100000000; // Default: 100MHz
600 gbeauche 1.47 TimebaseSpeed = 25000000; // Default: 25MHz
601 gbeauche 1.30 #if EMULATED_PPC
602     PVR = 0x000c0000; // Default: 7400 (with AltiVec)
603 gbeauche 1.39 #elif defined(__APPLE__) && defined(__MACH__)
604     proc_file = popen("ioreg -c IOPlatformDevice", "r");
605     if (proc_file) {
606     char line[256];
607     bool powerpc_node = false;
608     while (fgets(line, sizeof(line) - 1, proc_file)) {
609     // Read line
610     int len = strlen(line);
611     if (len == 0)
612     continue;
613     line[len - 1] = 0;
614    
615     // Parse line
616     if (strstr(line, "o PowerPC,"))
617     powerpc_node = true;
618     else if (powerpc_node) {
619     uint32 value;
620     char head[256];
621     if (sscanf(line, "%[ |]\"cpu-version\" = <%x>", head, &value) == 2)
622     PVR = value;
623     else if (sscanf(line, "%[ |]\"clock-frequency\" = <%x>", head, &value) == 2)
624     CPUClockSpeed = value;
625     else if (sscanf(line, "%[ |]\"bus-frequency\" = <%x>", head, &value) == 2)
626     BusClockSpeed = value;
627 gbeauche 1.48 else if (sscanf(line, "%[ |]\"timebase-frequency\" = <%x>", head, &value) == 2)
628     TimebaseSpeed = value;
629 gbeauche 1.39 else if (strchr(line, '}'))
630     powerpc_node = false;
631     }
632     }
633     fclose(proc_file);
634     } else {
635     sprintf(str, GetString(STR_PROC_CPUINFO_WARN), strerror(errno));
636     WarningAlert(str);
637     }
638 gbeauche 1.30 #else
639 cebix 1.1 proc_file = fopen("/proc/cpuinfo", "r");
640     if (proc_file) {
641 gbeauche 1.50 // CPU specs from Linux kernel
642     // TODO: make it more generic with features (e.g. AltiVec) and
643     // cache information and friends for NameRegistry
644     static const struct {
645     uint32 pvr_mask;
646     uint32 pvr_value;
647     const char *cpu_name;
648     }
649     cpu_specs[] = {
650     { 0xffff0000, 0x00010000, "601" },
651     { 0xffff0000, 0x00030000, "603" },
652     { 0xffff0000, 0x00060000, "603e" },
653     { 0xffff0000, 0x00070000, "603ev" },
654     { 0xffff0000, 0x00040000, "604" },
655     { 0xfffff000, 0x00090000, "604e" },
656     { 0xffff0000, 0x00090000, "604r" },
657     { 0xffff0000, 0x000a0000, "604ev" },
658     { 0xffffffff, 0x00084202, "740/750" },
659     { 0xfffff000, 0x00083000, "745/755" },
660     { 0xfffffff0, 0x00080100, "750CX" },
661     { 0xfffffff0, 0x00082200, "750CX" },
662     { 0xfffffff0, 0x00082210, "750CXe" },
663     { 0xffffff00, 0x70000100, "750FX" },
664     { 0xffffffff, 0x70000200, "750FX" },
665     { 0xffff0000, 0x70000000, "750FX" },
666     { 0xffff0000, 0x70020000, "750GX" },
667     { 0xffff0000, 0x00080000, "740/750" },
668     { 0xffffffff, 0x000c1101, "7400 (1.1)" },
669     { 0xffff0000, 0x000c0000, "7400" },
670     { 0xffff0000, 0x800c0000, "7410" },
671     { 0xffffffff, 0x80000200, "7450" },
672     { 0xffffffff, 0x80000201, "7450" },
673     { 0xffff0000, 0x80000000, "7450" },
674     { 0xffffff00, 0x80010100, "7455" },
675     { 0xffffffff, 0x80010200, "7455" },
676     { 0xffff0000, 0x80010000, "7455" },
677     { 0xffff0000, 0x80020000, "7457" },
678     { 0xffff0000, 0x80030000, "7447A" },
679     { 0x7fff0000, 0x00810000, "82xx" },
680     { 0x7fff0000, 0x00820000, "8280" },
681     { 0xffff0000, 0x00400000, "Power3 (630)" },
682     { 0xffff0000, 0x00410000, "Power3 (630+)" },
683     { 0xffff0000, 0x00360000, "I-star" },
684     { 0xffff0000, 0x00370000, "S-star" },
685     { 0xffff0000, 0x00350000, "Power4" },
686     { 0xffff0000, 0x00390000, "PPC970" },
687 gbeauche 1.63 { 0xffff0000, 0x003a0000, "POWER5" },
688 gbeauche 1.50 { 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 gbeauche 1.56 // Initialize everything
913     if (!InitAll())
914 cebix 1.1 goto quit;
915 gbeauche 1.56 D(bug("Initialization complete\n"));
916 cebix 1.1
917     // Clear caches (as we loaded and patched code) and write protect ROM
918     #if !EMULATED_PPC
919 gbeauche 1.57 flush_icache_range(ROM_BASE, ROM_BASE + ROM_AREA_SIZE);
920 cebix 1.1 #endif
921 gbeauche 1.52 vm_protect(ROMBaseHost, ROM_AREA_SIZE, VM_PAGE_READ | VM_PAGE_EXECUTE);
922 cebix 1.1
923     // Start 60Hz thread
924 gbeauche 1.40 tick_thread_cancel = false;
925 cebix 1.1 tick_thread_active = (pthread_create(&tick_thread, NULL, tick_func, NULL) == 0);
926     D(bug("Tick thread installed (%ld)\n", tick_thread));
927    
928     // Start NVRAM watchdog thread
929     memcpy(last_xpram, XPRAM, XPRAM_SIZE);
930 gbeauche 1.40 nvram_thread_cancel = false;
931 cebix 1.1 nvram_thread_active = (pthread_create(&nvram_thread, NULL, nvram_func, NULL) == 0);
932     D(bug("NVRAM thread installed (%ld)\n", nvram_thread));
933    
934     #if !EMULATED_PPC
935     // Install SIGILL handler
936     sigemptyset(&sigill_action.sa_mask); // Block interrupts during ILL handling
937     sigaddset(&sigill_action.sa_mask, SIGUSR2);
938 gbeauche 1.26 sigill_action.sa_sigaction = sigill_handler;
939     sigill_action.sa_flags = SA_ONSTACK | SA_SIGINFO;
940     #ifdef HAVE_SIGNAL_SA_RESTORER
941 cebix 1.1 sigill_action.sa_restorer = NULL;
942 gbeauche 1.26 #endif
943 cebix 1.1 if (sigaction(SIGILL, &sigill_action, NULL) < 0) {
944     sprintf(str, GetString(STR_SIGILL_INSTALL_ERR), strerror(errno));
945     ErrorAlert(str);
946     goto quit;
947     }
948 gbeauche 1.6 #endif
949 cebix 1.1
950 gbeauche 1.26 #if !EMULATED_PPC
951 cebix 1.1 // Install interrupt signal handler
952     sigemptyset(&sigusr2_action.sa_mask);
953 gbeauche 1.65 sigusr2_action.sa_sigaction = sigusr2_handler_init;
954 gbeauche 1.26 sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
955     #ifdef HAVE_SIGNAL_SA_RESTORER
956     sigusr2_action.sa_restorer = NULL;
957 gbeauche 1.8 #endif
958 cebix 1.1 if (sigaction(SIGUSR2, &sigusr2_action, NULL) < 0) {
959     sprintf(str, GetString(STR_SIGUSR2_INSTALL_ERR), strerror(errno));
960     ErrorAlert(str);
961     goto quit;
962     }
963 gbeauche 1.26 #endif
964 cebix 1.1
965     // Get my thread ID and execute MacOS thread function
966     emul_thread = pthread_self();
967     D(bug("MacOS thread is %ld\n", emul_thread));
968     emul_func(NULL);
969    
970     quit:
971     Quit();
972     return 0;
973     }
974    
975    
976     /*
977     * Cleanup and quit
978     */
979    
980     static void Quit(void)
981     {
982 gbeauche 1.13 #if EMULATED_PPC
983     // Exit PowerPC emulation
984     exit_emul_ppc();
985     #endif
986    
987 cebix 1.1 // Stop 60Hz thread
988     if (tick_thread_active) {
989 gbeauche 1.40 tick_thread_cancel = true;
990 cebix 1.1 pthread_cancel(tick_thread);
991     pthread_join(tick_thread, NULL);
992     }
993    
994     // Stop NVRAM watchdog thread
995     if (nvram_thread_active) {
996 gbeauche 1.40 nvram_thread_cancel = true;
997 cebix 1.1 pthread_cancel(nvram_thread);
998     pthread_join(nvram_thread, NULL);
999     }
1000    
1001     #if !EMULATED_PPC
1002 gbeauche 1.23 // Uninstall SIGSEGV and SIGBUS handlers
1003 cebix 1.1 sigemptyset(&sigsegv_action.sa_mask);
1004     sigsegv_action.sa_handler = SIG_DFL;
1005     sigsegv_action.sa_flags = 0;
1006     sigaction(SIGSEGV, &sigsegv_action, NULL);
1007 gbeauche 1.23 sigaction(SIGBUS, &sigsegv_action, NULL);
1008 cebix 1.1
1009     // Uninstall SIGILL handler
1010     sigemptyset(&sigill_action.sa_mask);
1011     sigill_action.sa_handler = SIG_DFL;
1012     sigill_action.sa_flags = 0;
1013     sigaction(SIGILL, &sigill_action, NULL);
1014 gbeauche 1.33
1015     // Delete stacks for signal handlers
1016 gbeauche 1.65 if (sig_stack.ss_sp)
1017     free(sig_stack.ss_sp);
1018     if (extra_stack.ss_sp)
1019     free(extra_stack.ss_sp);
1020 cebix 1.1 #endif
1021    
1022 gbeauche 1.56 // Deinitialize everything
1023     ExitAll();
1024 gbeauche 1.24
1025 gbeauche 1.15 // Delete SheepShaver globals
1026     SheepMem::Exit();
1027    
1028 cebix 1.1 // Delete RAM area
1029     if (ram_area_mapped)
1030 gbeauche 1.53 vm_mac_release(RAM_BASE, RAMSize);
1031 cebix 1.1
1032     // Delete ROM area
1033     if (rom_area_mapped)
1034 gbeauche 1.53 vm_mac_release(ROM_BASE, ROM_AREA_SIZE);
1035 cebix 1.1
1036 gbeauche 1.36 // Delete DR cache areas
1037     if (dr_emulator_area_mapped)
1038 gbeauche 1.53 vm_mac_release(DR_EMULATOR_BASE, DR_EMULATOR_SIZE);
1039 gbeauche 1.36 if (dr_cache_area_mapped)
1040 gbeauche 1.53 vm_mac_release(DR_CACHE_BASE, DR_CACHE_SIZE);
1041 gbeauche 1.36
1042 cebix 1.1 // Delete Kernel Data area
1043 gbeauche 1.53 kernel_data_exit();
1044 cebix 1.1
1045     // Delete Low Memory area
1046     if (lm_area_mapped)
1047 gbeauche 1.53 vm_mac_release(0, 0x3000);
1048 cebix 1.1
1049     // Close /dev/zero
1050     if (zero_fd > 0)
1051     close(zero_fd);
1052    
1053     // Exit system routines
1054     SysExit();
1055    
1056     // Exit preferences
1057     PrefsExit();
1058    
1059     #ifdef ENABLE_MON
1060     // Exit mon
1061     mon_exit();
1062     #endif
1063    
1064     // Close X11 server connection
1065 gbeauche 1.42 #ifndef USE_SDL_VIDEO
1066 cebix 1.1 if (x_display)
1067     XCloseDisplay(x_display);
1068 gbeauche 1.42 #endif
1069 cebix 1.1
1070     exit(0);
1071     }
1072    
1073    
1074     /*
1075 gbeauche 1.53 * Initialize Kernel Data segments
1076     */
1077    
1078     #if defined(__CYGWIN__)
1079     #define WIN32_LEAN_AND_MEAN
1080     #include <windows.h>
1081    
1082     static HANDLE kernel_handle; // Shared memory handle for Kernel Data
1083     static DWORD allocation_granule; // Minimum size of allocateable are (64K)
1084     static DWORD kernel_area_size; // Size of Kernel Data area
1085     #endif
1086    
1087     static bool kernel_data_init(void)
1088     {
1089 gbeauche 1.54 char str[256];
1090 gbeauche 1.53 #ifdef _WIN32
1091     SYSTEM_INFO si;
1092     GetSystemInfo(&si);
1093     allocation_granule = si.dwAllocationGranularity;
1094     kernel_area_size = (KERNEL_AREA_SIZE + allocation_granule - 1) & -allocation_granule;
1095    
1096     char rcs[10];
1097     LPVOID kernel_addr;
1098     kernel_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, kernel_area_size, NULL);
1099     if (kernel_handle == NULL) {
1100     sprintf(rcs, "%d", GetLastError());
1101     sprintf(str, GetString(STR_KD_SHMGET_ERR), rcs);
1102     ErrorAlert(str);
1103     return false;
1104     }
1105     kernel_addr = (LPVOID)Mac2HostAddr(KERNEL_DATA_BASE & -allocation_granule);
1106     if (MapViewOfFileEx(kernel_handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kernel_area_size, kernel_addr) != kernel_addr) {
1107     sprintf(rcs, "%d", GetLastError());
1108     sprintf(str, GetString(STR_KD_SHMAT_ERR), rcs);
1109     ErrorAlert(str);
1110     return false;
1111     }
1112     kernel_addr = (LPVOID)Mac2HostAddr(KERNEL_DATA2_BASE & -allocation_granule);
1113     if (MapViewOfFileEx(kernel_handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kernel_area_size, kernel_addr) != kernel_addr) {
1114     sprintf(rcs, "%d", GetLastError());
1115     sprintf(str, GetString(STR_KD2_SHMAT_ERR), rcs);
1116     ErrorAlert(str);
1117     return false;
1118     }
1119     #else
1120     kernel_area = shmget(IPC_PRIVATE, KERNEL_AREA_SIZE, 0600);
1121     if (kernel_area == -1) {
1122     sprintf(str, GetString(STR_KD_SHMGET_ERR), strerror(errno));
1123     ErrorAlert(str);
1124     return false;
1125     }
1126     if (shmat(kernel_area, Mac2HostAddr(KERNEL_DATA_BASE), 0) < 0) {
1127     sprintf(str, GetString(STR_KD_SHMAT_ERR), strerror(errno));
1128     ErrorAlert(str);
1129     return false;
1130     }
1131     if (shmat(kernel_area, Mac2HostAddr(KERNEL_DATA2_BASE), 0) < 0) {
1132     sprintf(str, GetString(STR_KD2_SHMAT_ERR), strerror(errno));
1133     ErrorAlert(str);
1134     return false;
1135     }
1136     #endif
1137     return true;
1138     }
1139    
1140    
1141     /*
1142     * Deallocate Kernel Data segments
1143     */
1144    
1145     static void kernel_data_exit(void)
1146     {
1147     #ifdef _WIN32
1148     if (kernel_handle) {
1149     UnmapViewOfFile(Mac2HostAddr(KERNEL_DATA_BASE & -allocation_granule));
1150     UnmapViewOfFile(Mac2HostAddr(KERNEL_DATA2_BASE & -allocation_granule));
1151     CloseHandle(kernel_handle);
1152     }
1153     #else
1154     if (kernel_area >= 0) {
1155     shmdt(Mac2HostAddr(KERNEL_DATA_BASE));
1156     shmdt(Mac2HostAddr(KERNEL_DATA2_BASE));
1157     shmctl(kernel_area, IPC_RMID, NULL);
1158     }
1159     #endif
1160     }
1161    
1162    
1163     /*
1164 cebix 1.1 * Jump into Mac ROM, start 680x0 emulator
1165     */
1166    
1167     #if EMULATED_PPC
1168     void jump_to_rom(uint32 entry)
1169     {
1170     init_emul_ppc();
1171     emul_ppc(entry);
1172     }
1173     #endif
1174    
1175    
1176     /*
1177     * Emulator thread function
1178     */
1179    
1180     static void *emul_func(void *arg)
1181     {
1182     // We're now ready to receive signals
1183     ready_for_signals = true;
1184    
1185     // Decrease priority, so more time-critical things like audio will work better
1186     nice(1);
1187    
1188     // Jump to ROM boot routine
1189     D(bug("Jumping to ROM\n"));
1190     #if EMULATED_PPC
1191     jump_to_rom(ROM_BASE + 0x310000);
1192     #else
1193     jump_to_rom(ROM_BASE + 0x310000, (uint32)emulator_data);
1194     #endif
1195     D(bug("Returned from ROM\n"));
1196    
1197     // We're no longer ready to receive signals
1198     ready_for_signals = false;
1199     return NULL;
1200     }
1201    
1202    
1203     #if !EMULATED_PPC
1204     /*
1205     * Execute 68k subroutine (must be ended with RTS)
1206     * This must only be called by the emul_thread when in EMUL_OP mode
1207     * r->a[7] is unused, the routine runs on the caller's stack
1208     */
1209    
1210     void Execute68k(uint32 pc, M68kRegisters *r)
1211     {
1212     #if SAFE_EXEC_68K
1213     if (ReadMacInt32(XLM_RUN_MODE) != MODE_EMUL_OP)
1214     printf("FATAL: Execute68k() not called from EMUL_OP mode\n");
1215     if (!pthread_equal(pthread_self(), emul_thread))
1216     printf("FATAL: Execute68k() not called from emul_thread\n");
1217     #endif
1218     execute_68k(pc, r);
1219     }
1220    
1221    
1222     /*
1223     * Execute 68k A-Trap from EMUL_OP routine
1224     * r->a[7] is unused, the routine runs on the caller's stack
1225     */
1226    
1227     void Execute68kTrap(uint16 trap, M68kRegisters *r)
1228     {
1229     uint16 proc[2] = {trap, M68K_RTS};
1230     Execute68k((uint32)proc, r);
1231     }
1232 gbeauche 1.7 #endif
1233 cebix 1.1
1234    
1235     /*
1236     * Quit emulator (cause return from jump_to_rom)
1237     */
1238    
1239     void QuitEmulator(void)
1240     {
1241     #if EMULATED_PPC
1242     Quit();
1243     #else
1244     quit_emulator();
1245     #endif
1246     }
1247    
1248    
1249     /*
1250     * Dump 68k registers
1251     */
1252    
1253     void Dump68kRegs(M68kRegisters *r)
1254     {
1255     // Display 68k registers
1256     for (int i=0; i<8; i++) {
1257     printf("d%d: %08x", i, r->d[i]);
1258     if (i == 3 || i == 7)
1259     printf("\n");
1260     else
1261     printf(", ");
1262     }
1263     for (int i=0; i<8; i++) {
1264     printf("a%d: %08x", i, r->a[i]);
1265     if (i == 3 || i == 7)
1266     printf("\n");
1267     else
1268     printf(", ");
1269     }
1270     }
1271    
1272    
1273     /*
1274     * Make code executable
1275     */
1276    
1277 gbeauche 1.52 void MakeExecutable(int dummy, uint32 start, uint32 length)
1278 cebix 1.1 {
1279 gbeauche 1.52 if ((start >= ROM_BASE) && (start < (ROM_BASE + ROM_SIZE)))
1280 cebix 1.1 return;
1281 gbeauche 1.9 #if EMULATED_PPC
1282 gbeauche 1.52 FlushCodeCache(start, start + length);
1283 gbeauche 1.9 #else
1284 gbeauche 1.57 flush_icache_range(start, start + length);
1285 cebix 1.1 #endif
1286     }
1287    
1288    
1289     /*
1290     * NVRAM watchdog thread (saves NVRAM every minute)
1291     */
1292    
1293 gbeauche 1.40 static void nvram_watchdog(void)
1294     {
1295     if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
1296     memcpy(last_xpram, XPRAM, XPRAM_SIZE);
1297     SaveXPRAM();
1298     }
1299     }
1300    
1301 cebix 1.1 static void *nvram_func(void *arg)
1302     {
1303 gbeauche 1.40 while (!nvram_thread_cancel) {
1304     for (int i=0; i<60 && !nvram_thread_cancel; i++)
1305     Delay_usec(999999); // Only wait 1 second so we quit promptly when nvram_thread_cancel becomes true
1306     nvram_watchdog();
1307 cebix 1.1 }
1308     return NULL;
1309     }
1310    
1311    
1312     /*
1313     * 60Hz thread (really 60.15Hz)
1314     */
1315    
1316     static void *tick_func(void *arg)
1317     {
1318     int tick_counter = 0;
1319 gbeauche 1.40 uint64 start = GetTicks_usec();
1320     int64 ticks = 0;
1321     uint64 next = GetTicks_usec();
1322 cebix 1.1
1323 gbeauche 1.40 while (!tick_thread_cancel) {
1324 cebix 1.1
1325     // Wait
1326 gbeauche 1.40 next += 16625;
1327     int64 delay = next - GetTicks_usec();
1328     if (delay > 0)
1329     Delay_usec(delay);
1330     else if (delay < -16625)
1331     next = GetTicks_usec();
1332     ticks++;
1333 cebix 1.1
1334     #if !EMULATED_PPC
1335     // Did we crash?
1336     if (emul_thread_fatal) {
1337    
1338     // Yes, dump registers
1339 gbeauche 1.26 sigregs *r = &sigsegv_regs;
1340 cebix 1.1 char str[256];
1341 gbeauche 1.23 if (crash_reason == NULL)
1342     crash_reason = "SIGSEGV";
1343     sprintf(str, "%s\n"
1344 cebix 1.1 " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
1345     " xer %08lx cr %08lx \n"
1346     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
1347     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
1348     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
1349     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
1350     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
1351     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
1352     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
1353     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
1354 gbeauche 1.23 crash_reason,
1355 cebix 1.1 r->nip, r->link, r->ctr, r->msr,
1356     r->xer, r->ccr,
1357     r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3],
1358     r->gpr[4], r->gpr[5], r->gpr[6], r->gpr[7],
1359     r->gpr[8], r->gpr[9], r->gpr[10], r->gpr[11],
1360     r->gpr[12], r->gpr[13], r->gpr[14], r->gpr[15],
1361     r->gpr[16], r->gpr[17], r->gpr[18], r->gpr[19],
1362     r->gpr[20], r->gpr[21], r->gpr[22], r->gpr[23],
1363     r->gpr[24], r->gpr[25], r->gpr[26], r->gpr[27],
1364     r->gpr[28], r->gpr[29], r->gpr[30], r->gpr[31]);
1365     printf(str);
1366     VideoQuitFullScreen();
1367    
1368     #ifdef ENABLE_MON
1369     // Start up mon in real-mode
1370     printf("Welcome to the sheep factory.\n");
1371     char *arg[4] = {"mon", "-m", "-r", NULL};
1372     mon(3, arg);
1373     #endif
1374     return NULL;
1375     }
1376     #endif
1377    
1378     // Pseudo Mac 1Hz interrupt, update local time
1379     if (++tick_counter > 60) {
1380     tick_counter = 0;
1381     WriteMacInt32(0x20c, TimerDateTime());
1382     }
1383    
1384     // Trigger 60Hz interrupt
1385     if (ReadMacInt32(XLM_IRQ_NEST) == 0) {
1386     SetInterruptFlag(INTFLAG_VIA);
1387     TriggerInterrupt();
1388     }
1389     }
1390 gbeauche 1.40
1391     uint64 end = GetTicks_usec();
1392     D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
1393 cebix 1.1 return NULL;
1394     }
1395    
1396    
1397     /*
1398 cebix 1.2 * Pthread configuration
1399     */
1400    
1401     void Set_pthread_attr(pthread_attr_t *attr, int priority)
1402     {
1403 gbeauche 1.14 #ifdef HAVE_PTHREADS
1404     pthread_attr_init(attr);
1405     #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
1406     // Some of these only work for superuser
1407     if (geteuid() == 0) {
1408     pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
1409     pthread_attr_setschedpolicy(attr, SCHED_FIFO);
1410     struct sched_param fifo_param;
1411     fifo_param.sched_priority = ((sched_get_priority_min(SCHED_FIFO) +
1412     sched_get_priority_max(SCHED_FIFO)) / 2 +
1413     priority);
1414     pthread_attr_setschedparam(attr, &fifo_param);
1415     }
1416     if (pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM) != 0) {
1417     #ifdef PTHREAD_SCOPE_BOUND_NP
1418     // If system scope is not available (eg. we're not running
1419     // with CAP_SCHED_MGT capability on an SGI box), try bound
1420     // scope. It exposes pthread scheduling to the kernel,
1421     // without setting realtime priority.
1422     pthread_attr_setscope(attr, PTHREAD_SCOPE_BOUND_NP);
1423     #endif
1424     }
1425     #endif
1426     #endif
1427 cebix 1.2 }
1428    
1429    
1430     /*
1431 cebix 1.1 * Mutexes
1432     */
1433    
1434 gbeauche 1.7 #ifdef HAVE_PTHREADS
1435    
1436     struct B2_mutex {
1437     B2_mutex() {
1438     pthread_mutexattr_t attr;
1439     pthread_mutexattr_init(&attr);
1440     // Initialize the mutex for priority inheritance --
1441     // required for accurate timing.
1442 gbeauche 1.53 #if defined(HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL) && !defined(__CYGWIN__)
1443 gbeauche 1.7 pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
1444     #endif
1445     #if defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE) && defined(PTHREAD_MUTEX_NORMAL)
1446     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
1447     #endif
1448     #ifdef HAVE_PTHREAD_MUTEXATTR_SETPSHARED
1449     pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
1450     #endif
1451     pthread_mutex_init(&m, &attr);
1452     pthread_mutexattr_destroy(&attr);
1453     }
1454     ~B2_mutex() {
1455     pthread_mutex_trylock(&m); // Make sure it's locked before
1456     pthread_mutex_unlock(&m); // unlocking it.
1457     pthread_mutex_destroy(&m);
1458     }
1459     pthread_mutex_t m;
1460     };
1461    
1462     B2_mutex *B2_create_mutex(void)
1463     {
1464     return new B2_mutex;
1465     }
1466    
1467     void B2_lock_mutex(B2_mutex *mutex)
1468     {
1469     pthread_mutex_lock(&mutex->m);
1470     }
1471    
1472     void B2_unlock_mutex(B2_mutex *mutex)
1473     {
1474     pthread_mutex_unlock(&mutex->m);
1475     }
1476    
1477     void B2_delete_mutex(B2_mutex *mutex)
1478     {
1479     delete mutex;
1480     }
1481    
1482     #else
1483    
1484 cebix 1.1 struct B2_mutex {
1485     int dummy;
1486     };
1487    
1488     B2_mutex *B2_create_mutex(void)
1489     {
1490     return new B2_mutex;
1491     }
1492    
1493     void B2_lock_mutex(B2_mutex *mutex)
1494     {
1495     }
1496    
1497     void B2_unlock_mutex(B2_mutex *mutex)
1498     {
1499     }
1500    
1501     void B2_delete_mutex(B2_mutex *mutex)
1502     {
1503     delete mutex;
1504     }
1505    
1506 gbeauche 1.7 #endif
1507    
1508 cebix 1.1
1509     /*
1510     * Trigger signal USR2 from another thread
1511     */
1512    
1513 gbeauche 1.35 #if !EMULATED_PPC
1514 cebix 1.1 void TriggerInterrupt(void)
1515     {
1516     if (ready_for_signals)
1517     pthread_kill(emul_thread, SIGUSR2);
1518     }
1519 gbeauche 1.7 #endif
1520 cebix 1.1
1521    
1522     /*
1523     * Interrupt flags (must be handled atomically!)
1524     */
1525    
1526     volatile uint32 InterruptFlags = 0;
1527    
1528     void SetInterruptFlag(uint32 flag)
1529     {
1530     atomic_or((int *)&InterruptFlags, flag);
1531     }
1532    
1533     void ClearInterruptFlag(uint32 flag)
1534     {
1535     atomic_and((int *)&InterruptFlags, ~flag);
1536     }
1537    
1538    
1539     /*
1540     * Disable interrupts
1541     */
1542    
1543     void DisableInterrupt(void)
1544     {
1545 gbeauche 1.41 #if EMULATED_PPC
1546     WriteMacInt32(XLM_IRQ_NEST, int32(ReadMacInt32(XLM_IRQ_NEST)) + 1);
1547     #else
1548 gbeauche 1.7 atomic_add((int *)XLM_IRQ_NEST, 1);
1549 gbeauche 1.41 #endif
1550 cebix 1.1 }
1551    
1552    
1553     /*
1554     * Enable interrupts
1555     */
1556    
1557     void EnableInterrupt(void)
1558     {
1559 gbeauche 1.41 #if EMULATED_PPC
1560     WriteMacInt32(XLM_IRQ_NEST, int32(ReadMacInt32(XLM_IRQ_NEST)) - 1);
1561     #else
1562 gbeauche 1.7 atomic_add((int *)XLM_IRQ_NEST, -1);
1563 gbeauche 1.41 #endif
1564 cebix 1.1 }
1565    
1566    
1567     /*
1568     * USR2 handler
1569     */
1570    
1571 gbeauche 1.35 #if !EMULATED_PPC
1572 gbeauche 1.65 void sigusr2_handler(int sig, siginfo_t *sip, void *scp)
1573 cebix 1.1 {
1574 gbeauche 1.26 machine_regs *r = MACHINE_REGISTERS(scp);
1575 cebix 1.1
1576 gbeauche 1.42 #ifdef USE_SDL_VIDEO
1577     // We must fill in the events queue in the same thread that did call SDL_SetVideoMode()
1578     SDL_PumpEvents();
1579     #endif
1580    
1581 cebix 1.1 // Do nothing if interrupts are disabled
1582     if (*(int32 *)XLM_IRQ_NEST > 0)
1583     return;
1584    
1585 gbeauche 1.60 #ifdef SYSTEM_CLOBBERS_R2
1586     // Restore pointer to Thread Local Storage
1587     set_r2(TOC);
1588     #endif
1589     #ifdef SYSTEM_CLOBBERS_R13
1590     // Restore pointer to .sdata section
1591     set_r13(R13);
1592     #endif
1593    
1594 cebix 1.1 // Disable MacOS stack sniffer
1595     WriteMacInt32(0x110, 0);
1596    
1597     // Interrupt action depends on current run mode
1598     switch (ReadMacInt32(XLM_RUN_MODE)) {
1599     case MODE_68K:
1600     // 68k emulator active, trigger 68k interrupt level 1
1601     WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1);
1602 gbeauche 1.26 r->cr() |= ntohl(kernel_data->v[0x674 >> 2]);
1603 cebix 1.1 break;
1604    
1605     #if INTERRUPTS_IN_NATIVE_MODE
1606     case MODE_NATIVE:
1607     // 68k emulator inactive, in nanokernel?
1608 gbeauche 1.26 if (r->gpr(1) != KernelDataAddr) {
1609 gbeauche 1.33
1610 gbeauche 1.65 // Set extra stack for SIGSEGV handler
1611     sigaltstack(&extra_stack, NULL);
1612 gbeauche 1.33
1613 cebix 1.1 // Prepare for 68k interrupt level 1
1614     WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1);
1615     WriteMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc, ReadMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc) | ntohl(kernel_data->v[0x674 >> 2]));
1616    
1617     // Execute nanokernel interrupt routine (this will activate the 68k emulator)
1618 gbeauche 1.33 DisableInterrupt();
1619 cebix 1.1 if (ROMType == ROMTYPE_NEWWORLD)
1620     ppc_interrupt(ROM_BASE + 0x312b1c, KernelDataAddr);
1621     else
1622     ppc_interrupt(ROM_BASE + 0x312a3c, KernelDataAddr);
1623 gbeauche 1.33
1624 gbeauche 1.65 // Reset normal stack
1625     sigaltstack(&sig_stack, NULL);
1626 cebix 1.1 }
1627     break;
1628     #endif
1629    
1630     #if INTERRUPTS_IN_EMUL_OP_MODE
1631     case MODE_EMUL_OP:
1632     // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
1633     if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) {
1634    
1635     // Set extra stack for SIGSEGV handler
1636 gbeauche 1.65 sigaltstack(&extra_stack, NULL);
1637 cebix 1.1 #if 1
1638     // Execute full 68k interrupt routine
1639     M68kRegisters r;
1640     uint32 old_r25 = ReadMacInt32(XLM_68K_R25); // Save interrupt level
1641     WriteMacInt32(XLM_68K_R25, 0x21); // Execute with interrupt level 1
1642     static const uint16 proc[] = {
1643     0x3f3c, 0x0000, // move.w #$0000,-(sp) (fake format word)
1644     0x487a, 0x000a, // pea @1(pc) (return address)
1645     0x40e7, // move sr,-(sp) (saved SR)
1646     0x2078, 0x0064, // move.l $64,a0
1647     0x4ed0, // jmp (a0)
1648     M68K_RTS // @1
1649     };
1650     Execute68k((uint32)proc, &r);
1651     WriteMacInt32(XLM_68K_R25, old_r25); // Restore interrupt level
1652     #else
1653     // Only update cursor
1654     if (HasMacStarted()) {
1655     if (InterruptFlags & INTFLAG_VIA) {
1656     ClearInterruptFlag(INTFLAG_VIA);
1657     ADBInterrupt();
1658 gbeauche 1.17 ExecuteNative(NATIVE_VIDEO_VBL);
1659 cebix 1.1 }
1660     }
1661     #endif
1662 gbeauche 1.65 // Reset normal stack
1663     sigaltstack(&sig_stack, NULL);
1664 cebix 1.1 }
1665     break;
1666     #endif
1667     }
1668     }
1669 gbeauche 1.8 #endif
1670 cebix 1.1
1671    
1672     /*
1673     * SIGSEGV handler
1674     */
1675    
1676 gbeauche 1.8 #if !EMULATED_PPC
1677 gbeauche 1.26 static void sigsegv_handler(int sig, siginfo_t *sip, void *scp)
1678 cebix 1.1 {
1679 gbeauche 1.26 machine_regs *r = MACHINE_REGISTERS(scp);
1680 gbeauche 1.5
1681     // Get effective address
1682 gbeauche 1.26 uint32 addr = r->dar();
1683 gbeauche 1.5
1684 gbeauche 1.60 #ifdef SYSTEM_CLOBBERS_R2
1685     // Restore pointer to Thread Local Storage
1686     set_r2(TOC);
1687     #endif
1688     #ifdef SYSTEM_CLOBBERS_R13
1689     // Restore pointer to .sdata section
1690     set_r13(R13);
1691     #endif
1692    
1693 gbeauche 1.5 #if ENABLE_VOSF
1694     // Handle screen fault.
1695     extern bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction);
1696 gbeauche 1.26 if (Screen_fault_handler((sigsegv_address_t)addr, (sigsegv_address_t)r->pc()))
1697 gbeauche 1.5 return;
1698     #endif
1699    
1700 cebix 1.1 num_segv++;
1701    
1702 gbeauche 1.37 // Fault in Mac ROM or RAM or DR Cache?
1703     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));
1704 cebix 1.1 if (mac_fault) {
1705    
1706     // "VM settings" during MacOS 8 installation
1707 gbeauche 1.26 if (r->pc() == ROM_BASE + 0x488160 && r->gpr(20) == 0xf8000000) {
1708     r->pc() += 4;
1709     r->gpr(8) = 0;
1710 cebix 1.1 return;
1711    
1712     // MacOS 8.5 installation
1713 gbeauche 1.26 } else if (r->pc() == ROM_BASE + 0x488140 && r->gpr(16) == 0xf8000000) {
1714     r->pc() += 4;
1715     r->gpr(8) = 0;
1716 cebix 1.1 return;
1717    
1718     // MacOS 8 serial drivers on startup
1719 gbeauche 1.26 } else if (r->pc() == ROM_BASE + 0x48e080 && (r->gpr(8) == 0xf3012002 || r->gpr(8) == 0xf3012000)) {
1720     r->pc() += 4;
1721     r->gpr(8) = 0;
1722 cebix 1.1 return;
1723    
1724     // MacOS 8.1 serial drivers on startup
1725 gbeauche 1.26 } else if (r->pc() == ROM_BASE + 0x48c5e0 && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) {
1726     r->pc() += 4;
1727 cebix 1.1 return;
1728 gbeauche 1.26 } else if (r->pc() == ROM_BASE + 0x4a10a0 && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) {
1729     r->pc() += 4;
1730 cebix 1.1 return;
1731 gbeauche 1.37
1732     // MacOS 8.6 serial drivers on startup (with DR Cache and OldWorld ROM)
1733     } else if ((r->pc() - DR_CACHE_BASE) < DR_CACHE_SIZE && (r->gpr(16) == 0xf3012002 || r->gpr(16) == 0xf3012000)) {
1734     r->pc() += 4;
1735     return;
1736     } else if ((r->pc() - DR_CACHE_BASE) < DR_CACHE_SIZE && (r->gpr(20) == 0xf3012002 || r->gpr(20) == 0xf3012000)) {
1737     r->pc() += 4;
1738     return;
1739 cebix 1.1 }
1740    
1741 gbeauche 1.5 // Get opcode and divide into fields
1742 gbeauche 1.26 uint32 opcode = *((uint32 *)r->pc());
1743 gbeauche 1.5 uint32 primop = opcode >> 26;
1744     uint32 exop = (opcode >> 1) & 0x3ff;
1745     uint32 ra = (opcode >> 16) & 0x1f;
1746     uint32 rb = (opcode >> 11) & 0x1f;
1747     uint32 rd = (opcode >> 21) & 0x1f;
1748     int32 imm = (int16)(opcode & 0xffff);
1749    
1750 cebix 1.1 // Analyze opcode
1751     enum {
1752     TYPE_UNKNOWN,
1753     TYPE_LOAD,
1754     TYPE_STORE
1755     } transfer_type = TYPE_UNKNOWN;
1756     enum {
1757     SIZE_UNKNOWN,
1758     SIZE_BYTE,
1759     SIZE_HALFWORD,
1760     SIZE_WORD
1761     } transfer_size = SIZE_UNKNOWN;
1762     enum {
1763     MODE_UNKNOWN,
1764     MODE_NORM,
1765     MODE_U,
1766     MODE_X,
1767     MODE_UX
1768     } addr_mode = MODE_UNKNOWN;
1769     switch (primop) {
1770     case 31:
1771     switch (exop) {
1772     case 23: // lwzx
1773     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1774     case 55: // lwzux
1775     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1776     case 87: // lbzx
1777     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1778     case 119: // lbzux
1779     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1780     case 151: // stwx
1781     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1782     case 183: // stwux
1783     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1784     case 215: // stbx
1785     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1786     case 247: // stbux
1787     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1788     case 279: // lhzx
1789     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1790     case 311: // lhzux
1791     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1792     case 343: // lhax
1793     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1794     case 375: // lhaux
1795     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1796     case 407: // sthx
1797     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1798     case 439: // sthux
1799     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1800     }
1801     break;
1802    
1803     case 32: // lwz
1804     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1805     case 33: // lwzu
1806     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1807     case 34: // lbz
1808     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1809     case 35: // lbzu
1810     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1811     case 36: // stw
1812     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1813     case 37: // stwu
1814     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1815     case 38: // stb
1816     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1817     case 39: // stbu
1818     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1819     case 40: // lhz
1820     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1821     case 41: // lhzu
1822     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1823     case 42: // lha
1824     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1825     case 43: // lhau
1826     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1827     case 44: // sth
1828     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1829     case 45: // sthu
1830     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1831 gbeauche 1.23 #if EMULATE_UNALIGNED_LOADSTORE_MULTIPLE
1832     case 46: // lmw
1833 gbeauche 1.27 if ((addr % 4) != 0) {
1834     uint32 ea = addr;
1835 gbeauche 1.26 D(bug("WARNING: unaligned lmw to EA=%08x from IP=%08x\n", ea, r->pc()));
1836 gbeauche 1.23 for (int i = rd; i <= 31; i++) {
1837 gbeauche 1.26 r->gpr(i) = ReadMacInt32(ea);
1838 gbeauche 1.23 ea += 4;
1839     }
1840 gbeauche 1.26 r->pc() += 4;
1841 gbeauche 1.23 goto rti;
1842     }
1843     break;
1844     case 47: // stmw
1845 gbeauche 1.27 if ((addr % 4) != 0) {
1846     uint32 ea = addr;
1847 gbeauche 1.26 D(bug("WARNING: unaligned stmw to EA=%08x from IP=%08x\n", ea, r->pc()));
1848 gbeauche 1.23 for (int i = rd; i <= 31; i++) {
1849 gbeauche 1.26 WriteMacInt32(ea, r->gpr(i));
1850 gbeauche 1.23 ea += 4;
1851     }
1852 gbeauche 1.26 r->pc() += 4;
1853 gbeauche 1.23 goto rti;
1854     }
1855     break;
1856     #endif
1857 cebix 1.1 }
1858    
1859 gbeauche 1.31 // Ignore ROM writes (including to the zero page, which is read-only)
1860     if (transfer_type == TYPE_STORE &&
1861     ((addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) ||
1862     (addr >= SheepMem::ZeroPage() && addr < SheepMem::ZeroPage() + SheepMem::PageSize()))) {
1863 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()));
1864 cebix 1.1 if (addr_mode == MODE_U || addr_mode == MODE_UX)
1865 gbeauche 1.26 r->gpr(ra) = addr;
1866     r->pc() += 4;
1867 cebix 1.1 goto rti;
1868     }
1869    
1870     // Ignore illegal memory accesses?
1871     if (PrefsFindBool("ignoresegv")) {
1872     if (addr_mode == MODE_U || addr_mode == MODE_UX)
1873 gbeauche 1.26 r->gpr(ra) = addr;
1874 cebix 1.1 if (transfer_type == TYPE_LOAD)
1875 gbeauche 1.26 r->gpr(rd) = 0;
1876     r->pc() += 4;
1877 cebix 1.1 goto rti;
1878     }
1879    
1880     // In GUI mode, show error alert
1881     if (!PrefsFindBool("nogui")) {
1882     char str[256];
1883     if (transfer_type == TYPE_LOAD || transfer_type == TYPE_STORE)
1884 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));
1885 cebix 1.1 else
1886 gbeauche 1.26 sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc(), r->gpr(24), r->gpr(1), opcode);
1887 cebix 1.1 ErrorAlert(str);
1888     QuitEmulator();
1889     return;
1890     }
1891     }
1892    
1893     // For all other errors, jump into debugger (sort of...)
1894 gbeauche 1.23 crash_reason = (sig == SIGBUS) ? "SIGBUS" : "SIGSEGV";
1895 cebix 1.1 if (!ready_for_signals) {
1896 gbeauche 1.23 printf("%s\n");
1897 gbeauche 1.26 printf(" sigcontext %p, machine_regs %p\n", scp, r);
1898 cebix 1.1 printf(
1899     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
1900     " xer %08lx cr %08lx \n"
1901     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
1902     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
1903     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
1904     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
1905     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
1906     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
1907     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
1908     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
1909 gbeauche 1.23 crash_reason,
1910 gbeauche 1.26 r->pc(), r->lr(), r->ctr(), r->msr(),
1911     r->xer(), r->cr(),
1912     r->gpr(0), r->gpr(1), r->gpr(2), r->gpr(3),
1913     r->gpr(4), r->gpr(5), r->gpr(6), r->gpr(7),
1914     r->gpr(8), r->gpr(9), r->gpr(10), r->gpr(11),
1915     r->gpr(12), r->gpr(13), r->gpr(14), r->gpr(15),
1916     r->gpr(16), r->gpr(17), r->gpr(18), r->gpr(19),
1917     r->gpr(20), r->gpr(21), r->gpr(22), r->gpr(23),
1918     r->gpr(24), r->gpr(25), r->gpr(26), r->gpr(27),
1919     r->gpr(28), r->gpr(29), r->gpr(30), r->gpr(31));
1920 cebix 1.1 exit(1);
1921     QuitEmulator();
1922     return;
1923     } else {
1924     // We crashed. Save registers, tell tick thread and loop forever
1925 gbeauche 1.26 build_sigregs(&sigsegv_regs, r);
1926 cebix 1.1 emul_thread_fatal = true;
1927     for (;;) ;
1928     }
1929     rti:;
1930     }
1931    
1932    
1933     /*
1934     * SIGILL handler
1935     */
1936    
1937 gbeauche 1.26 static void sigill_handler(int sig, siginfo_t *sip, void *scp)
1938 cebix 1.1 {
1939 gbeauche 1.26 machine_regs *r = MACHINE_REGISTERS(scp);
1940 cebix 1.1 char str[256];
1941    
1942 gbeauche 1.60 #ifdef SYSTEM_CLOBBERS_R2
1943     // Restore pointer to Thread Local Storage
1944     set_r2(TOC);
1945     #endif
1946     #ifdef SYSTEM_CLOBBERS_R13
1947     // Restore pointer to .sdata section
1948     set_r13(R13);
1949     #endif
1950    
1951 cebix 1.1 // Fault in Mac ROM or RAM?
1952 gbeauche 1.26 bool mac_fault = (r->pc() >= ROM_BASE) && (r->pc() < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc() >= RAMBase) && (r->pc() < (RAMBase + RAMSize));
1953 cebix 1.1 if (mac_fault) {
1954    
1955     // Get opcode and divide into fields
1956 gbeauche 1.26 uint32 opcode = *((uint32 *)r->pc());
1957 cebix 1.1 uint32 primop = opcode >> 26;
1958     uint32 exop = (opcode >> 1) & 0x3ff;
1959     uint32 ra = (opcode >> 16) & 0x1f;
1960     uint32 rb = (opcode >> 11) & 0x1f;
1961     uint32 rd = (opcode >> 21) & 0x1f;
1962     int32 imm = (int16)(opcode & 0xffff);
1963    
1964     switch (primop) {
1965     case 9: // POWER instructions
1966     case 22:
1967 gbeauche 1.26 power_inst: sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->pc(), r->gpr(1), opcode);
1968 cebix 1.1 ErrorAlert(str);
1969     QuitEmulator();
1970     return;
1971    
1972     case 31:
1973     switch (exop) {
1974     case 83: // mfmsr
1975 gbeauche 1.26 r->gpr(rd) = 0xf072;
1976     r->pc() += 4;
1977 cebix 1.1 goto rti;
1978    
1979     case 210: // mtsr
1980     case 242: // mtsrin
1981     case 306: // tlbie
1982 gbeauche 1.26 r->pc() += 4;
1983 cebix 1.1 goto rti;
1984    
1985     case 339: { // mfspr
1986     int spr = ra | (rb << 5);
1987     switch (spr) {
1988     case 0: // MQ
1989     case 22: // DEC
1990     case 952: // MMCR0
1991     case 953: // PMC1
1992     case 954: // PMC2
1993     case 955: // SIA
1994     case 956: // MMCR1
1995     case 957: // PMC3
1996     case 958: // PMC4
1997     case 959: // SDA
1998 gbeauche 1.26 r->pc() += 4;
1999 cebix 1.1 goto rti;
2000     case 25: // SDR1
2001 gbeauche 1.26 r->gpr(rd) = 0xdead001f;
2002     r->pc() += 4;
2003 cebix 1.1 goto rti;
2004     case 287: // PVR
2005 gbeauche 1.26 r->gpr(rd) = PVR;
2006     r->pc() += 4;
2007 cebix 1.1 goto rti;
2008     }
2009     break;
2010     }
2011    
2012     case 467: { // mtspr
2013     int spr = ra | (rb << 5);
2014     switch (spr) {
2015     case 0: // MQ
2016     case 22: // DEC
2017     case 275: // SPRG3
2018     case 528: // IBAT0U
2019     case 529: // IBAT0L
2020     case 530: // IBAT1U
2021     case 531: // IBAT1L
2022     case 532: // IBAT2U
2023     case 533: // IBAT2L
2024     case 534: // IBAT3U
2025     case 535: // IBAT3L
2026     case 536: // DBAT0U
2027     case 537: // DBAT0L
2028     case 538: // DBAT1U
2029     case 539: // DBAT1L
2030     case 540: // DBAT2U
2031     case 541: // DBAT2L
2032     case 542: // DBAT3U
2033     case 543: // DBAT3L
2034     case 952: // MMCR0
2035     case 953: // PMC1
2036     case 954: // PMC2
2037     case 955: // SIA
2038     case 956: // MMCR1
2039     case 957: // PMC3
2040     case 958: // PMC4
2041     case 959: // SDA
2042 gbeauche 1.26 r->pc() += 4;
2043 cebix 1.1 goto rti;
2044     }
2045     break;
2046     }
2047    
2048     case 29: case 107: case 152: case 153: // POWER instructions
2049     case 184: case 216: case 217: case 248:
2050     case 264: case 277: case 331: case 360:
2051     case 363: case 488: case 531: case 537:
2052     case 541: case 664: case 665: case 696:
2053     case 728: case 729: case 760: case 920:
2054     case 921: case 952:
2055     goto power_inst;
2056     }
2057     }
2058    
2059     // In GUI mode, show error alert
2060     if (!PrefsFindBool("nogui")) {
2061 gbeauche 1.26 sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc(), r->gpr(24), r->gpr(1), opcode);
2062 cebix 1.1 ErrorAlert(str);
2063     QuitEmulator();
2064     return;
2065     }
2066     }
2067    
2068     // For all other errors, jump into debugger (sort of...)
2069 gbeauche 1.23 crash_reason = "SIGILL";
2070 cebix 1.1 if (!ready_for_signals) {
2071 gbeauche 1.23 printf("%s\n");
2072 gbeauche 1.26 printf(" sigcontext %p, machine_regs %p\n", scp, r);
2073 cebix 1.1 printf(
2074     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
2075     " xer %08lx cr %08lx \n"
2076     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
2077     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
2078     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
2079     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
2080     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
2081     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
2082     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
2083     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
2084 gbeauche 1.23 crash_reason,
2085 gbeauche 1.26 r->pc(), r->lr(), r->ctr(), r->msr(),
2086     r->xer(), r->cr(),
2087     r->gpr(0), r->gpr(1), r->gpr(2), r->gpr(3),
2088     r->gpr(4), r->gpr(5), r->gpr(6), r->gpr(7),
2089     r->gpr(8), r->gpr(9), r->gpr(10), r->gpr(11),
2090     r->gpr(12), r->gpr(13), r->gpr(14), r->gpr(15),
2091     r->gpr(16), r->gpr(17), r->gpr(18), r->gpr(19),
2092     r->gpr(20), r->gpr(21), r->gpr(22), r->gpr(23),
2093     r->gpr(24), r->gpr(25), r->gpr(26), r->gpr(27),
2094     r->gpr(28), r->gpr(29), r->gpr(30), r->gpr(31));
2095 cebix 1.1 exit(1);
2096     QuitEmulator();
2097     return;
2098     } else {
2099     // We crashed. Save registers, tell tick thread and loop forever
2100 gbeauche 1.26 build_sigregs(&sigsegv_regs, r);
2101 cebix 1.1 emul_thread_fatal = true;
2102     for (;;) ;
2103     }
2104     rti:;
2105     }
2106     #endif
2107 gbeauche 1.15
2108    
2109     /*
2110     * Helpers to share 32-bit addressable data with MacOS
2111     */
2112    
2113     bool SheepMem::Init(void)
2114     {
2115 gbeauche 1.31 // Size of a native page
2116     page_size = getpagesize();
2117 gbeauche 1.20
2118     // Allocate SheepShaver globals
2119 gbeauche 1.53 proc = base;
2120     if (vm_mac_acquire(base, size) < 0)
2121 gbeauche 1.15 return false;
2122 gbeauche 1.18
2123 gbeauche 1.53 // Allocate page with all bits set to 0, right in the middle
2124     // This is also used to catch undesired overlaps between proc and data areas
2125     zero_page = proc + (size / 2);
2126     Mac_memset(zero_page, 0, page_size);
2127     if (vm_protect(Mac2HostAddr(zero_page), page_size, VM_PAGE_READ) < 0)
2128 gbeauche 1.18 return false;
2129    
2130 gbeauche 1.20 #if EMULATED_PPC
2131     // Allocate alternate stack for PowerPC interrupt routine
2132 gbeauche 1.53 sig_stack = base + size;
2133     if (vm_mac_acquire(sig_stack, SIG_STACK_SIZE) < 0)
2134 gbeauche 1.20 return false;
2135     #endif
2136    
2137 gbeauche 1.53 data = base + size;
2138 gbeauche 1.15 return true;
2139     }
2140    
2141     void SheepMem::Exit(void)
2142     {
2143 gbeauche 1.53 if (data) {
2144 gbeauche 1.20 // Delete SheepShaver globals
2145 gbeauche 1.53 vm_mac_release(base, size);
2146 gbeauche 1.20
2147     #if EMULATED_PPC
2148     // Delete alternate stack for PowerPC interrupt routine
2149 gbeauche 1.53 vm_mac_release(sig_stack, SIG_STACK_SIZE);
2150 gbeauche 1.20 #endif
2151 gbeauche 1.18 }
2152 gbeauche 1.15 }
2153 cebix 1.1
2154    
2155     /*
2156     * Display alert
2157     */
2158    
2159     #ifdef ENABLE_GTK
2160     static void dl_destroyed(void)
2161     {
2162     gtk_main_quit();
2163     }
2164    
2165     static void dl_quit(GtkWidget *dialog)
2166     {
2167     gtk_widget_destroy(dialog);
2168     }
2169    
2170     void display_alert(int title_id, int prefix_id, int button_id, const char *text)
2171     {
2172     char str[256];
2173     sprintf(str, GetString(prefix_id), text);
2174    
2175     GtkWidget *dialog = gtk_dialog_new();
2176     gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id));
2177     gtk_container_border_width(GTK_CONTAINER(dialog), 5);
2178     gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
2179     gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL);
2180    
2181     GtkWidget *label = gtk_label_new(str);
2182     gtk_widget_show(label);
2183     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
2184    
2185     GtkWidget *button = gtk_button_new_with_label(GetString(button_id));
2186     gtk_widget_show(button);
2187     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
2188     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
2189     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2190     gtk_widget_grab_default(button);
2191     gtk_widget_show(dialog);
2192    
2193     gtk_main();
2194     }
2195     #endif
2196    
2197    
2198     /*
2199     * Display error alert
2200     */
2201    
2202     void ErrorAlert(const char *text)
2203     {
2204 gbeauche 1.42 #if defined(ENABLE_GTK) && !defined(USE_SDL_VIDEO)
2205 cebix 1.1 if (PrefsFindBool("nogui") || x_display == NULL) {
2206     printf(GetString(STR_SHELL_ERROR_PREFIX), text);
2207     return;
2208     }
2209     VideoQuitFullScreen();
2210     display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text);
2211     #else
2212     printf(GetString(STR_SHELL_ERROR_PREFIX), text);
2213     #endif
2214     }
2215    
2216    
2217     /*
2218     * Display warning alert
2219     */
2220    
2221     void WarningAlert(const char *text)
2222     {
2223 gbeauche 1.42 #if defined(ENABLE_GTK) && !defined(USE_SDL_VIDEO)
2224 cebix 1.1 if (PrefsFindBool("nogui") || x_display == NULL) {
2225     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
2226     return;
2227     }
2228     display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text);
2229     #else
2230     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
2231     #endif
2232     }
2233    
2234    
2235     /*
2236     * Display choice alert
2237     */
2238    
2239     bool ChoiceAlert(const char *text, const char *pos, const char *neg)
2240     {
2241     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
2242     return false; //!!
2243     }