ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/main_unix.cpp
Revision: 1.30
Committed: 2004-02-15T17:20:36Z (20 years, 3 months ago) by gbeauche
Branch: MAIN
Changes since 1.29: +4 -2 lines
Log Message:
Now that we have AltiVec emulation, we can pretend for a G4 processor
Also make sure to actually fix PVR code for 7400

File Contents

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