Moved DOS memory handling to winedos.
This commit is contained in:
parent
e6267369b2
commit
16df50efbe
|
@ -40,7 +40,6 @@
|
||||||
|
|
||||||
#include "kernel_private.h"
|
#include "kernel_private.h"
|
||||||
#include "toolhelp.h"
|
#include "toolhelp.h"
|
||||||
#include "miscemu.h"
|
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(dosmem);
|
WINE_DEFAULT_DEBUG_CHANNEL(dosmem);
|
||||||
|
@ -54,33 +53,6 @@ WORD DOSMEM_BiosSysSeg; /* BIOS ROM segment at 0xf000:0 */
|
||||||
#define DOSMEM_SIZE 0x110000
|
#define DOSMEM_SIZE 0x110000
|
||||||
#define DOSMEM_64KB 0x10000
|
#define DOSMEM_64KB 0x10000
|
||||||
|
|
||||||
/* use 2 low bits of 'size' for the housekeeping */
|
|
||||||
|
|
||||||
#define DM_BLOCK_DEBUG 0xABE00000
|
|
||||||
#define DM_BLOCK_TERMINAL 0x00000001
|
|
||||||
#define DM_BLOCK_FREE 0x00000002
|
|
||||||
#define DM_BLOCK_MASK 0x001FFFFC
|
|
||||||
|
|
||||||
/*
|
|
||||||
#define __DOSMEM_DEBUG__
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned size;
|
|
||||||
} dosmem_entry;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned blocks;
|
|
||||||
unsigned free;
|
|
||||||
} dosmem_info;
|
|
||||||
|
|
||||||
#define NEXT_BLOCK(block) \
|
|
||||||
(dosmem_entry*)(((char*)(block)) + \
|
|
||||||
sizeof(dosmem_entry) + ((block)->size & DM_BLOCK_MASK))
|
|
||||||
|
|
||||||
#define VM_STUB(x) (0x90CF00CD|(x<<8)) /* INT x; IRET; NOP */
|
|
||||||
#define VM_STUB_SEGMENT 0xf000 /* BIOS segment */
|
|
||||||
|
|
||||||
/* when looking at DOS and real mode memory, we activate in three different
|
/* when looking at DOS and real mode memory, we activate in three different
|
||||||
* modes, depending the situation.
|
* modes, depending the situation.
|
||||||
* 1/ By default (protected mode), the first MB of memory (actually 0x110000,
|
* 1/ By default (protected mode), the first MB of memory (actually 0x110000,
|
||||||
|
@ -91,242 +63,71 @@ typedef struct {
|
||||||
* commit this memory, made of: BIOS segment, but also some system
|
* commit this memory, made of: BIOS segment, but also some system
|
||||||
* information, usually low in memory that we map for the circumstance also
|
* information, usually low in memory that we map for the circumstance also
|
||||||
* in the BIOS segment, so that we keep the low memory protected (for NULL
|
* in the BIOS segment, so that we keep the low memory protected (for NULL
|
||||||
* pointer deref catching for example). In this case, we'res still in PM
|
* pointer deref catching for example). In this case, we're still in PM
|
||||||
* mode, accessing part of the "physicale" real mode memory.
|
* mode, accessing part of the "physical" real mode memory. In fact, we don't
|
||||||
* 3/ if the process enters the real mode, then we commit the full first MB of
|
* map all the first meg, we keep 64k uncommitted to still catch NULL
|
||||||
* memory (and also initialize the DOS structures in it).
|
* pointers dereference
|
||||||
|
* 3/ if the process enters the real mode, then we (also) commit the full first
|
||||||
|
* MB of memory (and also initialize the DOS structures in it).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* DOS memory base (linear in process address space) */
|
/* DOS memory base (linear in process address space) */
|
||||||
static char *DOSMEM_dosmem;
|
static char *DOSMEM_dosmem;
|
||||||
/* DOS system base (for interrupt vector table and BIOS data area)
|
|
||||||
* ...should in theory (i.e. Windows) be equal to DOSMEM_dosmem (NULL),
|
|
||||||
* but is normally set to 0xf0000 in Wine to allow trapping of NULL pointers,
|
|
||||||
* and only relocated to NULL when absolutely necessary */
|
|
||||||
static char *DOSMEM_sysmem;
|
|
||||||
/* number of bytes protected from _dosmem. 0 when DOS memory is initialized,
|
/* number of bytes protected from _dosmem. 0 when DOS memory is initialized,
|
||||||
* 64k otherwise to trap NULL pointers deref */
|
* 64k otherwise to trap NULL pointers deref */
|
||||||
static DWORD DOSMEM_protect;
|
static DWORD DOSMEM_protect;
|
||||||
|
|
||||||
static void DOSMEM_InitMemory(void);
|
static LONG WINAPI dosmem_handler(EXCEPTION_POINTERS* except);
|
||||||
|
|
||||||
/***********************************************************************
|
struct winedos_exports winedos;
|
||||||
* DOSMEM_MemoryTop
|
|
||||||
*
|
void load_winedos(void)
|
||||||
* Gets the DOS memory top.
|
|
||||||
*/
|
|
||||||
static char *DOSMEM_MemoryTop(void)
|
|
||||||
{
|
{
|
||||||
return DOSMEM_dosmem+0x9FFFC; /* 640K */
|
static HANDLE hRunOnce /* = 0 */;
|
||||||
}
|
static HMODULE hWineDos /* = 0 */;
|
||||||
|
|
||||||
/***********************************************************************
|
/* FIXME: this isn't 100% thread safe, as we won't catch access to 1MB while
|
||||||
* DOSMEM_InfoBlock
|
* loading winedos (and may return uninitialized valued)
|
||||||
*
|
|
||||||
* Gets the DOS memory info block.
|
|
||||||
*/
|
|
||||||
static dosmem_info *DOSMEM_InfoBlock(void)
|
|
||||||
{
|
|
||||||
/* Start of DOS conventional memory */
|
|
||||||
static char *DOSMEM_membase;
|
|
||||||
|
|
||||||
if (!DOSMEM_membase)
|
|
||||||
{
|
|
||||||
DWORD reserve;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 = DOSMEM_64KB;
|
|
||||||
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_membase = DOSMEM_dosmem + reserve;
|
|
||||||
DOSMEM_InitMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (dosmem_info*)DOSMEM_membase;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* DOSMEM_RootBlock
|
|
||||||
*
|
|
||||||
* Gets the DOS memory root block.
|
|
||||||
*/
|
|
||||||
static dosmem_entry *DOSMEM_RootBlock(void)
|
|
||||||
{
|
|
||||||
/* first block has to be paragraph-aligned */
|
|
||||||
return (dosmem_entry*)(((char*)DOSMEM_InfoBlock()) +
|
|
||||||
((((sizeof(dosmem_info) + 0xf) & ~0xf) - sizeof(dosmem_entry))));
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static BIOSDATA * DOSMEM_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) return;
|
||||||
GetLocalTime( &time );
|
if (hRunOnce == 0)
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
char *pBiosSys = DOSMEM_dosmem + 0xf0000;
|
|
||||||
BYTE *pBiosROMTable = pBiosSys+0xe6f5;
|
|
||||||
BIOSDATA *pBiosData = DOSMEM_BiosData();
|
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
strcpy(pBiosSys+0xfff5, "13/01/99");
|
|
||||||
|
|
||||||
/* BIOS ID */
|
|
||||||
*(pBiosSys+0xfffe) = 0xfc;
|
|
||||||
|
|
||||||
/* Reboot vector (f000:fff0 or ffff:0000) */
|
|
||||||
*(DWORD*)(pBiosSys + 0xfff0) = VM_STUB(0x19);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* DOSMEM_InitMemory
|
|
||||||
*
|
|
||||||
* Initialises the DOS memory structures.
|
|
||||||
*/
|
|
||||||
static void DOSMEM_InitMemory(void)
|
|
||||||
{
|
|
||||||
dosmem_info* info_block = DOSMEM_InfoBlock();
|
|
||||||
dosmem_entry* root_block = DOSMEM_RootBlock();
|
|
||||||
dosmem_entry* dm;
|
|
||||||
|
|
||||||
root_block->size = DOSMEM_MemoryTop() - (((char*)root_block) + sizeof(dosmem_entry));
|
|
||||||
|
|
||||||
info_block->blocks = 0;
|
|
||||||
info_block->free = root_block->size;
|
|
||||||
|
|
||||||
dm = NEXT_BLOCK(root_block);
|
|
||||||
dm->size = DM_BLOCK_TERMINAL;
|
|
||||||
root_block->size |= DM_BLOCK_FREE
|
|
||||||
#ifdef __DOSMEM_DEBUG__
|
|
||||||
| DM_BLOCK_DEBUG
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
|
|
||||||
TRACE( "DOS conventional memory initialized, %d bytes free.\n",
|
|
||||||
DOSMEM_Available() );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dosmem_bios_init(void)
|
|
||||||
{
|
|
||||||
static int bios_created;
|
|
||||||
|
|
||||||
if (!bios_created)
|
|
||||||
{
|
{
|
||||||
DOSMEM_FillBiosSegments();
|
HANDLE hEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
|
||||||
DOSMEM_FillIsrTable();
|
if (InterlockedCompareExchangePointer( (PVOID)&hRunOnce, hEvent, 0 ) == 0)
|
||||||
bios_created = TRUE;
|
{
|
||||||
|
HMODULE hModule;
|
||||||
|
|
||||||
|
/* ok, we're the winning thread */
|
||||||
|
VirtualProtect( DOSMEM_dosmem + DOSMEM_protect,
|
||||||
|
DOSMEM_SIZE - DOSMEM_protect,
|
||||||
|
PAGE_EXECUTE_READWRITE, NULL );
|
||||||
|
if (!(hModule = LoadLibraryA( "winedos.dll" )))
|
||||||
|
{
|
||||||
|
ERR("Could not load winedos.dll, DOS subsystem unavailable\n");
|
||||||
|
hWineDos = (HMODULE)1; /* not to try to load it again */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#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);
|
||||||
|
GET_ADDR(BiosTick);
|
||||||
|
#undef GET_ADDR
|
||||||
|
RtlRemoveVectoredExceptionHandler( dosmem_handler );
|
||||||
|
hWineDos = hModule;
|
||||||
|
SetEvent( hRunOnce );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* someone beat us here... */
|
||||||
|
CloseHandle( hEvent );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* and wait for the winner to have finished */
|
||||||
|
WaitForSingleObject( hRunOnce, INFINITE );
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
|
@ -339,19 +140,10 @@ static LONG WINAPI dosmem_handler(EXCEPTION_POINTERS* except)
|
||||||
if (except->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
if (except->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
||||||
{
|
{
|
||||||
DWORD addr = except->ExceptionRecord->ExceptionInformation[1];
|
DWORD addr = except->ExceptionRecord->ExceptionInformation[1];
|
||||||
if (addr >= (ULONG_PTR)DOSMEM_sysmem &&
|
|
||||||
addr < (ULONG_PTR)DOSMEM_sysmem + DOSMEM_64KB)
|
|
||||||
{
|
|
||||||
VirtualProtect( DOSMEM_sysmem, DOSMEM_64KB, PAGE_EXECUTE_READWRITE, NULL );
|
|
||||||
dosmem_bios_init();
|
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
|
||||||
}
|
|
||||||
if (addr >= (ULONG_PTR)DOSMEM_dosmem + DOSMEM_protect &&
|
if (addr >= (ULONG_PTR)DOSMEM_dosmem + DOSMEM_protect &&
|
||||||
addr < (ULONG_PTR)DOSMEM_dosmem + DOSMEM_SIZE)
|
addr < (ULONG_PTR)DOSMEM_dosmem + DOSMEM_SIZE)
|
||||||
{
|
{
|
||||||
VirtualProtect( DOSMEM_dosmem + DOSMEM_protect, DOSMEM_SIZE - DOSMEM_protect,
|
load_winedos();
|
||||||
PAGE_EXECUTE_READWRITE, NULL );
|
|
||||||
dosmem_bios_init();
|
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,7 +155,7 @@ static LONG WINAPI dosmem_handler(EXCEPTION_POINTERS* except)
|
||||||
*
|
*
|
||||||
* Setup the first megabyte for DOS memory access
|
* Setup the first megabyte for DOS memory access
|
||||||
*/
|
*/
|
||||||
static void setup_dos_mem(void)
|
static char* setup_dos_mem(void)
|
||||||
{
|
{
|
||||||
int sys_offset = 0;
|
int sys_offset = 0;
|
||||||
int page_size = getpagesize();
|
int page_size = getpagesize();
|
||||||
|
@ -399,8 +191,8 @@ static void setup_dos_mem(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DOSMEM_dosmem = addr;
|
DOSMEM_dosmem = addr;
|
||||||
DOSMEM_sysmem = (char*)addr + sys_offset;
|
|
||||||
RtlAddVectoredExceptionHandler(FALSE, dosmem_handler);
|
RtlAddVectoredExceptionHandler(FALSE, dosmem_handler);
|
||||||
|
return (char*)addr + sys_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -412,285 +204,18 @@ static void setup_dos_mem(void)
|
||||||
*/
|
*/
|
||||||
BOOL DOSMEM_Init(void)
|
BOOL DOSMEM_Init(void)
|
||||||
{
|
{
|
||||||
setup_dos_mem();
|
char* sysmem = setup_dos_mem();
|
||||||
|
|
||||||
DOSMEM_0000H = GLOBAL_CreateBlock( GMEM_FIXED, DOSMEM_sysmem,
|
DOSMEM_0000H = GLOBAL_CreateBlock( GMEM_FIXED, sysmem,
|
||||||
DOSMEM_64KB, 0, WINE_LDT_FLAGS_DATA );
|
DOSMEM_64KB, 0, WINE_LDT_FLAGS_DATA );
|
||||||
DOSMEM_BiosDataSeg = GLOBAL_CreateBlock(GMEM_FIXED,DOSMEM_sysmem + 0x400,
|
DOSMEM_BiosDataSeg = GLOBAL_CreateBlock( GMEM_FIXED, sysmem + 0x400,
|
||||||
0x100, 0, WINE_LDT_FLAGS_DATA );
|
0x100, 0, WINE_LDT_FLAGS_DATA );
|
||||||
DOSMEM_BiosSysSeg = GLOBAL_CreateBlock(GMEM_FIXED,DOSMEM_dosmem + 0xf0000,
|
DOSMEM_BiosSysSeg = GLOBAL_CreateBlock( GMEM_FIXED, DOSMEM_dosmem + 0xf0000,
|
||||||
DOSMEM_64KB, 0, WINE_LDT_FLAGS_DATA );
|
DOSMEM_64KB, 0, WINE_LDT_FLAGS_DATA );
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
|
||||||
* DOSMEM_InitDosMem
|
|
||||||
*
|
|
||||||
* Initialize the first MB of memory to look like a real DOS setup
|
|
||||||
*/
|
|
||||||
BOOL DOSMEM_InitDosMem(void)
|
|
||||||
{
|
|
||||||
static int already_mapped;
|
|
||||||
|
|
||||||
if (!already_mapped)
|
|
||||||
{
|
|
||||||
if (DOSMEM_dosmem)
|
|
||||||
{
|
|
||||||
ERR( "Needs access to the first megabyte for DOS mode\n" );
|
|
||||||
ExitProcess(1);
|
|
||||||
}
|
|
||||||
MESSAGE( "Warning: unprotecting memory to allow real-mode calls.\n"
|
|
||||||
" NULL pointer accesses will no longer be caught.\n" );
|
|
||||||
VirtualProtect( NULL, DOSMEM_SIZE, PAGE_EXECUTE_READWRITE, NULL );
|
|
||||||
DOSMEM_protect = 0;
|
|
||||||
dosmem_bios_init();
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* DOSMEM_Tick
|
|
||||||
*
|
|
||||||
* Increment the BIOS tick counter. Called by timer signal handler.
|
|
||||||
*/
|
|
||||||
void DOSMEM_Tick( WORD timer )
|
|
||||||
{
|
|
||||||
BIOSDATA *pBiosData = DOSMEM_BiosData();
|
|
||||||
if (pBiosData) pBiosData->Ticks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* DOSMEM_GetBlock
|
|
||||||
*
|
|
||||||
* Carve a chunk of the DOS memory block (without selector).
|
|
||||||
*/
|
|
||||||
LPVOID DOSMEM_GetBlock(UINT size, UINT16* pseg)
|
|
||||||
{
|
|
||||||
UINT blocksize;
|
|
||||||
char *block = NULL;
|
|
||||||
dosmem_info *info_block = DOSMEM_InfoBlock();
|
|
||||||
dosmem_entry *dm;
|
|
||||||
#ifdef __DOSMEM_DEBUG_
|
|
||||||
dosmem_entry *prev = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( size > info_block->free ) return NULL;
|
|
||||||
dm = DOSMEM_RootBlock();
|
|
||||||
|
|
||||||
while (dm && dm->size != DM_BLOCK_TERMINAL)
|
|
||||||
{
|
|
||||||
#ifdef __DOSMEM_DEBUG__
|
|
||||||
if( (dm->size & DM_BLOCK_DEBUG) != DM_BLOCK_DEBUG )
|
|
||||||
{
|
|
||||||
WARN("MCB overrun! [prev = 0x%08x]\n", 4 + (UINT)prev);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
prev = dm;
|
|
||||||
#endif
|
|
||||||
if( dm->size & DM_BLOCK_FREE )
|
|
||||||
{
|
|
||||||
dosmem_entry *next = NEXT_BLOCK(dm);
|
|
||||||
|
|
||||||
while( next->size & DM_BLOCK_FREE ) /* collapse free blocks */
|
|
||||||
{
|
|
||||||
dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
|
|
||||||
next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
|
|
||||||
next = NEXT_BLOCK(dm);
|
|
||||||
}
|
|
||||||
|
|
||||||
blocksize = dm->size & DM_BLOCK_MASK;
|
|
||||||
if( blocksize >= size )
|
|
||||||
{
|
|
||||||
block = ((char*)dm) + sizeof(dosmem_entry);
|
|
||||||
if( blocksize - size > 0x20 )
|
|
||||||
{
|
|
||||||
/* split dm so that the next one stays
|
|
||||||
* paragraph-aligned (and dm loses free bit) */
|
|
||||||
|
|
||||||
dm->size = (((size + 0xf + sizeof(dosmem_entry)) & ~0xf) -
|
|
||||||
sizeof(dosmem_entry));
|
|
||||||
next = (dosmem_entry*)(((char*)dm) +
|
|
||||||
sizeof(dosmem_entry) + dm->size);
|
|
||||||
next->size = (blocksize - (dm->size +
|
|
||||||
sizeof(dosmem_entry))) | DM_BLOCK_FREE
|
|
||||||
#ifdef __DOSMEM_DEBUG__
|
|
||||||
| DM_BLOCK_DEBUG
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
} else dm->size &= DM_BLOCK_MASK;
|
|
||||||
|
|
||||||
info_block->blocks++;
|
|
||||||
info_block->free -= dm->size;
|
|
||||||
if( pseg ) *pseg = (block - DOSMEM_dosmem) >> 4;
|
|
||||||
#ifdef __DOSMEM_DEBUG__
|
|
||||||
dm->size |= DM_BLOCK_DEBUG;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dm = next;
|
|
||||||
}
|
|
||||||
else dm = NEXT_BLOCK(dm);
|
|
||||||
}
|
|
||||||
return (LPVOID)block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* DOSMEM_FreeBlock
|
|
||||||
*/
|
|
||||||
BOOL DOSMEM_FreeBlock(void* ptr)
|
|
||||||
{
|
|
||||||
dosmem_info *info_block = DOSMEM_InfoBlock();
|
|
||||||
|
|
||||||
if( ptr >= (void*)(((char*)DOSMEM_RootBlock()) + sizeof(dosmem_entry)) &&
|
|
||||||
ptr < (void*)DOSMEM_MemoryTop() && !((((char*)ptr)
|
|
||||||
- DOSMEM_dosmem) & 0xf) )
|
|
||||||
{
|
|
||||||
dosmem_entry *dm = (dosmem_entry*)(((char*)ptr) - sizeof(dosmem_entry));
|
|
||||||
|
|
||||||
if( !(dm->size & (DM_BLOCK_FREE | DM_BLOCK_TERMINAL))
|
|
||||||
#ifdef __DOSMEM_DEBUG__
|
|
||||||
&& ((dm->size & DM_BLOCK_DEBUG) == DM_BLOCK_DEBUG )
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
|
||||||
info_block->blocks--;
|
|
||||||
info_block->free += dm->size;
|
|
||||||
|
|
||||||
dm->size |= DM_BLOCK_FREE;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
UINT DOSMEM_ResizeBlock(void *ptr, UINT size, BOOL exact)
|
|
||||||
{
|
|
||||||
char *block = NULL;
|
|
||||||
dosmem_info *info_block = DOSMEM_InfoBlock();
|
|
||||||
dosmem_entry *dm;
|
|
||||||
dosmem_entry *next;
|
|
||||||
UINT blocksize;
|
|
||||||
UINT orgsize;
|
|
||||||
|
|
||||||
if( (ptr < (void*)(sizeof(dosmem_entry) + (char*)DOSMEM_RootBlock())) ||
|
|
||||||
(ptr >= (void*)DOSMEM_MemoryTop()) ||
|
|
||||||
(((((char*)ptr) - DOSMEM_dosmem) & 0xf) != 0) )
|
|
||||||
return (UINT)-1;
|
|
||||||
|
|
||||||
dm = (dosmem_entry*)(((char*)ptr) - sizeof(dosmem_entry));
|
|
||||||
if( dm->size & (DM_BLOCK_FREE | DM_BLOCK_TERMINAL) )
|
|
||||||
return (UINT)-1;
|
|
||||||
|
|
||||||
next = NEXT_BLOCK(dm);
|
|
||||||
orgsize = dm->size & DM_BLOCK_MASK;
|
|
||||||
|
|
||||||
/* collapse free blocks */
|
|
||||||
while( next->size & DM_BLOCK_FREE )
|
|
||||||
{
|
|
||||||
dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
|
|
||||||
next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
|
|
||||||
next = NEXT_BLOCK(dm);
|
|
||||||
}
|
|
||||||
|
|
||||||
blocksize = dm->size & DM_BLOCK_MASK;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If collapse didn't help we either expand block to maximum
|
|
||||||
* available size (exact == FALSE) or give collapsed blocks
|
|
||||||
* back to free storage (exact == TRUE).
|
|
||||||
*/
|
|
||||||
if (blocksize < size)
|
|
||||||
size = exact ? orgsize : blocksize;
|
|
||||||
|
|
||||||
block = ((char*)dm) + sizeof(dosmem_entry);
|
|
||||||
if( blocksize - size > 0x20 )
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* split dm so that the next one stays
|
|
||||||
* paragraph-aligned (and next gains free bit)
|
|
||||||
*/
|
|
||||||
|
|
||||||
dm->size = (((size + 0xf + sizeof(dosmem_entry)) & ~0xf) -
|
|
||||||
sizeof(dosmem_entry));
|
|
||||||
next = (dosmem_entry*)(((char*)dm) +
|
|
||||||
sizeof(dosmem_entry) + dm->size);
|
|
||||||
next->size = (blocksize - (dm->size +
|
|
||||||
sizeof(dosmem_entry))) | DM_BLOCK_FREE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dm->size &= DM_BLOCK_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Adjust available memory if block size changes.
|
|
||||||
*/
|
|
||||||
info_block->free += orgsize - dm->size;
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* DOSMEM_Available
|
|
||||||
*/
|
|
||||||
UINT DOSMEM_Available(void)
|
|
||||||
{
|
|
||||||
UINT blocksize, available = 0;
|
|
||||||
dosmem_entry *dm;
|
|
||||||
|
|
||||||
dm = DOSMEM_RootBlock();
|
|
||||||
|
|
||||||
while (dm && dm->size != DM_BLOCK_TERMINAL)
|
|
||||||
{
|
|
||||||
#ifdef __DOSMEM_DEBUG__
|
|
||||||
if( (dm->size & DM_BLOCK_DEBUG) != DM_BLOCK_DEBUG )
|
|
||||||
{
|
|
||||||
WARN("MCB overrun! [prev = 0x%08x]\n", 4 + (UINT)prev);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
prev = dm;
|
|
||||||
#endif
|
|
||||||
if( dm->size & DM_BLOCK_FREE )
|
|
||||||
{
|
|
||||||
dosmem_entry *next = NEXT_BLOCK(dm);
|
|
||||||
|
|
||||||
while( next->size & DM_BLOCK_FREE ) /* collapse free blocks */
|
|
||||||
{
|
|
||||||
dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
|
|
||||||
next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
|
|
||||||
next = NEXT_BLOCK(dm);
|
|
||||||
}
|
|
||||||
|
|
||||||
blocksize = dm->size & DM_BLOCK_MASK;
|
|
||||||
if ( blocksize > available ) available = blocksize;
|
|
||||||
dm = next;
|
|
||||||
}
|
|
||||||
else dm = NEXT_BLOCK(dm);
|
|
||||||
}
|
|
||||||
return available;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* DOSMEM_MapLinearToDos
|
* DOSMEM_MapLinearToDos
|
||||||
*
|
*
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
#include "wine/winbase16.h"
|
#include "wine/winbase16.h"
|
||||||
#include "ntstatus.h"
|
#include "ntstatus.h"
|
||||||
#include "toolhelp.h"
|
#include "toolhelp.h"
|
||||||
#include "miscemu.h"
|
|
||||||
#include "stackframe.h"
|
#include "stackframe.h"
|
||||||
#include "kernel_private.h"
|
#include "kernel_private.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
@ -77,6 +76,23 @@ static int globalArenaSize;
|
||||||
#define VALID_HANDLE(handle) (((handle)>>__AHSHIFT)<globalArenaSize)
|
#define VALID_HANDLE(handle) (((handle)>>__AHSHIFT)<globalArenaSize)
|
||||||
#define GET_ARENA_PTR(handle) (pGlobalArena + ((handle) >> __AHSHIFT))
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* GLOBAL_GetArena
|
* GLOBAL_GetArena
|
||||||
|
@ -336,7 +352,7 @@ HGLOBAL16 WINAPI GlobalReAlloc16(
|
||||||
newptr = 0;
|
newptr = 0;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newptr = DOSMEM_GetBlock( size, 0 );
|
newptr = DOSMEM_AllocBlock( size, 0 );
|
||||||
if (newptr)
|
if (newptr)
|
||||||
{
|
{
|
||||||
memcpy( newptr, ptr, oldsize );
|
memcpy( newptr, ptr, oldsize );
|
||||||
|
@ -757,7 +773,7 @@ DWORD WINAPI GlobalDOSAlloc16(
|
||||||
DWORD size /* [in] Number of bytes to be allocated */
|
DWORD size /* [in] Number of bytes to be allocated */
|
||||||
) {
|
) {
|
||||||
UINT16 uParagraph;
|
UINT16 uParagraph;
|
||||||
LPVOID lpBlock = DOSMEM_GetBlock( size, &uParagraph );
|
LPVOID lpBlock = DOSMEM_AllocBlock( size, &uParagraph );
|
||||||
|
|
||||||
if( lpBlock )
|
if( lpBlock )
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
#include "wine/winuser16.h"
|
#include "wine/winuser16.h"
|
||||||
#include "excpt.h"
|
#include "excpt.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "miscemu.h"
|
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
#include "kernel_private.h"
|
#include "kernel_private.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
@ -67,34 +66,6 @@ inline static void *get_stack( CONTEXT86 *context )
|
||||||
return wine_ldt_get_ptr( context->SegSs, context->Esp );
|
return wine_ldt_get_ptr( context->SegSs, context->Esp );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void (WINAPI *DOS_EmulateInterruptPM)( CONTEXT86 *context, BYTE intnum );
|
|
||||||
static void (WINAPI *DOS_CallBuiltinHandler)( CONTEXT86 *context, BYTE intnum );
|
|
||||||
static DWORD (WINAPI *DOS_inport)( int port, int size );
|
|
||||||
static void (WINAPI *DOS_outport)( int port, int size, DWORD val );
|
|
||||||
|
|
||||||
|
|
||||||
static void init_winedos(void)
|
|
||||||
{
|
|
||||||
static HMODULE module;
|
|
||||||
|
|
||||||
if (module) return;
|
|
||||||
module = LoadLibraryA( "winedos.dll" );
|
|
||||||
if (!module)
|
|
||||||
{
|
|
||||||
ERR("could not load winedos.dll, DOS subsystem unavailable\n");
|
|
||||||
module = (HMODULE)1; /* don't try again */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#define GET_ADDR(func) DOS_##func = (void *)GetProcAddress(module, #func);
|
|
||||||
GET_ADDR(inport);
|
|
||||||
GET_ADDR(outport);
|
|
||||||
GET_ADDR(EmulateInterruptPM);
|
|
||||||
GET_ADDR(CallBuiltinHandler);
|
|
||||||
#undef GET_ADDR
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* INSTR_ReplaceSelector
|
* INSTR_ReplaceSelector
|
||||||
*
|
*
|
||||||
|
@ -112,7 +83,11 @@ static BOOL INSTR_ReplaceSelector( CONTEXT86 *context, WORD *sel )
|
||||||
{
|
{
|
||||||
static WORD sys_timer = 0;
|
static WORD sys_timer = 0;
|
||||||
if (!sys_timer)
|
if (!sys_timer)
|
||||||
sys_timer = CreateSystemTimer( 55, DOSMEM_Tick );
|
{
|
||||||
|
if (!winedos.BiosTick) load_winedos();
|
||||||
|
if (winedos.BiosTick)
|
||||||
|
sys_timer = CreateSystemTimer( 55, winedos.BiosTick );
|
||||||
|
}
|
||||||
*sel = DOSMEM_BiosDataSeg;
|
*sel = DOSMEM_BiosDataSeg;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -367,8 +342,8 @@ static DWORD INSTR_inport( WORD port, int size, CONTEXT86 *context )
|
||||||
{
|
{
|
||||||
DWORD res = ~0U;
|
DWORD res = ~0U;
|
||||||
|
|
||||||
if (!DOS_inport) init_winedos();
|
if (!winedos.inport) load_winedos();
|
||||||
if (DOS_inport) res = DOS_inport( port, size );
|
if (winedos.inport) res = winedos.inport( port, size );
|
||||||
|
|
||||||
if (TRACE_ON(io))
|
if (TRACE_ON(io))
|
||||||
{
|
{
|
||||||
|
@ -399,8 +374,8 @@ static DWORD INSTR_inport( WORD port, int size, CONTEXT86 *context )
|
||||||
*/
|
*/
|
||||||
static void INSTR_outport( WORD port, int size, DWORD val, CONTEXT86 *context )
|
static void INSTR_outport( WORD port, int size, DWORD val, CONTEXT86 *context )
|
||||||
{
|
{
|
||||||
if (!DOS_outport) init_winedos();
|
if (!winedos.outport) load_winedos();
|
||||||
if (DOS_outport) DOS_outport( port, size, val );
|
if (winedos.outport) winedos.outport( port, size, val );
|
||||||
|
|
||||||
if (TRACE_ON(io))
|
if (TRACE_ON(io))
|
||||||
{
|
{
|
||||||
|
@ -733,11 +708,11 @@ DWORD INSTR_EmulateInstruction( EXCEPTION_RECORD *rec, CONTEXT86 *context )
|
||||||
|
|
||||||
case 0xcd: /* int <XX> */
|
case 0xcd: /* int <XX> */
|
||||||
if (wine_ldt_is_system(context->SegCs)) break; /* don't emulate it in 32-bit code */
|
if (wine_ldt_is_system(context->SegCs)) break; /* don't emulate it in 32-bit code */
|
||||||
if (!DOS_EmulateInterruptPM) init_winedos();
|
if (!winedos.EmulateInterruptPM) load_winedos();
|
||||||
if (DOS_EmulateInterruptPM)
|
if (winedos.EmulateInterruptPM)
|
||||||
{
|
{
|
||||||
context->Eip += prefixlen + 2;
|
context->Eip += prefixlen + 2;
|
||||||
DOS_EmulateInterruptPM( context, instr[1] );
|
winedos.EmulateInterruptPM( context, instr[1] );
|
||||||
return ExceptionContinueExecution;
|
return ExceptionContinueExecution;
|
||||||
}
|
}
|
||||||
break; /* Unable to emulate it */
|
break; /* Unable to emulate it */
|
||||||
|
@ -839,8 +814,8 @@ DWORD INSTR_EmulateInstruction( EXCEPTION_RECORD *rec, CONTEXT86 *context )
|
||||||
*/
|
*/
|
||||||
void INSTR_CallBuiltinHandler( CONTEXT86 *context, BYTE intnum )
|
void INSTR_CallBuiltinHandler( CONTEXT86 *context, BYTE intnum )
|
||||||
{
|
{
|
||||||
if (!DOS_CallBuiltinHandler) init_winedos();
|
if (!winedos.CallBuiltinHandler) load_winedos();
|
||||||
if (DOS_CallBuiltinHandler) DOS_CallBuiltinHandler( context, intnum );
|
if (winedos.CallBuiltinHandler) winedos.CallBuiltinHandler( context, intnum );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1167,11 +1167,6 @@
|
||||||
# Wine dll separation hacks, these will go away, don't use them
|
# Wine dll separation hacks, these will go away, don't use them
|
||||||
#
|
#
|
||||||
@ cdecl DOSMEM_AllocSelector(long)
|
@ cdecl DOSMEM_AllocSelector(long)
|
||||||
@ cdecl DOSMEM_Available()
|
|
||||||
@ cdecl DOSMEM_FreeBlock(ptr)
|
|
||||||
@ cdecl DOSMEM_GetBlock(long ptr)
|
|
||||||
@ cdecl DOSMEM_InitDosMem(long)
|
|
||||||
@ cdecl DOSMEM_ResizeBlock(ptr long long)
|
|
||||||
@ cdecl LOCAL_Alloc(long long long)
|
@ cdecl LOCAL_Alloc(long long long)
|
||||||
@ cdecl LOCAL_Compact(long long long)
|
@ cdecl LOCAL_Compact(long long long)
|
||||||
@ cdecl LOCAL_CountFree(long)
|
@ cdecl LOCAL_CountFree(long)
|
||||||
|
|
|
@ -90,5 +90,30 @@ typedef struct
|
||||||
WORD stackbottom; /* Bottom of the stack */
|
WORD stackbottom; /* Bottom of the stack */
|
||||||
} INSTANCEDATA;
|
} INSTANCEDATA;
|
||||||
#include "poppack.h"
|
#include "poppack.h"
|
||||||
|
extern WORD DOSMEM_0000H;
|
||||||
|
extern WORD DOSMEM_BiosDataSeg;
|
||||||
|
extern WORD DOSMEM_BiosSysSeg;
|
||||||
|
|
||||||
|
/* msdos/dosmem.c */
|
||||||
|
extern BOOL DOSMEM_Init(void);
|
||||||
|
extern WORD DOSMEM_AllocSelector(WORD);
|
||||||
|
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 void load_winedos(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 */
|
||||||
|
void (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 );
|
||||||
|
void (* BiosTick)(WORD timer);
|
||||||
|
} winedos;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,6 +14,7 @@ C_SRCS = \
|
||||||
dma.c \
|
dma.c \
|
||||||
dosaspi.c \
|
dosaspi.c \
|
||||||
dosconf.c \
|
dosconf.c \
|
||||||
|
dosmem.c \
|
||||||
dosvm.c \
|
dosvm.c \
|
||||||
fpu.c \
|
fpu.c \
|
||||||
himem.c \
|
himem.c \
|
||||||
|
|
|
@ -24,11 +24,11 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
|
#include "wine/library.h"
|
||||||
#include "wine/windef16.h"
|
#include "wine/windef16.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "winnt.h" /* for PCONTEXT */
|
#include "winnt.h" /* for PCONTEXT */
|
||||||
#include "wincon.h" /* for MOUSE_EVENT_RECORD */
|
#include "wincon.h" /* for MOUSE_EVENT_RECORD */
|
||||||
#include "miscemu.h"
|
|
||||||
|
|
||||||
#define MAX_DOS_DRIVES 26
|
#define MAX_DOS_DRIVES 26
|
||||||
|
|
||||||
|
@ -182,6 +182,68 @@ extern struct DPMI_segments *DOSVM_dpmi_segments;
|
||||||
#define SET_CH(context,val) ((void)((context)->Ecx = ((context)->Ecx & ~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)))
|
#define SET_DH(context,val) ((void)((context)->Edx = ((context)->Edx & ~0xff00) | (((BYTE)(val)) << 8)))
|
||||||
|
|
||||||
|
#include <pshpack1.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
WORD Com1Addr; /* 00: COM1 I/O address */
|
||||||
|
WORD Com2Addr; /* 02: COM2 I/O address */
|
||||||
|
WORD Com3Addr; /* 04: COM3 I/O address */
|
||||||
|
WORD Com4Addr; /* 06: COM4 I/O address */
|
||||||
|
WORD Lpt1Addr; /* 08: LPT1 I/O address */
|
||||||
|
WORD Lpt2Addr; /* 0a: LPT2 I/O address */
|
||||||
|
WORD Lpt3Addr; /* 0c: LPT3 I/O address */
|
||||||
|
WORD Lpt4Addr; /* 0e: LPT4 I/O address */
|
||||||
|
WORD InstalledHardware; /* 10: Installed hardware flags */
|
||||||
|
BYTE POSTstatus; /* 12: Power-On Self Test status */
|
||||||
|
WORD MemSize; /* 13: Base memory size in Kb */
|
||||||
|
WORD unused1; /* 15: Manufacturing test scratch pad */
|
||||||
|
BYTE KbdFlags1; /* 17: Keyboard flags 1 */
|
||||||
|
BYTE KbdFlags2; /* 18: Keyboard flags 2 */
|
||||||
|
BYTE unused2; /* 19: Keyboard driver workspace */
|
||||||
|
WORD NextKbdCharPtr; /* 1a: Next character in kbd buffer */
|
||||||
|
WORD FirstKbdCharPtr; /* 1c: First character in kbd buffer */
|
||||||
|
WORD KbdBuffer[16]; /* 1e: Keyboard buffer */
|
||||||
|
BYTE DisketteStatus1; /* 3e: Diskette recalibrate status */
|
||||||
|
BYTE DisketteStatus2; /* 3f: Diskette motor status */
|
||||||
|
BYTE DisketteStatus3; /* 40: Diskette motor timeout */
|
||||||
|
BYTE DisketteStatus4; /* 41: Diskette last operation status */
|
||||||
|
BYTE DiskStatus[7]; /* 42: Disk status/command bytes */
|
||||||
|
BYTE VideoMode; /* 49: Video mode */
|
||||||
|
WORD VideoColumns; /* 4a: Number of columns */
|
||||||
|
WORD VideoPageSize; /* 4c: Video page size in bytes */
|
||||||
|
WORD VideoPageStartAddr; /* 4e: Video page start address */
|
||||||
|
BYTE VideoCursorPos[16]; /* 50: Cursor position for 8 pages, column/row order */
|
||||||
|
WORD VideoCursorType; /* 60: Video cursor type */
|
||||||
|
BYTE VideoCurPage; /* 62: Video current page */
|
||||||
|
WORD VideoCtrlAddr; /* 63: Video controller address */
|
||||||
|
BYTE VideoReg1; /* 65: Video mode select register */
|
||||||
|
BYTE VideoReg2; /* 66: Video CGA palette register */
|
||||||
|
DWORD ResetEntry; /* 67: Warm reset entry point */
|
||||||
|
BYTE LastIRQ; /* 6b: Last unexpected interrupt */
|
||||||
|
DWORD Ticks; /* 6c: Ticks since midnight */
|
||||||
|
BYTE TicksOverflow; /* 70: Timer overflow if past midnight */
|
||||||
|
BYTE CtrlBreakFlag; /* 71: Ctrl-Break flag */
|
||||||
|
WORD ResetFlag; /* 72: POST Reset flag */
|
||||||
|
BYTE DiskOpStatus; /* 74: Last hard-disk operation status */
|
||||||
|
BYTE NbHardDisks; /* 75: Number of hard disks */
|
||||||
|
BYTE DiskCtrlByte; /* 76: Disk control byte */
|
||||||
|
BYTE DiskIOPort; /* 77: Disk I/O port offset */
|
||||||
|
BYTE LptTimeout[4]; /* 78: Timeouts for parallel ports */
|
||||||
|
BYTE ComTimeout[4]; /* 7c: Timeouts for serial ports */
|
||||||
|
WORD KbdBufferStart; /* 80: Keyboard buffer start */
|
||||||
|
WORD KbdBufferEnd; /* 82: Keyboard buffer end */
|
||||||
|
BYTE RowsOnScreenMinus1; /* 84: EGA only */
|
||||||
|
WORD BytesPerChar; /* 85: EGA only */
|
||||||
|
BYTE ModeOptions; /* 87: EGA only */
|
||||||
|
BYTE FeatureBitsSwitches; /* 88: EGA only */
|
||||||
|
BYTE VGASettings; /* 89: VGA misc settings */
|
||||||
|
BYTE DisplayCombination; /* 8A: VGA display combinations */
|
||||||
|
BYTE DiskDataRate; /* 8B: Last disk data rate selected */
|
||||||
|
} BIOSDATA;
|
||||||
|
|
||||||
|
#include <poppack.h>
|
||||||
|
|
||||||
/* module.c */
|
/* module.c */
|
||||||
extern void WINAPI MZ_LoadImage( LPCSTR filename, HANDLE hFile );
|
extern void WINAPI MZ_LoadImage( LPCSTR filename, HANDLE hFile );
|
||||||
extern BOOL WINAPI MZ_Exec( CONTEXT86 *context, LPCSTR filename, BYTE func, LPVOID paramblk );
|
extern BOOL WINAPI MZ_Exec( CONTEXT86 *context, LPCSTR filename, BYTE func, LPVOID paramblk );
|
||||||
|
@ -201,7 +263,6 @@ extern void WINAPI DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVO
|
||||||
extern void WINAPI DOSVM_PIC_ioport_out( WORD port, BYTE val );
|
extern void WINAPI DOSVM_PIC_ioport_out( WORD port, BYTE val );
|
||||||
extern void WINAPI DOSVM_SetTimer( UINT ticks );
|
extern void WINAPI DOSVM_SetTimer( UINT ticks );
|
||||||
extern UINT WINAPI DOSVM_GetTimer( void );
|
extern UINT WINAPI DOSVM_GetTimer( void );
|
||||||
extern BIOSDATA *DOSVM_BiosData( void );
|
|
||||||
|
|
||||||
/* devices.c */
|
/* devices.c */
|
||||||
extern void DOSDEV_InstallDOSDevices(void);
|
extern void DOSDEV_InstallDOSDevices(void);
|
||||||
|
@ -221,10 +282,20 @@ extern void DMA_ioport_out( WORD port, BYTE val );
|
||||||
extern BYTE DMA_ioport_in( WORD port );
|
extern BYTE DMA_ioport_in( WORD port );
|
||||||
|
|
||||||
/* dosaspi.c */
|
/* dosaspi.c */
|
||||||
void WINAPI DOSVM_ASPIHandler(CONTEXT86*);
|
extern void WINAPI DOSVM_ASPIHandler(CONTEXT86*);
|
||||||
|
|
||||||
/* dosconf.c */
|
/* dosconf.c */
|
||||||
DOSCONF *DOSCONF_GetConfig( void );
|
extern DOSCONF *DOSCONF_GetConfig( void );
|
||||||
|
|
||||||
|
/* dosmem.c */
|
||||||
|
extern void 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 */
|
/* fpu.c */
|
||||||
extern void WINAPI DOSVM_Int34Handler(CONTEXT86*);
|
extern void WINAPI DOSVM_Int34Handler(CONTEXT86*);
|
||||||
|
|
|
@ -0,0 +1,576 @@
|
||||||
|
/*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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;
|
||||||
|
|
||||||
|
/* use 2 low bits of 'size' for the housekeeping */
|
||||||
|
#define DM_BLOCK_DEBUG 0xABE00000
|
||||||
|
#define DM_BLOCK_TERMINAL 0x00000001
|
||||||
|
#define DM_BLOCK_FREE 0x00000002
|
||||||
|
#define DM_BLOCK_MASK 0x001FFFFC
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define __DOSMEM_DEBUG__
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned size;
|
||||||
|
} dosmem_entry;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned blocks;
|
||||||
|
unsigned free;
|
||||||
|
} dosmem_info;
|
||||||
|
|
||||||
|
static inline dosmem_entry* next_block(dosmem_entry* block)
|
||||||
|
{
|
||||||
|
return (dosmem_entry*)((char*)block +
|
||||||
|
sizeof(dosmem_entry) + (block->size & DM_BLOCK_MASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
#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, and the whole allocation strategy
|
||||||
|
* should use real MCB
|
||||||
|
*/
|
||||||
|
static dosmem_info* DOSMEM_info_block;
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* DOSMEM_MemoryTop
|
||||||
|
*
|
||||||
|
* Gets the DOS memory top.
|
||||||
|
*/
|
||||||
|
static char *DOSMEM_MemoryTop(void)
|
||||||
|
{
|
||||||
|
return DOSMEM_dosmem+0x9FFFC; /* 640K */
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* DOSMEM_RootBlock
|
||||||
|
*
|
||||||
|
* Gets the DOS memory root block.
|
||||||
|
*/
|
||||||
|
static dosmem_entry *DOSMEM_RootBlock(void)
|
||||||
|
{
|
||||||
|
/* first block has to be paragraph-aligned */
|
||||||
|
return (dosmem_entry*)(((char*)DOSMEM_info_block) +
|
||||||
|
((((sizeof(dosmem_info) + 0xf) & ~0xf) - sizeof(dosmem_entry))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
char *pBiosSys = DOSMEM_dosmem + 0xf0000;
|
||||||
|
BYTE *pBiosROMTable = pBiosSys+0xe6f5;
|
||||||
|
BIOSDATA *pBiosData = DOSVM_BiosData();
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
strcpy(pBiosSys+0xfff5, "13/01/99");
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
void BiosTick( WORD timer )
|
||||||
|
{
|
||||||
|
BIOSDATA *pBiosData = DOSVM_BiosData();
|
||||||
|
if (pBiosData) pBiosData->Ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* DOSMEM_AllocBlock
|
||||||
|
*
|
||||||
|
* Carve a chunk of the DOS memory block (without selector).
|
||||||
|
*/
|
||||||
|
LPVOID DOSMEM_AllocBlock(UINT size, UINT16* pseg)
|
||||||
|
{
|
||||||
|
UINT blocksize;
|
||||||
|
char *block = NULL;
|
||||||
|
dosmem_info *info_block = DOSMEM_info_block;
|
||||||
|
dosmem_entry *dm;
|
||||||
|
#ifdef __DOSMEM_DEBUG_
|
||||||
|
dosmem_entry *prev = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( size > info_block->free ) return NULL;
|
||||||
|
dm = DOSMEM_RootBlock();
|
||||||
|
|
||||||
|
while (dm && dm->size != DM_BLOCK_TERMINAL)
|
||||||
|
{
|
||||||
|
#ifdef __DOSMEM_DEBUG__
|
||||||
|
if( (dm->size & DM_BLOCK_DEBUG) != DM_BLOCK_DEBUG )
|
||||||
|
{
|
||||||
|
WARN("MCB overrun! [prev = 0x%08x]\n", 4 + (UINT)prev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
prev = dm;
|
||||||
|
#endif
|
||||||
|
if( dm->size & DM_BLOCK_FREE )
|
||||||
|
{
|
||||||
|
dosmem_entry *next = next_block(dm);
|
||||||
|
|
||||||
|
while ( next->size & DM_BLOCK_FREE ) /* collapse free blocks */
|
||||||
|
{
|
||||||
|
dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
|
||||||
|
next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
|
||||||
|
next = next_block(dm);
|
||||||
|
}
|
||||||
|
|
||||||
|
blocksize = dm->size & DM_BLOCK_MASK;
|
||||||
|
if( blocksize >= size )
|
||||||
|
{
|
||||||
|
block = ((char*)dm) + sizeof(dosmem_entry);
|
||||||
|
if( blocksize - size > 0x20 )
|
||||||
|
{
|
||||||
|
/* split dm so that the next one stays
|
||||||
|
* paragraph-aligned (and dm loses free bit) */
|
||||||
|
|
||||||
|
dm->size = (((size + 0xf + sizeof(dosmem_entry)) & ~0xf) -
|
||||||
|
sizeof(dosmem_entry));
|
||||||
|
next = (dosmem_entry*)(((char*)dm) +
|
||||||
|
sizeof(dosmem_entry) + dm->size);
|
||||||
|
next->size = (blocksize - (dm->size +
|
||||||
|
sizeof(dosmem_entry))) | DM_BLOCK_FREE
|
||||||
|
#ifdef __DOSMEM_DEBUG__
|
||||||
|
| DM_BLOCK_DEBUG
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
} else dm->size &= DM_BLOCK_MASK;
|
||||||
|
|
||||||
|
info_block->blocks++;
|
||||||
|
info_block->free -= dm->size;
|
||||||
|
if( pseg ) *pseg = (block - DOSMEM_dosmem) >> 4;
|
||||||
|
#ifdef __DOSMEM_DEBUG__
|
||||||
|
dm->size |= DM_BLOCK_DEBUG;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dm = next;
|
||||||
|
}
|
||||||
|
else dm = next_block(dm);
|
||||||
|
}
|
||||||
|
return (LPVOID)block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* DOSMEM_FreeBlock
|
||||||
|
*/
|
||||||
|
BOOL DOSMEM_FreeBlock(void* ptr)
|
||||||
|
{
|
||||||
|
dosmem_info *info_block = DOSMEM_info_block;
|
||||||
|
|
||||||
|
if( ptr >= (void*)(((char*)DOSMEM_RootBlock()) + sizeof(dosmem_entry)) &&
|
||||||
|
ptr < (void*)DOSMEM_MemoryTop() && !((((char*)ptr)
|
||||||
|
- DOSMEM_dosmem) & 0xf) )
|
||||||
|
{
|
||||||
|
dosmem_entry *dm = (dosmem_entry*)(((char*)ptr) - sizeof(dosmem_entry));
|
||||||
|
|
||||||
|
if( !(dm->size & (DM_BLOCK_FREE | DM_BLOCK_TERMINAL))
|
||||||
|
#ifdef __DOSMEM_DEBUG__
|
||||||
|
&& ((dm->size & DM_BLOCK_DEBUG) == DM_BLOCK_DEBUG )
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
info_block->blocks--;
|
||||||
|
info_block->free += dm->size;
|
||||||
|
|
||||||
|
dm->size |= DM_BLOCK_FREE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
UINT DOSMEM_ResizeBlock(void *ptr, UINT size, BOOL exact)
|
||||||
|
{
|
||||||
|
char *block = NULL;
|
||||||
|
dosmem_info *info_block = DOSMEM_info_block;
|
||||||
|
dosmem_entry *dm;
|
||||||
|
dosmem_entry *next;
|
||||||
|
UINT blocksize;
|
||||||
|
UINT orgsize;
|
||||||
|
|
||||||
|
if( (ptr < (void*)(sizeof(dosmem_entry) + (char*)DOSMEM_RootBlock())) ||
|
||||||
|
(ptr >= (void*)DOSMEM_MemoryTop()) ||
|
||||||
|
(((((char*)ptr) - DOSMEM_dosmem) & 0xf) != 0) )
|
||||||
|
return (UINT)-1;
|
||||||
|
|
||||||
|
dm = (dosmem_entry*)(((char*)ptr) - sizeof(dosmem_entry));
|
||||||
|
if( dm->size & (DM_BLOCK_FREE | DM_BLOCK_TERMINAL) )
|
||||||
|
return (UINT)-1;
|
||||||
|
|
||||||
|
next = next_block(dm);
|
||||||
|
orgsize = dm->size & DM_BLOCK_MASK;
|
||||||
|
|
||||||
|
/* collapse free blocks */
|
||||||
|
while ( next->size & DM_BLOCK_FREE )
|
||||||
|
{
|
||||||
|
dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
|
||||||
|
next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
|
||||||
|
next = next_block(dm);
|
||||||
|
}
|
||||||
|
|
||||||
|
blocksize = dm->size & DM_BLOCK_MASK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If collapse didn't help we either expand block to maximum
|
||||||
|
* available size (exact == FALSE) or give collapsed blocks
|
||||||
|
* back to free storage (exact == TRUE).
|
||||||
|
*/
|
||||||
|
if (blocksize < size)
|
||||||
|
size = exact ? orgsize : blocksize;
|
||||||
|
|
||||||
|
block = ((char*)dm) + sizeof(dosmem_entry);
|
||||||
|
if( blocksize - size > 0x20 )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* split dm so that the next one stays
|
||||||
|
* paragraph-aligned (and next gains free bit)
|
||||||
|
*/
|
||||||
|
|
||||||
|
dm->size = (((size + 0xf + sizeof(dosmem_entry)) & ~0xf) -
|
||||||
|
sizeof(dosmem_entry));
|
||||||
|
next = (dosmem_entry*)(((char*)dm) +
|
||||||
|
sizeof(dosmem_entry) + dm->size);
|
||||||
|
next->size = (blocksize - (dm->size +
|
||||||
|
sizeof(dosmem_entry))) | DM_BLOCK_FREE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dm->size &= DM_BLOCK_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adjust available memory if block size changes.
|
||||||
|
*/
|
||||||
|
info_block->free += orgsize - dm->size;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* DOSMEM_Available
|
||||||
|
*/
|
||||||
|
UINT DOSMEM_Available(void)
|
||||||
|
{
|
||||||
|
UINT blocksize, available = 0;
|
||||||
|
dosmem_entry *dm;
|
||||||
|
|
||||||
|
dm = DOSMEM_RootBlock();
|
||||||
|
|
||||||
|
while (dm && dm->size != DM_BLOCK_TERMINAL)
|
||||||
|
{
|
||||||
|
#ifdef __DOSMEM_DEBUG__
|
||||||
|
if( (dm->size & DM_BLOCK_DEBUG) != DM_BLOCK_DEBUG )
|
||||||
|
{
|
||||||
|
WARN("MCB overrun! [prev = 0x%08x]\n", 4 + (UINT)prev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
prev = dm;
|
||||||
|
#endif
|
||||||
|
if( dm->size & DM_BLOCK_FREE )
|
||||||
|
{
|
||||||
|
dosmem_entry *next = next_block(dm);
|
||||||
|
|
||||||
|
while ( next->size & DM_BLOCK_FREE ) /* collapse free blocks */
|
||||||
|
{
|
||||||
|
dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
|
||||||
|
next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
|
||||||
|
next = next_block(dm);
|
||||||
|
}
|
||||||
|
|
||||||
|
blocksize = dm->size & DM_BLOCK_MASK;
|
||||||
|
if ( blocksize > available ) available = blocksize;
|
||||||
|
dm = next;
|
||||||
|
}
|
||||||
|
else dm = next_block(dm);
|
||||||
|
}
|
||||||
|
return available;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* DOSMEM_InitMemory
|
||||||
|
*
|
||||||
|
* Initialises the DOS memory structures.
|
||||||
|
*/
|
||||||
|
static void DOSMEM_InitMemory(char* addr)
|
||||||
|
{
|
||||||
|
dosmem_entry* root_block;
|
||||||
|
dosmem_entry* dm;
|
||||||
|
|
||||||
|
DOSMEM_FillBiosSegments();
|
||||||
|
DOSMEM_FillIsrTable();
|
||||||
|
|
||||||
|
DOSMEM_info_block = (dosmem_info*)addr;
|
||||||
|
root_block = DOSMEM_RootBlock();
|
||||||
|
root_block->size = DOSMEM_MemoryTop() - (((char*)root_block) + sizeof(dosmem_entry));
|
||||||
|
|
||||||
|
DOSMEM_info_block->blocks = 0;
|
||||||
|
DOSMEM_info_block->free = root_block->size;
|
||||||
|
|
||||||
|
dm = next_block(root_block);
|
||||||
|
dm->size = DM_BLOCK_TERMINAL;
|
||||||
|
root_block->size |= DM_BLOCK_FREE
|
||||||
|
#ifdef __DOSMEM_DEBUG__
|
||||||
|
| DM_BLOCK_DEBUG
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
|
TRACE("DOS conventional memory initialized, %d bytes free.\n",
|
||||||
|
DOSMEM_Available());
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* DOSMEM_InitDosMemory
|
||||||
|
*
|
||||||
|
* When WineDOS is loaded, initializes the current DOS memory layout.
|
||||||
|
*/
|
||||||
|
void DOSMEM_InitDosMemory(void)
|
||||||
|
{
|
||||||
|
HMODULE16 hModule;
|
||||||
|
unsigned short sel;
|
||||||
|
LDT_ENTRY entry;
|
||||||
|
DWORD reserve;
|
||||||
|
|
||||||
|
hModule = GetModuleHandle16("KERNEL");
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
ERR( "Needs access to the first megabyte for DOS mode\n" );
|
||||||
|
ExitProcess(1);
|
||||||
|
}
|
||||||
|
MESSAGE( "Warning: unprotecting memory to allow real-mode calls.\n"
|
||||||
|
" NULL pointer accesses will no longer be caught.\n" );
|
||||||
|
VirtualProtect( NULL, DOSMEM_SIZE, PAGE_EXECUTE_READWRITE, NULL );
|
||||||
|
/* 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;
|
||||||
|
}
|
|
@ -693,26 +693,6 @@ void WINAPI DOSVM_AcknowledgeIRQ( CONTEXT86 *context )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* DOSVM_BiosData
|
|
||||||
*
|
|
||||||
* Get pointer to BIOS data area. This is not at fixed location
|
|
||||||
* because those Win16 programs that do not use any real mode code have
|
|
||||||
* protected NULL pointer catching block at low linear memory and
|
|
||||||
* BIOS data has been moved to another location.
|
|
||||||
*/
|
|
||||||
BIOSDATA *DOSVM_BiosData( void )
|
|
||||||
{
|
|
||||||
LDT_ENTRY entry;
|
|
||||||
FARPROC16 proc;
|
|
||||||
|
|
||||||
proc = GetProcAddress16( GetModuleHandle16( "KERNEL" ),
|
|
||||||
(LPCSTR)(ULONG_PTR)193 );
|
|
||||||
wine_ldt_get_entry( LOWORD(proc), &entry );
|
|
||||||
return (BIOSDATA *)wine_ldt_get_base( &entry );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* DllMain (DOSVM.0)
|
* DllMain (DOSVM.0)
|
||||||
*/
|
*/
|
||||||
|
@ -723,6 +703,7 @@ BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
|
||||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
if (fdwReason == DLL_PROCESS_ATTACH)
|
||||||
{
|
{
|
||||||
DisableThreadLibraryCalls(hinstDLL);
|
DisableThreadLibraryCalls(hinstDLL);
|
||||||
|
DOSMEM_InitDosMemory();
|
||||||
DOSVM_InitSegments();
|
DOSVM_InitSegments();
|
||||||
|
|
||||||
event_notifier = CreateEventW(NULL, FALSE, FALSE, NULL);
|
event_notifier = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||||
|
|
|
@ -4904,7 +4904,7 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context )
|
||||||
selector = LOWORD( rv );
|
selector = LOWORD( rv );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DOSMEM_GetBlock( bytes, &selector );
|
DOSMEM_AllocBlock( bytes, &selector );
|
||||||
|
|
||||||
if (selector)
|
if (selector)
|
||||||
{
|
{
|
||||||
|
@ -4934,7 +4934,7 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context )
|
||||||
context->SegEs = 0;
|
context->SegEs = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ok = DOSMEM_FreeBlock( (void*)((DWORD)context->SegEs << 4) );
|
ok = DOSMEM_FreeBlock( PTR_REAL_TO_LIN(context->SegEs, 0) );
|
||||||
|
|
||||||
if (!ok)
|
if (!ok)
|
||||||
{
|
{
|
||||||
|
|
|
@ -470,7 +470,7 @@ callrmproc_again:
|
||||||
if (!already) {
|
if (!already) {
|
||||||
if (!context->SegSs) {
|
if (!context->SegSs) {
|
||||||
alloc = 1; /* allocate default stack */
|
alloc = 1; /* allocate default stack */
|
||||||
stack16 = addr = DOSMEM_GetBlock( 64, (UINT16 *)&(context->SegSs) );
|
stack16 = addr = DOSMEM_AllocBlock( 64, (UINT16 *)&(context->SegSs) );
|
||||||
context->Esp = 64-2;
|
context->Esp = 64-2;
|
||||||
stack16 += 32-1;
|
stack16 += 32-1;
|
||||||
if (!addr) {
|
if (!addr) {
|
||||||
|
@ -649,7 +649,7 @@ static RMCB *DPMI_AllocRMCB( void )
|
||||||
|
|
||||||
if (NewRMCB)
|
if (NewRMCB)
|
||||||
{
|
{
|
||||||
LPVOID RMCBmem = DOSMEM_GetBlock(4, &uParagraph);
|
LPVOID RMCBmem = DOSMEM_AllocBlock(4, &uParagraph);
|
||||||
LPBYTE p = RMCBmem;
|
LPBYTE p = RMCBmem;
|
||||||
|
|
||||||
*p++ = 0xcd; /* RMCB: */
|
*p++ = 0xcd; /* RMCB: */
|
||||||
|
@ -968,7 +968,7 @@ void WINAPI DOSVM_Int31Handler( CONTEXT86 *context )
|
||||||
|
|
||||||
/* check if Win16 app wants to access lower 64K of DOS memory */
|
/* check if Win16 app wants to access lower 64K of DOS memory */
|
||||||
if (base < 0x10000 && DOSVM_IsWin16())
|
if (base < 0x10000 && DOSVM_IsWin16())
|
||||||
DOSMEM_InitDosMem();
|
DOSMEM_MapDosLayout();
|
||||||
|
|
||||||
SetSelectorBase( sel, base );
|
SetSelectorBase( sel, base );
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,7 +169,7 @@ static WORD MZ_InitEnvironment( LPCSTR env, LPCSTR name )
|
||||||
while (env[sz++]) sz+=strlen(env+sz)+1;
|
while (env[sz++]) sz+=strlen(env+sz)+1;
|
||||||
} else sz++;
|
} else sz++;
|
||||||
/* allocate it */
|
/* allocate it */
|
||||||
envblk=DOSMEM_GetBlock(sz+sizeof(WORD)+strlen(name)+1,&seg);
|
envblk=DOSMEM_AllocBlock(sz+sizeof(WORD)+strlen(name)+1,&seg);
|
||||||
/* fill it */
|
/* fill it */
|
||||||
if (env) {
|
if (env) {
|
||||||
memcpy(envblk,env,sz);
|
memcpy(envblk,env,sz);
|
||||||
|
@ -195,7 +195,7 @@ static BOOL MZ_InitMemory(void)
|
||||||
{
|
{
|
||||||
/* initialize the memory */
|
/* initialize the memory */
|
||||||
TRACE("Initializing DOS memory structures\n");
|
TRACE("Initializing DOS memory structures\n");
|
||||||
DOSMEM_InitDosMem();
|
DOSMEM_MapDosLayout();
|
||||||
DOSDEV_InstallDOSDevices();
|
DOSDEV_InstallDOSDevices();
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -283,7 +283,7 @@ static BOOL MZ_DoLoadImage( HANDLE hFile, LPCSTR filename, OverlayBlock *oblk, W
|
||||||
goto load_error;
|
goto load_error;
|
||||||
}
|
}
|
||||||
if (avail>max_size) avail=max_size;
|
if (avail>max_size) avail=max_size;
|
||||||
psp_start=DOSMEM_GetBlock(avail,&DOSVM_psp);
|
psp_start=DOSMEM_AllocBlock(avail,&DOSVM_psp);
|
||||||
if (!psp_start) {
|
if (!psp_start) {
|
||||||
ERR("error allocating DOS memory\n");
|
ERR("error allocating DOS memory\n");
|
||||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
|
|
@ -6,3 +6,11 @@
|
||||||
# I/O functions
|
# I/O functions
|
||||||
@ stdcall inport(long long) DOSVM_inport
|
@ stdcall inport(long long) DOSVM_inport
|
||||||
@ stdcall outport(long long long) DOSVM_outport
|
@ 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
|
||||||
|
|
||||||
|
# BIOS functions
|
||||||
|
@ cdecl BiosTick(long)
|
||||||
|
|
|
@ -26,83 +26,5 @@
|
||||||
#include <wine/windef16.h>
|
#include <wine/windef16.h>
|
||||||
|
|
||||||
/* msdos/dosmem.c */
|
/* msdos/dosmem.c */
|
||||||
#include <pshpack1.h>
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
WORD Com1Addr; /* 00: COM1 I/O address */
|
|
||||||
WORD Com2Addr; /* 02: COM2 I/O address */
|
|
||||||
WORD Com3Addr; /* 04: COM3 I/O address */
|
|
||||||
WORD Com4Addr; /* 06: COM4 I/O address */
|
|
||||||
WORD Lpt1Addr; /* 08: LPT1 I/O address */
|
|
||||||
WORD Lpt2Addr; /* 0a: LPT2 I/O address */
|
|
||||||
WORD Lpt3Addr; /* 0c: LPT3 I/O address */
|
|
||||||
WORD Lpt4Addr; /* 0e: LPT4 I/O address */
|
|
||||||
WORD InstalledHardware; /* 10: Installed hardware flags */
|
|
||||||
BYTE POSTstatus; /* 12: Power-On Self Test status */
|
|
||||||
WORD MemSize; /* 13: Base memory size in Kb */
|
|
||||||
WORD unused1; /* 15: Manufacturing test scratch pad */
|
|
||||||
BYTE KbdFlags1; /* 17: Keyboard flags 1 */
|
|
||||||
BYTE KbdFlags2; /* 18: Keyboard flags 2 */
|
|
||||||
BYTE unused2; /* 19: Keyboard driver workspace */
|
|
||||||
WORD NextKbdCharPtr; /* 1a: Next character in kbd buffer */
|
|
||||||
WORD FirstKbdCharPtr; /* 1c: First character in kbd buffer */
|
|
||||||
WORD KbdBuffer[16]; /* 1e: Keyboard buffer */
|
|
||||||
BYTE DisketteStatus1; /* 3e: Diskette recalibrate status */
|
|
||||||
BYTE DisketteStatus2; /* 3f: Diskette motor status */
|
|
||||||
BYTE DisketteStatus3; /* 40: Diskette motor timeout */
|
|
||||||
BYTE DisketteStatus4; /* 41: Diskette last operation status */
|
|
||||||
BYTE DiskStatus[7]; /* 42: Disk status/command bytes */
|
|
||||||
BYTE VideoMode; /* 49: Video mode */
|
|
||||||
WORD VideoColumns; /* 4a: Number of columns */
|
|
||||||
WORD VideoPageSize; /* 4c: Video page size in bytes */
|
|
||||||
WORD VideoPageStartAddr; /* 4e: Video page start address */
|
|
||||||
BYTE VideoCursorPos[16]; /* 50: Cursor position for 8 pages, column/row order */
|
|
||||||
WORD VideoCursorType; /* 60: Video cursor type */
|
|
||||||
BYTE VideoCurPage; /* 62: Video current page */
|
|
||||||
WORD VideoCtrlAddr; /* 63: Video controller address */
|
|
||||||
BYTE VideoReg1; /* 65: Video mode select register */
|
|
||||||
BYTE VideoReg2; /* 66: Video CGA palette register */
|
|
||||||
DWORD ResetEntry; /* 67: Warm reset entry point */
|
|
||||||
BYTE LastIRQ; /* 6b: Last unexpected interrupt */
|
|
||||||
DWORD Ticks; /* 6c: Ticks since midnight */
|
|
||||||
BYTE TicksOverflow; /* 70: Timer overflow if past midnight */
|
|
||||||
BYTE CtrlBreakFlag; /* 71: Ctrl-Break flag */
|
|
||||||
WORD ResetFlag; /* 72: POST Reset flag */
|
|
||||||
BYTE DiskOpStatus; /* 74: Last hard-disk operation status */
|
|
||||||
BYTE NbHardDisks; /* 75: Number of hard disks */
|
|
||||||
BYTE DiskCtrlByte; /* 76: Disk control byte */
|
|
||||||
BYTE DiskIOPort; /* 77: Disk I/O port offset */
|
|
||||||
BYTE LptTimeout[4]; /* 78: Timeouts for parallel ports */
|
|
||||||
BYTE ComTimeout[4]; /* 7c: Timeouts for serial ports */
|
|
||||||
WORD KbdBufferStart; /* 80: Keyboard buffer start */
|
|
||||||
WORD KbdBufferEnd; /* 82: Keyboard buffer end */
|
|
||||||
BYTE RowsOnScreenMinus1; /* 84: EGA only */
|
|
||||||
WORD BytesPerChar; /* 85: EGA only */
|
|
||||||
BYTE ModeOptions; /* 87: EGA only */
|
|
||||||
BYTE FeatureBitsSwitches; /* 88: EGA only */
|
|
||||||
BYTE VGASettings; /* 89: VGA misc settings */
|
|
||||||
BYTE DisplayCombination; /* 8A: VGA display combinations */
|
|
||||||
BYTE DiskDataRate; /* 8B: Last disk data rate selected */
|
|
||||||
} BIOSDATA;
|
|
||||||
|
|
||||||
#include <poppack.h>
|
|
||||||
|
|
||||||
extern WORD DOSMEM_0000H;
|
|
||||||
extern WORD DOSMEM_BiosDataSeg;
|
|
||||||
extern WORD DOSMEM_BiosSysSeg;
|
|
||||||
|
|
||||||
/* msdos/dosmem.c */
|
|
||||||
extern BOOL DOSMEM_Init(void);
|
|
||||||
extern BOOL DOSMEM_InitDosMem(void);
|
|
||||||
extern void DOSMEM_Tick(WORD timer);
|
|
||||||
extern WORD DOSMEM_AllocSelector(WORD);
|
|
||||||
extern LPVOID DOSMEM_GetBlock(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 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 */
|
|
||||||
|
|
||||||
#endif /* __WINE_MISCEMU_H */
|
#endif /* __WINE_MISCEMU_H */
|
||||||
|
|
Loading…
Reference in New Issue