ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.22
Committed: 2009-08-26T00:11:56Z (15 years, 2 months ago) by asvitkine
Branch: MAIN
Changes since 1.21: +1 -1 lines
Log Message:
[Michael Schmitt]
Attached is a patch to SheepShaver, to fix a problem where the ROM file can only be found on the first boot.

When a user creates a new SheepShaver machine, there is no preference file, so there is not ROM path preference. SheepShaver has logic so that in this case, it will look for a ROM file named "ROM" or "Mac OS ROM" in the current directory.

The user starts SheepShaver in order to get to the built-in Preferences Editor, and changes various settings (such as creation of a hard disk). Then the user reboots.

If the user forgot to set the ROM path at this time, then SheepShaver can no longer boot. The only recourse is for the user to find and delete the preferences file, or use an external preferences editor to set the ROM path.

The fix is to change SheepShaver to use the default ROM names when either the rom path is null (no preference) OR an empty string (preference exists with no rom path).

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