ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.14
Committed: 2004-11-13T14:09:15Z (20 years ago) by gbeauche
Branch: MAIN
Changes since 1.13: +10 -7 lines
Log Message:
Implement Direct Addressing mode similarly to Basilisk II. This is to get
SheepShaver working on OSes that don't support maipping of Low Memory globals
at 0x00000000, e.g. Windows.

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