winedos: Merge all of winedos back into krnl386.
This commit is contained in:
parent
03e31f9b86
commit
26a42f8452
|
@ -4102,7 +4102,6 @@ enable_win16=${enable_win16:-no}
|
|||
if test "x$enable_win16" != "xyes"
|
||||
then
|
||||
enable_w32skrnl=${enable_w32skrnl:-no}
|
||||
enable_winedos=${enable_winedos:-no}
|
||||
enable_winevdm=${enable_winevdm:-no}
|
||||
enable_wow32=${enable_wow32:-no}
|
||||
fi
|
||||
|
@ -17009,14 +17008,6 @@ ALL_MAKEFILE_DEPENDS="$ALL_MAKEFILE_DEPENDS
|
|||
dlls/wined3d/Makefile: dlls/wined3d/Makefile.in dlls/Makedll.rules"
|
||||
ac_config_files="$ac_config_files dlls/wined3d/Makefile"
|
||||
|
||||
ALL_MAKEFILES="$ALL_MAKEFILES \\
|
||||
dlls/winedos/Makefile"
|
||||
test "x$enable_winedos" != xno && ALL_DLL_DIRS="$ALL_DLL_DIRS \\
|
||||
winedos"
|
||||
ALL_MAKEFILE_DEPENDS="$ALL_MAKEFILE_DEPENDS
|
||||
dlls/winedos/Makefile: dlls/winedos/Makefile.in dlls/Makedll.rules"
|
||||
ac_config_files="$ac_config_files dlls/winedos/Makefile"
|
||||
|
||||
ALL_MAKEFILES="$ALL_MAKEFILES \\
|
||||
dlls/wineesd.drv/Makefile"
|
||||
test "x$enable_wineesd_drv" != xno && ALL_DLL_DIRS="$ALL_DLL_DIRS \\
|
||||
|
@ -19161,7 +19152,6 @@ do
|
|||
"dlls/winecoreaudio.drv/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/winecoreaudio.drv/Makefile" ;;
|
||||
"dlls/winecrt0/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/winecrt0/Makefile" ;;
|
||||
"dlls/wined3d/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/wined3d/Makefile" ;;
|
||||
"dlls/winedos/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/winedos/Makefile" ;;
|
||||
"dlls/wineesd.drv/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/wineesd.drv/Makefile" ;;
|
||||
"dlls/winejack.drv/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/winejack.drv/Makefile" ;;
|
||||
"dlls/winejoystick.drv/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/winejoystick.drv/Makefile" ;;
|
||||
|
|
|
@ -172,7 +172,6 @@ enable_win16=${enable_win16:-no}
|
|||
if test "x$enable_win16" != "xyes"
|
||||
then
|
||||
enable_w32skrnl=${enable_w32skrnl:-no}
|
||||
enable_winedos=${enable_winedos:-no}
|
||||
enable_winevdm=${enable_winevdm:-no}
|
||||
enable_wow32=${enable_wow32:-no}
|
||||
fi
|
||||
|
@ -2538,7 +2537,6 @@ WINE_CONFIG_MAKEFILE([dlls/wineaudioio.drv/Makefile],[dlls/Makedll.rules],[dlls]
|
|||
WINE_CONFIG_MAKEFILE([dlls/winecoreaudio.drv/Makefile],[dlls/Makedll.rules],[dlls],[ALL_DLL_DIRS])
|
||||
WINE_CONFIG_MAKEFILE([dlls/winecrt0/Makefile],[dlls/Makeimplib.rules],[dlls],[ALL_IMPLIB_DIRS])
|
||||
WINE_CONFIG_MAKEFILE([dlls/wined3d/Makefile],[dlls/Makedll.rules],[dlls],[ALL_DLL_DIRS])
|
||||
WINE_CONFIG_MAKEFILE([dlls/winedos/Makefile],[dlls/Makedll.rules],[dlls],[ALL_DLL_DIRS])
|
||||
WINE_CONFIG_MAKEFILE([dlls/wineesd.drv/Makefile],[dlls/Makedll.rules],[dlls],[ALL_DLL_DIRS])
|
||||
WINE_CONFIG_MAKEFILE([dlls/winejack.drv/Makefile],[dlls/Makedll.rules],[dlls],[ALL_DLL_DIRS])
|
||||
WINE_CONFIG_MAKEFILE([dlls/winejoystick.drv/Makefile],[dlls/Makedll.rules],[dlls],[ALL_DLL_DIRS])
|
||||
|
|
|
@ -3,7 +3,7 @@ TOPOBJDIR = ../..
|
|||
SRCDIR = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
MODULE = ifsmgr.vxd
|
||||
IMPORTS = kernel32
|
||||
IMPORTS = kernel32 kernel
|
||||
|
||||
C_SRCS = \
|
||||
ifsmgr.c
|
||||
|
|
|
@ -97,22 +97,7 @@ static void CONTEXT_2_win32apieq(const CONTEXT86 *pCxt, struct win32apireq *pOut
|
|||
/* FIXME: pOut->ar_pad ignored */
|
||||
}
|
||||
|
||||
typedef void (WINAPI *CallBuiltinHandler)( CONTEXT *context, BYTE intnum );
|
||||
|
||||
static CallBuiltinHandler load_builtin_handler(void)
|
||||
{
|
||||
static CallBuiltinHandler handler;
|
||||
static BOOL init_done;
|
||||
|
||||
if (!init_done)
|
||||
{
|
||||
HMODULE mod = LoadLibraryA( "winedos.dll" );
|
||||
if (mod) handler = (void *)GetProcAddress( mod, "CallBuiltinHandler" );
|
||||
if (!handler) FIXME( "DOS calls not supported\n" );
|
||||
init_done = TRUE;
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
extern void __wine_call_int_handler( CONTEXT *context, BYTE intnum );
|
||||
|
||||
/***********************************************************************
|
||||
* DeviceIoControl (IFSMGR.VXD.@)
|
||||
|
@ -134,9 +119,6 @@ BOOL WINAPI IFSMGR_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpvInBuffer, DW
|
|||
CONTEXT86 cxt;
|
||||
struct win32apireq *pIn=lpvInBuffer;
|
||||
struct win32apireq *pOut=lpvOutBuffer;
|
||||
CallBuiltinHandler handler;
|
||||
|
||||
if (!(handler = load_builtin_handler())) return FALSE;
|
||||
|
||||
TRACE( "Control '%s': "
|
||||
"proid=0x%08lx, eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
|
||||
|
@ -150,9 +132,9 @@ BOOL WINAPI IFSMGR_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpvInBuffer, DW
|
|||
win32apieq_2_CONTEXT(pIn,&cxt);
|
||||
|
||||
if(dwIoControlCode==IFS_IOCTL_21)
|
||||
handler( &cxt, 0x21 );
|
||||
__wine_call_int_handler( &cxt, 0x21 );
|
||||
else
|
||||
handler( &cxt, 0x2f );
|
||||
__wine_call_int_handler( &cxt, 0x2f );
|
||||
|
||||
CONTEXT_2_win32apieq(&cxt,pOut);
|
||||
return TRUE;
|
||||
|
|
|
@ -5,17 +5,39 @@ VPATH = @srcdir@
|
|||
MODULE = krnl386.exe16
|
||||
IMPORTLIB = kernel
|
||||
IMPORTS = kernel32 ntdll
|
||||
DELAYIMPORTS = ddraw dsound user32
|
||||
EXTRAIMPLIBFLAGS = --subsystem win16
|
||||
EXTRADLLFLAGS = -Wb,--subsystem,win16,--dll-name,kernel
|
||||
EXTRARCFLAGS = -O res16
|
||||
|
||||
C_SRCS = \
|
||||
atom.c \
|
||||
dma.c \
|
||||
dosaspi.c \
|
||||
dosconf.c \
|
||||
dosdev.c \
|
||||
dosexe.c \
|
||||
dosmem.c \
|
||||
dosvm.c \
|
||||
error.c \
|
||||
file.c \
|
||||
fpu.c \
|
||||
global.c \
|
||||
instr.c \
|
||||
int09.c \
|
||||
int10.c \
|
||||
int13.c \
|
||||
int15.c \
|
||||
int16.c \
|
||||
int21.c \
|
||||
int25.c \
|
||||
int26.c \
|
||||
int2f.c \
|
||||
int31.c \
|
||||
int33.c \
|
||||
int67.c \
|
||||
interrupts.c \
|
||||
ioports.c \
|
||||
kernel.c \
|
||||
local.c \
|
||||
ne_module.c \
|
||||
|
@ -25,10 +47,13 @@ C_SRCS = \
|
|||
resource.c \
|
||||
selector.c \
|
||||
snoop.c \
|
||||
soundblaster.c \
|
||||
syslevel.c \
|
||||
task.c \
|
||||
thunk.c \
|
||||
timer.c \
|
||||
utthunk.c \
|
||||
vga.c \
|
||||
vxd.c \
|
||||
wowthunk.c
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "winuser.h"
|
||||
#include "winerror.h"
|
||||
#include "wine/debug.h"
|
||||
#include "kernel16_private.h"
|
||||
#include "dosexe.h"
|
||||
#include "vga.h"
|
||||
|
||||
|
@ -77,14 +78,6 @@ void DOSVM_Exit( WORD retval )
|
|||
|
||||
#ifdef MZ_SUPPORTED
|
||||
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
/* define this to try mapping through /proc/pid/mem instead of a temp file,
|
||||
but Linus doesn't like mmapping /proc/pid/mem, so it doesn't work for me */
|
||||
#undef MZ_MAPSELF
|
||||
|
||||
#define BIOS_DATA_SEGMENT 0x40
|
||||
#define PSP_SIZE 0x10
|
||||
|
||||
|
@ -362,12 +355,12 @@ load_error:
|
|||
}
|
||||
|
||||
/***********************************************************************
|
||||
* wine_load_dos_exe (WINEDOS.@)
|
||||
* __wine_load_dos_exe (KERNEL.@)
|
||||
*
|
||||
* Called from WineVDM when a new real-mode DOS process is started.
|
||||
* Loads DOS program into memory and executes the program.
|
||||
*/
|
||||
void WINAPI wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline )
|
||||
void __wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline )
|
||||
{
|
||||
char dos_cmdtail[126];
|
||||
int dos_length = 0;
|
||||
|
@ -376,6 +369,7 @@ void WINAPI wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline )
|
|||
NULL, OPEN_EXISTING, 0, 0 );
|
||||
if (hFile == INVALID_HANDLE_VALUE) return;
|
||||
DOSVM_isdosexe = TRUE;
|
||||
DOSMEM_InitDosMemory();
|
||||
|
||||
if(cmdline && *cmdline)
|
||||
{
|
||||
|
@ -757,9 +751,9 @@ BOOL MZ_Current( void )
|
|||
#else /* !MZ_SUPPORTED */
|
||||
|
||||
/***********************************************************************
|
||||
* wine_load_dos_exe (WINEDOS.@)
|
||||
* __wine_load_dos_exe (KERNEL.@)
|
||||
*/
|
||||
void WINAPI wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline )
|
||||
void __wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline )
|
||||
{
|
||||
FIXME("DOS executables not supported on this platform\n");
|
||||
SetLastError(ERROR_BAD_FORMAT);
|
|
@ -352,7 +352,7 @@ typedef struct
|
|||
RMCBPROC interrupt;
|
||||
} WINEDEV;
|
||||
|
||||
/* module.c */
|
||||
/* dosexe.c */
|
||||
extern BOOL MZ_Exec( CONTEXT86 *context, LPCSTR filename, BYTE func, LPVOID paramblk );
|
||||
extern void MZ_Exit( CONTEXT86 *context, BOOL cs_psp, WORD retval );
|
||||
extern BOOL MZ_Current( void );
|
||||
|
@ -371,6 +371,7 @@ extern void DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data
|
|||
extern void DOSVM_PIC_ioport_out( WORD port, BYTE val );
|
||||
extern void DOSVM_SetTimer( UINT ticks );
|
||||
extern LPVOID DOSVM_AllocDataUMB(DWORD, WORD *, WORD *);
|
||||
extern void DOSVM_InitSegments(void);
|
||||
|
||||
/* devices.c */
|
||||
extern void DOSDEV_InstallDOSDevices(void);
|
||||
|
@ -391,13 +392,6 @@ extern void DOSVM_ASPIHandler(CONTEXT86*);
|
|||
extern DOSCONF *DOSCONF_GetConfig( void );
|
||||
|
||||
/* dosmem.c */
|
||||
extern BOOL DOSMEM_InitDosMemory(void);
|
||||
extern BOOL DOSMEM_MapDosLayout(void);
|
||||
extern WORD DOSMEM_AllocSelector(WORD); /* FIXME: to be removed */
|
||||
extern LPVOID DOSMEM_AllocBlock(UINT size, WORD* p);
|
||||
extern BOOL DOSMEM_FreeBlock(void* ptr);
|
||||
extern UINT DOSMEM_ResizeBlock(void* ptr, UINT size, BOOL exact);
|
||||
extern UINT DOSMEM_Available(void);
|
||||
extern BIOSDATA *DOSVM_BiosData( void );
|
||||
|
||||
/* fpu.c */
|
||||
|
@ -466,8 +460,9 @@ extern void WINAPI DOSVM_Int67Handler(CONTEXT86*);
|
|||
extern void EMS_Ioctl_Handler(CONTEXT86*);
|
||||
|
||||
/* interrupts.c */
|
||||
extern void WINAPI DOSVM_CallBuiltinHandler( CONTEXT86 *, BYTE );
|
||||
extern BOOL WINAPI DOSVM_EmulateInterruptPM( CONTEXT86 *, BYTE );
|
||||
extern void __wine_call_int_handler( CONTEXT86 *, BYTE );
|
||||
extern void DOSVM_CallBuiltinHandler( CONTEXT86 *, BYTE );
|
||||
extern BOOL DOSVM_EmulateInterruptPM( CONTEXT86 *, BYTE );
|
||||
extern BOOL DOSVM_EmulateInterruptRM( CONTEXT86 *, BYTE );
|
||||
extern FARPROC16 DOSVM_GetPMHandler16( BYTE );
|
||||
extern FARPROC48 DOSVM_GetPMHandler48( BYTE );
|
||||
|
@ -478,6 +473,10 @@ extern void DOSVM_SetPMHandler16( BYTE, FARPROC16 );
|
|||
extern void DOSVM_SetPMHandler48( BYTE, FARPROC48 );
|
||||
extern void DOSVM_SetRMHandler( BYTE, FARPROC16 );
|
||||
|
||||
/* ioports.c */
|
||||
extern DWORD DOSVM_inport( int port, int size );
|
||||
extern void DOSVM_outport( int port, int size, DWORD value );
|
||||
|
||||
/* relay.c */
|
||||
void DOSVM_RelayHandler( CONTEXT86 * );
|
||||
void DOSVM_BuildCallFrame( CONTEXT86 *, DOSRELAY, LPVOID );
|
|
@ -38,6 +38,7 @@
|
|||
#include "wine/winbase16.h"
|
||||
|
||||
#include "kernel16_private.h"
|
||||
#include "dosexe.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dosmem);
|
||||
|
@ -51,6 +52,48 @@ WORD DOSMEM_BiosSysSeg; /* BIOS ROM segment at 0xf000:0 */
|
|||
#define DOSMEM_SIZE 0x110000
|
||||
#define DOSMEM_64KB 0x10000
|
||||
|
||||
/*
|
||||
* Memory Control Block (MCB) definition
|
||||
* FIXME: implement Allocation Strategy
|
||||
*/
|
||||
|
||||
#define MCB_DUMP(mc) \
|
||||
TRACE ("MCB_DUMP base=%p type=%02xh psp=%04xh size=%04xh\n", mc, mc->type, mc->psp , mc->size )
|
||||
|
||||
#define MCB_NEXT(mc) \
|
||||
(MCB*) ((mc->type==MCB_TYPE_LAST) ? NULL : (char*)(mc) + ((mc->size + 1) << 4) )
|
||||
|
||||
/* FIXME: should we check more? */
|
||||
#define MCB_VALID(mc) \
|
||||
((mc->type==MCB_TYPE_NORMAL) || (mc->type==MCB_TYPE_LAST))
|
||||
|
||||
|
||||
#define MCB_TYPE_NORMAL 0x4d
|
||||
#define MCB_TYPE_LAST 0x5a
|
||||
|
||||
#define MCB_PSP_DOS 0x0060
|
||||
#define MCB_PSP_FREE 0
|
||||
|
||||
#include "pshpack1.h"
|
||||
typedef struct {
|
||||
BYTE type;
|
||||
WORD psp; /* segment of owner psp */
|
||||
WORD size; /* in paragraphs */
|
||||
BYTE pad[3];
|
||||
BYTE name[8];
|
||||
} MCB;
|
||||
#include "poppack.h"
|
||||
|
||||
/*
|
||||
#define __DOSMEM_DEBUG__
|
||||
*/
|
||||
|
||||
#define VM_STUB(x) (0x90CF00CD|(x<<8)) /* INT x; IRET; NOP */
|
||||
#define VM_STUB_SEGMENT 0xf000 /* BIOS segment */
|
||||
|
||||
/* FIXME: this should be moved to the LOL */
|
||||
static MCB* DOSMEM_root_block;
|
||||
|
||||
/* when looking at DOS and real mode memory, we activate in three different
|
||||
* modes, depending the situation.
|
||||
* 1/ By default (protected mode), the first MB of memory (actually 0x110000,
|
||||
|
@ -71,55 +114,232 @@ WORD DOSMEM_BiosSysSeg; /* BIOS ROM segment at 0xf000:0 */
|
|||
|
||||
/* DOS memory base (linear in process address space) */
|
||||
static char *DOSMEM_dosmem;
|
||||
static char *DOSMEM_sysmem;
|
||||
/* number of bytes protected from _dosmem. 0 when DOS memory is initialized,
|
||||
* 64k otherwise to trap NULL pointers deref */
|
||||
static DWORD DOSMEM_protect;
|
||||
|
||||
static LONG WINAPI dosmem_handler(EXCEPTION_POINTERS* except);
|
||||
|
||||
struct winedos_exports winedos;
|
||||
|
||||
BOOL load_winedos(void)
|
||||
/***********************************************************************
|
||||
* DOSMEM_FillIsrTable
|
||||
*
|
||||
* Fill the interrupt table with fake BIOS calls to BIOSSEG (0xf000).
|
||||
*
|
||||
* NOTES:
|
||||
* Linux normally only traps INTs performed from or destined to BIOSSEG
|
||||
* for us to handle, if the int_revectored table is empty. Filling the
|
||||
* interrupt table with calls to INT stubs in BIOSSEG allows DOS programs
|
||||
* to hook interrupts, as well as use their familiar retf tricks to call
|
||||
* them, AND let Wine handle any unhooked interrupts transparently.
|
||||
*/
|
||||
static void DOSMEM_FillIsrTable(void)
|
||||
{
|
||||
static HANDLE hRunOnce /* = 0 */;
|
||||
static HMODULE hWineDos /* = 0 */;
|
||||
SEGPTR *isr = (SEGPTR*)DOSMEM_sysmem;
|
||||
int x;
|
||||
|
||||
/* FIXME: this isn't 100% thread safe, as we won't catch access to 1MB while
|
||||
* loading winedos (and may return uninitialized valued)
|
||||
for (x=0; x<256; x++) isr[x]=MAKESEGPTR(VM_STUB_SEGMENT,x*4);
|
||||
}
|
||||
|
||||
static void DOSMEM_MakeIsrStubs(void)
|
||||
{
|
||||
DWORD *stub = (DWORD*)(DOSMEM_dosmem + (VM_STUB_SEGMENT << 4));
|
||||
int x;
|
||||
|
||||
for (x=0; x<256; x++) stub[x]=VM_STUB(x);
|
||||
}
|
||||
|
||||
BIOSDATA* DOSVM_BiosData(void)
|
||||
{
|
||||
return (BIOSDATA *)(DOSMEM_sysmem + 0x400);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* DOSMEM_GetTicksSinceMidnight
|
||||
*
|
||||
* Return number of clock ticks since midnight.
|
||||
*/
|
||||
static DWORD DOSMEM_GetTicksSinceMidnight(void)
|
||||
{
|
||||
SYSTEMTIME time;
|
||||
|
||||
/* This should give us the (approximately) correct
|
||||
* 18.206 clock ticks per second since midnight.
|
||||
*/
|
||||
if (hWineDos) goto done;
|
||||
|
||||
GetLocalTime( &time );
|
||||
|
||||
return (((time.wHour * 3600 + time.wMinute * 60 +
|
||||
time.wSecond) * 18206) / 1000) +
|
||||
(time.wMilliseconds * 1000 / 54927);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_FillBiosSegments
|
||||
*
|
||||
* Fill the BIOS data segment with dummy values.
|
||||
*/
|
||||
static void DOSMEM_FillBiosSegments(void)
|
||||
{
|
||||
BYTE *pBiosSys = (BYTE*)DOSMEM_dosmem + 0xf0000;
|
||||
BYTE *pBiosROMTable = pBiosSys+0xe6f5;
|
||||
BIOSDATA *pBiosData = DOSVM_BiosData();
|
||||
static const char bios_date[] = "13/01/99";
|
||||
|
||||
/* Clear all unused values */
|
||||
memset( pBiosData, 0, sizeof(*pBiosData) );
|
||||
|
||||
/* FIXME: should check the number of configured drives and ports */
|
||||
pBiosData->Com1Addr = 0x3f8;
|
||||
pBiosData->Com2Addr = 0x2f8;
|
||||
pBiosData->Lpt1Addr = 0x378;
|
||||
pBiosData->Lpt2Addr = 0x278;
|
||||
pBiosData->InstalledHardware = 0x5463;
|
||||
pBiosData->MemSize = 640;
|
||||
pBiosData->NextKbdCharPtr = 0x1e;
|
||||
pBiosData->FirstKbdCharPtr = 0x1e;
|
||||
pBiosData->VideoMode = 3;
|
||||
pBiosData->VideoColumns = 80;
|
||||
pBiosData->VideoPageSize = 80 * 25 * 2;
|
||||
pBiosData->VideoPageStartAddr = 0xb800;
|
||||
pBiosData->VideoCtrlAddr = 0x3d4;
|
||||
pBiosData->Ticks = DOSMEM_GetTicksSinceMidnight();
|
||||
pBiosData->NbHardDisks = 2;
|
||||
pBiosData->KbdBufferStart = 0x1e;
|
||||
pBiosData->KbdBufferEnd = 0x3e;
|
||||
pBiosData->RowsOnScreenMinus1 = 24;
|
||||
pBiosData->BytesPerChar = 0x10;
|
||||
pBiosData->ModeOptions = 0x64;
|
||||
pBiosData->FeatureBitsSwitches = 0xf9;
|
||||
pBiosData->VGASettings = 0x51;
|
||||
pBiosData->DisplayCombination = 0x08;
|
||||
pBiosData->DiskDataRate = 0;
|
||||
|
||||
/* fill ROM configuration table (values from Award) */
|
||||
*(pBiosROMTable+0x0) = 0x08; /* number of bytes following LO */
|
||||
*(pBiosROMTable+0x1) = 0x00; /* number of bytes following HI */
|
||||
*(pBiosROMTable+0x2) = 0xfc; /* model */
|
||||
*(pBiosROMTable+0x3) = 0x01; /* submodel */
|
||||
*(pBiosROMTable+0x4) = 0x00; /* BIOS revision */
|
||||
*(pBiosROMTable+0x5) = 0x74; /* feature byte 1 */
|
||||
*(pBiosROMTable+0x6) = 0x00; /* feature byte 2 */
|
||||
*(pBiosROMTable+0x7) = 0x00; /* feature byte 3 */
|
||||
*(pBiosROMTable+0x8) = 0x00; /* feature byte 4 */
|
||||
*(pBiosROMTable+0x9) = 0x00; /* feature byte 5 */
|
||||
|
||||
/* BIOS date string */
|
||||
memcpy(pBiosSys+0xfff5, bios_date, sizeof bios_date);
|
||||
|
||||
/* BIOS ID */
|
||||
*(pBiosSys+0xfffe) = 0xfc;
|
||||
|
||||
/* Reboot vector (f000:fff0 or ffff:0000) */
|
||||
*(DWORD*)(pBiosSys + 0xfff0) = VM_STUB(0x19);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* BiosTick
|
||||
*
|
||||
* Increment the BIOS tick counter. Called by timer signal handler.
|
||||
*/
|
||||
static void CALLBACK BiosTick( LPVOID arg, DWORD low, DWORD high )
|
||||
{
|
||||
BIOSDATA *pBiosData = arg;
|
||||
pBiosData->Ticks++;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* timer_thread
|
||||
*/
|
||||
static DWORD CALLBACK timer_thread( void *arg )
|
||||
{
|
||||
LARGE_INTEGER when;
|
||||
HANDLE timer;
|
||||
|
||||
if (!(timer = CreateWaitableTimerA( NULL, FALSE, NULL ))) return 0;
|
||||
|
||||
when.u.LowPart = when.u.HighPart = 0;
|
||||
SetWaitableTimer( timer, &when, 55 /* actually 54.925 */, BiosTick, arg, FALSE );
|
||||
for (;;) SleepEx( INFINITE, TRUE );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_Collapse
|
||||
*
|
||||
* Helper function for internal use only.
|
||||
* Attach all following free blocks to this one, even if this one is not free.
|
||||
*/
|
||||
static void DOSMEM_Collapse( MCB* mcb )
|
||||
{
|
||||
MCB* next = MCB_NEXT( mcb );
|
||||
|
||||
while (next && next->psp == MCB_PSP_FREE)
|
||||
{
|
||||
mcb->size = mcb->size + next->size + 1;
|
||||
mcb->type = next->type; /* make sure keeping MCB_TYPE_LAST */
|
||||
next = MCB_NEXT( next );
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* DOSMEM_InitDosMemory
|
||||
*/
|
||||
BOOL DOSMEM_InitDosMemory(void)
|
||||
{
|
||||
static int done;
|
||||
static HANDLE hRunOnce;
|
||||
|
||||
if (done) return TRUE;
|
||||
|
||||
/* FIXME: this isn't 100% thread safe, as we won't catch accesses while initializing */
|
||||
if (hRunOnce == 0)
|
||||
{
|
||||
HANDLE hEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
|
||||
if (InterlockedCompareExchangePointer( &hRunOnce, hEvent, 0 ) == 0)
|
||||
{
|
||||
HMODULE hModule;
|
||||
BOOL ret;
|
||||
DWORD reserve;
|
||||
|
||||
/* ok, we're the winning thread */
|
||||
if (!VirtualProtect( DOSMEM_dosmem + DOSMEM_protect,
|
||||
DOSMEM_SIZE - DOSMEM_protect,
|
||||
PAGE_READWRITE, NULL ) ||
|
||||
!(hModule = LoadLibraryA( "winedos.dll" )))
|
||||
{
|
||||
ERR("Could not load winedos.dll, DOS subsystem unavailable\n");
|
||||
hModule = (HMODULE)1; /* not to try to load it again */
|
||||
}
|
||||
else
|
||||
{
|
||||
#define GET_ADDR(func) winedos.func = (void *)GetProcAddress( hModule, #func );
|
||||
GET_ADDR(AllocDosBlock);
|
||||
GET_ADDR(FreeDosBlock);
|
||||
GET_ADDR(ResizeDosBlock);
|
||||
GET_ADDR(inport);
|
||||
GET_ADDR(outport);
|
||||
GET_ADDR(EmulateInterruptPM);
|
||||
GET_ADDR(CallBuiltinHandler);
|
||||
#undef GET_ADDR
|
||||
}
|
||||
if (!(ret = VirtualProtect( DOSMEM_dosmem + DOSMEM_protect,
|
||||
DOSMEM_SIZE - DOSMEM_protect,
|
||||
PAGE_READWRITE, NULL )))
|
||||
ERR("Cannot load access low 1Mb, DOS subsystem unavailable\n");
|
||||
RtlRemoveVectoredExceptionHandler( dosmem_handler );
|
||||
hWineDos = hModule;
|
||||
|
||||
/*
|
||||
* Reserve either:
|
||||
* - lowest 64k for NULL pointer catching (Win16)
|
||||
* - lowest 1k for interrupt handlers and
|
||||
* another 0.5k for BIOS, DOS and intra-application
|
||||
* areas (DOS)
|
||||
*/
|
||||
if (DOSMEM_dosmem != DOSMEM_sysmem)
|
||||
reserve = 0x10000; /* 64k */
|
||||
else
|
||||
reserve = 0x600; /* 1.5k */
|
||||
|
||||
/*
|
||||
* Set DOS memory base and initialize conventional memory.
|
||||
*/
|
||||
DOSMEM_FillBiosSegments();
|
||||
DOSMEM_FillIsrTable();
|
||||
|
||||
/* align root block to paragraph */
|
||||
DOSMEM_root_block = (MCB*)(DOSMEM_dosmem + reserve);
|
||||
DOSMEM_root_block->type = MCB_TYPE_LAST;
|
||||
DOSMEM_root_block->psp = MCB_PSP_FREE;
|
||||
DOSMEM_root_block->size = (DOSMEM_dosmem + 0x9fffc - ((char*)DOSMEM_root_block)) >> 4;
|
||||
|
||||
TRACE("DOS conventional memory initialized, %d bytes free.\n",
|
||||
DOSMEM_Available());
|
||||
|
||||
DOSVM_InitSegments();
|
||||
CloseHandle( CreateThread( NULL, 0, timer_thread, DOSVM_BiosData(), 0, NULL ));
|
||||
|
||||
SetEvent( hRunOnce );
|
||||
goto done;
|
||||
done = 1;
|
||||
return ret;
|
||||
}
|
||||
/* someone beat us here... */
|
||||
CloseHandle( hEvent );
|
||||
|
@ -127,8 +347,7 @@ BOOL load_winedos(void)
|
|||
|
||||
/* and wait for the winner to have finished */
|
||||
WaitForSingleObject( hRunOnce, INFINITE );
|
||||
done:
|
||||
return (hWineDos != (HMODULE)1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
@ -143,7 +362,7 @@ static LONG WINAPI dosmem_handler(EXCEPTION_POINTERS* except)
|
|||
char *addr = (char *)except->ExceptionRecord->ExceptionInformation[1];
|
||||
if (addr >= DOSMEM_dosmem + DOSMEM_protect && addr < DOSMEM_dosmem + DOSMEM_SIZE)
|
||||
{
|
||||
if (load_winedos()) return EXCEPTION_CONTINUE_EXECUTION;
|
||||
if (DOSMEM_InitDosMemory()) return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
@ -157,7 +376,6 @@ static LONG WINAPI dosmem_handler(EXCEPTION_POINTERS* except)
|
|||
*/
|
||||
BOOL DOSMEM_Init(void)
|
||||
{
|
||||
char *sysmem;
|
||||
void *addr = (void *)1;
|
||||
SIZE_T size = DOSMEM_SIZE - 1;
|
||||
|
||||
|
@ -172,20 +390,20 @@ BOOL DOSMEM_Init(void)
|
|||
{
|
||||
DOSMEM_dosmem = 0;
|
||||
DOSMEM_protect = DOSMEM_64KB;
|
||||
sysmem = (char *)0xf0000; /* store sysmem in high addresses for now */
|
||||
DOSMEM_sysmem = (char *)0xf0000; /* store sysmem in high addresses for now */
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN( "First megabyte not available for DOS address space.\n" );
|
||||
DOSMEM_dosmem = addr;
|
||||
DOSMEM_protect = 0;
|
||||
sysmem = DOSMEM_dosmem;
|
||||
DOSMEM_sysmem = DOSMEM_dosmem;
|
||||
}
|
||||
|
||||
RtlAddVectoredExceptionHandler(FALSE, dosmem_handler);
|
||||
DOSMEM_0000H = GLOBAL_CreateBlock( GMEM_FIXED, sysmem,
|
||||
DOSMEM_0000H = GLOBAL_CreateBlock( GMEM_FIXED, DOSMEM_sysmem,
|
||||
DOSMEM_64KB, 0, WINE_LDT_FLAGS_DATA );
|
||||
DOSMEM_BiosDataSeg = GLOBAL_CreateBlock( GMEM_FIXED, sysmem + 0x400,
|
||||
DOSMEM_BiosDataSeg = GLOBAL_CreateBlock( GMEM_FIXED, DOSMEM_sysmem + 0x400,
|
||||
0x100, 0, WINE_LDT_FLAGS_DATA );
|
||||
DOSMEM_BiosSysSeg = GLOBAL_CreateBlock( GMEM_FIXED, DOSMEM_dosmem + 0xf0000,
|
||||
DOSMEM_64KB, 0, WINE_LDT_FLAGS_DATA );
|
||||
|
@ -232,3 +450,210 @@ LPVOID DOSMEM_MapRealToLinear(DWORD x)
|
|||
TRACE_(selector)("(0x%08x) returns %p.\n", x, lin );
|
||||
return lin;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_AllocBlock
|
||||
*
|
||||
* Carve a chunk of the DOS memory block (without selector).
|
||||
*/
|
||||
LPVOID DOSMEM_AllocBlock(UINT size, UINT16* pseg)
|
||||
{
|
||||
MCB *curr;
|
||||
MCB *next = NULL;
|
||||
WORD psp = DOSVM_psp;
|
||||
|
||||
DOSMEM_InitDosMemory();
|
||||
|
||||
curr = DOSMEM_root_block;
|
||||
if (!(psp = DOSVM_psp)) psp = MCB_PSP_DOS;
|
||||
|
||||
*pseg = 0;
|
||||
|
||||
TRACE( "(%04xh)\n", size );
|
||||
|
||||
/* round up to paragraph */
|
||||
size = (size + 15) >> 4;
|
||||
|
||||
#ifdef __DOSMEM_DEBUG__
|
||||
DOSMEM_Available(); /* checks the whole MCB list */
|
||||
#endif
|
||||
|
||||
/* loop over all MCB and search the next large enough MCB */
|
||||
while (curr)
|
||||
{
|
||||
if (!MCB_VALID (curr))
|
||||
{
|
||||
ERR( "MCB List Corrupt\n" );
|
||||
MCB_DUMP( curr );
|
||||
return NULL;
|
||||
}
|
||||
if (curr->psp == MCB_PSP_FREE)
|
||||
{
|
||||
DOSMEM_Collapse( curr );
|
||||
/* is it large enough (one paragraph for the MCB)? */
|
||||
if (curr->size >= size)
|
||||
{
|
||||
if (curr->size > size)
|
||||
{
|
||||
/* split curr */
|
||||
next = (MCB *) ((char*) curr + ((size+1) << 4));
|
||||
next->psp = MCB_PSP_FREE;
|
||||
next->size = curr->size - (size+1);
|
||||
next->type = curr->type;
|
||||
curr->type = MCB_TYPE_NORMAL;
|
||||
curr->size = size;
|
||||
}
|
||||
/* curr is the found block */
|
||||
curr->psp = psp;
|
||||
if( pseg ) *pseg = (((char*)curr) + 16 - DOSMEM_dosmem) >> 4;
|
||||
return (LPVOID) ((char*)curr + 16);
|
||||
}
|
||||
}
|
||||
curr = MCB_NEXT(curr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_FreeBlock
|
||||
*/
|
||||
BOOL DOSMEM_FreeBlock(void* ptr)
|
||||
{
|
||||
MCB* mcb = (MCB*) ((char*)ptr - 16);
|
||||
|
||||
TRACE( "(%p)\n", ptr );
|
||||
|
||||
#ifdef __DOSMEM_DEBUG__
|
||||
DOSMEM_Available();
|
||||
#endif
|
||||
|
||||
if (!MCB_VALID (mcb))
|
||||
{
|
||||
ERR( "MCB invalid\n" );
|
||||
MCB_DUMP( mcb );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mcb->psp = MCB_PSP_FREE;
|
||||
DOSMEM_Collapse( mcb );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_ResizeBlock
|
||||
*
|
||||
* Resize DOS memory block in place. Returns block size or -1 on error.
|
||||
*
|
||||
* If exact is TRUE, returned value is either old or requested block
|
||||
* size. If exact is FALSE, block is expanded even if there is not
|
||||
* enough space for full requested block size.
|
||||
*
|
||||
* TODO: return also biggest block size
|
||||
*/
|
||||
UINT DOSMEM_ResizeBlock(void *ptr, UINT size, BOOL exact)
|
||||
{
|
||||
MCB* mcb = (MCB*) ((char*)ptr - 16);
|
||||
MCB* next;
|
||||
|
||||
TRACE( "(%p,%04xh,%s)\n", ptr, size, exact ? "TRUE" : "FALSE" );
|
||||
|
||||
/* round up to paragraph */
|
||||
size = (size + 15) >> 4;
|
||||
|
||||
#ifdef __DOSMEM_DEBUG__
|
||||
DOSMEM_Available();
|
||||
#endif
|
||||
|
||||
if (!MCB_VALID (mcb))
|
||||
{
|
||||
ERR( "MCB invalid\n" );
|
||||
MCB_DUMP( mcb );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* resize needed? */
|
||||
if (mcb->size == size)
|
||||
return size << 4;
|
||||
|
||||
/* collapse free blocks */
|
||||
DOSMEM_Collapse( mcb );
|
||||
|
||||
/* shrink mcb ? */
|
||||
if (mcb->size > size)
|
||||
{
|
||||
next = (MCB *) ((char*)mcb + ((size+1) << 4));
|
||||
next->type = mcb->type;
|
||||
next->psp = MCB_PSP_FREE;
|
||||
next->size = mcb->size - (size+1);
|
||||
mcb->type = MCB_TYPE_NORMAL;
|
||||
mcb->size = size;
|
||||
return size << 4;
|
||||
}
|
||||
|
||||
if (!exact)
|
||||
{
|
||||
return mcb->size << 4;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_Available
|
||||
*/
|
||||
UINT DOSMEM_Available(void)
|
||||
{
|
||||
UINT available = 0;
|
||||
UINT total = 0;
|
||||
MCB *curr = DOSMEM_root_block;
|
||||
/* loop over all MCB and search the largest free MCB */
|
||||
while (curr)
|
||||
{
|
||||
#ifdef __DOSMEM_DEBUG__
|
||||
MCB_DUMP( curr );
|
||||
#endif
|
||||
if (!MCB_VALID (curr))
|
||||
{
|
||||
ERR( "MCB List Corrupt\n" );
|
||||
MCB_DUMP( curr );
|
||||
return 0;
|
||||
}
|
||||
if (curr->psp == MCB_PSP_FREE &&
|
||||
curr->size > available )
|
||||
available = curr->size;
|
||||
|
||||
total += curr->size + 1;
|
||||
curr = MCB_NEXT( curr );
|
||||
}
|
||||
TRACE( " %04xh of %04xh paragraphs available\n", available, total );
|
||||
return available << 4;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* DOSMEM_MapDosLayout
|
||||
*
|
||||
* Initialize the first MB of memory to look like a real DOS setup
|
||||
*/
|
||||
BOOL DOSMEM_MapDosLayout(void)
|
||||
{
|
||||
static int already_mapped;
|
||||
|
||||
if (!already_mapped)
|
||||
{
|
||||
if (DOSMEM_dosmem || !VirtualProtect( NULL, DOSMEM_SIZE, PAGE_EXECUTE_READWRITE, NULL ))
|
||||
{
|
||||
ERR( "Need full access to the first megabyte for DOS mode\n" );
|
||||
ExitProcess(1);
|
||||
}
|
||||
/* copy the BIOS and ISR area down */
|
||||
memcpy( DOSMEM_dosmem, DOSMEM_sysmem, 0x400 + 0x100 );
|
||||
DOSMEM_sysmem = DOSMEM_dosmem;
|
||||
SetSelectorBase( DOSMEM_0000H, 0 );
|
||||
SetSelectorBase( DOSMEM_BiosDataSeg, 0x400 );
|
||||
/* we may now need the actual interrupt stubs, and since we've just moved the
|
||||
* interrupt vector table away, we can fill the area with stubs instead... */
|
||||
DOSMEM_MakeIsrStubs();
|
||||
already_mapped = 1;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -825,7 +825,7 @@ LPVOID DOSVM_AllocDataUMB( DWORD size, WORD *segment, WORD *selector )
|
|||
* Initializes DOSVM_dpmi_segments. Allocates required memory and
|
||||
* sets up segments and selectors for accessing the memory.
|
||||
*/
|
||||
static void DOSVM_InitSegments(void)
|
||||
void DOSVM_InitSegments(void)
|
||||
{
|
||||
LPSTR ptr;
|
||||
int i;
|
||||
|
@ -967,25 +967,6 @@ static void DOSVM_InitSegments(void)
|
|||
* As we store code in UMB we should make sure it is executable
|
||||
*/
|
||||
VirtualProtect((void *)DOSVM_UMB_BOTTOM, DOSVM_UMB_TOP - DOSVM_UMB_BOTTOM, PAGE_EXECUTE_READWRITE, NULL);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* DllMain (DOSVM.0)
|
||||
*/
|
||||
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
|
||||
{
|
||||
TRACE_(module)("(%p,%d,%p)\n", hinstDLL, fdwReason, lpvReserved);
|
||||
|
||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
DisableThreadLibraryCalls(hinstDLL);
|
||||
if (!DOSMEM_InitDosMemory()) return FALSE;
|
||||
DOSVM_InitSegments();
|
||||
|
||||
event_notifier = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
if(!event_notifier)
|
||||
ERR("Failed to create event object!\n");
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
event_notifier = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
}
|
|
@ -74,24 +74,6 @@ static int globalArenaSize;
|
|||
#define VALID_HANDLE(handle) (((handle)>>__AHSHIFT)<globalArenaSize)
|
||||
#define GET_ARENA_PTR(handle) (pGlobalArena + ((handle) >> __AHSHIFT))
|
||||
|
||||
static inline void* DOSMEM_AllocBlock(UINT size, UINT16* pseg)
|
||||
{
|
||||
if (!winedos.AllocDosBlock) load_winedos();
|
||||
return winedos.AllocDosBlock ? winedos.AllocDosBlock(size, pseg) : NULL;
|
||||
}
|
||||
|
||||
static inline BOOL DOSMEM_FreeBlock(void* ptr)
|
||||
{
|
||||
if (!winedos.FreeDosBlock) load_winedos();
|
||||
return winedos.FreeDosBlock ? winedos.FreeDosBlock( ptr ) : FALSE;
|
||||
}
|
||||
|
||||
static inline UINT DOSMEM_ResizeBlock(void *ptr, UINT size, BOOL exact)
|
||||
{
|
||||
if (!winedos.ResizeDosBlock) load_winedos();
|
||||
return winedos.ResizeDosBlock ? winedos.ResizeDosBlock(ptr, size, TRUE) : 0;
|
||||
}
|
||||
|
||||
static HANDLE get_win16_heap(void)
|
||||
{
|
||||
static HANDLE win16_heap;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "excpt.h"
|
||||
#include "wine/debug.h"
|
||||
#include "kernel16_private.h"
|
||||
#include "dosexe.h"
|
||||
#include "wine/exception.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(int);
|
||||
|
@ -361,10 +362,7 @@ static BOOL INSTR_EmulateLDS( CONTEXT86 *context, BYTE *instr, int long_op,
|
|||
*/
|
||||
static DWORD INSTR_inport( WORD port, int size, CONTEXT86 *context )
|
||||
{
|
||||
DWORD res = ~0U;
|
||||
|
||||
if (!winedos.inport) load_winedos();
|
||||
if (winedos.inport) res = winedos.inport( port, size );
|
||||
DWORD res = DOSVM_inport( port, size );
|
||||
|
||||
if (TRACE_ON(io))
|
||||
{
|
||||
|
@ -395,8 +393,7 @@ static DWORD INSTR_inport( WORD port, int size, CONTEXT86 *context )
|
|||
*/
|
||||
static void INSTR_outport( WORD port, int size, DWORD val, CONTEXT86 *context )
|
||||
{
|
||||
if (!winedos.outport) load_winedos();
|
||||
if (winedos.outport) winedos.outport( port, size, val );
|
||||
DOSVM_outport( port, size, val );
|
||||
|
||||
if (TRACE_ON(io))
|
||||
{
|
||||
|
@ -761,13 +758,9 @@ DWORD __wine_emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT86 *context )
|
|||
break; /* Unable to emulate it */
|
||||
|
||||
case 0xcd: /* int <XX> */
|
||||
if (!winedos.EmulateInterruptPM) load_winedos();
|
||||
if (winedos.EmulateInterruptPM)
|
||||
{
|
||||
context->Eip += prefixlen + 2;
|
||||
if (winedos.EmulateInterruptPM( context, instr[1] )) return ExceptionContinueExecution;
|
||||
context->Eip -= prefixlen + 2; /* restore eip */
|
||||
}
|
||||
context->Eip += prefixlen + 2;
|
||||
if (DOSVM_EmulateInterruptPM( context, instr[1] )) return ExceptionContinueExecution;
|
||||
context->Eip -= prefixlen + 2; /* restore eip */
|
||||
break; /* Unable to emulate it */
|
||||
|
||||
case 0xcf: /* iret */
|
||||
|
@ -884,22 +877,12 @@ LONG CALLBACK INSTR_vectored_handler( EXCEPTION_POINTERS *ptrs )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* INSTR_CallBuiltinHandler
|
||||
*/
|
||||
static void INSTR_CallBuiltinHandler( CONTEXT86 *context, BYTE intnum )
|
||||
{
|
||||
if (!winedos.CallBuiltinHandler) load_winedos();
|
||||
if (winedos.CallBuiltinHandler) winedos.CallBuiltinHandler( context, intnum );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DOS3Call (KERNEL.102)
|
||||
*/
|
||||
void WINAPI DOS3Call( CONTEXT86 *context )
|
||||
{
|
||||
INSTR_CallBuiltinHandler( context, 0x21 );
|
||||
__wine_call_int_handler( context, 0x21 );
|
||||
}
|
||||
|
||||
|
||||
|
@ -908,7 +891,7 @@ void WINAPI DOS3Call( CONTEXT86 *context )
|
|||
*/
|
||||
void WINAPI NetBIOSCall16( CONTEXT86 *context )
|
||||
{
|
||||
INSTR_CallBuiltinHandler( context, 0x5c );
|
||||
__wine_call_int_handler( context, 0x5c );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -620,7 +620,7 @@ static void INT10_FillStateInformation( BYTE *buffer, BIOSDATA *data )
|
|||
/**********************************************************************
|
||||
* INT10_GetHeap
|
||||
*/
|
||||
INT10_HEAP *INT10_GetHeap( void )
|
||||
static INT10_HEAP *INT10_GetHeap( void )
|
||||
{
|
||||
static INT10_HEAP *heap_pointer = 0;
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
#include "winreg.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/winbase16.h"
|
||||
#include "kernel16_private.h"
|
||||
#include "dosexe.h"
|
||||
#include "winerror.h"
|
||||
#include "winuser.h"
|
|
@ -63,58 +63,6 @@ typedef struct
|
|||
static void do_int2f_16( CONTEXT86 *context );
|
||||
static void MSCDEX_Handler( CONTEXT86 *context );
|
||||
|
||||
/***********************************************************************
|
||||
* GetVersion (KERNEL.3)
|
||||
*
|
||||
* FIXME: Duplicated from kernel since it's a 16-bit function.
|
||||
*/
|
||||
DWORD WINAPI GetVersion16(void)
|
||||
{
|
||||
static WORD dosver, winver;
|
||||
|
||||
if (!dosver) /* not determined yet */
|
||||
{
|
||||
RTL_OSVERSIONINFOEXW info;
|
||||
|
||||
info.dwOSVersionInfoSize = sizeof(info);
|
||||
if (RtlGetVersion( &info )) return 0;
|
||||
|
||||
if (info.dwMajorVersion <= 3)
|
||||
winver = MAKEWORD( info.dwMajorVersion, info.dwMinorVersion );
|
||||
else
|
||||
winver = MAKEWORD( 3, 95 );
|
||||
|
||||
switch(info.dwPlatformId)
|
||||
{
|
||||
case VER_PLATFORM_WIN32s:
|
||||
switch(MAKELONG( info.dwMinorVersion, info.dwMajorVersion ))
|
||||
{
|
||||
case 0x0200:
|
||||
dosver = 0x0303; /* DOS 3.3 for Windows 2.0 */
|
||||
break;
|
||||
case 0x0300:
|
||||
dosver = 0x0500; /* DOS 5.0 for Windows 3.0 */
|
||||
break;
|
||||
default:
|
||||
dosver = 0x0616; /* DOS 6.22 for Windows 3.1 and later */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VER_PLATFORM_WIN32_WINDOWS:
|
||||
/* DOS 8.0 for WinME, 7.0 for Win95/98 */
|
||||
if (info.dwMinorVersion >= 90) dosver = 0x0800;
|
||||
else dosver = 0x0700;
|
||||
break;
|
||||
case VER_PLATFORM_WIN32_NT:
|
||||
dosver = 0x0500; /* always DOS 5.0 for NT */
|
||||
break;
|
||||
}
|
||||
TRACE( "DOS %d.%02d Win %d.%02d\n",
|
||||
HIBYTE(dosver), LOBYTE(dosver), LOBYTE(winver), HIBYTE(winver) );
|
||||
}
|
||||
return MAKELONG( winver, dosver );
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* DOSVM_Int2fHandler
|
||||
*
|
|
@ -28,6 +28,7 @@
|
|||
#include "winternl.h"
|
||||
#include "wine/winbase16.h"
|
||||
#include "wownt32.h"
|
||||
#include "kernel16_private.h"
|
||||
#include "dosexe.h"
|
||||
|
||||
#include "excpt.h"
|
||||
|
@ -125,7 +126,6 @@ static WORD alloc_pm_selector( WORD seg, unsigned char flags )
|
|||
*/
|
||||
static LONG WINAPI dpmi_exception_handler(EXCEPTION_POINTERS *eptr)
|
||||
{
|
||||
#ifdef __i386__
|
||||
EXCEPTION_RECORD *rec = eptr->ExceptionRecord;
|
||||
CONTEXT *context = eptr->ContextRecord;
|
||||
|
||||
|
@ -144,7 +144,6 @@ static LONG WINAPI dpmi_exception_handler(EXCEPTION_POINTERS *eptr)
|
|||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
#endif
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
|
@ -298,8 +297,6 @@ static LPVOID DPMI_xrealloc( LPVOID ptr, DWORD newsize )
|
|||
}
|
||||
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
void DPMI_CallRMCB32(RMCB *rmcb, UINT16 ss, DWORD esp, UINT16*es, DWORD*edi)
|
||||
#if 0 /* original code, which early gccs puke on */
|
||||
{
|
||||
|
@ -368,8 +365,6 @@ __ASM_GLOBAL_FUNC(DPMI_CallRMCB32,
|
|||
"ret")
|
||||
#endif
|
||||
|
||||
#endif /* __i386__ */
|
||||
|
||||
/**********************************************************************
|
||||
* DPMI_CallRMCBProc
|
||||
*
|
||||
|
@ -386,7 +381,6 @@ static void DPMI_CallRMCBProc( CONTEXT86 *context, RMCB *rmcb, WORD flag )
|
|||
/* Wine-internal RMCB, call directly */
|
||||
((RMCBPROC)rmcb->proc_ofs)(context);
|
||||
} else __TRY {
|
||||
#ifdef __i386__
|
||||
UINT16 ss,es;
|
||||
DWORD esp,edi;
|
||||
|
||||
|
@ -422,11 +416,8 @@ static void DPMI_CallRMCBProc( CONTEXT86 *context, RMCB *rmcb, WORD flag )
|
|||
}
|
||||
wine_ldt_free_entries( ss, 1 );
|
||||
INT_GetRealModeContext( MapSL( MAKESEGPTR( es, edi )), context);
|
||||
#else
|
||||
ERR("RMCBs only implemented for i386\n");
|
||||
#endif
|
||||
} __EXCEPT(dpmi_exception_handler) { } __ENDTRY
|
||||
|
||||
|
||||
/* Restore virtual interrupt flag. */
|
||||
get_vm86_teb_info()->dpmi_vif = old_vif;
|
||||
}
|
|
@ -22,10 +22,11 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "wine/winbase16.h"
|
||||
#include "kernel16_private.h"
|
||||
#include "dosexe.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/winbase16.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(int);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
||||
|
@ -258,7 +259,7 @@ static void DOSVM_PushFlags( CONTEXT86 *context, BOOL islong, BOOL isstub )
|
|||
* Pushes interrupt frame to stack and changes instruction
|
||||
* pointer to interrupt handler.
|
||||
*/
|
||||
BOOL WINAPI DOSVM_EmulateInterruptPM( CONTEXT86 *context, BYTE intnum )
|
||||
BOOL DOSVM_EmulateInterruptPM( CONTEXT86 *context, BYTE intnum )
|
||||
{
|
||||
TRACE_(relay)("Call DOS int 0x%02x ret=%04x:%08x\n"
|
||||
" eax=%08x ebx=%08x ecx=%08x edx=%08x\n"
|
||||
|
@ -270,6 +271,8 @@ BOOL WINAPI DOSVM_EmulateInterruptPM( CONTEXT86 *context, BYTE intnum )
|
|||
context->SegDs, context->SegEs, context->SegFs, context->SegGs,
|
||||
context->SegSs, context->EFlags );
|
||||
|
||||
DOSMEM_InitDosMemory();
|
||||
|
||||
if (context->SegCs == DOSVM_dpmi_segments->dpmi_sel)
|
||||
{
|
||||
DOSVM_BuildCallFrame( context,
|
||||
|
@ -700,7 +703,7 @@ void DOSVM_SetPMHandler48( BYTE intnum, FARPROC48 handler )
|
|||
*
|
||||
* Execute Wine interrupt handler procedure.
|
||||
*/
|
||||
void WINAPI DOSVM_CallBuiltinHandler( CONTEXT86 *context, BYTE intnum )
|
||||
void DOSVM_CallBuiltinHandler( CONTEXT86 *context, BYTE intnum )
|
||||
{
|
||||
/*
|
||||
* FIXME: Make all builtin interrupt calls go via this routine.
|
||||
|
@ -713,6 +716,16 @@ void WINAPI DOSVM_CallBuiltinHandler( CONTEXT86 *context, BYTE intnum )
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* __wine_call_int_handler (KERNEL.@)
|
||||
*/
|
||||
void __wine_call_int_handler( CONTEXT86 *context, BYTE intnum )
|
||||
{
|
||||
DOSMEM_InitDosMemory();
|
||||
DOSVM_CallBuiltinHandler( context, intnum );
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* DOSVM_Int11Handler
|
||||
*
|
|
@ -52,6 +52,7 @@
|
|||
#include "winnls.h"
|
||||
#include "winreg.h"
|
||||
#include "winternl.h"
|
||||
#include "kernel16_private.h"
|
||||
#include "dosexe.h"
|
||||
#include "vga.h"
|
||||
#include "wine/unicode.h"
|
||||
|
@ -734,12 +735,14 @@ static BOOL IO_pp_outp(int port, DWORD* res)
|
|||
* Note: The size argument has to be handled correctly _externally_
|
||||
* (as we always return a DWORD)
|
||||
*/
|
||||
DWORD WINAPI DOSVM_inport( int port, int size )
|
||||
DWORD DOSVM_inport( int port, int size )
|
||||
{
|
||||
DWORD res = ~0U;
|
||||
|
||||
TRACE("%d-byte value from port 0x%04x\n", size, port );
|
||||
|
||||
DOSMEM_InitDosMemory();
|
||||
|
||||
#ifdef HAVE_PPDEV
|
||||
if (do_pp_port_access == -1) do_pp_port_access =IO_pp_init();
|
||||
if ((do_pp_port_access == 0 ) && (size == 1))
|
||||
|
@ -929,10 +932,12 @@ DWORD WINAPI DOSVM_inport( int port, int size )
|
|||
/**********************************************************************
|
||||
* DOSVM_outport
|
||||
*/
|
||||
void WINAPI DOSVM_outport( int port, int size, DWORD value )
|
||||
void DOSVM_outport( int port, int size, DWORD value )
|
||||
{
|
||||
TRACE("IO: 0x%x (%d-byte value) to port 0x%04x\n", value, size, port );
|
||||
|
||||
DOSMEM_InitDosMemory();
|
||||
|
||||
#ifdef HAVE_PPDEV
|
||||
if (do_pp_port_access == -1) do_pp_port_access = IO_pp_init();
|
||||
if ((do_pp_port_access == 0) && (size == 1))
|
|
@ -190,10 +190,15 @@ static inline void stack16_pop( int size )
|
|||
|
||||
/* dosmem.c */
|
||||
extern BOOL DOSMEM_Init(void);
|
||||
extern BOOL DOSMEM_InitDosMemory(void);
|
||||
extern LPVOID DOSMEM_MapRealToLinear(DWORD); /* real-mode to linear */
|
||||
extern LPVOID DOSMEM_MapDosToLinear(UINT); /* linear DOS to Wine */
|
||||
extern UINT DOSMEM_MapLinearToDos(LPVOID); /* linear Wine to DOS */
|
||||
extern BOOL load_winedos(void);
|
||||
extern BOOL DOSMEM_MapDosLayout(void);
|
||||
extern LPVOID DOSMEM_AllocBlock(UINT size, WORD* p);
|
||||
extern BOOL DOSMEM_FreeBlock(void* ptr);
|
||||
extern UINT DOSMEM_ResizeBlock(void* ptr, UINT size, BOOL exact);
|
||||
extern UINT DOSMEM_Available(void);
|
||||
|
||||
/* global16.c */
|
||||
extern HGLOBAL16 GLOBAL_CreateBlock( UINT16 flags, void *ptr, DWORD size,
|
||||
|
@ -253,19 +258,6 @@ extern void TASK_InstallTHHook( THHOOK *pNewThook );
|
|||
|
||||
extern BOOL WOWTHUNK_Init(void);
|
||||
|
||||
extern struct winedos_exports
|
||||
{
|
||||
/* for global16.c */
|
||||
void* (*AllocDosBlock)(UINT size, UINT16* pseg);
|
||||
BOOL (*FreeDosBlock)(void* ptr);
|
||||
UINT (*ResizeDosBlock)(void *ptr, UINT size, BOOL exact);
|
||||
/* for instr.c */
|
||||
BOOL (WINAPI *EmulateInterruptPM)( CONTEXT86 *context, BYTE intnum );
|
||||
void (WINAPI *CallBuiltinHandler)( CONTEXT86 *context, BYTE intnum );
|
||||
DWORD (WINAPI *inport)( int port, int size );
|
||||
void (WINAPI *outport)( int port, int size, DWORD val );
|
||||
} winedos;
|
||||
|
||||
extern WORD DOSMEM_0000H;
|
||||
extern WORD DOSMEM_BiosDataSeg;
|
||||
extern WORD DOSMEM_BiosSysSeg;
|
||||
|
@ -298,43 +290,4 @@ static inline struct kernel_thread_data *kernel_get_thread_data(void)
|
|||
"call " __ASM_NAME("__wine_call_from_32_regs") "\n\t" \
|
||||
"ret $(4*" #args ")" ) /* fake ret to make copy protections happy */
|
||||
|
||||
#define AX_reg(context) ((WORD)(context)->Eax)
|
||||
#define BX_reg(context) ((WORD)(context)->Ebx)
|
||||
#define CX_reg(context) ((WORD)(context)->Ecx)
|
||||
#define DX_reg(context) ((WORD)(context)->Edx)
|
||||
#define SI_reg(context) ((WORD)(context)->Esi)
|
||||
#define DI_reg(context) ((WORD)(context)->Edi)
|
||||
|
||||
#define AL_reg(context) ((BYTE)(context)->Eax)
|
||||
#define AH_reg(context) ((BYTE)((context)->Eax >> 8))
|
||||
#define BL_reg(context) ((BYTE)(context)->Ebx)
|
||||
#define BH_reg(context) ((BYTE)((context)->Ebx >> 8))
|
||||
#define CL_reg(context) ((BYTE)(context)->Ecx)
|
||||
#define CH_reg(context) ((BYTE)((context)->Ecx >> 8))
|
||||
#define DL_reg(context) ((BYTE)(context)->Edx)
|
||||
#define DH_reg(context) ((BYTE)((context)->Edx >> 8))
|
||||
|
||||
#define SET_CFLAG(context) ((context)->EFlags |= 0x0001)
|
||||
#define RESET_CFLAG(context) ((context)->EFlags &= ~0x0001)
|
||||
#define SET_ZFLAG(context) ((context)->EFlags |= 0x0040)
|
||||
#define RESET_ZFLAG(context) ((context)->EFlags &= ~0x0040)
|
||||
#define ISV86(context) ((context)->EFlags & 0x00020000)
|
||||
|
||||
#define SET_AX(context,val) ((void)((context)->Eax = ((context)->Eax & ~0xffff) | (WORD)(val)))
|
||||
#define SET_BX(context,val) ((void)((context)->Ebx = ((context)->Ebx & ~0xffff) | (WORD)(val)))
|
||||
#define SET_CX(context,val) ((void)((context)->Ecx = ((context)->Ecx & ~0xffff) | (WORD)(val)))
|
||||
#define SET_DX(context,val) ((void)((context)->Edx = ((context)->Edx & ~0xffff) | (WORD)(val)))
|
||||
#define SET_SI(context,val) ((void)((context)->Esi = ((context)->Esi & ~0xffff) | (WORD)(val)))
|
||||
#define SET_DI(context,val) ((void)((context)->Edi = ((context)->Edi & ~0xffff) | (WORD)(val)))
|
||||
|
||||
#define SET_AL(context,val) ((void)((context)->Eax = ((context)->Eax & ~0xff) | (BYTE)(val)))
|
||||
#define SET_BL(context,val) ((void)((context)->Ebx = ((context)->Ebx & ~0xff) | (BYTE)(val)))
|
||||
#define SET_CL(context,val) ((void)((context)->Ecx = ((context)->Ecx & ~0xff) | (BYTE)(val)))
|
||||
#define SET_DL(context,val) ((void)((context)->Edx = ((context)->Edx & ~0xff) | (BYTE)(val)))
|
||||
|
||||
#define SET_AH(context,val) ((void)((context)->Eax = ((context)->Eax & ~0xff00) | (((BYTE)(val)) << 8)))
|
||||
#define SET_BH(context,val) ((void)((context)->Ebx = ((context)->Ebx & ~0xff00) | (((BYTE)(val)) << 8)))
|
||||
#define SET_CH(context,val) ((void)((context)->Ecx = ((context)->Ecx & ~0xff00) | (((BYTE)(val)) << 8)))
|
||||
#define SET_DH(context,val) ((void)((context)->Edx = ((context)->Edx & ~0xff00) | (((BYTE)(val)) << 8)))
|
||||
|
||||
#endif /* __WINE_KERNEL16_PRIVATE_H */
|
||||
|
|
|
@ -743,6 +743,10 @@
|
|||
# All functions must be prefixed with '__wine_' (for internal functions)
|
||||
# or 'wine_' (for user-visible functions) to avoid namespace conflicts.
|
||||
|
||||
# DOS support
|
||||
@ cdecl -arch=win32 __wine_call_int_handler(ptr long)
|
||||
@ cdecl -arch=win32 __wine_load_dos_exe(str str)
|
||||
|
||||
# VxDs
|
||||
@ cdecl -arch=win32 -private __wine_vxd_open(wstr long ptr)
|
||||
@ cdecl -arch=win32 -private __wine_vxd_get_proc(long)
|
||||
|
|
|
@ -1072,6 +1072,7 @@ static HINSTANCE16 MODULE_LoadModule16( LPCSTR libname, BOOL implicit, BOOL lib_
|
|||
NE_InitializeDLLs(hModule);
|
||||
NE_DllProcessAttach(hModule);
|
||||
}
|
||||
else DOSMEM_InitDosMemory(); /* we will be running a 16-bit task, setup DOS memory */
|
||||
}
|
||||
return hinst; /* The last error that occurred */
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright 1993 Robert J. Amstadt
|
||||
* Copyright 1995 Alexandre Julliard
|
||||
* Copyright 2002 Jukka Heinonen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -20,8 +21,6 @@
|
|||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -33,12 +32,33 @@
|
|||
#include "wine/winbase16.h"
|
||||
#include "winternl.h"
|
||||
#include "kernel16_private.h"
|
||||
#include "dosexe.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "wine/library.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(relay);
|
||||
|
||||
/*
|
||||
* Magic DWORD used to check stack integrity.
|
||||
*/
|
||||
#define RELAY_MAGIC 0xabcdef00
|
||||
|
||||
/*
|
||||
* Memory block for temporary 16-bit stacks used with relay calls.
|
||||
*/
|
||||
typedef struct {
|
||||
DWORD inuse; /* non-zero if stack block is in use */
|
||||
DWORD eip; /* saved ip */
|
||||
DWORD seg_cs; /* saved cs */
|
||||
DWORD esp; /* saved sp */
|
||||
DWORD seg_ss; /* saved ss */
|
||||
DWORD stack_bottom; /* guard dword */
|
||||
BYTE stack[256-7*4]; /* 16-bit stack */
|
||||
DWORD stack_top; /* guard dword */
|
||||
} RELAY_Stack16;
|
||||
|
||||
|
||||
static const WCHAR **debug_relay_excludelist;
|
||||
static const WCHAR **debug_relay_includelist;
|
||||
static const WCHAR **debug_snoop_excludelist;
|
||||
|
@ -577,4 +597,154 @@ int relay_call_from_16( void *entry_point, unsigned char *args16, CONTEXT86 *con
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
#endif /* __i386__ */
|
||||
/**********************************************************************
|
||||
* RELAY_GetPointer
|
||||
*
|
||||
* Get pointer to stack block when given esp pointing to 16-bit stack
|
||||
* inside relay data segment.
|
||||
*/
|
||||
static RELAY_Stack16 *RELAY_GetPointer( DWORD offset )
|
||||
{
|
||||
offset = offset / sizeof(RELAY_Stack16) * sizeof(RELAY_Stack16);
|
||||
return MapSL(MAKESEGPTR(DOSVM_dpmi_segments->relay_data_sel, offset));
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RELAY_MakeShortContext
|
||||
*
|
||||
* Allocate separate 16-bit stack, make stack pointer point to this
|
||||
* stack and make code pointer point to stub that restores everything.
|
||||
* So, after this routine, SS and CS are guaranteed to be 16-bit.
|
||||
*
|
||||
* Note: This might be called from signal handler, so the stack
|
||||
* allocation algorithm must be signal safe.
|
||||
*/
|
||||
static void RELAY_MakeShortContext( CONTEXT86 *context )
|
||||
{
|
||||
DWORD offset = offsetof(RELAY_Stack16, stack_top);
|
||||
RELAY_Stack16 *stack = RELAY_GetPointer( 0 );
|
||||
|
||||
while (stack->inuse && offset < DOSVM_RELAY_DATA_SIZE) {
|
||||
stack++;
|
||||
offset += sizeof(RELAY_Stack16);
|
||||
}
|
||||
|
||||
if (offset >= DOSVM_RELAY_DATA_SIZE)
|
||||
ERR( "Too many nested interrupts!\n" );
|
||||
|
||||
stack->inuse = 1;
|
||||
stack->eip = context->Eip;
|
||||
stack->seg_cs = context->SegCs;
|
||||
stack->esp = context->Esp;
|
||||
stack->seg_ss = context->SegSs;
|
||||
|
||||
stack->stack_bottom = RELAY_MAGIC;
|
||||
stack->stack_top = RELAY_MAGIC;
|
||||
|
||||
context->SegSs = DOSVM_dpmi_segments->relay_data_sel;
|
||||
context->Esp = offset;
|
||||
context->SegCs = DOSVM_dpmi_segments->relay_code_sel;
|
||||
context->Eip = 3;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RELAY_RelayStub
|
||||
*
|
||||
* This stub is called by __wine_call_from_16_regs in order to marshall
|
||||
* relay parameters.
|
||||
*/
|
||||
static void __stdcall RELAY_RelayStub( DOSRELAY proc, unsigned char *args, CONTEXT86 *context )
|
||||
{
|
||||
if (proc)
|
||||
{
|
||||
RELAY_Stack16 *stack = RELAY_GetPointer( context->Esp );
|
||||
|
||||
DWORD old_seg_cs = context->SegCs;
|
||||
DWORD old_eip = context->Eip;
|
||||
DWORD old_seg_ss = context->SegSs;
|
||||
DWORD old_esp = context->Esp;
|
||||
|
||||
context->SegCs = stack->seg_cs;
|
||||
context->Eip = stack->eip;
|
||||
context->SegSs = stack->seg_ss;
|
||||
context->Esp = stack->esp;
|
||||
|
||||
proc( context, *(LPVOID *)args );
|
||||
|
||||
stack->seg_cs = context->SegCs;
|
||||
stack->eip = context->Eip;
|
||||
stack->seg_ss = context->SegSs;
|
||||
stack->esp = context->Esp;
|
||||
|
||||
context->SegCs = old_seg_cs;
|
||||
context->Eip = old_eip;
|
||||
context->SegSs = old_seg_ss;
|
||||
context->Esp = old_esp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* DOSVM_RelayHandler
|
||||
*
|
||||
* Restore saved code and stack pointers and release stack block.
|
||||
*/
|
||||
void DOSVM_RelayHandler( CONTEXT86 *context )
|
||||
{
|
||||
RELAY_Stack16 *stack = RELAY_GetPointer( context->Esp );
|
||||
|
||||
context->SegSs = stack->seg_ss;
|
||||
context->Esp = stack->esp;
|
||||
context->SegCs = stack->seg_cs;
|
||||
context->Eip = stack->eip;
|
||||
|
||||
if (!stack->inuse ||
|
||||
stack->stack_bottom != RELAY_MAGIC ||
|
||||
stack->stack_top != RELAY_MAGIC)
|
||||
ERR( "Stack corrupted!\n" );
|
||||
|
||||
stack->inuse = 0;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* DOSVM_BuildCallFrame
|
||||
*
|
||||
* Modifies the context so that return to context calls DOSRELAY and
|
||||
* only after return from DOSRELAY the original context will be returned to.
|
||||
*/
|
||||
void DOSVM_BuildCallFrame( CONTEXT86 *context, DOSRELAY relay, LPVOID data )
|
||||
{
|
||||
WORD code_sel = DOSVM_dpmi_segments->relay_code_sel;
|
||||
|
||||
/*
|
||||
* Allocate separate stack for relay call.
|
||||
*/
|
||||
RELAY_MakeShortContext( context );
|
||||
|
||||
/*
|
||||
* Build call frame.
|
||||
*/
|
||||
PUSH_WORD16( context, HIWORD(data) ); /* argument.hiword */
|
||||
PUSH_WORD16( context, LOWORD(data) ); /* argument.loword */
|
||||
PUSH_WORD16( context, context->SegCs ); /* STACK16FRAME.cs */
|
||||
PUSH_WORD16( context, LOWORD(context->Eip) ); /* STACK16FRAME.ip */
|
||||
PUSH_WORD16( context, LOWORD(context->Ebp) ); /* STACK16FRAME.bp */
|
||||
PUSH_WORD16( context, HIWORD(relay) ); /* STACK16FRAME.entry_point.hiword */
|
||||
PUSH_WORD16( context, LOWORD(relay) ); /* STACK16FRAME.entry_point.loword */
|
||||
PUSH_WORD16( context, 0 ); /* STACK16FRAME.entry_ip */
|
||||
PUSH_WORD16( context, HIWORD(RELAY_RelayStub) ); /* STACK16FRAME.relay.hiword */
|
||||
PUSH_WORD16( context, LOWORD(RELAY_RelayStub) ); /* STACK16FRAME.relay.loword */
|
||||
PUSH_WORD16( context, 0 ); /* STACK16FRAME.module_cs.hiword */
|
||||
PUSH_WORD16( context, code_sel ); /* STACK16FRAME.module_cs.loword */
|
||||
PUSH_WORD16( context, 0 ); /* STACK16FRAME.callfrom_ip.hiword */
|
||||
PUSH_WORD16( context, 0 ); /* STACK16FRAME.callfrom_ip.loword */
|
||||
|
||||
/*
|
||||
* Adjust code pointer.
|
||||
*/
|
||||
context->SegCs = wine_get_cs();
|
||||
context->Eip = (DWORD)__wine_call_from_16_regs;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "winternl.h"
|
||||
#include "winioctl.h"
|
||||
#include "kernel16_private.h"
|
||||
#include "dosexe.h"
|
||||
#include "wine/library.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "wine/server.h"
|
||||
|
|
|
@ -3,7 +3,7 @@ TOPOBJDIR = ../..
|
|||
SRCDIR = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
MODULE = vwin32.vxd
|
||||
IMPORTS = kernel32
|
||||
IMPORTS = kernel32 kernel
|
||||
|
||||
C_SRCS = \
|
||||
vwin32.c
|
||||
|
|
|
@ -55,22 +55,7 @@ typedef struct tagMID {
|
|||
} MID, *PMID;
|
||||
#include <poppack.h>
|
||||
|
||||
typedef void (WINAPI *CallBuiltinHandler)( CONTEXT *context, BYTE intnum );
|
||||
|
||||
static CallBuiltinHandler load_builtin_handler(void)
|
||||
{
|
||||
static CallBuiltinHandler handler;
|
||||
static BOOL init_done;
|
||||
|
||||
if (!init_done)
|
||||
{
|
||||
HMODULE mod = LoadLibraryA( "winedos.dll" );
|
||||
if (mod) handler = (void *)GetProcAddress( mod, "CallBuiltinHandler" );
|
||||
if (!handler) FIXME( "DOS calls not supported\n" );
|
||||
init_done = TRUE;
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
extern void __wine_call_int_handler( CONTEXT *context, BYTE intnum );
|
||||
|
||||
/* Pop a DWORD from the 32-bit stack */
|
||||
static inline DWORD stack32_pop( CONTEXT86 *context )
|
||||
|
@ -136,13 +121,6 @@ BOOL WINAPI VWIN32_DeviceIoControl(DWORD dwIoControlCode,
|
|||
DIOC_REGISTERS *pIn = lpvInBuffer;
|
||||
DIOC_REGISTERS *pOut = lpvOutBuffer;
|
||||
BYTE intnum = 0;
|
||||
CallBuiltinHandler handler;
|
||||
|
||||
if (!(handler = load_builtin_handler()))
|
||||
{
|
||||
pOut->reg_Flags |= 0x0001;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TRACE( "Control '%s': "
|
||||
"eax=0x%08x, ebx=0x%08x, ecx=0x%08x, "
|
||||
|
@ -177,7 +155,7 @@ BOOL WINAPI VWIN32_DeviceIoControl(DWORD dwIoControlCode,
|
|||
break;
|
||||
}
|
||||
|
||||
handler( &cxt, intnum );
|
||||
__wine_call_int_handler( &cxt, intnum );
|
||||
CONTEXT_2_DIOCRegs( &cxt, pOut );
|
||||
}
|
||||
return TRUE;
|
||||
|
@ -225,19 +203,12 @@ DWORD WINAPI VWIN32_VxDCall( DWORD service, CONTEXT86 *context )
|
|||
{
|
||||
DWORD callnum = stack32_pop(context);
|
||||
DWORD parm = stack32_pop(context);
|
||||
CallBuiltinHandler handler;
|
||||
|
||||
TRACE("Int31/DPMI dispatch(%08x)\n", callnum);
|
||||
|
||||
if (!(handler = load_builtin_handler()))
|
||||
{
|
||||
context->EFlags |= 0x0001;
|
||||
return 0;
|
||||
}
|
||||
|
||||
context->Eax = callnum;
|
||||
context->Ecx = parm;
|
||||
handler( context, 0x31 );
|
||||
__wine_call_int_handler( context, 0x31 );
|
||||
return LOWORD(context->Eax);
|
||||
}
|
||||
case 0x002a: /* Int41 dispatch - parm = int41 service number */
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
TOPSRCDIR = @top_srcdir@
|
||||
TOPOBJDIR = ../..
|
||||
SRCDIR = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
MODULE = winedos.dll
|
||||
IMPORTS = user32 kernel32 kernel ntdll
|
||||
DELAYIMPORTS = ddraw dsound
|
||||
|
||||
C_SRCS = \
|
||||
devices.c \
|
||||
dma.c \
|
||||
dosaspi.c \
|
||||
dosconf.c \
|
||||
dosmem.c \
|
||||
dosvm.c \
|
||||
fpu.c \
|
||||
int09.c \
|
||||
int10.c \
|
||||
int13.c \
|
||||
int15.c \
|
||||
int16.c \
|
||||
int21.c \
|
||||
int25.c \
|
||||
int26.c \
|
||||
int2f.c \
|
||||
int31.c \
|
||||
int33.c \
|
||||
int67.c \
|
||||
interrupts.c \
|
||||
ioports.c \
|
||||
module.c \
|
||||
relay.c \
|
||||
soundblaster.c \
|
||||
timer.c \
|
||||
vga.c
|
||||
|
||||
@MAKE_DLL_RULES@
|
||||
|
||||
@DEPENDENCIES@ # everything below this line is overwritten by make depend
|
|
@ -1,551 +0,0 @@
|
|||
/*
|
||||
* DOS memory emulation
|
||||
*
|
||||
* Copyright 1995 Alexandre Julliard
|
||||
* Copyright 1996 Marcus Meissner
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winreg.h"
|
||||
#include "excpt.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/winbase16.h"
|
||||
|
||||
#include "dosexe.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dosmem);
|
||||
|
||||
/* DOS memory highest address (including HMA) */
|
||||
#define DOSMEM_SIZE 0x110000
|
||||
#define DOSMEM_64KB 0x10000
|
||||
|
||||
/* see dlls/kernel/dosmem.c for the details */
|
||||
static char *DOSMEM_dosmem;
|
||||
static char *DOSMEM_sysmem;
|
||||
|
||||
/*
|
||||
* Memory Control Block (MCB) definition
|
||||
* FIXME: implement Allocation Strategy
|
||||
*/
|
||||
|
||||
#define MCB_DUMP(mc) \
|
||||
TRACE ("MCB_DUMP base=%p type=%02xh psp=%04xh size=%04xh\n", mc, mc->type, mc->psp , mc->size )
|
||||
|
||||
#define MCB_NEXT(mc) \
|
||||
(MCB*) ((mc->type==MCB_TYPE_LAST) ? NULL : (char*)(mc) + ((mc->size + 1) << 4) )
|
||||
|
||||
/* FIXME: should we check more? */
|
||||
#define MCB_VALID(mc) \
|
||||
((mc->type==MCB_TYPE_NORMAL) || (mc->type==MCB_TYPE_LAST))
|
||||
|
||||
|
||||
#define MCB_TYPE_NORMAL 0x4d
|
||||
#define MCB_TYPE_LAST 0x5a
|
||||
|
||||
#define MCB_PSP_DOS 0x0060
|
||||
#define MCB_PSP_FREE 0
|
||||
|
||||
#include "pshpack1.h"
|
||||
typedef struct {
|
||||
BYTE type;
|
||||
WORD psp; /* segment of owner psp */
|
||||
WORD size; /* in paragraphs */
|
||||
BYTE pad[3];
|
||||
BYTE name[8];
|
||||
} MCB;
|
||||
#include "poppack.h"
|
||||
|
||||
/*
|
||||
#define __DOSMEM_DEBUG__
|
||||
*/
|
||||
|
||||
#define VM_STUB(x) (0x90CF00CD|(x<<8)) /* INT x; IRET; NOP */
|
||||
#define VM_STUB_SEGMENT 0xf000 /* BIOS segment */
|
||||
|
||||
/* FIXME: this should be moved to the LOL */
|
||||
static MCB* DOSMEM_root_block;
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_MemoryTop
|
||||
*
|
||||
* Gets the DOS memory top.
|
||||
*/
|
||||
static char *DOSMEM_MemoryTop(void)
|
||||
{
|
||||
return DOSMEM_dosmem+0x9FFFC; /* 640K */
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_FillIsrTable
|
||||
*
|
||||
* Fill the interrupt table with fake BIOS calls to BIOSSEG (0xf000).
|
||||
*
|
||||
* NOTES:
|
||||
* Linux normally only traps INTs performed from or destined to BIOSSEG
|
||||
* for us to handle, if the int_revectored table is empty. Filling the
|
||||
* interrupt table with calls to INT stubs in BIOSSEG allows DOS programs
|
||||
* to hook interrupts, as well as use their familiar retf tricks to call
|
||||
* them, AND let Wine handle any unhooked interrupts transparently.
|
||||
*/
|
||||
static void DOSMEM_FillIsrTable(void)
|
||||
{
|
||||
SEGPTR *isr = (SEGPTR*)DOSMEM_sysmem;
|
||||
int x;
|
||||
|
||||
for (x=0; x<256; x++) isr[x]=MAKESEGPTR(VM_STUB_SEGMENT,x*4);
|
||||
}
|
||||
|
||||
static void DOSMEM_MakeIsrStubs(void)
|
||||
{
|
||||
DWORD *stub = (DWORD*)(DOSMEM_dosmem + (VM_STUB_SEGMENT << 4));
|
||||
int x;
|
||||
|
||||
for (x=0; x<256; x++) stub[x]=VM_STUB(x);
|
||||
}
|
||||
|
||||
BIOSDATA* DOSVM_BiosData(void)
|
||||
{
|
||||
return (BIOSDATA *)(DOSMEM_sysmem + 0x400);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* DOSMEM_GetTicksSinceMidnight
|
||||
*
|
||||
* Return number of clock ticks since midnight.
|
||||
*/
|
||||
static DWORD DOSMEM_GetTicksSinceMidnight(void)
|
||||
{
|
||||
SYSTEMTIME time;
|
||||
|
||||
/* This should give us the (approximately) correct
|
||||
* 18.206 clock ticks per second since midnight.
|
||||
*/
|
||||
|
||||
GetLocalTime( &time );
|
||||
|
||||
return (((time.wHour * 3600 + time.wMinute * 60 +
|
||||
time.wSecond) * 18206) / 1000) +
|
||||
(time.wMilliseconds * 1000 / 54927);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_FillBiosSegments
|
||||
*
|
||||
* Fill the BIOS data segment with dummy values.
|
||||
*/
|
||||
static void DOSMEM_FillBiosSegments(void)
|
||||
{
|
||||
BYTE *pBiosSys = (BYTE*)DOSMEM_dosmem + 0xf0000;
|
||||
BYTE *pBiosROMTable = pBiosSys+0xe6f5;
|
||||
BIOSDATA *pBiosData = DOSVM_BiosData();
|
||||
static const char bios_date[] = "13/01/99";
|
||||
|
||||
/* Clear all unused values */
|
||||
memset( pBiosData, 0, sizeof(*pBiosData) );
|
||||
|
||||
/* FIXME: should check the number of configured drives and ports */
|
||||
pBiosData->Com1Addr = 0x3f8;
|
||||
pBiosData->Com2Addr = 0x2f8;
|
||||
pBiosData->Lpt1Addr = 0x378;
|
||||
pBiosData->Lpt2Addr = 0x278;
|
||||
pBiosData->InstalledHardware = 0x5463;
|
||||
pBiosData->MemSize = 640;
|
||||
pBiosData->NextKbdCharPtr = 0x1e;
|
||||
pBiosData->FirstKbdCharPtr = 0x1e;
|
||||
pBiosData->VideoMode = 3;
|
||||
pBiosData->VideoColumns = 80;
|
||||
pBiosData->VideoPageSize = 80 * 25 * 2;
|
||||
pBiosData->VideoPageStartAddr = 0xb800;
|
||||
pBiosData->VideoCtrlAddr = 0x3d4;
|
||||
pBiosData->Ticks = DOSMEM_GetTicksSinceMidnight();
|
||||
pBiosData->NbHardDisks = 2;
|
||||
pBiosData->KbdBufferStart = 0x1e;
|
||||
pBiosData->KbdBufferEnd = 0x3e;
|
||||
pBiosData->RowsOnScreenMinus1 = 24;
|
||||
pBiosData->BytesPerChar = 0x10;
|
||||
pBiosData->ModeOptions = 0x64;
|
||||
pBiosData->FeatureBitsSwitches = 0xf9;
|
||||
pBiosData->VGASettings = 0x51;
|
||||
pBiosData->DisplayCombination = 0x08;
|
||||
pBiosData->DiskDataRate = 0;
|
||||
|
||||
/* fill ROM configuration table (values from Award) */
|
||||
*(pBiosROMTable+0x0) = 0x08; /* number of bytes following LO */
|
||||
*(pBiosROMTable+0x1) = 0x00; /* number of bytes following HI */
|
||||
*(pBiosROMTable+0x2) = 0xfc; /* model */
|
||||
*(pBiosROMTable+0x3) = 0x01; /* submodel */
|
||||
*(pBiosROMTable+0x4) = 0x00; /* BIOS revision */
|
||||
*(pBiosROMTable+0x5) = 0x74; /* feature byte 1 */
|
||||
*(pBiosROMTable+0x6) = 0x00; /* feature byte 2 */
|
||||
*(pBiosROMTable+0x7) = 0x00; /* feature byte 3 */
|
||||
*(pBiosROMTable+0x8) = 0x00; /* feature byte 4 */
|
||||
*(pBiosROMTable+0x9) = 0x00; /* feature byte 5 */
|
||||
|
||||
/* BIOS date string */
|
||||
memcpy(pBiosSys+0xfff5, bios_date, sizeof bios_date);
|
||||
|
||||
/* BIOS ID */
|
||||
*(pBiosSys+0xfffe) = 0xfc;
|
||||
|
||||
/* Reboot vector (f000:fff0 or ffff:0000) */
|
||||
*(DWORD*)(pBiosSys + 0xfff0) = VM_STUB(0x19);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* BiosTick
|
||||
*
|
||||
* Increment the BIOS tick counter. Called by timer signal handler.
|
||||
*/
|
||||
static void CALLBACK BiosTick( LPVOID arg, DWORD low, DWORD high )
|
||||
{
|
||||
BIOSDATA *pBiosData = arg;
|
||||
pBiosData->Ticks++;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* timer_thread
|
||||
*/
|
||||
static DWORD CALLBACK timer_thread( void *arg )
|
||||
{
|
||||
LARGE_INTEGER when;
|
||||
HANDLE timer;
|
||||
|
||||
if (!(timer = CreateWaitableTimerA( NULL, FALSE, NULL ))) return 0;
|
||||
|
||||
when.u.LowPart = when.u.HighPart = 0;
|
||||
SetWaitableTimer( timer, &when, 55 /* actually 54.925 */, BiosTick, arg, FALSE );
|
||||
for (;;) SleepEx( INFINITE, TRUE );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_Collapse
|
||||
*
|
||||
* Helper function for internal use only.
|
||||
* Attach all following free blocks to this one, even if this one is not free.
|
||||
*/
|
||||
static void DOSMEM_Collapse( MCB* mcb )
|
||||
{
|
||||
MCB* next = MCB_NEXT( mcb );
|
||||
|
||||
while (next && next->psp == MCB_PSP_FREE)
|
||||
{
|
||||
mcb->size = mcb->size + next->size + 1;
|
||||
mcb->type = next->type; /* make sure keeping MCB_TYPE_LAST */
|
||||
next = MCB_NEXT( next );
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_AllocBlock
|
||||
*
|
||||
* Carve a chunk of the DOS memory block (without selector).
|
||||
*/
|
||||
LPVOID DOSMEM_AllocBlock(UINT size, UINT16* pseg)
|
||||
{
|
||||
MCB *curr = DOSMEM_root_block;
|
||||
MCB *next = NULL;
|
||||
WORD psp = DOSVM_psp;
|
||||
|
||||
if (!psp)
|
||||
psp = MCB_PSP_DOS;
|
||||
|
||||
*pseg = 0;
|
||||
|
||||
TRACE( "(%04xh)\n", size );
|
||||
|
||||
/* round up to paragraph */
|
||||
size = (size + 15) >> 4;
|
||||
|
||||
#ifdef __DOSMEM_DEBUG__
|
||||
DOSMEM_Available(); /* checks the whole MCB list */
|
||||
#endif
|
||||
|
||||
/* loop over all MCB and search the next large enough MCB */
|
||||
while (curr)
|
||||
{
|
||||
if (!MCB_VALID (curr))
|
||||
{
|
||||
ERR( "MCB List Corrupt\n" );
|
||||
MCB_DUMP( curr );
|
||||
return NULL;
|
||||
}
|
||||
if (curr->psp == MCB_PSP_FREE)
|
||||
{
|
||||
DOSMEM_Collapse( curr );
|
||||
/* is it large enough (one paragraph for the MCB)? */
|
||||
if (curr->size >= size)
|
||||
{
|
||||
if (curr->size > size)
|
||||
{
|
||||
/* split curr */
|
||||
next = (MCB *) ((char*) curr + ((size+1) << 4));
|
||||
next->psp = MCB_PSP_FREE;
|
||||
next->size = curr->size - (size+1);
|
||||
next->type = curr->type;
|
||||
curr->type = MCB_TYPE_NORMAL;
|
||||
curr->size = size;
|
||||
}
|
||||
/* curr is the found block */
|
||||
curr->psp = psp;
|
||||
if( pseg ) *pseg = (((char*)curr) + 16 - DOSMEM_dosmem) >> 4;
|
||||
return (LPVOID) ((char*)curr + 16);
|
||||
}
|
||||
}
|
||||
curr = MCB_NEXT(curr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_FreeBlock
|
||||
*/
|
||||
BOOL DOSMEM_FreeBlock(void* ptr)
|
||||
{
|
||||
MCB* mcb = (MCB*) ((char*)ptr - 16);
|
||||
|
||||
TRACE( "(%p)\n", ptr );
|
||||
|
||||
#ifdef __DOSMEM_DEBUG__
|
||||
DOSMEM_Available();
|
||||
#endif
|
||||
|
||||
if (!MCB_VALID (mcb))
|
||||
{
|
||||
ERR( "MCB invalid\n" );
|
||||
MCB_DUMP( mcb );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mcb->psp = MCB_PSP_FREE;
|
||||
DOSMEM_Collapse( mcb );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_ResizeBlock
|
||||
*
|
||||
* Resize DOS memory block in place. Returns block size or -1 on error.
|
||||
*
|
||||
* If exact is TRUE, returned value is either old or requested block
|
||||
* size. If exact is FALSE, block is expanded even if there is not
|
||||
* enough space for full requested block size.
|
||||
*
|
||||
* TODO: return also biggest block size
|
||||
*/
|
||||
UINT DOSMEM_ResizeBlock(void *ptr, UINT size, BOOL exact)
|
||||
{
|
||||
MCB* mcb = (MCB*) ((char*)ptr - 16);
|
||||
MCB* next;
|
||||
|
||||
TRACE( "(%p,%04xh,%s)\n", ptr, size, exact ? "TRUE" : "FALSE" );
|
||||
|
||||
/* round up to paragraph */
|
||||
size = (size + 15) >> 4;
|
||||
|
||||
#ifdef __DOSMEM_DEBUG__
|
||||
DOSMEM_Available();
|
||||
#endif
|
||||
|
||||
if (!MCB_VALID (mcb))
|
||||
{
|
||||
ERR( "MCB invalid\n" );
|
||||
MCB_DUMP( mcb );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* resize needed? */
|
||||
if (mcb->size == size)
|
||||
return size << 4;
|
||||
|
||||
/* collapse free blocks */
|
||||
DOSMEM_Collapse( mcb );
|
||||
|
||||
/* shrink mcb ? */
|
||||
if (mcb->size > size)
|
||||
{
|
||||
next = (MCB *) ((char*)mcb + ((size+1) << 4));
|
||||
next->type = mcb->type;
|
||||
next->psp = MCB_PSP_FREE;
|
||||
next->size = mcb->size - (size+1);
|
||||
mcb->type = MCB_TYPE_NORMAL;
|
||||
mcb->size = size;
|
||||
return size << 4;
|
||||
}
|
||||
|
||||
if (!exact)
|
||||
{
|
||||
return mcb->size << 4;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_Available
|
||||
*/
|
||||
UINT DOSMEM_Available(void)
|
||||
{
|
||||
UINT available = 0;
|
||||
UINT total = 0;
|
||||
MCB *curr = DOSMEM_root_block;
|
||||
/* loop over all MCB and search the largest free MCB */
|
||||
while (curr)
|
||||
{
|
||||
#ifdef __DOSMEM_DEBUG__
|
||||
MCB_DUMP( curr );
|
||||
#endif
|
||||
if (!MCB_VALID (curr))
|
||||
{
|
||||
ERR( "MCB List Corrupt\n" );
|
||||
MCB_DUMP( curr );
|
||||
return 0;
|
||||
}
|
||||
if (curr->psp == MCB_PSP_FREE &&
|
||||
curr->size > available )
|
||||
available = curr->size;
|
||||
|
||||
total += curr->size + 1;
|
||||
curr = MCB_NEXT( curr );
|
||||
}
|
||||
TRACE( " %04xh of %04xh paragraphs available\n", available, total );
|
||||
return available << 4;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DOSMEM_InitMemory
|
||||
*
|
||||
* Initialises the DOS memory structures.
|
||||
*/
|
||||
static void DOSMEM_InitMemory(char* addr)
|
||||
{
|
||||
DOSMEM_FillBiosSegments();
|
||||
DOSMEM_FillIsrTable();
|
||||
|
||||
/* align root block to paragraph */
|
||||
DOSMEM_root_block = (MCB*) (( (DWORD_PTR)(addr+0xf) >> 4) << 4);
|
||||
DOSMEM_root_block->type = MCB_TYPE_LAST;
|
||||
DOSMEM_root_block->psp = MCB_PSP_FREE;
|
||||
DOSMEM_root_block->size = (DOSMEM_MemoryTop() - ((char*)DOSMEM_root_block)) >> 4;
|
||||
|
||||
TRACE("DOS conventional memory initialized, %d bytes free.\n",
|
||||
DOSMEM_Available());
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* DOSMEM_InitDosMemory
|
||||
*
|
||||
* When WineDOS is loaded, initializes the current DOS memory layout.
|
||||
*/
|
||||
BOOL DOSMEM_InitDosMemory(void)
|
||||
{
|
||||
HMODULE16 hModule;
|
||||
unsigned short sel;
|
||||
LDT_ENTRY entry;
|
||||
DWORD reserve;
|
||||
|
||||
if (!(hModule = GetModuleHandle16("KERNEL"))) return FALSE;
|
||||
/* KERNEL.194: __F000H */
|
||||
sel = LOWORD(GetProcAddress16(hModule, (LPCSTR)(ULONG_PTR)194));
|
||||
wine_ldt_get_entry(sel, &entry);
|
||||
DOSMEM_dosmem = (char*)wine_ldt_get_base(&entry) - 0xF0000;
|
||||
/* KERNEL.183: __0000H */
|
||||
sel = LOWORD(GetProcAddress16(hModule, (LPCSTR)(DWORD_PTR)183));
|
||||
wine_ldt_get_entry(sel, &entry);
|
||||
DOSMEM_sysmem = wine_ldt_get_base(&entry);
|
||||
|
||||
/*
|
||||
* Reserve either:
|
||||
* - lowest 64k for NULL pointer catching (Win16)
|
||||
* - lowest 1k for interrupt handlers and
|
||||
* another 0.5k for BIOS, DOS and intra-application
|
||||
* areas (DOS)
|
||||
*/
|
||||
if (DOSMEM_dosmem != DOSMEM_sysmem)
|
||||
reserve = 0x10000; /* 64k */
|
||||
else
|
||||
reserve = 0x600; /* 1.5k */
|
||||
|
||||
/*
|
||||
* Round to paragraph boundary in order to make
|
||||
* sure the alignment is correct.
|
||||
*/
|
||||
reserve = ((reserve + 15) >> 4) << 4;
|
||||
|
||||
/*
|
||||
* Set DOS memory base and initialize conventional memory.
|
||||
*/
|
||||
DOSMEM_InitMemory(DOSMEM_dosmem + reserve);
|
||||
|
||||
CloseHandle( CreateThread( NULL, 0, timer_thread, DOSVM_BiosData(), 0, NULL ));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* DOSMEM_MapDosLayout
|
||||
*
|
||||
* Initialize the first MB of memory to look like a real DOS setup
|
||||
*/
|
||||
BOOL DOSMEM_MapDosLayout(void)
|
||||
{
|
||||
static int already_mapped;
|
||||
|
||||
if (!already_mapped)
|
||||
{
|
||||
HMODULE16 hModule;
|
||||
unsigned short sel;
|
||||
LDT_ENTRY entry;
|
||||
|
||||
if (DOSMEM_dosmem || !VirtualProtect( NULL, DOSMEM_SIZE, PAGE_EXECUTE_READWRITE, NULL ))
|
||||
{
|
||||
ERR( "Need full access to the first megabyte for DOS mode\n" );
|
||||
ExitProcess(1);
|
||||
}
|
||||
/* copy the BIOS and ISR area down */
|
||||
memcpy( DOSMEM_dosmem, DOSMEM_sysmem, 0x400 + 0x100 );
|
||||
DOSMEM_sysmem = DOSMEM_dosmem;
|
||||
hModule = GetModuleHandle16("KERNEL");
|
||||
/* selector to 0000H */
|
||||
sel = LOWORD(GetProcAddress16(hModule, (LPCSTR)(DWORD_PTR)183));
|
||||
wine_ldt_get_entry(sel, &entry);
|
||||
wine_ldt_set_base(&entry, NULL);
|
||||
wine_ldt_set_entry(sel, &entry);
|
||||
/* selector to BiosData */
|
||||
sel = LOWORD(GetProcAddress16(hModule, (LPCSTR)(DWORD_PTR)193));
|
||||
wine_ldt_get_entry(sel, &entry);
|
||||
wine_ldt_set_base(&entry, (const void*)0x400);
|
||||
wine_ldt_set_entry(sel, &entry);
|
||||
/* we may now need the actual interrupt stubs, and since we've just moved the
|
||||
* interrupt vector table away, we can fill the area with stubs instead... */
|
||||
DOSMEM_MakeIsrStubs();
|
||||
already_mapped = 1;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
|
@ -1,204 +0,0 @@
|
|||
/*
|
||||
* Routines for dynamically building calls to Wine from
|
||||
* protected mode applications.
|
||||
*
|
||||
* Copyright 2002 Jukka Heinonen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
#include "dosexe.h"
|
||||
#include "wine/winbase16.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(int);
|
||||
|
||||
/*
|
||||
* Magic DWORD used to check stack integrity.
|
||||
*/
|
||||
#define RELAY_MAGIC 0xabcdef00
|
||||
|
||||
/*
|
||||
* Memory block for temporary 16-bit stacks used with relay calls.
|
||||
*/
|
||||
typedef struct {
|
||||
DWORD inuse; /* non-zero if stack block is in use */
|
||||
DWORD eip; /* saved ip */
|
||||
DWORD seg_cs; /* saved cs */
|
||||
DWORD esp; /* saved sp */
|
||||
DWORD seg_ss; /* saved ss */
|
||||
DWORD stack_bottom; /* guard dword */
|
||||
BYTE stack[256-7*4]; /* 16-bit stack */
|
||||
DWORD stack_top; /* guard dword */
|
||||
} RELAY_Stack16;
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RELAY_GetPointer
|
||||
*
|
||||
* Get pointer to stack block when given esp pointing to 16-bit stack
|
||||
* inside relay data segment.
|
||||
*/
|
||||
static RELAY_Stack16 *RELAY_GetPointer( DWORD offset )
|
||||
{
|
||||
offset = offset / sizeof(RELAY_Stack16) * sizeof(RELAY_Stack16);
|
||||
return MapSL(MAKESEGPTR(DOSVM_dpmi_segments->relay_data_sel, offset));
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RELAY_MakeShortContext
|
||||
*
|
||||
* Allocate separate 16-bit stack, make stack pointer point to this
|
||||
* stack and make code pointer point to stub that restores everything.
|
||||
* So, after this routine, SS and CS are guaranteed to be 16-bit.
|
||||
*
|
||||
* Note: This might be called from signal handler, so the stack
|
||||
* allocation algorithm must be signal safe.
|
||||
*/
|
||||
static void RELAY_MakeShortContext( CONTEXT86 *context )
|
||||
{
|
||||
DWORD offset = offsetof(RELAY_Stack16, stack_top);
|
||||
RELAY_Stack16 *stack = RELAY_GetPointer( 0 );
|
||||
|
||||
while (stack->inuse && offset < DOSVM_RELAY_DATA_SIZE) {
|
||||
stack++;
|
||||
offset += sizeof(RELAY_Stack16);
|
||||
}
|
||||
|
||||
if (offset >= DOSVM_RELAY_DATA_SIZE)
|
||||
ERR( "Too many nested interrupts!\n" );
|
||||
|
||||
stack->inuse = 1;
|
||||
stack->eip = context->Eip;
|
||||
stack->seg_cs = context->SegCs;
|
||||
stack->esp = context->Esp;
|
||||
stack->seg_ss = context->SegSs;
|
||||
|
||||
stack->stack_bottom = RELAY_MAGIC;
|
||||
stack->stack_top = RELAY_MAGIC;
|
||||
|
||||
context->SegSs = DOSVM_dpmi_segments->relay_data_sel;
|
||||
context->Esp = offset;
|
||||
context->SegCs = DOSVM_dpmi_segments->relay_code_sel;
|
||||
context->Eip = 3;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RELAY_RelayStub
|
||||
*
|
||||
* This stub is called by __wine_call_from_16_regs in order to marshall
|
||||
* relay parameters.
|
||||
*/
|
||||
static void __stdcall RELAY_RelayStub( DOSRELAY proc,
|
||||
unsigned char *args,
|
||||
void *ctx86 )
|
||||
{
|
||||
if (proc)
|
||||
{
|
||||
CONTEXT86 *context = ctx86;
|
||||
RELAY_Stack16 *stack = RELAY_GetPointer( context->Esp );
|
||||
|
||||
DWORD old_seg_cs = context->SegCs;
|
||||
DWORD old_eip = context->Eip;
|
||||
DWORD old_seg_ss = context->SegSs;
|
||||
DWORD old_esp = context->Esp;
|
||||
|
||||
context->SegCs = stack->seg_cs;
|
||||
context->Eip = stack->eip;
|
||||
context->SegSs = stack->seg_ss;
|
||||
context->Esp = stack->esp;
|
||||
|
||||
proc( context, *(LPVOID *)args );
|
||||
|
||||
stack->seg_cs = context->SegCs;
|
||||
stack->eip = context->Eip;
|
||||
stack->seg_ss = context->SegSs;
|
||||
stack->esp = context->Esp;
|
||||
|
||||
context->SegCs = old_seg_cs;
|
||||
context->Eip = old_eip;
|
||||
context->SegSs = old_seg_ss;
|
||||
context->Esp = old_esp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* DOSVM_RelayHandler
|
||||
*
|
||||
* Restore saved code and stack pointers and release stack block.
|
||||
*/
|
||||
void DOSVM_RelayHandler( CONTEXT86 *context )
|
||||
{
|
||||
RELAY_Stack16 *stack = RELAY_GetPointer( context->Esp );
|
||||
|
||||
context->SegSs = stack->seg_ss;
|
||||
context->Esp = stack->esp;
|
||||
context->SegCs = stack->seg_cs;
|
||||
context->Eip = stack->eip;
|
||||
|
||||
if (!stack->inuse ||
|
||||
stack->stack_bottom != RELAY_MAGIC ||
|
||||
stack->stack_top != RELAY_MAGIC)
|
||||
ERR( "Stack corrupted!\n" );
|
||||
|
||||
stack->inuse = 0;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* DOSVM_BuildCallFrame
|
||||
*
|
||||
* Modifies the context so that return to context calls DOSRELAY and
|
||||
* only after return from DOSRELAY the original context will be returned to.
|
||||
*/
|
||||
void DOSVM_BuildCallFrame( CONTEXT86 *context, DOSRELAY relay, LPVOID data )
|
||||
{
|
||||
static void (*__wine_call_from_16_regs_ptr)(void);
|
||||
WORD code_sel = DOSVM_dpmi_segments->relay_code_sel;
|
||||
|
||||
/*
|
||||
* Allocate separate stack for relay call.
|
||||
*/
|
||||
RELAY_MakeShortContext( context );
|
||||
|
||||
/*
|
||||
* Build call frame.
|
||||
*/
|
||||
PUSH_WORD16( context, HIWORD(data) ); /* argument.hiword */
|
||||
PUSH_WORD16( context, LOWORD(data) ); /* argument.loword */
|
||||
PUSH_WORD16( context, context->SegCs ); /* STACK16FRAME.cs */
|
||||
PUSH_WORD16( context, LOWORD(context->Eip) ); /* STACK16FRAME.ip */
|
||||
PUSH_WORD16( context, LOWORD(context->Ebp) ); /* STACK16FRAME.bp */
|
||||
PUSH_WORD16( context, HIWORD(relay) ); /* STACK16FRAME.entry_point.hiword */
|
||||
PUSH_WORD16( context, LOWORD(relay) ); /* STACK16FRAME.entry_point.loword */
|
||||
PUSH_WORD16( context, 0 ); /* STACK16FRAME.entry_ip */
|
||||
PUSH_WORD16( context, HIWORD(RELAY_RelayStub) ); /* STACK16FRAME.relay.hiword */
|
||||
PUSH_WORD16( context, LOWORD(RELAY_RelayStub) ); /* STACK16FRAME.relay.loword */
|
||||
PUSH_WORD16( context, 0 ); /* STACK16FRAME.module_cs.hiword */
|
||||
PUSH_WORD16( context, code_sel ); /* STACK16FRAME.module_cs.loword */
|
||||
PUSH_WORD16( context, 0 ); /* STACK16FRAME.callfrom_ip.hiword */
|
||||
PUSH_WORD16( context, 0 ); /* STACK16FRAME.callfrom_ip.loword */
|
||||
|
||||
/*
|
||||
* Adjust code pointer.
|
||||
*/
|
||||
if (!__wine_call_from_16_regs_ptr)
|
||||
__wine_call_from_16_regs_ptr = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"),
|
||||
"__wine_call_from_16_regs" );
|
||||
context->SegCs = wine_get_cs();
|
||||
context->Eip = (DWORD)__wine_call_from_16_regs_ptr;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
@ stdcall wine_load_dos_exe(str str)
|
||||
|
||||
@ stdcall EmulateInterruptPM(ptr long) DOSVM_EmulateInterruptPM
|
||||
@ stdcall CallBuiltinHandler(ptr long) DOSVM_CallBuiltinHandler
|
||||
|
||||
# I/O functions
|
||||
@ stdcall inport(long long) DOSVM_inport
|
||||
@ stdcall outport(long long long) DOSVM_outport
|
||||
|
||||
# DOS memory functions
|
||||
@ cdecl FreeDosBlock(ptr) DOSMEM_FreeBlock
|
||||
@ cdecl AllocDosBlock(long ptr) DOSMEM_AllocBlock
|
||||
@ cdecl ResizeDosBlock(ptr long long) DOSMEM_ResizeBlock
|
|
@ -1,19 +0,0 @@
|
|||
# VxDs. The first Vxd is at 400
|
||||
#
|
||||
#400+VXD_ID pascal -register <VxD handler>() <VxD handler>
|
||||
#
|
||||
401 pascal -register VXD_VMM() VXD_VMM
|
||||
405 pascal -register VXD_Timer() VXD_Timer
|
||||
409 pascal -register VXD_Reboot() VXD_Reboot
|
||||
410 pascal -register VXD_VDD() VXD_VDD
|
||||
412 pascal -register VXD_VMD() VXD_VMD
|
||||
414 pascal -register VXD_Comm() VXD_Comm
|
||||
#415 pascal -register VXD_Printer() VXD_Printer
|
||||
423 pascal -register VXD_Shell() VXD_Shell
|
||||
433 pascal -register VXD_PageFile() VXD_PageFile
|
||||
438 pascal -register VXD_APM() VXD_APM
|
||||
439 pascal -register VXD_VXDLoader() VXD_VXDLoader
|
||||
445 pascal -register VXD_Win32s() VXD_Win32s
|
||||
451 pascal -register VXD_ConfigMG() VXD_ConfigMG
|
||||
455 pascal -register VXD_Enable() VXD_Enable
|
||||
1490 pascal -register VXD_TimerAPI() VXD_TimerAPI
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winevdm);
|
||||
|
||||
static void (WINAPI *wine_load_dos_exe)( LPCSTR filename, LPCSTR cmdline );
|
||||
extern void __wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline );
|
||||
|
||||
|
||||
/*** PIF file structures ***/
|
||||
|
@ -244,7 +244,7 @@ static VOID pif_cmd( char *filename, char *cmdline)
|
|||
* - hot key's
|
||||
* - etc.
|
||||
*/
|
||||
wine_load_dos_exe( progpath, cmdline );
|
||||
__wine_load_dos_exe( progpath, cmdline );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -382,7 +382,6 @@ int main( int argc, char *argv[] )
|
|||
STARTUPINFOA info;
|
||||
char *cmdline, *appname, **first_arg;
|
||||
char *p;
|
||||
HMODULE winedos;
|
||||
MEMORY_BASIC_INFORMATION mem_info;
|
||||
|
||||
if (!argv[1]) usage();
|
||||
|
@ -403,13 +402,6 @@ int main( int argc, char *argv[] )
|
|||
first_arg = argv + 1;
|
||||
}
|
||||
|
||||
if (!(winedos = LoadLibraryA( "winedos.dll" )) ||
|
||||
!(wine_load_dos_exe = (void *)GetProcAddress( winedos, "wine_load_dos_exe" )))
|
||||
{
|
||||
WINE_MESSAGE( "winevdm: unable to exec '%s': DOS support unavailable\n", appname );
|
||||
ExitProcess(1);
|
||||
}
|
||||
|
||||
if (*first_arg) first_arg++; /* skip program name */
|
||||
cmdline = build_command_line( first_arg );
|
||||
|
||||
|
@ -455,7 +447,7 @@ int main( int argc, char *argv[] )
|
|||
|
||||
/* try DOS format */
|
||||
/* loader expects arguments to be regular C strings */
|
||||
wine_load_dos_exe( appname, cmdline + 1 );
|
||||
__wine_load_dos_exe( appname, cmdline + 1 );
|
||||
}
|
||||
/* if we get back here it failed */
|
||||
instance = GetLastError();
|
||||
|
|
Loading…
Reference in New Issue