ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.5
Committed: 2003-12-04T17:26:36Z (20 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.4: +52 -1 lines
Log Message:
Add new thunking system for 64-bit fixes.

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