From 97b7898dfe07c6955d508be96ef99eb1d6aaca98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Wed, 5 Aug 2015 19:06:58 +0000 Subject: [PATCH] [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 --- .../mvdm/ntvdm/dos/dos32krnl/emsdrv.c | 244 ++++++++++++++++-- .../mvdm/ntvdm/dos/dos32krnl/emsdrv.h | 40 ++- 2 files changed, 248 insertions(+), 36 deletions(-) diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c index a4861b3e812..cc3a9764dea 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c @@ -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, diff --git a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.h b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.h index 3789fb406e3..9156956a1de 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.h +++ b/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.h @@ -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;