winedos: Merge all of winedos back into krnl386.

This commit is contained in:
Alexandre Julliard 2010-01-05 14:26:05 +01:00
parent 03e31f9b86
commit 26a42f8452
47 changed files with 738 additions and 1155 deletions

10
configure vendored
View File

@ -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" ;;

View File

@ -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])

View File

@ -3,7 +3,7 @@ TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = ifsmgr.vxd
IMPORTS = kernel32
IMPORTS = kernel32 kernel
C_SRCS = \
ifsmgr.c

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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 );

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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 );
}

View File

@ -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;

View File

@ -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"

View File

@ -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
*

View File

@ -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;
}

View File

@ -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
*

View File

@ -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))

View File

@ -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 */

View File

@ -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)

View File

@ -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 */
}

View File

@ -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;
}

View File

@ -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"

View File

@ -3,7 +3,7 @@ TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = vwin32.vxd
IMPORTS = kernel32
IMPORTS = kernel32 kernel
C_SRCS = \
vwin32.c

View File

@ -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 */

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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();