Implement Upper Memory Blocks (UMB) support.


svn path=/branches/ntvdm/; revision=59501
This commit is contained in:
Aleksandar Andrejevic 2013-07-18 11:44:06 +00:00
parent 09e7fede48
commit 495320af6e
3 changed files with 104 additions and 2 deletions

View 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

View 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;

View 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)