ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.11
Committed: 2004-02-24T11:12:52Z (20 years, 3 months ago) by gbeauche
Branch: MAIN
Changes since 1.10: +4 -0 lines
Log Message:
Make SheepShaver work with OS 8.6 out-of-the-box with no extra patch for
the time being. i.e. ignore writes to the zero page when faking SCSIGlobals

File Contents

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