X-Git-Url: http://4ch.mooo.com/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fdl%2Fdos.h;fp=src%2Flib%2Fdl%2Fdos.h;h=2ae46b5b872163cab6fe3bfd7be13ca965510b30;hb=10d8a0d8b1b72502f34c2ac1bd3a5c2d87849080;hp=0000000000000000000000000000000000000000;hpb=bc10e84da5198561bb96cf8eb459f59b8b0739ec;p=16.git diff --git a/src/lib/dl/dos.h b/src/lib/dl/dos.h new file mode 100755 index 00000000..2ae46b5b --- /dev/null +++ b/src/lib/dl/dos.h @@ -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. + * + */ + +#ifndef __HW_DOS_DOS_H +#define __HW_DOS_DOS_H + +#include "src/lib/doslib/cpu.h" +//#include "src/lib/16_head.h" +#include + +#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2) +/* NTVDM.EXE DOSNTAST.VDD call support */ +//#include +#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 +#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 = + * 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 = + * out: EBX = tick count */ + +# define DOSNTAST_GET_IO_PORT 0xD0500003 +# define DOSNTAST_GET_IO_PORT_C 0xD0500003ULL +/* in: EBX = + * out: EBX = 0x55AA55AA + * EDX = I/O port base */ + +# define DOSNTAST_NOTIFY_UNLOAD 0xD050FFFF +# define DOSNTAST_NOTIFY_UNLOAD_C 0xD050FFFFULL +/* in: EBX = + * 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 */ +