reactos/freeldr/freeldr/memory.c
Brian Palmer 17dc9b5270 Full memory management support (memory.c & memory.h & mem.S)
Preliminary debug code (debug.c & debug.h)
Reworked .ini file code (parseini.c & parseini.h)
Size optimizations (fat.asm & fat32.asm)
FAT12/16 boot sector now fully understands the FAT (fat.asm)

svn path=/trunk/; revision=2049
2001-07-06 22:05:05 +00:00

281 lines
7.5 KiB
C

/*
* FreeLoader
* Copyright (C) 2001 Brian Palmer <brianp@sginet.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "freeldr.h"
#include "memory.h"
#include "stdlib.h"
#include "debug.h"
#define MEM_BLOCK_SIZE 256
typedef struct
{
BOOL MemBlockAllocated; // Is this block allocated or free
ULONG BlocksAllocated; // Block length, in multiples of 256 bytes
} MEMBLOCK, *PMEMBLOCK;
PVOID HeapBaseAddress = NULL;
ULONG HeapLengthInBytes = 0;
ULONG HeapMemBlockCount = 0;
PMEMBLOCK HeapMemBlockArray = NULL;
#ifdef DEBUG
ULONG AllocationCount = 0;
VOID VerifyHeap(VOID);
VOID IncrementAllocationCount(VOID);
VOID DecrementAllocationCount(VOID);
VOID MemAllocTest(VOID);
#endif DEBUG
VOID InitMemoryManager(PVOID BaseAddress, ULONG Length)
{
ULONG MemBlocks;
// Calculate how many memory blocks we have
MemBlocks = (Length / MEM_BLOCK_SIZE);
// Adjust the heap length so we can reserve
// enough storage space for the MEMBLOCK array
Length -= (MemBlocks * sizeof(MEMBLOCK));
// Initialize our tracking variables
HeapBaseAddress = BaseAddress;
HeapLengthInBytes = Length;
HeapMemBlockCount = (HeapLengthInBytes / MEM_BLOCK_SIZE);
HeapMemBlockArray = (PMEMBLOCK)(HeapBaseAddress + HeapLengthInBytes);
// Clear the memory
ZeroMemory(HeapBaseAddress, HeapLengthInBytes);
ZeroMemory(HeapMemBlockArray, (HeapMemBlockCount * sizeof(MEMBLOCK)));
#ifdef DEBUG
DebugPrint(DPRINT_MEMORY, "Memory Manager initialized. BaseAddress = 0x%x Length = 0x%x. %d blocks in heap.\n", BaseAddress, Length, HeapMemBlockCount);
//MemAllocTest();
#endif
}
PVOID AllocateMemory(ULONG NumberOfBytes)
{
ULONG BlocksNeeded;
ULONG Idx;
ULONG NumFree;
PVOID MemPointer;
#ifdef DEBUG
VerifyHeap();
#endif DEBUG
// Find out how many blocks it will take to
// satisfy this allocation
BlocksNeeded = ROUND_UP(NumberOfBytes, MEM_BLOCK_SIZE) / MEM_BLOCK_SIZE;
// Now loop through our array of blocks and
// see if we have enough space
for (Idx=0,NumFree=0; Idx<HeapMemBlockCount; Idx++)
{
// Check this block and see if it is already allocated
// If so reset our counter and continue the loop
if (HeapMemBlockArray[Idx].MemBlockAllocated)
{
NumFree = 0;
continue;
}
else
{
// It is free memory so lets increment our count
NumFree++;
}
// If we have found enough blocks to satisfy the request
// then we're done searching
if (NumFree >= BlocksNeeded)
{
break;
}
}
Idx++;
// If we don't have enough available mem
// then return NULL
if (NumFree < BlocksNeeded)
{
return NULL;
}
// Subtract the block count from Idx and we have
// the start block of the memory
Idx -= NumFree;
// Now we know which block to give them
MemPointer = HeapBaseAddress + (Idx * MEM_BLOCK_SIZE);
// Now loop through and mark all the blocks as allocated
for (NumFree=0; NumFree<BlocksNeeded; NumFree++)
{
HeapMemBlockArray[Idx + NumFree].MemBlockAllocated = TRUE;
HeapMemBlockArray[Idx + NumFree].BlocksAllocated = NumFree ? 0 : BlocksNeeded; // Mark only the first block with the count
}
#ifdef DEBUG
IncrementAllocationCount();
DebugPrint(DPRINT_MEMORY, "Allocated %d bytes (%d blocks) of memory starting at block %d. AllocationCount: %d\n", NumberOfBytes, BlocksNeeded, Idx, AllocationCount);
#endif DEBUG
// Now return the pointer
return MemPointer;
}
VOID FreeMemory(PVOID MemBlock)
{
ULONG BlockNumber;
ULONG BlockCount;
ULONG Idx;
#ifdef DEBUG
VerifyHeap();
// Make sure we didn't get a bogus pointer
if ((MemBlock < HeapBaseAddress) || (MemBlock > (HeapBaseAddress + HeapLengthInBytes)))
{
BugCheck1("Bogus memory pointer (0x%x) passed to FreeMemory()\n", MemBlock);
}
#endif DEBUG
// Find out the block number if the first
// block of memory they allocated
BlockNumber = (MemBlock - HeapBaseAddress) / MEM_BLOCK_SIZE;
BlockCount = HeapMemBlockArray[BlockNumber].BlocksAllocated;
#ifdef DEBUG
// Make sure we didn't get a bogus pointer
if ((BlockCount < 1) || (BlockCount > HeapMemBlockCount))
{
BugCheck1("Invalid block count in heap page header. HeapMemBlockArray[BlockNumber].BlocksAllocated = %d\n", HeapMemBlockArray[BlockNumber].BlocksAllocated);
}
#endif
// Loop through our array and mark all the
// blocks as free
for (Idx=BlockNumber; Idx<(BlockNumber + BlockCount); Idx++)
{
HeapMemBlockArray[Idx].MemBlockAllocated = FALSE;
HeapMemBlockArray[Idx].BlocksAllocated = 0;
}
#ifdef DEBUG
DecrementAllocationCount();
DebugPrint(DPRINT_MEMORY, "Freed %d blocks of memory starting at block %d. AllocationCount: %d\n", BlockCount, BlockNumber, AllocationCount);
#endif DEBUG
}
#ifdef DEBUG
VOID VerifyHeap(VOID)
{
ULONG Idx;
ULONG Idx2;
ULONG Count;
// Loop through the array and verify that
// everything is kosher
for (Idx=0; Idx<HeapMemBlockCount; Idx++)
{
// Check if this block is allocation
if (HeapMemBlockArray[Idx].MemBlockAllocated)
{
// This is the first block in the run so it
// had better have a length that is within range
if ((HeapMemBlockArray[Idx].BlocksAllocated < 1) || (HeapMemBlockArray[Idx].BlocksAllocated > (HeapMemBlockCount - Idx)))
{
BugCheck1("Allocation length out of range in heap table. HeapMemBlockArray[Idx].BlocksAllocated = %d\n", HeapMemBlockArray[Idx].BlocksAllocated);
}
// Now go through and verify that the rest of
// this run has the blocks marked allocated
// with a length of zero but don't check the
// first one because we already did
Count = HeapMemBlockArray[Idx].BlocksAllocated;
for (Idx2=1; Idx2<Count; Idx2++)
{
// Make sure it's allocated
if (HeapMemBlockArray[Idx + Idx2].MemBlockAllocated != TRUE)
{
BugCheck0("Heap table indicates hole in memory allocation. HeapMemBlockArray[Idx + Idx2].MemBlockAllocated != TRUE\n");
}
// Make sure the length is zero
if (HeapMemBlockArray[Idx + Idx2].BlocksAllocated != 0)
{
BugCheck0("Allocation chain has non-zero value in non-first block in heap table. HeapMemBlockArray[Idx + Idx2].BlocksAllocated != 0\n");
}
}
// Move on to the next run
Idx += Count;
}
else
{
// Nope, not allocated so make sure the length is zero
if (HeapMemBlockArray[Idx].BlocksAllocated != 0)
{
BugCheck0("Free block is start of memory allocation. HeapMemBlockArray[Idx].BlocksAllocated != 0\n");
}
}
}
}
VOID IncrementAllocationCount(VOID)
{
AllocationCount++;
}
VOID DecrementAllocationCount(VOID)
{
AllocationCount--;
}
VOID MemAllocTest(VOID)
{
PVOID MemPtr1;
PVOID MemPtr2;
PVOID MemPtr3;
PVOID MemPtr4;
PVOID MemPtr5;
MemPtr1 = AllocateMemory(4096);
printf("MemPtr1: 0x%x\n", (int)MemPtr1);
getch();
MemPtr2 = AllocateMemory(4096);
printf("MemPtr2: 0x%x\n", (int)MemPtr2);
getch();
MemPtr3 = AllocateMemory(4096);
printf("MemPtr3: 0x%x\n", (int)MemPtr3);
getch();
FreeMemory(MemPtr2);
getch();
MemPtr4 = AllocateMemory(2048);
printf("MemPtr4: 0x%x\n", (int)MemPtr4);
getch();
MemPtr5 = AllocateMemory(4096);
printf("MemPtr5: 0x%x\n", (int)MemPtr5);
getch();
}
#endif DEBUG