[NTVDM]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Mon, 27 Apr 2015 03:37:24 +0000 (03:37 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Mon, 27 Apr 2015 03:37:24 +0000 (03:37 +0000)
- In INT 21h, AH = 0Ah, the final carriage return is not counted.
- Implement XMS function 0Bh (Move Extended Memory Block).
- The driver must preserve the contents of unlocked Extended Memory Blocks (EMBs),
so move the bitmap setting/clearing code into XmsAlloc and XmsFree.
- Make XmsAlloc optimize memory blocks by moving them around, except it can't
move locked blocks.

svn path=/trunk/; revision=67457

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

index ae904a2..9f49650 100644 (file)
@@ -1036,7 +1036,6 @@ VOID WINAPI DosInt21h(LPWORD Stack)
                     {
                         /* Append it to the buffer */
                         InputBuffer->Buffer[Count] = Character;
-                        Count++; /* Carriage returns are also counted */
 
                         /* Check if this is a special character */
                         if (Character < 0x20 && Character != 0x0A && Character != 0x0D)
@@ -1051,10 +1050,11 @@ VOID WINAPI DosInt21h(LPWORD Stack)
                 }
 
                 if (Character == '\r') break;
+                Count++; /* Carriage returns are NOT counted */
             }
 
             /* Update the length */
-            InputBuffer->Length = Count;
+            InputBuffer->Length = Count - 1;
 
             break;
         }
index 816141a..4da96bb 100644 (file)
 /* BOP Identifiers */
 #define BOP_XMS 0x52
 
+ULONG
+NTAPI
+RtlFindLastBackwardRunClear
+(
+    IN PRTL_BITMAP BitMapHeader,
+    IN ULONG FromIndex,
+    OUT PULONG StartingRunIndex
+);
+
 /* PRIVATE VARIABLES **********************************************************/
 
 static const BYTE EntryProcedure[] = {
@@ -180,6 +189,9 @@ static CHAR XmsAlloc(WORD Size, PWORD Handle)
 {
     BYTE i;
     PXMS_HANDLE HandleEntry;
+    DWORD CurrentIndex = 0;
+    ULONG RunStart;
+    ULONG RunSize;
 
     if (Size > FreeBlocks) return XMS_STATUS_OUT_OF_MEMORY;
 
@@ -195,55 +207,43 @@ static CHAR XmsAlloc(WORD Size, PWORD Handle)
 
     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;
+    /* Optimize blocks */
+    for (i = 0; i < XMS_MAX_HANDLES; i++)
+    {
+        /* Skip free and locked blocks */
+        if (HandleEntry->Handle == 0 || HandleEntry->LockCount > 0) continue;
 
-    HandleEntry->Handle = 0;
-    FreeBlocks += HandleEntry->Size;
+        CurrentIndex = (HandleEntry->Address - XMS_ADDRESS) / XMS_BLOCK_SIZE;
 
-    return XMS_STATUS_SUCCESS;
-}
+        /* Check if there is any free space before this block */
+        RunSize = RtlFindLastBackwardRunClear(&AllocBitmap, CurrentIndex, &RunStart);
+        if (RunSize == 0) break;
 
-static CHAR XmsLock(WORD Handle, PDWORD Address)
-{
-    DWORD CurrentIndex = 0;
-    PXMS_HANDLE HandleEntry = GetHandleRecord(Handle);
+        /* Move this block back */
+        RtlMoveMemory((PVOID)REAL_TO_PHYS(HandleEntry->Address - RunSize * XMS_BLOCK_SIZE),
+                      (PVOID)REAL_TO_PHYS(HandleEntry->Address),
+                      RunSize * XMS_BLOCK_SIZE);
 
-    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;
+        /* Update the address */
+        HandleEntry->Address -= RunSize * XMS_BLOCK_SIZE;
     }
 
     while (CurrentIndex < XMS_BLOCKS)
     {
-        ULONG RunStart;
-        ULONG RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart);
+        RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart);
         if (RunSize == 0) break;
 
         if (RunSize >= HandleEntry->Size)
         {
-            /* Lock it here */
-            HandleEntry->LockCount++;
+            /* Allocate it here */
+            HandleEntry->Handle = i + 1;
+            HandleEntry->LockCount = 0;
+            HandleEntry->Size = Size;
             HandleEntry->Address = XMS_ADDRESS + RunStart * XMS_BLOCK_SIZE;
 
+            FreeBlocks -= Size;
             RtlSetBits(&AllocBitmap, RunStart, RunSize);
-            *Address = HandleEntry->Address;
+
             return XMS_STATUS_SUCCESS;
         }
 
@@ -251,24 +251,50 @@ static CHAR XmsLock(WORD Handle, PDWORD Address)
         CurrentIndex = RunStart + RunSize;
     }
 
-    /* Can't find any suitable range */
-    return XMS_STATUS_CANNOT_LOCK;
+    return XMS_STATUS_OUT_OF_MEMORY;
 }
 
-static CHAR XmsUnlock(WORD Handle)
+static CHAR XmsFree(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;
+    if (HandleEntry->LockCount) return XMS_STATUS_LOCKED;
 
     BlockNumber = (HandleEntry->Address - XMS_ADDRESS) / XMS_BLOCK_SIZE;
     RtlClearBits(&AllocBitmap, BlockNumber, HandleEntry->Size);
 
+    HandleEntry->Handle = 0;
+    FreeBlocks += HandleEntry->Size;
+
+    return XMS_STATUS_SUCCESS;
+}
+
+static CHAR XmsLock(WORD Handle, PDWORD Address)
+{
+    PXMS_HANDLE HandleEntry = GetHandleRecord(Handle);
+
+    if (HandleEntry == NULL) return XMS_STATUS_INVALID_HANDLE;
+    if (HandleEntry->LockCount == 0xFF) return XMS_STATUS_LOCK_OVERFLOW;
+
+    /* Increment the lock count */
+    HandleEntry->LockCount++;
+    *Address = HandleEntry->Address;
+
+    return XMS_STATUS_SUCCESS;
+}
+
+static CHAR XmsUnlock(WORD Handle)
+{
+    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 */
+    HandleEntry->LockCount--;
+
     return XMS_STATUS_SUCCESS;
 }
 
@@ -391,6 +417,68 @@ static VOID WINAPI XmsBopProcedure(LPWORD Stack)
             break;
         }
 
+        /* Move Extended Memory Block */
+        case 0x0B:
+        {
+            PVOID SourceAddress, DestAddress;
+            PXMS_COPY_DATA CopyData = (PXMS_COPY_DATA)SEG_OFF_TO_PTR(getDS(), getSI());
+
+            if (CopyData->SourceHandle)
+            {
+                PXMS_HANDLE Entry = GetHandleRecord(CopyData->SourceHandle);
+                if (!Entry)
+                {
+                    setAX(0);
+                    setBL(XMS_STATUS_BAD_SRC_HANDLE);
+                    break;
+                }
+
+                if (CopyData->SourceOffset >= Entry->Size * XMS_BLOCK_SIZE)
+                {
+                    setAX(0);
+                    setBL(XMS_STATUS_BAD_SRC_OFFSET);
+                }
+
+                SourceAddress = (PVOID)REAL_TO_PHYS(Entry->Address + CopyData->SourceOffset);
+            }
+            else
+            {
+                /* The offset is actually a 16-bit segment:offset pointer */
+                SourceAddress = SEG_OFF_TO_PTR(HIWORD(CopyData->SourceOffset),
+                                               LOWORD(CopyData->SourceOffset));
+            }
+
+            if (CopyData->DestHandle)
+            {
+                PXMS_HANDLE Entry = GetHandleRecord(CopyData->DestHandle);
+                if (!Entry)
+                {
+                    setAX(0);
+                    setBL(XMS_STATUS_BAD_DEST_HANDLE);
+                    break;
+                }
+
+                if (CopyData->DestOffset >= Entry->Size * XMS_BLOCK_SIZE)
+                {
+                    setAX(0);
+                    setBL(XMS_STATUS_BAD_DEST_OFFSET);
+                }
+
+                DestAddress = (PVOID)REAL_TO_PHYS(Entry->Address + CopyData->DestOffset);
+            }
+            else
+            {
+                /* The offset is actually a 16-bit segment:offset pointer */
+                DestAddress = SEG_OFF_TO_PTR(HIWORD(CopyData->DestOffset),
+                                             LOWORD(CopyData->DestOffset));
+            }
+
+            setAX(1);
+            setBL(XMS_STATUS_SUCCESS);
+            RtlMoveMemory(DestAddress, SourceAddress, CopyData->Count);
+            break;
+        }
+
         /* Lock Extended Memory Block */
         case 0x0C:
         {
index 142de4a..fb66135 100644 (file)
 #define XMS_STATUS_OUT_OF_MEMORY   0xA0
 #define XMS_STATUS_OUT_OF_HANDLES  0xA1
 #define XMS_STATUS_INVALID_HANDLE  0xA2
+#define XMS_STATUS_BAD_SRC_HANDLE  0xA3
+#define XMS_STATUS_BAD_DEST_HANDLE 0xA4
+#define XMS_STATUS_BAD_SRC_OFFSET  0xA5
+#define XMS_STATUS_BAD_DEST_OFFSET 0xA6
 #define XMS_STATUS_NOT_LOCKED      0xAA
 #define XMS_STATUS_LOCKED          0xAB
 #define XMS_STATUS_LOCK_OVERFLOW   0xAC
@@ -33,6 +37,17 @@ typedef struct _XMS_HANDLE
     DWORD Address;
 } XMS_HANDLE, *PXMS_HANDLE;
 
+#pragma pack(push, 1)
+typedef struct _XMS_COPY_DATA
+{
+    DWORD Count;
+    WORD SourceHandle;
+    DWORD SourceOffset;
+    WORD DestHandle;
+    DWORD DestOffset;
+} XMS_COPY_DATA, *PXMS_COPY_DATA;
+#pragma pack(pop)
+
 /* FUNCTIONS ******************************************************************/
 
 BOOLEAN XmsGetDriverEntry(PDWORD Pointer);