ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.20
Committed: 2009-07-23T19:12:50Z (14 years, 10 months ago) by asvitkine
Branch: MAIN
Changes since 1.19: +1 -1 lines
Log Message:
support for .sheepvm bundles on macosx, containing "prefs" and "nvram" files

File Contents

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