[NTVDM]: EMS functions.

- Implement function 4Dh "Get All Handles Number of Pages", 54h "Get Handle Directory / Search for Named Handle / Get Total Number of Handles"
- Fix the return error of few functions.
- Start handling the "system handle" (special handle 0; see the specs for more details); WIP.

svn path=/trunk/; revision=68601
This commit is contained in:
Hermès Bélusca-Maïto
2015-08-05 19:06:58 +00:00
parent f4853ceb55
commit 97b7898dfe
2 changed files with 248 additions and 36 deletions
@@ -27,6 +27,7 @@
#define EMS_DEVICE_NAME "EMMXXXX0"
#define EMS_SEGMENT_SIZE ((EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE) >> 4)
#define EMS_SYSTEM_HANDLE 0
/* PRIVATE VARIABLES **********************************************************/
@@ -45,9 +46,9 @@ static USHORT EmsSegment = EMS_SEGMENT;
static VOID InitHandlesTable(VOID)
{
ULONG i;
USHORT i;
for (i = 0; i < EMS_MAX_HANDLES; i++)
for (i = 0; i < ARRAYSIZE(HandleTable); i++)
{
HandleTable[i].Allocated = FALSE;
HandleTable[i].PageCount = 0;
@@ -59,22 +60,21 @@ static VOID InitHandlesTable(VOID)
static PEMS_HANDLE CreateHandle(PUSHORT Handle)
{
PEMS_HANDLE HandleEntry;
ULONG i;
USHORT i;
for (i = 0; i < EMS_MAX_HANDLES; i++)
/* Handle 0 is reserved (system handle) */
for (i = 1; i < ARRAYSIZE(HandleTable); i++)
{
HandleEntry = &HandleTable[i];
if (!HandleEntry->Allocated)
{
*Handle = i;
break;
HandleEntry->Allocated = TRUE;
return HandleEntry;
}
}
if (i == EMS_MAX_HANDLES) return NULL;
HandleEntry->Allocated = TRUE;
return HandleEntry;
return NULL;
}
static VOID FreeHandle(PEMS_HANDLE HandleEntry)
@@ -82,12 +82,12 @@ static VOID FreeHandle(PEMS_HANDLE HandleEntry)
HandleEntry->Allocated = FALSE;
HandleEntry->PageCount = 0;
RtlZeroMemory(HandleEntry->Name, sizeof(HandleEntry->Name));
// InitializeListHead(HandleEntry->PageList);
// InitializeListHead(&HandleEntry->PageList);
}
static inline PEMS_HANDLE GetHandleRecord(USHORT Handle)
{
if (Handle >= EMS_MAX_HANDLES) return NULL;
if (Handle >= ARRAYSIZE(HandleTable)) return NULL;
return &HandleTable[Handle];
}
@@ -116,7 +116,9 @@ static UCHAR EmsFree(USHORT Handle)
}
InitializeListHead(&HandleEntry->PageList);
FreeHandle(HandleEntry);
if (Handle != EMS_SYSTEM_HANDLE)
FreeHandle(HandleEntry);
return EMS_STATUS_SUCCESS;
}
@@ -162,6 +164,57 @@ static UCHAR EmsAlloc(USHORT NumPages, PUSHORT Handle)
return EMS_STATUS_SUCCESS;
}
static UCHAR InitSystemHandle(USHORT NumPages)
{
//
// FIXME: This is an adapted copy of EmsAlloc!!
//
ULONG i, CurrentIndex = 0;
PEMS_HANDLE HandleEntry = &HandleTable[EMS_SYSTEM_HANDLE];
/* The system handle must never have been initialized before */
ASSERT(!HandleEntry->Allocated);
/* Now allocate it */
HandleEntry->Allocated = TRUE;
while (HandleEntry->PageCount < NumPages)
{
ULONG RunStart;
ULONG RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart);
if (RunSize == 0)
{
/* Free what's been allocated already and report failure */
EmsFree(EMS_SYSTEM_HANDLE);
// FIXME: For this function (and EmsAlloc as well),
// use instead an internal function that just uses
// PEMS_HANDLE pointers instead. It's only in the
// EMS interrupt handler that we should do the
// unfolding.
return EMS_STATUS_INSUFFICIENT_PAGES;
}
else if ((HandleEntry->PageCount + RunSize) > NumPages)
{
/* We don't need the entire run */
RunSize = NumPages - HandleEntry->PageCount;
}
CurrentIndex = RunStart + RunSize;
HandleEntry->PageCount += RunSize;
RtlSetBits(&AllocBitmap, RunStart, RunSize);
for (i = 0; i < RunSize; i++)
{
PageTable[RunStart + i].Handle = EMS_SYSTEM_HANDLE;
InsertTailList(&HandleEntry->PageList, &PageTable[RunStart + i].Entry);
}
}
return EMS_STATUS_SUCCESS;
}
static PEMS_PAGE GetLogicalPage(PEMS_HANDLE HandleEntry, USHORT LogicalPage)
{
PLIST_ENTRY Entry = HandleEntry->PageList.Flink;
@@ -236,8 +289,10 @@ static VOID WINAPI EmsIntHandler(LPWORD Stack)
USHORT Handle;
UCHAR Status = EmsAlloc(getBX(), &Handle);
if (Status == EMS_STATUS_SUCCESS)
setDX(Handle);
setAH(Status);
if (Status == EMS_STATUS_SUCCESS) setDX(Handle);
break;
}
@@ -266,14 +321,18 @@ static VOID WINAPI EmsIntHandler(LPWORD Stack)
/* Save Page Map */
case 0x47:
{
// FIXME: This depends on an EMS handle given in DX
RtlCopyMemory(MappingBackup, Mapping, sizeof(Mapping));
setAH(EMS_STATUS_SUCCESS);
break;
}
/* Restore Page Map */
case 0x48:
{
// FIXME: This depends on an EMS handle given in DX
RtlCopyMemory(Mapping, MappingBackup, sizeof(Mapping));
setAH(EMS_STATUS_SUCCESS);
break;
}
@@ -281,9 +340,9 @@ static VOID WINAPI EmsIntHandler(LPWORD Stack)
case 0x4B:
{
USHORT NumOpenHandles = 0;
ULONG i;
USHORT i;
for (i = 0; i < EMS_MAX_HANDLES; i++)
for (i = 0; i < ARRAYSIZE(HandleTable); i++)
{
if (HandleTable[i].Allocated)
++NumOpenHandles;
@@ -310,6 +369,29 @@ static VOID WINAPI EmsIntHandler(LPWORD Stack)
break;
}
/* Get All Handles Number of Pages */
case 0x4D:
{
PEMS_HANDLE_PAGE_INFO HandlePageInfo = (PEMS_HANDLE_PAGE_INFO)SEG_OFF_TO_PTR(getES(), getDI());
USHORT NumOpenHandles = 0;
USHORT i;
for (i = 0; i < ARRAYSIZE(HandleTable); i++)
{
if (HandleTable[i].Allocated)
{
HandlePageInfo->Handle = i;
HandlePageInfo->PageCount = HandleTable[i].PageCount;
++HandlePageInfo;
++NumOpenHandles;
}
}
setAH(EMS_STATUS_SUCCESS);
setBX(NumOpenHandles);
break;
}
/* Get/Set Handle Name */
case 0x53:
{
@@ -340,7 +422,99 @@ static VOID WINAPI EmsIntHandler(LPWORD Stack)
else
{
DPRINT1("Invalid subfunction %02X for EMS function AH = 53h\n", getAL());
setAH(EMS_STATUS_UNKNOWN_FUNCTION);
setAH(EMS_STATUS_INVALID_SUBFUNCTION);
}
break;
}
/* Handle Directory functions */
case 0x54:
{
if (getAL() == 0x00)
{
/* Get Handle Directory */
PEMS_HANDLE_DIR_ENTRY HandleDir = (PEMS_HANDLE_DIR_ENTRY)SEG_OFF_TO_PTR(getES(), getDI());
USHORT NumOpenHandles = 0;
USHORT i;
for (i = 0; i < ARRAYSIZE(HandleTable); i++)
{
if (HandleTable[i].Allocated)
{
HandleDir->Handle = i;
RtlCopyMemory(HandleDir->Name,
HandleTable[i].Name,
sizeof(HandleDir->Name));
++HandleDir;
++NumOpenHandles;
}
}
setAH(EMS_STATUS_SUCCESS);
setAL((UCHAR)NumOpenHandles);
}
else if (getAL() == 0x01)
{
/* Search for Named Handle */
PUCHAR HandleName = (PUCHAR)SEG_OFF_TO_PTR(getDS(), getSI());
PEMS_HANDLE HandleFound = NULL;
USHORT i;
for (i = 0; i < ARRAYSIZE(HandleTable); i++)
{
if (HandleTable[i].Allocated &&
RtlCompareMemory(HandleName,
HandleTable[i].Name,
sizeof(HandleTable[i].Name)) != 0)
{
HandleFound = &HandleTable[i];
break;
}
}
/* Bail out if no handle was found */
if (i >= ARRAYSIZE(HandleTable)) // HandleFound == NULL
{
setAH(EMS_STATUS_HANDLE_NOT_FOUND);
break;
}
/* Return the handle number */
setDX(i);
/* Sanity check: Check whether the handle was unnamed */
i = 0;
while ((i < sizeof(HandleFound->Name)) && (HandleFound->Name[i] == '\0'))
++i;
if (i >= sizeof(HandleFound->Name))
{
setAH(EMS_STATUS_UNNAMED_HANDLE);
}
else
{
setAH(EMS_STATUS_SUCCESS);
}
}
else if (getAL() == 0x02)
{
/*
* Get Total Number of Handles
*
* This function retrieves the maximum number of handles
* (allocated or not) the memory manager supports, which
* a program may request.
*/
setAH(EMS_STATUS_SUCCESS);
setBX(ARRAYSIZE(HandleTable));
}
else
{
DPRINT1("Invalid subfunction %02X for EMS function AH = 54h\n", getAL());
setAH(EMS_STATUS_INVALID_SUBFUNCTION);
}
break;
@@ -436,15 +610,14 @@ static VOID WINAPI EmsIntHandler(LPWORD Stack)
{
if (getAL() == 0x00)
{
PEMS_MAPPABLE_PHYS_PAGE PageArray = (PEMS_MAPPABLE_PHYS_PAGE)SEG_OFF_TO_PTR(getES(), getDI());
ULONG i;
WORD Offset = getDI();
for (i = 0; i < EMS_PHYSICAL_PAGES; i++)
{
*(PWORD)SEG_OFF_TO_PTR(getES(), Offset++) =
EMS_SEGMENT + i * (EMS_PAGE_SIZE >> 4);
*(PWORD)SEG_OFF_TO_PTR(getES(), Offset++) = i;
PageArray->PageSegment = EMS_SEGMENT + i * (EMS_PAGE_SIZE >> 4);
PageArray->PageNumber = i;
++PageArray;
}
setAH(EMS_STATUS_SUCCESS);
@@ -458,7 +631,7 @@ static VOID WINAPI EmsIntHandler(LPWORD Stack)
else
{
DPRINT1("Invalid subfunction %02X for EMS function AH = 58h\n", getAL());
setAH(EMS_STATUS_UNKNOWN_FUNCTION);
setAH(EMS_STATUS_INVALID_SUBFUNCTION);
}
break;
@@ -490,7 +663,7 @@ static VOID WINAPI EmsIntHandler(LPWORD Stack)
else
{
DPRINT1("Invalid subfunction %02X for EMS function AH = 59h\n", getAL());
setAH(EMS_STATUS_UNKNOWN_FUNCTION);
setAH(EMS_STATUS_INVALID_SUBFUNCTION);
}
break;
@@ -601,15 +774,32 @@ BOOLEAN EmsDrvInitialize(USHORT Segment, ULONG TotalPages)
return FALSE;
}
InitHandlesTable();
/*
* FIXME: We should ensure that the system handle is associated
* with mapped pages from conventional memory. DosEmu seems to do
* it correctly. 384kB of memory mapped.
*/
if (InitSystemHandle(384/16) != EMS_STATUS_SUCCESS)
{
DPRINT1("Impossible to allocate pages for the system handle!\n");
RtlFreeHeap(RtlGetProcessHeap(), 0, EmsMemory);
EmsMemory = NULL;
RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable);
PageTable = NULL;
RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer);
BitmapBuffer = NULL;
UmaDescRelease(EmsSegment);
return FALSE;
}
MemInstallFastMemoryHook((PVOID)TO_LINEAR(EmsSegment, 0),
EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE,
EmsReadMemory,
EmsWriteMemory);
// FIXME: The EMS driver MUST automatically initialize handle 0x0000
// (operating system handle) as per the specification says!
InitHandlesTable();
/* Create the device */
Node = DosCreateDeviceEx(DOS_DEVATTR_IOCTL | DOS_DEVATTR_CHARACTER,
EMS_DEVICE_NAME,
@@ -23,15 +23,19 @@
/* 16 MB of EMS memory */
#define EMS_TOTAL_PAGES 1024
#define EMS_STATUS_SUCCESS 0x00
#define EMS_STATUS_INTERNAL_ERROR 0x80
#define EMS_STATUS_INVALID_HANDLE 0x83
#define EMS_STATUS_NO_MORE_HANDLES 0x85
#define EMS_STATUS_INSUFFICIENT_PAGES 0x88
#define EMS_STATUS_ZERO_PAGES 0x89
#define EMS_STATUS_INV_LOGICAL_PAGE 0x8A
#define EMS_STATUS_INV_PHYSICAL_PAGE 0x8B
#define EMS_STATUS_UNKNOWN_FUNCTION 0x8F
#define EMS_STATUS_SUCCESS 0x00
#define EMS_STATUS_INTERNAL_ERROR 0x80
#define EMS_STATUS_INVALID_HANDLE 0x83
#define EMS_STATUS_UNKNOWN_FUNCTION 0x84
#define EMS_STATUS_NO_MORE_HANDLES 0x85
#define EMS_STATUS_INSUFFICIENT_PAGES 0x88
#define EMS_STATUS_ZERO_PAGES 0x89
#define EMS_STATUS_INV_LOGICAL_PAGE 0x8A
#define EMS_STATUS_INV_PHYSICAL_PAGE 0x8B
#define EMS_STATUS_INVALID_SUBFUNCTION 0x8F
#define EMS_STATUS_HANDLE_NOT_FOUND 0xA0
#define EMS_STATUS_UNNAMED_HANDLE 0xA1
#define EMS_STATUS_HANDLE_ALREADY_EXISTS 0xA1
typedef struct _EMS_HANDLE
{
@@ -49,6 +53,18 @@ typedef struct _EMS_PAGE
#pragma pack(push, 1)
typedef struct _EMS_HANDLE_PAGE_INFO
{
USHORT Handle;
USHORT PageCount;
} EMS_HANDLE_PAGE_INFO, *PEMS_HANDLE_PAGE_INFO;
typedef struct _EMS_HANDLE_DIR_ENTRY
{
USHORT Handle;
UCHAR Name[8];
} EMS_HANDLE_DIR_ENTRY, *PEMS_HANDLE_DIR_ENTRY;
typedef struct _EMS_COPY_DATA
{
ULONG RegionLength;
@@ -62,6 +78,12 @@ typedef struct _EMS_COPY_DATA
USHORT DestSegment;
} EMS_COPY_DATA, *PEMS_COPY_DATA;
typedef struct _EMS_MAPPABLE_PHYS_PAGE
{
USHORT PageSegment;
USHORT PageNumber;
} EMS_MAPPABLE_PHYS_PAGE, *PEMS_MAPPABLE_PHYS_PAGE;
typedef struct _EMS_HARDWARE_INFO
{
WORD RawPageSize;