ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.17
Committed: 2005-01-30T21:48:19Z (19 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.16: +1 -1 lines
Log Message:
Happy New Year 2005!

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * main_beos.cpp - Emulation core, BeOS implementation
3     *
4 gbeauche 1.17 * SheepShaver (C) 1997-2005 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     PrefsInit(argc, argv);
322    
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     #if 0
1252     WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
1253     #else
1254     if (the_app->emul_thread > 0 && the_app->ReadyForSignals)
1255     send_signal(the_app->emul_thread, SIGUSR1);
1256     #endif
1257     }
1258    
1259    
1260     /*
1261     * Mutexes
1262     */
1263    
1264     struct B2_mutex {
1265     int dummy; //!!
1266     };
1267    
1268     B2_mutex *B2_create_mutex(void)
1269     {
1270     return new B2_mutex;
1271     }
1272    
1273     void B2_lock_mutex(B2_mutex *mutex)
1274     {
1275     }
1276    
1277     void B2_unlock_mutex(B2_mutex *mutex)
1278     {
1279     }
1280    
1281     void B2_delete_mutex(B2_mutex *mutex)
1282     {
1283     delete mutex;
1284     }
1285    
1286    
1287     /*
1288     * Set/clear interrupt flags (must be done atomically!)
1289     */
1290    
1291     volatile uint32 InterruptFlags = 0;
1292    
1293     void SetInterruptFlag(uint32 flag)
1294     {
1295     atomic_or((int32 *)&InterruptFlags, flag);
1296     }
1297    
1298     void ClearInterruptFlag(uint32 flag)
1299     {
1300     atomic_and((int32 *)&InterruptFlags, ~flag);
1301     }
1302    
1303    
1304     /*
1305     * Disable interrupts
1306     */
1307    
1308     void DisableInterrupt(void)
1309     {
1310     atomic_add((int32 *)XLM_IRQ_NEST, 1);
1311     }
1312    
1313    
1314     /*
1315     * Enable interrupts
1316     */
1317    
1318     void EnableInterrupt(void)
1319     {
1320     atomic_add((int32 *)XLM_IRQ_NEST, -1);
1321     }
1322    
1323    
1324     /*
1325     * USR1 handler
1326     */
1327    
1328     void SheepShaver::sigusr1_invoc(int sig, void *arg, vregs *r)
1329     {
1330     ((SheepShaver *)arg)->sigusr1_handler(r);
1331     }
1332    
1333     #if !EMULATED_PPC
1334     static asm void ppc_interrupt(register uint32 entry)
1335     {
1336     fralloc
1337    
1338     // Get address of return routine
1339     bl @1
1340    
1341     // Return routine
1342     frfree
1343     blr
1344    
1345     @1
1346     // Prepare registers for nanokernel interrupt routine
1347     mtctr r1
1348     lwz r1,XLM_KERNEL_DATA
1349     stw r6,0x018(r1)
1350     mfctr r6
1351     stw r6,0x004(r1)
1352     lwz r6,0x65c(r1)
1353     stw r7,0x13c(r6)
1354     stw r8,0x144(r6)
1355     stw r9,0x14c(r6)
1356     stw r10,0x154(r6)
1357     stw r11,0x15c(r6)
1358     stw r12,0x164(r6)
1359     stw r13,0x16c(r6)
1360    
1361     mflr r10
1362     mfcr r13
1363     lwz r7,0x660(r1)
1364     mflr r12
1365     rlwimi. r7,r7,8,0,0
1366     li r11,0
1367     ori r11,r11,0xf072 // MSR (SRR1)
1368     mtcrf 0x70,r11
1369     li r8,0
1370    
1371     // Enter nanokernel
1372     mtlr r3
1373     blr
1374     }
1375     #endif
1376    
1377     void SheepShaver::sigusr1_handler(vregs *r)
1378     {
1379     // Do nothing if interrupts are disabled
1380     if ((*(int32 *)XLM_IRQ_NEST) > 0)
1381     return;
1382    
1383     // Interrupt action depends on current run mode
1384     switch (*(uint32 *)XLM_RUN_MODE) {
1385     case MODE_68K:
1386     // 68k emulator active, trigger 68k interrupt level 1
1387     *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1;
1388     r->cr |= kernel_data->v[0x674 >> 2];
1389     break;
1390    
1391     #if INTERRUPTS_IN_NATIVE_MODE
1392     case MODE_NATIVE:
1393     // 68k emulator inactive, in nanokernel?
1394     if (r->r1 != KernelDataAddr) {
1395     // No, prepare for 68k interrupt level 1
1396     *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1;
1397     *(uint32 *)(kernel_data->v[0x658 >> 2] + 0xdc) |= kernel_data->v[0x674 >> 2];
1398    
1399     // Execute nanokernel interrupt routine (this will activate the 68k emulator)
1400     atomic_add((int32 *)XLM_IRQ_NEST, 1);
1401     if (ROMType == ROMTYPE_NEWWORLD)
1402     ppc_interrupt(ROM_BASE + 0x312b1c);
1403     else
1404     ppc_interrupt(ROM_BASE + 0x312a3c);
1405     }
1406     break;
1407     #endif
1408    
1409     #if INTERRUPTS_IN_EMUL_OP_MODE
1410     case MODE_EMUL_OP:
1411     // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
1412     if ((*(uint32 *)XLM_68K_R25 & 7) == 0) {
1413    
1414     // Set extra stack for SIGSEGV handler
1415     set_signal_stack(extra_stack, SIG_STACK_SIZE);
1416     #if 1
1417     // Execute full 68k interrupt routine
1418     M68kRegisters r;
1419     uint32 old_r25 = *(uint32 *)XLM_68K_R25; // Save interrupt level
1420     *(uint32 *)XLM_68K_R25 = 0x21; // Execute with interrupt level 1
1421     static const uint16 proc[] = {
1422     0x3f3c, 0x0000, // move.w #$0000,-(sp) (fake format word)
1423     0x487a, 0x000a, // pea @1(pc) (return address)
1424     0x40e7, // move sr,-(sp) (saved SR)
1425     0x2078, 0x0064, // move.l $64,a0
1426     0x4ed0, // jmp (a0)
1427     M68K_RTS // @1
1428     };
1429     Execute68k((uint32)proc, &r);
1430     *(uint32 *)XLM_68K_R25 = old_r25; // Restore interrupt level
1431     #else
1432     // Only update cursor
1433     if (HasMacStarted()) {
1434     if (InterruptFlags & INTFLAG_VIA) {
1435     ClearInterruptFlag(INTFLAG_VIA);
1436     ADBInterrupt();
1437 gbeauche 1.7 ExecuteNative(NATIVE_VIDEO_VBL);
1438 cebix 1.1 }
1439     }
1440     #endif
1441     // Reset normal signal stack
1442     set_signal_stack(sig_stack, SIG_STACK_SIZE);
1443     }
1444     break;
1445     #endif
1446     }
1447     }
1448    
1449    
1450     /*
1451     * SIGSEGV handler
1452     */
1453    
1454     static uint32 segv_r[32];
1455    
1456     #if !EMULATED_PPC
1457     asm void SheepShaver::sigsegv_invoc(register int sig, register void *arg, register vregs *r)
1458     {
1459     mflr r0
1460     stw r0,8(r1)
1461     stwu r1,-56(r1)
1462    
1463     lwz r3,segv_r(r2)
1464     stmw r13,13*4(r3)
1465    
1466     mr r3,r5
1467     bl sigsegv_handler
1468    
1469     lwz r3,segv_r(r2)
1470     lmw r13,13*4(r3)
1471    
1472     lwz r0,56+8(r1)
1473     mtlr r0
1474     addi r1,r1,56
1475     blr
1476     }
1477     #endif
1478    
1479     static void sigsegv_handler(vregs *r)
1480     {
1481     char str[256];
1482    
1483     // Fetch volatile registers
1484     segv_r[0] = r->r0;
1485     segv_r[1] = r->r1;
1486     segv_r[2] = r->r2;
1487     segv_r[3] = r->r3;
1488     segv_r[4] = r->r4;
1489     segv_r[5] = r->r5;
1490     segv_r[6] = r->r6;
1491     segv_r[7] = r->r7;
1492     segv_r[8] = r->r8;
1493     segv_r[9] = r->r9;
1494     segv_r[10] = r->r10;
1495     segv_r[11] = r->r11;
1496     segv_r[12] = r->r12;
1497    
1498     // Get opcode and divide into fields
1499     uint32 opcode = *(uint32 *)r->pc;
1500     uint32 primop = opcode >> 26;
1501     uint32 exop = (opcode >> 1) & 0x3ff;
1502     uint32 ra = (opcode >> 16) & 0x1f;
1503     uint32 rb = (opcode >> 11) & 0x1f;
1504     uint32 rd = (opcode >> 21) & 0x1f;
1505     uint32 imm = opcode & 0xffff;
1506    
1507     // Fault in Mac ROM or RAM?
1508     bool mac_fault = (r->pc >= ROM_BASE) && (r->pc < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc >= RAMBase) && (r->pc < (RAMBase + RAMSize));
1509     if (mac_fault) {
1510    
1511     // "VM settings" during MacOS 8 installation
1512     if (r->pc == ROM_BASE + 0x488160 && segv_r[20] == 0xf8000000) {
1513     r->pc += 4;
1514     segv_r[8] = 0;
1515     goto rti;
1516    
1517     // MacOS 8.5 installation
1518     } else if (r->pc == ROM_BASE + 0x488140 && segv_r[16] == 0xf8000000) {
1519     r->pc += 4;
1520     segv_r[8] = 0;
1521     goto rti;
1522    
1523     // MacOS 8 serial drivers on startup
1524     } else if (r->pc == ROM_BASE + 0x48e080 && (segv_r[8] == 0xf3012002 || segv_r[8] == 0xf3012000)) {
1525     r->pc += 4;
1526     segv_r[8] = 0;
1527     goto rti;
1528    
1529     // MacOS 8.1 serial drivers on startup
1530     } else if (r->pc == ROM_BASE + 0x48c5e0 && (segv_r[20] == 0xf3012002 || segv_r[20] == 0xf3012000)) {
1531     r->pc += 4;
1532     goto rti;
1533     } else if (r->pc == ROM_BASE + 0x4a10a0 && (segv_r[20] == 0xf3012002 || segv_r[20] == 0xf3012000)) {
1534     r->pc += 4;
1535     goto rti;
1536     }
1537     }
1538    
1539     // Analyze opcode
1540     enum {
1541     TYPE_UNKNOWN,
1542     TYPE_LOAD,
1543     TYPE_STORE
1544     } transfer_type = TYPE_UNKNOWN;
1545     enum {
1546     SIZE_UNKNOWN,
1547     SIZE_BYTE,
1548     SIZE_HALFWORD,
1549     SIZE_WORD
1550     } transfer_size = SIZE_UNKNOWN;
1551     enum {
1552     MODE_UNKNOWN,
1553     MODE_NORM,
1554     MODE_U,
1555     MODE_X,
1556     MODE_UX
1557     } addr_mode = MODE_UNKNOWN;
1558     switch (primop) {
1559     case 31:
1560     switch (exop) {
1561     case 23: // lwzx
1562     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1563     case 55: // lwzux
1564     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1565     case 87: // lbzx
1566     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1567     case 119: // lbzux
1568     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1569     case 151: // stwx
1570     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1571     case 183: // stwux
1572     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1573     case 215: // stbx
1574     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1575     case 247: // stbux
1576     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1577     case 279: // lhzx
1578     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1579     case 311: // lhzux
1580     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1581     case 343: // lhax
1582     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1583     case 375: // lhaux
1584     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1585     case 407: // sthx
1586     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1587     case 439: // sthux
1588     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1589     }
1590     break;
1591    
1592     case 32: // lwz
1593     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1594     case 33: // lwzu
1595     transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1596     case 34: // lbz
1597     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1598     case 35: // lbzu
1599     transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1600     case 36: // stw
1601     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1602     case 37: // stwu
1603     transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1604     case 38: // stb
1605     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1606     case 39: // stbu
1607     transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1608     case 40: // lhz
1609     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1610     case 41: // lhzu
1611     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1612     case 42: // lha
1613     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1614     case 43: // lhau
1615     transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1616     case 44: // sth
1617     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1618     case 45: // sthu
1619     transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1620     }
1621    
1622     // Calculate effective address
1623     uint32 addr = 0;
1624     switch (addr_mode) {
1625     case MODE_X:
1626     case MODE_UX:
1627     if (ra == 0)
1628     addr = segv_r[rb];
1629     else
1630     addr = segv_r[ra] + segv_r[rb];
1631     break;
1632     case MODE_NORM:
1633     case MODE_U:
1634     if (ra == 0)
1635     addr = (int32)(int16)imm;
1636     else
1637     addr = segv_r[ra] + (int32)(int16)imm;
1638     break;
1639     default:
1640     break;
1641     }
1642    
1643     // Ignore ROM writes
1644     if (transfer_type == TYPE_STORE && addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) {
1645     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));
1646     if (addr_mode == MODE_U || addr_mode == MODE_UX)
1647     segv_r[ra] = addr;
1648     r->pc += 4;
1649     goto rti;
1650     }
1651    
1652     // Fault in Mac ROM or RAM?
1653     if (mac_fault) {
1654    
1655     // Ignore illegal memory accesses?
1656     if (PrefsFindBool("ignoresegv")) {
1657     if (addr_mode == MODE_U || addr_mode == MODE_UX)
1658     segv_r[ra] = addr;
1659     if (transfer_type == TYPE_LOAD)
1660     segv_r[rd] = 0;
1661     r->pc += 4;
1662     goto rti;
1663     }
1664    
1665     // In GUI mode, show error alert
1666     if (!PrefsFindBool("nogui")) {
1667     if (transfer_type == TYPE_LOAD || transfer_type == TYPE_STORE)
1668     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]);
1669     else
1670     sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc, segv_r[24], segv_r[1], opcode);
1671     ErrorAlert(str);
1672     QuitEmulator();
1673     return;
1674     }
1675     }
1676    
1677     // For all other errors, jump into debugger
1678     sprintf(str, "SIGSEGV\n"
1679     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
1680     " xer %08lx cr %08lx fpscr %08lx\n"
1681     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
1682     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
1683     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
1684     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
1685     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
1686     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
1687     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
1688     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
1689     r->pc, r->lr, r->ctr, r->msr,
1690     r->xer, r->cr, r->fpscr,
1691     r->r0, r->r1, r->r2, r->r3,
1692     r->r4, r->r5, r->r6, r->r7,
1693     r->r8, r->r9, r->r10, r->r11,
1694     r->r12, segv_r[13], segv_r[14], segv_r[15],
1695     segv_r[16], segv_r[17], segv_r[18], segv_r[19],
1696     segv_r[20], segv_r[21], segv_r[22], segv_r[23],
1697     segv_r[24], segv_r[25], segv_r[26], segv_r[27],
1698     segv_r[28], segv_r[29], segv_r[30], segv_r[31]);
1699     VideoQuitFullScreen();
1700     disable_debugger(false);
1701     debugger(str);
1702     exit(1);
1703     return;
1704    
1705     rti:
1706     // Restore volatile registers
1707     r->r0 = segv_r[0];
1708     r->r1 = segv_r[1];
1709     r->r2 = segv_r[2];
1710     r->r3 = segv_r[3];
1711     r->r4 = segv_r[4];
1712     r->r5 = segv_r[5];
1713     r->r6 = segv_r[6];
1714     r->r7 = segv_r[7];
1715     r->r8 = segv_r[8];
1716     r->r9 = segv_r[9];
1717     r->r10 = segv_r[10];
1718     r->r11 = segv_r[11];
1719     r->r12 = segv_r[12];
1720     }
1721    
1722    
1723     /*
1724     * SIGILL handler
1725     */
1726    
1727     #if !EMULATED_PPC
1728     asm void SheepShaver::sigill_invoc(register int sig, register void *arg, register vregs *r)
1729     {
1730     mflr r0
1731     stw r0,8(r1)
1732     stwu r1,-56(r1)
1733    
1734     lwz r3,segv_r(r2)
1735     stmw r13,13*4(r3)
1736    
1737     mr r3,r5
1738     bl sigill_handler
1739    
1740     lwz r3,segv_r(r2)
1741     lmw r13,13*4(r3)
1742    
1743     lwz r0,56+8(r1)
1744     mtlr r0
1745     addi r1,r1,56
1746     blr
1747     }
1748     #endif
1749    
1750     static void sigill_handler(vregs *r)
1751     {
1752     char str[256];
1753    
1754     // Fetch volatile registers
1755     segv_r[0] = r->r0;
1756     segv_r[1] = r->r1;
1757     segv_r[2] = r->r2;
1758     segv_r[3] = r->r3;
1759     segv_r[4] = r->r4;
1760     segv_r[5] = r->r5;
1761     segv_r[6] = r->r6;
1762     segv_r[7] = r->r7;
1763     segv_r[8] = r->r8;
1764     segv_r[9] = r->r9;
1765     segv_r[10] = r->r10;
1766     segv_r[11] = r->r11;
1767     segv_r[12] = r->r12;
1768    
1769     // Get opcode and divide into fields
1770     uint32 opcode = *(uint32 *)r->pc;
1771     uint32 primop = opcode >> 26;
1772     uint32 exop = (opcode >> 1) & 0x3ff;
1773     uint32 ra = (opcode >> 16) & 0x1f;
1774     uint32 rb = (opcode >> 11) & 0x1f;
1775     uint32 rd = (opcode >> 21) & 0x1f;
1776     uint32 imm = opcode & 0xffff;
1777    
1778     // Fault in Mac ROM or RAM?
1779     bool mac_fault = (r->pc >= ROM_BASE) && (r->pc < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc >= RAMBase) && (r->pc < (RAMBase + RAMSize));
1780     if (mac_fault) {
1781    
1782     switch (primop) {
1783     case 9: // POWER instructions
1784     case 22:
1785     power_inst: sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->pc, segv_r[1], opcode);
1786     ErrorAlert(str);
1787     QuitEmulator();
1788     return;
1789    
1790     case 31:
1791     switch (exop) {
1792     case 83: // mfmsr
1793     segv_r[rd] = 0xf072;
1794     r->pc += 4;
1795     goto rti;
1796    
1797     case 210: // mtsr
1798     case 242: // mtsrin
1799     case 306: // tlbie
1800     r->pc += 4;
1801     goto rti;
1802    
1803     case 339: { // mfspr
1804     int spr = ra | (rb << 5);
1805     switch (spr) {
1806     case 0: // MQ
1807     case 22: // DEC
1808     case 952: // MMCR0
1809     case 953: // PMC1
1810     case 954: // PMC2
1811     case 955: // SIA
1812     case 956: // MMCR1
1813     case 957: // PMC3
1814     case 958: // PMC4
1815     case 959: // SDA
1816     r->pc += 4;
1817     goto rti;
1818     case 25: // SDR1
1819     segv_r[rd] = 0xdead001f;
1820     r->pc += 4;
1821     goto rti;
1822     case 287: // PVR
1823     segv_r[rd] = PVR;
1824     r->pc += 4;
1825     goto rti;
1826     }
1827     break;
1828     }
1829    
1830     case 467: { // mtspr
1831     int spr = ra | (rb << 5);
1832     switch (spr) {
1833     case 0: // MQ
1834     case 22: // DEC
1835     case 275: // SPRG3
1836     case 528: // IBAT0U
1837     case 529: // IBAT0L
1838     case 530: // IBAT1U
1839     case 531: // IBAT1L
1840     case 532: // IBAT2U
1841     case 533: // IBAT2L
1842     case 534: // IBAT3U
1843     case 535: // IBAT3L
1844     case 536: // DBAT0U
1845     case 537: // DBAT0L
1846     case 538: // DBAT1U
1847     case 539: // DBAT1L
1848     case 540: // DBAT2U
1849     case 541: // DBAT2L
1850     case 542: // DBAT3U
1851     case 543: // DBAT3L
1852     case 952: // MMCR0
1853     case 953: // PMC1
1854     case 954: // PMC2
1855     case 955: // SIA
1856     case 956: // MMCR1
1857     case 957: // PMC3
1858     case 958: // PMC4
1859     case 959: // SDA
1860     r->pc += 4;
1861     goto rti;
1862     }
1863     break;
1864     }
1865    
1866     case 29: case 107: case 152: case 153: // POWER instructions
1867     case 184: case 216: case 217: case 248:
1868     case 264: case 277: case 331: case 360:
1869     case 363: case 488: case 531: case 537:
1870     case 541: case 664: case 665: case 696:
1871     case 728: case 729: case 760: case 920:
1872     case 921: case 952:
1873     goto power_inst;
1874     }
1875     }
1876    
1877     // In GUI mode, show error alert
1878     if (!PrefsFindBool("nogui")) {
1879     sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc, segv_r[24], segv_r[1], opcode);
1880     ErrorAlert(str);
1881     QuitEmulator();
1882     return;
1883     }
1884     }
1885    
1886     // For all other errors, jump into debugger
1887     sprintf(str, "SIGILL\n"
1888     " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
1889     " xer %08lx cr %08lx fpscr %08lx\n"
1890     " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
1891     " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
1892     " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
1893     " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
1894     " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
1895     " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
1896     " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
1897     " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
1898     r->pc, r->lr, r->ctr, r->msr,
1899     r->xer, r->cr, r->fpscr,
1900     r->r0, r->r1, r->r2, r->r3,
1901     r->r4, r->r5, r->r6, r->r7,
1902     r->r8, r->r9, r->r10, r->r11,
1903     r->r12, segv_r[13], segv_r[14], segv_r[15],
1904     segv_r[16], segv_r[17], segv_r[18], segv_r[19],
1905     segv_r[20], segv_r[21], segv_r[22], segv_r[23],
1906     segv_r[24], segv_r[25], segv_r[26], segv_r[27],
1907     segv_r[28], segv_r[29], segv_r[30], segv_r[31]);
1908     VideoQuitFullScreen();
1909     disable_debugger(false);
1910     debugger(str);
1911     exit(1);
1912     return;
1913    
1914     rti:
1915     // Restore volatile registers
1916     r->r0 = segv_r[0];
1917     r->r1 = segv_r[1];
1918     r->r2 = segv_r[2];
1919     r->r3 = segv_r[3];
1920     r->r4 = segv_r[4];
1921     r->r5 = segv_r[5];
1922     r->r6 = segv_r[6];
1923     r->r7 = segv_r[7];
1924     r->r8 = segv_r[8];
1925     r->r9 = segv_r[9];
1926     r->r10 = segv_r[10];
1927     r->r11 = segv_r[11];
1928     r->r12 = segv_r[12];
1929 gbeauche 1.5 }
1930    
1931    
1932     /*
1933     * Helpers to share 32-bit addressable data with MacOS
1934     */
1935    
1936     bool SheepMem::Init(void)
1937     {
1938     // Delete old area
1939     area_id old_sheep_area = find_area(SHEEP_AREA_NAME);
1940     if (old_sheep_area > 0)
1941     delete_area(old_sheep_area);
1942    
1943     // Create area for SheepShaver data
1944 gbeauche 1.15 proc = base = 0x60000000;
1945 gbeauche 1.5 SheepMemArea = create_area(SHEEP_AREA_NAME, (void **)&base, B_BASE_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1946     if (SheepMemArea < 0)
1947     return false;
1948 gbeauche 1.8
1949     // Create read-only area with all bits set to 0
1950     static const uint8 const_zero_page[4096] = {0,};
1951     zero_page = const_zero_page;
1952 gbeauche 1.5
1953     D(bug("SheepShaver area %ld at %p\n", SheepMemArea, base));
1954 gbeauche 1.15 data = base + size;
1955 gbeauche 1.5 return true;
1956     }
1957    
1958     void SheepMem::Exit(void)
1959     {
1960     if (SheepMemArea >= 0)
1961     delete_area(SheepMemArea);
1962 cebix 1.1 }
1963    
1964    
1965     /*
1966     * Display error alert
1967     */
1968    
1969     void ErrorAlert(const char *text)
1970     {
1971     if (PrefsFindBool("nogui")) {
1972     printf(GetString(STR_SHELL_ERROR_PREFIX), text);
1973     return;
1974     }
1975     char str[256];
1976     sprintf(str, GetString(STR_GUI_ERROR_PREFIX), text);
1977     VideoQuitFullScreen();
1978     BAlert *alert = new BAlert(GetString(STR_ERROR_ALERT_TITLE), str, GetString(STR_QUIT_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
1979     alert->Go();
1980     }
1981    
1982    
1983     /*
1984     * Display warning alert
1985     */
1986    
1987     void WarningAlert(const char *text)
1988     {
1989     if (PrefsFindBool("nogui")) {
1990     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
1991     return;
1992     }
1993     char str[256];
1994     sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
1995     BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, GetString(STR_OK_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
1996     alert->Go();
1997     }
1998    
1999    
2000     /*
2001     * Display choice alert
2002     */
2003    
2004     bool ChoiceAlert(const char *text, const char *pos, const char *neg)
2005     {
2006     char str[256];
2007     sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
2008     BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, pos, neg, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
2009     return alert->Go() == 0;
2010     }