Implement multiple allocation strategies.


svn path=/branches/ntvdm/; revision=59530
This commit is contained in:
Aleksandar Andrejevic 2013-07-20 06:14:13 +00:00
parent bac747f151
commit f603441db9
2 changed files with 98 additions and 6 deletions

View file

@ -15,9 +15,11 @@
/* PRIVATE VARIABLES **********************************************************/ /* PRIVATE VARIABLES **********************************************************/
static WORD CurrentPsp = SYSTEM_PSP; static WORD CurrentPsp = SYSTEM_PSP;
static WORD DosLastError = 0;
static DWORD DiskTransferArea; static DWORD DiskTransferArea;
static HANDLE DosSystemFileTable[DOS_SFT_SIZE]; static HANDLE DosSystemFileTable[DOS_SFT_SIZE];
static WORD DosSftRefCount[DOS_SFT_SIZE]; static WORD DosSftRefCount[DOS_SFT_SIZE];
static BYTE DosAllocStrategy = DOS_ALLOC_BEST_FIT;
static BOOLEAN DosUmbLinked = FALSE; static BOOLEAN DosUmbLinked = FALSE;
/* PRIVATE FUNCTIONS **********************************************************/ /* PRIVATE FUNCTIONS **********************************************************/
@ -225,6 +227,14 @@ WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
{ {
WORD Result = 0, Segment = FIRST_MCB_SEGMENT, MaxSize = 0; WORD Result = 0, Segment = FIRST_MCB_SEGMENT, MaxSize = 0;
PDOS_MCB CurrentMcb, NextMcb; PDOS_MCB CurrentMcb, NextMcb;
BOOLEAN SearchUmb = FALSE;
if (DosUmbLinked && (DosAllocStrategy & (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW)))
{
/* Search UMB first */
Segment = UMB_START_SEGMENT;
SearchUmb = TRUE;
}
while (TRUE) while (TRUE)
{ {
@ -234,6 +244,7 @@ WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
/* Make sure it's valid */ /* Make sure it's valid */
if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType != 'Z') if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType != 'Z')
{ {
DosLastError = ERROR_ARENA_TRASHED;
return 0; return 0;
} }
@ -249,23 +260,59 @@ WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
/* Check if this block is big enough */ /* Check if this block is big enough */
if (CurrentMcb->Size < Size) goto Next; if (CurrentMcb->Size < Size) goto Next;
/* It is, update the smallest found so far */ switch (DosAllocStrategy & 0x3F)
if ((Result == 0) || (CurrentMcb->Size < SEGMENT_TO_MCB(Result)->Size))
{ {
Result = Segment; case DOS_ALLOC_FIRST_FIT:
{
/* For first fit, stop immediately */
Result = Segment;
goto Done;
}
case DOS_ALLOC_BEST_FIT:
{
/* For best fit, update the smallest block found so far */
if ((Result == 0) || (CurrentMcb->Size < SEGMENT_TO_MCB(Result)->Size))
{
Result = Segment;
}
break;
}
case DOS_ALLOC_LAST_FIT:
{
/* For last fit, make the current block the result, but keep searching */
Result = Segment;
break;
}
} }
Next: 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; if (CurrentMcb->BlockType == 'Z')
{
/* Check if nothing was found while searching through UMBs */
if ((Result == 0) && SearchUmb && (DosAllocStrategy & DOS_ALLOC_HIGH_LOW))
{
/* Search low memory */
Segment = FIRST_MCB_SEGMENT;
continue;
}
break;
}
/* Otherwise, update the segment and continue */ /* Otherwise, update the segment and continue */
Segment += CurrentMcb->Size + 1; Segment += CurrentMcb->Size + 1;
} }
Done:
/* If we didn't find a free block, return 0 */ /* If we didn't find a free block, return 0 */
if (Result == 0) if (Result == 0)
{ {
DosLastError = ERROR_NOT_ENOUGH_MEMORY;
if (MaxAvailable) *MaxAvailable = MaxSize; if (MaxAvailable) *MaxAvailable = MaxSize;
return 0; return 0;
} }
@ -306,6 +353,7 @@ BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable)
if ((Mcb->BlockType != 'M' && Mcb->BlockType != 'Z') || Mcb->OwnerPsp == 0) if ((Mcb->BlockType != 'M' && Mcb->BlockType != 'Z') || Mcb->OwnerPsp == 0)
{ {
Success = FALSE; Success = FALSE;
DosLastError = ERROR_INVALID_PARAMETER;
goto Done; goto Done;
} }
@ -328,6 +376,7 @@ BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable)
/* Make sure the next segment is free */ /* Make sure the next segment is free */
if (NextMcb->OwnerPsp != 0) if (NextMcb->OwnerPsp != 0)
{ {
DosLastError = ERROR_NOT_ENOUGH_MEMORY;
Success = FALSE; Success = FALSE;
goto Done; goto Done;
} }
@ -1457,7 +1506,7 @@ VOID DosInt21h(WORD CodeSegment)
} }
else else
{ {
EmulatorSetRegister(EMULATOR_REG_AX, ERROR_NOT_ENOUGH_MEMORY); EmulatorSetRegister(EMULATOR_REG_AX, DosLastError);
EmulatorSetRegister(EMULATOR_REG_BX, MaxAvailable); EmulatorSetRegister(EMULATOR_REG_BX, MaxAvailable);
EmulatorSetFlag(EMULATOR_FLAG_CF); EmulatorSetFlag(EMULATOR_FLAG_CF);
} }
@ -1492,6 +1541,7 @@ VOID DosInt21h(WORD CodeSegment)
} }
else else
{ {
EmulatorSetRegister(EMULATOR_REG_AX, DosLastError);
EmulatorSetFlag(EMULATOR_FLAG_CF); EmulatorSetFlag(EMULATOR_FLAG_CF);
EmulatorSetRegister(EMULATOR_REG_BX, Size); EmulatorSetRegister(EMULATOR_REG_BX, Size);
} }
@ -1509,13 +1559,45 @@ VOID DosInt21h(WORD CodeSegment)
/* Get/Set Memory Management Options */ /* Get/Set Memory Management Options */
case 0x58: case 0x58:
{ {
if (LOBYTE(Eax) == 0x02) if (LOBYTE(Eax) == 0x00)
{
/* Get allocation strategy */
EmulatorSetRegister(EMULATOR_REG_AX, DosAllocStrategy);
EmulatorClearFlag(EMULATOR_FLAG_CF);
}
else if (LOBYTE(Eax) == 0x01)
{
/* Set allocation strategy */
if ((LOBYTE(Ebx) & (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
== (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
{
/* Can't set both */
EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_PARAMETER);
EmulatorSetFlag(EMULATOR_FLAG_CF);
break;
}
if ((LOBYTE(Ebx) & 0x3F) > DOS_ALLOC_LAST_FIT)
{
/* Invalid allocation strategy */
EmulatorSetRegister(EMULATOR_REG_AX, ERROR_INVALID_PARAMETER);
EmulatorSetFlag(EMULATOR_FLAG_CF);
break;
}
DosAllocStrategy = LOBYTE(Ebx);
EmulatorClearFlag(EMULATOR_FLAG_CF);
}
else if (LOBYTE(Eax) == 0x02)
{ {
/* Get UMB link state */ /* Get UMB link state */
Eax &= 0xFFFFFF00; Eax &= 0xFFFFFF00;
if (DosUmbLinked) Eax |= 1; if (DosUmbLinked) Eax |= 1;
EmulatorSetRegister(EMULATOR_REG_AX, Eax); EmulatorSetRegister(EMULATOR_REG_AX, Eax);
EmulatorClearFlag(EMULATOR_FLAG_CF);
} }
else if (LOBYTE(Eax) == 0x03) else if (LOBYTE(Eax) == 0x03)
{ {
@ -1523,6 +1605,7 @@ VOID DosInt21h(WORD CodeSegment)
if (Ebx) DosLinkUmb(); if (Ebx) DosLinkUmb();
else DosUnlinkUmb(); else DosUnlinkUmb();
EmulatorClearFlag(EMULATOR_FLAG_CF);
} }
else else
{ {

View file

@ -31,6 +31,15 @@
#define SEGMENT_TO_PSP(seg) ((PDOS_PSP)((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_START_SEGMENT 0xC000
#define UMB_END_SEGMENT 0xDFFF #define UMB_END_SEGMENT 0xDFFF
#define DOS_ALLOC_HIGH 0x40
#define DOS_ALLOC_HIGH_LOW 0x80
enum DOS_ALLOC_STRATEGY
{
DOS_ALLOC_FIRST_FIT,
DOS_ALLOC_BEST_FIT,
DOS_ALLOC_LAST_FIT
};
#pragma pack(push, 1) #pragma pack(push, 1)