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.
7 * This code is licensed under the LGPL.
8 * <insert LGPL legal text here>
11 #ifndef __HW_DOS_DOS_H
12 #define __HW_DOS_DOS_H
14 #include "src/lib/doslib/cpu.h"
17 #if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
18 /* NTVDM.EXE DOSNTAST.VDD call support */
19 //#include <windows/ntvdm/ntvdmlib.h>
22 #if defined(TARGET_OS2)
24 # ifdef FAR /* <- conflict between OS/2 headers and cpu.h definition of "FAR" */
30 extern unsigned char FAR *dos_LOL;
32 #if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
33 extern int8_t dpmi_no_0301h; /* -1 = not tested 0 = avail 1 = N/A */
35 # define dpmi_no_0301h 0 /* FIXME: Is it possible for DOS extenders to run non-4GW non-LE executables? */
38 #define DPMI_ENTER_AUTO 0xFF
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... */
46 DOS_FLAVOR_NONE=0, /* generic DOS */
47 DOS_FLAVOR_MSDOS, /* Microsoft MS-DOS */
48 DOS_FLAVOR_FREEDOS, /* FreeDOS */
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;
58 extern char far *freedos_kernel_version_str;
60 extern unsigned char vcpi_present;
61 extern unsigned char vcpi_major_version,vcpi_minor_version;
67 unsigned char FAR *ptr; /* pointer to actual memory content */
68 uint16_t size,psp,cur_segment;
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;
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) {
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);
97 #if TARGET_MSDOS == 16 && !defined(TARGET_OS2)
98 static inline void far *normalize_realmode_far_ptr(void far *p) {
100 FP_SEG(p) + (FP_OFF(p) >> 4),
106 # if TARGET_MSDOS == 32
107 int _dos_xread(int fd,void *buffer,int bsz);
109 int _dos_xread(int fd,void far *buffer,int bsz);
112 # if TARGET_MSDOS == 32
113 int _dos_xwrite(int fd,void *buffer,int bsz);
115 int _dos_xwrite(int fd,void far *buffer,int bsz);
119 #if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
120 # define dpmi_alloc_descriptor() dpmi_alloc_descriptors(1)
122 void *dpmi_alloc_dos(unsigned long len,uint16_t *selector);
123 void dpmi_free_dos(uint16_t selector);
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);
134 #if TARGET_MSDOS == 32
135 unsigned char *dos_list_of_lists();
137 unsigned char far *dos_list_of_lists();
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);
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
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;
167 void __cdecl dpmi_enter_core(); /* Watcom's inline assembler is too limiting to carry out the DPMI entry and switch back */
170 #if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
171 int dpmi_private_alloc();
172 int dpmi_enter(unsigned char mode);
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);
186 struct dos_psp_cooked {
187 unsigned char FAR *raw;
188 uint16_t memsize,callpsp,env;
192 int dos_parse_psp(uint16_t seg,struct dos_psp_cooked *e);
194 struct dos_device_enum {
195 unsigned char FAR *raw,FAR *next;
196 uint16_t ns,no,attr,entry,intent,count;
200 int dos_device_first(struct dos_device_enum *e);
201 int dos_device_next(struct dos_device_enum *e);
203 #if TARGET_MSDOS == 16 && !defined(TARGET_OS2)
204 uint32_t dos_linear_to_phys_vcpi(uint32_t pn);
207 #if TARGET_MSDOS == 32
208 extern struct dos_linear_to_phys_info dos_ltp_info;
209 extern unsigned char dos_ltp_info_init;
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);
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);
223 #define DOS_LTP_FAILED 0xFFFFFFFFFFFFFFFFULL
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;
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 */
240 #define BIOS_KS_ALT 0x08
241 #define BIOS_KT_CTRL 0x04
243 static inline unsigned char read_bios_keystate() { /* from 0x40:0x17 */
244 #if TARGET_MSDOS == 32
245 return *((unsigned char*)(0x400 + 0x17));
247 return *((unsigned char far*)MK_FP(0x40,0x17));
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);
258 #if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
259 typedef struct Win32OrdinalLookupInfo {
260 DWORD entries,base,base_addr;
262 } Win32OrdinalLookupInfo;
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);
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,...);
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,...);
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
290 int genthunk32_init();
291 void genthunk32_free();
294 #if TARGET_MSDOS == 16 || !defined(TARGET_WINDOWS)
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];
306 #define MAXPNAMELEN 32
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
315 typedef struct WAVEOUTCAPS {
318 uint32_t vDriverVersion;
319 char szPname[MAXPNAMELEN];
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);
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)();
339 void do_nmi_32_unhook();
340 void do_nmi_32_hook();
343 #if defined(TARGET_MSDOS) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
345 DOS_CLOSE_AWARENESS_NOT_ACK=0,
346 DOS_CLOSE_AWARENESS_ACKED=1
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);
357 /* unlike DOSBox, VirtualBox's ROM BIOS contains it's version number, which we copy down here */
358 extern char virtualbox_version_str[64];
360 int detect_virtualbox_emu();
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();
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;
377 extern struct lib_dos_options lib_dos_option;
379 # define DOSNTAST_HANDLE_UNASSIGNED 0xFFFFU
381 # define DOSNTAST_INIT_REPORT_HANDLE 0xD0500000
382 # define DOSNTAST_INIT_REPORT_HANDLE_C 0xD0500000ULL
383 /* in: EBX = DOSNTAST_INIT_REPORT_HANDLE
385 * out: EBX = 0x55AA55AA
386 * ECX = flat memory address where signature is stored (must be in BIOS data area) */
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
394 * DS:ESI = filled in with OS struct */
396 # define DOSNTAST_GET_TICK_COUNT 0xD0500002
397 # define DOSNTAST_GET_TICK_COUNT_C 0xD0500002ULL
398 /* in: EBX = <command>
399 * out: EBX = tick count */
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 */
407 # define DOSNTAST_NOTIFY_UNLOAD 0xD050FFFF
408 # define DOSNTAST_NOTIFY_UNLOAD_C 0xD050FFFFULL
409 /* in: EBX = <command>
412 # define DOSNTAST_FUNCTION_GENERAL 0x1000
413 # define DOSNTAST_FUN_GEN_SUB_MESSAGEBOX 0x0000
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
420 const char *dos_flavor_str(uint8_t f);
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);
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;
436 int smartdrv_close();
437 int smartdrv_flush();
438 int smartdrv_detect();
441 uint32_t dos_linear_to_phys_vcpi(uint32_t pn);
443 #endif /* __HW_DOS_DOS_H */