ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.13
Committed: 2004-07-03T10:39:05Z (20 years, 2 months ago) by gbeauche
Branch: MAIN
Changes since 1.12: +2 -0 lines
Log Message:
Introducce TimebaseSpeed which represents exact timebase-frequency instead
of supposing it to be (BusClockSpeed/4), which is no longer true on G5 et al.

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