ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Windows/main_windows.cpp
Revision: 1.6
Committed: 2005-01-30T21:19:07Z (19 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.5: +6 -208 lines
Log Message:
Add InitAll() which covers common initializations so that to avoid duplicate
code and possible bugs (e.g. on BeOS/PPC). Likewise for ExitAll().

File Contents

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