ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Windows/main_windows.cpp
Revision: 1.18
Committed: 2009-08-26T00:11:56Z (14 years, 9 months ago) by asvitkine
Branch: MAIN
Changes since 1.17: +2 -2 lines
Log Message:
[Michael Schmitt]
Attached is a patch to SheepShaver, to fix a problem where the ROM file can only be found on the first boot.

When a user creates a new SheepShaver machine, there is no preference file, so there is not ROM path preference. SheepShaver has logic so that in this case, it will look for a ROM file named "ROM" or "Mac OS ROM" in the current directory.

The user starts SheepShaver in order to get to the built-in Preferences Editor, and changes various settings (such as creation of a hard disk). Then the user reboots.

If the user forgot to set the ROM path at this time, then SheepShaver can no longer boot. The only recourse is for the user to find and delete the preferences file, or use an external preferences editor to set the ROM path.

The fix is to change SheepShaver to use the default ROM names when either the rom path is null (no preference) OR an empty string (preference exists with no rom path).

File Contents

# Content
1 /*
2 * main_windows.cpp - Emulation core, Windows implementation
3 *
4 * SheepShaver (C) 1997-2008 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 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <SDL.h>
27
28 #include "sysdeps.h"
29 #include "main.h"
30 #include "version.h"
31 #include "prefs.h"
32 #include "prefs_editor.h"
33 #include "cpu_emulation.h"
34 #include "emul_op.h"
35 #include "xlowmem.h"
36 #include "xpram.h"
37 #include "timer.h"
38 #include "adb.h"
39 #include "video.h"
40 #include "sys.h"
41 #include "macos_util.h"
42 #include "rom_patches.h"
43 #include "user_strings.h"
44 #include "vm_alloc.h"
45 #include "sigsegv.h"
46 #include "util_windows.h"
47 #include "kernel_windows.h"
48
49 #define DEBUG 0
50 #include "debug.h"
51
52 #ifdef ENABLE_MON
53 #include "mon.h"
54 #endif
55
56
57 // Constants
58 const char ROM_FILE_NAME[] = "ROM";
59 const char ROM_FILE_NAME2[] = "Mac OS ROM";
60
61 const uintptr ROM_BASE = 0x40800000; // Base address of ROM
62
63 const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack
64
65
66 // Global variables (exported)
67 uint32 RAMBase; // Base address of Mac RAM
68 uint32 RAMSize; // Size of Mac RAM
69 uint32 ROMBase; // Base address of Mac ROM
70 uint32 KernelDataAddr; // Address of Kernel Data
71 uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM
72 uint32 DRCacheAddr; // Address of DR Cache
73 uint32 PVR; // Theoretical PVR
74 int64 CPUClockSpeed; // Processor clock speed (Hz)
75 int64 BusClockSpeed; // Bus clock speed (Hz)
76 int64 TimebaseSpeed; // Timebase clock speed (Hz)
77 uint8 *RAMBaseHost; // Base address of Mac RAM (host address space)
78 uint8 *ROMBaseHost; // Base address of Mac ROM (host address space)
79 DWORD win_os; // Windows OS id
80 DWORD win_os_major; // Windows OS version major
81
82
83 // Global variables
84 static int kernel_area = -1; // SHM ID of Kernel Data area
85 static bool rom_area_mapped = false; // Flag: Mac ROM mmap()ped
86 static bool ram_area_mapped = false; // Flag: Mac RAM mmap()ped
87 static bool dr_cache_area_mapped = false; // Flag: Mac DR Cache mmap()ped
88 static bool dr_emulator_area_mapped = false;// Flag: Mac DR Emulator mmap()ped
89 static KernelData *kernel_data; // Pointer to Kernel Data
90 static EmulatorData *emulator_data;
91
92 static uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes
93 static bool nvram_thread_active = false; // Flag: NVRAM watchdog installed
94 static volatile bool nvram_thread_cancel; // Flag: Cancel NVRAM thread
95 static HANDLE nvram_thread = NULL; // NVRAM watchdog
96 static bool tick_thread_active = false; // Flag: MacOS thread installed
97 static volatile bool tick_thread_cancel; // Flag: Cancel 60Hz thread
98 static HANDLE tick_thread = NULL; // 60Hz thread
99 static HANDLE emul_thread = NULL; // MacOS thread
100 static uintptr sig_stack = 0; // Stack for PowerPC interrupt routine
101
102 uint32 SheepMem::page_size; // Size of a native page
103 uintptr SheepMem::zero_page = 0; // Address of ro page filled in with zeros
104 uintptr SheepMem::base = 0x60000000; // Address of SheepShaver data
105 uintptr SheepMem::proc; // Bottom address of SheepShave procedures
106 uintptr SheepMem::data; // Top of SheepShaver data (stack like storage)
107
108
109 // Prototypes
110 static bool kernel_data_init(void);
111 static void kernel_data_exit(void);
112 static void Quit(void);
113 static DWORD WINAPI nvram_func(void *arg);
114 static DWORD WINAPI tick_func(void *arg);
115
116 static void jump_to_rom(uint32 entry);
117 extern void emul_ppc(uint32 start);
118 extern void init_emul_ppc(void);
119 extern void exit_emul_ppc(void);
120 sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip);
121
122
123 /*
124 * Return signal stack base
125 */
126
127 uintptr SignalStackBase(void)
128 {
129 return sig_stack + SIG_STACK_SIZE;
130 }
131
132
133 /*
134 * Memory management helpers
135 */
136
137 static inline int vm_mac_acquire(uint32 addr, uint32 size)
138 {
139 return vm_acquire_fixed(Mac2HostAddr(addr), size);
140 }
141
142 static inline int vm_mac_release(uint32 addr, uint32 size)
143 {
144 return vm_release(Mac2HostAddr(addr), size);
145 }
146
147
148 /*
149 * Main program
150 */
151
152 static void usage(const char *prg_name)
153 {
154 printf("Usage: %s [OPTION...]\n", prg_name);
155 printf("\nUnix options:\n");
156 printf(" --display STRING\n X display to use\n");
157 PrefsPrintUsage();
158 exit(0);
159 }
160
161 int main(int argc, char **argv)
162 {
163 char str[256];
164 int16 i16;
165 HANDLE rom_fh;
166 const char *rom_path;
167 uint32 rom_size;
168 DWORD actual;
169 uint8 *rom_tmp;
170
171 // Initialize variables
172 RAMBase = 0;
173
174 // Print some info
175 printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
176 printf(" %s\n", GetString(STR_ABOUT_TEXT2));
177
178 // Read preferences
179 PrefsInit(NULL, argc, argv);
180
181 // Parse command line arguments
182 for (int i=1; i<argc; i++) {
183 if (strcmp(argv[i], "--help") == 0) {
184 usage(argv[0]);
185 } else if (argv[i][0] == '-') {
186 fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
187 usage(argv[0]);
188 }
189 }
190
191 // Check we are using a Windows NT kernel >= 4.0
192 OSVERSIONINFO osvi;
193 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
194 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
195 if (!GetVersionEx(&osvi)) {
196 ErrorAlert("Could not determine OS type");
197 QuitEmulator();
198 }
199 win_os = osvi.dwPlatformId;
200 win_os_major = osvi.dwMajorVersion;
201 if (win_os != VER_PLATFORM_WIN32_NT || win_os_major < 4) {
202 ErrorAlert(GetString(STR_NO_WIN32_NT_4));
203 QuitEmulator();
204 }
205
206 // Check that drivers are installed
207 if (!check_drivers())
208 QuitEmulator();
209
210 // Load win32 libraries
211 KernelInit();
212
213 // FIXME: default to DIB driver
214 if (getenv("SDL_VIDEODRIVER") == NULL)
215 putenv("SDL_VIDEODRIVER=windib");
216
217 // Initialize SDL system
218 int sdl_flags = 0;
219 #ifdef USE_SDL_VIDEO
220 sdl_flags |= SDL_INIT_VIDEO;
221 #endif
222 #ifdef USE_SDL_AUDIO
223 sdl_flags |= SDL_INIT_AUDIO;
224 #endif
225 assert(sdl_flags != 0);
226 if (SDL_Init(sdl_flags) == -1) {
227 char str[256];
228 sprintf(str, "Could not initialize SDL: %s.\n", SDL_GetError());
229 ErrorAlert(str);
230 goto quit;
231 }
232 atexit(SDL_Quit);
233
234 #ifdef ENABLE_MON
235 // Initialize mon
236 mon_init();
237 #endif
238
239 // Install SIGSEGV handler for CPU emulator
240 if (!sigsegv_install_handler(sigsegv_handler)) {
241 sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno));
242 ErrorAlert(str);
243 goto quit;
244 }
245
246 // Initialize VM system
247 vm_init();
248
249 // Get system info
250 PVR = 0x00040000; // Default: 604
251 CPUClockSpeed = 100000000; // Default: 100MHz
252 BusClockSpeed = 100000000; // Default: 100MHz
253 TimebaseSpeed = 25000000; // Default: 25MHz
254 PVR = 0x000c0000; // Default: 7400 (with AltiVec)
255 D(bug("PVR: %08x (assumed)\n", PVR));
256
257 // Init system routines
258 SysInit();
259
260 // Show preferences editor
261 if (!PrefsFindBool("nogui"))
262 if (!PrefsEditor())
263 goto quit;
264
265 // Create areas for Kernel Data
266 if (!kernel_data_init())
267 goto quit;
268 kernel_data = (KernelData *)Mac2HostAddr(KERNEL_DATA_BASE);
269 emulator_data = &kernel_data->ed;
270 KernelDataAddr = KERNEL_DATA_BASE;
271 D(bug("Kernel Data at %p (%08x)\n", kernel_data, KERNEL_DATA_BASE));
272 D(bug("Emulator Data at %p (%08x)\n", emulator_data, KERNEL_DATA_BASE + offsetof(KernelData, ed)));
273
274 // Create area for DR Cache
275 if (vm_mac_acquire(DR_EMULATOR_BASE, DR_EMULATOR_SIZE) < 0) {
276 sprintf(str, GetString(STR_DR_EMULATOR_MMAP_ERR), strerror(errno));
277 ErrorAlert(str);
278 goto quit;
279 }
280 dr_emulator_area_mapped = true;
281 if (vm_mac_acquire(DR_CACHE_BASE, DR_CACHE_SIZE) < 0) {
282 sprintf(str, GetString(STR_DR_CACHE_MMAP_ERR), strerror(errno));
283 ErrorAlert(str);
284 goto quit;
285 }
286 dr_cache_area_mapped = true;
287 DRCacheAddr = (uint32)Mac2HostAddr(DR_CACHE_BASE);
288 D(bug("DR Cache at %p (%08x)\n", DRCacheAddr, DR_CACHE_BASE));
289
290 // Create area for SheepShaver data
291 if (!SheepMem::Init()) {
292 sprintf(str, GetString(STR_SHEEP_MEM_MMAP_ERR), strerror(errno));
293 ErrorAlert(str);
294 goto quit;
295 }
296
297 // Create area for Mac ROM
298 if (vm_mac_acquire(ROM_BASE, ROM_AREA_SIZE) < 0) {
299 sprintf(str, GetString(STR_ROM_MMAP_ERR), strerror(errno));
300 ErrorAlert(str);
301 goto quit;
302 }
303 ROMBase = ROM_BASE;
304 ROMBaseHost = Mac2HostAddr(ROMBase);
305 rom_area_mapped = true;
306 D(bug("ROM area at %p (%08x)\n", ROMBaseHost, ROMBase));
307
308 // Create area for Mac RAM
309 RAMSize = PrefsFindInt32("ramsize");
310 if (RAMSize < 8*1024*1024) {
311 WarningAlert(GetString(STR_SMALL_RAM_WARN));
312 RAMSize = 8*1024*1024;
313 }
314 RAMBase = 0;
315 if (vm_mac_acquire(RAMBase, RAMSize) < 0) {
316 sprintf(str, GetString(STR_RAM_MMAP_ERR), strerror(errno));
317 ErrorAlert(str);
318 goto quit;
319 }
320 RAMBaseHost = Mac2HostAddr(RAMBase);
321 ram_area_mapped = true;
322 D(bug("RAM area at %p (%08x)\n", RAMBaseHost, RAMBase));
323
324 if (RAMBase > ROMBase) {
325 ErrorAlert(GetString(STR_RAM_HIGHER_THAN_ROM_ERR));
326 goto quit;
327 }
328
329 // Load Mac ROM
330 rom_path = PrefsFindString("rom");
331 rom_fh = CreateFile(rom_path && *rom_path ? rom_path : ROM_FILE_NAME,
332 GENERIC_READ, 0, NULL, OPEN_EXISTING,
333 FILE_ATTRIBUTE_NORMAL, NULL);
334
335 if (rom_fh == INVALID_HANDLE_VALUE) {
336 rom_fh = CreateFile(ROM_FILE_NAME2,
337 GENERIC_READ, 0, NULL, OPEN_EXISTING,
338 FILE_ATTRIBUTE_NORMAL, NULL);
339
340 if (rom_fh == INVALID_HANDLE_VALUE) {
341 ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
342 goto quit;
343 }
344 }
345 printf(GetString(STR_READING_ROM_FILE));
346 rom_size = GetFileSize(rom_fh, NULL);
347 rom_tmp = new uint8[ROM_SIZE];
348 ReadFile(rom_fh, (void *)rom_tmp, ROM_SIZE, &actual, NULL);
349 CloseHandle(rom_fh);
350
351 // Decode Mac ROM
352 if (!DecodeROM(rom_tmp, actual)) {
353 if (rom_size != 4*1024*1024) {
354 ErrorAlert(GetString(STR_ROM_SIZE_ERR));
355 goto quit;
356 } else {
357 ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
358 goto quit;
359 }
360 }
361 delete[] rom_tmp;
362
363 // Initialize native timers
364 timer_init();
365
366 // Initialize everything
367 if (!InitAll())
368 goto quit;
369 D(bug("Initialization complete\n"));
370
371 // Write protect ROM
372 vm_protect(ROMBaseHost, ROM_AREA_SIZE, VM_PAGE_READ);
373
374 // Start 60Hz thread
375 tick_thread_cancel = false;
376 tick_thread_active = ((tick_thread = create_thread(tick_func)) != NULL);
377 SetThreadPriority(tick_thread, THREAD_PRIORITY_ABOVE_NORMAL);
378 D(bug("Tick thread installed (%ld)\n", tick_thread));
379
380 // Start NVRAM watchdog thread
381 memcpy(last_xpram, XPRAM, XPRAM_SIZE);
382 nvram_thread_cancel = false;
383 nvram_thread_active = ((nvram_thread = create_thread(nvram_func, NULL)) != NULL);
384 SetThreadPriority(nvram_thread, THREAD_PRIORITY_BELOW_NORMAL);
385 D(bug("NVRAM thread installed (%ld)\n", nvram_thread));
386
387 // Get my thread ID and jump to ROM boot routine
388 emul_thread = GetCurrentThread();
389 D(bug("Jumping to ROM\n"));
390 jump_to_rom(ROMBase + 0x310000);
391 D(bug("Returned from ROM\n"));
392
393 quit:
394 Quit();
395 return 0;
396 }
397
398
399 /*
400 * Cleanup and quit
401 */
402
403 static void Quit(void)
404 {
405 // Exit PowerPC emulation
406 exit_emul_ppc();
407
408 // Stop 60Hz thread
409 if (tick_thread_active) {
410 tick_thread_cancel = true;
411 wait_thread(tick_thread);
412 }
413
414 // Stop NVRAM watchdog thread
415 if (nvram_thread_active) {
416 nvram_thread_cancel = true;
417 wait_thread(nvram_thread);
418 }
419
420 // Deinitialize everything
421 ExitAll();
422
423 // Delete SheepShaver globals
424 SheepMem::Exit();
425
426 // Delete RAM area
427 if (ram_area_mapped)
428 vm_mac_release(RAMBase, RAMSize);
429
430 // Delete ROM area
431 if (rom_area_mapped)
432 vm_mac_release(ROMBase, ROM_AREA_SIZE);
433
434 // Delete DR cache areas
435 if (dr_emulator_area_mapped)
436 vm_mac_release(DR_EMULATOR_BASE, DR_EMULATOR_SIZE);
437 if (dr_cache_area_mapped)
438 vm_mac_release(DR_CACHE_BASE, DR_CACHE_SIZE);
439
440 // Delete Kernel Data area
441 kernel_data_exit();
442
443 // Exit system routines
444 SysExit();
445
446 // Exit preferences
447 PrefsExit();
448
449 // Release win32 libraries
450 KernelExit();
451
452 #ifdef ENABLE_MON
453 // Exit mon
454 mon_exit();
455 #endif
456
457 exit(0);
458 }
459
460
461 /*
462 * Initialize Kernel Data segments
463 */
464
465 static HANDLE kernel_handle; // Shared memory handle for Kernel Data
466 static DWORD allocation_granule; // Minimum size of allocateable are (64K)
467 static DWORD kernel_area_size; // Size of Kernel Data area
468
469 static bool kernel_data_init(void)
470 {
471 char str[256];
472 SYSTEM_INFO si;
473 GetSystemInfo(&si);
474 allocation_granule = si.dwAllocationGranularity;
475 kernel_area_size = (KERNEL_AREA_SIZE + allocation_granule - 1) & -allocation_granule;
476
477 char rcs[10];
478 LPVOID kernel_addr;
479 kernel_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, kernel_area_size, NULL);
480 if (kernel_handle == NULL) {
481 sprintf(rcs, "%d", GetLastError());
482 sprintf(str, GetString(STR_KD_SHMGET_ERR), rcs);
483 ErrorAlert(str);
484 return false;
485 }
486 kernel_addr = (LPVOID)Mac2HostAddr(KERNEL_DATA_BASE & -allocation_granule);
487 if (MapViewOfFileEx(kernel_handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kernel_area_size, kernel_addr) != kernel_addr) {
488 sprintf(rcs, "%d", GetLastError());
489 sprintf(str, GetString(STR_KD_SHMAT_ERR), rcs);
490 ErrorAlert(str);
491 return false;
492 }
493 kernel_addr = (LPVOID)Mac2HostAddr(KERNEL_DATA2_BASE & -allocation_granule);
494 if (MapViewOfFileEx(kernel_handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kernel_area_size, kernel_addr) != kernel_addr) {
495 sprintf(rcs, "%d", GetLastError());
496 sprintf(str, GetString(STR_KD2_SHMAT_ERR), rcs);
497 ErrorAlert(str);
498 return false;
499 }
500 return true;
501 }
502
503
504 /*
505 * Deallocate Kernel Data segments
506 */
507
508 static void kernel_data_exit(void)
509 {
510 if (kernel_handle) {
511 UnmapViewOfFile(Mac2HostAddr(KERNEL_DATA_BASE & -allocation_granule));
512 UnmapViewOfFile(Mac2HostAddr(KERNEL_DATA2_BASE & -allocation_granule));
513 CloseHandle(kernel_handle);
514 }
515 }
516
517
518 /*
519 * Jump into Mac ROM, start 680x0 emulator
520 */
521
522 void jump_to_rom(uint32 entry)
523 {
524 init_emul_ppc();
525 emul_ppc(entry);
526 }
527
528
529 /*
530 * Quit emulator (cause return from jump_to_rom)
531 */
532
533 void QuitEmulator(void)
534 {
535 Quit();
536 }
537
538
539 /*
540 * Pause/resume emulator
541 */
542
543 void PauseEmulator(void)
544 {
545 SuspendThread(emul_thread);
546 }
547
548 void ResumeEmulator(void)
549 {
550 ResumeThread(emul_thread);
551 }
552
553
554 /*
555 * Dump 68k registers
556 */
557
558 void Dump68kRegs(M68kRegisters *r)
559 {
560 // Display 68k registers
561 for (int i=0; i<8; i++) {
562 printf("d%d: %08x", i, r->d[i]);
563 if (i == 3 || i == 7)
564 printf("\n");
565 else
566 printf(", ");
567 }
568 for (int i=0; i<8; i++) {
569 printf("a%d: %08x", i, r->a[i]);
570 if (i == 3 || i == 7)
571 printf("\n");
572 else
573 printf(", ");
574 }
575 }
576
577
578 /*
579 * Make code executable
580 */
581
582 void MakeExecutable(int dummy, uint32 start, uint32 length)
583 {
584 if ((start >= ROMBase) && (start < (ROMBase + ROM_SIZE)))
585 return;
586 FlushCodeCache(start, start + length);
587 }
588
589
590 /*
591 * NVRAM watchdog thread (saves NVRAM every minute)
592 */
593
594 static void nvram_watchdog(void)
595 {
596 if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
597 memcpy(last_xpram, XPRAM, XPRAM_SIZE);
598 SaveXPRAM();
599 }
600 }
601
602 static DWORD nvram_func(void *arg)
603 {
604 while (!nvram_thread_cancel) {
605 for (int i=0; i<60 && !nvram_thread_cancel; i++)
606 Delay_usec(999999); // Only wait 1 second so we quit promptly when nvram_thread_cancel becomes true
607 nvram_watchdog();
608 }
609 return 0;
610 }
611
612
613 /*
614 * 60Hz thread (really 60.15Hz)
615 */
616
617 static DWORD tick_func(void *arg)
618 {
619 int tick_counter = 0;
620 uint64 start = GetTicks_usec();
621 int64 ticks = 0;
622 uint64 next = GetTicks_usec();
623
624 while (!tick_thread_cancel) {
625
626 // Wait
627 next += 16625;
628 int64 delay = next - GetTicks_usec();
629 if (delay > 0)
630 Delay_usec(delay);
631 else if (delay < -16625)
632 next = GetTicks_usec();
633 ticks++;
634
635 // Pseudo Mac 1Hz interrupt, update local time
636 if (++tick_counter > 60) {
637 tick_counter = 0;
638 WriteMacInt32(0x20c, TimerDateTime());
639 }
640
641 // Trigger 60Hz interrupt
642 if (ReadMacInt32(XLM_IRQ_NEST) == 0) {
643 SetInterruptFlag(INTFLAG_VIA);
644 TriggerInterrupt();
645 }
646 }
647
648 uint64 end = GetTicks_usec();
649 D(bug("%lu ticks in %lu usec = %f ticks/sec\n", (unsigned long)ticks, (unsigned long)(end - start), ticks * 1000000.0 / (end - start)));
650 return 0;
651 }
652
653
654 /*
655 * Mutexes
656 */
657
658 struct B2_mutex {
659 mutex_t m;
660 };
661
662 B2_mutex *B2_create_mutex(void)
663 {
664 return new B2_mutex;
665 }
666
667 void B2_lock_mutex(B2_mutex *mutex)
668 {
669 mutex->m.lock();
670 }
671
672 void B2_unlock_mutex(B2_mutex *mutex)
673 {
674 mutex->m.unlock();
675 }
676
677 void B2_delete_mutex(B2_mutex *mutex)
678 {
679 delete mutex;
680 }
681
682
683 /*
684 * Interrupt flags (must be handled atomically!)
685 */
686
687 volatile uint32 InterruptFlags = 0;
688 static mutex_t intflags_mutex;
689
690 void SetInterruptFlag(uint32 flag)
691 {
692 intflags_mutex.lock();
693 InterruptFlags |= flag;
694 intflags_mutex.unlock();
695 }
696
697 void ClearInterruptFlag(uint32 flag)
698 {
699 intflags_mutex.lock();
700 InterruptFlags &= ~flag;
701 intflags_mutex.unlock();
702 }
703
704
705 /*
706 * Disable interrupts
707 */
708
709 void DisableInterrupt(void)
710 {
711 WriteMacInt32(XLM_IRQ_NEST, int32(ReadMacInt32(XLM_IRQ_NEST)) + 1);
712 }
713
714
715 /*
716 * Enable interrupts
717 */
718
719 void EnableInterrupt(void)
720 {
721 WriteMacInt32(XLM_IRQ_NEST, int32(ReadMacInt32(XLM_IRQ_NEST)) - 1);
722 }
723
724
725 /*
726 * Helpers to share 32-bit addressable data with MacOS
727 */
728
729 bool SheepMem::Init(void)
730 {
731 // Size of a native page
732 page_size = vm_get_page_size();
733
734 // Allocate SheepShaver globals
735 proc = base;
736 if (vm_mac_acquire(base, size) < 0)
737 return false;
738
739 // Allocate page with all bits set to 0, right in the middle
740 // This is also used to catch undesired overlaps between proc and data areas
741 zero_page = proc + (size / 2);
742 Mac_memset(zero_page, 0, page_size);
743 if (vm_protect(Mac2HostAddr(zero_page), page_size, VM_PAGE_READ) < 0)
744 return false;
745
746 // Allocate alternate stack for PowerPC interrupt routine
747 sig_stack = base + size;
748 if (vm_mac_acquire(sig_stack, SIG_STACK_SIZE) < 0)
749 return false;
750
751 data = base + size;
752 return true;
753 }
754
755 void SheepMem::Exit(void)
756 {
757 if (data) {
758 // Delete SheepShaver globals
759 vm_mac_release(base, size);
760
761 // Delete alternate stack for PowerPC interrupt routine
762 vm_mac_release(sig_stack, SIG_STACK_SIZE);
763 }
764 }
765
766
767 /*
768 * Get the main window handle
769 */
770
771 #ifdef USE_SDL_VIDEO
772 #include <SDL_syswm.h>
773 HWND GetMainWindowHandle(void)
774 {
775 SDL_SysWMinfo wmInfo;
776 SDL_VERSION(&wmInfo.version);
777 return SDL_GetWMInfo(&wmInfo) ? wmInfo.window : NULL;
778 }
779 #endif
780
781
782 /*
783 * Display alert
784 */
785
786 static void display_alert(int title_id, const char *text, int flags)
787 {
788 HWND hMainWnd = GetMainWindowHandle();
789 MessageBox(hMainWnd, text, GetString(title_id), MB_OK | flags);
790 }
791
792
793 /*
794 * Display error alert
795 */
796
797 void ErrorAlert(const char *text)
798 {
799 if (PrefsFindBool("nogui"))
800 return;
801
802 VideoQuitFullScreen();
803 display_alert(STR_ERROR_ALERT_TITLE, text, MB_ICONSTOP);
804 }
805
806
807 /*
808 * Display warning alert
809 */
810
811 void WarningAlert(const char *text)
812 {
813 if (PrefsFindBool("nogui"))
814 return;
815
816 display_alert(STR_WARNING_ALERT_TITLE, text, MB_ICONINFORMATION);
817 }
818
819
820 /*
821 * Display choice alert
822 */
823
824 bool ChoiceAlert(const char *text, const char *pos, const char *neg)
825 {
826 printf(GetString(STR_SHELL_WARNING_PREFIX), text);
827 return false; //!!
828 }