ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/main_unix.cpp
Revision: 1.86
Committed: 2009-08-18T18:26:10Z (15 years, 1 month ago) by asvitkine
Branch: MAIN
Changes since 1.85: +80 -47 lines
Log Message:
[Michael Schmitt]
Attached is a patch to SheepShaver to fix memory allocation problems when OS X 10.5 is the host. It also relaxes the 512 MB RAM limit on OS X hosts.


Problem
-------
Some users have been unable to run SheepShaver on OS X 10.5 (Leopard) hosts. The symptom is error "ERROR: Cannot map RAM: File already exists".

SheepShaver allocates RAM at fixed addresses. If it is running in "Real" addressing mode, and can't allocate at address 0, then it was hard-coded to allocate the RAM area at 0x20000000. The ROM area as allocated at 0x40800000.

The normal configuration is for SheepShaver to run under SDL, which is a Cocoa wrapper. By the time SheepShaver does its memory allocations, the Cocoa application has already started. The result is the SheepShaver memory address space already contains libraries, fonts, Input Managers, and IOKit areas.

On Leopard hosts these areas can land on the same addresses SheepShaver needs, so SheepShaver's memory allocation fails.


Solution
--------
The approach is to change SheepShaver (on Unix & OS X hosts) to allocate the RAM area anywhere it can find the space, rather than at a fixed address.

This could result in the RAM allocated higher than the ROM area, which causes a crash. To prevent this from occurring, the RAM and ROM areas are allocated contiguously.

Previously the ROM starting address was a constant ROM_BASE, which was used throughout the source files. The ROM start address is now a variable ROMBase. ROMBase is allocated and set by main_*.cpp just like RAMBase.

A side-effect of this change is that it lifts the 512 MB RAM limit for OS X hosts. The limit was because the fixed RAM and ROM addresses were such that the RAM could only be 512 MB before it overlapped the ROM area.


Impact
------
The change to make ROMBase a variable is throughout all hosts & addressing modes.

The RAM and ROM areas will only shift when run on Unix & OS X hosts, otherwise the same fixed allocation address is used as before.

This change is limited to "Real" addressing mode. Unlike Basilisk II, SheepShaver *pre-calculates* the offset for "Direct" addressing mode; the offset is compiled into the program. If the RAM address were allowed to shift, it could result in the RAM area wrapping around address 0.


Changes to main_unix.cpp
------------------------
1. Real addressing mode no longer defines a RAM_BASE constant.

2. The base address of the Mac ROM (ROMBase) is defined and exported by this program.

3. Memory management helper vm_mac_acquire is renamed to vm_mac_acquire_fixed. Added a new memory management helper vm_mac_acquire, which allocates memory at any address.

4. Changed and rearranged the allocation of RAM and ROM areas.

Before it worked like this:

  - Allocate ROM area
  - If can, attempt to allocate RAM at address zero
  - If RAM not allocated at 0, allocate at fixed address

We still want to try allocating the RAM at zero, and if using DIRECT addressing we're still going to use the fixed addresses. So we don't know where the ROM should be until after we do the RAM. The new logic is:

  - If can, attempt to allocate RAM at address zero
  - If RAM not allocated at 0
      if REAL addressing
         allocate RAM and ROM together. The ROM address is aligned to a 1 MB boundary
      else (direct addressing)
         allocate RAM at fixed address
  - If ROM hasn't been allocated yet, allocate at fixed address

5. Calculate ROMBase and ROMBaseHost based on where the ROM was loaded.

6. There is a crash if the RAM is allocated too high. To try and catch this, check if it was allocated higher than the kernel data address.

7. Change subsequent code from using constant ROM_BASE to variable ROMBase.


Changes to Other Programs
-------------------------
emul_op.cpp, main.cpp, name_registery.cpp, rom_patches.cpp, rsrc_patches.cpp, emul_ppc.cpp, sheepshaver_glue.cpp, ppc-translate-cpp:
Change from constant ROM_BASE to variable ROMBase.

ppc_asm.S: It was setting register to a hard-coded literal address: 0x40b0d000. Changed to set it to ROMBase + 0x30d000.

ppc_asm.tmpl: It defined a macro ASM_LO16 but it assumed that the macro would always be used with operands that included a register specification. This is not true. Moved the register specification from the macro to the macro invocations.

main_beos.cpp, main_windows.cpp: Since the subprograms are all expecting a variable ROMBase, all the main_*.cpp pgrams have to define and export it. The ROM_BASE constant is moved here for consistency. The mains for beos and windows just allocate the ROM at the same fixed address as before, set ROMBaseHost and ROMBase to that address, and then use ROMBase for the subsequent code.

cpu_emulation.h: removed ROM_BASE constant. This value is moved to the main_*.cpp modules, to be consistent with RAM_BASE.

user_strings_unix.cpp, user_strings_unix.h: Added new error messages related to errors that occur when the RAM and ROM are allocated anywhere.

File Contents

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