Author: aandrejevic
Date: Mon Jun 24 23:10:31 2013
New Revision: 59336
URL:
http://svn.reactos.org/svn/reactos?rev=59336&view=rev
Log:
[NTVDM]
Fix many VDM DOS memory manager bugs.
Modified:
branches/ntvdm/subsystems/ntvdm/dos.c
branches/ntvdm/subsystems/ntvdm/ntvdm.h
Modified: branches/ntvdm/subsystems/ntvdm/dos.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/dos.c?re…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/dos.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/dos.c [iso-8859-1] Mon Jun 24 23:10:31 2013
@@ -10,38 +10,31 @@
WORD CurrentPsp = SYSTEM_PSP, LastError = 0;
-static VOID DosCombineFreeBlocks()
-{
- WORD Segment = FIRST_MCB_SEGMENT;
- PDOS_MCB CurrentMcb, NextMcb;
-
- /* Loop through all the blocks */
+static VOID DosCombineFreeBlocks(WORD StartBlock)
+{
+ PDOS_MCB CurrentMcb = SEGMENT_TO_MCB(StartBlock), NextMcb;
+
+ /* If this is the last block or it's not free, quit */
+ if (CurrentMcb->BlockType == 'Z' || CurrentMcb->OwnerPsp != 0) return;
+
while (TRUE)
{
- /* Get a pointer to the MCB */
- CurrentMcb = SEGMENT_TO_MCB(Segment);
-
- /* Ignore the last block */
- if (CurrentMcb->BlockType == 'Z') break;
-
/* Get a pointer to the next MCB */
- NextMcb = SEGMENT_TO_MCB(Segment + CurrentMcb->Size + 1);
-
- /* If both this block and the next one are free, combine them */
- if ((CurrentMcb->OwnerPsp == 0) && (NextMcb->OwnerPsp == 0))
- {
+ NextMcb = SEGMENT_TO_MCB(StartBlock + CurrentMcb->Size + 1);
+
+ /* Check if the next MCB is free */
+ if (NextMcb->OwnerPsp == 0)
+ {
+ /* Combine them */
CurrentMcb->Size += NextMcb->Size + 1;
CurrentMcb->BlockType = NextMcb->BlockType;
-
- /* Invalidate the next MCB */
NextMcb->BlockType = 'I';
-
- /* Try to combine the current block again with the next one */
- continue;
- }
-
- /* Update the segment and continue */
- Segment += CurrentMcb->Size + 1;
+ }
+ else
+ {
+ /* No more adjoining free blocks */
+ break;
+ }
}
}
@@ -62,7 +55,7 @@
TotalSize++;
/* Allocate the memory for the environment block */
- DestSegment = DosAllocateMemory((TotalSize + 0x0F) >> 4);
+ DestSegment = DosAllocateMemory((TotalSize + 0x0F) >> 4, NULL);
if (!DestSegment) return 0;
Ptr = SourceBuffer;
@@ -84,12 +77,11 @@
return DestSegment;
}
-WORD DosAllocateMemory(WORD Size)
-{
- WORD Result = 0, Segment = FIRST_MCB_SEGMENT;
+WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
+{
+ WORD Result = 0, Segment = FIRST_MCB_SEGMENT, MaxSize = 0;
PDOS_MCB CurrentMcb, NextMcb;
- /* Find an unallocated block */
while (TRUE)
{
/* Get a pointer to the MCB */
@@ -104,7 +96,13 @@
/* Only check free blocks */
if (CurrentMcb->OwnerPsp != 0) goto Next;
- /* Check if the block is big enough */
+ /* Combine this free block with adjoining free blocks */
+ DosCombineFreeBlocks(Segment);
+
+ /* Update the maximum block size */
+ if (CurrentMcb->Size > MaxSize) MaxSize = CurrentMcb->Size;
+
+ /* Check if this block is big enough */
if (CurrentMcb->Size < Size) goto Next;
/* It is, update the smallest found so far */
@@ -114,15 +112,19 @@
}
Next:
- /* If this was the last MCB in the chain, quit. */
+ /* If this was the last MCB in the chain, quit */
if (CurrentMcb->BlockType == 'Z') break;
/* Otherwise, update the segment and continue */
Segment += CurrentMcb->Size + 1;
}
- /* If we didn't find a free block, return zero */
- if (Result == 0) return 0;
+ /* If we didn't find a free block, return 0 */
+ if (Result == 0)
+ {
+ if (MaxAvailable) *MaxAvailable = MaxSize;
+ return 0;
+ }
/* Get a pointer to the MCB */
CurrentMcb = SEGMENT_TO_MCB(Result);
@@ -135,15 +137,12 @@
/* Initialize the new MCB structure */
NextMcb->BlockType = CurrentMcb->BlockType;
- NextMcb->Size = Size - CurrentMcb->Size - 1;
+ NextMcb->Size = CurrentMcb->Size - Size - 1;
NextMcb->OwnerPsp = 0;
/* Update the current block */
CurrentMcb->BlockType = 'M';
CurrentMcb->Size = Size;
-
- /* Combine consecutive free blocks into larger blocks */
- DosCombineFreeBlocks();
}
/* Take ownership of the block */
@@ -154,77 +153,71 @@
WORD DosResizeMemory(WORD Segment, WORD NewSize)
{
- WORD ReturnSize = 0, CurrentSeg;
- PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment), CurrentMcb;
- BOOLEAN FinalBlockUsed = FALSE;
-
- /* We can't expand the last block */
- if (Mcb->BlockType != 'M') return 0;
+ WORD ReturnSize = 0, NextSegment;
+ PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment), NextMcb;
+
+ /* Make sure this is a valid, allocated block */
+ if ((Mcb->BlockType != 'M' && Mcb->BlockType != 'Z') ||
Mcb->OwnerPsp == 0)
+ {
+ return 0;
+ }
/* Check if need to expand or contract the block */
if (NewSize > Mcb->Size)
{
+ /* We can't expand the last block */
+ if (Mcb->BlockType != 'M') return Mcb->Size;
+
ReturnSize = Mcb->Size;
-
- /* Get the segment of the next MCB */
- CurrentSeg = Segment + Mcb->Size + 1;
-
- /* Calculate the maximum amount of memory this block could expand to */
- while (ReturnSize < NewSize)
- {
- /* Get the MCB */
- CurrentMcb = SEGMENT_TO_MCB(CurrentSeg);
-
- /* We can't expand the block over an allocated block */
- if (CurrentMcb->OwnerPsp != 0) break;
-
- ReturnSize += CurrentMcb->Size + 1;
-
- /* Check if this is the last block */
- if (CurrentMcb->BlockType == 'Z')
- {
- FinalBlockUsed = TRUE;
- break;
- }
-
- /* Update the segment and continue */
- CurrentSeg += CurrentMcb->Size + 1;
- }
-
- /* Check if we need to split the last block */
- if (ReturnSize > NewSize)
- {
+
+ /* Get the pointer and segment of the next MCB */
+ NextSegment = Segment + Mcb->Size + 1;
+ NextMcb = SEGMENT_TO_MCB(NextSegment);
+
+ /* Make sure the next segment is free */
+ if (NextMcb->OwnerPsp != 0) return Mcb->Size;
+
+ /* Combine this free block with adjoining free blocks */
+ DosCombineFreeBlocks(NextSegment);
+
+ /* Set the maximum possible size of the block */
+ ReturnSize += NextMcb->Size + 1;
+
+ /* Maximize the current block */
+ Mcb->Size = ReturnSize;
+ Mcb->BlockType = NextMcb->BlockType;
+
+ /* Invalidate the next block */
+ NextMcb->BlockType = 'I';
+
+ /* Check if the block is larger than requested */
+ if (Mcb->Size > NewSize)
+ {
+ /* It is, split it into two blocks */
+ NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
+
/* Initialize the new MCB structure */
- CurrentMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
- CurrentMcb->BlockType = (FinalBlockUsed) ? 'Z' : 'M';
- CurrentMcb->Size = ReturnSize - NewSize - 1;
- CurrentMcb->OwnerPsp = 0;
- }
-
- /* Calculate the new size of the block */
- ReturnSize = min(ReturnSize, NewSize);
-
- /* Update the MCB */
- if (FinalBlockUsed) Mcb->BlockType = 'Z';
- Mcb->Size = ReturnSize;
+ NextMcb->BlockType = Mcb->BlockType;
+ NextMcb->Size = Mcb->Size - NewSize - 1;
+ NextMcb->OwnerPsp = 0;
+
+ /* Update the current block */
+ Mcb->BlockType = 'M';
+ Mcb->Size = NewSize;
+ }
}
else if (NewSize < Mcb->Size)
{
/* Just split the block */
- CurrentMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
- CurrentMcb->BlockType = Mcb->BlockType;
- CurrentMcb->Size = Mcb->Size - NewSize - 1;
- CurrentMcb->OwnerPsp = 0;
+ NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
+ NextMcb->BlockType = Mcb->BlockType;
+ NextMcb->Size = Mcb->Size - NewSize - 1;
+ NextMcb->OwnerPsp = 0;
/* Update the MCB */
Mcb->BlockType = 'M';
Mcb->Size = NewSize;
-
- ReturnSize = NewSize;
- }
-
- /* Combine consecutive free blocks into larger blocks */
- DosCombineFreeBlocks();
+ }
return ReturnSize;
}
@@ -238,9 +231,6 @@
/* Mark the block as free */
Mcb->OwnerPsp = 0;
-
- /* Combine consecutive free blocks into larger blocks */
- DosCombineFreeBlocks();
return TRUE;
}
@@ -381,7 +371,7 @@
for (i = Header->e_maxalloc; i >= Header->e_minalloc; i--)
{
/* Try to allocate that much memory */
- Segment = DosAllocateMemory(ExeSize + (sizeof(DOS_PSP) >> 4) + i);
+ Segment = DosAllocateMemory(ExeSize + (sizeof(DOS_PSP) >> 4) + i,
NULL);
if (Segment != 0) break;
}
@@ -433,7 +423,7 @@
/* COM file */
/* Allocate memory for the whole program and the PSP */
- Segment = DosAllocateMemory((FileSize + sizeof(DOS_PSP)) >> 4);
+ Segment = DosAllocateMemory((FileSize + sizeof(DOS_PSP)) >> 4, NULL);
if (Segment == 0) goto Cleanup;
/* Copy the program to Segment:0100 */
@@ -765,10 +755,13 @@
/* Allocate Memory */
case 0x48:
{
- WORD Segment = DosAllocateMemory(LOWORD(Ebx));
+ WORD MaxAvailable = 0;
+ WORD Segment = DosAllocateMemory(LOWORD(Ebx), &MaxAvailable);
+
if (Segment != 0)
{
EmulatorSetRegister(EMULATOR_REG_AX, Segment);
+ EmulatorSetRegister(EMULATOR_REG_BX, MaxAvailable);
EmulatorClearFlag(EMULATOR_FLAG_CF);
}
else EmulatorSetFlag(EMULATOR_FLAG_CF);
Modified: branches/ntvdm/subsystems/ntvdm/ntvdm.h
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/ntvdm.h?…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/ntvdm.h [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/ntvdm.h [iso-8859-1] Mon Jun 24 23:10:31 2013
@@ -206,7 +206,7 @@
VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress);
VOID BiosPrintCharacter(CHAR Character, BYTE Attribute);
BOOLEAN DosInitialize();
-WORD DosAllocateMemory(WORD Size);
+WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable);
BOOLEAN DosFreeMemory(WORD Segment);
WORD DosResizeMemory(WORD Segment, WORD NewSize);
BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock);