ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/main_unix.cpp
Revision: 1.23
Committed: 2004-01-04T18:35:21Z (20 years, 5 months ago) by gbeauche
Branch: MAIN
Changes since 1.22: +48 -5 lines
Log Message:
Emulated lmw/stmw with unaligned EA. e.g. for BBEdit under MacOS 8.6.
This may be due to some switch mode that needs to save r13 and upwards.
The faultive code seems to explicitly add 0xee to r1, which causes it to
be unaligned for upcoming lmw/stmw.

File Contents

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