Author: hbelusca
Date: Wed Aug  5 19:06:58 2015
New Revision: 68601
URL: 
http://svn.reactos.org/svn/reactos?rev=68601&view=rev
Log:
[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.
Modified:
    trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c
    trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.h
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c  [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c  [iso-8859-1] Wed Aug  5
19:06:58 2015
@@ -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 VOID InitHandlesTable(VOID)
 {
-    ULONG i;
-
-    for (i = 0; i < EMS_MAX_HANDLES; i++)
+    USHORT i;
+
+    for (i = 0; i < ARRAYSIZE(HandleTable); i++)
     {
         HandleTable[i].Allocated = FALSE;
         HandleTable[i].PageCount = 0;
@@ -59,22 +60,21 @@
 static PEMS_HANDLE CreateHandle(PUSHORT Handle)
 {
     PEMS_HANDLE HandleEntry;
-    ULONG i;
-
-    for (i = 0; i < EMS_MAX_HANDLES; i++)
+    USHORT i;
+
+    /* Handle 0 is reserved (system handle) */
+    for (i = 1; i < ARRAYSIZE(HandleTable); i++)
     {
         HandleEntry = &HandleTable[i];
         if (!HandleEntry->Allocated)
         {
             *Handle = i;
-            break;
-        }
-    }
-
-    if (i == EMS_MAX_HANDLES) return NULL;
-    HandleEntry->Allocated = TRUE;
-
-    return HandleEntry;
+            HandleEntry->Allocated = TRUE;
+            return HandleEntry;
+        }
+    }
+
+    return NULL;
 }
 static VOID FreeHandle(PEMS_HANDLE HandleEntry)
@@ -82,12 +82,12 @@
     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 @@
     }
     InitializeListHead(&HandleEntry->PageList);
-    FreeHandle(HandleEntry);
+
+    if (Handle != EMS_SYSTEM_HANDLE)
+        FreeHandle(HandleEntry);
     return EMS_STATUS_SUCCESS;
 }
@@ -162,6 +164,57 @@
     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 @@
             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 @@
         /* 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 @@
         case 0x4B:
         {
             USHORT NumOpenHandles = 0;
-            ULONG i;
-
-            for (i = 0; i < EMS_MAX_HANDLES; i++)
+            USHORT i;
+
+            for (i = 0; i < ARRAYSIZE(HandleTable); i++)
             {
                 if (HandleTable[i].Allocated)
                     ++NumOpenHandles;
@@ -307,6 +366,29 @@
             setAH(EMS_STATUS_SUCCESS);
             setBX(HandleEntry->PageCount);
+            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;
         }
@@ -340,7 +422,99 @@
             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 @@
         {
             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 @@
             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 @@
             else
             {
                 DPRINT1("Invalid subfunction %02X for EMS function AH = 59h\n",
getAL());
-                setAH(EMS_STATUS_UNKNOWN_FUNCTION);
+                setAH(EMS_STATUS_INVALID_SUBFUNCTION);
             }
             break;
@@ -601,14 +774,31 @@
         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,
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.h  [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.h  [iso-8859-1] Wed Aug  5
19:06:58 2015
@@ -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 @@
 #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;
@@ -61,6 +77,12 @@
     USHORT DestOffset;
     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
 {