ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.20
Committed: 2009-07-23T19:12:50Z (14 years, 10 months ago) by asvitkine
Branch: MAIN
Changes since 1.19: +1 -1 lines
Log Message:
support for .sheepvm bundles on macosx, containing "prefs" and "nvram" files

File Contents

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