ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.1
Committed: 2002-02-04T16:58:13Z (22 years, 4 months ago) by cebix
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

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