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"
15 //#include "src/lib/16_head.h"
18 #if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
19 /* NTVDM.EXE DOSNTAST.VDD call support */
20 //#include <windows/ntvdm/ntvdmlib.h>
23 #if defined(TARGET_OS2)
25 # ifdef FAR /* <- conflict between OS/2 headers and cpu.h definition of "FAR" */
31 extern unsigned char FAR *dos_LOL;
33 #if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
34 extern int8_t dpmi_no_0301h; /* -1 = not tested 0 = avail 1 = N/A */
36 # define dpmi_no_0301h 0 /* FIXME: Is it possible for DOS extenders to run non-4GW non-LE executables? */
39 #define DPMI_ENTER_AUTO 0xFF
41 /* DOS "Flavor" we are running under.
42 * I originally didn't care too much until one day some really strange
43 * fatal bugs popped up when running this code under FreeDOS 1.0, almost
44 * as if the FreeDOS kernel does something to fuck with the DOS extender's
45 * mind if our code attempts certain things like reading the ROM area... */
47 DOS_FLAVOR_NONE=0, /* generic DOS */
48 DOS_FLAVOR_MSDOS, /* Microsoft MS-DOS */
49 DOS_FLAVOR_FREEDOS, /* FreeDOS */
52 extern uint8_t dos_flavor;
53 extern uint16_t dos_version;
54 extern const char *dos_version_method;
55 extern uint32_t freedos_kernel_version;
56 #if TARGET_MSDOS == 32
57 extern char *freedos_kernel_version_str;
59 extern char far *freedos_kernel_version_str;
61 extern unsigned char vcpi_present;
62 extern unsigned char vcpi_major_version,vcpi_minor_version;
68 unsigned char FAR *ptr; /* pointer to actual memory content */
69 uint16_t size,psp,cur_segment;
75 struct dpmi_realmode_call {
76 uint32_t edi,esi,ebp,reserved;
77 uint32_t ebx,edx,ecx,eax;
78 uint16_t flags,es,ds,fs,gs,ip,cs,sp,ss;
83 # if TARGET_MSDOS == 32
84 /* WARNING: This is only 100% reliable if the memory in question is below the 1MB mark!
85 * This may happen to work for pointers above the 1MB mark because DOS4GW and DOS32a tend to
86 * allocate that way, but that 1:1 correspondence is not guaranteed */
87 static inline uint32_t ptr2phys_low1mb(unsigned char *x) {
91 static inline uint32_t ptr2phys_low1mb(unsigned char far *x) {
92 uint32_t r = (uint32_t)FP_SEG(x) << 4UL;
93 return r + (uint32_t)FP_OFF(x);
98 #if TARGET_MSDOS == 16 && !defined(TARGET_OS2)
99 static inline void far *normalize_realmode_far_ptr(void far *p) {
101 FP_SEG(p) + (FP_OFF(p) >> 4),
107 # if TARGET_MSDOS == 32
108 int _dos_xread(int fd,void *buffer,int bsz);
110 int _dos_xread(int fd,void far *buffer,int bsz);
113 # if TARGET_MSDOS == 32
114 int _dos_xwrite(int fd,void *buffer,int bsz);
116 int _dos_xwrite(int fd,void far *buffer,int bsz);
120 #if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
121 # define dpmi_alloc_descriptor() dpmi_alloc_descriptors(1)
123 void *dpmi_alloc_dos(unsigned long len,uint16_t *selector);
124 void dpmi_free_dos(uint16_t selector);
126 void dpmi_free_descriptor(uint16_t d);
127 uint16_t dpmi_alloc_descriptors(uint16_t c);
128 unsigned int dpmi_set_segment_base(uint16_t sel,uint32_t base);
129 unsigned int dpmi_set_segment_limit(uint16_t sel,uint32_t limit);
130 unsigned int dpmi_set_segment_access(uint16_t sel,uint16_t access);
131 void *dpmi_phys_addr_map(uint32_t phys,uint32_t size);
132 void dpmi_phys_addr_free(void *base);
135 #if TARGET_MSDOS == 32
136 unsigned char *dos_list_of_lists();
138 unsigned char far *dos_list_of_lists();
141 #if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
142 int dpmi_alternate_rm_call(struct dpmi_realmode_call *rc);
143 int dpmi_alternate_rm_call_stacko(struct dpmi_realmode_call *rc);
146 #if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
147 # if defined(TARGET_WINDOWS)
148 /* 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 */
149 # define dpmi_present 0
152 #if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS))
153 /* 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,
154 * because NTVDM.EXE will emulate some DPMI functions. */
155 extern unsigned char dpmi_present;
156 extern uint16_t dpmi_flags;
157 extern unsigned char dpmi_init;
158 extern uint32_t dpmi_entry_point; /* NTS: This is the real-mode address, even for 32-bit builds */
159 extern unsigned char dpmi_processor_type;
160 extern uint16_t dpmi_version;
161 extern uint16_t dpmi_private_data_length_paragraphs;
162 extern uint16_t dpmi_private_data_segment;
163 extern unsigned char dpmi_entered; /* 0=not yet entered, 16=entered as 16bit, 32=entered as 32bit */
164 extern uint64_t dpmi_rm_entry;
165 extern uint32_t dpmi_pm_entry;
166 extern uint16_t dpmi_pm_cs,dpmi_pm_ds,dpmi_pm_es,dpmi_pm_ss;
168 void __cdecl dpmi_enter_core(); /* Watcom's inline assembler is too limiting to carry out the DPMI entry and switch back */
171 #if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
172 int dpmi_private_alloc();
173 int dpmi_enter(unsigned char mode);
180 uint16_t dos_mcb_first_segment();
181 int mcb_name_is_junk(char *s/*8 char*/);
182 int dos_mcb_next(struct dos_mcb_enum *e);
183 int dos_mcb_first(struct dos_mcb_enum *e);
184 void mcb_filter_name(struct dos_mcb_enum *e);
185 unsigned char FAR *dos_mcb_get_psp(struct dos_mcb_enum *e);
187 struct dos_psp_cooked {
188 unsigned char FAR *raw;
189 uint16_t memsize,callpsp,env;
193 int dos_parse_psp(uint16_t seg,struct dos_psp_cooked *e);
195 struct dos_device_enum {
196 unsigned char FAR *raw,FAR *next;
197 uint16_t ns,no,attr,entry,intent,count;
201 int dos_device_first(struct dos_device_enum *e);
202 int dos_device_next(struct dos_device_enum *e);
204 #if TARGET_MSDOS == 16 && !defined(TARGET_OS2)
205 uint32_t dos_linear_to_phys_vcpi(uint32_t pn);
208 #if TARGET_MSDOS == 32
209 extern struct dos_linear_to_phys_info dos_ltp_info;
210 extern unsigned char dos_ltp_info_init;
214 /* NTS: The return value is 64-bit so that in scenarios where we hack DPMI to support PSE and PAE modes,
215 * the function will still return the physical address associated with the page even when it's above
216 * the 4GB boundary. But as a 32-bit DOS program, the linear addresses will never exceed 32-bit. */
217 uint64_t dos_linear_to_phys(uint32_t linear);
219 int dpmi_linear_lock(uint32_t lin,uint32_t size);
220 int dpmi_linear_unlock(uint32_t lin,uint32_t size);
221 void *dpmi_linear_alloc(uint32_t try_lin,uint32_t size,uint32_t flags,uint32_t *handle);
222 int dpmi_linear_free(uint32_t handle);
224 #define DOS_LTP_FAILED 0xFFFFFFFFFFFFFFFFULL
226 struct dos_linear_to_phys_info {
227 unsigned char paging:1; /* paging is enabled, therefore mapping will occur. if not set, then linear == physical memory addresses */
228 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 */
229 unsigned char should_lock_pages:1; /* if set, the program should call DPMI functions to lock pages before attempting to get physical memory address */
230 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 */
231 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 */
232 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 */
233 unsigned char vcpi_xlate:1; /* use VCPI to translate linear -> phys */
234 unsigned char reserved:1;
236 uint32_t cr3; /* last known copy of the CR3 (page table base) register */
237 uint32_t cr4; /* last known copy of the CR4 register */
241 #define BIOS_KS_ALT 0x08
242 #define BIOS_KT_CTRL 0x04
244 static inline unsigned char read_bios_keystate() { /* from 0x40:0x17 */
245 #if TARGET_MSDOS == 32
246 return *((unsigned char*)(0x400 + 0x17));
248 return *((unsigned char far*)MK_FP(0x40,0x17));
252 #if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
253 void far *win16_getexhandler(unsigned char n);
254 int win16_setexhandler(unsigned char n,void far *x);
255 void far *win16_getvect(unsigned char n);
256 int win16_setvect(unsigned char n,void far *x);
259 #if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
260 typedef struct Win32OrdinalLookupInfo {
261 DWORD entries,base,base_addr;
263 } Win32OrdinalLookupInfo;
265 DWORD *Win32GetExportOrdinalTable(HMODULE mod,DWORD *entries,DWORD *base,DWORD *base_addr);
266 void *Win32GetOrdinalAddress(Win32OrdinalLookupInfo *nfo,unsigned int ord);
267 int Win32GetOrdinalLookupInfo(HMODULE mod,Win32OrdinalLookupInfo *info);
270 #if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
271 extern DWORD genthunk32w_ntdll;
272 extern DWORD genthunk32w_kernel32;
273 extern DWORD genthunk32w_kernel32_GetVersion;
274 extern DWORD genthunk32w_kernel32_GetVersionEx;
275 extern DWORD genthunk32w_kernel32_GetLastError;
276 extern BOOL __GenThunksExist;
277 extern BOOL __GenThunksChecked;
278 extern DWORD (PASCAL FAR *__LoadLibraryEx32W)(LPCSTR lpName,DWORD a,DWORD b);
279 extern BOOL (PASCAL FAR *__FreeLibrary32W)(DWORD hinst);
280 extern DWORD (PASCAL FAR *__GetProcAddress32W)(DWORD hinst,LPCSTR name);
281 extern DWORD (PASCAL FAR *__GetVDMPointer32W)(LPVOID ptr,UINT mask);
282 extern DWORD (_cdecl _far *__CallProcEx32W)(DWORD params,DWORD convertMask,DWORD procaddr32,...);
284 /* NOTE: You call it as if it were declared CallProc32W(..., DWORD hinst,DWORD convertMask,DWORD procaddr32); Ick */
285 extern DWORD (PASCAL FAR *__CallProc32W)(DWORD hinst,DWORD convertMask,DWORD procaddr32,...);
287 /* it would be nice if Open Watcom defined these constants for Win16 */
288 #define CPEX_DEST_STDCALL 0x00000000UL
289 #define CPEX_DEST_CDECL 0x80000000UL
291 int genthunk32_init();
292 void genthunk32_free();
295 #if TARGET_MSDOS == 16 || !defined(TARGET_WINDOWS)
297 /* OpenWatcom does not define the OSVERSIONINFO struct for Win16 */
298 typedef struct OSVERSIONINFO {
299 uint32_t dwOSVersionInfoSize;
300 uint32_t dwMajorVersion;
301 uint32_t dwMinorVersion;
302 uint32_t dwBuildNumber;
303 uint32_t dwPlatformId;
304 char szCSDVersion[128];
307 #define MAXPNAMELEN 32
309 #define WAVECAPS_PITCH 0x0001
310 #define WAVECAPS_PLAYBACKRATE 0x0002
311 #define WAVECAPS_VOLUME 0x0004
312 #define WAVECAPS_LRVOLUME 0x0008
313 #define WAVECAPS_SYNC 0x0010
314 #define WAVECAPS_SAMPLEACCURATE 0x0020
316 typedef struct WAVEOUTCAPS {
319 uint32_t vDriverVersion;
320 char szPname[MAXPNAMELEN];
329 #if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
330 void far *dpmi_getexhandler(unsigned char n);
331 int dpmi_setexhandler(unsigned char n,void far *x);
334 #if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
335 /* TODO: This should be moved into the hw/DOS library */
336 extern unsigned char nmi_32_hooked;
337 extern int nmi_32_refcount;
338 extern void (interrupt *nmi_32_old_vec)();
340 void do_nmi_32_unhook();
341 void do_nmi_32_hook();
344 #if defined(TARGET_MSDOS) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
346 DOS_CLOSE_AWARENESS_NOT_ACK=0,
347 DOS_CLOSE_AWARENESS_ACKED=1
351 void dos_close_awareness_ack();
352 int dos_close_awareness_query();
353 void dos_close_awareness_cancel();
354 int dos_close_awareness_available();
355 int dos_close_awareness_enable(unsigned char en);
358 /* unlike DOSBox, VirtualBox's ROM BIOS contains it's version number, which we copy down here */
359 extern char virtualbox_version_str[64];
361 int detect_virtualbox_emu();
363 #if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
364 int __cdecl dpmi_lin2fmemcpy_32(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
365 int __cdecl dpmi_lin2fmemcpy_16(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
366 int dpmi_lin2fmemcpy(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
367 int dpmi_lin2fmemcpy_init();
370 struct lib_dos_options {
371 uint8_t dont_load_dosntast:1; /* do not automatically load DOSNTAST, but use it if loaded. */
372 /* if not loaded and the program wants it later on, it should
373 * call ntvdm_dosntast_load_vdd(); */
374 uint8_t dont_use_dosntast:1; /* do not use DOSNTAST, even if loaded */
375 uint8_t __reserved__:6;
378 extern struct lib_dos_options lib_dos_option;
380 # define DOSNTAST_HANDLE_UNASSIGNED 0xFFFFU
382 # define DOSNTAST_INIT_REPORT_HANDLE 0xD0500000
383 # define DOSNTAST_INIT_REPORT_HANDLE_C 0xD0500000ULL
384 /* in: EBX = DOSNTAST_INIT_REPORT_HANDLE
386 * out: EBX = 0x55AA55AA
387 * ECX = flat memory address where signature is stored (must be in BIOS data area) */
389 # define DOSNTAST_GETVERSIONEX 0xD0500001
390 # define DOSNTAST_GETVERSIONEX_C 0xD0500001ULL
391 /* in: EBX = <command>
392 * ECX = protected mode call (1) or real-mode call (0)
393 * DS:ESI = OSVERSIONINFO struct
395 * DS:ESI = filled in with OS struct */
397 # define DOSNTAST_GET_TICK_COUNT 0xD0500002
398 # define DOSNTAST_GET_TICK_COUNT_C 0xD0500002ULL
399 /* in: EBX = <command>
400 * out: EBX = tick count */
402 # define DOSNTAST_GET_IO_PORT 0xD0500003
403 # define DOSNTAST_GET_IO_PORT_C 0xD0500003ULL
404 /* in: EBX = <command>
405 * out: EBX = 0x55AA55AA
406 * EDX = I/O port base */
408 # define DOSNTAST_NOTIFY_UNLOAD 0xD050FFFF
409 # define DOSNTAST_NOTIFY_UNLOAD_C 0xD050FFFFULL
410 /* in: EBX = <command>
413 # define DOSNTAST_FUNCTION_GENERAL 0x1000
414 # define DOSNTAST_FUN_GEN_SUB_MESSAGEBOX 0x0000
416 # define DOSNTAST_FUNCTION_WINMM 0x1001
417 # define DOSNTAST_FUN_WINMM_SUB_waveOutGetNumDevs 0x0000
418 # define DOSNTAST_FUN_WINMM_SUB_waveOutGetDevCaps 0x0001
419 # define DOSNTAST_FUN_WINMM_SUB_waveOutOpen 0x0002
421 const char *dos_flavor_str(uint8_t f);
423 /* Windows NT-friendly version of Win386 MapAliasToFlat.
424 * The library version is naive and assumes Windows 3.x/9x/ME behavior.
425 * If you need to convert pointers NOT given by Win386's AllocAlias() functions
426 * (such as 16:16 pointers given by Window messages) and need the code to gracefully
427 * handle itself under Windows NT, use this function not MapAliasToFlat() */
428 #if TARGET_MSDOS == 32 && defined(WIN386)
429 void far *win386_alt_winnt_MapAliasToFlat(DWORD farptr);
430 void far *win386_help_MapAliasToFlat(DWORD farptr);
433 #if (TARGET_MSDOS == 16 || TARGET_MSDOS == 32) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
434 extern unsigned short smartdrv_version;
435 extern int smartdrv_fd;
437 int smartdrv_close();
438 int smartdrv_flush();
439 int smartdrv_detect();
442 uint32_t dos_linear_to_phys_vcpi(uint32_t pn);
444 #endif /* __HW_DOS_DOS_H */