ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.15
Committed: 2004-11-22T21:22:58Z (20 years ago) by gbeauche
Branch: MAIN
Changes since 1.14: +4 -3 lines
Log Message:
new SheepShaver globals layout

File Contents

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