ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.8
Committed: 2003-12-05T12:36:10Z (20 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.7: +8 -2 lines
Log Message:
Add XLM_ZERO_PAGE globals which points to a read-only page with all bits
set to zero.

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