[NTVDM]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Thu, 18 Jul 2013 11:44:06 +0000 (11:44 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Thu, 18 Jul 2013 11:44:06 +0000 (11:44 +0000)
Implement Upper Memory Blocks (UMB) support.

svn path=/branches/ntvdm/; revision=59501

subsystems/ntvdm/bios.h
subsystems/ntvdm/dos.c
subsystems/ntvdm/dos.h

index 99a6371..5c6508f 100644 (file)
@@ -16,7 +16,7 @@
 /* DEFINES ********************************************************************/
 
 #define CONSOLE_VIDEO_MEM_END 0xBFFFF
-#define ROM_AREA_START 0xC0000
+#define ROM_AREA_START 0xE0000
 #define ROM_AREA_END 0xFFFFF
 #define BDA_SEGMENT 0x40
 #define BIOS_PIC_MASTER_INT 0x08
index d89c8c2..a9d63f7 100644 (file)
@@ -18,6 +18,7 @@ static WORD CurrentPsp = SYSTEM_PSP;
 static DWORD DiskTransferArea;
 static HANDLE DosSystemFileTable[DOS_SFT_SIZE];
 static WORD DosSftRefCount[DOS_SFT_SIZE];
+static BOOLEAN DosUmbLinked = FALSE;
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
@@ -397,6 +398,60 @@ BOOLEAN DosFreeMemory(WORD BlockData)
     return TRUE;
 }
 
+BOOLEAN DosLinkUmb()
+{
+    DWORD Segment = FIRST_MCB_SEGMENT;
+    PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment);
+
+    /* Check if UMBs are already linked */
+    if (DosUmbLinked) return FALSE;
+
+    /* Find the last block */
+    while ((Mcb->BlockType == 'M') && (Segment <= 0xFFFF))
+    {
+        Segment += Mcb->Size + 1;
+        Mcb = SEGMENT_TO_MCB(Segment);
+    }
+
+    /* Make sure it's valid */
+    if (Mcb->BlockType != 'Z') return FALSE;
+
+    /* Connect the MCB with the UMB chain */
+    Mcb->BlockType = 'M';
+
+    DosUmbLinked = TRUE;
+    return TRUE;
+}
+
+BOOLEAN DosUnlinkUmb()
+{
+    DWORD Segment = FIRST_MCB_SEGMENT;
+    PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment);
+
+    /* Check if UMBs are already unlinked */
+    if (!DosUmbLinked) return FALSE;
+
+    /* Find the block preceding the MCB that links it with the UMB chain */
+    while (Segment <= 0xFFFF)
+    {
+        if ((Segment + Mcb->Size) == (FIRST_MCB_SEGMENT + USER_MEMORY_SIZE))
+        {
+            /* This is the last non-UMB segment */
+            break;
+        }
+
+        /* Advance to the next MCB */
+        Segment += Mcb->Size + 1;
+        Mcb = SEGMENT_TO_MCB(Segment);
+    }
+
+    /* Mark the MCB as the last MCB */
+    Mcb->BlockType = 'Z';
+
+    DosUmbLinked = FALSE;
+    return TRUE;
+}
+
 WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes)
 {
     HANDLE FileHandle;
@@ -1412,7 +1467,11 @@ VOID DosInt21h(WORD CodeSegment)
             {
                 EmulatorClearFlag(EMULATOR_FLAG_CF);
             }
-            else EmulatorSetFlag(EMULATOR_FLAG_CF);
+            else
+            {
+                EmulatorSetRegister(EMULATOR_REG_AX, ERROR_ARENA_TRASHED);
+                EmulatorSetFlag(EMULATOR_FLAG_CF);
+            }
 
             break;
         }
@@ -1442,6 +1501,35 @@ VOID DosInt21h(WORD CodeSegment)
             break;
         }
 
+        /* Get/Set Memory Management Options */
+        case 0x58:
+        {
+            if (LOBYTE(Eax) == 0x02)
+            {
+                /* Get UMB link state */
+
+                Eax &= 0xFFFFFF00;
+                if (DosUmbLinked) Eax |= 1;
+                EmulatorSetRegister(EMULATOR_REG_AX, Eax);
+            }
+            else if (LOBYTE(Eax) == 0x03)
+            {
+                /* Set UMB link state */
+
+                if (Ebx) DosLinkUmb();
+                else DosUnlinkUmb();
+            }
+            else
+            {
+                /* Invalid or unsupported function */
+
+                EmulatorSetFlag(EMULATOR_FLAG_CF);
+                EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_FUNCTION);
+            }
+
+            break;
+        }
+
         /* Unsupported */
         default:
         {
@@ -1472,6 +1560,18 @@ BOOLEAN DosInitialize()
     Mcb->Size = USER_MEMORY_SIZE;
     Mcb->OwnerPsp = 0;
 
+    /* Initialize the link MCB to the UMB area */
+    Mcb = SEGMENT_TO_MCB(FIRST_MCB_SEGMENT + USER_MEMORY_SIZE + 1);
+    Mcb->BlockType = 'M';
+    Mcb->Size = UMB_START_SEGMENT - FIRST_MCB_SEGMENT - USER_MEMORY_SIZE - 2;
+    Mcb->OwnerPsp = SYSTEM_PSP;
+
+    /* Initialize the UMB area */
+    Mcb = SEGMENT_TO_MCB(UMB_START_SEGMENT);
+    Mcb->BlockType = 'Z';
+    Mcb->Size = UMB_END_SEGMENT - UMB_START_SEGMENT;
+    Mcb->OwnerPsp = 0;
+
     /* Get the environment strings */
     SourcePtr = Environment = GetEnvironmentStringsW();
     if (Environment == NULL) return FALSE;
index 0c5f1be..ad8d2d3 100644 (file)
@@ -29,6 +29,8 @@
 #define DOS_SFT_SIZE 255
 #define SEGMENT_TO_MCB(seg) ((PDOS_MCB)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
 #define SEGMENT_TO_PSP(seg) ((PDOS_PSP)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
+#define UMB_START_SEGMENT 0xC000
+#define UMB_END_SEGMENT 0xDFFF
 
 #pragma pack(push, 1)