ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.10
Committed: 2004-01-12T15:37:19Z (20 years, 5 months ago) by cebix
Branch: MAIN
Changes since 1.9: +1 -1 lines
Log Message:
Happy New Year! :)

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 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 thunks
680 ThunksExit();
681
682 // Delete SheepShaver globals
683 SheepMem::Exit();
684
685 // Delete DR Cache area
686 if (dr_cache_area >= 0)
687 delete_area(dr_cache_area);
688
689 // Delete ROM area
690 if (rom_area >= 0)
691 delete_area(rom_area);
692
693 // Delete RAM area
694 if (ram_area >= 0)
695 delete_area(ram_area);
696
697 // Delete Kernel Data area2
698 if (kernel_area2 >= 0)
699 delete_area(kernel_area2);
700 if (kernel_area >= 0)
701 delete_area(kernel_area);
702
703 // Unmap low memory and close sheep driver
704 if (sheep_fd >= 0) {
705 ioctl(sheep_fd, SHEEP_DOWN);
706 close(sheep_fd);
707 }
708
709 // Exit system routines
710 SysExit();
711
712 // Exit preferences
713 PrefsExit();
714
715 BApplication::Quit();
716 }
717
718
719 /*
720 * Create area for ROM (sets rom_area) and load ROM file
721 *
722 * area_error : Cannot create area
723 * file_open_error: Cannot open ROM file
724 * file_read_error: Cannot read ROM file
725 */
726
727 void SheepShaver::init_rom(void)
728 {
729 // Create area for ROM
730 void *rom_addr = (void *)ROM_BASE;
731 rom_area = create_area(ROM_AREA_NAME, &rom_addr, B_EXACT_ADDRESS, ROM_AREA_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
732 if (rom_area < 0)
733 throw area_error();
734 D(bug("ROM area %ld at %p\n", rom_area, rom_addr));
735
736 // Load ROM
737 load_rom();
738 }
739
740
741 /*
742 * Load ROM file
743 *
744 * file_open_error: Cannot open ROM file (nor use built-in ROM)
745 * file_read_error: Cannot read ROM file
746 */
747
748 void SheepShaver::load_rom(void)
749 {
750 // Get rom file path from preferences
751 const char *rom_path = PrefsFindString("rom");
752
753 // Try to open ROM file
754 BFile file(rom_path ? rom_path : ROM_FILE_NAME, B_READ_ONLY);
755 if (file.InitCheck() != B_NO_ERROR) {
756
757 // Failed, then ask memory_mess driver for ROM
758 uint8 *rom = new uint8[ROM_SIZE]; // Reading directly into the area doesn't work
759 ssize_t actual = read(sheep_fd, (void *)rom, ROM_SIZE);
760 if (actual == ROM_SIZE) {
761 memcpy((void *)ROM_BASE, rom, ROM_SIZE);
762 delete[] rom;
763 return;
764 } else
765 throw file_open_error();
766 }
767
768 printf(GetString(STR_READING_ROM_FILE));
769
770 // Get file size
771 off_t rom_size = 0;
772 file.GetSize(&rom_size);
773
774 uint8 *rom = new uint8[ROM_SIZE]; // Reading directly into the area doesn't work
775 ssize_t actual = file.Read((void *)rom, ROM_SIZE);
776
777 // Decode Mac ROM
778 if (!DecodeROM(rom, actual)) {
779 if (rom_size != 4*1024*1024)
780 throw rom_size_error();
781 else
782 throw file_read_error();
783 }
784 delete[] rom;
785 }
786
787
788 /*
789 * Emulator thread function
790 */
791
792 status_t SheepShaver::emul_func(void *arg)
793 {
794 SheepShaver *obj = (SheepShaver *)arg;
795
796 // Install interrupt signal handler
797 sigemptyset(&obj->sigusr1_action.sa_mask);
798 obj->sigusr1_action.sa_handler = (__signal_func_ptr)(obj->sigusr1_invoc);
799 obj->sigusr1_action.sa_flags = 0;
800 obj->sigusr1_action.sa_userdata = arg;
801 sigaction(SIGUSR1, &obj->sigusr1_action, NULL);
802
803 // Install data access signal handler
804 sigemptyset(&obj->sigsegv_action.sa_mask);
805 obj->sigsegv_action.sa_handler = (__signal_func_ptr)(obj->sigsegv_invoc);
806 obj->sigsegv_action.sa_flags = 0;
807 obj->sigsegv_action.sa_userdata = arg;
808 sigaction(SIGSEGV, &obj->sigsegv_action, NULL);
809
810 #if !EMULATED_PPC
811 // Install illegal instruction signal handler
812 sigemptyset(&obj->sigill_action.sa_mask);
813 obj->sigill_action.sa_handler = (__signal_func_ptr)(obj->sigill_invoc);
814 obj->sigill_action.sa_flags = 0;
815 obj->sigill_action.sa_userdata = arg;
816 sigaction(SIGILL, &obj->sigill_action, NULL);
817 #endif
818
819 // Exceptions will send signals
820 disable_debugger(true);
821
822 // Install signal stack
823 sig_stack = malloc(SIG_STACK_SIZE);
824 extra_stack = malloc(SIG_STACK_SIZE);
825 set_signal_stack(sig_stack, SIG_STACK_SIZE);
826
827 // We're now ready to receive signals
828 obj->ReadyForSignals = true;
829
830 // Jump to ROM boot routine
831 D(bug("Jumping to ROM\n"));
832 obj->jump_to_rom(ROM_BASE + 0x310000);
833 D(bug("Returned from ROM\n"));
834
835 // We're no longer ready to receive signals
836 obj->ReadyForSignals = false;
837 obj->AllowQuitting = true;
838
839 // Quit program
840 be_app->PostMessage(B_QUIT_REQUESTED);
841 return 0;
842 }
843
844
845 /*
846 * Jump into Mac ROM, start 680x0 emulator
847 * (also contains other EMUL_RETURN and EMUL_OP routines)
848 */
849
850 #if EMULATED_PPC
851 extern void emul_ppc(uint32 start);
852 extern void init_emul_ppc(void);
853 void SheepShaver::jump_to_rom(uint32 entry)
854 {
855 init_emul_ppc();
856 emul_ppc(entry);
857 }
858 #else
859 asm void SheepShaver::jump_to_rom(register uint32 entry)
860 {
861 // Create stack frame
862 mflr r0
863 stw r0,8(r1)
864 mfcr r0
865 stw r0,4(r1)
866 stwu r1,-(56+19*4+18*8)(r1)
867
868 // Save PowerPC registers
869 stmw r13,56(r1)
870 stfd f14,56+19*4+0*8(r1)
871 stfd f15,56+19*4+1*8(r1)
872 stfd f16,56+19*4+2*8(r1)
873 stfd f17,56+19*4+3*8(r1)
874 stfd f18,56+19*4+4*8(r1)
875 stfd f19,56+19*4+5*8(r1)
876 stfd f20,56+19*4+6*8(r1)
877 stfd f21,56+19*4+7*8(r1)
878 stfd f22,56+19*4+8*8(r1)
879 stfd f23,56+19*4+9*8(r1)
880 stfd f24,56+19*4+10*8(r1)
881 stfd f25,56+19*4+11*8(r1)
882 stfd f26,56+19*4+12*8(r1)
883 stfd f27,56+19*4+13*8(r1)
884 stfd f28,56+19*4+14*8(r1)
885 stfd f29,56+19*4+15*8(r1)
886 stfd f30,56+19*4+16*8(r1)
887 stfd f31,56+19*4+17*8(r1)
888
889 // Move entry address to ctr, get pointer to Emulator Data
890 mtctr r4
891 lwz r4,SheepShaver.emulator_data(r3)
892
893 // Skip over EMUL_RETURN routine and get its address
894 bl @1
895
896
897 /*
898 * EMUL_RETURN: Returned from emulator
899 */
900
901 // Restore PowerPC registers
902 lwz r1,XLM_EMUL_RETURN_STACK
903 lwz r2,XLM_TOC
904 lmw r13,56(r1)
905 lfd f14,56+19*4+0*8(r1)
906 lfd f15,56+19*4+1*8(r1)
907 lfd f16,56+19*4+2*8(r1)
908 lfd f17,56+19*4+3*8(r1)
909 lfd f18,56+19*4+4*8(r1)
910 lfd f19,56+19*4+5*8(r1)
911 lfd f20,56+19*4+6*8(r1)
912 lfd f21,56+19*4+7*8(r1)
913 lfd f22,56+19*4+8*8(r1)
914 lfd f23,56+19*4+9*8(r1)
915 lfd f24,56+19*4+10*8(r1)
916 lfd f25,56+19*4+11*8(r1)
917 lfd f26,56+19*4+12*8(r1)
918 lfd f27,56+19*4+13*8(r1)
919 lfd f28,56+19*4+14*8(r1)
920 lfd f29,56+19*4+15*8(r1)
921 lfd f30,56+19*4+16*8(r1)
922 lfd f31,56+19*4+17*8(r1)
923
924 // Exiting from 68k emulator
925 li r0,1
926 stw r0,XLM_IRQ_NEST
927 li r0,MODE_NATIVE
928 stw r0,XLM_RUN_MODE
929
930 // Return to caller of jump_to_rom()
931 lwz r0,56+19*4+18*8+8(r1)
932 mtlr r0
933 lwz r0,56+19*4+18*8+4(r1)
934 mtcrf 0xff,r0
935 addi r1,r1,56+19*4+18*8
936 blr
937
938
939 // Save address of EMUL_RETURN routine for 68k emulator patch
940 @1 mflr r0
941 stw r0,XLM_EMUL_RETURN_PROC
942
943 // Skip over EXEC_RETURN routine and get its address
944 bl @2
945
946
947 /*
948 * EXEC_RETURN: Returned from 68k routine executed with Execute68k()
949 */
950
951 // Save r25 (contains current 68k interrupt level)
952 stw r25,XLM_68K_R25
953
954 // Reentering EMUL_OP mode
955 li r0,MODE_EMUL_OP
956 stw r0,XLM_RUN_MODE
957
958 // Save 68k registers
959 lwz r4,56+19*4+18*8+12(r1)
960 stw r8,M68kRegisters.d[0](r4)
961 stw r9,M68kRegisters.d[1](r4)
962 stw r10,M68kRegisters.d[2](r4)
963 stw r11,M68kRegisters.d[3](r4)
964 stw r12,M68kRegisters.d[4](r4)
965 stw r13,M68kRegisters.d[5](r4)
966 stw r14,M68kRegisters.d[6](r4)
967 stw r15,M68kRegisters.d[7](r4)
968 stw r16,M68kRegisters.a[0](r4)
969 stw r17,M68kRegisters.a[1](r4)
970 stw r18,M68kRegisters.a[2](r4)
971 stw r19,M68kRegisters.a[3](r4)
972 stw r20,M68kRegisters.a[4](r4)
973 stw r21,M68kRegisters.a[5](r4)
974 stw r22,M68kRegisters.a[6](r4)
975
976 // Restore PowerPC registers
977 lmw r13,56(r1)
978 #if SAVE_FP_EXEC_68K
979 lfd f14,56+19*4+0*8(r1)
980 lfd f15,56+19*4+1*8(r1)
981 lfd f16,56+19*4+2*8(r1)
982 lfd f17,56+19*4+3*8(r1)
983 lfd f18,56+19*4+4*8(r1)
984 lfd f19,56+19*4+5*8(r1)
985 lfd f20,56+19*4+6*8(r1)
986 lfd f21,56+19*4+7*8(r1)
987 lfd f22,56+19*4+8*8(r1)
988 lfd f23,56+19*4+9*8(r1)
989 lfd f24,56+19*4+10*8(r1)
990 lfd f25,56+19*4+11*8(r1)
991 lfd f26,56+19*4+12*8(r1)
992 lfd f27,56+19*4+13*8(r1)
993 lfd f28,56+19*4+14*8(r1)
994 lfd f29,56+19*4+15*8(r1)
995 lfd f30,56+19*4+16*8(r1)
996 lfd f31,56+19*4+17*8(r1)
997 #endif
998
999 // Return to caller
1000 lwz r0,56+19*4+18*8+8(r1)
1001 mtlr r0
1002 addi r1,r1,56+19*4+18*8
1003 blr
1004
1005
1006 // Stave address of EXEC_RETURN routine for 68k emulator patch
1007 @2 mflr r0
1008 stw r0,XLM_EXEC_RETURN_PROC
1009
1010 // Skip over EMUL_BREAK/EMUL_OP routine and get its address
1011 bl @3
1012
1013
1014 /*
1015 * EMUL_BREAK/EMUL_OP: Execute native routine, selector in r5 (my own private mode switch)
1016 *
1017 * 68k registers are stored in a M68kRegisters struct on the stack
1018 * which the native routine may read and modify
1019 */
1020
1021 // Save r25 (contains current 68k interrupt level)
1022 stw r25,XLM_68K_R25
1023
1024 // Entering EMUL_OP mode within 68k emulator
1025 li r0,MODE_EMUL_OP
1026 stw r0,XLM_RUN_MODE
1027
1028 // Create PowerPC stack frame, reserve space for M68kRegisters
1029 mr r3,r1
1030 subi r1,r1,56 // Fake "caller" frame
1031 rlwinm r1,r1,0,0,29 // Align stack
1032
1033 mfcr r0
1034 rlwinm r0,r0,0,11,8
1035 stw r0,4(r1)
1036 mfxer r0
1037 stw r0,16(r1)
1038 stw r2,12(r1)
1039 stwu r1,-(56+16*4+15*8)(r1)
1040 lwz r2,XLM_TOC
1041
1042 // Save 68k registers
1043 stw r8,56+M68kRegisters.d[0](r1)
1044 stw r9,56+M68kRegisters.d[1](r1)
1045 stw r10,56+M68kRegisters.d[2](r1)
1046 stw r11,56+M68kRegisters.d[3](r1)
1047 stw r12,56+M68kRegisters.d[4](r1)
1048 stw r13,56+M68kRegisters.d[5](r1)
1049 stw r14,56+M68kRegisters.d[6](r1)
1050 stw r15,56+M68kRegisters.d[7](r1)
1051 stw r16,56+M68kRegisters.a[0](r1)
1052 stw r17,56+M68kRegisters.a[1](r1)
1053 stw r18,56+M68kRegisters.a[2](r1)
1054 stw r19,56+M68kRegisters.a[3](r1)
1055 stw r20,56+M68kRegisters.a[4](r1)
1056 stw r21,56+M68kRegisters.a[5](r1)
1057 stw r22,56+M68kRegisters.a[6](r1)
1058 stw r3,56+M68kRegisters.a[7](r1)
1059 stfd f0,56+16*4+0*8(r1)
1060 stfd f1,56+16*4+1*8(r1)
1061 stfd f2,56+16*4+2*8(r1)
1062 stfd f3,56+16*4+3*8(r1)
1063 stfd f4,56+16*4+4*8(r1)
1064 stfd f5,56+16*4+5*8(r1)
1065 stfd f6,56+16*4+6*8(r1)
1066 stfd f7,56+16*4+7*8(r1)
1067 mffs f0
1068 stfd f8,56+16*4+8*8(r1)
1069 stfd f9,56+16*4+9*8(r1)
1070 stfd f10,56+16*4+10*8(r1)
1071 stfd f11,56+16*4+11*8(r1)
1072 stfd f12,56+16*4+12*8(r1)
1073 stfd f13,56+16*4+13*8(r1)
1074 stfd f0,56+16*4+14*8(r1)
1075
1076 // Execute native routine
1077 addi r3,r1,56
1078 mr r4,r24
1079 bl EmulOp
1080
1081 // Restore 68k registers
1082 lwz r8,56+M68kRegisters.d[0](r1)
1083 lwz r9,56+M68kRegisters.d[1](r1)
1084 lwz r10,56+M68kRegisters.d[2](r1)
1085 lwz r11,56+M68kRegisters.d[3](r1)
1086 lwz r12,56+M68kRegisters.d[4](r1)
1087 lwz r13,56+M68kRegisters.d[5](r1)
1088 lwz r14,56+M68kRegisters.d[6](r1)
1089 lwz r15,56+M68kRegisters.d[7](r1)
1090 lwz r16,56+M68kRegisters.a[0](r1)
1091 lwz r17,56+M68kRegisters.a[1](r1)
1092 lwz r18,56+M68kRegisters.a[2](r1)
1093 lwz r19,56+M68kRegisters.a[3](r1)
1094 lwz r20,56+M68kRegisters.a[4](r1)
1095 lwz r21,56+M68kRegisters.a[5](r1)
1096 lwz r22,56+M68kRegisters.a[6](r1)
1097 lwz r3,56+M68kRegisters.a[7](r1)
1098 lfd f13,56+16*4+14*8(r1)
1099 lfd f0,56+16*4+0*8(r1)
1100 lfd f1,56+16*4+1*8(r1)
1101 lfd f2,56+16*4+2*8(r1)
1102 lfd f3,56+16*4+3*8(r1)
1103 lfd f4,56+16*4+4*8(r1)
1104 lfd f5,56+16*4+5*8(r1)
1105 lfd f6,56+16*4+6*8(r1)
1106 lfd f7,56+16*4+7*8(r1)
1107 mtfsf 0xff,f13
1108 lfd f8,56+16*4+8*8(r1)
1109 lfd f9,56+16*4+9*8(r1)
1110 lfd f10,56+16*4+10*8(r1)
1111 lfd f11,56+16*4+11*8(r1)
1112 lfd f12,56+16*4+12*8(r1)
1113 lfd f13,56+16*4+13*8(r1)
1114
1115 // Delete PowerPC stack frame
1116 lwz r2,56+16*4+15*8+12(r1)
1117 lwz r0,56+16*4+15*8+16(r1)
1118 mtxer r0
1119 lwz r0,56+16*4+15*8+4(r1)
1120 mtcrf 0xff,r0
1121 mr r1,r3
1122
1123 // Reeintering 68k emulator
1124 li r0,MODE_68K
1125 stw r0,XLM_RUN_MODE
1126
1127 // Set r0 to 0 for 68k emulator
1128 li r0,0
1129
1130 // Execute next 68k opcode
1131 rlwimi r29,r27,3,13,28
1132 lhau r27,2(r24)
1133 mtlr r29
1134 blr
1135
1136
1137 // Save address of EMUL_BREAK/EMUL_OP routine for 68k emulator patch
1138 @3 mflr r0
1139 stw r0,XLM_EMUL_OP_PROC
1140
1141 // Save stack pointer for EMUL_RETURN
1142 stw r1,XLM_EMUL_RETURN_STACK
1143
1144 // Preset registers for ROM boot routine
1145 lis r3,0x40b0 // Pointer to ROM boot structure
1146 ori r3,r3,0xd000
1147
1148 // 68k emulator is now active
1149 li r0,MODE_68K
1150 stw r0,XLM_RUN_MODE
1151
1152 // Jump to ROM
1153 bctr
1154 }
1155 #endif
1156
1157
1158 #if !EMULATED_PPC
1159 /*
1160 * Execute 68k subroutine (must be ended with RTS)
1161 * This must only be called by the emul_thread when in EMUL_OP mode
1162 * r->a[7] is unused, the routine runs on the caller's stack
1163 */
1164
1165 #if SAFE_EXEC_68K
1166 void execute_68k(uint32 pc, M68kRegisters *r);
1167
1168 void Execute68k(uint32 pc, M68kRegisters *r)
1169 {
1170 if (*(uint32 *)XLM_RUN_MODE != MODE_EMUL_OP)
1171 printf("FATAL: Execute68k() not called from EMUL_OP mode\n");
1172 if (find_thread(NULL) != the_app->emul_thread)
1173 printf("FATAL: Execute68k() not called from emul_thread\n");
1174 execute_68k(pc, r);
1175 }
1176
1177 asm void execute_68k(register uint32 pc, register M68kRegisters *r)
1178 #else
1179 asm void Execute68k(register uint32 pc, register M68kRegisters *r)
1180 #endif
1181 {
1182 // Create stack frame
1183 mflr r0
1184 stw r0,8(r1)
1185 stw r4,12(r1)
1186 stwu r1,-(56+19*4+18*8)(r1)
1187
1188 // Save PowerPC registers
1189 stmw r13,56(r1)
1190 #if SAVE_FP_EXEC_68K
1191 stfd f14,56+19*4+0*8(r1)
1192 stfd f15,56+19*4+1*8(r1)
1193 stfd f16,56+19*4+2*8(r1)
1194 stfd f17,56+19*4+3*8(r1)
1195 stfd f18,56+19*4+4*8(r1)
1196 stfd f19,56+19*4+5*8(r1)
1197 stfd f20,56+19*4+6*8(r1)
1198 stfd f21,56+19*4+7*8(r1)
1199 stfd f22,56+19*4+8*8(r1)
1200 stfd f23,56+19*4+9*8(r1)
1201 stfd f24,56+19*4+10*8(r1)
1202 stfd f25,56+19*4+11*8(r1)
1203 stfd f26,56+19*4+12*8(r1)
1204 stfd f27,56+19*4+13*8(r1)
1205 stfd f28,56+19*4+14*8(r1)
1206 stfd f29,56+19*4+15*8(r1)
1207 stfd f30,56+19*4+16*8(r1)
1208 stfd f31,56+19*4+17*8(r1)
1209 #endif
1210
1211 // Set up registers for 68k emulator
1212 lwz r31,XLM_KERNEL_DATA // Pointer to Kernel Data
1213 addi r31,r31,0x1000
1214 li r0,0
1215 mtcrf 0xff,r0
1216 creqv 11,11,11 // Supervisor mode
1217 lwz r8,M68kRegisters.d[0](r4)
1218 lwz r9,M68kRegisters.d[1](r4)
1219 lwz r10,M68kRegisters.d[2](r4)
1220 lwz r11,M68kRegisters.d[3](r4)
1221 lwz r12,M68kRegisters.d[4](r4)
1222 lwz r13,M68kRegisters.d[5](r4)
1223 lwz r14,M68kRegisters.d[6](r4)
1224 lwz r15,M68kRegisters.d[7](r4)
1225 lwz r16,M68kRegisters.a[0](r4)
1226 lwz r17,M68kRegisters.a[1](r4)
1227 lwz r18,M68kRegisters.a[2](r4)
1228 lwz r19,M68kRegisters.a[3](r4)
1229 lwz r20,M68kRegisters.a[4](r4)
1230 lwz r21,M68kRegisters.a[5](r4)
1231 lwz r22,M68kRegisters.a[6](r4)
1232 li r23,0
1233 mr r24,r3
1234 lwz r25,XLM_68K_R25 // MSB of SR
1235 li r26,0
1236 li r28,0 // VBR
1237 lwz r29,0x74(r31) // Pointer to opcode table
1238 lwz r30,0x78(r31) // Address of emulator
1239
1240 // Push return address (points to EXEC_RETURN opcode) on stack
1241 li r0,XLM_EXEC_RETURN_OPCODE
1242 stwu r0,-4(r1)
1243
1244 // Reentering 68k emulator
1245 li r0,MODE_68K
1246 stw r0,XLM_RUN_MODE
1247
1248 // Set r0 to 0 for 68k emulator
1249 li r0,0
1250
1251 // Execute 68k opcode
1252 lha r27,0(r24)
1253 rlwimi r29,r27,3,13,28
1254 lhau r27,2(r24)
1255 mtlr r29
1256 blr
1257 }
1258
1259
1260 /*
1261 * Execute 68k A-Trap from EMUL_OP routine
1262 * r->a[7] is unused, the routine runs on the caller's stack
1263 */
1264
1265 void Execute68kTrap(uint16 trap, M68kRegisters *r)
1266 {
1267 uint16 proc[2] = {trap, M68K_RTS};
1268 Execute68k((uint32)proc, r);
1269 }
1270
1271
1272 /*
1273 * Quit emulator (must only be called from main thread)
1274 */
1275
1276 asm void QuitEmulator(void)
1277 {
1278 lwz r0,XLM_EMUL_RETURN_PROC
1279 mtlr r0
1280 blr
1281 }
1282 #endif
1283
1284
1285 /*
1286 * Dump 68k registers
1287 */
1288
1289 void Dump68kRegs(M68kRegisters *r)
1290 {
1291 // Display 68k registers
1292 for (int i=0; i<8; i++) {
1293 printf("d%d: %08lx", i, r->d[i]);
1294 if (i == 3 || i == 7)
1295 printf("\n");
1296 else
1297 printf(", ");
1298 }
1299 for (int i=0; i<8; i++) {
1300 printf("a%d: %08lx", i, r->a[i]);
1301 if (i == 3 || i == 7)
1302 printf("\n");
1303 else
1304 printf(", ");
1305 }
1306 }
1307
1308
1309 /*
1310 * Make code executable
1311 */
1312
1313 void MakeExecutable(int dummy, void *start, uint32 length)
1314 {
1315 if (((uint32)start >= ROM_BASE) && ((uint32)start < (ROM_BASE + ROM_SIZE)))
1316 return;
1317 clear_caches(start, length, B_INVALIDATE_ICACHE | B_FLUSH_DCACHE);
1318 }
1319
1320
1321 /*
1322 * Patch things after system startup (gets called by disk driver accRun routine)
1323 */
1324
1325 void PatchAfterStartup(void)
1326 {
1327 ExecuteNative(NATIVE_VIDEO_INSTALL_ACCEL);
1328 InstallExtFS();
1329 }
1330
1331
1332 /*
1333 * NVRAM watchdog thread (saves NVRAM every minute)
1334 */
1335
1336 status_t SheepShaver::nvram_func(void *arg)
1337 {
1338 SheepShaver *obj = (SheepShaver *)arg;
1339
1340 while (obj->NVRAMThreadActive) {
1341 snooze(60*1000000);
1342 if (memcmp(obj->last_xpram, XPRAM, XPRAM_SIZE)) {
1343 memcpy(obj->last_xpram, XPRAM, XPRAM_SIZE);
1344 SaveXPRAM();
1345 }
1346 }
1347 return 0;
1348 }
1349
1350
1351 /*
1352 * 60Hz thread (really 60.15Hz)
1353 */
1354
1355 status_t SheepShaver::tick_func(void *arg)
1356 {
1357 SheepShaver *obj = (SheepShaver *)arg;
1358 int tick_counter = 0;
1359 bigtime_t current = system_time();
1360
1361 while (obj->TickThreadActive) {
1362
1363 // Wait
1364 current += 16625;
1365 snooze_until(current, B_SYSTEM_TIMEBASE);
1366
1367 // Pseudo Mac 1Hz interrupt, update local time
1368 if (++tick_counter > 60) {
1369 tick_counter = 0;
1370 WriteMacInt32(0x20c, TimerDateTime());
1371 }
1372
1373 // 60Hz interrupt
1374 if (ReadMacInt32(XLM_IRQ_NEST) == 0) {
1375 SetInterruptFlag(INTFLAG_VIA);
1376 TriggerInterrupt();
1377 }
1378 }
1379 return 0;
1380 }
1381
1382
1383 /*
1384 * Trigger signal USR1 from another thread
1385 */
1386
1387 void TriggerInterrupt(void)
1388 {
1389 #if 0
1390 WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
1391 #else
1392 if (the_app->emul_thread > 0 && the_app->ReadyForSignals)
1393 send_signal(the_app->emul_thread, SIGUSR1);
1394 #endif
1395 }
1396
1397
1398 /*
1399 * Mutexes
1400 */
1401
1402 struct B2_mutex {
1403 int dummy; //!!
1404 };
1405
1406 B2_mutex *B2_create_mutex(void)
1407 {
1408 return new B2_mutex;
1409 }
1410
1411 void B2_lock_mutex(B2_mutex *mutex)
1412 {
1413 }
1414
1415 void B2_unlock_mutex(B2_mutex *mutex)
1416 {
1417 }
1418
1419 void B2_delete_mutex(B2_mutex *mutex)
1420 {
1421 delete mutex;
1422 }
1423
1424
1425 /*
1426 * Set/clear interrupt flags (must be done atomically!)
1427 */
1428
1429 volatile uint32 InterruptFlags = 0;
1430
1431 void SetInterruptFlag(uint32 flag)
1432 {
1433 atomic_or((int32 *)&InterruptFlags, flag);
1434 }
1435
1436 void ClearInterruptFlag(uint32 flag)
1437 {
1438 atomic_and((int32 *)&InterruptFlags, ~flag);
1439 }
1440
1441
1442 /*
1443 * Disable interrupts
1444 */
1445
1446 void DisableInterrupt(void)
1447 {
1448 atomic_add((int32 *)XLM_IRQ_NEST, 1);
1449 }
1450
1451
1452 /*
1453 * Enable interrupts
1454 */
1455
1456 void EnableInterrupt(void)
1457 {
1458 atomic_add((int32 *)XLM_IRQ_NEST, -1);
1459 }
1460
1461
1462 /*
1463 * USR1 handler
1464 */
1465
1466 void SheepShaver::sigusr1_invoc(int sig, void *arg, vregs *r)
1467 {
1468 ((SheepShaver *)arg)->sigusr1_handler(r);
1469 }
1470
1471 #if !EMULATED_PPC
1472 static asm void ppc_interrupt(register uint32 entry)
1473 {
1474 fralloc
1475
1476 // Get address of return routine
1477 bl @1
1478
1479 // Return routine
1480 frfree
1481 blr
1482
1483 @1
1484 // Prepare registers for nanokernel interrupt routine
1485 mtctr r1
1486 lwz r1,XLM_KERNEL_DATA
1487 stw r6,0x018(r1)
1488 mfctr r6
1489 stw r6,0x004(r1)
1490 lwz r6,0x65c(r1)
1491 stw r7,0x13c(r6)
1492 stw r8,0x144(r6)
1493 stw r9,0x14c(r6)
1494 stw r10,0x154(r6)
1495 stw r11,0x15c(r6)
1496 stw r12,0x164(r6)
1497 stw r13,0x16c(r6)
1498
1499 mflr r10
1500 mfcr r13
1501 lwz r7,0x660(r1)
1502 mflr r12
1503 rlwimi. r7,r7,8,0,0
1504 li r11,0
1505 ori r11,r11,0xf072 // MSR (SRR1)
1506 mtcrf 0x70,r11
1507 li r8,0
1508
1509 // Enter nanokernel
1510 mtlr r3
1511 blr
1512 }
1513 #endif
1514
1515 void SheepShaver::sigusr1_handler(vregs *r)
1516 {
1517 // Do nothing if interrupts are disabled
1518 if ((*(int32 *)XLM_IRQ_NEST) > 0)
1519 return;
1520
1521 // Interrupt action depends on current run mode
1522 switch (*(uint32 *)XLM_RUN_MODE) {
1523 case MODE_68K:
1524 // 68k emulator active, trigger 68k interrupt level 1
1525 *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1;
1526 r->cr |= kernel_data->v[0x674 >> 2];
1527 break;
1528
1529 #if INTERRUPTS_IN_NATIVE_MODE
1530 case MODE_NATIVE:
1531 // 68k emulator inactive, in nanokernel?
1532 if (r->r1 != KernelDataAddr) {
1533 // No, prepare for 68k interrupt level 1
1534 *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1;
1535 *(uint32 *)(kernel_data->v[0x658 >> 2] + 0xdc) |= kernel_data->v[0x674 >> 2];
1536
1537 // Execute nanokernel interrupt routine (this will activate the 68k emulator)
1538 atomic_add((int32 *)XLM_IRQ_NEST, 1);
1539 if (ROMType == ROMTYPE_NEWWORLD)
1540 ppc_interrupt(ROM_BASE + 0x312b1c);
1541 else
1542 ppc_interrupt(ROM_BASE + 0x312a3c);
1543 }
1544 break;
1545 #endif
1546
1547 #if INTERRUPTS_IN_EMUL_OP_MODE
1548 case MODE_EMUL_OP:
1549 // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
1550 if ((*(uint32 *)XLM_68K_R25 & 7) == 0) {
1551
1552 // Set extra stack for SIGSEGV handler
1553 set_signal_stack(extra_stack, SIG_STACK_SIZE);
1554 #if 1
1555 // Execute full 68k interrupt routine
1556 M68kRegisters r;
1557 uint32 old_r25 = *(uint32 *)XLM_68K_R25; // Save interrupt level
1558 *(uint32 *)XLM_68K_R25 = 0x21; // Execute with interrupt level 1
1559 static const uint16 proc[] = {
1560 0x3f3c, 0x0000, // move.w #$0000,-(sp) (fake format word)
1561 0x487a, 0x000a, // pea @1(pc) (return address)
1562 0x40e7, // move sr,-(sp) (saved SR)
1563 0x2078, 0x0064, // move.l $64,a0
1564 0x4ed0, // jmp (a0)
1565 M68K_RTS // @1
1566 };
1567 Execute68k((uint32)proc, &r);
1568 *(uint32 *)XLM_68K_R25 = old_r25; // Restore interrupt level
1569 #else
1570 // Only update cursor
1571 if (HasMacStarted()) {
1572 if (InterruptFlags & INTFLAG_VIA) {
1573 ClearInterruptFlag(INTFLAG_VIA);
1574 ADBInterrupt();
1575 ExecuteNative(NATIVE_VIDEO_VBL);
1576 }
1577 }
1578 #endif
1579 // Reset normal signal stack
1580 set_signal_stack(sig_stack, SIG_STACK_SIZE);
1581 }
1582 break;
1583 #endif
1584 }
1585 }
1586
1587
1588 /*
1589 * SIGSEGV handler
1590 */
1591
1592 static uint32 segv_r[32];
1593
1594 #if !EMULATED_PPC
1595 asm void SheepShaver::sigsegv_invoc(register int sig, register void *arg, register vregs *r)
1596 {
1597 mflr r0
1598 stw r0,8(r1)
1599 stwu r1,-56(r1)
1600
1601 lwz r3,segv_r(r2)
1602 stmw r13,13*4(r3)
1603
1604 mr r3,r5
1605 bl sigsegv_handler
1606
1607 lwz r3,segv_r(r2)
1608 lmw r13,13*4(r3)
1609
1610 lwz r0,56+8(r1)
1611 mtlr r0
1612 addi r1,r1,56
1613 blr
1614 }
1615 #endif
1616
1617 static void sigsegv_handler(vregs *r)
1618 {
1619 char str[256];
1620
1621 // Fetch volatile registers
1622 segv_r[0] = r->r0;
1623 segv_r[1] = r->r1;
1624 segv_r[2] = r->r2;
1625 segv_r[3] = r->r3;
1626 segv_r[4] = r->r4;
1627 segv_r[5] = r->r5;
1628 segv_r[6] = r->r6;
1629 segv_r[7] = r->r7;
1630 segv_r[8] = r->r8;
1631 segv_r[9] = r->r9;
1632 segv_r[10] = r->r10;
1633 segv_r[11] = r->r11;
1634 segv_r[12] = r->r12;
1635
1636 // Get opcode and divide into fields
1637 uint32 opcode = *(uint32 *)r->pc;
1638 uint32 primop = opcode >> 26;
1639 uint32 exop = (opcode >> 1) & 0x3ff;
1640 uint32 ra = (opcode >> 16) & 0x1f;
1641 uint32 rb = (opcode >> 11) & 0x1f;
1642 uint32 rd = (opcode >> 21) & 0x1f;
1643 uint32 imm = opcode & 0xffff;
1644
1645 // Fault in Mac ROM or RAM?
1646 bool mac_fault = (r->pc >= ROM_BASE) && (r->pc < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc >= RAMBase) && (r->pc < (RAMBase + RAMSize));
1647 if (mac_fault) {
1648
1649 // "VM settings" during MacOS 8 installation
1650 if (r->pc == ROM_BASE + 0x488160 && segv_r[20] == 0xf8000000) {
1651 r->pc += 4;
1652 segv_r[8] = 0;
1653 goto rti;
1654
1655 // MacOS 8.5 installation
1656 } else if (r->pc == ROM_BASE + 0x488140 && segv_r[16] == 0xf8000000) {
1657 r->pc += 4;
1658 segv_r[8] = 0;
1659 goto rti;
1660
1661 // MacOS 8 serial drivers on startup
1662 } else if (r->pc == ROM_BASE + 0x48e080 && (segv_r[8] == 0xf3012002 || segv_r[8] == 0xf3012000)) {
1663 r->pc += 4;
1664 segv_r[8] = 0;
1665 goto rti;
1666
1667 // MacOS 8.1 serial drivers on startup
1668 } else if (r->pc == ROM_BASE + 0x48c5e0 && (segv_r[20] == 0xf3012002 || segv_r[20] == 0xf3012000)) {
1669 r->pc += 4;
1670 goto rti;
1671 } else if (r->pc == ROM_BASE + 0x4a10a0 && (segv_r[20] == 0xf3012002 || segv_r[20] == 0xf3012000)) {
1672 r->pc += 4;
1673 goto rti;
1674 }
1675 }
1676
1677 // Analyze opcode
1678 enum {
1679 TYPE_UNKNOWN,
1680 TYPE_LOAD,
1681 TYPE_STORE
1682 } transfer_type = TYPE_UNKNOWN;
1683 enum {
1684 SIZE_UNKNOWN,
1685 SIZE_BYTE,
1686 SIZE_HALFWORD,
1687 SIZE_WORD
1688 } transfer_size = SIZE_UNKNOWN;
1689 enum {
1690 MODE_UNKNOWN,
1691 MODE_NORM,
1692 MODE_U,
1693 MODE_X,
1694 MODE_UX
1695 } addr_mode = MODE_UNKNOWN;
1696 switch (primop) {
1697 case 31:
1698 switch (exop) {
1699 case 23: // lwzx
1700 transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1701 case 55: // lwzux
1702 transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1703 case 87: // lbzx
1704 transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1705 case 119: // lbzux
1706 transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1707 case 151: // stwx
1708 transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
1709 case 183: // stwux
1710 transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
1711 case 215: // stbx
1712 transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
1713 case 247: // stbux
1714 transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
1715 case 279: // lhzx
1716 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1717 case 311: // lhzux
1718 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1719 case 343: // lhax
1720 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1721 case 375: // lhaux
1722 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1723 case 407: // sthx
1724 transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
1725 case 439: // sthux
1726 transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
1727 }
1728 break;
1729
1730 case 32: // lwz
1731 transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1732 case 33: // lwzu
1733 transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1734 case 34: // lbz
1735 transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1736 case 35: // lbzu
1737 transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1738 case 36: // stw
1739 transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
1740 case 37: // stwu
1741 transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
1742 case 38: // stb
1743 transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
1744 case 39: // stbu
1745 transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
1746 case 40: // lhz
1747 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1748 case 41: // lhzu
1749 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1750 case 42: // lha
1751 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1752 case 43: // lhau
1753 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1754 case 44: // sth
1755 transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
1756 case 45: // sthu
1757 transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
1758 }
1759
1760 // Calculate effective address
1761 uint32 addr = 0;
1762 switch (addr_mode) {
1763 case MODE_X:
1764 case MODE_UX:
1765 if (ra == 0)
1766 addr = segv_r[rb];
1767 else
1768 addr = segv_r[ra] + segv_r[rb];
1769 break;
1770 case MODE_NORM:
1771 case MODE_U:
1772 if (ra == 0)
1773 addr = (int32)(int16)imm;
1774 else
1775 addr = segv_r[ra] + (int32)(int16)imm;
1776 break;
1777 default:
1778 break;
1779 }
1780
1781 // Ignore ROM writes
1782 if (transfer_type == TYPE_STORE && addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) {
1783 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));
1784 if (addr_mode == MODE_U || addr_mode == MODE_UX)
1785 segv_r[ra] = addr;
1786 r->pc += 4;
1787 goto rti;
1788 }
1789
1790 // Fault in Mac ROM or RAM?
1791 if (mac_fault) {
1792
1793 // Ignore illegal memory accesses?
1794 if (PrefsFindBool("ignoresegv")) {
1795 if (addr_mode == MODE_U || addr_mode == MODE_UX)
1796 segv_r[ra] = addr;
1797 if (transfer_type == TYPE_LOAD)
1798 segv_r[rd] = 0;
1799 r->pc += 4;
1800 goto rti;
1801 }
1802
1803 // In GUI mode, show error alert
1804 if (!PrefsFindBool("nogui")) {
1805 if (transfer_type == TYPE_LOAD || transfer_type == TYPE_STORE)
1806 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]);
1807 else
1808 sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc, segv_r[24], segv_r[1], opcode);
1809 ErrorAlert(str);
1810 QuitEmulator();
1811 return;
1812 }
1813 }
1814
1815 // For all other errors, jump into debugger
1816 sprintf(str, "SIGSEGV\n"
1817 " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
1818 " xer %08lx cr %08lx fpscr %08lx\n"
1819 " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
1820 " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
1821 " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
1822 " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
1823 " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
1824 " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
1825 " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
1826 " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
1827 r->pc, r->lr, r->ctr, r->msr,
1828 r->xer, r->cr, r->fpscr,
1829 r->r0, r->r1, r->r2, r->r3,
1830 r->r4, r->r5, r->r6, r->r7,
1831 r->r8, r->r9, r->r10, r->r11,
1832 r->r12, segv_r[13], segv_r[14], segv_r[15],
1833 segv_r[16], segv_r[17], segv_r[18], segv_r[19],
1834 segv_r[20], segv_r[21], segv_r[22], segv_r[23],
1835 segv_r[24], segv_r[25], segv_r[26], segv_r[27],
1836 segv_r[28], segv_r[29], segv_r[30], segv_r[31]);
1837 VideoQuitFullScreen();
1838 disable_debugger(false);
1839 debugger(str);
1840 exit(1);
1841 return;
1842
1843 rti:
1844 // Restore volatile registers
1845 r->r0 = segv_r[0];
1846 r->r1 = segv_r[1];
1847 r->r2 = segv_r[2];
1848 r->r3 = segv_r[3];
1849 r->r4 = segv_r[4];
1850 r->r5 = segv_r[5];
1851 r->r6 = segv_r[6];
1852 r->r7 = segv_r[7];
1853 r->r8 = segv_r[8];
1854 r->r9 = segv_r[9];
1855 r->r10 = segv_r[10];
1856 r->r11 = segv_r[11];
1857 r->r12 = segv_r[12];
1858 }
1859
1860
1861 /*
1862 * SIGILL handler
1863 */
1864
1865 #if !EMULATED_PPC
1866 asm void SheepShaver::sigill_invoc(register int sig, register void *arg, register vregs *r)
1867 {
1868 mflr r0
1869 stw r0,8(r1)
1870 stwu r1,-56(r1)
1871
1872 lwz r3,segv_r(r2)
1873 stmw r13,13*4(r3)
1874
1875 mr r3,r5
1876 bl sigill_handler
1877
1878 lwz r3,segv_r(r2)
1879 lmw r13,13*4(r3)
1880
1881 lwz r0,56+8(r1)
1882 mtlr r0
1883 addi r1,r1,56
1884 blr
1885 }
1886 #endif
1887
1888 static void sigill_handler(vregs *r)
1889 {
1890 char str[256];
1891
1892 // Fetch volatile registers
1893 segv_r[0] = r->r0;
1894 segv_r[1] = r->r1;
1895 segv_r[2] = r->r2;
1896 segv_r[3] = r->r3;
1897 segv_r[4] = r->r4;
1898 segv_r[5] = r->r5;
1899 segv_r[6] = r->r6;
1900 segv_r[7] = r->r7;
1901 segv_r[8] = r->r8;
1902 segv_r[9] = r->r9;
1903 segv_r[10] = r->r10;
1904 segv_r[11] = r->r11;
1905 segv_r[12] = r->r12;
1906
1907 // Get opcode and divide into fields
1908 uint32 opcode = *(uint32 *)r->pc;
1909 uint32 primop = opcode >> 26;
1910 uint32 exop = (opcode >> 1) & 0x3ff;
1911 uint32 ra = (opcode >> 16) & 0x1f;
1912 uint32 rb = (opcode >> 11) & 0x1f;
1913 uint32 rd = (opcode >> 21) & 0x1f;
1914 uint32 imm = opcode & 0xffff;
1915
1916 // Fault in Mac ROM or RAM?
1917 bool mac_fault = (r->pc >= ROM_BASE) && (r->pc < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc >= RAMBase) && (r->pc < (RAMBase + RAMSize));
1918 if (mac_fault) {
1919
1920 switch (primop) {
1921 case 9: // POWER instructions
1922 case 22:
1923 power_inst: sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->pc, segv_r[1], opcode);
1924 ErrorAlert(str);
1925 QuitEmulator();
1926 return;
1927
1928 case 31:
1929 switch (exop) {
1930 case 83: // mfmsr
1931 segv_r[rd] = 0xf072;
1932 r->pc += 4;
1933 goto rti;
1934
1935 case 210: // mtsr
1936 case 242: // mtsrin
1937 case 306: // tlbie
1938 r->pc += 4;
1939 goto rti;
1940
1941 case 339: { // mfspr
1942 int spr = ra | (rb << 5);
1943 switch (spr) {
1944 case 0: // MQ
1945 case 22: // DEC
1946 case 952: // MMCR0
1947 case 953: // PMC1
1948 case 954: // PMC2
1949 case 955: // SIA
1950 case 956: // MMCR1
1951 case 957: // PMC3
1952 case 958: // PMC4
1953 case 959: // SDA
1954 r->pc += 4;
1955 goto rti;
1956 case 25: // SDR1
1957 segv_r[rd] = 0xdead001f;
1958 r->pc += 4;
1959 goto rti;
1960 case 287: // PVR
1961 segv_r[rd] = PVR;
1962 r->pc += 4;
1963 goto rti;
1964 }
1965 break;
1966 }
1967
1968 case 467: { // mtspr
1969 int spr = ra | (rb << 5);
1970 switch (spr) {
1971 case 0: // MQ
1972 case 22: // DEC
1973 case 275: // SPRG3
1974 case 528: // IBAT0U
1975 case 529: // IBAT0L
1976 case 530: // IBAT1U
1977 case 531: // IBAT1L
1978 case 532: // IBAT2U
1979 case 533: // IBAT2L
1980 case 534: // IBAT3U
1981 case 535: // IBAT3L
1982 case 536: // DBAT0U
1983 case 537: // DBAT0L
1984 case 538: // DBAT1U
1985 case 539: // DBAT1L
1986 case 540: // DBAT2U
1987 case 541: // DBAT2L
1988 case 542: // DBAT3U
1989 case 543: // DBAT3L
1990 case 952: // MMCR0
1991 case 953: // PMC1
1992 case 954: // PMC2
1993 case 955: // SIA
1994 case 956: // MMCR1
1995 case 957: // PMC3
1996 case 958: // PMC4
1997 case 959: // SDA
1998 r->pc += 4;
1999 goto rti;
2000 }
2001 break;
2002 }
2003
2004 case 29: case 107: case 152: case 153: // POWER instructions
2005 case 184: case 216: case 217: case 248:
2006 case 264: case 277: case 331: case 360:
2007 case 363: case 488: case 531: case 537:
2008 case 541: case 664: case 665: case 696:
2009 case 728: case 729: case 760: case 920:
2010 case 921: case 952:
2011 goto power_inst;
2012 }
2013 }
2014
2015 // In GUI mode, show error alert
2016 if (!PrefsFindBool("nogui")) {
2017 sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc, segv_r[24], segv_r[1], opcode);
2018 ErrorAlert(str);
2019 QuitEmulator();
2020 return;
2021 }
2022 }
2023
2024 // For all other errors, jump into debugger
2025 sprintf(str, "SIGILL\n"
2026 " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
2027 " xer %08lx cr %08lx fpscr %08lx\n"
2028 " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
2029 " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
2030 " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
2031 " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
2032 " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
2033 " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
2034 " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
2035 " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
2036 r->pc, r->lr, r->ctr, r->msr,
2037 r->xer, r->cr, r->fpscr,
2038 r->r0, r->r1, r->r2, r->r3,
2039 r->r4, r->r5, r->r6, r->r7,
2040 r->r8, r->r9, r->r10, r->r11,
2041 r->r12, segv_r[13], segv_r[14], segv_r[15],
2042 segv_r[16], segv_r[17], segv_r[18], segv_r[19],
2043 segv_r[20], segv_r[21], segv_r[22], segv_r[23],
2044 segv_r[24], segv_r[25], segv_r[26], segv_r[27],
2045 segv_r[28], segv_r[29], segv_r[30], segv_r[31]);
2046 VideoQuitFullScreen();
2047 disable_debugger(false);
2048 debugger(str);
2049 exit(1);
2050 return;
2051
2052 rti:
2053 // Restore volatile registers
2054 r->r0 = segv_r[0];
2055 r->r1 = segv_r[1];
2056 r->r2 = segv_r[2];
2057 r->r3 = segv_r[3];
2058 r->r4 = segv_r[4];
2059 r->r5 = segv_r[5];
2060 r->r6 = segv_r[6];
2061 r->r7 = segv_r[7];
2062 r->r8 = segv_r[8];
2063 r->r9 = segv_r[9];
2064 r->r10 = segv_r[10];
2065 r->r11 = segv_r[11];
2066 r->r12 = segv_r[12];
2067 }
2068
2069
2070 /*
2071 * Helpers to share 32-bit addressable data with MacOS
2072 */
2073
2074 bool SheepMem::Init(void)
2075 {
2076 // Delete old area
2077 area_id old_sheep_area = find_area(SHEEP_AREA_NAME);
2078 if (old_sheep_area > 0)
2079 delete_area(old_sheep_area);
2080
2081 // Create area for SheepShaver data
2082 base = 0x60000000;
2083 SheepMemArea = create_area(SHEEP_AREA_NAME, (void **)&base, B_BASE_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
2084 if (SheepMemArea < 0)
2085 return false;
2086
2087 // Create read-only area with all bits set to 0
2088 static const uint8 const_zero_page[4096] = {0,};
2089 zero_page = const_zero_page;
2090
2091 D(bug("SheepShaver area %ld at %p\n", SheepMemArea, base));
2092 top = base + size;
2093 return true;
2094 }
2095
2096 void SheepMem::Exit(void)
2097 {
2098 if (SheepMemArea >= 0)
2099 delete_area(SheepMemArea);
2100 }
2101
2102
2103 /*
2104 * Display error alert
2105 */
2106
2107 void ErrorAlert(const char *text)
2108 {
2109 if (PrefsFindBool("nogui")) {
2110 printf(GetString(STR_SHELL_ERROR_PREFIX), text);
2111 return;
2112 }
2113 char str[256];
2114 sprintf(str, GetString(STR_GUI_ERROR_PREFIX), text);
2115 VideoQuitFullScreen();
2116 BAlert *alert = new BAlert(GetString(STR_ERROR_ALERT_TITLE), str, GetString(STR_QUIT_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
2117 alert->Go();
2118 }
2119
2120
2121 /*
2122 * Display warning alert
2123 */
2124
2125 void WarningAlert(const char *text)
2126 {
2127 if (PrefsFindBool("nogui")) {
2128 printf(GetString(STR_SHELL_WARNING_PREFIX), text);
2129 return;
2130 }
2131 char str[256];
2132 sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
2133 BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, GetString(STR_OK_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
2134 alert->Go();
2135 }
2136
2137
2138 /*
2139 * Display choice alert
2140 */
2141
2142 bool ChoiceAlert(const char *text, const char *pos, const char *neg)
2143 {
2144 char str[256];
2145 sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
2146 BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, pos, neg, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
2147 return alert->Go() == 0;
2148 }