ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.3
Committed: 2003-09-29T15:46:05Z (21 years, 1 month ago) by gbeauche
Branch: MAIN
Changes since 1.2: +0 -19 lines
Log Message:
- Share EmulatorData & KernelData struct definitions
- Introduce new SheepShaver data area for alternate stacks, thunks, etc.
- Experimental asynchronous interrupts handling. This improves performance
  by 30% but some (rare) lockups may occur. To be debugged!

File Contents

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