ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Windows/main_windows.cpp
Revision: 1.8
Committed: 2005-03-17T23:48:50Z (19 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.7: +4 -2 lines
Log Message:
Always set RAM_BASE to 0x20000000 for now as there could be some weird
problems depending on the amount of memory requested. Also fix
initialization of the system dependent timers. Remove unixism.

File Contents

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