ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.11
Committed: 2004-02-24T11:12:52Z (20 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.10: +4 -0 lines
Log Message:
Make SheepShaver work with OS 8.6 out-of-the-box with no extra patch for
the time being. i.e. ignore writes to the zero page when faking SCSIGlobals

File Contents

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