ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.12
Committed: 2004-05-31T09:04:43Z (20 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.11: +23 -2 lines
Log Message:
Enable Apple DR emulator from NewWorld ROMs only.

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