]> 4ch.mooo.com Git - 16.git/blob - src/lib/doslib/dos.h
added a bunch of things~ and midi stuff~
[16.git] / src / lib / doslib / dos.h
1 /* dos.h
2  *
3  * Code to detect the surrounding DOS/Windows environment and support routines to work with it
4  * (C) 2009-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 #ifndef __HW_DOS_DOS_H
12 #define __HW_DOS_DOS_H
13
14 #include "src/lib/doslib/cpu.h"
15 #include <stdint.h>
16
17 #if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
18 /* NTVDM.EXE DOSNTAST.VDD call support */
19 //#include <windows/ntvdm/ntvdmlib.h>
20 #endif
21
22 #if defined(TARGET_OS2)
23 # define INCL_DOSMISC
24 # ifdef FAR /* <- conflict between OS/2 headers and cpu.h definition of "FAR" */
25 #  undef FAR
26 # endif
27 # include <os2.h>
28 #endif
29
30 extern unsigned char FAR *dos_LOL;
31
32 #if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
33 extern int8_t dpmi_no_0301h; /* -1 = not tested 0 = avail 1 = N/A */
34 #else
35 # define dpmi_no_0301h 0 /* FIXME: Is it possible for DOS extenders to run non-4GW non-LE executables? */
36 #endif
37
38 #define DPMI_ENTER_AUTO 0xFF
39
40 /* DOS "Flavor" we are running under.
41  * I originally didn't care too much until one day some really strange
42  * fatal bugs popped up when running this code under FreeDOS 1.0, almost
43  * as if the FreeDOS kernel does something to fuck with the DOS extender's
44  * mind if our code attempts certain things like reading the ROM area... */
45 enum {
46         DOS_FLAVOR_NONE=0,              /* generic DOS */
47         DOS_FLAVOR_MSDOS,               /* Microsoft MS-DOS */
48         DOS_FLAVOR_FREEDOS,             /* FreeDOS */
49 };
50
51 extern uint8_t dos_flavor;
52 extern uint16_t dos_version;
53 extern const char *dos_version_method;
54 extern uint32_t freedos_kernel_version;
55 #if TARGET_MSDOS == 32
56 extern char *freedos_kernel_version_str;
57 #else
58 extern char far *freedos_kernel_version_str;
59 #endif
60 extern unsigned char vcpi_present;
61 extern unsigned char vcpi_major_version,vcpi_minor_version;
62
63 struct dos_mcb_enum {
64         uint16_t        segment;
65         uint16_t        counter;
66         /* acquired data */
67         unsigned char FAR *ptr; /* pointer to actual memory content */
68         uint16_t        size,psp,cur_segment;
69         uint8_t         type;
70         char            name[9];
71 };
72
73 #pragma pack(push,1)
74 struct dpmi_realmode_call {
75         uint32_t        edi,esi,ebp,reserved;
76         uint32_t        ebx,edx,ecx,eax;
77         uint16_t        flags,es,ds,fs,gs,ip,cs,sp,ss;
78 };
79 #pragma pack(pop)
80
81 #ifndef TARGET_OS2
82 # if TARGET_MSDOS == 32
83 /* WARNING: This is only 100% reliable if the memory in question is below the 1MB mark!
84  *          This may happen to work for pointers above the 1MB mark because DOS4GW and DOS32a tend to
85  *          allocate that way, but that 1:1 correspondence is not guaranteed */
86 static inline uint32_t ptr2phys_low1mb(unsigned char *x) {
87         return (uint32_t)x;
88 }
89 # else
90 static inline uint32_t ptr2phys_low1mb(unsigned char far *x) {
91         uint32_t r = (uint32_t)FP_SEG(x) << 4UL;
92         return r + (uint32_t)FP_OFF(x);
93 }
94 # endif
95 #endif
96
97 #if TARGET_MSDOS == 16 && !defined(TARGET_OS2)
98 static inline void far *normalize_realmode_far_ptr(void far *p) {
99         return MK_FP(
100                 FP_SEG(p) + (FP_OFF(p) >> 4),
101                 FP_OFF(p) & 0xF);
102 }
103 #endif
104
105 #ifndef TARGET_OS2
106 # if TARGET_MSDOS == 32
107 int _dos_xread(int fd,void *buffer,int bsz);
108 # else
109 int _dos_xread(int fd,void far *buffer,int bsz);
110 # endif
111
112 # if TARGET_MSDOS == 32
113 int _dos_xwrite(int fd,void *buffer,int bsz);
114 # else
115 int _dos_xwrite(int fd,void far *buffer,int bsz);
116 # endif
117 #endif
118
119 #if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
120 #  define dpmi_alloc_descriptor() dpmi_alloc_descriptors(1)
121
122 void *dpmi_alloc_dos(unsigned long len,uint16_t *selector);
123 void dpmi_free_dos(uint16_t selector);
124
125 void dpmi_free_descriptor(uint16_t d);
126 uint16_t dpmi_alloc_descriptors(uint16_t c);
127 unsigned int dpmi_set_segment_base(uint16_t sel,uint32_t base);
128 unsigned int dpmi_set_segment_limit(uint16_t sel,uint32_t limit);
129 unsigned int dpmi_set_segment_access(uint16_t sel,uint16_t access);
130 void *dpmi_phys_addr_map(uint32_t phys,uint32_t size);
131 void dpmi_phys_addr_free(void *base);
132 #endif
133
134 #if TARGET_MSDOS == 32
135 unsigned char *dos_list_of_lists();
136 #else
137 unsigned char far *dos_list_of_lists();
138 #endif
139
140 #if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
141 int dpmi_alternate_rm_call(struct dpmi_realmode_call *rc);
142 int dpmi_alternate_rm_call_stacko(struct dpmi_realmode_call *rc);
143 #endif
144
145 #if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
146 # if defined(TARGET_WINDOWS)
147 /* as a 32-bit Windows program: even if DPMI is present, it's useless to us because we can't call into that part of Windows */
148 #  define dpmi_present 0
149 # endif
150 #endif
151 #if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS))
152 /* as a 16-bit program (DOS or Windows), DPMI might be present. Note that DPMI can be present even under NTVDM.EXE under Windows NT,
153  * because NTVDM.EXE will emulate some DPMI functions. */
154 extern unsigned char dpmi_present;
155 extern uint16_t dpmi_flags;
156 extern unsigned char dpmi_init;
157 extern uint32_t dpmi_entry_point; /* NTS: This is the real-mode address, even for 32-bit builds */
158 extern unsigned char dpmi_processor_type;
159 extern uint16_t dpmi_version;
160 extern uint16_t dpmi_private_data_length_paragraphs;
161 extern uint16_t dpmi_private_data_segment;
162 extern unsigned char dpmi_entered;      /* 0=not yet entered, 16=entered as 16bit, 32=entered as 32bit */
163 extern uint64_t dpmi_rm_entry;
164 extern uint32_t dpmi_pm_entry;
165 extern uint16_t dpmi_pm_cs,dpmi_pm_ds,dpmi_pm_es,dpmi_pm_ss;
166
167 void __cdecl dpmi_enter_core(); /* Watcom's inline assembler is too limiting to carry out the DPMI entry and switch back */
168 #endif
169
170 #if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
171 int dpmi_private_alloc();
172 int dpmi_enter(unsigned char mode);
173 #endif
174
175 void probe_dos();
176 void probe_dpmi();
177 int probe_vcpi();
178
179 uint16_t dos_mcb_first_segment();
180 int mcb_name_is_junk(char *s/*8 char*/);
181 int dos_mcb_next(struct dos_mcb_enum *e);
182 int dos_mcb_first(struct dos_mcb_enum *e);
183 void mcb_filter_name(struct dos_mcb_enum *e);
184 unsigned char FAR *dos_mcb_get_psp(struct dos_mcb_enum *e);
185
186 struct dos_psp_cooked {
187         unsigned char FAR *raw;
188         uint16_t        memsize,callpsp,env;
189         char            cmd[130];
190 };
191
192 int dos_parse_psp(uint16_t seg,struct dos_psp_cooked *e);
193
194 struct dos_device_enum {
195         unsigned char FAR *raw,FAR *next;
196         uint16_t                ns,no,attr,entry,intent,count;
197         char                    name[9];
198 };
199
200 int dos_device_first(struct dos_device_enum *e);
201 int dos_device_next(struct dos_device_enum *e);
202
203 #if TARGET_MSDOS == 16 && !defined(TARGET_OS2)
204 uint32_t dos_linear_to_phys_vcpi(uint32_t pn);
205 #endif
206
207 #if TARGET_MSDOS == 32
208 extern struct dos_linear_to_phys_info dos_ltp_info;
209 extern unsigned char dos_ltp_info_init;
210
211 int dos_ltp_probe();
212
213 /* NTS: The return value is 64-bit so that in scenarios where we hack DPMI to support PSE and PAE modes,
214  *      the function will still return the physical address associated with the page even when it's above
215  *      the 4GB boundary. But as a 32-bit DOS program, the linear addresses will never exceed 32-bit. */
216 uint64_t dos_linear_to_phys(uint32_t linear);
217
218 int dpmi_linear_lock(uint32_t lin,uint32_t size);
219 int dpmi_linear_unlock(uint32_t lin,uint32_t size);
220 void *dpmi_linear_alloc(uint32_t try_lin,uint32_t size,uint32_t flags,uint32_t *handle);
221 int dpmi_linear_free(uint32_t handle);
222
223 #define DOS_LTP_FAILED 0xFFFFFFFFFFFFFFFFULL
224
225 struct dos_linear_to_phys_info {
226         unsigned char           paging:1;               /* paging is enabled, therefore mapping will occur. if not set, then linear == physical memory addresses */
227         unsigned char           dos_remap:1;            /* if set, the lower 1MB region (DOS conventional memory) is remapped. if clear, we can assume 1:1 mapping below 1MB */
228         unsigned char           should_lock_pages:1;    /* if set, the program should call DPMI functions to lock pages before attempting to get physical memory address */
229         unsigned char           cant_xlate:1;           /* if set, resources to determine physical memory addresses are not available (such as: running in a Windows DOS Box). however dos_remap=0 means we can assume 1:1 mapping below 1MB */
230         unsigned char           using_pae:1;            /* if set, the DOS extender or DPMI host has PAE/PSE extensions enabled. This changes how page tables are parsed, and can prevent us from mapping */
231         unsigned char           dma_dos_xlate:1;        /* usually set if dos_remap=1 to say the DOS extender or environment translates DMA addresses (i.e. Windows DOS Box), but we can't actually know the physical memory address. We can do DMA from DOS memory */
232         unsigned char           vcpi_xlate:1;           /* use VCPI to translate linear -> phys */
233         unsigned char           reserved:1;
234         uint32_t                cr0;
235         uint32_t                cr3;                    /* last known copy of the CR3 (page table base) register */
236         uint32_t                cr4;                    /* last known copy of the CR4 register */
237 };
238 #endif
239
240 #define BIOS_KS_ALT             0x08
241 #define BIOS_KT_CTRL            0x04
242
243 static inline unsigned char read_bios_keystate() { /* from 0x40:0x17 */
244 #if TARGET_MSDOS == 32
245         return *((unsigned char*)(0x400 + 0x17));
246 #else
247         return *((unsigned char far*)MK_FP(0x40,0x17));
248 #endif
249 }
250
251 #if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
252 void far *win16_getexhandler(unsigned char n);
253 int win16_setexhandler(unsigned char n,void far *x);
254 void far *win16_getvect(unsigned char n);
255 int win16_setvect(unsigned char n,void far *x);
256 #endif
257
258 #if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
259 typedef struct Win32OrdinalLookupInfo {
260         DWORD   entries,base,base_addr;
261         DWORD*  table;
262 } Win32OrdinalLookupInfo;
263
264 DWORD *Win32GetExportOrdinalTable(HMODULE mod,DWORD *entries,DWORD *base,DWORD *base_addr);
265 void *Win32GetOrdinalAddress(Win32OrdinalLookupInfo *nfo,unsigned int ord);
266 int Win32GetOrdinalLookupInfo(HMODULE mod,Win32OrdinalLookupInfo *info);
267 #endif
268
269 #if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
270 extern DWORD            genthunk32w_ntdll;
271 extern DWORD            genthunk32w_kernel32;
272 extern DWORD            genthunk32w_kernel32_GetVersion;
273 extern DWORD            genthunk32w_kernel32_GetVersionEx;
274 extern DWORD            genthunk32w_kernel32_GetLastError;
275 extern BOOL             __GenThunksExist;
276 extern BOOL             __GenThunksChecked;
277 extern DWORD            (PASCAL FAR *__LoadLibraryEx32W)(LPCSTR lpName,DWORD a,DWORD b);
278 extern BOOL             (PASCAL FAR *__FreeLibrary32W)(DWORD hinst);
279 extern DWORD            (PASCAL FAR *__GetProcAddress32W)(DWORD hinst,LPCSTR name);
280 extern DWORD            (PASCAL FAR *__GetVDMPointer32W)(LPVOID ptr,UINT mask);
281 extern DWORD            (_cdecl _far *__CallProcEx32W)(DWORD params,DWORD convertMask,DWORD procaddr32,...);
282
283 /* NOTE: You call it as if it were declared CallProc32W(..., DWORD hinst,DWORD convertMask,DWORD procaddr32); Ick */
284 extern DWORD            (PASCAL FAR *__CallProc32W)(DWORD hinst,DWORD convertMask,DWORD procaddr32,...);
285
286 /* it would be nice if Open Watcom defined these constants for Win16 */
287 #define CPEX_DEST_STDCALL       0x00000000UL
288 #define CPEX_DEST_CDECL         0x80000000UL
289
290 int genthunk32_init();
291 void genthunk32_free();
292 #endif
293
294 #if TARGET_MSDOS == 16 || !defined(TARGET_WINDOWS)
295 #pragma pack(push,4)
296 /* OpenWatcom does not define the OSVERSIONINFO struct for Win16 */
297 typedef struct OSVERSIONINFO {
298         uint32_t        dwOSVersionInfoSize;
299         uint32_t        dwMajorVersion;
300         uint32_t        dwMinorVersion;
301         uint32_t        dwBuildNumber;
302         uint32_t        dwPlatformId;
303         char            szCSDVersion[128];
304 } OSVERSIONINFO;
305
306 #define MAXPNAMELEN             32
307
308 #define WAVECAPS_PITCH          0x0001
309 #define WAVECAPS_PLAYBACKRATE   0x0002
310 #define WAVECAPS_VOLUME         0x0004
311 #define WAVECAPS_LRVOLUME       0x0008
312 #define WAVECAPS_SYNC           0x0010
313 #define WAVECAPS_SAMPLEACCURATE 0x0020
314
315 typedef struct WAVEOUTCAPS {
316         uint16_t        wMid;
317         uint16_t        wPid;
318         uint32_t        vDriverVersion;
319         char            szPname[MAXPNAMELEN];
320         uint32_t        dwFormats;
321         uint16_t        wChannels;
322         uint16_t        wReserved1;
323         uint32_t        dwSupport;
324 } WAVEOUTCAPS;
325 #pragma pack(pop)
326 #endif
327
328 #if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
329 void far *dpmi_getexhandler(unsigned char n);
330 int dpmi_setexhandler(unsigned char n,void far *x);
331 #endif
332
333 #if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
334 /* TODO: This should be moved into the hw/DOS library */
335 extern unsigned char            nmi_32_hooked;
336 extern int                      nmi_32_refcount;
337 extern void                     (interrupt *nmi_32_old_vec)();
338
339 void do_nmi_32_unhook();
340 void do_nmi_32_hook();
341 #endif
342
343 #if defined(TARGET_MSDOS) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
344 enum {
345         DOS_CLOSE_AWARENESS_NOT_ACK=0,
346         DOS_CLOSE_AWARENESS_ACKED=1
347 };
348
349 void dos_vm_yield();
350 void dos_close_awareness_ack();
351 int dos_close_awareness_query();
352 void dos_close_awareness_cancel();
353 int dos_close_awareness_available();
354 int dos_close_awareness_enable(unsigned char en);
355 #endif
356
357 /* unlike DOSBox, VirtualBox's ROM BIOS contains it's version number, which we copy down here */
358 extern char virtualbox_version_str[64];
359
360 int detect_virtualbox_emu();
361
362 #if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
363 int __cdecl dpmi_lin2fmemcpy_32(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
364 int __cdecl dpmi_lin2fmemcpy_16(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
365 int dpmi_lin2fmemcpy(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
366 int dpmi_lin2fmemcpy_init();
367 #endif
368
369 struct lib_dos_options {
370         uint8_t                 dont_load_dosntast:1;   /* do not automatically load DOSNTAST, but use it if loaded. */
371                                                         /* if not loaded and the program wants it later on, it should
372                                                          * call ntvdm_dosntast_load_vdd(); */
373         uint8_t                 dont_use_dosntast:1;    /* do not use DOSNTAST, even if loaded */
374         uint8_t                 __reserved__:6;
375 };
376
377 extern struct lib_dos_options lib_dos_option;
378
379 # define DOSNTAST_HANDLE_UNASSIGNED             0xFFFFU
380
381 # define DOSNTAST_INIT_REPORT_HANDLE            0xD0500000
382 # define DOSNTAST_INIT_REPORT_HANDLE_C          0xD0500000ULL
383 /* in: EBX = DOSNTAST_INIT_REPORT_HANDLE
384  *     ECX = NTVDM handle
385  * out: EBX = 0x55AA55AA
386  *      ECX = flat memory address where signature is stored (must be in BIOS data area) */
387
388 # define DOSNTAST_GETVERSIONEX                  0xD0500001
389 # define DOSNTAST_GETVERSIONEX_C                0xD0500001ULL
390 /* in: EBX = <command>
391  *     ECX = protected mode call (1) or real-mode call (0)
392  *     DS:ESI = OSVERSIONINFO struct
393  * out: EBX = result
394  *     DS:ESI = filled in with OS struct */
395
396 # define DOSNTAST_GET_TICK_COUNT                0xD0500002
397 # define DOSNTAST_GET_TICK_COUNT_C              0xD0500002ULL
398 /* in: EBX = <command>
399  * out: EBX = tick count */
400
401 # define DOSNTAST_GET_IO_PORT                   0xD0500003
402 # define DOSNTAST_GET_IO_PORT_C                 0xD0500003ULL
403 /* in: EBX = <command>
404  * out: EBX = 0x55AA55AA
405  *      EDX = I/O port base */
406
407 # define DOSNTAST_NOTIFY_UNLOAD                 0xD050FFFF
408 # define DOSNTAST_NOTIFY_UNLOAD_C               0xD050FFFFULL
409 /* in: EBX = <command>
410  * out: EBX = none */
411
412 # define DOSNTAST_FUNCTION_GENERAL              0x1000
413 #  define DOSNTAST_FUN_GEN_SUB_MESSAGEBOX       0x0000
414
415 # define DOSNTAST_FUNCTION_WINMM                        0x1001
416 #  define DOSNTAST_FUN_WINMM_SUB_waveOutGetNumDevs      0x0000
417 #  define DOSNTAST_FUN_WINMM_SUB_waveOutGetDevCaps      0x0001
418 #  define DOSNTAST_FUN_WINMM_SUB_waveOutOpen            0x0002
419
420 const char *dos_flavor_str(uint8_t f);
421
422 /* Windows NT-friendly version of Win386 MapAliasToFlat.
423  * The library version is naive and assumes Windows 3.x/9x/ME behavior.
424  * If you need to convert pointers NOT given by Win386's AllocAlias() functions
425  * (such as 16:16 pointers given by Window messages) and need the code to gracefully
426  * handle itself under Windows NT, use this function not MapAliasToFlat() */
427 #if TARGET_MSDOS == 32 && defined(WIN386)
428 void far *win386_alt_winnt_MapAliasToFlat(DWORD farptr);
429 void far *win386_help_MapAliasToFlat(DWORD farptr);
430 #endif
431
432 #if (TARGET_MSDOS == 16 || TARGET_MSDOS == 32) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
433 extern unsigned short                   smartdrv_version;
434 extern int                              smartdrv_fd;
435
436 int smartdrv_close();
437 int smartdrv_flush();
438 int smartdrv_detect();
439 #endif
440
441 uint32_t dos_linear_to_phys_vcpi(uint32_t pn);
442
443 #endif /* __HW_DOS_DOS_H */
444