ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.1.1.1 (vendor branch)
Committed: 2002-02-04T16:58:13Z (22 years, 3 months ago) by cebix
Branch: cebix
CVS Tags: start
Changes since 1.1: +0 -0 lines
Log Message:
Imported sources

File Contents

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