[NTVDM]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Wed, 22 Apr 2015 03:10:11 +0000 (03:10 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Wed, 22 Apr 2015 03:10:11 +0000 (03:10 +0000)
Implement basic XMS functions.

svn path=/trunk/; revision=67340

reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.c
reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.h

index e40070d..c8c52f3 100644 (file)
@@ -17,6 +17,7 @@
 #include "dos.h"
 #include "dos/dem.h"
 #include "device.h"
+#include "himem.h"
 
 #define XMS_DEVICE_NAME "XMSXXXX0"
 #define XMS_BOP 0x52
@@ -36,9 +37,117 @@ static const BYTE EntryProcedure[] = {
 };
 
 static PDOS_DEVICE_NODE Node = NULL;
+static XMS_HANDLE HandleTable[XMS_MAX_HANDLES];
+static WORD FreeBlocks = XMS_BLOCKS;
+static RTL_BITMAP AllocBitmap;
+static ULONG BitmapBuffer[(XMS_BLOCKS + 31) / 32];
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
+static inline PXMS_HANDLE GetHandleRecord(WORD Handle)
+{
+    PXMS_HANDLE Entry = &HandleTable[Handle - 1];
+    if (Handle == 0 || Handle >= XMS_MAX_HANDLES) return NULL;
+
+    return Entry->Size ? Entry : NULL;
+}
+
+static CHAR XmsAlloc(WORD Size, PWORD Handle)
+{
+    BYTE i;
+    PXMS_HANDLE HandleEntry;
+
+    if (Size > FreeBlocks) return XMS_STATUS_OUT_OF_MEMORY;
+
+    for (i = 0; i < XMS_MAX_HANDLES; i++)
+    {
+        HandleEntry = &HandleTable[i];
+        if (HandleEntry->Handle == 0)
+        {
+            *Handle = i + 1;
+            break;
+        }
+    }
+
+    if (i == XMS_MAX_HANDLES) return XMS_STATUS_OUT_OF_HANDLES;
+
+    HandleEntry->Handle = i + 1;
+    HandleEntry->LockCount = 0;
+    HandleEntry->Size = Size;
+    FreeBlocks -= Size;
+
+    return XMS_STATUS_SUCCESS;
+}
+
+static CHAR XmsFree(WORD Handle)
+{
+    PXMS_HANDLE HandleEntry = GetHandleRecord(Handle);
+    if (HandleEntry == NULL) return XMS_STATUS_INVALID_HANDLE;
+    if (HandleEntry->LockCount) return XMS_STATUS_LOCKED;
+
+    HandleEntry->Handle = 0;
+    FreeBlocks += HandleEntry->Size;
+
+    return XMS_STATUS_SUCCESS;
+}
+
+static CHAR XmsLock(WORD Handle, PDWORD Address)
+{
+    DWORD CurrentIndex = 0;
+    PXMS_HANDLE HandleEntry = GetHandleRecord(Handle);
+
+    if (HandleEntry == NULL) return XMS_STATUS_INVALID_HANDLE;
+    if (HandleEntry->LockCount == 0xFF) return XMS_STATUS_LOCK_OVERFLOW;
+
+    if (HandleEntry->LockCount)
+    {
+        /* Just increment the lock count */
+        HandleEntry->LockCount++;
+        return XMS_STATUS_SUCCESS;
+    }
+
+    while (CurrentIndex < XMS_BLOCKS)
+    {
+        ULONG RunStart;
+        ULONG RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart);
+        if (RunSize == 0) break;
+
+        if (RunSize >= HandleEntry->Size)
+        {
+            /* Lock it here */
+            HandleEntry->LockCount++;
+            HandleEntry->Address = XMS_ADDRESS + RunStart * XMS_BLOCK_SIZE;
+
+            RtlSetBits(&AllocBitmap, RunStart, RunSize);
+            *Address = HandleEntry->Address;
+            return XMS_STATUS_SUCCESS;
+        }
+
+        /* Keep searching */
+        CurrentIndex = RunStart + RunSize;
+    }
+
+    /* Can't find any suitable range */
+    return XMS_STATUS_CANNOT_LOCK;
+}
+
+static CHAR XmsUnlock(WORD Handle)
+{
+    DWORD BlockNumber;
+    PXMS_HANDLE HandleEntry = GetHandleRecord(Handle);
+
+    if (HandleEntry == NULL) return XMS_STATUS_INVALID_HANDLE;
+    if (!HandleEntry->LockCount) return XMS_STATUS_NOT_LOCKED;
+
+    /* Decrement the lock count and exit early if it's still locked */
+    if (--HandleEntry->LockCount) return XMS_STATUS_SUCCESS;
+
+    BlockNumber = (HandleEntry->Address - XMS_ADDRESS) / XMS_BLOCK_SIZE;
+    RtlClearBits(&AllocBitmap, BlockNumber, HandleEntry->Size);
+
+    return XMS_STATUS_SUCCESS;
+}
+
 static VOID WINAPI XmsBopProcedure(LPWORD Stack)
 {
     switch (getAH())
@@ -52,9 +161,85 @@ static VOID WINAPI XmsBopProcedure(LPWORD Stack)
             break;
         }
 
+        /* Query Free Extended Memory */
+        case 0x08:
+        {
+            setAX(FreeBlocks);
+            setDX(XMS_BLOCKS);
+            setBL(XMS_STATUS_SUCCESS);
+
+            break;
+        }
+
+        /* Allocate Extended Memory Block */
+        case 0x09:
+        {
+            WORD Handle;
+            CHAR Result = XmsAlloc(getDX(), &Handle);
+
+            if (Result >= 0)
+            {
+                setAX(1);
+                setDX(Handle);
+            }
+            else
+            {
+                setAX(0);
+                setBL(Result);
+            }
+
+            break;
+        }
+
+        /* Free Extended Memory Block */
+        case 0x0A:
+        {
+            CHAR Result = XmsFree(getDX());
+
+            setAX(Result >= 0);
+            setBL(Result);
+
+            break;
+        }
+
+        /* Lock Extended Memory Block */
+        case 0x0C:
+        {
+            DWORD Address;
+            CHAR Result = XmsLock(getDX(), &Address);
+
+            if (Result >= 0)
+            {
+                setAX(1);
+
+                /* Store the LINEAR address in DX:BX */
+                setDX(HIWORD(Address));
+                setBX(LOWORD(Address));
+            }
+            else
+            {
+                setAX(0);
+                setBL(Result);
+            }
+
+            break;
+        }
+
+        /* Unlock Extended Memory Block */
+        case 0x0D:
+        {
+            CHAR Result = XmsUnlock(getDX());
+
+            setAX(Result >= 0);
+            setBL(Result);
+
+            break;
+        }
+
         default:
         {
             DPRINT1("XMS command AH = 0x%02X NOT IMPLEMENTED\n", getAH());
+            setBL(XMS_STATUS_NOT_IMPLEMENTED);
         }
     }
 }
@@ -70,6 +255,10 @@ BOOLEAN XmsGetDriverEntry(PDWORD Pointer)
 
 VOID XmsInitialize(VOID)
 {
+    RtlZeroMemory(HandleTable, sizeof(HandleTable));
+    RtlZeroMemory(BitmapBuffer, sizeof(BitmapBuffer));
+    RtlInitializeBitMap(&AllocBitmap, BitmapBuffer, XMS_BLOCKS);
+
     Node = DosCreateDeviceEx(DOS_DEVATTR_IOCTL | DOS_DEVATTR_CHARACTER,
                              XMS_DEVICE_NAME,
                              sizeof(EntryProcedure));
index 09a7465..bfb1a8a 100644 (file)
@@ -6,6 +6,32 @@
  * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  */
 
+/* DEFINITIONS ****************************************************************/
+
+#define XMS_ADDRESS     0x110000
+#define XMS_BLOCKS      0x37C0
+#define XMS_BLOCK_SIZE  1024
+#define XMS_MAX_HANDLES 16
+
+#define XMS_STATUS_SUCCESS         0x00
+#define XMS_STATUS_NOT_IMPLEMENTED 0x80
+#define XMS_STATUS_HMA_IN_USE      0x91
+#define XMS_STATUS_OUT_OF_MEMORY   0xA0
+#define XMS_STATUS_OUT_OF_HANDLES  0xA1
+#define XMS_STATUS_INVALID_HANDLE  0xA2
+#define XMS_STATUS_NOT_LOCKED      0xAA
+#define XMS_STATUS_LOCKED          0xAB
+#define XMS_STATUS_LOCK_OVERFLOW   0xAC
+#define XMS_STATUS_CANNOT_LOCK     0xAD
+
+typedef struct _XMS_HANDLE
+{
+    BYTE Handle;
+    BYTE LockCount;
+    WORD Size;
+    DWORD Address;
+} XMS_HANDLE, *PXMS_HANDLE;
+
 /* FUNCTIONS ******************************************************************/
 
 BOOLEAN XmsGetDriverEntry(PDWORD Pointer);