ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.8
Committed: 2003-12-05T12:36:10Z (20 years, 11 months ago) by gbeauche
Branch: MAIN
Changes since 1.7: +8 -2 lines
Log Message:
Add XLM_ZERO_PAGE globals which points to a read-only page with all bits
set to zero.

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * main_beos.cpp - Emulation core, BeOS implementation
3     *
4     * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig
5     *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     /*
22     * NOTES:
23     *
24     * SheepShaver uses three run-time environments, reflected by the value of XLM_RUN_MODE.
25     * The two modes which are also present in the original MacOS, are:
26     * MODE_68K - 68k emulator is active
27     * MODE_NATIVE - 68k emulator is inactive
28     * In the original MacOS, these two modes have different memory mappings and exception
29     * tables. Under SheepShaver, the only difference is the handling of interrupts (see below).
30     * SheepShaver extends the 68k emulator with special opcodes (EMUL_OP) to perform faster
31     * mode switches when patching 68k routines with PowerPC code and adds a third run mode:
32     * MODE_EMUL_OP - 68k emulator active, but native register usage
33     *
34     * Switches between MODE_68K and MODE_NATIVE are only done with the Mixed Mode Manager
35     * (via nanokernel patches). The switch from MODE_68K to MODE_EMUL_OP occurs when executin
36     * one of the EMUL_OP 68k opcodes. When the opcode routine is done, it returns to MODE_68K.
37     *
38     * The Execute68k() routine allows EMUL_OP routines to execute 68k subroutines. It switches
39     * from MODE_EMUL_OP back to MODE_68K, so it must not be used by native routines (executing
40     * in MODE_NATIVE) nor by any other thread than the emul_thread (because the 68k emulator
41     * is not reentrant). When the 68k subroutine returns, it switches back to MODE_EMUL_OP.
42     * It is OK for a 68k routine called with Execute68k() to contain an EMUL_OP opcode.
43     *
44     * The handling of interrupts depends on the current run mode:
45     * MODE_68K - The USR1 signal handler sets one bit in the processor's CR. The 68k emulator
46     * will then execute the 68k interrupt routine when fetching the next instruction.
47     * MODE_NATIVE - The USR1 signal handler switches back to the original stack (signals run
48     * on a separate signal stack) and enters the External Interrupt routine in the
49     * nanokernel.
50     * MODE_EMUL_OP - The USR1 signal handler directly executes the 68k interrupt routine
51     * with Execute68k(). Before doing this, it must first check the current 68k interrupt
52     * level which is stored in XLM_68K_R25. This variable is set to the current level
53     * when entering EMUL_OP mode. Execute68k() also uses it to restore the level so that
54     * Execute68k()'d routines will run at the same interrupt level as the EMUL_OP routine
55     * it was called from.
56     */
57    
58     #include <Path.h>
59     #include <unistd.h>
60     #include <signal.h>
61     #include <stdio.h>
62     #include <stdlib.h>
63     #include <string.h>
64     #include <time.h>
65    
66     #include "sysdeps.h"
67     #include "main.h"
68     #include "version.h"
69     #include "prefs.h"
70     #include "prefs_editor.h"
71     #include "cpu_emulation.h"
72     #include "emul_op.h"
73     #include "xlowmem.h"
74     #include "xpram.h"
75     #include "timer.h"
76     #include "adb.h"
77     #include "sony.h"
78     #include "disk.h"
79     #include "cdrom.h"
80     #include "scsi.h"
81     #include "video.h"
82     #include "audio.h"
83     #include "ether.h"
84     #include "serial.h"
85     #include "clip.h"
86     #include "extfs.h"
87     #include "sys.h"
88     #include "macos_util.h"
89     #include "rom_patches.h"
90     #include "user_strings.h"
91 gbeauche 1.5 #include "thunks.h"
92 cebix 1.1
93     #include "sheep_driver.h"
94    
95     #define DEBUG 0
96     #include "debug.h"
97    
98     // Enable Execute68k() safety checks?
99     #define SAFE_EXEC_68K 0
100    
101     // Save FP regs in Execute68k()?
102     #define SAVE_FP_EXEC_68K 0
103    
104     // Interrupts in EMUL_OP mode?
105     #define INTERRUPTS_IN_EMUL_OP_MODE 1
106    
107     // Interrupts in native mode?
108     #define INTERRUPTS_IN_NATIVE_MODE 1
109    
110    
111     // Constants
112     const char APP_SIGNATURE[] = "application/x-vnd.cebix-SheepShaver";
113     const char ROM_FILE_NAME[] = "ROM";
114     const char ROM_FILE_NAME2[] = "Mac OS ROM";
115     const char KERNEL_AREA_NAME[] = "Macintosh Kernel Data";
116     const char KERNEL_AREA2_NAME[] = "Macintosh Kernel Data 2";
117     const char RAM_AREA_NAME[] = "Macintosh RAM";
118     const char ROM_AREA_NAME[] = "Macintosh ROM";
119     const char DR_CACHE_AREA_NAME[] = "Macintosh DR Cache";
120 gbeauche 1.5 const char SHEEP_AREA_NAME[] = "SheepShaver Virtual Stack";
121 cebix 1.1
122     const uint32 SIG_STACK_SIZE = 8192; // Size of signal stack
123    
124     const uint32 MSG_START = 'strt'; // Emulator start message
125    
126    
127     // Application object
128     class SheepShaver : public BApplication {
129     public:
130     SheepShaver() : BApplication(APP_SIGNATURE)
131     {
132     // Find application directory and cwd to it
133     app_info the_info;
134     GetAppInfo(&the_info);
135     BEntry the_file(&the_info.ref);
136     BEntry the_dir;
137     the_file.GetParent(&the_dir);
138     BPath the_path;
139     the_dir.GetPath(&the_path);
140     chdir(the_path.Path());
141    
142     // Initialize other variables
143     sheep_fd = -1;
144     emulator_data = NULL;
145     kernel_area = kernel_area2 = rom_area = ram_area = dr_cache_area = -1;
146     emul_thread = nvram_thread = tick_thread = -1;
147     ReadyForSignals = false;
148     AllowQuitting = true;
149     NVRAMThreadActive = true;
150     TickThreadActive = true;
151     memset(last_xpram, 0, XPRAM_SIZE);
152     }
153     virtual void ReadyToRun(void);
154     virtual void MessageReceived(BMessage *msg);
155     void StartEmulator(void);
156     virtual bool QuitRequested(void);
157     virtual void Quit(void);
158    
159     thread_id emul_thread; // Emulator thread
160     thread_id nvram_thread; // NVRAM watchdog thread
161     thread_id tick_thread; // 60Hz thread
162    
163     KernelData *kernel_data; // Pointer to Kernel Data
164     EmulatorData *emulator_data;
165    
166     bool ReadyForSignals; // Flag: emul_thread ready to receive signals
167     bool AllowQuitting; // Flag: Alt-Q quitting allowed
168     bool NVRAMThreadActive; // nvram_thread will exit when this is false
169     bool TickThreadActive; // tick_thread will exit when this is false
170    
171     uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes
172    
173     private:
174     static status_t emul_func(void *arg);
175     static status_t nvram_func(void *arg);
176     static status_t tick_func(void *arg);
177     static void sigusr1_invoc(int sig, void *arg, vregs *r);
178     void sigusr1_handler(vregs *r);
179     static void sigsegv_invoc(int sig, void *arg, vregs *r);
180     static void sigill_invoc(int sig, void *arg, vregs *r);
181     void jump_to_rom(uint32 entry);
182    
183     void init_rom(void);
184     void load_rom(void);
185    
186     int sheep_fd; // FD of sheep driver
187    
188     area_id kernel_area; // Kernel Data area ID
189     area_id kernel_area2; // Alternate Kernel Data area ID
190     area_id rom_area; // ROM area ID
191     area_id ram_area; // RAM area ID
192     area_id dr_cache_area; // DR Cache area ID
193    
194     struct sigaction sigusr1_action; // Interrupt signal (of emulator thread)
195     struct sigaction sigsegv_action; // Data access exception signal (of emulator thread)
196     struct sigaction sigill_action; // Illegal instruction exception signal (of emulator thread)
197    
198     // Exceptions
199     class area_error {};
200     class file_open_error {};
201     class file_read_error {};
202     class rom_size_error {};
203     };
204    
205    
206     // Global variables
207     SheepShaver *the_app; // Pointer to application object
208     #if !EMULATED_PPC
209     void *TOC; // TOC pointer
210     #endif
211     uint32 RAMBase; // Base address of Mac RAM
212     uint32 RAMSize; // Size of Mac RAM
213     uint32 KernelDataAddr; // Address of Kernel Data
214     uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM
215     uint32 DRCacheAddr; // Address of DR Cache
216     uint32 PVR; // Theoretical PVR
217     int64 CPUClockSpeed; // Processor clock speed (Hz)
218     int64 BusClockSpeed; // Bus clock speed (Hz)
219     system_info SysInfo; // System information
220    
221     static void *sig_stack = NULL; // Stack for signal handlers
222     static void *extra_stack = NULL; // Stack for SIGSEGV inside interrupt handler
223 gbeauche 1.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.5 // Delete SheepShaver globals
680     SheepMem::Exit();
681    
682 cebix 1.1 // Delete DR Cache area
683     if (dr_cache_area >= 0)
684     delete_area(dr_cache_area);
685    
686     // Delete ROM area
687     if (rom_area >= 0)
688     delete_area(rom_area);
689    
690     // Delete RAM area
691     if (ram_area >= 0)
692     delete_area(ram_area);
693    
694     // Delete Kernel Data area2
695     if (kernel_area2 >= 0)
696     delete_area(kernel_area2);
697     if (kernel_area >= 0)
698     delete_area(kernel_area);
699    
700     // Unmap low memory and close sheep driver
701     if (sheep_fd >= 0) {
702     ioctl(sheep_fd, SHEEP_DOWN);
703     close(sheep_fd);
704     }
705    
706     // Exit system routines
707     SysExit();
708    
709     // Exit preferences
710     PrefsExit();
711    
712     BApplication::Quit();
713     }
714    
715    
716     /*
717     * Create area for ROM (sets rom_area) and load ROM file
718     *
719     * area_error : Cannot create area
720     * file_open_error: Cannot open ROM file
721     * file_read_error: Cannot read ROM file
722     */
723    
724     void SheepShaver::init_rom(void)
725     {
726     // Create area for ROM
727     void *rom_addr = (void *)ROM_BASE;
728     rom_area = create_area(ROM_AREA_NAME, &rom_addr, B_EXACT_ADDRESS, ROM_AREA_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
729     if (rom_area < 0)
730     throw area_error();
731     D(bug("ROM area %ld at %p\n", rom_area, rom_addr));
732    
733     // Load ROM
734     load_rom();
735     }
736    
737    
738     /*
739     * Load ROM file
740     *
741     * file_open_error: Cannot open ROM file (nor use built-in ROM)
742     * file_read_error: Cannot read ROM file
743     */
744    
745     void SheepShaver::load_rom(void)
746     {
747     // Get rom file path from preferences
748     const char *rom_path = PrefsFindString("rom");
749    
750     // Try to open ROM file
751     BFile file(rom_path ? rom_path : ROM_FILE_NAME, B_READ_ONLY);
752     if (file.InitCheck() != B_NO_ERROR) {
753    
754     // Failed, then ask memory_mess driver for ROM
755     uint8 *rom = new uint8[ROM_SIZE]; // Reading directly into the area doesn't work
756     ssize_t actual = read(sheep_fd, (void *)rom, ROM_SIZE);
757     if (actual == ROM_SIZE) {
758     memcpy((void *)ROM_BASE, rom, ROM_SIZE);
759     delete[] rom;
760     return;
761     } else
762     throw file_open_error();
763     }
764    
765     printf(GetString(STR_READING_ROM_FILE));
766    
767     // Get file size
768     off_t rom_size = 0;
769     file.GetSize(&rom_size);
770    
771     uint8 *rom = new uint8[ROM_SIZE]; // Reading directly into the area doesn't work
772     ssize_t actual = file.Read((void *)rom, ROM_SIZE);
773 gbeauche 1.2
774     // Decode Mac ROM
775     if (!DecodeROM(rom, actual)) {
776     if (rom_size != 4*1024*1024)
777 cebix 1.1 throw rom_size_error();
778     else
779     throw file_read_error();
780     }
781 gbeauche 1.2 delete[] rom;
782 cebix 1.1 }
783    
784    
785     /*
786     * Emulator thread function
787     */
788    
789     status_t SheepShaver::emul_func(void *arg)
790     {
791     SheepShaver *obj = (SheepShaver *)arg;
792    
793     // Install interrupt signal handler
794     sigemptyset(&obj->sigusr1_action.sa_mask);
795     obj->sigusr1_action.sa_handler = (__signal_func_ptr)(obj->sigusr1_invoc);
796     obj->sigusr1_action.sa_flags = 0;
797     obj->sigusr1_action.sa_userdata = arg;
798     sigaction(SIGUSR1, &obj->sigusr1_action, NULL);
799    
800     // Install data access signal handler
801     sigemptyset(&obj->sigsegv_action.sa_mask);
802     obj->sigsegv_action.sa_handler = (__signal_func_ptr)(obj->sigsegv_invoc);
803     obj->sigsegv_action.sa_flags = 0;
804     obj->sigsegv_action.sa_userdata = arg;
805     sigaction(SIGSEGV, &obj->sigsegv_action, NULL);
806    
807     #if !EMULATED_PPC
808     // Install illegal instruction signal handler
809     sigemptyset(&obj->sigill_action.sa_mask);
810     obj->sigill_action.sa_handler = (__signal_func_ptr)(obj->sigill_invoc);
811     obj->sigill_action.sa_flags = 0;
812     obj->sigill_action.sa_userdata = arg;
813     sigaction(SIGILL, &obj->sigill_action, NULL);
814     #endif
815    
816     // Exceptions will send signals
817     disable_debugger(true);
818    
819     // Install signal stack
820     sig_stack = malloc(SIG_STACK_SIZE);
821     extra_stack = malloc(SIG_STACK_SIZE);
822     set_signal_stack(sig_stack, SIG_STACK_SIZE);
823    
824     // We're now ready to receive signals
825     obj->ReadyForSignals = true;
826    
827     // Jump to ROM boot routine
828     D(bug("Jumping to ROM\n"));
829     obj->jump_to_rom(ROM_BASE + 0x310000);
830     D(bug("Returned from ROM\n"));
831    
832     // We're no longer ready to receive signals
833     obj->ReadyForSignals = false;
834     obj->AllowQuitting = true;
835    
836     // Quit program
837     be_app->PostMessage(B_QUIT_REQUESTED);
838     return 0;
839     }
840    
841    
842     /*
843     * Jump into Mac ROM, start 680x0 emulator
844     * (also contains other EMUL_RETURN and EMUL_OP routines)
845     */
846    
847     #if EMULATED_PPC
848     extern void emul_ppc(uint32 start);
849     extern void init_emul_ppc(void);
850     void SheepShaver::jump_to_rom(uint32 entry)
851     {
852     init_emul_ppc();
853     emul_ppc(entry);
854     }
855     #else
856     asm void SheepShaver::jump_to_rom(register uint32 entry)
857     {
858     // Create stack frame
859     mflr r0
860     stw r0,8(r1)
861     mfcr r0
862     stw r0,4(r1)
863     stwu r1,-(56+19*4+18*8)(r1)
864    
865     // Save PowerPC registers
866     stmw r13,56(r1)
867     stfd f14,56+19*4+0*8(r1)
868     stfd f15,56+19*4+1*8(r1)
869     stfd f16,56+19*4+2*8(r1)
870     stfd f17,56+19*4+3*8(r1)
871     stfd f18,56+19*4+4*8(r1)
872     stfd f19,56+19*4+5*8(r1)
873     stfd f20,56+19*4+6*8(r1)
874     stfd f21,56+19*4+7*8(r1)
875     stfd f22,56+19*4+8*8(r1)
876     stfd f23,56+19*4+9*8(r1)
877     stfd f24,56+19*4+10*8(r1)
878     stfd f25,56+19*4+11*8(r1)
879     stfd f26,56+19*4+12*8(r1)
880     stfd f27,56+19*4+13*8(r1)
881     stfd f28,56+19*4+14*8(r1)
882     stfd f29,56+19*4+15*8(r1)
883     stfd f30,56+19*4+16*8(r1)
884     stfd f31,56+19*4+17*8(r1)
885    
886     // Move entry address to ctr, get pointer to Emulator Data
887     mtctr r4
888     lwz r4,SheepShaver.emulator_data(r3)
889    
890     // Skip over EMUL_RETURN routine and get its address
891     bl @1
892    
893    
894     /*
895     * EMUL_RETURN: Returned from emulator
896     */
897    
898     // Restore PowerPC registers
899     lwz r1,XLM_EMUL_RETURN_STACK
900     lwz r2,XLM_TOC
901     lmw r13,56(r1)
902     lfd f14,56+19*4+0*8(r1)
903     lfd f15,56+19*4+1*8(r1)
904     lfd f16,56+19*4+2*8(r1)
905     lfd f17,56+19*4+3*8(r1)
906     lfd f18,56+19*4+4*8(r1)
907     lfd f19,56+19*4+5*8(r1)
908     lfd f20,56+19*4+6*8(r1)
909     lfd f21,56+19*4+7*8(r1)
910     lfd f22,56+19*4+8*8(r1)
911     lfd f23,56+19*4+9*8(r1)
912     lfd f24,56+19*4+10*8(r1)
913     lfd f25,56+19*4+11*8(r1)
914     lfd f26,56+19*4+12*8(r1)
915     lfd f27,56+19*4+13*8(r1)
916     lfd f28,56+19*4+14*8(r1)
917     lfd f29,56+19*4+15*8(r1)
918     lfd f30,56+19*4+16*8(r1)
919     lfd f31,56+19*4+17*8(r1)
920    
921     // Exiting from 68k emulator
922     li r0,1
923     stw r0,XLM_IRQ_NEST
924     li r0,MODE_NATIVE
925     stw r0,XLM_RUN_MODE
926    
927     // Return to caller of jump_to_rom()
928     lwz r0,56+19*4+18*8+8(r1)
929     mtlr r0
930     lwz r0,56+19*4+18*8+4(r1)
931     mtcrf 0xff,r0
932     addi r1,r1,56+19*4+18*8
933     blr
934    
935    
936     // Save address of EMUL_RETURN routine for 68k emulator patch
937     @1 mflr r0
938     stw r0,XLM_EMUL_RETURN_PROC
939    
940     // Skip over EXEC_RETURN routine and get its address
941     bl @2
942    
943    
944     /*
945     * EXEC_RETURN: Returned from 68k routine executed with Execute68k()
946     */
947    
948     // Save r25 (contains current 68k interrupt level)
949     stw r25,XLM_68K_R25
950    
951     // Reentering EMUL_OP mode
952     li r0,MODE_EMUL_OP
953     stw r0,XLM_RUN_MODE
954    
955     // Save 68k registers
956     lwz r4,56+19*4+18*8+12(r1)
957     stw r8,M68kRegisters.d[0](r4)
958     stw r9,M68kRegisters.d[1](r4)
959     stw r10,M68kRegisters.d[2](r4)
960     stw r11,M68kRegisters.d[3](r4)
961     stw r12,M68kRegisters.d[4](r4)
962     stw r13,M68kRegisters.d[5](r4)
963     stw r14,M68kRegisters.d[6](r4)
964     stw r15,M68kRegisters.d[7](r4)
965     stw r16,M68kRegisters.a[0](r4)
966     stw r17,M68kRegisters.a[1](r4)
967     stw r18,M68kRegisters.a[2](r4)
968     stw r19,M68kRegisters.a[3](r4)
969     stw r20,M68kRegisters.a[4](r4)
970     stw r21,M68kRegisters.a[5](r4)
971     stw r22,M68kRegisters.a[6](r4)
972    
973     // Restore PowerPC registers
974     lmw r13,56(r1)
975     #if SAVE_FP_EXEC_68K
976     lfd f14,56+19*4+0*8(r1)
977     lfd f15,56+19*4+1*8(r1)
978     lfd f16,56+19*4+2*8(r1)
979     lfd f17,56+19*4+3*8(r1)
980     lfd f18,56+19*4+4*8(r1)
981     lfd f19,56+19*4+5*8(r1)
982     lfd f20,56+19*4+6*8(r1)
983     lfd f21,56+19*4+7*8(r1)
984     lfd f22,56+19*4+8*8(r1)
985     lfd f23,56+19*4+9*8(r1)
986     lfd f24,56+19*4+10*8(r1)
987     lfd f25,56+19*4+11*8(r1)
988     lfd f26,56+19*4+12*8(r1)
989     lfd f27,56+19*4+13*8(r1)
990     lfd f28,56+19*4+14*8(r1)
991     lfd f29,56+19*4+15*8(r1)
992     lfd f30,56+19*4+16*8(r1)
993     lfd f31,56+19*4+17*8(r1)
994     #endif
995    
996     // Return to caller
997     lwz r0,56+19*4+18*8+8(r1)
998     mtlr r0
999     addi r1,r1,56+19*4+18*8
1000     blr
1001    
1002    
1003     // Stave address of EXEC_RETURN routine for 68k emulator patch
1004     @2 mflr r0
1005     stw r0,XLM_EXEC_RETURN_PROC
1006    
1007     // Skip over EMUL_BREAK/EMUL_OP routine and get its address
1008     bl @3
1009    
1010    
1011     /*
1012     * EMUL_BREAK/EMUL_OP: Execute native routine, selector in r5 (my own private mode switch)
1013     *
1014     * 68k registers are stored in a M68kRegisters struct on the stack
1015     * which the native routine may read and modify
1016     */
1017    
1018     // Save r25 (contains current 68k interrupt level)
1019     stw r25,XLM_68K_R25
1020    
1021     // Entering EMUL_OP mode within 68k emulator
1022     li r0,MODE_EMUL_OP
1023     stw r0,XLM_RUN_MODE
1024    
1025     // Create PowerPC stack frame, reserve space for M68kRegisters
1026     mr r3,r1
1027     subi r1,r1,56 // Fake "caller" frame
1028     rlwinm r1,r1,0,0,29 // Align stack
1029    
1030     mfcr r0
1031     rlwinm r0,r0,0,11,8
1032     stw r0,4(r1)
1033     mfxer r0
1034     stw r0,16(r1)
1035     stw r2,12(r1)
1036     stwu r1,-(56+16*4+15*8)(r1)
1037     lwz r2,XLM_TOC
1038    
1039     // Save 68k registers
1040     stw r8,56+M68kRegisters.d[0](r1)
1041     stw r9,56+M68kRegisters.d[1](r1)
1042     stw r10,56+M68kRegisters.d[2](r1)
1043     stw r11,56+M68kRegisters.d[3](r1)
1044     stw r12,56+M68kRegisters.d[4](r1)
1045     stw r13,56+M68kRegisters.d[5](r1)
1046     stw r14,56+M68kRegisters.d[6](r1)
1047     stw r15,56+M68kRegisters.d[7](r1)
1048     stw r16,56+M68kRegisters.a[0](r1)
1049     stw r17,56+M68kRegisters.a[1](r1)
1050     stw r18,56+M68kRegisters.a[2](r1)
1051     stw r19,56+M68kRegisters.a[3](r1)
1052     stw r20,56+M68kRegisters.a[4](r1)
1053     stw r21,56+M68kRegisters.a[5](r1)
1054     stw r22,56+M68kRegisters.a[6](r1)
1055     stw r3,56+M68kRegisters.a[7](r1)
1056     stfd f0,56+16*4+0*8(r1)
1057     stfd f1,56+16*4+1*8(r1)
1058     stfd f2,56+16*4+2*8(r1)
1059     stfd f3,56+16*4+3*8(r1)
1060     stfd f4,56+16*4+4*8(r1)
1061     stfd f5,56+16*4+5*8(r1)
1062     stfd f6,56+16*4+6*8(r1)
1063     stfd f7,56+16*4+7*8(r1)
1064     mffs f0
1065     stfd f8,56+16*4+8*8(r1)
1066     stfd f9,56+16*4+9*8(r1)
1067     stfd f10,56+16*4+10*8(r1)
1068     stfd f11,56+16*4+11*8(r1)
1069     stfd f12,56+16*4+12*8(r1)
1070     stfd f13,56+16*4+13*8(r1)
1071     stfd f0,56+16*4+14*8(r1)
1072    
1073     // Execute native routine
1074     addi r3,r1,56
1075     mr r4,r24
1076     bl EmulOp
1077    
1078     // Restore 68k registers
1079     lwz r8,56+M68kRegisters.d[0](r1)
1080     lwz r9,56+M68kRegisters.d[1](r1)
1081     lwz r10,56+M68kRegisters.d[2](r1)
1082     lwz r11,56+M68kRegisters.d[3](r1)
1083     lwz r12,56+M68kRegisters.d[4](r1)
1084     lwz r13,56+M68kRegisters.d[5](r1)
1085     lwz r14,56+M68kRegisters.d[6](r1)
1086     lwz r15,56+M68kRegisters.d[7](r1)
1087     lwz r16,56+M68kRegisters.a[0](r1)
1088     lwz r17,56+M68kRegisters.a[1](r1)
1089     lwz r18,56+M68kRegisters.a[2](r1)
1090     lwz r19,56+M68kRegisters.a[3](r1)
1091     lwz r20,56+M68kRegisters.a[4](r1)
1092     lwz r21,56+M68kRegisters.a[5](r1)
1093     lwz r22,56+M68kRegisters.a[6](r1)
1094     lwz r3,56+M68kRegisters.a[7](r1)
1095     lfd f13,56+16*4+14*8(r1)
1096     lfd f0,56+16*4+0*8(r1)
1097     lfd f1,56+16*4+1*8(r1)
1098     lfd f2,56+16*4+2*8(r1)
1099     lfd f3,56+16*4+3*8(r1)
1100     lfd f4,56+16*4+4*8(r1)
1101     lfd f5,56+16*4+5*8(r1)
1102     lfd f6,56+16*4+6*8(r1)
1103     lfd f7,56+16*4+7*8(r1)
1104     mtfsf 0xff,f13
1105     lfd f8,56+16*4+8*8(r1)
1106     lfd f9,56+16*4+9*8(r1)
1107     lfd f10,56+16*4+10*8(r1)
1108     lfd f11,56+16*4+11*8(r1)
1109     lfd f12,56+16*4+12*8(r1)
1110     lfd f13,56+16*4+13*8(r1)
1111    
1112     // Delete PowerPC stack frame
1113     lwz r2,56+16*4+15*8+12(r1)
1114     lwz r0,56+16*4+15*8+16(r1)
1115     mtxer r0
1116     lwz r0,56+16*4+15*8+4(r1)
1117     mtcrf 0xff,r0
1118     mr r1,r3
1119    
1120     // Reeintering 68k emulator
1121     li r0,MODE_68K
1122     stw r0,XLM_RUN_MODE
1123    
1124     // Set r0 to 0 for 68k emulator
1125     li r0,0
1126    
1127     // Execute next 68k opcode
1128     rlwimi r29,r27,3,13,28
1129     lhau r27,2(r24)
1130     mtlr r29
1131     blr
1132    
1133    
1134     // Save address of EMUL_BREAK/EMUL_OP routine for 68k emulator patch
1135     @3 mflr r0
1136     stw r0,XLM_EMUL_OP_PROC
1137    
1138     // Save stack pointer for EMUL_RETURN
1139     stw r1,XLM_EMUL_RETURN_STACK
1140    
1141     // Preset registers for ROM boot routine
1142     lis r3,0x40b0 // Pointer to ROM boot structure
1143     ori r3,r3,0xd000
1144    
1145     // 68k emulator is now active
1146     li r0,MODE_68K
1147     stw r0,XLM_RUN_MODE
1148    
1149     // Jump to ROM
1150     bctr
1151     }
1152     #endif
1153    
1154    
1155     #if !EMULATED_PPC
1156     /*
1157     * Execute 68k subroutine (must be ended with RTS)
1158     * This must only be called by the emul_thread when in EMUL_OP mode
1159     * r->a[7] is unused, the routine runs on the caller's stack
1160     */
1161    
1162     #if SAFE_EXEC_68K
1163     void execute_68k(uint32 pc, M68kRegisters *r);
1164    
1165     void Execute68k(uint32 pc, M68kRegisters *r)
1166     {
1167     if (*(uint32 *)XLM_RUN_MODE != MODE_EMUL_OP)
1168     printf("FATAL: Execute68k() not called from EMUL_OP mode\n");
1169     if (find_thread(NULL) != the_app->emul_thread)
1170     printf("FATAL: Execute68k() not called from emul_thread\n");
1171     execute_68k(pc, r);
1172     }
1173    
1174     asm void execute_68k(register uint32 pc, register M68kRegisters *r)
1175     #else
1176     asm void Execute68k(register uint32 pc, register M68kRegisters *r)
1177     #endif
1178     {
1179     // Create stack frame
1180     mflr r0
1181     stw r0,8(r1)
1182     stw r4,12(r1)
1183     stwu r1,-(56+19*4+18*8)(r1)
1184    
1185     // Save PowerPC registers
1186     stmw r13,56(r1)
1187     #if SAVE_FP_EXEC_68K
1188     stfd f14,56+19*4+0*8(r1)
1189     stfd f15,56+19*4+1*8(r1)
1190     stfd f16,56+19*4+2*8(r1)
1191     stfd f17,56+19*4+3*8(r1)
1192     stfd f18,56+19*4+4*8(r1)
1193     stfd f19,56+19*4+5*8(r1)
1194     stfd f20,56+19*4+6*8(r1)
1195     stfd f21,56+19*4+7*8(r1)
1196     stfd f22,56+19*4+8*8(r1)
1197     stfd f23,56+19*4+9*8(r1)
1198     stfd f24,56+19*4+10*8(r1)
1199     stfd f25,56+19*4+11*8(r1)
1200     stfd f26,56+19*4+12*8(r1)
1201     stfd f27,56+19*4+13*8(r1)
1202     stfd f28,56+19*4+14*8(r1)
1203     stfd f29,56+19*4+15*8(r1)
1204     stfd f30,56+19*4+16*8(r1)
1205     stfd f31,56+19*4+17*8(r1)
1206     #endif
1207    
1208     // Set up registers for 68k emulator
1209     lwz r31,XLM_KERNEL_DATA // Pointer to Kernel Data
1210     addi r31,r31,0x1000
1211     li r0,0
1212     mtcrf 0xff,r0
1213     creqv 11,11,11 // Supervisor mode
1214     lwz r8,M68kRegisters.d[0](r4)
1215     lwz r9,M68kRegisters.d[1](r4)
1216     lwz r10,M68kRegisters.d[2](r4)
1217     lwz r11,M68kRegisters.d[3](r4)
1218     lwz r12,M68kRegisters.d[4](r4)
1219     lwz r13,M68kRegisters.d[5](r4)
1220     lwz r14,M68kRegisters.d[6](r4)
1221     lwz r15,M68kRegisters.d[7](r4)
1222     lwz r16,M68kRegisters.a[0](r4)
1223     lwz r17,M68kRegisters.a[1](r4)
1224     lwz r18,M68kRegisters.a[2](r4)
1225     lwz r19,M68kRegisters.a[3](r4)
1226     lwz r20,M68kRegisters.a[4](r4)
1227     lwz r21,M68kRegisters.a[5](r4)
1228     lwz r22,M68kRegisters.a[6](r4)
1229     li r23,0
1230     mr r24,r3
1231     lwz r25,XLM_68K_R25 // MSB of SR
1232     li r26,0
1233     li r28,0 // VBR
1234     lwz r29,0x74(r31) // Pointer to opcode table
1235     lwz r30,0x78(r31) // Address of emulator
1236    
1237     // Push return address (points to EXEC_RETURN opcode) on stack
1238     li r0,XLM_EXEC_RETURN_OPCODE
1239     stwu r0,-4(r1)
1240    
1241     // Reentering 68k emulator
1242     li r0,MODE_68K
1243     stw r0,XLM_RUN_MODE
1244    
1245     // Set r0 to 0 for 68k emulator
1246     li r0,0
1247    
1248     // Execute 68k opcode
1249     lha r27,0(r24)
1250     rlwimi r29,r27,3,13,28
1251     lhau r27,2(r24)
1252     mtlr r29
1253     blr
1254     }
1255    
1256    
1257     /*
1258     * Execute 68k A-Trap from EMUL_OP routine
1259     * r->a[7] is unused, the routine runs on the caller's stack
1260     */
1261    
1262     void Execute68kTrap(uint16 trap, M68kRegisters *r)
1263     {
1264     uint16 proc[2] = {trap, M68K_RTS};
1265     Execute68k((uint32)proc, r);
1266     }
1267    
1268    
1269     /*
1270     * Quit emulator (must only be called from main thread)
1271     */
1272    
1273     asm void QuitEmulator(void)
1274     {
1275     lwz r0,XLM_EMUL_RETURN_PROC
1276     mtlr r0
1277     blr
1278     }
1279     #endif
1280    
1281    
1282     /*
1283     * Dump 68k registers
1284     */
1285    
1286     void Dump68kRegs(M68kRegisters *r)
1287     {
1288     // Display 68k registers
1289     for (int i=0; i<8; i++) {
1290     printf("d%d: %08lx", i, r->d[i]);
1291     if (i == 3 || i == 7)
1292     printf("\n");
1293     else
1294     printf(", ");
1295     }
1296     for (int i=0; i<8; i++) {
1297     printf("a%d: %08lx", i, r->a[i]);
1298     if (i == 3 || i == 7)
1299     printf("\n");
1300     else
1301     printf(", ");
1302     }
1303     }
1304    
1305    
1306     /*
1307     * Make code executable
1308     */
1309    
1310     void MakeExecutable(int dummy, void *start, uint32 length)
1311     {
1312     if (((uint32)start >= ROM_BASE) && ((uint32)start < (ROM_BASE + ROM_SIZE)))
1313     return;
1314     clear_caches(start, length, B_INVALIDATE_ICACHE | B_FLUSH_DCACHE);
1315     }
1316    
1317    
1318     /*
1319     * Patch things after system startup (gets called by disk driver accRun routine)
1320     */
1321    
1322     void PatchAfterStartup(void)
1323     {
1324 gbeauche 1.7 ExecuteNative(NATIVE_VIDEO_INSTALL_ACCEL);
1325 cebix 1.1 InstallExtFS();
1326     }
1327    
1328    
1329     /*
1330     * NVRAM watchdog thread (saves NVRAM every minute)
1331     */
1332    
1333 cebix 1.4 status_t SheepShaver::nvram_func(void *arg)
1334 cebix 1.1 {
1335     SheepShaver *obj = (SheepShaver *)arg;
1336    
1337     while (obj->NVRAMThreadActive) {
1338     snooze(60*1000000);
1339     if (memcmp(obj->last_xpram, XPRAM, XPRAM_SIZE)) {
1340     memcpy(obj->last_xpram, XPRAM, XPRAM_SIZE);
1341     SaveXPRAM();
1342     }
1343     }
1344     return 0;
1345     }
1346    
1347    
1348     /*
1349     * 60Hz thread (really 60.15Hz)
1350     */
1351    
1352     status_t SheepShaver::tick_func(void *arg)
1353     {
1354     SheepShaver *obj = (SheepShaver *)arg;
1355     int tick_counter = 0;
1356     bigtime_t current = system_time();
1357    
1358     while (obj->TickThreadActive) {
1359    
1360     // Wait
1361     current += 16625;
1362     snooze_until(current, B_SYSTEM_TIMEBASE);
1363    
1364     // Pseudo Mac 1Hz interrupt, update local time
1365     if (++tick_counter > 60) {
1366     tick_counter = 0;
1367     WriteMacInt32(0x20c, TimerDateTime());
1368     }
1369    
1370     // 60Hz interrupt
1371     if (ReadMacInt32(XLM_IRQ_NEST) == 0) {
1372     SetInterruptFlag(INTFLAG_VIA);
1373     TriggerInterrupt();
1374     }
1375     }
1376     return 0;
1377     }
1378    
1379    
1380     /*
1381     * Trigger signal USR1 from another thread
1382     */
1383    
1384     void TriggerInterrupt(void)
1385     {
1386     #if 0
1387     WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
1388     #else
1389     if (the_app->emul_thread > 0 && the_app->ReadyForSignals)
1390     send_signal(the_app->emul_thread, SIGUSR1);
1391     #endif
1392     }
1393    
1394    
1395     /*
1396     * Mutexes
1397     */
1398    
1399     struct B2_mutex {
1400     int dummy; //!!
1401     };
1402    
1403     B2_mutex *B2_create_mutex(void)
1404     {
1405     return new B2_mutex;
1406     }
1407    
1408     void B2_lock_mutex(B2_mutex *mutex)
1409     {
1410     }
1411    
1412     void B2_unlock_mutex(B2_mutex *mutex)
1413     {
1414     }
1415    
1416     void B2_delete_mutex(B2_mutex *mutex)
1417     {
1418     delete mutex;
1419     }
1420    
1421    
1422     /*
1423     * Set/clear interrupt flags (must be done atomically!)
1424     */
1425    
1426     volatile uint32 InterruptFlags = 0;
1427    
1428     void SetInterruptFlag(uint32 flag)
1429     {
1430     atomic_or((int32 *)&InterruptFlags, flag);
1431     }
1432    
1433     void ClearInterruptFlag(uint32 flag)
1434     {
1435     atomic_and((int32 *)&InterruptFlags, ~flag);
1436     }
1437    
1438    
1439     /*
1440     * Disable interrupts
1441     */
1442    
1443     void DisableInterrupt(void)
1444     {
1445     atomic_add((int32 *)XLM_IRQ_NEST, 1);
1446     }
1447    
1448    
1449     /*
1450     * Enable interrupts
1451     */
1452    
1453     void EnableInterrupt(void)
1454     {
1455     atomic_add((int32 *)XLM_IRQ_NEST, -1);
1456     }
1457    
1458    
1459     /*
1460     * USR1 handler
1461     */
1462    
1463     void SheepShaver::sigusr1_invoc(int sig, void *arg, vregs *r)
1464     {
1465     ((SheepShaver *)arg)->sigusr1_handler(r);
1466     }
1467    
1468     #if !EMULATED_PPC
1469     static asm void ppc_interrupt(register uint32 entry)
1470     {
1471     fralloc
1472    
1473     // Get address of return routine
1474     bl @1
1475    
1476     // Return routine
1477     frfree
1478     blr
1479    
1480     @1
1481     // Prepare registers for nanokernel interrupt routine
1482     mtctr r1
1483     lwz r1,XLM_KERNEL_DATA
1484     stw r6,0x018(r1)
1485     mfctr r6
1486     stw r6,0x004(r1)
1487     lwz r6,0x65c(r1)
1488     stw r7,0x13c(r6)
1489     stw r8,0x144(r6)
1490     stw r9,0x14c(r6)
1491     stw r10,0x154(r6)
1492     stw r11,0x15c(r6)
1493     stw r12,0x164(r6)
1494     stw r13,0x16c(r6)
1495    
1496     mflr r10
1497     mfcr r13
1498     lwz r7,0x660(r1)
1499     mflr r12
1500     rlwimi. r7,r7,8,0,0
1501     li r11,0
1502     ori r11,r11,0xf072 // MSR (SRR1)
1503     mtcrf 0x70,r11
1504     li r8,0
1505    
1506     // Enter nanokernel
1507     mtlr r3
1508     blr
1509     }
1510     #endif
1511    
1512     void SheepShaver::sigusr1_handler(vregs *r)
1513     {
1514     // Do nothing if interrupts are disabled
1515     if ((*(int32 *)XLM_IRQ_NEST) > 0)
1516     return;
1517    
1518     // Interrupt action depends on current run mode
1519     switch (*(uint32 *)XLM_RUN_MODE) {
1520     case MODE_68K:
1521     // 68k emulator active, trigger 68k interrupt level 1
1522     *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1;
1523     r->cr |= kernel_data->v[0x674 >> 2];
1524     break;
1525    
1526     #if INTERRUPTS_IN_NATIVE_MODE
1527     case MODE_NATIVE:
1528     // 68k emulator inactive, in nanokernel?
1529     if (r->r1 != KernelDataAddr) {
1530     // No, prepare for 68k interrupt level 1
1531     *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1;
1532     *(uint32 *)(kernel_data->v[0x658 >> 2] + 0xdc) |= kernel_data->v[0x674 >> 2];
1533    
1534     // Execute nanokernel interrupt routine (this will activate the 68k emulator)
1535     atomic_add((int32 *)XLM_IRQ_NEST, 1);
1536     if (ROMType == ROMTYPE_NEWWORLD)
1537     ppc_interrupt(ROM_BASE + 0x312b1c);
1538     else
1539     ppc_interrupt(ROM_BASE + 0x312a3c);
1540     }
1541     break;
1542     #endif
1543    
1544     #if INTERRUPTS_IN_EMUL_OP_MODE
1545     case MODE_EMUL_OP:
1546     // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
1547     if ((*(uint32 *)XLM_68K_R25 & 7) == 0) {
1548    
1549     // Set extra stack for SIGSEGV handler
1550     set_signal_stack(extra_stack, SIG_STACK_SIZE);
1551     #if 1
1552     // Execute full 68k interrupt routine
1553     M68kRegisters r;
1554     uint32 old_r25 = *(uint32 *)XLM_68K_R25; // Save interrupt level
1555     *(uint32 *)XLM_68K_R25 = 0x21; // Execute with interrupt level 1
1556     static const uint16 proc[] = {
1557     0x3f3c, 0x0000, // move.w #$0000,-(sp) (fake format word)
1558     0x487a, 0x000a, // pea @1(pc) (return address)
1559     0x40e7, // move sr,-(sp) (saved SR)
1560     0x2078, 0x0064, // move.l $64,a0
1561     0x4ed0, // jmp (a0)
1562     M68K_RTS // @1
1563     };
1564     Execute68k((uint32)proc, &r);
1565     *(uint32 *)XLM_68K_R25 = old_r25; // Restore interrupt level
1566     #else
1567     // Only update cursor
1568     if (HasMacStarted()) {
1569     if (InterruptFlags & INTFLAG_VIA) {
1570     ClearInterruptFlag(INTFLAG_VIA);
1571     ADBInterrupt();
1572 gbeauche 1.7 ExecuteNative(NATIVE_VIDEO_VBL);
1573 cebix 1.1 }
1574     }
1575     #endif
1576     // Reset normal signal stack
1577     set_signal_stack(sig_stack, SIG_STACK_SIZE);
1578     }
1579     break;
1580     #endif
1581     }
1582     }
1583    
1584    
1585     /*
1586     * SIGSEGV handler
1587     */
1588    
1589     static uint32 segv_r[32];
1590    
1591     #if !EMULATED_PPC
1592     asm void SheepShaver::sigsegv_invoc(register int sig, register void *arg, register vregs *r)
1593     {
1594     mflr r0
1595     stw r0,8(r1)
1596     stwu r1,-56(r1)
1597    
1598     lwz r3,segv_r(r2)
1599     stmw r13,13*4(r3)
1600    
1601     mr r3,r5
1602     bl sigsegv_handler
1603    
1604     lwz r3,segv_r(r2)
1605     lmw r13,13*4(r3)
1606    
1607     lwz r0,56+8(r1)
1608     mtlr r0
1609     addi r1,r1,56
1610     blr
1611     }
1612     #endif
1613    
1614     static void sigsegv_handler(vregs *r)
1615     {
1616     char str[256];
1617    
1618     // Fetch volatile registers
1619     segv_r[0] = r->r0;
1620     segv_r[1] = r->r1;
1621     segv_r[2] = r->r2;
1622     segv_r[3] = r->r3;
1623     segv_r[4] = r->r4;
1624     segv_r[5] = r->r5;
1625     segv_r[6] = r->r6;
1626     segv_r[7] = r->r7;
1627     segv_r[8] = r->r8;
1628     segv_r[9] = r->r9;
1629     segv_r[10] = r->r10;
1630     segv_r[11] = r->r11;
1631     segv_r[12] = r->r12;
1632    
1633     // Get opcode and divide into fields
1634     uint32 opcode = *(uint32 *)r->pc;
1635     uint32 primop = opcode >> 26;
1636     uint32 exop = (opcode >> 1) & 0x3ff;
1637     uint32 ra = (opcode >> 16) & 0x1f;
1638     uint32 rb = (opcode >> 11) & 0x1f;
1639     uint32 rd = (opcode >> 21) & 0x1f;
1640     uint32 imm = opcode & 0xffff;
1641    
1642     // Fault in Mac ROM or RAM?
1643     bool mac_fault = (r->pc >= ROM_BASE) && (r->pc < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc >= RAMBase) && (r->pc < (RAMBase + RAMSize));
1644     if (mac_fault) {
1645    
1646     // "VM settings" during MacOS 8 installation
1647     if (r->pc == ROM_BASE + 0x488160 && segv_r[20] == 0xf8000000) {
1648     r->pc += 4;
1649     segv_r[8] = 0;
1650     goto rti;
1651    
1652     // MacOS 8.5 installation
1653     } else if (r->pc == ROM_BASE + 0x488140 && segv_r[16] == 0xf8000000) {
1654     r->pc += 4;
1655     segv_r[8] = 0;
1656     goto rti;
1657    
1658     // MacOS 8 serial drivers on startup
1659     } else if (r->pc == ROM_BASE + 0x48e080 && (segv_r[8] == 0xf3012002 || segv_r[8] == 0xf3012000)) {
1660     r->pc += 4;
1661     segv_r[8] = 0;
1662     goto rti;
1663    
1664     // MacOS 8.1 serial drivers on startup
1665     } else if (r->pc == ROM_BASE + 0x48c5e0 && (segv_r[20] == 0xf3012002 || segv_r[20] == 0xf3012000)) {
1666     r->pc += 4;
1667     goto rti;
1668     } else if (r->pc == ROM_BASE + 0x4a10a0 && (segv_r[20] == 0xf3012002 || segv_r[20] == 0xf3012000)) {
1669     r->pc += 4;
1670     goto rti;
1671     }
1672     }
1673    
1674     // Analyze opcode
1675     enum {
1676     TYPE_UNKNOWN,
1677     TYPE_LOAD,
1678     TYPE_STORE
1679     } transfer_type = TYPE_UNKNOWN;
1680     enum {
1681     SIZE_UNKNOWN,
1682     SIZE_BYTE,
1683     SIZE_HALFWORD,
1684     SIZE_WORD
1685     } transfer_size = SIZE_UNKNOWN;
1686     enum {
1687     MODE_UNKNOWN,
1688     MODE_NORM,
1689     MODE_U,
1690     MODE_X,
1691     MODE_UX
1692     } addr_mode = MODE_UNKNOWN;
1693     switch (primop) {
1694     case 31:
1695     switch (exop) {
1696     case 23: // lwzx
1697     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1698     case 55: // lwzux
1699     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1700     case 87: // lbzx
1701     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1702     case 119: // lbzux
1703     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1704     case 151: // stwx
1705     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1706     case 183: // stwux
1707     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1708     case 215: // stbx
1709     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1710     case 247: // stbux
1711     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1712     case 279: // lhzx
1713     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1714     case 311: // lhzux
1715     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1716     case 343: // lhax
1717     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1718     case 375: // lhaux
1719     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1720     case 407: // sthx
1721     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1722     case 439: // sthux
1723     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1724     }
1725     break;
1726    
1727     case 32: // lwz
1728     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1729     case 33: // lwzu
1730     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1731     case 34: // lbz
1732     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1733     case 35: // lbzu
1734     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1735     case 36: // stw
1736     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1737     case 37: // stwu
1738     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1739     case 38: // stb
1740     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1741     case 39: // stbu
1742     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1743     case 40: // lhz
1744     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1745     case 41: // lhzu
1746     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1747     case 42: // lha
1748     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1749     case 43: // lhau
1750     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1751     case 44: // sth
1752     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1753     case 45: // sthu
1754     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1755     }
1756    
1757     // Calculate effective address
1758     uint32 addr = 0;
1759     switch (addr_mode) {
1760     case MODE_X:
1761     case MODE_UX:
1762     if (ra == 0)
1763     addr = segv_r[rb];
1764     else
1765     addr = segv_r[ra] + segv_r[rb];
1766     break;
1767     case MODE_NORM:
1768     case MODE_U:
1769     if (ra == 0)
1770     addr = (int32)(int16)imm;
1771     else
1772     addr = segv_r[ra] + (int32)(int16)imm;
1773     break;
1774     default:
1775     break;
1776     }
1777    
1778     // Ignore ROM writes
1779     if (transfer_type == TYPE_STORE && addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) {
1780     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));
1781     if (addr_mode == MODE_U || addr_mode == MODE_UX)
1782     segv_r[ra] = addr;
1783     r->pc += 4;
1784     goto rti;
1785     }
1786    
1787     // Fault in Mac ROM or RAM?
1788     if (mac_fault) {
1789    
1790     // Ignore illegal memory accesses?
1791     if (PrefsFindBool("ignoresegv")) {
1792     if (addr_mode == MODE_U || addr_mode == MODE_UX)
1793     segv_r[ra] = addr;
1794     if (transfer_type == TYPE_LOAD)
1795     segv_r[rd] = 0;
1796     r->pc += 4;
1797     goto rti;
1798     }
1799    
1800     // In GUI mode, show error alert
1801     if (!PrefsFindBool("nogui")) {
1802     if (transfer_type == TYPE_LOAD || transfer_type == TYPE_STORE)
1803     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]);
1804     else
1805     sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc, segv_r[24], segv_r[1], opcode);
1806     ErrorAlert(str);
1807     QuitEmulator();
1808     return;
1809     }
1810     }
1811    
1812     // For all other errors, jump into debugger
1813     sprintf(str, "SIGSEGV\n"
1814     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
1815     " xer %08lx cr %08lx fpscr %08lx\n"
1816     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
1817     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
1818     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
1819     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
1820     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
1821     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
1822     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
1823     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
1824     r->pc, r->lr, r->ctr, r->msr,
1825     r->xer, r->cr, r->fpscr,
1826     r->r0, r->r1, r->r2, r->r3,
1827     r->r4, r->r5, r->r6, r->r7,
1828     r->r8, r->r9, r->r10, r->r11,
1829     r->r12, segv_r[13], segv_r[14], segv_r[15],
1830     segv_r[16], segv_r[17], segv_r[18], segv_r[19],
1831     segv_r[20], segv_r[21], segv_r[22], segv_r[23],
1832     segv_r[24], segv_r[25], segv_r[26], segv_r[27],
1833     segv_r[28], segv_r[29], segv_r[30], segv_r[31]);
1834     VideoQuitFullScreen();
1835     disable_debugger(false);
1836     debugger(str);
1837     exit(1);
1838     return;
1839    
1840     rti:
1841     // Restore volatile registers
1842     r->r0 = segv_r[0];
1843     r->r1 = segv_r[1];
1844     r->r2 = segv_r[2];
1845     r->r3 = segv_r[3];
1846     r->r4 = segv_r[4];
1847     r->r5 = segv_r[5];
1848     r->r6 = segv_r[6];
1849     r->r7 = segv_r[7];
1850     r->r8 = segv_r[8];
1851     r->r9 = segv_r[9];
1852     r->r10 = segv_r[10];
1853     r->r11 = segv_r[11];
1854     r->r12 = segv_r[12];
1855     }
1856    
1857    
1858     /*
1859     * SIGILL handler
1860     */
1861    
1862     #if !EMULATED_PPC
1863     asm void SheepShaver::sigill_invoc(register int sig, register void *arg, register vregs *r)
1864     {
1865     mflr r0
1866     stw r0,8(r1)
1867     stwu r1,-56(r1)
1868    
1869     lwz r3,segv_r(r2)
1870     stmw r13,13*4(r3)
1871    
1872     mr r3,r5
1873     bl sigill_handler
1874    
1875     lwz r3,segv_r(r2)
1876     lmw r13,13*4(r3)
1877    
1878     lwz r0,56+8(r1)
1879     mtlr r0
1880     addi r1,r1,56
1881     blr
1882     }
1883     #endif
1884    
1885     static void sigill_handler(vregs *r)
1886     {
1887     char str[256];
1888    
1889     // Fetch volatile registers
1890     segv_r[0] = r->r0;
1891     segv_r[1] = r->r1;
1892     segv_r[2] = r->r2;
1893     segv_r[3] = r->r3;
1894     segv_r[4] = r->r4;
1895     segv_r[5] = r->r5;
1896     segv_r[6] = r->r6;
1897     segv_r[7] = r->r7;
1898     segv_r[8] = r->r8;
1899     segv_r[9] = r->r9;
1900     segv_r[10] = r->r10;
1901     segv_r[11] = r->r11;
1902     segv_r[12] = r->r12;
1903    
1904     // Get opcode and divide into fields
1905     uint32 opcode = *(uint32 *)r->pc;
1906     uint32 primop = opcode >> 26;
1907     uint32 exop = (opcode >> 1) & 0x3ff;
1908     uint32 ra = (opcode >> 16) & 0x1f;
1909     uint32 rb = (opcode >> 11) & 0x1f;
1910     uint32 rd = (opcode >> 21) & 0x1f;
1911     uint32 imm = opcode & 0xffff;
1912    
1913     // Fault in Mac ROM or RAM?
1914     bool mac_fault = (r->pc >= ROM_BASE) && (r->pc < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc >= RAMBase) && (r->pc < (RAMBase + RAMSize));
1915     if (mac_fault) {
1916    
1917     switch (primop) {
1918     case 9: // POWER instructions
1919     case 22:
1920     power_inst: sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->pc, segv_r[1], opcode);
1921     ErrorAlert(str);
1922     QuitEmulator();
1923     return;
1924    
1925     case 31:
1926     switch (exop) {
1927     case 83: // mfmsr
1928     segv_r[rd] = 0xf072;
1929     r->pc += 4;
1930     goto rti;
1931    
1932     case 210: // mtsr
1933     case 242: // mtsrin
1934     case 306: // tlbie
1935     r->pc += 4;
1936     goto rti;
1937    
1938     case 339: { // mfspr
1939     int spr = ra | (rb << 5);
1940     switch (spr) {
1941     case 0: // MQ
1942     case 22: // DEC
1943     case 952: // MMCR0
1944     case 953: // PMC1
1945     case 954: // PMC2
1946     case 955: // SIA
1947     case 956: // MMCR1
1948     case 957: // PMC3
1949     case 958: // PMC4
1950     case 959: // SDA
1951     r->pc += 4;
1952     goto rti;
1953     case 25: // SDR1
1954     segv_r[rd] = 0xdead001f;
1955     r->pc += 4;
1956     goto rti;
1957     case 287: // PVR
1958     segv_r[rd] = PVR;
1959     r->pc += 4;
1960     goto rti;
1961     }
1962     break;
1963     }
1964    
1965     case 467: { // mtspr
1966     int spr = ra | (rb << 5);
1967     switch (spr) {
1968     case 0: // MQ
1969     case 22: // DEC
1970     case 275: // SPRG3
1971     case 528: // IBAT0U
1972     case 529: // IBAT0L
1973     case 530: // IBAT1U
1974     case 531: // IBAT1L
1975     case 532: // IBAT2U
1976     case 533: // IBAT2L
1977     case 534: // IBAT3U
1978     case 535: // IBAT3L
1979     case 536: // DBAT0U
1980     case 537: // DBAT0L
1981     case 538: // DBAT1U
1982     case 539: // DBAT1L
1983     case 540: // DBAT2U
1984     case 541: // DBAT2L
1985     case 542: // DBAT3U
1986     case 543: // DBAT3L
1987     case 952: // MMCR0
1988     case 953: // PMC1
1989     case 954: // PMC2
1990     case 955: // SIA
1991     case 956: // MMCR1
1992     case 957: // PMC3
1993     case 958: // PMC4
1994     case 959: // SDA
1995     r->pc += 4;
1996     goto rti;
1997     }
1998     break;
1999     }
2000    
2001     case 29: case 107: case 152: case 153: // POWER instructions
2002     case 184: case 216: case 217: case 248:
2003     case 264: case 277: case 331: case 360:
2004     case 363: case 488: case 531: case 537:
2005     case 541: case 664: case 665: case 696:
2006     case 728: case 729: case 760: case 920:
2007     case 921: case 952:
2008     goto power_inst;
2009     }
2010     }
2011    
2012     // In GUI mode, show error alert
2013     if (!PrefsFindBool("nogui")) {
2014     sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc, segv_r[24], segv_r[1], opcode);
2015     ErrorAlert(str);
2016     QuitEmulator();
2017     return;
2018     }
2019     }
2020    
2021     // For all other errors, jump into debugger
2022     sprintf(str, "SIGILL\n"
2023     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
2024     " xer %08lx cr %08lx fpscr %08lx\n"
2025     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
2026     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
2027     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
2028     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
2029     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
2030     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
2031     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
2032     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
2033     r->pc, r->lr, r->ctr, r->msr,
2034     r->xer, r->cr, r->fpscr,
2035     r->r0, r->r1, r->r2, r->r3,
2036     r->r4, r->r5, r->r6, r->r7,
2037     r->r8, r->r9, r->r10, r->r11,
2038     r->r12, segv_r[13], segv_r[14], segv_r[15],
2039     segv_r[16], segv_r[17], segv_r[18], segv_r[19],
2040     segv_r[20], segv_r[21], segv_r[22], segv_r[23],
2041     segv_r[24], segv_r[25], segv_r[26], segv_r[27],
2042     segv_r[28], segv_r[29], segv_r[30], segv_r[31]);
2043     VideoQuitFullScreen();
2044     disable_debugger(false);
2045     debugger(str);
2046     exit(1);
2047     return;
2048    
2049     rti:
2050     // Restore volatile registers
2051     r->r0 = segv_r[0];
2052     r->r1 = segv_r[1];
2053     r->r2 = segv_r[2];
2054     r->r3 = segv_r[3];
2055     r->r4 = segv_r[4];
2056     r->r5 = segv_r[5];
2057     r->r6 = segv_r[6];
2058     r->r7 = segv_r[7];
2059     r->r8 = segv_r[8];
2060     r->r9 = segv_r[9];
2061     r->r10 = segv_r[10];
2062     r->r11 = segv_r[11];
2063     r->r12 = segv_r[12];
2064 gbeauche 1.5 }
2065    
2066    
2067     /*
2068     * Helpers to share 32-bit addressable data with MacOS
2069     */
2070    
2071     bool SheepMem::Init(void)
2072     {
2073     // Delete old area
2074     area_id old_sheep_area = find_area(SHEEP_AREA_NAME);
2075     if (old_sheep_area > 0)
2076     delete_area(old_sheep_area);
2077    
2078     // Create area for SheepShaver data
2079     base = 0x60000000;
2080     SheepMemArea = create_area(SHEEP_AREA_NAME, (void **)&base, B_BASE_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
2081     if (SheepMemArea < 0)
2082     return false;
2083 gbeauche 1.8
2084     // Create read-only area with all bits set to 0
2085     static const uint8 const_zero_page[4096] = {0,};
2086     zero_page = const_zero_page;
2087 gbeauche 1.5
2088     D(bug("SheepShaver area %ld at %p\n", SheepMemArea, base));
2089     top = base + size;
2090     return true;
2091     }
2092    
2093     void SheepMem::Exit(void)
2094     {
2095     if (SheepMemArea >= 0)
2096     delete_area(SheepMemArea);
2097 cebix 1.1 }
2098    
2099    
2100     /*
2101     * Display error alert
2102     */
2103    
2104     void ErrorAlert(const char *text)
2105     {
2106     if (PrefsFindBool("nogui")) {
2107     printf(GetString(STR_SHELL_ERROR_PREFIX), text);
2108     return;
2109     }
2110     char str[256];
2111     sprintf(str, GetString(STR_GUI_ERROR_PREFIX), text);
2112     VideoQuitFullScreen();
2113     BAlert *alert = new BAlert(GetString(STR_ERROR_ALERT_TITLE), str, GetString(STR_QUIT_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
2114     alert->Go();
2115     }
2116    
2117    
2118     /*
2119     * Display warning alert
2120     */
2121    
2122     void WarningAlert(const char *text)
2123     {
2124     if (PrefsFindBool("nogui")) {
2125     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
2126     return;
2127     }
2128     char str[256];
2129     sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
2130     BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, GetString(STR_OK_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
2131     alert->Go();
2132     }
2133    
2134    
2135     /*
2136     * Display choice alert
2137     */
2138    
2139     bool ChoiceAlert(const char *text, const char *pos, const char *neg)
2140     {
2141     char str[256];
2142     sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
2143     BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, pos, neg, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
2144     return alert->Go() == 0;
2145     }