ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.7
Committed: 2003-12-04T23:37:35Z (21 years ago) by gbeauche
Branch: MAIN
Changes since 1.6: +2 -14 lines
Log Message:
Use a unique ExecuteNative() interface in any case, i.e. native & emulated

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