ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.24
Committed: 2012-06-17T16:52:58Z (12 years, 5 months ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.23: +1 -1 lines
Error occurred while calculating annotation data.
Log Message:
[Alexander von Gluck IV] BeOS: Fix missing ;
4fb0f92aaf065276712a36cb169081ebc41eeeb4
From: Alexander von Gluck IV <kallisti5@unixzen.com>
Date: Sun, 17 Jun 2012 03:47:26 +0000
Subject: [PATCH] Haiku: Fix missing ;

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