mirror of
https://github.com/reactos/reactos.git
synced 2025-01-07 06:45:24 +00:00
685 lines
20 KiB
C
685 lines
20 KiB
C
/*
|
|
* COPYRIGHT: GPL - See COPYING in the top level directory
|
|
* PROJECT: ReactOS Virtual DOS Machine
|
|
* FILE: subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c
|
|
* PURPOSE: DOS32 Memory Manager
|
|
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
|
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "ntvdm.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#include "emulator.h"
|
|
|
|
#include "bios/umamgr.h" // HACK until we correctly call XMS services for UMBs.
|
|
|
|
#include "dos.h"
|
|
#include "dos/dem.h"
|
|
#include "memory.h"
|
|
#include "process.h"
|
|
#include "himem.h"
|
|
|
|
// FIXME: Should be dynamically initialized!
|
|
#define FIRST_MCB_SEGMENT (SYSTEM_ENV_BLOCK + 0x200) // old value: 0x1000
|
|
#define USER_MEMORY_SIZE (0x9FFE - FIRST_MCB_SEGMENT)
|
|
|
|
/*
|
|
* Activate this line if you want run-time DOS memory arena integrity validation
|
|
* (useful to know whether this is an application, or DOS kernel itself, which
|
|
* messes up the DOS memory arena).
|
|
*/
|
|
// #define DBG_MEMORY
|
|
|
|
/* PRIVATE VARIABLES **********************************************************/
|
|
|
|
/* PUBLIC VARIABLES ***********************************************************/
|
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
|
|
|
static inline BOOLEAN ValidateMcb(PDOS_MCB Mcb)
|
|
{
|
|
return (Mcb->BlockType == 'M' || Mcb->BlockType == 'Z');
|
|
}
|
|
|
|
/*
|
|
* This is a helper function to help us detecting
|
|
* when the DOS arena starts to become corrupted.
|
|
*/
|
|
#ifdef DBG_MEMORY
|
|
static VOID DosMemValidate(VOID)
|
|
{
|
|
WORD PrevSegment, Segment = SysVars->FirstMcb;
|
|
PDOS_MCB CurrentMcb;
|
|
|
|
PrevSegment = Segment;
|
|
while (TRUE)
|
|
{
|
|
/* Get a pointer to the MCB */
|
|
CurrentMcb = SEGMENT_TO_MCB(Segment);
|
|
|
|
/* Make sure it's valid */
|
|
if (!ValidateMcb(CurrentMcb))
|
|
{
|
|
DPRINT1("The DOS memory arena is corrupted! (CurrentMcb = 0x%04X; PreviousMcb = 0x%04X)\n", Segment, PrevSegment);
|
|
return;
|
|
}
|
|
|
|
PrevSegment = Segment;
|
|
|
|
/* If this was the last MCB in the chain, quit */
|
|
if (CurrentMcb->BlockType == 'Z') return;
|
|
|
|
/* Otherwise, update the segment and continue */
|
|
Segment += CurrentMcb->Size + 1;
|
|
}
|
|
}
|
|
#else
|
|
#define DosMemValidate()
|
|
#endif
|
|
|
|
static VOID DosCombineFreeBlocks(WORD StartBlock)
|
|
{
|
|
/* NOTE: This function is always called with valid MCB blocks */
|
|
|
|
PDOS_MCB CurrentMcb = SEGMENT_TO_MCB(StartBlock), NextMcb;
|
|
|
|
/* If the block is not free, quit */
|
|
if (CurrentMcb->OwnerPsp != 0) return;
|
|
|
|
/*
|
|
* Loop while the current block is not the last one. It can happen
|
|
* that the block is not the last one at the beginning, but becomes
|
|
* the last one at the end of the process. This happens in the case
|
|
* where its next following blocks are free but not combined yet,
|
|
* and they are terminated by a free last block. During the process
|
|
* all the blocks are combined together and we end up in the situation
|
|
* where the current (free) block is followed by the last (free) block.
|
|
* At the last step of the algorithm the current block becomes the
|
|
* last one.
|
|
*/
|
|
while (CurrentMcb->BlockType != 'Z')
|
|
{
|
|
/* Get a pointer to the next MCB */
|
|
NextMcb = SEGMENT_TO_MCB(StartBlock + CurrentMcb->Size + 1);
|
|
|
|
/* Make sure it's valid */
|
|
if (!ValidateMcb(NextMcb))
|
|
{
|
|
DPRINT1("The DOS memory arena is corrupted!\n");
|
|
Sda->LastErrorCode = ERROR_ARENA_TRASHED;
|
|
return;
|
|
}
|
|
|
|
/* Check if the next MCB is free */
|
|
if (NextMcb->OwnerPsp == 0)
|
|
{
|
|
/* Combine them */
|
|
CurrentMcb->Size += NextMcb->Size + 1;
|
|
CurrentMcb->BlockType = NextMcb->BlockType;
|
|
NextMcb->BlockType = 'I';
|
|
}
|
|
else
|
|
{
|
|
/* No more adjoining free blocks */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
|
|
|
WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
|
|
{
|
|
WORD Result = 0, Segment = SysVars->FirstMcb, MaxSize = 0;
|
|
PDOS_MCB CurrentMcb;
|
|
BOOLEAN SearchUmb = FALSE;
|
|
|
|
DPRINT("DosAllocateMemory: Size 0x%04X\n", Size);
|
|
|
|
DosMemValidate();
|
|
|
|
if (SysVars->UmbLinked && SysVars->UmbChainStart != 0xFFFF &&
|
|
(Sda->AllocStrategy & (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW)))
|
|
{
|
|
/* Search UMB first */
|
|
Segment = SysVars->UmbChainStart;
|
|
SearchUmb = TRUE;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
/* Get a pointer to the MCB */
|
|
CurrentMcb = SEGMENT_TO_MCB(Segment);
|
|
|
|
/* Make sure it's valid */
|
|
if (!ValidateMcb(CurrentMcb))
|
|
{
|
|
DPRINT1("The DOS memory arena is corrupted!\n");
|
|
Sda->LastErrorCode = ERROR_ARENA_TRASHED;
|
|
return 0;
|
|
}
|
|
|
|
/* Only check free blocks */
|
|
if (CurrentMcb->OwnerPsp != 0) goto Next;
|
|
|
|
/* 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;
|
|
|
|
switch (Sda->AllocStrategy & ~(DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
|
|
{
|
|
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:
|
|
/* If this was the last MCB in the chain, quit */
|
|
if (CurrentMcb->BlockType == 'Z')
|
|
{
|
|
/* Check if nothing was found while searching through UMBs */
|
|
if ((Result == 0) && SearchUmb && (Sda->AllocStrategy & DOS_ALLOC_HIGH_LOW))
|
|
{
|
|
/* Search low memory */
|
|
Segment = SysVars->FirstMcb;
|
|
SearchUmb = FALSE;
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/* Otherwise, update the segment and continue */
|
|
Segment += CurrentMcb->Size + 1;
|
|
}
|
|
|
|
Done:
|
|
DosMemValidate();
|
|
|
|
/* If we didn't find a free block, bail out */
|
|
if (Result == 0)
|
|
{
|
|
DPRINT("DosAllocateMemory FAILED. Maximum available: 0x%04X\n", MaxSize);
|
|
Sda->LastErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
if (MaxAvailable) *MaxAvailable = MaxSize;
|
|
return 0;
|
|
}
|
|
|
|
/* Get a pointer to the MCB */
|
|
CurrentMcb = SEGMENT_TO_MCB(Result);
|
|
|
|
/* Check if the block is larger than requested */
|
|
if (CurrentMcb->Size > Size)
|
|
{
|
|
/* It is, split it into two blocks */
|
|
if ((Sda->AllocStrategy & ~(DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW)) != DOS_ALLOC_LAST_FIT)
|
|
{
|
|
PDOS_MCB NextMcb = SEGMENT_TO_MCB(Result + Size + 1);
|
|
|
|
/* Initialize the new MCB structure */
|
|
NextMcb->BlockType = CurrentMcb->BlockType;
|
|
NextMcb->Size = CurrentMcb->Size - Size - 1;
|
|
NextMcb->OwnerPsp = 0;
|
|
|
|
/* Update the current block */
|
|
CurrentMcb->BlockType = 'M';
|
|
CurrentMcb->Size = Size;
|
|
}
|
|
else
|
|
{
|
|
/* Save the location of the current MCB */
|
|
PDOS_MCB PreviousMcb = CurrentMcb;
|
|
|
|
/* Move the current MCB higher */
|
|
Result += CurrentMcb->Size - Size;
|
|
CurrentMcb = SEGMENT_TO_MCB(Result);
|
|
|
|
/* Initialize the new MCB structure */
|
|
CurrentMcb->BlockType = PreviousMcb->BlockType;
|
|
CurrentMcb->Size = Size;
|
|
CurrentMcb->OwnerPsp = 0;
|
|
|
|
/* Update the previous block */
|
|
PreviousMcb->BlockType = 'M';
|
|
PreviousMcb->Size -= Size + 1;
|
|
}
|
|
}
|
|
|
|
/* Take ownership of the block */
|
|
CurrentMcb->OwnerPsp = Sda->CurrentPsp;
|
|
RtlCopyMemory(CurrentMcb->Name, SEGMENT_TO_MCB(Sda->CurrentPsp - 1)->Name, sizeof(CurrentMcb->Name));
|
|
|
|
DosMemValidate();
|
|
|
|
/* Return the segment of the data portion of the block */
|
|
return Result + 1;
|
|
}
|
|
|
|
BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable)
|
|
{
|
|
BOOLEAN Success = TRUE;
|
|
WORD Segment = BlockData - 1, ReturnSize = 0, NextSegment;
|
|
PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment), NextMcb;
|
|
|
|
DPRINT("DosResizeMemory: BlockData 0x%04X, NewSize 0x%04X\n",
|
|
BlockData, NewSize);
|
|
|
|
DosMemValidate();
|
|
|
|
/* Make sure this is a valid and allocated block */
|
|
if (BlockData == 0 || !ValidateMcb(Mcb) || Mcb->OwnerPsp == 0)
|
|
{
|
|
Sda->LastErrorCode = ERROR_INVALID_BLOCK;
|
|
Success = FALSE;
|
|
goto Done;
|
|
}
|
|
|
|
ReturnSize = Mcb->Size;
|
|
|
|
/* Check if we need to expand or contract the block */
|
|
if (NewSize > Mcb->Size)
|
|
{
|
|
/* We can't expand the last block */
|
|
if (Mcb->BlockType == 'Z')
|
|
{
|
|
DPRINT("Cannot expand memory block 0x%04X: this is the last block (size 0x%04X)!\n", Segment, Mcb->Size);
|
|
Sda->LastErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
Success = FALSE;
|
|
goto Done;
|
|
}
|
|
|
|
/* Get the pointer and segment of the next MCB */
|
|
NextSegment = Segment + Mcb->Size + 1;
|
|
NextMcb = SEGMENT_TO_MCB(NextSegment);
|
|
|
|
/* Make sure it's valid */
|
|
if (!ValidateMcb(NextMcb))
|
|
{
|
|
DPRINT1("The DOS memory arena is corrupted!\n");
|
|
Sda->LastErrorCode = ERROR_ARENA_TRASHED;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Make sure the next segment is free */
|
|
if (NextMcb->OwnerPsp != 0)
|
|
{
|
|
DPRINT("Cannot expand memory block 0x%04X: next segment is not free!\n", Segment);
|
|
Sda->LastErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
Success = FALSE;
|
|
goto Done;
|
|
}
|
|
|
|
/* Combine this free block with adjoining free blocks */
|
|
DosCombineFreeBlocks(NextSegment);
|
|
|
|
/* Set the maximum possible size of the block */
|
|
ReturnSize += NextMcb->Size + 1;
|
|
|
|
if (ReturnSize < NewSize)
|
|
{
|
|
DPRINT("Cannot expand memory block 0x%04X: insufficient free segments available!\n", Segment);
|
|
Sda->LastErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
Success = FALSE;
|
|
goto Done;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
DPRINT("Block too large, reducing size from 0x%04X to 0x%04X\n",
|
|
Mcb->Size, NewSize);
|
|
|
|
/* It is, split it into two blocks */
|
|
NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
|
|
|
|
/* Initialize the new MCB structure */
|
|
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)
|
|
{
|
|
DPRINT("Shrinking block from 0x%04X to 0x%04X\n",
|
|
Mcb->Size, NewSize);
|
|
|
|
/* Just split the block */
|
|
NextSegment = Segment + NewSize + 1;
|
|
NextMcb = SEGMENT_TO_MCB(NextSegment);
|
|
NextMcb->BlockType = Mcb->BlockType;
|
|
NextMcb->Size = Mcb->Size - NewSize - 1;
|
|
NextMcb->OwnerPsp = 0;
|
|
|
|
/* Update the MCB */
|
|
Mcb->BlockType = 'M';
|
|
Mcb->Size = NewSize;
|
|
|
|
/* Combine this free block with adjoining free blocks */
|
|
DosCombineFreeBlocks(NextSegment);
|
|
}
|
|
|
|
Done:
|
|
/* Check if the operation failed */
|
|
if (!Success)
|
|
{
|
|
DPRINT("DosResizeMemory FAILED. Maximum available: 0x%04X\n", ReturnSize);
|
|
|
|
/* Return the maximum possible size */
|
|
if (MaxAvailable) *MaxAvailable = ReturnSize;
|
|
}
|
|
|
|
DosMemValidate();
|
|
|
|
return Success;
|
|
}
|
|
|
|
BOOLEAN DosFreeMemory(WORD BlockData)
|
|
{
|
|
PDOS_MCB Mcb = SEGMENT_TO_MCB(BlockData - 1);
|
|
|
|
DPRINT("DosFreeMemory: BlockData 0x%04X\n", BlockData);
|
|
|
|
if (BlockData == 0)
|
|
{
|
|
Sda->LastErrorCode = ERROR_INVALID_BLOCK;
|
|
return FALSE;
|
|
}
|
|
|
|
DosMemValidate();
|
|
|
|
/* Make sure the MCB is valid */
|
|
if (!ValidateMcb(Mcb))
|
|
{
|
|
DPRINT("MCB block type '%c' not valid!\n", Mcb->BlockType);
|
|
Sda->LastErrorCode = ERROR_INVALID_BLOCK;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Mark the block as free */
|
|
Mcb->OwnerPsp = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN DosLinkUmb(VOID)
|
|
{
|
|
DWORD Segment = SysVars->FirstMcb;
|
|
PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment);
|
|
|
|
DPRINT("Linking UMB\n");
|
|
|
|
/* Check if UMBs are initialized and already linked */
|
|
if (SysVars->UmbChainStart == 0xFFFF) return FALSE;
|
|
if (SysVars->UmbLinked) return TRUE;
|
|
|
|
DosMemValidate();
|
|
|
|
/* Find the last block before the start of the UMB chain */
|
|
while (Segment < SysVars->UmbChainStart)
|
|
{
|
|
/* Get a pointer to the MCB */
|
|
Mcb = SEGMENT_TO_MCB(Segment);
|
|
|
|
/* Make sure it's valid */
|
|
if (!ValidateMcb(Mcb))
|
|
{
|
|
DPRINT1("The DOS memory arena is corrupted!\n");
|
|
Sda->LastErrorCode = ERROR_ARENA_TRASHED;
|
|
return FALSE;
|
|
}
|
|
|
|
/* If this was the last MCB in the chain, quit */
|
|
if (Mcb->BlockType == 'Z') break;
|
|
|
|
/* Otherwise, update the segment and continue */
|
|
Segment += Mcb->Size + 1;
|
|
}
|
|
|
|
/* Make sure it's valid */
|
|
if (Mcb->BlockType != 'Z') return FALSE;
|
|
|
|
/* Connect the MCB with the UMB chain */
|
|
Mcb->BlockType = 'M';
|
|
|
|
DosMemValidate();
|
|
|
|
SysVars->UmbLinked = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN DosUnlinkUmb(VOID)
|
|
{
|
|
DWORD Segment = SysVars->FirstMcb;
|
|
PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment);
|
|
|
|
DPRINT("Unlinking UMB\n");
|
|
|
|
/* Check if UMBs are initialized and already unlinked */
|
|
if (SysVars->UmbChainStart == 0xFFFF) return FALSE;
|
|
if (!SysVars->UmbLinked) return TRUE;
|
|
|
|
DosMemValidate();
|
|
|
|
/* Find the last block before the start of the UMB chain */
|
|
while (Segment < SysVars->UmbChainStart)
|
|
{
|
|
/* Get a pointer to the MCB */
|
|
Mcb = SEGMENT_TO_MCB(Segment);
|
|
|
|
/* Make sure it's valid */
|
|
if (!ValidateMcb(Mcb))
|
|
{
|
|
DPRINT1("The DOS memory arena is corrupted!\n");
|
|
Sda->LastErrorCode = ERROR_ARENA_TRASHED;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Advance to the next MCB */
|
|
Segment += Mcb->Size + 1;
|
|
}
|
|
|
|
/* Mark the MCB as the last MCB */
|
|
Mcb->BlockType = 'Z';
|
|
|
|
DosMemValidate();
|
|
|
|
SysVars->UmbLinked = FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
VOID DosChangeMemoryOwner(WORD Segment, WORD NewOwner)
|
|
{
|
|
PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment - 1);
|
|
Mcb->OwnerPsp = NewOwner;
|
|
}
|
|
|
|
/*
|
|
* Some information about DOS UMBs:
|
|
* http://textfiles.com/virus/datut010.txt
|
|
* http://www.asmcommunity.net/forums/topic/?id=30884
|
|
*/
|
|
|
|
WORD DosGetPreviousUmb(WORD UmbSegment)
|
|
{
|
|
PDOS_MCB CurrentMcb;
|
|
WORD Segment, PrevSegment = 0; // FIXME: or use UmbChainStart ??
|
|
|
|
if (SysVars->UmbChainStart == 0xFFFF)
|
|
return 0;
|
|
|
|
/* Start scanning the UMB chain */
|
|
Segment = SysVars->UmbChainStart;
|
|
while (TRUE)
|
|
{
|
|
/* Get a pointer to the MCB */
|
|
CurrentMcb = SEGMENT_TO_MCB(Segment);
|
|
|
|
/* Make sure it's valid */
|
|
if (!ValidateMcb(CurrentMcb))
|
|
{
|
|
DPRINT1("The UMB DOS memory arena is corrupted!\n");
|
|
Sda->LastErrorCode = ERROR_ARENA_TRASHED;
|
|
return 0;
|
|
}
|
|
|
|
/* We went over the UMB segment, quit */
|
|
if (Segment >= UmbSegment) break;
|
|
|
|
PrevSegment = Segment;
|
|
|
|
/* 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;
|
|
}
|
|
|
|
return PrevSegment;
|
|
}
|
|
|
|
VOID DosInitializeUmb(VOID)
|
|
{
|
|
BOOLEAN Result;
|
|
USHORT UmbSegment = 0x0000, PrevSegment;
|
|
USHORT Size;
|
|
PDOS_MCB Mcb, PrevMcb;
|
|
|
|
ASSERT(SysVars->UmbChainStart == 0xFFFF);
|
|
|
|
// SysVars->UmbLinked = FALSE;
|
|
|
|
/* Try to allocate all the UMBs */
|
|
while (TRUE)
|
|
{
|
|
/* Find the maximum amount of memory that can be allocated */
|
|
Size = 0xFFFF;
|
|
Result = UmaDescReserve(&UmbSegment, &Size);
|
|
|
|
/* If we are out of UMBs, bail out */
|
|
if (!Result && Size == 0) // XMS_STATUS_OUT_OF_UMBS
|
|
break;
|
|
|
|
/* We should not have succeeded! */
|
|
ASSERT(!Result);
|
|
|
|
/* 'Size' now contains the size of the biggest UMB block. Request it. */
|
|
Result = UmaDescReserve(&UmbSegment, &Size);
|
|
ASSERT(Result); // XMS_STATUS_SUCCESS
|
|
|
|
/* If this is our first UMB block, initialize the UMB chain */
|
|
if (SysVars->UmbChainStart == 0xFFFF)
|
|
{
|
|
/* Initialize the link MCB to the UMB area */
|
|
// NOTE: We use the fact that UmbChainStart is still == 0xFFFF
|
|
// so that we initialize this block from 9FFF:0000 up to FFFF:000F.
|
|
// It will be splitted as needed just below.
|
|
Mcb = SEGMENT_TO_MCB(SysVars->FirstMcb + USER_MEMORY_SIZE + 1); // '+1': Readjust the fact that USER_MEMORY_SIZE is based using 0x9FFE instead of 0x9FFF
|
|
Mcb->BlockType = 'Z'; // At the moment it is really the last block
|
|
Mcb->Size = (SysVars->UmbChainStart /* UmbSegment */ - SysVars->FirstMcb - USER_MEMORY_SIZE - 2) + 1;
|
|
Mcb->OwnerPsp = SYSTEM_PSP;
|
|
RtlCopyMemory(Mcb->Name, "SC ", sizeof("SC ")-1);
|
|
|
|
#if 0 // Keep here for reference; this will be deleted as soon as it becomes unneeded.
|
|
/* Initialize the UMB area */
|
|
Mcb = SEGMENT_TO_MCB(SysVars->UmbChainStart);
|
|
Mcb->Size = UMB_END_SEGMENT - SysVars->UmbChainStart;
|
|
#endif
|
|
|
|
// FIXME: We should adjust the size of the previous block!!
|
|
|
|
/* Initialize the start of the UMB chain */
|
|
SysVars->UmbChainStart = SysVars->FirstMcb + USER_MEMORY_SIZE + 1;
|
|
}
|
|
|
|
/* Split the block */
|
|
|
|
/* Get the previous block */
|
|
PrevSegment = DosGetPreviousUmb(UmbSegment);
|
|
PrevMcb = SEGMENT_TO_MCB(PrevSegment);
|
|
|
|
/* Initialize the next block */
|
|
Mcb = SEGMENT_TO_MCB(UmbSegment + /*Mcb->Size*/(Size - 1) + 0);
|
|
// Mcb->BlockType = 'Z'; // FIXME: What if this block happens to be the last one??
|
|
Mcb->BlockType = PrevMcb->BlockType;
|
|
Mcb->Size = PrevMcb->Size - (UmbSegment + Size - PrevSegment) + 1;
|
|
Mcb->OwnerPsp = PrevMcb->OwnerPsp;
|
|
RtlCopyMemory(Mcb->Name, PrevMcb->Name, sizeof(PrevMcb->Name));
|
|
|
|
/* The previous block is not the latest one anymore */
|
|
PrevMcb->BlockType = 'M';
|
|
PrevMcb->Size = UmbSegment - PrevSegment - 1;
|
|
|
|
/* Initialize the new UMB block */
|
|
Mcb = SEGMENT_TO_MCB(UmbSegment);
|
|
Mcb->BlockType = 'M'; // 'Z' // FIXME: What if this block happens to be the last one??
|
|
Mcb->Size = Size - 1 - 1; // minus 2 because we need to have one arena at the beginning and one at the end.
|
|
Mcb->OwnerPsp = 0;
|
|
// FIXME: Which MCB name should we use? I need to explore more the docs!
|
|
RtlCopyMemory(Mcb->Name, "UMB ", sizeof("UMB ")-1);
|
|
// RtlCopyMemory(Mcb->Name, "SM ", sizeof("SM ")-1);
|
|
}
|
|
}
|
|
|
|
VOID DosInitializeMemory(VOID)
|
|
{
|
|
PDOS_MCB Mcb;
|
|
|
|
/* Set the initial allocation strategy to "best fit" */
|
|
Sda->AllocStrategy = DOS_ALLOC_BEST_FIT;
|
|
|
|
/* Initialize conventional memory; we don't have UMBs yet */
|
|
SysVars->FirstMcb = FIRST_MCB_SEGMENT; // The Arena Head
|
|
SysVars->UmbLinked = FALSE;
|
|
SysVars->UmbChainStart = 0xFFFF;
|
|
|
|
Mcb = SEGMENT_TO_MCB(SysVars->FirstMcb);
|
|
|
|
/* Initialize the MCB */
|
|
Mcb->BlockType = 'Z';
|
|
Mcb->Size = USER_MEMORY_SIZE;
|
|
Mcb->OwnerPsp = 0;
|
|
}
|
|
|
|
/* EOF */
|