ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.4
Committed: 2003-10-26T00:32:27Z (20 years, 7 months ago) by cebix
Branch: MAIN
Changes since 1.3: +4 -3 lines
Log Message:
- fixed compilation problems under BeOS
- boot drive wasn't set correctly

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * main_beos.cpp - Emulation core, BeOS 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     * SheepShaver uses three run-time environments, reflected by the value of XLM_RUN_MODE.
25     * The two modes which are also present in the original MacOS, are:
26     * MODE_68K - 68k emulator is active
27     * MODE_NATIVE - 68k emulator is inactive
28     * In the original MacOS, these two modes have different memory mappings and exception
29     * tables. Under SheepShaver, the only difference is the handling of interrupts (see below).
30     * SheepShaver extends the 68k emulator with special opcodes (EMUL_OP) to perform faster
31     * mode switches when patching 68k routines with PowerPC code and adds a third run mode:
32     * MODE_EMUL_OP - 68k emulator active, but native register usage
33     *
34     * Switches between MODE_68K and MODE_NATIVE are only done with the Mixed Mode Manager
35     * (via nanokernel patches). The switch from MODE_68K to MODE_EMUL_OP occurs when executin
36     * one of the EMUL_OP 68k opcodes. When the opcode routine is done, it returns to MODE_68K.
37     *
38     * The Execute68k() routine allows EMUL_OP routines to execute 68k subroutines. It switches
39     * from MODE_EMUL_OP back to MODE_68K, so it must not be used by native routines (executing
40     * in MODE_NATIVE) nor by any other thread than the emul_thread (because the 68k emulator
41     * is not reentrant). When the 68k subroutine returns, it switches back to MODE_EMUL_OP.
42     * It is OK for a 68k routine called with Execute68k() to contain an EMUL_OP opcode.
43     *
44     * The handling of interrupts depends on the current run mode:
45     * MODE_68K - The USR1 signal handler sets one bit in the processor's CR. The 68k emulator
46     * will then execute the 68k interrupt routine when fetching the next instruction.
47     * MODE_NATIVE - The USR1 signal handler switches back to the original stack (signals run
48     * on a separate signal stack) and enters the External Interrupt routine in the
49     * nanokernel.
50     * MODE_EMUL_OP - The USR1 signal handler directly executes the 68k interrupt routine
51     * with Execute68k(). Before doing this, it must first check the current 68k interrupt
52     * level which is stored in XLM_68K_R25. This variable is set to the current level
53     * when entering EMUL_OP mode. Execute68k() also uses it to restore the level so that
54     * Execute68k()'d routines will run at the same interrupt level as the EMUL_OP routine
55     * it was called from.
56     */
57    
58     #include <Path.h>
59     #include <unistd.h>
60     #include <signal.h>
61     #include <stdio.h>
62     #include <stdlib.h>
63     #include <string.h>
64     #include <time.h>
65    
66     #include "sysdeps.h"
67     #include "main.h"
68     #include "version.h"
69     #include "prefs.h"
70     #include "prefs_editor.h"
71     #include "cpu_emulation.h"
72     #include "emul_op.h"
73     #include "xlowmem.h"
74     #include "xpram.h"
75     #include "timer.h"
76     #include "adb.h"
77     #include "sony.h"
78     #include "disk.h"
79     #include "cdrom.h"
80     #include "scsi.h"
81     #include "video.h"
82     #include "audio.h"
83     #include "ether.h"
84     #include "serial.h"
85     #include "clip.h"
86     #include "extfs.h"
87     #include "sys.h"
88     #include "macos_util.h"
89     #include "rom_patches.h"
90     #include "user_strings.h"
91    
92     #include "sheep_driver.h"
93    
94     #define DEBUG 0
95     #include "debug.h"
96    
97     // Enable Execute68k() safety checks?
98     #define SAFE_EXEC_68K 0
99    
100     // Save FP regs in Execute68k()?
101     #define SAVE_FP_EXEC_68K 0
102    
103     // Interrupts in EMUL_OP mode?
104     #define INTERRUPTS_IN_EMUL_OP_MODE 1
105    
106     // Interrupts in native mode?
107     #define INTERRUPTS_IN_NATIVE_MODE 1
108    
109    
110     // Constants
111     const char APP_SIGNATURE[] = "application/x-vnd.cebix-SheepShaver";
112     const char ROM_FILE_NAME[] = "ROM";
113     const char ROM_FILE_NAME2[] = "Mac OS ROM";
114     const char KERNEL_AREA_NAME[] = "Macintosh Kernel Data";
115     const char KERNEL_AREA2_NAME[] = "Macintosh Kernel Data 2";
116     const char RAM_AREA_NAME[] = "Macintosh RAM";
117     const char ROM_AREA_NAME[] = "Macintosh ROM";
118     const char DR_CACHE_AREA_NAME[] = "Macintosh DR Cache";
119    
120     const uint32 SIG_STACK_SIZE = 8192; // Size of signal stack
121    
122     const uint32 MSG_START = 'strt'; // Emulator start message
123    
124    
125     // Application object
126     class SheepShaver : public BApplication {
127     public:
128     SheepShaver() : BApplication(APP_SIGNATURE)
129     {
130     // Find application directory and cwd to it
131     app_info the_info;
132     GetAppInfo(&the_info);
133     BEntry the_file(&the_info.ref);
134     BEntry the_dir;
135     the_file.GetParent(&the_dir);
136     BPath the_path;
137     the_dir.GetPath(&the_path);
138     chdir(the_path.Path());
139    
140     // Initialize other variables
141     sheep_fd = -1;
142     emulator_data = NULL;
143     kernel_area = kernel_area2 = rom_area = ram_area = dr_cache_area = -1;
144     emul_thread = nvram_thread = tick_thread = -1;
145     ReadyForSignals = false;
146     AllowQuitting = true;
147     NVRAMThreadActive = true;
148     TickThreadActive = true;
149     memset(last_xpram, 0, XPRAM_SIZE);
150     }
151     virtual void ReadyToRun(void);
152     virtual void MessageReceived(BMessage *msg);
153     void StartEmulator(void);
154     virtual bool QuitRequested(void);
155     virtual void Quit(void);
156    
157     thread_id emul_thread; // Emulator thread
158     thread_id nvram_thread; // NVRAM watchdog thread
159     thread_id tick_thread; // 60Hz thread
160    
161     KernelData *kernel_data; // Pointer to Kernel Data
162     EmulatorData *emulator_data;
163    
164     bool ReadyForSignals; // Flag: emul_thread ready to receive signals
165     bool AllowQuitting; // Flag: Alt-Q quitting allowed
166     bool NVRAMThreadActive; // nvram_thread will exit when this is false
167     bool TickThreadActive; // tick_thread will exit when this is false
168    
169     uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes
170    
171     private:
172     static status_t emul_func(void *arg);
173     static status_t nvram_func(void *arg);
174     static status_t tick_func(void *arg);
175     static void sigusr1_invoc(int sig, void *arg, vregs *r);
176     void sigusr1_handler(vregs *r);
177     static void sigsegv_invoc(int sig, void *arg, vregs *r);
178     static void sigill_invoc(int sig, void *arg, vregs *r);
179     void jump_to_rom(uint32 entry);
180    
181     void init_rom(void);
182     void load_rom(void);
183    
184     int sheep_fd; // FD of sheep driver
185    
186     area_id kernel_area; // Kernel Data area ID
187     area_id kernel_area2; // Alternate Kernel Data area ID
188     area_id rom_area; // ROM area ID
189     area_id ram_area; // RAM area ID
190     area_id dr_cache_area; // DR Cache area ID
191    
192     struct sigaction sigusr1_action; // Interrupt signal (of emulator thread)
193     struct sigaction sigsegv_action; // Data access exception signal (of emulator thread)
194     struct sigaction sigill_action; // Illegal instruction exception signal (of emulator thread)
195    
196     // Exceptions
197     class area_error {};
198     class file_open_error {};
199     class file_read_error {};
200     class rom_size_error {};
201     };
202    
203    
204     // Global variables
205     SheepShaver *the_app; // Pointer to application object
206     #if !EMULATED_PPC
207     void *TOC; // TOC pointer
208     #endif
209     uint32 RAMBase; // Base address of Mac RAM
210     uint32 RAMSize; // Size of Mac RAM
211     uint32 KernelDataAddr; // Address of Kernel Data
212     uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM
213     uint32 DRCacheAddr; // Address of DR Cache
214     uint32 PVR; // Theoretical PVR
215     int64 CPUClockSpeed; // Processor clock speed (Hz)
216     int64 BusClockSpeed; // Bus clock speed (Hz)
217     system_info SysInfo; // System information
218    
219     static void *sig_stack = NULL; // Stack for signal handlers
220     static void *extra_stack = NULL; // Stack for SIGSEGV inside interrupt handler
221    
222    
223     // Prototypes
224     static void sigsegv_handler(vregs *r);
225     static void sigill_handler(vregs *r);
226    
227    
228     /*
229     * Create application object and start it
230     */
231    
232     int main(int argc, char **argv)
233     {
234     tzset();
235     the_app = new SheepShaver();
236     the_app->Run();
237     delete the_app;
238     return 0;
239     }
240    
241    
242     /*
243     * Run application
244     */
245    
246     #if !EMULATED_PPC
247     static asm void *get_toc(void)
248     {
249     mr r3,r2
250     blr
251     }
252     #endif
253    
254     void SheepShaver::ReadyToRun(void)
255     {
256     // Print some info
257     printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
258     printf(" %s\n", GetString(STR_ABOUT_TEXT2));
259    
260     #if !EMULATED_PPC
261     // Get TOC pointer
262     TOC = get_toc();
263     #endif
264    
265     // Get system info
266     get_system_info(&SysInfo);
267     switch (SysInfo.cpu_type) {
268     case B_CPU_PPC_601:
269     PVR = 0x00010000;
270     break;
271     case B_CPU_PPC_603:
272     PVR = 0x00030000;
273     break;
274     case B_CPU_PPC_603e:
275     PVR = 0x00060000;
276     break;
277     case B_CPU_PPC_604:
278     PVR = 0x00040000;
279     break;
280     case B_CPU_PPC_604e:
281     PVR = 0x00090000;
282     break;
283     case B_CPU_PPC_750:
284     PVR = 0x00080000;
285     break;
286     default:
287     PVR = 0x00040000;
288     break;
289     }
290     CPUClockSpeed = SysInfo.cpu_clock_speed;
291     BusClockSpeed = SysInfo.bus_clock_speed;
292    
293     // Delete old areas
294     area_id old_kernel_area = find_area(KERNEL_AREA_NAME);
295     if (old_kernel_area > 0)
296     delete_area(old_kernel_area);
297     area_id old_kernel2_area = find_area(KERNEL_AREA2_NAME);
298     if (old_kernel2_area > 0)
299     delete_area(old_kernel2_area);
300     area_id old_ram_area = find_area(RAM_AREA_NAME);
301     if (old_ram_area > 0)
302     delete_area(old_ram_area);
303     area_id old_rom_area = find_area(ROM_AREA_NAME);
304     if (old_rom_area > 0)
305     delete_area(old_rom_area);
306     area_id old_dr_cache_area = find_area(DR_CACHE_AREA_NAME);
307     if (old_dr_cache_area > 0)
308     delete_area(old_dr_cache_area);
309    
310     // Read preferences
311     int argc = 0;
312     char **argv = NULL;
313     PrefsInit(argc, argv);
314    
315     // Init system routines
316     SysInit();
317    
318     // Test amount of RAM available for areas
319     if (SysInfo.max_pages * B_PAGE_SIZE < 16 * 1024 * 1024) {
320     ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
321     PostMessage(B_QUIT_REQUESTED);
322     return;
323     }
324    
325     // Show preferences editor (or start emulator directly)
326     if (!PrefsFindBool("nogui"))
327     PrefsEditor(MSG_START);
328     else
329     PostMessage(MSG_START);
330     }
331    
332    
333     /*
334     * Message received
335     */
336    
337     void SheepShaver::MessageReceived(BMessage *msg)
338     {
339     switch (msg->what) {
340     case MSG_START:
341     StartEmulator();
342     break;
343     default:
344     BApplication::MessageReceived(msg);
345     }
346     }
347    
348    
349     /*
350     * Start emulator
351     */
352    
353     void SheepShaver::StartEmulator(void)
354     {
355     char str[256];
356 cebix 1.4 int16 i16;
357 cebix 1.1
358     // Open sheep driver and remap low memory
359     sheep_fd = open("/dev/sheep", 0);
360     if (sheep_fd < 0) {
361     sprintf(str, GetString(STR_NO_SHEEP_DRIVER_ERR), strerror(sheep_fd), sheep_fd);
362     ErrorAlert(str);
363     PostMessage(B_QUIT_REQUESTED);
364     return;
365     }
366     status_t res = ioctl(sheep_fd, SHEEP_UP);
367     if (res < 0) {
368     sprintf(str, GetString(STR_SHEEP_UP_ERR), strerror(res), res);
369     ErrorAlert(str);
370     PostMessage(B_QUIT_REQUESTED);
371     return;
372     }
373    
374     // Create areas for Kernel Data
375     kernel_data = (KernelData *)KERNEL_DATA_BASE;
376     kernel_area = create_area(KERNEL_AREA_NAME, &kernel_data, B_EXACT_ADDRESS, KERNEL_AREA_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
377     if (kernel_area < 0) {
378     sprintf(str, GetString(STR_NO_KERNEL_DATA_ERR), strerror(kernel_area), kernel_area);
379     ErrorAlert(str);
380     PostMessage(B_QUIT_REQUESTED);
381     return;
382     }
383     emulator_data = &kernel_data->ed;
384     KernelDataAddr = (uint32)kernel_data;
385     D(bug("Kernel Data area %ld at %p, Emulator Data at %p\n", kernel_area, kernel_data, emulator_data));
386    
387     void *kernel_data2 = (void *)KERNEL_DATA2_BASE;
388     kernel_area2 = clone_area(KERNEL_AREA2_NAME, &kernel_data2, B_EXACT_ADDRESS, B_READ_AREA | B_WRITE_AREA, kernel_area);
389     if (kernel_area2 < 0) {
390     sprintf(str, GetString(STR_NO_KERNEL_DATA_ERR), strerror(kernel_area2), kernel_area2);
391     ErrorAlert(str);
392     PostMessage(B_QUIT_REQUESTED);
393     return;
394     }
395     D(bug("Kernel Data 2 area %ld at %p\n", kernel_area2, kernel_data2));
396    
397     // Create area for Mac RAM
398     RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary
399     if (RAMSize < 8*1024*1024) {
400     WarningAlert(GetString(STR_SMALL_RAM_WARN));
401     RAMSize = 8*1024*1024;
402     }
403    
404     RAMBase = 0x10000000;
405     ram_area = create_area(RAM_AREA_NAME, (void **)&RAMBase, B_BASE_ADDRESS, RAMSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
406     if (ram_area < 0) {
407     sprintf(str, GetString(STR_NO_RAM_AREA_ERR), strerror(ram_area), ram_area);
408     ErrorAlert(str);
409     PostMessage(B_QUIT_REQUESTED);
410     return;
411     }
412     D(bug("RAM area %ld at %p\n", ram_area, RAMBase));
413    
414     // Create area and load Mac ROM
415     try {
416     init_rom();
417     } catch (area_error) {
418     ErrorAlert(GetString(STR_NO_ROM_AREA_ERR));
419     PostMessage(B_QUIT_REQUESTED);
420     return;
421     } catch (file_open_error) {
422     ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
423     PostMessage(B_QUIT_REQUESTED);
424     return;
425     } catch (file_read_error) {
426     ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
427     PostMessage(B_QUIT_REQUESTED);
428     return;
429     } catch (rom_size_error) {
430     ErrorAlert(GetString(STR_ROM_SIZE_ERR));
431     PostMessage(B_QUIT_REQUESTED);
432     return;
433     }
434    
435     // Create area for DR Cache
436     DRCacheAddr = DR_CACHE_BASE;
437     dr_cache_area = create_area(DR_CACHE_AREA_NAME, (void **)&DRCacheAddr, B_EXACT_ADDRESS, DR_CACHE_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
438     if (dr_cache_area < 0) {
439     sprintf(str, GetString(STR_NO_KERNEL_DATA_ERR), strerror(dr_cache_area), dr_cache_area);
440     ErrorAlert(str);
441     PostMessage(B_QUIT_REQUESTED);
442     return;
443     }
444     D(bug("DR Cache area %ld at %p\n", dr_cache_area, DRCacheAddr));
445    
446     // Load NVRAM
447     XPRAMInit();
448    
449     // Set boot volume
450 cebix 1.4 i16 = PrefsFindInt32("bootdrive");
451 cebix 1.1 XPRAM[0x1378] = i16 >> 8;
452     XPRAM[0x1379] = i16 & 0xff;
453 cebix 1.4 i16 = PrefsFindInt32("bootdriver");
454 cebix 1.1 XPRAM[0x137a] = i16 >> 8;
455     XPRAM[0x137b] = i16 & 0xff;
456    
457     // Create BootGlobs at top of Mac memory
458     memset((void *)(RAMBase + RAMSize - 4096), 0, 4096);
459     BootGlobsAddr = RAMBase + RAMSize - 0x1c;
460     uint32 *boot_globs = (uint32 *)BootGlobsAddr;
461     boot_globs[-5] = htonl(RAMBase + RAMSize); // MemTop
462     boot_globs[0] = htonl(RAMBase); // First RAM bank
463     boot_globs[1] = htonl(RAMSize);
464     boot_globs[2] = htonl((uint32)-1); // End of bank table
465    
466     // Init drivers
467     SonyInit();
468     DiskInit();
469     CDROMInit();
470     SCSIInit();
471    
472     // Init external file system
473     ExtFSInit();
474    
475     // Init audio
476     AudioInit();
477    
478     // Init network
479     EtherInit();
480    
481     // Init serial ports
482     SerialInit();
483    
484     // Init Time Manager
485     TimerInit();
486    
487     // Init clipboard
488     ClipInit();
489    
490     // Init video
491     if (!VideoInit()) {
492     PostMessage(B_QUIT_REQUESTED);
493     return;
494     }
495    
496     // Install ROM patches
497     if (!PatchROM()) {
498     ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR));
499     PostMessage(B_QUIT_REQUESTED);
500     return;
501     }
502    
503     // Clear caches (as we loaded and patched code) and write protect ROM
504     #if !EMULATED_PPC
505     clear_caches((void *)ROM_BASE, ROM_AREA_SIZE, B_INVALIDATE_ICACHE | B_FLUSH_DCACHE);
506     #endif
507     set_area_protection(rom_area, B_READ_AREA);
508    
509     // Initialize Kernel Data
510     memset(kernel_data, 0, sizeof(KernelData));
511     if (ROMType == ROMTYPE_NEWWORLD) {
512     static uint32 of_dev_tree[4] = {0, 0, 0, 0};
513     static uint8 vector_lookup_tbl[128];
514     static uint8 vector_mask_tbl[64];
515     memset((uint8 *)kernel_data + 0xb80, 0x3d, 0x80);
516     memset(vector_lookup_tbl, 0, 128);
517     memset(vector_mask_tbl, 0, 64);
518     kernel_data->v[0xb80 >> 2] = htonl(ROM_BASE);
519     kernel_data->v[0xb84 >> 2] = htonl((uint32)of_dev_tree); // OF device tree base
520     kernel_data->v[0xb90 >> 2] = htonl((uint32)vector_lookup_tbl);
521     kernel_data->v[0xb94 >> 2] = htonl((uint32)vector_mask_tbl);
522     kernel_data->v[0xb98 >> 2] = htonl(ROM_BASE); // OpenPIC base
523     kernel_data->v[0xbb0 >> 2] = htonl(0); // ADB base
524     kernel_data->v[0xc20 >> 2] = htonl(RAMSize);
525     kernel_data->v[0xc24 >> 2] = htonl(RAMSize);
526     kernel_data->v[0xc30 >> 2] = htonl(RAMSize);
527     kernel_data->v[0xc34 >> 2] = htonl(RAMSize);
528     kernel_data->v[0xc38 >> 2] = htonl(0x00010020);
529     kernel_data->v[0xc3c >> 2] = htonl(0x00200001);
530     kernel_data->v[0xc40 >> 2] = htonl(0x00010000);
531     kernel_data->v[0xc50 >> 2] = htonl(RAMBase);
532     kernel_data->v[0xc54 >> 2] = htonl(RAMSize);
533     kernel_data->v[0xf60 >> 2] = htonl(PVR);
534     kernel_data->v[0xf64 >> 2] = htonl(CPUClockSpeed);
535     kernel_data->v[0xf68 >> 2] = htonl(BusClockSpeed);
536     kernel_data->v[0xf6c >> 2] = htonl(CPUClockSpeed);
537     } else {
538     kernel_data->v[0xc80 >> 2] = htonl(RAMSize);
539     kernel_data->v[0xc84 >> 2] = htonl(RAMSize);
540     kernel_data->v[0xc90 >> 2] = htonl(RAMSize);
541     kernel_data->v[0xc94 >> 2] = htonl(RAMSize);
542     kernel_data->v[0xc98 >> 2] = htonl(0x00010020);
543     kernel_data->v[0xc9c >> 2] = htonl(0x00200001);
544     kernel_data->v[0xca0 >> 2] = htonl(0x00010000);
545     kernel_data->v[0xcb0 >> 2] = htonl(RAMBase);
546     kernel_data->v[0xcb4 >> 2] = htonl(RAMSize);
547     kernel_data->v[0xf80 >> 2] = htonl(PVR);
548     kernel_data->v[0xf84 >> 2] = htonl(CPUClockSpeed);
549     kernel_data->v[0xf88 >> 2] = htonl(BusClockSpeed);
550     kernel_data->v[0xf8c >> 2] = htonl(CPUClockSpeed);
551     }
552    
553     // Initialize extra low memory
554     D(bug("Initializing Low Memory...\n"));
555     memset(NULL, 0, 0x3000);
556     WriteMacInt32(XLM_SIGNATURE, 'Baah'); // Signature to detect SheepShaver
557     WriteMacInt32(XLM_KERNEL_DATA, (uint32)kernel_data); // For trap replacement routines
558     WriteMacInt32(XLM_SHEEP_OBJ, (uint32)this); // Pointer to SheepShaver object
559     WriteMacInt32(XLM_PVR, PVR); // Theoretical PVR
560     WriteMacInt32(XLM_BUS_CLOCK, BusClockSpeed); // For DriverServicesLib patch
561     WriteMacInt16(XLM_EXEC_RETURN_OPCODE, M68K_EXEC_RETURN); // For Execute68k() (RTS from the executed 68k code will jump here and end 68k mode)
562     #if !EMULATED_PPC
563     WriteMacInt32(XLM_TOC, (uint32)TOC); // TOC pointer of emulator
564     WriteMacInt32(XLM_ETHER_INIT, *(uint32 *)InitStreamModule); // DLPI ethernet driver functions
565     WriteMacInt32(XLM_ETHER_TERM, *(uint32 *)TerminateStreamModule);
566     WriteMacInt32(XLM_ETHER_OPEN, *(uint32 *)ether_open);
567     WriteMacInt32(XLM_ETHER_CLOSE, *(uint32 *)ether_close);
568     WriteMacInt32(XLM_ETHER_WPUT, *(uint32 *)ether_wput);
569     WriteMacInt32(XLM_ETHER_RSRV, *(uint32 *)ether_rsrv);
570     WriteMacInt32(XLM_VIDEO_DOIO, *(uint32 *)VideoDoDriverIO);
571     #endif
572     D(bug("Low Memory initialized\n"));
573    
574     // Disallow quitting with Alt-Q from now on
575     AllowQuitting = false;
576    
577     // Start 60Hz interrupt
578     tick_thread = spawn_thread(tick_func, "60Hz", B_URGENT_DISPLAY_PRIORITY, this);
579     resume_thread(tick_thread);
580    
581     // Start NVRAM watchdog thread
582     memcpy(last_xpram, XPRAM, XPRAM_SIZE);
583     nvram_thread = spawn_thread(nvram_func, "NVRAM Watchdog", B_LOW_PRIORITY, this);
584     resume_thread(nvram_thread);
585    
586     // Start emulator thread
587     emul_thread = spawn_thread(emul_func, "MacOS", B_NORMAL_PRIORITY, this);
588     resume_thread(emul_thread);
589     }
590    
591    
592     /*
593     * Quit requested
594     */
595    
596     bool SheepShaver::QuitRequested(void)
597     {
598     if (AllowQuitting)
599     return BApplication::QuitRequested();
600     else
601     return false;
602     }
603    
604     void SheepShaver::Quit(void)
605     {
606     status_t l;
607    
608     // Stop 60Hz interrupt
609     if (tick_thread > 0) {
610     TickThreadActive = false;
611     wait_for_thread(tick_thread, &l);
612     }
613    
614     // Stop NVRAM watchdog
615     if (nvram_thread > 0) {
616     status_t l;
617     NVRAMThreadActive = false;
618     suspend_thread(nvram_thread); // Wake thread up from snooze()
619     snooze(1000);
620     resume_thread(nvram_thread);
621     while (wait_for_thread(nvram_thread, &l) == B_INTERRUPTED) ;
622     }
623    
624     // Wait for emulator thread to finish
625     if (emul_thread > 0)
626     wait_for_thread(emul_thread, &l);
627    
628     // Save NVRAM
629     XPRAMExit();
630    
631     // Exit clipboard
632     ClipExit();
633    
634     // Exit Time Manager
635     TimerExit();
636    
637     // Exit serial
638     SerialExit();
639    
640     // Exit network
641     EtherExit();
642    
643     // Exit audio
644     AudioExit();
645    
646     // Exit video
647     VideoExit();
648    
649     // Exit external file system
650     ExtFSExit();
651    
652     // Exit drivers
653     SCSIExit();
654     CDROMExit();
655     DiskExit();
656     SonyExit();
657    
658     // Delete DR Cache area
659     if (dr_cache_area >= 0)
660     delete_area(dr_cache_area);
661    
662     // Delete ROM area
663     if (rom_area >= 0)
664     delete_area(rom_area);
665    
666     // Delete RAM area
667     if (ram_area >= 0)
668     delete_area(ram_area);
669    
670     // Delete Kernel Data area2
671     if (kernel_area2 >= 0)
672     delete_area(kernel_area2);
673     if (kernel_area >= 0)
674     delete_area(kernel_area);
675    
676     // Unmap low memory and close sheep driver
677     if (sheep_fd >= 0) {
678     ioctl(sheep_fd, SHEEP_DOWN);
679     close(sheep_fd);
680     }
681    
682     // Exit system routines
683     SysExit();
684    
685     // Exit preferences
686     PrefsExit();
687    
688     BApplication::Quit();
689     }
690    
691    
692     /*
693     * Create area for ROM (sets rom_area) and load ROM file
694     *
695     * area_error : Cannot create area
696     * file_open_error: Cannot open ROM file
697     * file_read_error: Cannot read ROM file
698     */
699    
700     void SheepShaver::init_rom(void)
701     {
702     // Create area for ROM
703     void *rom_addr = (void *)ROM_BASE;
704     rom_area = create_area(ROM_AREA_NAME, &rom_addr, B_EXACT_ADDRESS, ROM_AREA_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
705     if (rom_area < 0)
706     throw area_error();
707     D(bug("ROM area %ld at %p\n", rom_area, rom_addr));
708    
709     // Load ROM
710     load_rom();
711     }
712    
713    
714     /*
715     * Load ROM file
716     *
717     * file_open_error: Cannot open ROM file (nor use built-in ROM)
718     * file_read_error: Cannot read ROM file
719     */
720    
721     void SheepShaver::load_rom(void)
722     {
723     // Get rom file path from preferences
724     const char *rom_path = PrefsFindString("rom");
725    
726     // Try to open ROM file
727     BFile file(rom_path ? rom_path : ROM_FILE_NAME, B_READ_ONLY);
728     if (file.InitCheck() != B_NO_ERROR) {
729    
730     // Failed, then ask memory_mess driver for ROM
731     uint8 *rom = new uint8[ROM_SIZE]; // Reading directly into the area doesn't work
732     ssize_t actual = read(sheep_fd, (void *)rom, ROM_SIZE);
733     if (actual == ROM_SIZE) {
734     memcpy((void *)ROM_BASE, rom, ROM_SIZE);
735     delete[] rom;
736     return;
737     } else
738     throw file_open_error();
739     }
740    
741     printf(GetString(STR_READING_ROM_FILE));
742    
743     // Get file size
744     off_t rom_size = 0;
745     file.GetSize(&rom_size);
746    
747     uint8 *rom = new uint8[ROM_SIZE]; // Reading directly into the area doesn't work
748     ssize_t actual = file.Read((void *)rom, ROM_SIZE);
749 gbeauche 1.2
750     // Decode Mac ROM
751     if (!DecodeROM(rom, actual)) {
752     if (rom_size != 4*1024*1024)
753 cebix 1.1 throw rom_size_error();
754     else
755     throw file_read_error();
756     }
757 gbeauche 1.2 delete[] rom;
758 cebix 1.1 }
759    
760    
761     /*
762     * Emulator thread function
763     */
764    
765     status_t SheepShaver::emul_func(void *arg)
766     {
767     SheepShaver *obj = (SheepShaver *)arg;
768    
769     // Install interrupt signal handler
770     sigemptyset(&obj->sigusr1_action.sa_mask);
771     obj->sigusr1_action.sa_handler = (__signal_func_ptr)(obj->sigusr1_invoc);
772     obj->sigusr1_action.sa_flags = 0;
773     obj->sigusr1_action.sa_userdata = arg;
774     sigaction(SIGUSR1, &obj->sigusr1_action, NULL);
775    
776     // Install data access signal handler
777     sigemptyset(&obj->sigsegv_action.sa_mask);
778     obj->sigsegv_action.sa_handler = (__signal_func_ptr)(obj->sigsegv_invoc);
779     obj->sigsegv_action.sa_flags = 0;
780     obj->sigsegv_action.sa_userdata = arg;
781     sigaction(SIGSEGV, &obj->sigsegv_action, NULL);
782    
783     #if !EMULATED_PPC
784     // Install illegal instruction signal handler
785     sigemptyset(&obj->sigill_action.sa_mask);
786     obj->sigill_action.sa_handler = (__signal_func_ptr)(obj->sigill_invoc);
787     obj->sigill_action.sa_flags = 0;
788     obj->sigill_action.sa_userdata = arg;
789     sigaction(SIGILL, &obj->sigill_action, NULL);
790     #endif
791    
792     // Exceptions will send signals
793     disable_debugger(true);
794    
795     // Install signal stack
796     sig_stack = malloc(SIG_STACK_SIZE);
797     extra_stack = malloc(SIG_STACK_SIZE);
798     set_signal_stack(sig_stack, SIG_STACK_SIZE);
799    
800     // We're now ready to receive signals
801     obj->ReadyForSignals = true;
802    
803     // Jump to ROM boot routine
804     D(bug("Jumping to ROM\n"));
805     obj->jump_to_rom(ROM_BASE + 0x310000);
806     D(bug("Returned from ROM\n"));
807    
808     // We're no longer ready to receive signals
809     obj->ReadyForSignals = false;
810     obj->AllowQuitting = true;
811    
812     // Quit program
813     be_app->PostMessage(B_QUIT_REQUESTED);
814     return 0;
815     }
816    
817    
818     /*
819     * Jump into Mac ROM, start 680x0 emulator
820     * (also contains other EMUL_RETURN and EMUL_OP routines)
821     */
822    
823     #if EMULATED_PPC
824     extern void emul_ppc(uint32 start);
825     extern void init_emul_ppc(void);
826     void SheepShaver::jump_to_rom(uint32 entry)
827     {
828     init_emul_ppc();
829     emul_ppc(entry);
830     }
831     #else
832     asm void SheepShaver::jump_to_rom(register uint32 entry)
833     {
834     // Create stack frame
835     mflr r0
836     stw r0,8(r1)
837     mfcr r0
838     stw r0,4(r1)
839     stwu r1,-(56+19*4+18*8)(r1)
840    
841     // Save PowerPC registers
842     stmw r13,56(r1)
843     stfd f14,56+19*4+0*8(r1)
844     stfd f15,56+19*4+1*8(r1)
845     stfd f16,56+19*4+2*8(r1)
846     stfd f17,56+19*4+3*8(r1)
847     stfd f18,56+19*4+4*8(r1)
848     stfd f19,56+19*4+5*8(r1)
849     stfd f20,56+19*4+6*8(r1)
850     stfd f21,56+19*4+7*8(r1)
851     stfd f22,56+19*4+8*8(r1)
852     stfd f23,56+19*4+9*8(r1)
853     stfd f24,56+19*4+10*8(r1)
854     stfd f25,56+19*4+11*8(r1)
855     stfd f26,56+19*4+12*8(r1)
856     stfd f27,56+19*4+13*8(r1)
857     stfd f28,56+19*4+14*8(r1)
858     stfd f29,56+19*4+15*8(r1)
859     stfd f30,56+19*4+16*8(r1)
860     stfd f31,56+19*4+17*8(r1)
861    
862     // Move entry address to ctr, get pointer to Emulator Data
863     mtctr r4
864     lwz r4,SheepShaver.emulator_data(r3)
865    
866     // Skip over EMUL_RETURN routine and get its address
867     bl @1
868    
869    
870     /*
871     * EMUL_RETURN: Returned from emulator
872     */
873    
874     // Restore PowerPC registers
875     lwz r1,XLM_EMUL_RETURN_STACK
876     lwz r2,XLM_TOC
877     lmw r13,56(r1)
878     lfd f14,56+19*4+0*8(r1)
879     lfd f15,56+19*4+1*8(r1)
880     lfd f16,56+19*4+2*8(r1)
881     lfd f17,56+19*4+3*8(r1)
882     lfd f18,56+19*4+4*8(r1)
883     lfd f19,56+19*4+5*8(r1)
884     lfd f20,56+19*4+6*8(r1)
885     lfd f21,56+19*4+7*8(r1)
886     lfd f22,56+19*4+8*8(r1)
887     lfd f23,56+19*4+9*8(r1)
888     lfd f24,56+19*4+10*8(r1)
889     lfd f25,56+19*4+11*8(r1)
890     lfd f26,56+19*4+12*8(r1)
891     lfd f27,56+19*4+13*8(r1)
892     lfd f28,56+19*4+14*8(r1)
893     lfd f29,56+19*4+15*8(r1)
894     lfd f30,56+19*4+16*8(r1)
895     lfd f31,56+19*4+17*8(r1)
896    
897     // Exiting from 68k emulator
898     li r0,1
899     stw r0,XLM_IRQ_NEST
900     li r0,MODE_NATIVE
901     stw r0,XLM_RUN_MODE
902    
903     // Return to caller of jump_to_rom()
904     lwz r0,56+19*4+18*8+8(r1)
905     mtlr r0
906     lwz r0,56+19*4+18*8+4(r1)
907     mtcrf 0xff,r0
908     addi r1,r1,56+19*4+18*8
909     blr
910    
911    
912     // Save address of EMUL_RETURN routine for 68k emulator patch
913     @1 mflr r0
914     stw r0,XLM_EMUL_RETURN_PROC
915    
916     // Skip over EXEC_RETURN routine and get its address
917     bl @2
918    
919    
920     /*
921     * EXEC_RETURN: Returned from 68k routine executed with Execute68k()
922     */
923    
924     // Save r25 (contains current 68k interrupt level)
925     stw r25,XLM_68K_R25
926    
927     // Reentering EMUL_OP mode
928     li r0,MODE_EMUL_OP
929     stw r0,XLM_RUN_MODE
930    
931     // Save 68k registers
932     lwz r4,56+19*4+18*8+12(r1)
933     stw r8,M68kRegisters.d[0](r4)
934     stw r9,M68kRegisters.d[1](r4)
935     stw r10,M68kRegisters.d[2](r4)
936     stw r11,M68kRegisters.d[3](r4)
937     stw r12,M68kRegisters.d[4](r4)
938     stw r13,M68kRegisters.d[5](r4)
939     stw r14,M68kRegisters.d[6](r4)
940     stw r15,M68kRegisters.d[7](r4)
941     stw r16,M68kRegisters.a[0](r4)
942     stw r17,M68kRegisters.a[1](r4)
943     stw r18,M68kRegisters.a[2](r4)
944     stw r19,M68kRegisters.a[3](r4)
945     stw r20,M68kRegisters.a[4](r4)
946     stw r21,M68kRegisters.a[5](r4)
947     stw r22,M68kRegisters.a[6](r4)
948    
949     // Restore PowerPC registers
950     lmw r13,56(r1)
951     #if SAVE_FP_EXEC_68K
952     lfd f14,56+19*4+0*8(r1)
953     lfd f15,56+19*4+1*8(r1)
954     lfd f16,56+19*4+2*8(r1)
955     lfd f17,56+19*4+3*8(r1)
956     lfd f18,56+19*4+4*8(r1)
957     lfd f19,56+19*4+5*8(r1)
958     lfd f20,56+19*4+6*8(r1)
959     lfd f21,56+19*4+7*8(r1)
960     lfd f22,56+19*4+8*8(r1)
961     lfd f23,56+19*4+9*8(r1)
962     lfd f24,56+19*4+10*8(r1)
963     lfd f25,56+19*4+11*8(r1)
964     lfd f26,56+19*4+12*8(r1)
965     lfd f27,56+19*4+13*8(r1)
966     lfd f28,56+19*4+14*8(r1)
967     lfd f29,56+19*4+15*8(r1)
968     lfd f30,56+19*4+16*8(r1)
969     lfd f31,56+19*4+17*8(r1)
970     #endif
971    
972     // Return to caller
973     lwz r0,56+19*4+18*8+8(r1)
974     mtlr r0
975     addi r1,r1,56+19*4+18*8
976     blr
977    
978    
979     // Stave address of EXEC_RETURN routine for 68k emulator patch
980     @2 mflr r0
981     stw r0,XLM_EXEC_RETURN_PROC
982    
983     // Skip over EMUL_BREAK/EMUL_OP routine and get its address
984     bl @3
985    
986    
987     /*
988     * EMUL_BREAK/EMUL_OP: Execute native routine, selector in r5 (my own private mode switch)
989     *
990     * 68k registers are stored in a M68kRegisters struct on the stack
991     * which the native routine may read and modify
992     */
993    
994     // Save r25 (contains current 68k interrupt level)
995     stw r25,XLM_68K_R25
996    
997     // Entering EMUL_OP mode within 68k emulator
998     li r0,MODE_EMUL_OP
999     stw r0,XLM_RUN_MODE
1000    
1001     // Create PowerPC stack frame, reserve space for M68kRegisters
1002     mr r3,r1
1003     subi r1,r1,56 // Fake "caller" frame
1004     rlwinm r1,r1,0,0,29 // Align stack
1005    
1006     mfcr r0
1007     rlwinm r0,r0,0,11,8
1008     stw r0,4(r1)
1009     mfxer r0
1010     stw r0,16(r1)
1011     stw r2,12(r1)
1012     stwu r1,-(56+16*4+15*8)(r1)
1013     lwz r2,XLM_TOC
1014    
1015     // Save 68k registers
1016     stw r8,56+M68kRegisters.d[0](r1)
1017     stw r9,56+M68kRegisters.d[1](r1)
1018     stw r10,56+M68kRegisters.d[2](r1)
1019     stw r11,56+M68kRegisters.d[3](r1)
1020     stw r12,56+M68kRegisters.d[4](r1)
1021     stw r13,56+M68kRegisters.d[5](r1)
1022     stw r14,56+M68kRegisters.d[6](r1)
1023     stw r15,56+M68kRegisters.d[7](r1)
1024     stw r16,56+M68kRegisters.a[0](r1)
1025     stw r17,56+M68kRegisters.a[1](r1)
1026     stw r18,56+M68kRegisters.a[2](r1)
1027     stw r19,56+M68kRegisters.a[3](r1)
1028     stw r20,56+M68kRegisters.a[4](r1)
1029     stw r21,56+M68kRegisters.a[5](r1)
1030     stw r22,56+M68kRegisters.a[6](r1)
1031     stw r3,56+M68kRegisters.a[7](r1)
1032     stfd f0,56+16*4+0*8(r1)
1033     stfd f1,56+16*4+1*8(r1)
1034     stfd f2,56+16*4+2*8(r1)
1035     stfd f3,56+16*4+3*8(r1)
1036     stfd f4,56+16*4+4*8(r1)
1037     stfd f5,56+16*4+5*8(r1)
1038     stfd f6,56+16*4+6*8(r1)
1039     stfd f7,56+16*4+7*8(r1)
1040     mffs f0
1041     stfd f8,56+16*4+8*8(r1)
1042     stfd f9,56+16*4+9*8(r1)
1043     stfd f10,56+16*4+10*8(r1)
1044     stfd f11,56+16*4+11*8(r1)
1045     stfd f12,56+16*4+12*8(r1)
1046     stfd f13,56+16*4+13*8(r1)
1047     stfd f0,56+16*4+14*8(r1)
1048    
1049     // Execute native routine
1050     addi r3,r1,56
1051     mr r4,r24
1052     bl EmulOp
1053    
1054     // Restore 68k registers
1055     lwz r8,56+M68kRegisters.d[0](r1)
1056     lwz r9,56+M68kRegisters.d[1](r1)
1057     lwz r10,56+M68kRegisters.d[2](r1)
1058     lwz r11,56+M68kRegisters.d[3](r1)
1059     lwz r12,56+M68kRegisters.d[4](r1)
1060     lwz r13,56+M68kRegisters.d[5](r1)
1061     lwz r14,56+M68kRegisters.d[6](r1)
1062     lwz r15,56+M68kRegisters.d[7](r1)
1063     lwz r16,56+M68kRegisters.a[0](r1)
1064     lwz r17,56+M68kRegisters.a[1](r1)
1065     lwz r18,56+M68kRegisters.a[2](r1)
1066     lwz r19,56+M68kRegisters.a[3](r1)
1067     lwz r20,56+M68kRegisters.a[4](r1)
1068     lwz r21,56+M68kRegisters.a[5](r1)
1069     lwz r22,56+M68kRegisters.a[6](r1)
1070     lwz r3,56+M68kRegisters.a[7](r1)
1071     lfd f13,56+16*4+14*8(r1)
1072     lfd f0,56+16*4+0*8(r1)
1073     lfd f1,56+16*4+1*8(r1)
1074     lfd f2,56+16*4+2*8(r1)
1075     lfd f3,56+16*4+3*8(r1)
1076     lfd f4,56+16*4+4*8(r1)
1077     lfd f5,56+16*4+5*8(r1)
1078     lfd f6,56+16*4+6*8(r1)
1079     lfd f7,56+16*4+7*8(r1)
1080     mtfsf 0xff,f13
1081     lfd f8,56+16*4+8*8(r1)
1082     lfd f9,56+16*4+9*8(r1)
1083     lfd f10,56+16*4+10*8(r1)
1084     lfd f11,56+16*4+11*8(r1)
1085     lfd f12,56+16*4+12*8(r1)
1086     lfd f13,56+16*4+13*8(r1)
1087    
1088     // Delete PowerPC stack frame
1089     lwz r2,56+16*4+15*8+12(r1)
1090     lwz r0,56+16*4+15*8+16(r1)
1091     mtxer r0
1092     lwz r0,56+16*4+15*8+4(r1)
1093     mtcrf 0xff,r0
1094     mr r1,r3
1095    
1096     // Reeintering 68k emulator
1097     li r0,MODE_68K
1098     stw r0,XLM_RUN_MODE
1099    
1100     // Set r0 to 0 for 68k emulator
1101     li r0,0
1102    
1103     // Execute next 68k opcode
1104     rlwimi r29,r27,3,13,28
1105     lhau r27,2(r24)
1106     mtlr r29
1107     blr
1108    
1109    
1110     // Save address of EMUL_BREAK/EMUL_OP routine for 68k emulator patch
1111     @3 mflr r0
1112     stw r0,XLM_EMUL_OP_PROC
1113    
1114     // Save stack pointer for EMUL_RETURN
1115     stw r1,XLM_EMUL_RETURN_STACK
1116    
1117     // Preset registers for ROM boot routine
1118     lis r3,0x40b0 // Pointer to ROM boot structure
1119     ori r3,r3,0xd000
1120    
1121     // 68k emulator is now active
1122     li r0,MODE_68K
1123     stw r0,XLM_RUN_MODE
1124    
1125     // Jump to ROM
1126     bctr
1127     }
1128     #endif
1129    
1130    
1131     #if !EMULATED_PPC
1132     /*
1133     * Execute 68k subroutine (must be ended with RTS)
1134     * This must only be called by the emul_thread when in EMUL_OP mode
1135     * r->a[7] is unused, the routine runs on the caller's stack
1136     */
1137    
1138     #if SAFE_EXEC_68K
1139     void execute_68k(uint32 pc, M68kRegisters *r);
1140    
1141     void Execute68k(uint32 pc, M68kRegisters *r)
1142     {
1143     if (*(uint32 *)XLM_RUN_MODE != MODE_EMUL_OP)
1144     printf("FATAL: Execute68k() not called from EMUL_OP mode\n");
1145     if (find_thread(NULL) != the_app->emul_thread)
1146     printf("FATAL: Execute68k() not called from emul_thread\n");
1147     execute_68k(pc, r);
1148     }
1149    
1150     asm void execute_68k(register uint32 pc, register M68kRegisters *r)
1151     #else
1152     asm void Execute68k(register uint32 pc, register M68kRegisters *r)
1153     #endif
1154     {
1155     // Create stack frame
1156     mflr r0
1157     stw r0,8(r1)
1158     stw r4,12(r1)
1159     stwu r1,-(56+19*4+18*8)(r1)
1160    
1161     // Save PowerPC registers
1162     stmw r13,56(r1)
1163     #if SAVE_FP_EXEC_68K
1164     stfd f14,56+19*4+0*8(r1)
1165     stfd f15,56+19*4+1*8(r1)
1166     stfd f16,56+19*4+2*8(r1)
1167     stfd f17,56+19*4+3*8(r1)
1168     stfd f18,56+19*4+4*8(r1)
1169     stfd f19,56+19*4+5*8(r1)
1170     stfd f20,56+19*4+6*8(r1)
1171     stfd f21,56+19*4+7*8(r1)
1172     stfd f22,56+19*4+8*8(r1)
1173     stfd f23,56+19*4+9*8(r1)
1174     stfd f24,56+19*4+10*8(r1)
1175     stfd f25,56+19*4+11*8(r1)
1176     stfd f26,56+19*4+12*8(r1)
1177     stfd f27,56+19*4+13*8(r1)
1178     stfd f28,56+19*4+14*8(r1)
1179     stfd f29,56+19*4+15*8(r1)
1180     stfd f30,56+19*4+16*8(r1)
1181     stfd f31,56+19*4+17*8(r1)
1182     #endif
1183    
1184     // Set up registers for 68k emulator
1185     lwz r31,XLM_KERNEL_DATA // Pointer to Kernel Data
1186     addi r31,r31,0x1000
1187     li r0,0
1188     mtcrf 0xff,r0
1189     creqv 11,11,11 // Supervisor mode
1190     lwz r8,M68kRegisters.d[0](r4)
1191     lwz r9,M68kRegisters.d[1](r4)
1192     lwz r10,M68kRegisters.d[2](r4)
1193     lwz r11,M68kRegisters.d[3](r4)
1194     lwz r12,M68kRegisters.d[4](r4)
1195     lwz r13,M68kRegisters.d[5](r4)
1196     lwz r14,M68kRegisters.d[6](r4)
1197     lwz r15,M68kRegisters.d[7](r4)
1198     lwz r16,M68kRegisters.a[0](r4)
1199     lwz r17,M68kRegisters.a[1](r4)
1200     lwz r18,M68kRegisters.a[2](r4)
1201     lwz r19,M68kRegisters.a[3](r4)
1202     lwz r20,M68kRegisters.a[4](r4)
1203     lwz r21,M68kRegisters.a[5](r4)
1204     lwz r22,M68kRegisters.a[6](r4)
1205     li r23,0
1206     mr r24,r3
1207     lwz r25,XLM_68K_R25 // MSB of SR
1208     li r26,0
1209     li r28,0 // VBR
1210     lwz r29,0x74(r31) // Pointer to opcode table
1211     lwz r30,0x78(r31) // Address of emulator
1212    
1213     // Push return address (points to EXEC_RETURN opcode) on stack
1214     li r0,XLM_EXEC_RETURN_OPCODE
1215     stwu r0,-4(r1)
1216    
1217     // Reentering 68k emulator
1218     li r0,MODE_68K
1219     stw r0,XLM_RUN_MODE
1220    
1221     // Set r0 to 0 for 68k emulator
1222     li r0,0
1223    
1224     // Execute 68k opcode
1225     lha r27,0(r24)
1226     rlwimi r29,r27,3,13,28
1227     lhau r27,2(r24)
1228     mtlr r29
1229     blr
1230     }
1231    
1232    
1233     /*
1234     * Execute 68k A-Trap from EMUL_OP routine
1235     * r->a[7] is unused, the routine runs on the caller's stack
1236     */
1237    
1238     void Execute68kTrap(uint16 trap, M68kRegisters *r)
1239     {
1240     uint16 proc[2] = {trap, M68K_RTS};
1241     Execute68k((uint32)proc, r);
1242     }
1243    
1244    
1245     /*
1246     * Execute PPC code from EMUL_OP routine (real mode switch)
1247     */
1248    
1249     void ExecutePPC(void (*func)())
1250     {
1251     RoutineDescriptor desc = BUILD_PPC_ROUTINE_DESCRIPTOR(0, func);
1252     M68kRegisters r;
1253     Execute68k((uint32)&desc, &r);
1254     }
1255    
1256    
1257     /*
1258     * Quit emulator (must only be called from main thread)
1259     */
1260    
1261     asm void QuitEmulator(void)
1262     {
1263     lwz r0,XLM_EMUL_RETURN_PROC
1264     mtlr r0
1265     blr
1266     }
1267     #endif
1268    
1269    
1270     /*
1271     * Dump 68k registers
1272     */
1273    
1274     void Dump68kRegs(M68kRegisters *r)
1275     {
1276     // Display 68k registers
1277     for (int i=0; i<8; i++) {
1278     printf("d%d: %08lx", i, r->d[i]);
1279     if (i == 3 || i == 7)
1280     printf("\n");
1281     else
1282     printf(", ");
1283     }
1284     for (int i=0; i<8; i++) {
1285     printf("a%d: %08lx", i, r->a[i]);
1286     if (i == 3 || i == 7)
1287     printf("\n");
1288     else
1289     printf(", ");
1290     }
1291     }
1292    
1293    
1294     /*
1295     * Make code executable
1296     */
1297    
1298     void MakeExecutable(int dummy, void *start, uint32 length)
1299     {
1300     if (((uint32)start >= ROM_BASE) && ((uint32)start < (ROM_BASE + ROM_SIZE)))
1301     return;
1302     clear_caches(start, length, B_INVALIDATE_ICACHE | B_FLUSH_DCACHE);
1303     }
1304    
1305    
1306     /*
1307     * Patch things after system startup (gets called by disk driver accRun routine)
1308     */
1309    
1310     void PatchAfterStartup(void)
1311     {
1312     ExecutePPC(VideoInstallAccel);
1313     InstallExtFS();
1314     }
1315    
1316    
1317     /*
1318     * NVRAM watchdog thread (saves NVRAM every minute)
1319     */
1320    
1321 cebix 1.4 status_t SheepShaver::nvram_func(void *arg)
1322 cebix 1.1 {
1323     SheepShaver *obj = (SheepShaver *)arg;
1324    
1325     while (obj->NVRAMThreadActive) {
1326     snooze(60*1000000);
1327     if (memcmp(obj->last_xpram, XPRAM, XPRAM_SIZE)) {
1328     memcpy(obj->last_xpram, XPRAM, XPRAM_SIZE);
1329     SaveXPRAM();
1330     }
1331     }
1332     return 0;
1333     }
1334    
1335    
1336     /*
1337     * 60Hz thread (really 60.15Hz)
1338     */
1339    
1340     status_t SheepShaver::tick_func(void *arg)
1341     {
1342     SheepShaver *obj = (SheepShaver *)arg;
1343     int tick_counter = 0;
1344     bigtime_t current = system_time();
1345    
1346     while (obj->TickThreadActive) {
1347    
1348     // Wait
1349     current += 16625;
1350     snooze_until(current, B_SYSTEM_TIMEBASE);
1351    
1352     // Pseudo Mac 1Hz interrupt, update local time
1353     if (++tick_counter > 60) {
1354     tick_counter = 0;
1355     WriteMacInt32(0x20c, TimerDateTime());
1356     }
1357    
1358     // 60Hz interrupt
1359     if (ReadMacInt32(XLM_IRQ_NEST) == 0) {
1360     SetInterruptFlag(INTFLAG_VIA);
1361     TriggerInterrupt();
1362     }
1363     }
1364     return 0;
1365     }
1366    
1367    
1368     /*
1369     * Trigger signal USR1 from another thread
1370     */
1371    
1372     void TriggerInterrupt(void)
1373     {
1374     #if 0
1375     WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
1376     #else
1377     if (the_app->emul_thread > 0 && the_app->ReadyForSignals)
1378     send_signal(the_app->emul_thread, SIGUSR1);
1379     #endif
1380     }
1381    
1382    
1383     /*
1384     * Mutexes
1385     */
1386    
1387     struct B2_mutex {
1388     int dummy; //!!
1389     };
1390    
1391     B2_mutex *B2_create_mutex(void)
1392     {
1393     return new B2_mutex;
1394     }
1395    
1396     void B2_lock_mutex(B2_mutex *mutex)
1397     {
1398     }
1399    
1400     void B2_unlock_mutex(B2_mutex *mutex)
1401     {
1402     }
1403    
1404     void B2_delete_mutex(B2_mutex *mutex)
1405     {
1406     delete mutex;
1407     }
1408    
1409    
1410     /*
1411     * Set/clear interrupt flags (must be done atomically!)
1412     */
1413    
1414     volatile uint32 InterruptFlags = 0;
1415    
1416     void SetInterruptFlag(uint32 flag)
1417     {
1418     atomic_or((int32 *)&InterruptFlags, flag);
1419     }
1420    
1421     void ClearInterruptFlag(uint32 flag)
1422     {
1423     atomic_and((int32 *)&InterruptFlags, ~flag);
1424     }
1425    
1426    
1427     /*
1428     * Disable interrupts
1429     */
1430    
1431     void DisableInterrupt(void)
1432     {
1433     atomic_add((int32 *)XLM_IRQ_NEST, 1);
1434     }
1435    
1436    
1437     /*
1438     * Enable interrupts
1439     */
1440    
1441     void EnableInterrupt(void)
1442     {
1443     atomic_add((int32 *)XLM_IRQ_NEST, -1);
1444     }
1445    
1446    
1447     /*
1448     * USR1 handler
1449     */
1450    
1451     void SheepShaver::sigusr1_invoc(int sig, void *arg, vregs *r)
1452     {
1453     ((SheepShaver *)arg)->sigusr1_handler(r);
1454     }
1455    
1456     #if !EMULATED_PPC
1457     static asm void ppc_interrupt(register uint32 entry)
1458     {
1459     fralloc
1460    
1461     // Get address of return routine
1462     bl @1
1463    
1464     // Return routine
1465     frfree
1466     blr
1467    
1468     @1
1469     // Prepare registers for nanokernel interrupt routine
1470     mtctr r1
1471     lwz r1,XLM_KERNEL_DATA
1472     stw r6,0x018(r1)
1473     mfctr r6
1474     stw r6,0x004(r1)
1475     lwz r6,0x65c(r1)
1476     stw r7,0x13c(r6)
1477     stw r8,0x144(r6)
1478     stw r9,0x14c(r6)
1479     stw r10,0x154(r6)
1480     stw r11,0x15c(r6)
1481     stw r12,0x164(r6)
1482     stw r13,0x16c(r6)
1483    
1484     mflr r10
1485     mfcr r13
1486     lwz r7,0x660(r1)
1487     mflr r12
1488     rlwimi. r7,r7,8,0,0
1489     li r11,0
1490     ori r11,r11,0xf072 // MSR (SRR1)
1491     mtcrf 0x70,r11
1492     li r8,0
1493    
1494     // Enter nanokernel
1495     mtlr r3
1496     blr
1497     }
1498     #endif
1499    
1500     void SheepShaver::sigusr1_handler(vregs *r)
1501     {
1502     // Do nothing if interrupts are disabled
1503     if ((*(int32 *)XLM_IRQ_NEST) > 0)
1504     return;
1505    
1506     // Interrupt action depends on current run mode
1507     switch (*(uint32 *)XLM_RUN_MODE) {
1508     case MODE_68K:
1509     // 68k emulator active, trigger 68k interrupt level 1
1510     *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1;
1511     r->cr |= kernel_data->v[0x674 >> 2];
1512     break;
1513    
1514     #if INTERRUPTS_IN_NATIVE_MODE
1515     case MODE_NATIVE:
1516     // 68k emulator inactive, in nanokernel?
1517     if (r->r1 != KernelDataAddr) {
1518     // No, prepare for 68k interrupt level 1
1519     *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1;
1520     *(uint32 *)(kernel_data->v[0x658 >> 2] + 0xdc) |= kernel_data->v[0x674 >> 2];
1521    
1522     // Execute nanokernel interrupt routine (this will activate the 68k emulator)
1523     atomic_add((int32 *)XLM_IRQ_NEST, 1);
1524     if (ROMType == ROMTYPE_NEWWORLD)
1525     ppc_interrupt(ROM_BASE + 0x312b1c);
1526     else
1527     ppc_interrupt(ROM_BASE + 0x312a3c);
1528     }
1529     break;
1530     #endif
1531    
1532     #if INTERRUPTS_IN_EMUL_OP_MODE
1533     case MODE_EMUL_OP:
1534     // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
1535     if ((*(uint32 *)XLM_68K_R25 & 7) == 0) {
1536    
1537     // Set extra stack for SIGSEGV handler
1538     set_signal_stack(extra_stack, SIG_STACK_SIZE);
1539     #if 1
1540     // Execute full 68k interrupt routine
1541     M68kRegisters r;
1542     uint32 old_r25 = *(uint32 *)XLM_68K_R25; // Save interrupt level
1543     *(uint32 *)XLM_68K_R25 = 0x21; // Execute with interrupt level 1
1544     static const uint16 proc[] = {
1545     0x3f3c, 0x0000, // move.w #$0000,-(sp) (fake format word)
1546     0x487a, 0x000a, // pea @1(pc) (return address)
1547     0x40e7, // move sr,-(sp) (saved SR)
1548     0x2078, 0x0064, // move.l $64,a0
1549     0x4ed0, // jmp (a0)
1550     M68K_RTS // @1
1551     };
1552     Execute68k((uint32)proc, &r);
1553     *(uint32 *)XLM_68K_R25 = old_r25; // Restore interrupt level
1554     #else
1555     // Only update cursor
1556     if (HasMacStarted()) {
1557     if (InterruptFlags & INTFLAG_VIA) {
1558     ClearInterruptFlag(INTFLAG_VIA);
1559     ADBInterrupt();
1560     ExecutePPC(VideoVBL);
1561     }
1562     }
1563     #endif
1564     // Reset normal signal stack
1565     set_signal_stack(sig_stack, SIG_STACK_SIZE);
1566     }
1567     break;
1568     #endif
1569     }
1570     }
1571    
1572    
1573     /*
1574     * SIGSEGV handler
1575     */
1576    
1577     static uint32 segv_r[32];
1578    
1579     #if !EMULATED_PPC
1580     asm void SheepShaver::sigsegv_invoc(register int sig, register void *arg, register vregs *r)
1581     {
1582     mflr r0
1583     stw r0,8(r1)
1584     stwu r1,-56(r1)
1585    
1586     lwz r3,segv_r(r2)
1587     stmw r13,13*4(r3)
1588    
1589     mr r3,r5
1590     bl sigsegv_handler
1591    
1592     lwz r3,segv_r(r2)
1593     lmw r13,13*4(r3)
1594    
1595     lwz r0,56+8(r1)
1596     mtlr r0
1597     addi r1,r1,56
1598     blr
1599     }
1600     #endif
1601    
1602     static void sigsegv_handler(vregs *r)
1603     {
1604     char str[256];
1605    
1606     // Fetch volatile registers
1607     segv_r[0] = r->r0;
1608     segv_r[1] = r->r1;
1609     segv_r[2] = r->r2;
1610     segv_r[3] = r->r3;
1611     segv_r[4] = r->r4;
1612     segv_r[5] = r->r5;
1613     segv_r[6] = r->r6;
1614     segv_r[7] = r->r7;
1615     segv_r[8] = r->r8;
1616     segv_r[9] = r->r9;
1617     segv_r[10] = r->r10;
1618     segv_r[11] = r->r11;
1619     segv_r[12] = r->r12;
1620    
1621     // Get opcode and divide into fields
1622     uint32 opcode = *(uint32 *)r->pc;
1623     uint32 primop = opcode >> 26;
1624     uint32 exop = (opcode >> 1) & 0x3ff;
1625     uint32 ra = (opcode >> 16) & 0x1f;
1626     uint32 rb = (opcode >> 11) & 0x1f;
1627     uint32 rd = (opcode >> 21) & 0x1f;
1628     uint32 imm = opcode & 0xffff;
1629    
1630     // Fault in Mac ROM or RAM?
1631     bool mac_fault = (r->pc >= ROM_BASE) && (r->pc < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc >= RAMBase) && (r->pc < (RAMBase + RAMSize));
1632     if (mac_fault) {
1633    
1634     // "VM settings" during MacOS 8 installation
1635     if (r->pc == ROM_BASE + 0x488160 && segv_r[20] == 0xf8000000) {
1636     r->pc += 4;
1637     segv_r[8] = 0;
1638     goto rti;
1639    
1640     // MacOS 8.5 installation
1641     } else if (r->pc == ROM_BASE + 0x488140 && segv_r[16] == 0xf8000000) {
1642     r->pc += 4;
1643     segv_r[8] = 0;
1644     goto rti;
1645    
1646     // MacOS 8 serial drivers on startup
1647     } else if (r->pc == ROM_BASE + 0x48e080 && (segv_r[8] == 0xf3012002 || segv_r[8] == 0xf3012000)) {
1648     r->pc += 4;
1649     segv_r[8] = 0;
1650     goto rti;
1651    
1652     // MacOS 8.1 serial drivers on startup
1653     } else if (r->pc == ROM_BASE + 0x48c5e0 && (segv_r[20] == 0xf3012002 || segv_r[20] == 0xf3012000)) {
1654     r->pc += 4;
1655     goto rti;
1656     } else if (r->pc == ROM_BASE + 0x4a10a0 && (segv_r[20] == 0xf3012002 || segv_r[20] == 0xf3012000)) {
1657     r->pc += 4;
1658     goto rti;
1659     }
1660     }
1661    
1662     // Analyze opcode
1663     enum {
1664     TYPE_UNKNOWN,
1665     TYPE_LOAD,
1666     TYPE_STORE
1667     } transfer_type = TYPE_UNKNOWN;
1668     enum {
1669     SIZE_UNKNOWN,
1670     SIZE_BYTE,
1671     SIZE_HALFWORD,
1672     SIZE_WORD
1673     } transfer_size = SIZE_UNKNOWN;
1674     enum {
1675     MODE_UNKNOWN,
1676     MODE_NORM,
1677     MODE_U,
1678     MODE_X,
1679     MODE_UX
1680     } addr_mode = MODE_UNKNOWN;
1681     switch (primop) {
1682     case 31:
1683     switch (exop) {
1684     case 23: // lwzx
1685     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1686     case 55: // lwzux
1687     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1688     case 87: // lbzx
1689     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1690     case 119: // lbzux
1691     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1692     case 151: // stwx
1693     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1694     case 183: // stwux
1695     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1696     case 215: // stbx
1697     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1698     case 247: // stbux
1699     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1700     case 279: // lhzx
1701     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1702     case 311: // lhzux
1703     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1704     case 343: // lhax
1705     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1706     case 375: // lhaux
1707     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1708     case 407: // sthx
1709     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1710     case 439: // sthux
1711     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1712     }
1713     break;
1714    
1715     case 32: // lwz
1716     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1717     case 33: // lwzu
1718     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1719     case 34: // lbz
1720     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1721     case 35: // lbzu
1722     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1723     case 36: // stw
1724     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1725     case 37: // stwu
1726     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1727     case 38: // stb
1728     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1729     case 39: // stbu
1730     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1731     case 40: // lhz
1732     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1733     case 41: // lhzu
1734     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1735     case 42: // lha
1736     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1737     case 43: // lhau
1738     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1739     case 44: // sth
1740     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1741     case 45: // sthu
1742     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1743     }
1744    
1745     // Calculate effective address
1746     uint32 addr = 0;
1747     switch (addr_mode) {
1748     case MODE_X:
1749     case MODE_UX:
1750     if (ra == 0)
1751     addr = segv_r[rb];
1752     else
1753     addr = segv_r[ra] + segv_r[rb];
1754     break;
1755     case MODE_NORM:
1756     case MODE_U:
1757     if (ra == 0)
1758     addr = (int32)(int16)imm;
1759     else
1760     addr = segv_r[ra] + (int32)(int16)imm;
1761     break;
1762     default:
1763     break;
1764     }
1765    
1766     // Ignore ROM writes
1767     if (transfer_type == TYPE_STORE && addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) {
1768     D(bug("WARNING: %s write access to ROM at %p, pc %p\n", transfer_size == SIZE_BYTE ? "Byte" : transfer_size == SIZE_HALFWORD ? "Halfword" : "Word", addr, r->pc));
1769     if (addr_mode == MODE_U || addr_mode == MODE_UX)
1770     segv_r[ra] = addr;
1771     r->pc += 4;
1772     goto rti;
1773     }
1774    
1775     // Fault in Mac ROM or RAM?
1776     if (mac_fault) {
1777    
1778     // Ignore illegal memory accesses?
1779     if (PrefsFindBool("ignoresegv")) {
1780     if (addr_mode == MODE_U || addr_mode == MODE_UX)
1781     segv_r[ra] = addr;
1782     if (transfer_type == TYPE_LOAD)
1783     segv_r[rd] = 0;
1784     r->pc += 4;
1785     goto rti;
1786     }
1787    
1788     // In GUI mode, show error alert
1789     if (!PrefsFindBool("nogui")) {
1790     if (transfer_type == TYPE_LOAD || transfer_type == TYPE_STORE)
1791     sprintf(str, GetString(STR_MEM_ACCESS_ERR), transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_HALFWORD ? "halfword" : "word", transfer_type == TYPE_LOAD ? GetString(STR_MEM_ACCESS_READ) : GetString(STR_MEM_ACCESS_WRITE), addr, r->pc, segv_r[24], segv_r[1]);
1792     else
1793     sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc, segv_r[24], segv_r[1], opcode);
1794     ErrorAlert(str);
1795     QuitEmulator();
1796     return;
1797     }
1798     }
1799    
1800     // For all other errors, jump into debugger
1801     sprintf(str, "SIGSEGV\n"
1802     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
1803     " xer %08lx cr %08lx fpscr %08lx\n"
1804     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
1805     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
1806     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
1807     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
1808     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
1809     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
1810     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
1811     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
1812     r->pc, r->lr, r->ctr, r->msr,
1813     r->xer, r->cr, r->fpscr,
1814     r->r0, r->r1, r->r2, r->r3,
1815     r->r4, r->r5, r->r6, r->r7,
1816     r->r8, r->r9, r->r10, r->r11,
1817     r->r12, segv_r[13], segv_r[14], segv_r[15],
1818     segv_r[16], segv_r[17], segv_r[18], segv_r[19],
1819     segv_r[20], segv_r[21], segv_r[22], segv_r[23],
1820     segv_r[24], segv_r[25], segv_r[26], segv_r[27],
1821     segv_r[28], segv_r[29], segv_r[30], segv_r[31]);
1822     VideoQuitFullScreen();
1823     disable_debugger(false);
1824     debugger(str);
1825     exit(1);
1826     return;
1827    
1828     rti:
1829     // Restore volatile registers
1830     r->r0 = segv_r[0];
1831     r->r1 = segv_r[1];
1832     r->r2 = segv_r[2];
1833     r->r3 = segv_r[3];
1834     r->r4 = segv_r[4];
1835     r->r5 = segv_r[5];
1836     r->r6 = segv_r[6];
1837     r->r7 = segv_r[7];
1838     r->r8 = segv_r[8];
1839     r->r9 = segv_r[9];
1840     r->r10 = segv_r[10];
1841     r->r11 = segv_r[11];
1842     r->r12 = segv_r[12];
1843     }
1844    
1845    
1846     /*
1847     * SIGILL handler
1848     */
1849    
1850     #if !EMULATED_PPC
1851     asm void SheepShaver::sigill_invoc(register int sig, register void *arg, register vregs *r)
1852     {
1853     mflr r0
1854     stw r0,8(r1)
1855     stwu r1,-56(r1)
1856    
1857     lwz r3,segv_r(r2)
1858     stmw r13,13*4(r3)
1859    
1860     mr r3,r5
1861     bl sigill_handler
1862    
1863     lwz r3,segv_r(r2)
1864     lmw r13,13*4(r3)
1865    
1866     lwz r0,56+8(r1)
1867     mtlr r0
1868     addi r1,r1,56
1869     blr
1870     }
1871     #endif
1872    
1873     static void sigill_handler(vregs *r)
1874     {
1875     char str[256];
1876    
1877     // Fetch volatile registers
1878     segv_r[0] = r->r0;
1879     segv_r[1] = r->r1;
1880     segv_r[2] = r->r2;
1881     segv_r[3] = r->r3;
1882     segv_r[4] = r->r4;
1883     segv_r[5] = r->r5;
1884     segv_r[6] = r->r6;
1885     segv_r[7] = r->r7;
1886     segv_r[8] = r->r8;
1887     segv_r[9] = r->r9;
1888     segv_r[10] = r->r10;
1889     segv_r[11] = r->r11;
1890     segv_r[12] = r->r12;
1891    
1892     // Get opcode and divide into fields
1893     uint32 opcode = *(uint32 *)r->pc;
1894     uint32 primop = opcode >> 26;
1895     uint32 exop = (opcode >> 1) & 0x3ff;
1896     uint32 ra = (opcode >> 16) & 0x1f;
1897     uint32 rb = (opcode >> 11) & 0x1f;
1898     uint32 rd = (opcode >> 21) & 0x1f;
1899     uint32 imm = opcode & 0xffff;
1900    
1901     // Fault in Mac ROM or RAM?
1902     bool mac_fault = (r->pc >= ROM_BASE) && (r->pc < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc >= RAMBase) && (r->pc < (RAMBase + RAMSize));
1903     if (mac_fault) {
1904    
1905     switch (primop) {
1906     case 9: // POWER instructions
1907     case 22:
1908     power_inst: sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->pc, segv_r[1], opcode);
1909     ErrorAlert(str);
1910     QuitEmulator();
1911     return;
1912    
1913     case 31:
1914     switch (exop) {
1915     case 83: // mfmsr
1916     segv_r[rd] = 0xf072;
1917     r->pc += 4;
1918     goto rti;
1919    
1920     case 210: // mtsr
1921     case 242: // mtsrin
1922     case 306: // tlbie
1923     r->pc += 4;
1924     goto rti;
1925    
1926     case 339: { // mfspr
1927     int spr = ra | (rb << 5);
1928     switch (spr) {
1929     case 0: // MQ
1930     case 22: // DEC
1931     case 952: // MMCR0
1932     case 953: // PMC1
1933     case 954: // PMC2
1934     case 955: // SIA
1935     case 956: // MMCR1
1936     case 957: // PMC3
1937     case 958: // PMC4
1938     case 959: // SDA
1939     r->pc += 4;
1940     goto rti;
1941     case 25: // SDR1
1942     segv_r[rd] = 0xdead001f;
1943     r->pc += 4;
1944     goto rti;
1945     case 287: // PVR
1946     segv_r[rd] = PVR;
1947     r->pc += 4;
1948     goto rti;
1949     }
1950     break;
1951     }
1952    
1953     case 467: { // mtspr
1954     int spr = ra | (rb << 5);
1955     switch (spr) {
1956     case 0: // MQ
1957     case 22: // DEC
1958     case 275: // SPRG3
1959     case 528: // IBAT0U
1960     case 529: // IBAT0L
1961     case 530: // IBAT1U
1962     case 531: // IBAT1L
1963     case 532: // IBAT2U
1964     case 533: // IBAT2L
1965     case 534: // IBAT3U
1966     case 535: // IBAT3L
1967     case 536: // DBAT0U
1968     case 537: // DBAT0L
1969     case 538: // DBAT1U
1970     case 539: // DBAT1L
1971     case 540: // DBAT2U
1972     case 541: // DBAT2L
1973     case 542: // DBAT3U
1974     case 543: // DBAT3L
1975     case 952: // MMCR0
1976     case 953: // PMC1
1977     case 954: // PMC2
1978     case 955: // SIA
1979     case 956: // MMCR1
1980     case 957: // PMC3
1981     case 958: // PMC4
1982     case 959: // SDA
1983     r->pc += 4;
1984     goto rti;
1985     }
1986     break;
1987     }
1988    
1989     case 29: case 107: case 152: case 153: // POWER instructions
1990     case 184: case 216: case 217: case 248:
1991     case 264: case 277: case 331: case 360:
1992     case 363: case 488: case 531: case 537:
1993     case 541: case 664: case 665: case 696:
1994     case 728: case 729: case 760: case 920:
1995     case 921: case 952:
1996     goto power_inst;
1997     }
1998     }
1999    
2000     // In GUI mode, show error alert
2001     if (!PrefsFindBool("nogui")) {
2002     sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc, segv_r[24], segv_r[1], opcode);
2003     ErrorAlert(str);
2004     QuitEmulator();
2005     return;
2006     }
2007     }
2008    
2009     // For all other errors, jump into debugger
2010     sprintf(str, "SIGILL\n"
2011     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
2012     " xer %08lx cr %08lx fpscr %08lx\n"
2013     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
2014     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
2015     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
2016     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
2017     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
2018     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
2019     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
2020     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
2021     r->pc, r->lr, r->ctr, r->msr,
2022     r->xer, r->cr, r->fpscr,
2023     r->r0, r->r1, r->r2, r->r3,
2024     r->r4, r->r5, r->r6, r->r7,
2025     r->r8, r->r9, r->r10, r->r11,
2026     r->r12, segv_r[13], segv_r[14], segv_r[15],
2027     segv_r[16], segv_r[17], segv_r[18], segv_r[19],
2028     segv_r[20], segv_r[21], segv_r[22], segv_r[23],
2029     segv_r[24], segv_r[25], segv_r[26], segv_r[27],
2030     segv_r[28], segv_r[29], segv_r[30], segv_r[31]);
2031     VideoQuitFullScreen();
2032     disable_debugger(false);
2033     debugger(str);
2034     exit(1);
2035     return;
2036    
2037     rti:
2038     // Restore volatile registers
2039     r->r0 = segv_r[0];
2040     r->r1 = segv_r[1];
2041     r->r2 = segv_r[2];
2042     r->r3 = segv_r[3];
2043     r->r4 = segv_r[4];
2044     r->r5 = segv_r[5];
2045     r->r6 = segv_r[6];
2046     r->r7 = segv_r[7];
2047     r->r8 = segv_r[8];
2048     r->r9 = segv_r[9];
2049     r->r10 = segv_r[10];
2050     r->r11 = segv_r[11];
2051     r->r12 = segv_r[12];
2052     }
2053    
2054    
2055     /*
2056     * Display error alert
2057     */
2058    
2059     void ErrorAlert(const char *text)
2060     {
2061     if (PrefsFindBool("nogui")) {
2062     printf(GetString(STR_SHELL_ERROR_PREFIX), text);
2063     return;
2064     }
2065     char str[256];
2066     sprintf(str, GetString(STR_GUI_ERROR_PREFIX), text);
2067     VideoQuitFullScreen();
2068     BAlert *alert = new BAlert(GetString(STR_ERROR_ALERT_TITLE), str, GetString(STR_QUIT_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
2069     alert->Go();
2070     }
2071    
2072    
2073     /*
2074     * Display warning alert
2075     */
2076    
2077     void WarningAlert(const char *text)
2078     {
2079     if (PrefsFindBool("nogui")) {
2080     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
2081     return;
2082     }
2083     char str[256];
2084     sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
2085     BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, GetString(STR_OK_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
2086     alert->Go();
2087     }
2088    
2089    
2090     /*
2091     * Display choice alert
2092     */
2093    
2094     bool ChoiceAlert(const char *text, const char *pos, const char *neg)
2095     {
2096     char str[256];
2097     sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
2098     BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, pos, neg, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
2099     return alert->Go() == 0;
2100     }