ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.5
Committed: 2003-12-04T17:26:36Z (20 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.4: +52 -1 lines
Log Message:
Add new thunking system for 64-bit fixes.

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     * Execute PPC code from EMUL_OP routine (real mode switch)
1269     */
1270    
1271     void ExecutePPC(void (*func)())
1272     {
1273 gbeauche 1.5 SheepRoutineDescriptor desc(0, (uint32)func);
1274 cebix 1.1 M68kRegisters r;
1275     Execute68k((uint32)&desc, &r);
1276     }
1277    
1278    
1279     /*
1280     * Quit emulator (must only be called from main thread)
1281     */
1282    
1283     asm void QuitEmulator(void)
1284     {
1285     lwz r0,XLM_EMUL_RETURN_PROC
1286     mtlr r0
1287     blr
1288     }
1289     #endif
1290    
1291    
1292     /*
1293     * Dump 68k registers
1294     */
1295    
1296     void Dump68kRegs(M68kRegisters *r)
1297     {
1298     // Display 68k registers
1299     for (int i=0; i<8; i++) {
1300     printf("d%d: %08lx", i, r->d[i]);
1301     if (i == 3 || i == 7)
1302     printf("\n");
1303     else
1304     printf(", ");
1305     }
1306     for (int i=0; i<8; i++) {
1307     printf("a%d: %08lx", i, r->a[i]);
1308     if (i == 3 || i == 7)
1309     printf("\n");
1310     else
1311     printf(", ");
1312     }
1313     }
1314    
1315    
1316     /*
1317     * Make code executable
1318     */
1319    
1320     void MakeExecutable(int dummy, void *start, uint32 length)
1321     {
1322     if (((uint32)start >= ROM_BASE) && ((uint32)start < (ROM_BASE + ROM_SIZE)))
1323     return;
1324     clear_caches(start, length, B_INVALIDATE_ICACHE | B_FLUSH_DCACHE);
1325     }
1326    
1327    
1328     /*
1329     * Patch things after system startup (gets called by disk driver accRun routine)
1330     */
1331    
1332     void PatchAfterStartup(void)
1333     {
1334     ExecutePPC(VideoInstallAccel);
1335     InstallExtFS();
1336     }
1337    
1338    
1339     /*
1340     * NVRAM watchdog thread (saves NVRAM every minute)
1341     */
1342    
1343 cebix 1.4 status_t SheepShaver::nvram_func(void *arg)
1344 cebix 1.1 {
1345     SheepShaver *obj = (SheepShaver *)arg;
1346    
1347     while (obj->NVRAMThreadActive) {
1348     snooze(60*1000000);
1349     if (memcmp(obj->last_xpram, XPRAM, XPRAM_SIZE)) {
1350     memcpy(obj->last_xpram, XPRAM, XPRAM_SIZE);
1351     SaveXPRAM();
1352     }
1353     }
1354     return 0;
1355     }
1356    
1357    
1358     /*
1359     * 60Hz thread (really 60.15Hz)
1360     */
1361    
1362     status_t SheepShaver::tick_func(void *arg)
1363     {
1364     SheepShaver *obj = (SheepShaver *)arg;
1365     int tick_counter = 0;
1366     bigtime_t current = system_time();
1367    
1368     while (obj->TickThreadActive) {
1369    
1370     // Wait
1371     current += 16625;
1372     snooze_until(current, B_SYSTEM_TIMEBASE);
1373    
1374     // Pseudo Mac 1Hz interrupt, update local time
1375     if (++tick_counter > 60) {
1376     tick_counter = 0;
1377     WriteMacInt32(0x20c, TimerDateTime());
1378     }
1379    
1380     // 60Hz interrupt
1381     if (ReadMacInt32(XLM_IRQ_NEST) == 0) {
1382     SetInterruptFlag(INTFLAG_VIA);
1383     TriggerInterrupt();
1384     }
1385     }
1386     return 0;
1387     }
1388    
1389    
1390     /*
1391     * Trigger signal USR1 from another thread
1392     */
1393    
1394     void TriggerInterrupt(void)
1395     {
1396     #if 0
1397     WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
1398     #else
1399     if (the_app->emul_thread > 0 && the_app->ReadyForSignals)
1400     send_signal(the_app->emul_thread, SIGUSR1);
1401     #endif
1402     }
1403    
1404    
1405     /*
1406     * Mutexes
1407     */
1408    
1409     struct B2_mutex {
1410     int dummy; //!!
1411     };
1412    
1413     B2_mutex *B2_create_mutex(void)
1414     {
1415     return new B2_mutex;
1416     }
1417    
1418     void B2_lock_mutex(B2_mutex *mutex)
1419     {
1420     }
1421    
1422     void B2_unlock_mutex(B2_mutex *mutex)
1423     {
1424     }
1425    
1426     void B2_delete_mutex(B2_mutex *mutex)
1427     {
1428     delete mutex;
1429     }
1430    
1431    
1432     /*
1433     * Set/clear interrupt flags (must be done atomically!)
1434     */
1435    
1436     volatile uint32 InterruptFlags = 0;
1437    
1438     void SetInterruptFlag(uint32 flag)
1439     {
1440     atomic_or((int32 *)&InterruptFlags, flag);
1441     }
1442    
1443     void ClearInterruptFlag(uint32 flag)
1444     {
1445     atomic_and((int32 *)&InterruptFlags, ~flag);
1446     }
1447    
1448    
1449     /*
1450     * Disable interrupts
1451     */
1452    
1453     void DisableInterrupt(void)
1454     {
1455     atomic_add((int32 *)XLM_IRQ_NEST, 1);
1456     }
1457    
1458    
1459     /*
1460     * Enable interrupts
1461     */
1462    
1463     void EnableInterrupt(void)
1464     {
1465     atomic_add((int32 *)XLM_IRQ_NEST, -1);
1466     }
1467    
1468    
1469     /*
1470     * USR1 handler
1471     */
1472    
1473     void SheepShaver::sigusr1_invoc(int sig, void *arg, vregs *r)
1474     {
1475     ((SheepShaver *)arg)->sigusr1_handler(r);
1476     }
1477    
1478     #if !EMULATED_PPC
1479     static asm void ppc_interrupt(register uint32 entry)
1480     {
1481     fralloc
1482    
1483     // Get address of return routine
1484     bl @1
1485    
1486     // Return routine
1487     frfree
1488     blr
1489    
1490     @1
1491     // Prepare registers for nanokernel interrupt routine
1492     mtctr r1
1493     lwz r1,XLM_KERNEL_DATA
1494     stw r6,0x018(r1)
1495     mfctr r6
1496     stw r6,0x004(r1)
1497     lwz r6,0x65c(r1)
1498     stw r7,0x13c(r6)
1499     stw r8,0x144(r6)
1500     stw r9,0x14c(r6)
1501     stw r10,0x154(r6)
1502     stw r11,0x15c(r6)
1503     stw r12,0x164(r6)
1504     stw r13,0x16c(r6)
1505    
1506     mflr r10
1507     mfcr r13
1508     lwz r7,0x660(r1)
1509     mflr r12
1510     rlwimi. r7,r7,8,0,0
1511     li r11,0
1512     ori r11,r11,0xf072 // MSR (SRR1)
1513     mtcrf 0x70,r11
1514     li r8,0
1515    
1516     // Enter nanokernel
1517     mtlr r3
1518     blr
1519     }
1520     #endif
1521    
1522     void SheepShaver::sigusr1_handler(vregs *r)
1523     {
1524     // Do nothing if interrupts are disabled
1525     if ((*(int32 *)XLM_IRQ_NEST) > 0)
1526     return;
1527    
1528     // Interrupt action depends on current run mode
1529     switch (*(uint32 *)XLM_RUN_MODE) {
1530     case MODE_68K:
1531     // 68k emulator active, trigger 68k interrupt level 1
1532     *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1;
1533     r->cr |= kernel_data->v[0x674 >> 2];
1534     break;
1535    
1536     #if INTERRUPTS_IN_NATIVE_MODE
1537     case MODE_NATIVE:
1538     // 68k emulator inactive, in nanokernel?
1539     if (r->r1 != KernelDataAddr) {
1540     // No, prepare for 68k interrupt level 1
1541     *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1;
1542     *(uint32 *)(kernel_data->v[0x658 >> 2] + 0xdc) |= kernel_data->v[0x674 >> 2];
1543    
1544     // Execute nanokernel interrupt routine (this will activate the 68k emulator)
1545     atomic_add((int32 *)XLM_IRQ_NEST, 1);
1546     if (ROMType == ROMTYPE_NEWWORLD)
1547     ppc_interrupt(ROM_BASE + 0x312b1c);
1548     else
1549     ppc_interrupt(ROM_BASE + 0x312a3c);
1550     }
1551     break;
1552     #endif
1553    
1554     #if INTERRUPTS_IN_EMUL_OP_MODE
1555     case MODE_EMUL_OP:
1556     // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
1557     if ((*(uint32 *)XLM_68K_R25 & 7) == 0) {
1558    
1559     // Set extra stack for SIGSEGV handler
1560     set_signal_stack(extra_stack, SIG_STACK_SIZE);
1561     #if 1
1562     // Execute full 68k interrupt routine
1563     M68kRegisters r;
1564     uint32 old_r25 = *(uint32 *)XLM_68K_R25; // Save interrupt level
1565     *(uint32 *)XLM_68K_R25 = 0x21; // Execute with interrupt level 1
1566     static const uint16 proc[] = {
1567     0x3f3c, 0x0000, // move.w #$0000,-(sp) (fake format word)
1568     0x487a, 0x000a, // pea @1(pc) (return address)
1569     0x40e7, // move sr,-(sp) (saved SR)
1570     0x2078, 0x0064, // move.l $64,a0
1571     0x4ed0, // jmp (a0)
1572     M68K_RTS // @1
1573     };
1574     Execute68k((uint32)proc, &r);
1575     *(uint32 *)XLM_68K_R25 = old_r25; // Restore interrupt level
1576     #else
1577     // Only update cursor
1578     if (HasMacStarted()) {
1579     if (InterruptFlags & INTFLAG_VIA) {
1580     ClearInterruptFlag(INTFLAG_VIA);
1581     ADBInterrupt();
1582     ExecutePPC(VideoVBL);
1583     }
1584     }
1585     #endif
1586     // Reset normal signal stack
1587     set_signal_stack(sig_stack, SIG_STACK_SIZE);
1588     }
1589     break;
1590     #endif
1591     }
1592     }
1593    
1594    
1595     /*
1596     * SIGSEGV handler
1597     */
1598    
1599     static uint32 segv_r[32];
1600    
1601     #if !EMULATED_PPC
1602     asm void SheepShaver::sigsegv_invoc(register int sig, register void *arg, register vregs *r)
1603     {
1604     mflr r0
1605     stw r0,8(r1)
1606     stwu r1,-56(r1)
1607    
1608     lwz r3,segv_r(r2)
1609     stmw r13,13*4(r3)
1610    
1611     mr r3,r5
1612     bl sigsegv_handler
1613    
1614     lwz r3,segv_r(r2)
1615     lmw r13,13*4(r3)
1616    
1617     lwz r0,56+8(r1)
1618     mtlr r0
1619     addi r1,r1,56
1620     blr
1621     }
1622     #endif
1623    
1624     static void sigsegv_handler(vregs *r)
1625     {
1626     char str[256];
1627    
1628     // Fetch volatile registers
1629     segv_r[0] = r->r0;
1630     segv_r[1] = r->r1;
1631     segv_r[2] = r->r2;
1632     segv_r[3] = r->r3;
1633     segv_r[4] = r->r4;
1634     segv_r[5] = r->r5;
1635     segv_r[6] = r->r6;
1636     segv_r[7] = r->r7;
1637     segv_r[8] = r->r8;
1638     segv_r[9] = r->r9;
1639     segv_r[10] = r->r10;
1640     segv_r[11] = r->r11;
1641     segv_r[12] = r->r12;
1642    
1643     // Get opcode and divide into fields
1644     uint32 opcode = *(uint32 *)r->pc;
1645     uint32 primop = opcode >> 26;
1646     uint32 exop = (opcode >> 1) & 0x3ff;
1647     uint32 ra = (opcode >> 16) & 0x1f;
1648     uint32 rb = (opcode >> 11) & 0x1f;
1649     uint32 rd = (opcode >> 21) & 0x1f;
1650     uint32 imm = opcode & 0xffff;
1651    
1652     // Fault in Mac ROM or RAM?
1653     bool mac_fault = (r->pc >= ROM_BASE) && (r->pc < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc >= RAMBase) && (r->pc < (RAMBase + RAMSize));
1654     if (mac_fault) {
1655    
1656     // "VM settings" during MacOS 8 installation
1657     if (r->pc == ROM_BASE + 0x488160 && segv_r[20] == 0xf8000000) {
1658     r->pc += 4;
1659     segv_r[8] = 0;
1660     goto rti;
1661    
1662     // MacOS 8.5 installation
1663     } else if (r->pc == ROM_BASE + 0x488140 && segv_r[16] == 0xf8000000) {
1664     r->pc += 4;
1665     segv_r[8] = 0;
1666     goto rti;
1667    
1668     // MacOS 8 serial drivers on startup
1669     } else if (r->pc == ROM_BASE + 0x48e080 && (segv_r[8] == 0xf3012002 || segv_r[8] == 0xf3012000)) {
1670     r->pc += 4;
1671     segv_r[8] = 0;
1672     goto rti;
1673    
1674     // MacOS 8.1 serial drivers on startup
1675     } else if (r->pc == ROM_BASE + 0x48c5e0 && (segv_r[20] == 0xf3012002 || segv_r[20] == 0xf3012000)) {
1676     r->pc += 4;
1677     goto rti;
1678     } else if (r->pc == ROM_BASE + 0x4a10a0 && (segv_r[20] == 0xf3012002 || segv_r[20] == 0xf3012000)) {
1679     r->pc += 4;
1680     goto rti;
1681     }
1682     }
1683    
1684     // Analyze opcode
1685     enum {
1686     TYPE_UNKNOWN,
1687     TYPE_LOAD,
1688     TYPE_STORE
1689     } transfer_type = TYPE_UNKNOWN;
1690     enum {
1691     SIZE_UNKNOWN,
1692     SIZE_BYTE,
1693     SIZE_HALFWORD,
1694     SIZE_WORD
1695     } transfer_size = SIZE_UNKNOWN;
1696     enum {
1697     MODE_UNKNOWN,
1698     MODE_NORM,
1699     MODE_U,
1700     MODE_X,
1701     MODE_UX
1702     } addr_mode = MODE_UNKNOWN;
1703     switch (primop) {
1704     case 31:
1705     switch (exop) {
1706     case 23: // lwzx
1707     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1708     case 55: // lwzux
1709     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1710     case 87: // lbzx
1711     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1712     case 119: // lbzux
1713     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1714     case 151: // stwx
1715     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1716     case 183: // stwux
1717     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1718     case 215: // stbx
1719     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1720     case 247: // stbux
1721     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1722     case 279: // lhzx
1723     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1724     case 311: // lhzux
1725     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1726     case 343: // lhax
1727     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1728     case 375: // lhaux
1729     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1730     case 407: // sthx
1731     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1732     case 439: // sthux
1733     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1734     }
1735     break;
1736    
1737     case 32: // lwz
1738     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1739     case 33: // lwzu
1740     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1741     case 34: // lbz
1742     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1743     case 35: // lbzu
1744     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1745     case 36: // stw
1746     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1747     case 37: // stwu
1748     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1749     case 38: // stb
1750     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1751     case 39: // stbu
1752     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1753     case 40: // lhz
1754     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1755     case 41: // lhzu
1756     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1757     case 42: // lha
1758     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1759     case 43: // lhau
1760     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1761     case 44: // sth
1762     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1763     case 45: // sthu
1764     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1765     }
1766    
1767     // Calculate effective address
1768     uint32 addr = 0;
1769     switch (addr_mode) {
1770     case MODE_X:
1771     case MODE_UX:
1772     if (ra == 0)
1773     addr = segv_r[rb];
1774     else
1775     addr = segv_r[ra] + segv_r[rb];
1776     break;
1777     case MODE_NORM:
1778     case MODE_U:
1779     if (ra == 0)
1780     addr = (int32)(int16)imm;
1781     else
1782     addr = segv_r[ra] + (int32)(int16)imm;
1783     break;
1784     default:
1785     break;
1786     }
1787    
1788     // Ignore ROM writes
1789     if (transfer_type == TYPE_STORE && addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) {
1790     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));
1791     if (addr_mode == MODE_U || addr_mode == MODE_UX)
1792     segv_r[ra] = addr;
1793     r->pc += 4;
1794     goto rti;
1795     }
1796    
1797     // Fault in Mac ROM or RAM?
1798     if (mac_fault) {
1799    
1800     // Ignore illegal memory accesses?
1801     if (PrefsFindBool("ignoresegv")) {
1802     if (addr_mode == MODE_U || addr_mode == MODE_UX)
1803     segv_r[ra] = addr;
1804     if (transfer_type == TYPE_LOAD)
1805     segv_r[rd] = 0;
1806     r->pc += 4;
1807     goto rti;
1808     }
1809    
1810     // In GUI mode, show error alert
1811     if (!PrefsFindBool("nogui")) {
1812     if (transfer_type == TYPE_LOAD || transfer_type == TYPE_STORE)
1813     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]);
1814     else
1815     sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc, segv_r[24], segv_r[1], opcode);
1816     ErrorAlert(str);
1817     QuitEmulator();
1818     return;
1819     }
1820     }
1821    
1822     // For all other errors, jump into debugger
1823     sprintf(str, "SIGSEGV\n"
1824     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
1825     " xer %08lx cr %08lx fpscr %08lx\n"
1826     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
1827     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
1828     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
1829     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
1830     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
1831     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
1832     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
1833     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
1834     r->pc, r->lr, r->ctr, r->msr,
1835     r->xer, r->cr, r->fpscr,
1836     r->r0, r->r1, r->r2, r->r3,
1837     r->r4, r->r5, r->r6, r->r7,
1838     r->r8, r->r9, r->r10, r->r11,
1839     r->r12, segv_r[13], segv_r[14], segv_r[15],
1840     segv_r[16], segv_r[17], segv_r[18], segv_r[19],
1841     segv_r[20], segv_r[21], segv_r[22], segv_r[23],
1842     segv_r[24], segv_r[25], segv_r[26], segv_r[27],
1843     segv_r[28], segv_r[29], segv_r[30], segv_r[31]);
1844     VideoQuitFullScreen();
1845     disable_debugger(false);
1846     debugger(str);
1847     exit(1);
1848     return;
1849    
1850     rti:
1851     // Restore volatile registers
1852     r->r0 = segv_r[0];
1853     r->r1 = segv_r[1];
1854     r->r2 = segv_r[2];
1855     r->r3 = segv_r[3];
1856     r->r4 = segv_r[4];
1857     r->r5 = segv_r[5];
1858     r->r6 = segv_r[6];
1859     r->r7 = segv_r[7];
1860     r->r8 = segv_r[8];
1861     r->r9 = segv_r[9];
1862     r->r10 = segv_r[10];
1863     r->r11 = segv_r[11];
1864     r->r12 = segv_r[12];
1865     }
1866    
1867    
1868     /*
1869     * SIGILL handler
1870     */
1871    
1872     #if !EMULATED_PPC
1873     asm void SheepShaver::sigill_invoc(register int sig, register void *arg, register vregs *r)
1874     {
1875     mflr r0
1876     stw r0,8(r1)
1877     stwu r1,-56(r1)
1878    
1879     lwz r3,segv_r(r2)
1880     stmw r13,13*4(r3)
1881    
1882     mr r3,r5
1883     bl sigill_handler
1884    
1885     lwz r3,segv_r(r2)
1886     lmw r13,13*4(r3)
1887    
1888     lwz r0,56+8(r1)
1889     mtlr r0
1890     addi r1,r1,56
1891     blr
1892     }
1893     #endif
1894    
1895     static void sigill_handler(vregs *r)
1896     {
1897     char str[256];
1898    
1899     // Fetch volatile registers
1900     segv_r[0] = r->r0;
1901     segv_r[1] = r->r1;
1902     segv_r[2] = r->r2;
1903     segv_r[3] = r->r3;
1904     segv_r[4] = r->r4;
1905     segv_r[5] = r->r5;
1906     segv_r[6] = r->r6;
1907     segv_r[7] = r->r7;
1908     segv_r[8] = r->r8;
1909     segv_r[9] = r->r9;
1910     segv_r[10] = r->r10;
1911     segv_r[11] = r->r11;
1912     segv_r[12] = r->r12;
1913    
1914     // Get opcode and divide into fields
1915     uint32 opcode = *(uint32 *)r->pc;
1916     uint32 primop = opcode >> 26;
1917     uint32 exop = (opcode >> 1) & 0x3ff;
1918     uint32 ra = (opcode >> 16) & 0x1f;
1919     uint32 rb = (opcode >> 11) & 0x1f;
1920     uint32 rd = (opcode >> 21) & 0x1f;
1921     uint32 imm = opcode & 0xffff;
1922    
1923     // Fault in Mac ROM or RAM?
1924     bool mac_fault = (r->pc >= ROM_BASE) && (r->pc < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc >= RAMBase) && (r->pc < (RAMBase + RAMSize));
1925     if (mac_fault) {
1926    
1927     switch (primop) {
1928     case 9: // POWER instructions
1929     case 22:
1930     power_inst: sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->pc, segv_r[1], opcode);
1931     ErrorAlert(str);
1932     QuitEmulator();
1933     return;
1934    
1935     case 31:
1936     switch (exop) {
1937     case 83: // mfmsr
1938     segv_r[rd] = 0xf072;
1939     r->pc += 4;
1940     goto rti;
1941    
1942     case 210: // mtsr
1943     case 242: // mtsrin
1944     case 306: // tlbie
1945     r->pc += 4;
1946     goto rti;
1947    
1948     case 339: { // mfspr
1949     int spr = ra | (rb << 5);
1950     switch (spr) {
1951     case 0: // MQ
1952     case 22: // DEC
1953     case 952: // MMCR0
1954     case 953: // PMC1
1955     case 954: // PMC2
1956     case 955: // SIA
1957     case 956: // MMCR1
1958     case 957: // PMC3
1959     case 958: // PMC4
1960     case 959: // SDA
1961     r->pc += 4;
1962     goto rti;
1963     case 25: // SDR1
1964     segv_r[rd] = 0xdead001f;
1965     r->pc += 4;
1966     goto rti;
1967     case 287: // PVR
1968     segv_r[rd] = PVR;
1969     r->pc += 4;
1970     goto rti;
1971     }
1972     break;
1973     }
1974    
1975     case 467: { // mtspr
1976     int spr = ra | (rb << 5);
1977     switch (spr) {
1978     case 0: // MQ
1979     case 22: // DEC
1980     case 275: // SPRG3
1981     case 528: // IBAT0U
1982     case 529: // IBAT0L
1983     case 530: // IBAT1U
1984     case 531: // IBAT1L
1985     case 532: // IBAT2U
1986     case 533: // IBAT2L
1987     case 534: // IBAT3U
1988     case 535: // IBAT3L
1989     case 536: // DBAT0U
1990     case 537: // DBAT0L
1991     case 538: // DBAT1U
1992     case 539: // DBAT1L
1993     case 540: // DBAT2U
1994     case 541: // DBAT2L
1995     case 542: // DBAT3U
1996     case 543: // DBAT3L
1997     case 952: // MMCR0
1998     case 953: // PMC1
1999     case 954: // PMC2
2000     case 955: // SIA
2001     case 956: // MMCR1
2002     case 957: // PMC3
2003     case 958: // PMC4
2004     case 959: // SDA
2005     r->pc += 4;
2006     goto rti;
2007     }
2008     break;
2009     }
2010    
2011     case 29: case 107: case 152: case 153: // POWER instructions
2012     case 184: case 216: case 217: case 248:
2013     case 264: case 277: case 331: case 360:
2014     case 363: case 488: case 531: case 537:
2015     case 541: case 664: case 665: case 696:
2016     case 728: case 729: case 760: case 920:
2017     case 921: case 952:
2018     goto power_inst;
2019     }
2020     }
2021    
2022     // In GUI mode, show error alert
2023     if (!PrefsFindBool("nogui")) {
2024     sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc, segv_r[24], segv_r[1], opcode);
2025     ErrorAlert(str);
2026     QuitEmulator();
2027     return;
2028     }
2029     }
2030    
2031     // For all other errors, jump into debugger
2032     sprintf(str, "SIGILL\n"
2033     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
2034     " xer %08lx cr %08lx fpscr %08lx\n"
2035     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
2036     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
2037     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
2038     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
2039     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
2040     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
2041     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
2042     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
2043     r->pc, r->lr, r->ctr, r->msr,
2044     r->xer, r->cr, r->fpscr,
2045     r->r0, r->r1, r->r2, r->r3,
2046     r->r4, r->r5, r->r6, r->r7,
2047     r->r8, r->r9, r->r10, r->r11,
2048     r->r12, segv_r[13], segv_r[14], segv_r[15],
2049     segv_r[16], segv_r[17], segv_r[18], segv_r[19],
2050     segv_r[20], segv_r[21], segv_r[22], segv_r[23],
2051     segv_r[24], segv_r[25], segv_r[26], segv_r[27],
2052     segv_r[28], segv_r[29], segv_r[30], segv_r[31]);
2053     VideoQuitFullScreen();
2054     disable_debugger(false);
2055     debugger(str);
2056     exit(1);
2057     return;
2058    
2059     rti:
2060     // Restore volatile registers
2061     r->r0 = segv_r[0];
2062     r->r1 = segv_r[1];
2063     r->r2 = segv_r[2];
2064     r->r3 = segv_r[3];
2065     r->r4 = segv_r[4];
2066     r->r5 = segv_r[5];
2067     r->r6 = segv_r[6];
2068     r->r7 = segv_r[7];
2069     r->r8 = segv_r[8];
2070     r->r9 = segv_r[9];
2071     r->r10 = segv_r[10];
2072     r->r11 = segv_r[11];
2073     r->r12 = segv_r[12];
2074 gbeauche 1.5 }
2075    
2076    
2077     /*
2078     * Helpers to share 32-bit addressable data with MacOS
2079     */
2080    
2081     bool SheepMem::Init(void)
2082     {
2083     // Delete old area
2084     area_id old_sheep_area = find_area(SHEEP_AREA_NAME);
2085     if (old_sheep_area > 0)
2086     delete_area(old_sheep_area);
2087    
2088     // Create area for SheepShaver data
2089     base = 0x60000000;
2090     SheepMemArea = create_area(SHEEP_AREA_NAME, (void **)&base, B_BASE_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
2091     if (SheepMemArea < 0)
2092     return false;
2093    
2094     D(bug("SheepShaver area %ld at %p\n", SheepMemArea, base));
2095     top = base + size;
2096     return true;
2097     }
2098    
2099     void SheepMem::Exit(void)
2100     {
2101     if (SheepMemArea >= 0)
2102     delete_area(SheepMemArea);
2103 cebix 1.1 }
2104    
2105    
2106     /*
2107     * Display error alert
2108     */
2109    
2110     void ErrorAlert(const char *text)
2111     {
2112     if (PrefsFindBool("nogui")) {
2113     printf(GetString(STR_SHELL_ERROR_PREFIX), text);
2114     return;
2115     }
2116     char str[256];
2117     sprintf(str, GetString(STR_GUI_ERROR_PREFIX), text);
2118     VideoQuitFullScreen();
2119     BAlert *alert = new BAlert(GetString(STR_ERROR_ALERT_TITLE), str, GetString(STR_QUIT_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
2120     alert->Go();
2121     }
2122    
2123    
2124     /*
2125     * Display warning alert
2126     */
2127    
2128     void WarningAlert(const char *text)
2129     {
2130     if (PrefsFindBool("nogui")) {
2131     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
2132     return;
2133     }
2134     char str[256];
2135     sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
2136     BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, GetString(STR_OK_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
2137     alert->Go();
2138     }
2139    
2140    
2141     /*
2142     * Display choice alert
2143     */
2144    
2145     bool ChoiceAlert(const char *text, const char *pos, const char *neg)
2146     {
2147     char str[256];
2148     sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
2149     BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, pos, neg, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
2150     return alert->Go() == 0;
2151     }