]> 4ch.mooo.com Git - 16.git/blob - src/lib/doslib/dos/dosbox.c
added a bunch of things~ and midi stuff~
[16.git] / src / lib / doslib / dos / dosbox.c
1 /* dosbox.c
2  *
3  * Detect whether or not we're running under the DOSBox emulator
4  * (C) 2010-2012 Jonathan Campbell.
5  * Hackipedia DOS library.
6  *
7  * This code is licensed under the LGPL.
8  * <insert LGPL legal text here>
9  */
10
11 #include <stdlib.h>
12 #include <string.h>
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <conio.h>
16 #include <dos.h>
17
18 #include <hw/cpu/cpu.h>
19 #include <hw/dos/dos.h>
20 #include <hw/dos/dosbox.h>
21
22 #if defined(TARGET_WINDOWS) || defined(TARGET_OS2)
23 #else
24 static const char *dosbox_fakebios = "DOSBox FakeBIOS v1.0";
25 #endif
26
27 /* the ROM area doesn't change. so remember our last result */
28 #if defined(TARGET_WINDOWS) || defined(TARGET_OS2)
29 #else
30 static signed char dosbox_detect_cache = -1;
31 #endif
32
33 int detect_dosbox_emu() {
34 #if defined(TARGET_OS2)
35         /* TODO: So... how does one read the ROM BIOS area from OS/2? */
36         return 0;
37 #elif defined(TARGET_WINDOWS)
38         /* TODO: I know that from within Windows there are various ways to scan the ROM BIOS area.
39          *       Windows 1.x and 2.x (if real mode) we can just use MK_FP as we do under DOS, but
40          *       we have to use alternate means if Windows is in protected mode. Windows 2.x/3.x protected
41          *       mode (and because of compatibility, Windows 95/98/ME), there are two methods open to us:
42          *       One is to use selector constants that are hidden away in KRNL386.EXE with names like _A0000,
43          *       _B0000, etc. They are data selectors that when loaded into the segment registers point to
44          *       their respective parts of DOS adapter ROM and BIOS ROM. Another way is to use the Win16
45          *       API to create a data selector that points to the BIOS. Windows 386 Enhanced mode may map
46          *       additional things over the unused parts of adapter ROM, but experience shows that it never
47          *       relocates or messes with the VGA BIOS or with the ROM BIOS,
48          *
49          *       My memory is foggy at this point, but I remember that under Windows XP SP2, one of the
50          *       above Win16 methods still worked even from under the NT kernel.
51          *
52          *       For Win32 applications, if the host OS is Windows 3.1 Win32s or Windows 95/98/ME, we can
53          *       take advantage of a strange quirk in the way the kernel maps the lower 1MB. For whatever
54          *       reason, the VGA RAM, adapter ROM, and ROM BIOS areas are left open even for Win32 applications
55          *       with no protection. Thus, a Win32 programmer can just make a pointer like
56          *       char *a = (char*)0xA0000 and scribble on legacy VGA RAM to his heart's content (though on
57          *       modern PCI SVGA hardware the driver probably instructs the card to disable VGA compatible
58          *       mapping). In fact, this ability to scribble on RAM directly is at the heart of one of Microsoft's
59          *       earliest and hackiest "Direct Draw" interfaces known as "DISPDIB.DLL", a not-to-well documented
60          *       library responsible for those Windows 3.1 multimedia apps and games that were somehow able to
61          *       run full-screen 320x200x256 color VGA despite being Windows GDI-based apps. Ever wonder how the
62          *       MCI AVI player was able to go full-screen when DirectX and WinG were not invented yet? Now you
63          *       know :)
64          *
65          *       There are some VFW codecs out there as well, that also like to abuse DISPDIB.DLL for "fullscreen"
66          *       modes. One good example is the old "Motion Pixels" codec, that when asked to go fullscreen,
67          *       uses DISPDIB.DLL and direct VGA I/O port trickery to effectively set up a 320x480 256-color mode,
68          *       which it then draws on "fake hicolor" style to display the video (though a bit dim since you're
69          *       sort of watching a video through a dithered mesh, but...)
70          *       
71          *       In case you were probably wondering, no, Windows NT doesn't allow Win32 applications the same
72          *       privilege. Win32 apps writing to 0xA0000 would page fault and crash. Curiously enough though,
73          *       NTVDM.EXE does seem to open up the 0xA0000-0xFFFFF memory area to Win16 applications if they
74          *       use the right selectors and API calls. */
75         return 0;
76 #else
77         int i;
78 # if TARGET_MSDOS == 32
79         const char *scan;
80 # else
81         const char far *scan;
82 # endif
83
84         probe_dos();
85         if (dosbox_detect_cache >= 0)
86                 return (int)dosbox_detect_cache;
87
88 # if TARGET_MSDOS == 32
89         if (dos_flavor == DOS_FLAVOR_FREEDOS) {
90                 /* FIXME: I have no idea why but FreeDOS 1.0 has a strange conflict with DOS32a where if this code
91                  *        tries to read the ROM BIOS it causes a GPF and crashes (or sometimes runs off into the
92                  *        weeds leaving a little garbage on the screen). DOS32a's register dump seems to imply that
93                  *        at one point our segment limits were suddenly limited to 1MB (0xFFFFF). I have no clue
94                  *        what the hell is triggering it, but I know from testing we can avoid that crash by not
95                  *        scanning. */
96                 if (freedos_kernel_version == 0x000024UL) /* 0.0.36 */
97                         return (dosbox_detect_cache=0);
98         }
99 # endif
100
101 /* signs that we're running under DOSBOX:
102  *   - the majority of the adapter ROM area is 0x00 (not 0xFF or any other value). Here we check 0xE000:0xFF00 and 0xF000:0x000.
103  *   - an ASCII string is visible at 0xF000:0xE061: "DOSBox FakeBIOS v1.0" */
104
105 # if TARGET_MSDOS == 32
106         scan = (const char*)0xEFF00UL;
107 # else
108         scan = (const char far*)MK_FP(0xE000,0xFF00);
109 # endif
110
111         for (i=0;i < 256;i++) {
112                 if (scan[i] != 0)
113                         return (dosbox_detect_cache=0);
114         }
115
116 # if TARGET_MSDOS == 32
117         scan = (const char*)0xF0000UL;
118 # else
119         scan = (const char far*)MK_FP(0xF000,0x0000);
120 # endif
121         for (i=0;i < 256;i++) {
122                 if (scan[i] != 0)
123                         return (dosbox_detect_cache=0);
124         }
125
126 # if TARGET_MSDOS == 32
127         scan = (const char*)0xFE061UL;
128 # else
129         scan = (const char far*)MK_FP(0xF000,0xE061);
130 # endif
131         i = 0;
132         do {
133                 if (dosbox_fakebios[i] != scan[i])
134                         return (dosbox_detect_cache=0);
135         } while (dosbox_fakebios[i++] != 0);
136
137         return (dosbox_detect_cache=1);
138 #endif
139 }
140