]> 4ch.mooo.com Git - 16.git/blobdiff - src/lib/dl/dos.h
wwww
[16.git] / src / lib / dl / dos.h
diff --git a/src/lib/dl/dos.h b/src/lib/dl/dos.h
new file mode 100755 (executable)
index 0000000..2ae46b5
--- /dev/null
@@ -0,0 +1,445 @@
+/* dos.h
+ *
+ * Code to detect the surrounding DOS/Windows environment and support routines to work with it
+ * (C) 2009-2012 Jonathan Campbell.
+ * Hackipedia DOS library.
+ *
+ * This code is licensed under the LGPL.
+ * <insert LGPL legal text here>
+ */
+
+#ifndef __HW_DOS_DOS_H
+#define __HW_DOS_DOS_H
+
+#include "src/lib/doslib/cpu.h"
+//#include "src/lib/16_head.h"
+#include <stdint.h>
+
+#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
+/* NTVDM.EXE DOSNTAST.VDD call support */
+//#include <windows/ntvdm/ntvdmlib.h>
+#endif
+
+#if defined(TARGET_OS2)
+# define INCL_DOSMISC
+# ifdef FAR /* <- conflict between OS/2 headers and cpu.h definition of "FAR" */
+#  undef FAR
+# endif
+# include <os2.h>
+#endif
+
+extern unsigned char FAR *dos_LOL;
+
+#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
+extern int8_t dpmi_no_0301h; /* -1 = not tested 0 = avail 1 = N/A */
+#else
+# define dpmi_no_0301h 0 /* FIXME: Is it possible for DOS extenders to run non-4GW non-LE executables? */
+#endif
+
+#define DPMI_ENTER_AUTO 0xFF
+
+/* DOS "Flavor" we are running under.
+ * I originally didn't care too much until one day some really strange
+ * fatal bugs popped up when running this code under FreeDOS 1.0, almost
+ * as if the FreeDOS kernel does something to fuck with the DOS extender's
+ * mind if our code attempts certain things like reading the ROM area... */
+enum {
+       DOS_FLAVOR_NONE=0,              /* generic DOS */
+       DOS_FLAVOR_MSDOS,               /* Microsoft MS-DOS */
+       DOS_FLAVOR_FREEDOS,             /* FreeDOS */
+};
+
+extern uint8_t dos_flavor;
+extern uint16_t dos_version;
+extern const char *dos_version_method;
+extern uint32_t freedos_kernel_version;
+#if TARGET_MSDOS == 32
+extern char *freedos_kernel_version_str;
+#else
+extern char far *freedos_kernel_version_str;
+#endif
+extern unsigned char vcpi_present;
+extern unsigned char vcpi_major_version,vcpi_minor_version;
+
+struct dos_mcb_enum {
+       uint16_t        segment;
+       uint16_t        counter;
+       /* acquired data */
+       unsigned char FAR *ptr; /* pointer to actual memory content */
+       uint16_t        size,psp,cur_segment;
+       uint8_t         type;
+       char            name[9];
+};
+
+#pragma pack(push,1)
+struct dpmi_realmode_call {
+       uint32_t        edi,esi,ebp,reserved;
+       uint32_t        ebx,edx,ecx,eax;
+       uint16_t        flags,es,ds,fs,gs,ip,cs,sp,ss;
+};
+#pragma pack(pop)
+
+#ifndef TARGET_OS2
+# if TARGET_MSDOS == 32
+/* WARNING: This is only 100% reliable if the memory in question is below the 1MB mark!
+ *          This may happen to work for pointers above the 1MB mark because DOS4GW and DOS32a tend to
+ *          allocate that way, but that 1:1 correspondence is not guaranteed */
+static inline uint32_t ptr2phys_low1mb(unsigned char *x) {
+       return (uint32_t)x;
+}
+# else
+static inline uint32_t ptr2phys_low1mb(unsigned char far *x) {
+       uint32_t r = (uint32_t)FP_SEG(x) << 4UL;
+       return r + (uint32_t)FP_OFF(x);
+}
+# endif
+#endif
+
+#if TARGET_MSDOS == 16 && !defined(TARGET_OS2)
+static inline void far *normalize_realmode_far_ptr(void far *p) {
+       return MK_FP(
+               FP_SEG(p) + (FP_OFF(p) >> 4),
+               FP_OFF(p) & 0xF);
+}
+#endif
+
+#ifndef TARGET_OS2
+# if TARGET_MSDOS == 32
+int _dos_xread(int fd,void *buffer,int bsz);
+# else
+int _dos_xread(int fd,void far *buffer,int bsz);
+# endif
+
+# if TARGET_MSDOS == 32
+int _dos_xwrite(int fd,void *buffer,int bsz);
+# else
+int _dos_xwrite(int fd,void far *buffer,int bsz);
+# endif
+#endif
+
+#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
+#  define dpmi_alloc_descriptor() dpmi_alloc_descriptors(1)
+
+void *dpmi_alloc_dos(unsigned long len,uint16_t *selector);
+void dpmi_free_dos(uint16_t selector);
+
+void dpmi_free_descriptor(uint16_t d);
+uint16_t dpmi_alloc_descriptors(uint16_t c);
+unsigned int dpmi_set_segment_base(uint16_t sel,uint32_t base);
+unsigned int dpmi_set_segment_limit(uint16_t sel,uint32_t limit);
+unsigned int dpmi_set_segment_access(uint16_t sel,uint16_t access);
+void *dpmi_phys_addr_map(uint32_t phys,uint32_t size);
+void dpmi_phys_addr_free(void *base);
+#endif
+
+#if TARGET_MSDOS == 32
+unsigned char *dos_list_of_lists();
+#else
+unsigned char far *dos_list_of_lists();
+#endif
+
+#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
+int dpmi_alternate_rm_call(struct dpmi_realmode_call *rc);
+int dpmi_alternate_rm_call_stacko(struct dpmi_realmode_call *rc);
+#endif
+
+#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
+# if defined(TARGET_WINDOWS)
+/* 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 */
+#  define dpmi_present 0
+# endif
+#endif
+#if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS))
+/* 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,
+ * because NTVDM.EXE will emulate some DPMI functions. */
+extern unsigned char dpmi_present;
+extern uint16_t dpmi_flags;
+extern unsigned char dpmi_init;
+extern uint32_t dpmi_entry_point; /* NTS: This is the real-mode address, even for 32-bit builds */
+extern unsigned char dpmi_processor_type;
+extern uint16_t dpmi_version;
+extern uint16_t dpmi_private_data_length_paragraphs;
+extern uint16_t dpmi_private_data_segment;
+extern unsigned char dpmi_entered;     /* 0=not yet entered, 16=entered as 16bit, 32=entered as 32bit */
+extern uint64_t dpmi_rm_entry;
+extern uint32_t dpmi_pm_entry;
+extern uint16_t dpmi_pm_cs,dpmi_pm_ds,dpmi_pm_es,dpmi_pm_ss;
+
+void __cdecl dpmi_enter_core(); /* Watcom's inline assembler is too limiting to carry out the DPMI entry and switch back */
+#endif
+
+#if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
+int dpmi_private_alloc();
+int dpmi_enter(unsigned char mode);
+#endif
+
+void probe_dos();
+void probe_dpmi();
+int probe_vcpi();
+
+uint16_t dos_mcb_first_segment();
+int mcb_name_is_junk(char *s/*8 char*/);
+int dos_mcb_next(struct dos_mcb_enum *e);
+int dos_mcb_first(struct dos_mcb_enum *e);
+void mcb_filter_name(struct dos_mcb_enum *e);
+unsigned char FAR *dos_mcb_get_psp(struct dos_mcb_enum *e);
+
+struct dos_psp_cooked {
+       unsigned char FAR *raw;
+       uint16_t        memsize,callpsp,env;
+       char            cmd[130];
+};
+
+int dos_parse_psp(uint16_t seg,struct dos_psp_cooked *e);
+
+struct dos_device_enum {
+       unsigned char FAR *raw,FAR *next;
+       uint16_t                ns,no,attr,entry,intent,count;
+       char                    name[9];
+};
+
+int dos_device_first(struct dos_device_enum *e);
+int dos_device_next(struct dos_device_enum *e);
+
+#if TARGET_MSDOS == 16 && !defined(TARGET_OS2)
+uint32_t dos_linear_to_phys_vcpi(uint32_t pn);
+#endif
+
+#if TARGET_MSDOS == 32
+extern struct dos_linear_to_phys_info dos_ltp_info;
+extern unsigned char dos_ltp_info_init;
+
+int dos_ltp_probe();
+
+/* NTS: The return value is 64-bit so that in scenarios where we hack DPMI to support PSE and PAE modes,
+ *      the function will still return the physical address associated with the page even when it's above
+ *      the 4GB boundary. But as a 32-bit DOS program, the linear addresses will never exceed 32-bit. */
+uint64_t dos_linear_to_phys(uint32_t linear);
+
+int dpmi_linear_lock(uint32_t lin,uint32_t size);
+int dpmi_linear_unlock(uint32_t lin,uint32_t size);
+void *dpmi_linear_alloc(uint32_t try_lin,uint32_t size,uint32_t flags,uint32_t *handle);
+int dpmi_linear_free(uint32_t handle);
+
+#define DOS_LTP_FAILED 0xFFFFFFFFFFFFFFFFULL
+
+struct dos_linear_to_phys_info {
+       unsigned char           paging:1;               /* paging is enabled, therefore mapping will occur. if not set, then linear == physical memory addresses */
+       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 */
+       unsigned char           should_lock_pages:1;    /* if set, the program should call DPMI functions to lock pages before attempting to get physical memory address */
+       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 */
+       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 */
+       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 */
+       unsigned char           vcpi_xlate:1;           /* use VCPI to translate linear -> phys */
+       unsigned char           reserved:1;
+       uint32_t                cr0;
+       uint32_t                cr3;                    /* last known copy of the CR3 (page table base) register */
+       uint32_t                cr4;                    /* last known copy of the CR4 register */
+};
+#endif
+
+#define BIOS_KS_ALT            0x08
+#define BIOS_KT_CTRL           0x04
+
+static inline unsigned char read_bios_keystate() { /* from 0x40:0x17 */
+#if TARGET_MSDOS == 32
+       return *((unsigned char*)(0x400 + 0x17));
+#else
+       return *((unsigned char far*)MK_FP(0x40,0x17));
+#endif
+}
+
+#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
+void far *win16_getexhandler(unsigned char n);
+int win16_setexhandler(unsigned char n,void far *x);
+void far *win16_getvect(unsigned char n);
+int win16_setvect(unsigned char n,void far *x);
+#endif
+
+#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
+typedef struct Win32OrdinalLookupInfo {
+       DWORD   entries,base,base_addr;
+       DWORD*  table;
+} Win32OrdinalLookupInfo;
+
+DWORD *Win32GetExportOrdinalTable(HMODULE mod,DWORD *entries,DWORD *base,DWORD *base_addr);
+void *Win32GetOrdinalAddress(Win32OrdinalLookupInfo *nfo,unsigned int ord);
+int Win32GetOrdinalLookupInfo(HMODULE mod,Win32OrdinalLookupInfo *info);
+#endif
+
+#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
+extern DWORD           genthunk32w_ntdll;
+extern DWORD           genthunk32w_kernel32;
+extern DWORD           genthunk32w_kernel32_GetVersion;
+extern DWORD           genthunk32w_kernel32_GetVersionEx;
+extern DWORD           genthunk32w_kernel32_GetLastError;
+extern BOOL            __GenThunksExist;
+extern BOOL            __GenThunksChecked;
+extern DWORD           (PASCAL FAR *__LoadLibraryEx32W)(LPCSTR lpName,DWORD a,DWORD b);
+extern BOOL            (PASCAL FAR *__FreeLibrary32W)(DWORD hinst);
+extern DWORD           (PASCAL FAR *__GetProcAddress32W)(DWORD hinst,LPCSTR name);
+extern DWORD           (PASCAL FAR *__GetVDMPointer32W)(LPVOID ptr,UINT mask);
+extern DWORD           (_cdecl _far *__CallProcEx32W)(DWORD params,DWORD convertMask,DWORD procaddr32,...);
+
+/* NOTE: You call it as if it were declared CallProc32W(..., DWORD hinst,DWORD convertMask,DWORD procaddr32); Ick */
+extern DWORD           (PASCAL FAR *__CallProc32W)(DWORD hinst,DWORD convertMask,DWORD procaddr32,...);
+
+/* it would be nice if Open Watcom defined these constants for Win16 */
+#define CPEX_DEST_STDCALL      0x00000000UL
+#define CPEX_DEST_CDECL                0x80000000UL
+
+int genthunk32_init();
+void genthunk32_free();
+#endif
+
+#if TARGET_MSDOS == 16 || !defined(TARGET_WINDOWS)
+#pragma pack(push,4)
+/* OpenWatcom does not define the OSVERSIONINFO struct for Win16 */
+typedef struct OSVERSIONINFO {
+       uint32_t        dwOSVersionInfoSize;
+       uint32_t        dwMajorVersion;
+       uint32_t        dwMinorVersion;
+       uint32_t        dwBuildNumber;
+       uint32_t        dwPlatformId;
+       char            szCSDVersion[128];
+} OSVERSIONINFO;
+
+#define MAXPNAMELEN            32
+
+#define WAVECAPS_PITCH          0x0001
+#define WAVECAPS_PLAYBACKRATE   0x0002
+#define WAVECAPS_VOLUME         0x0004
+#define WAVECAPS_LRVOLUME       0x0008
+#define WAVECAPS_SYNC           0x0010
+#define WAVECAPS_SAMPLEACCURATE        0x0020
+
+typedef struct WAVEOUTCAPS {
+       uint16_t        wMid;
+       uint16_t        wPid;
+       uint32_t        vDriverVersion;
+       char            szPname[MAXPNAMELEN];
+       uint32_t        dwFormats;
+       uint16_t        wChannels;
+       uint16_t        wReserved1;
+       uint32_t        dwSupport;
+} WAVEOUTCAPS;
+#pragma pack(pop)
+#endif
+
+#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
+void far *dpmi_getexhandler(unsigned char n);
+int dpmi_setexhandler(unsigned char n,void far *x);
+#endif
+
+#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
+/* TODO: This should be moved into the hw/DOS library */
+extern unsigned char           nmi_32_hooked;
+extern int                     nmi_32_refcount;
+extern void                    (interrupt *nmi_32_old_vec)();
+
+void do_nmi_32_unhook();
+void do_nmi_32_hook();
+#endif
+
+#if defined(TARGET_MSDOS) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
+enum {
+       DOS_CLOSE_AWARENESS_NOT_ACK=0,
+       DOS_CLOSE_AWARENESS_ACKED=1
+};
+
+void dos_vm_yield();
+void dos_close_awareness_ack();
+int dos_close_awareness_query();
+void dos_close_awareness_cancel();
+int dos_close_awareness_available();
+int dos_close_awareness_enable(unsigned char en);
+#endif
+
+/* unlike DOSBox, VirtualBox's ROM BIOS contains it's version number, which we copy down here */
+extern char virtualbox_version_str[64];
+
+int detect_virtualbox_emu();
+
+#if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
+int __cdecl dpmi_lin2fmemcpy_32(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
+int __cdecl dpmi_lin2fmemcpy_16(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
+int dpmi_lin2fmemcpy(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
+int dpmi_lin2fmemcpy_init();
+#endif
+
+struct lib_dos_options {
+       uint8_t                 dont_load_dosntast:1;   /* do not automatically load DOSNTAST, but use it if loaded. */
+                                                       /* if not loaded and the program wants it later on, it should
+                                                        * call ntvdm_dosntast_load_vdd(); */
+       uint8_t                 dont_use_dosntast:1;    /* do not use DOSNTAST, even if loaded */
+       uint8_t                 __reserved__:6;
+};
+
+extern struct lib_dos_options lib_dos_option;
+
+# define DOSNTAST_HANDLE_UNASSIGNED            0xFFFFU
+
+# define DOSNTAST_INIT_REPORT_HANDLE           0xD0500000
+# define DOSNTAST_INIT_REPORT_HANDLE_C         0xD0500000ULL
+/* in: EBX = DOSNTAST_INIT_REPORT_HANDLE
+ *     ECX = NTVDM handle
+ * out: EBX = 0x55AA55AA
+ *      ECX = flat memory address where signature is stored (must be in BIOS data area) */
+
+# define DOSNTAST_GETVERSIONEX                 0xD0500001
+# define DOSNTAST_GETVERSIONEX_C               0xD0500001ULL
+/* in: EBX = <command>
+ *     ECX = protected mode call (1) or real-mode call (0)
+ *     DS:ESI = OSVERSIONINFO struct
+ * out: EBX = result
+ *     DS:ESI = filled in with OS struct */
+
+# define DOSNTAST_GET_TICK_COUNT               0xD0500002
+# define DOSNTAST_GET_TICK_COUNT_C             0xD0500002ULL
+/* in: EBX = <command>
+ * out: EBX = tick count */
+
+# define DOSNTAST_GET_IO_PORT                  0xD0500003
+# define DOSNTAST_GET_IO_PORT_C                        0xD0500003ULL
+/* in: EBX = <command>
+ * out: EBX = 0x55AA55AA
+ *      EDX = I/O port base */
+
+# define DOSNTAST_NOTIFY_UNLOAD                        0xD050FFFF
+# define DOSNTAST_NOTIFY_UNLOAD_C              0xD050FFFFULL
+/* in: EBX = <command>
+ * out: EBX = none */
+
+# define DOSNTAST_FUNCTION_GENERAL             0x1000
+#  define DOSNTAST_FUN_GEN_SUB_MESSAGEBOX      0x0000
+
+# define DOSNTAST_FUNCTION_WINMM                       0x1001
+#  define DOSNTAST_FUN_WINMM_SUB_waveOutGetNumDevs     0x0000
+#  define DOSNTAST_FUN_WINMM_SUB_waveOutGetDevCaps     0x0001
+#  define DOSNTAST_FUN_WINMM_SUB_waveOutOpen           0x0002
+
+const char *dos_flavor_str(uint8_t f);
+
+/* Windows NT-friendly version of Win386 MapAliasToFlat.
+ * The library version is naive and assumes Windows 3.x/9x/ME behavior.
+ * If you need to convert pointers NOT given by Win386's AllocAlias() functions
+ * (such as 16:16 pointers given by Window messages) and need the code to gracefully
+ * handle itself under Windows NT, use this function not MapAliasToFlat() */
+#if TARGET_MSDOS == 32 && defined(WIN386)
+void far *win386_alt_winnt_MapAliasToFlat(DWORD farptr);
+void far *win386_help_MapAliasToFlat(DWORD farptr);
+#endif
+
+#if (TARGET_MSDOS == 16 || TARGET_MSDOS == 32) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
+extern unsigned short                  smartdrv_version;
+extern int                             smartdrv_fd;
+
+int smartdrv_close();
+int smartdrv_flush();
+int smartdrv_detect();
+#endif
+
+uint32_t dos_linear_to_phys_vcpi(uint32_t pn);
+
+#endif /* __HW_DOS_DOS_H */
+