ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/main_unix.cpp
Revision: 1.1.1.1 (vendor branch)
Committed: 2002-02-04T16:58:13Z (22 years, 3 months ago) by cebix
Branch: cebix
CVS Tags: start
Changes since 1.1: +0 -0 lines
Log Message:
Imported sources

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