ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/main_unix.cpp
Revision: 1.11
Committed: 2003-10-26T07:54:02Z (20 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.10: +1 -1 lines
Log Message:
allow DGA & Xshm only on local displays

File Contents

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