2012-10-30 14:37:51 +00:00
|
|
|
// This is a frame allocator that uses bitmaps, and allocates space for these bitmaps via itself.
|
2011-08-25 17:56:32 +00:00
|
|
|
//
|
2012-10-30 14:37:51 +00:00
|
|
|
// The funny / tragic part is that we will access the bitmaps via a temp page at first. It will be slow,
|
|
|
|
// but it'll save us some mind-twisting if we would try to integrate a directory structure into it.
|
|
|
|
|
|
|
|
// TODO: actually implement being able to used chained metadata - right now we are limited to ~128M of RAM.
|
2011-08-25 17:56:32 +00:00
|
|
|
|
2011-08-25 18:06:16 +00:00
|
|
|
#include "Tier0/physmem.h"
|
2011-08-25 21:26:24 +00:00
|
|
|
#include "Tier0/system.h"
|
2011-08-25 17:56:32 +00:00
|
|
|
#include "Tier0/kstdio.h"
|
|
|
|
#include "Tier0/panic.h"
|
2011-08-27 17:43:37 +00:00
|
|
|
#include "Tier0/paging.h"
|
2011-08-25 17:56:32 +00:00
|
|
|
|
2012-10-30 14:37:51 +00:00
|
|
|
struct {
|
|
|
|
// The amount of memory in the system, or the top usable pointer.
|
|
|
|
u64 MemorySize;
|
|
|
|
// The first metadata structure
|
|
|
|
u64 FirstMetadata;
|
|
|
|
// for fast access
|
|
|
|
u64 MemoryFree ;
|
|
|
|
} g_PhysicalMemory;
|
2011-08-25 17:56:32 +00:00
|
|
|
|
2012-10-30 14:37:51 +00:00
|
|
|
#define PHYSMEM_METADATA_BITS (64 * 511)
|
|
|
|
#define PHYSMEM_METADATA_COVERS_BYTES (PHYSMEM_METADATA_BITS * 4096)
|
|
|
|
#define PHYSMEM_METADATA_COVERS_BITS (PHYSMEM_METADATA_BITS)
|
|
|
|
#define PHYSMEM_ADDRESS_TO_BIT_NUMBER(address) ((address) / 4096)
|
|
|
|
#define PHYSMEM_BIT_NUMBER_TO_METADATA_NUMBER(bit) ((bit) / PHYSMEM_METADATA_COVERS_BITS)
|
|
|
|
#define PHYSMEM_ADDRESS_TO_METADATA_NUMBER(address) ((address) / PHYSMEM_METADATA_COVERS_BYTES)
|
|
|
|
#define PHYSMEM_ADDRESS_TO_BIT_IN_METADATA(address) ((address) % PHYSMEM_METADATA_COVERS_BYTES)
|
|
|
|
#define PHYSMEM_BIT_NUMBER_TO_BIT_IN_METADATA(bit) ((bit) % PHYSMEM_METADATA_COVERS_BITS)
|
|
|
|
#define PHYSMEM_METADATA_SET_BIT(mdp, bit) do { (mdp)->Bitmap[(bit)/64] |= (1 << ((bit)%64)); } while(0)
|
|
|
|
#define PHYSMEM_METADATA_CLEAR_BIT(mdp, bit) do { (mdp)->Bitmap[(bit)/64] &= ~(1 << ((bit)%64)); } while(0)
|
2011-08-25 17:56:32 +00:00
|
|
|
|
2012-10-30 14:37:51 +00:00
|
|
|
typedef struct {
|
|
|
|
u64 Bitmap[511]; // covers 511*64 frames, or 130816KiB
|
|
|
|
u64 NextMetadata; // physical address of next metadata
|
|
|
|
} __attribute__((packed)) T_PHYSMEM_METADATA; // exactly 4k in size, to fit in a frame
|
|
|
|
|
|
|
|
u64 __physmem_allocate_first_page(void)
|
2011-08-25 17:56:32 +00:00
|
|
|
{
|
2012-10-30 14:37:51 +00:00
|
|
|
u64 NextPageStart = 0;
|
2011-08-25 21:26:24 +00:00
|
|
|
|
|
|
|
while (!system_memory_available(NextPageStart, PHYSMEM_PAGE_SIZE))
|
|
|
|
{
|
|
|
|
NextPageStart += PHYSMEM_PAGE_SIZE;
|
|
|
|
|
2012-10-30 14:37:51 +00:00
|
|
|
if (NextPageStart > g_PhysicalMemory.MemorySize)
|
2011-08-25 21:26:24 +00:00
|
|
|
PANIC("Out of memory!");
|
|
|
|
}
|
|
|
|
|
2012-10-30 14:37:51 +00:00
|
|
|
return NextPageStart;
|
2011-08-25 17:56:32 +00:00
|
|
|
}
|
|
|
|
|
2012-10-30 14:37:51 +00:00
|
|
|
void physmem_init(void)
|
|
|
|
{
|
|
|
|
g_PhysicalMemory.MemorySize = system_get_memory_top();
|
|
|
|
g_PhysicalMemory.MemoryFree = system_get_memory_top();
|
|
|
|
|
|
|
|
// allocate the first frame, for metadata
|
|
|
|
u64 MetadataFrame = __physmem_allocate_first_page();
|
|
|
|
kprintf("[i] Physmem: First frame @%x\n", MetadataFrame);
|
|
|
|
kprintf("[i] Physmem: First bit: %i\n", PHYSMEM_ADDRESS_TO_BIT_NUMBER(MetadataFrame));
|
|
|
|
if (PHYSMEM_ADDRESS_TO_METADATA_NUMBER(MetadataFrame) > 0)
|
|
|
|
PANIC("Physmem: First allocated address > metadata covering!");
|
|
|
|
|
|
|
|
// map it to virtual mem so we can use it
|
|
|
|
paging_temp_page_set_physical(MetadataFrame);
|
|
|
|
T_PHYSMEM_METADATA *Metadata = (T_PHYSMEM_METADATA *)paging_temp_page_get_virtual();
|
|
|
|
|
|
|
|
// zero the metadata (the 512th bit overflows into the nextmatadata field)
|
|
|
|
for (u64 i = 0; i < 512; i++)
|
|
|
|
Metadata->Bitmap[i] = 0;
|
|
|
|
|
|
|
|
// mask all the bits up to and including our metadata frame as used
|
|
|
|
for (u32 i = 0; i <= PHYSMEM_ADDRESS_TO_BIT_NUMBER(MetadataFrame); i++)
|
|
|
|
{
|
|
|
|
u32 Bit = PHYSMEM_BIT_NUMBER_TO_BIT_IN_METADATA(i);
|
|
|
|
PHYSMEM_METADATA_SET_BIT(Metadata, Bit);
|
|
|
|
g_PhysicalMemory.MemoryFree -= 4096;
|
|
|
|
}
|
|
|
|
|
|
|
|
// mask all the bits that are reserved accoriding to system
|
|
|
|
for (u32 i = PHYSMEM_ADDRESS_TO_BIT_NUMBER(MetadataFrame) + 1; i < PHYSMEM_METADATA_COVERS_BITS; i ++)
|
|
|
|
{
|
|
|
|
u64 Address = i * 4096;
|
|
|
|
if (!system_memory_available(Address, 4096))
|
|
|
|
{
|
|
|
|
PHYSMEM_METADATA_SET_BIT(Metadata, i);
|
|
|
|
g_PhysicalMemory.MemoryFree -= 4096;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
u64 physmem_allocate_page(void)
|
|
|
|
{
|
|
|
|
paging_temp_page_set_physical(g_PhysicalMemory.FirstMetadata);
|
|
|
|
T_PHYSMEM_METADATA *Metadata = (T_PHYSMEM_METADATA *)paging_temp_page_get_virtual();
|
|
|
|
for (u32 i = 0; i < PHYSMEM_METADATA_COVERS_BITS; i++)
|
|
|
|
{
|
|
|
|
if (Metadata->Bitmap[i] != 0xFFFFFFFFFFFF)
|
|
|
|
{
|
|
|
|
// scan the subbitmap
|
|
|
|
for (u8 j = 0; j < 64; j++)
|
|
|
|
if (((Metadata->Bitmap[i] >> j)&1) == 0)
|
|
|
|
{
|
|
|
|
PHYSMEM_METADATA_SET_BIT(Metadata, i * 64 + j);
|
|
|
|
g_PhysicalMemory.MemoryFree -= 4096;
|
|
|
|
return i * 64 + j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PANIC("physmem metadata addition not yet implemented - OOM!");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void physmem_free_page(u64 Page)
|
|
|
|
{
|
|
|
|
if (Page > PHYSMEM_METADATA_COVERS_BITS)
|
|
|
|
PANIC("...and where did you get that page index?");
|
|
|
|
|
|
|
|
paging_temp_page_set_physical(g_PhysicalMemory.FirstMetadata);
|
|
|
|
T_PHYSMEM_METADATA *Metadata = (T_PHYSMEM_METADATA *)paging_temp_page_get_virtual();
|
|
|
|
|
|
|
|
// todo: check for double frees
|
|
|
|
u32 Bit = PHYSMEM_BIT_NUMBER_TO_BIT_IN_METADATA(Page);
|
|
|
|
PHYSMEM_METADATA_CLEAR_BIT(Metadata, Bit);
|
|
|
|
g_PhysicalMemory.MemoryFree += 4096;
|
|
|
|
}
|
2011-08-25 17:56:32 +00:00
|
|
|
|
|
|
|
u64 physmem_page_to_physical(u64 Page)
|
|
|
|
{
|
2011-08-25 21:26:24 +00:00
|
|
|
return Page * PHYSMEM_PAGE_SIZE;
|
2011-08-25 17:56:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
u64 physmem_physical_to_page(u64 Physical)
|
|
|
|
{
|
2011-08-25 21:26:24 +00:00
|
|
|
return Physical / PHYSMEM_PAGE_SIZE;
|
2011-08-25 17:56:32 +00:00
|
|
|
}
|
2011-08-27 17:43:37 +00:00
|
|
|
|
|
|
|
void physmem_read(u64 Base, u64 Size, void *Destination)
|
|
|
|
{
|
|
|
|
u8 *DataSource = (u8 *)paging_temp_page_get_virtual();
|
|
|
|
u64 OffsetInSource = Base & 0xFFF;
|
|
|
|
|
|
|
|
u64 PreviousPageBase = Base & ~((u64)0xFFF);
|
|
|
|
paging_temp_page_set_physical(PreviousPageBase);
|
|
|
|
for (u64 i = 0; i < Size; i++)
|
|
|
|
{
|
|
|
|
u64 PageBase = (Base + i) & ~((u64)0xFFF);
|
|
|
|
|
|
|
|
if (PageBase != PreviousPageBase)
|
|
|
|
paging_temp_page_set_physical(PageBase);
|
|
|
|
|
|
|
|
PreviousPageBase = PageBase;
|
|
|
|
|
|
|
|
*((u8 *)Destination + i) = DataSource[OffsetInSource % 4096];
|
|
|
|
OffsetInSource++;
|
|
|
|
}
|
|
|
|
}
|
2012-10-30 10:53:21 +00:00
|
|
|
|
|
|
|
u64 physmem_get_free(void)
|
|
|
|
{
|
2012-10-30 14:37:51 +00:00
|
|
|
return g_PhysicalMemory.MemoryFree;
|
2012-10-30 10:53:21 +00:00
|
|
|
}
|