ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/main_beos.cpp
Revision: 1.4
Committed: 2003-10-26T00:32:27Z (20 years, 8 months ago) by cebix
Branch: MAIN
Changes since 1.3: +4 -3 lines
Log Message:
- fixed compilation problems under BeOS
- boot drive wasn't set correctly

File Contents

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