ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.10
Committed: 2004-01-12T15:37:19Z (20 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.9: +1 -1 lines
Log Message:
Happy New Year! :)

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