157 lines
4.1 KiB
Plaintext
157 lines
4.1 KiB
Plaintext
|
// Kinda like a heap, but not really.
|
||
|
// (the following sizes are for x86)
|
||
|
// Based on a very large number of 4k pages. They are kept in a linear list
|
||
|
// of 512 64-bit (4kbyte) bitmaps. If there aren't any free pages in the
|
||
|
// bitmap, oh we want to mark a page as reserved further down in the list,
|
||
|
// then we create a new one and link the together. Freeing pages does not
|
||
|
// (yet?) free bitmaps. We always reserve one page for extending the list.
|
||
|
|
||
|
#include "Tier0/physical_alloc.h"
|
||
|
#include "Tier0/kstdio.h"
|
||
|
#include "Tier0/panic.h"
|
||
|
|
||
|
T_PHYSALLOC_NODE g_physalloc_root_node;
|
||
|
T_PHYSALLOC_NODE *g_physalloc_top_node;
|
||
|
u64 g_physalloc_list_size = 1;
|
||
|
u64 g_physalloc_space_for_next = 0;
|
||
|
u64 g_physalloc_mem_max = 0;
|
||
|
|
||
|
void physmem_zero_node(T_PHYSALLOC_NODE *Node)
|
||
|
{
|
||
|
for (u64 i = 0; i < PHYSALLOC_NUM_BITMAPS; i++)
|
||
|
Node->Bitmaps[i] = 0;
|
||
|
|
||
|
Node->Next = 0;
|
||
|
}
|
||
|
|
||
|
void physmem_init(u64 MemorySize)
|
||
|
{
|
||
|
// Create the first node
|
||
|
physmem_zero_node(&g_physalloc_root_node);
|
||
|
g_physalloc_top_node = &g_physalloc_root_node;
|
||
|
g_physalloc_mem_max = MemorySize;
|
||
|
}
|
||
|
|
||
|
void physmem_create_node(void)
|
||
|
{
|
||
|
if (!g_physalloc_space_for_next)
|
||
|
PANIC("No space for next physmem node! :o");
|
||
|
|
||
|
|
||
|
T_PHYSALLOC_NODE *NewNode = (T_PHYSALLOC_NODE *)g_physalloc_space_for_next;
|
||
|
kprintf("%x\n", g_physalloc_space_for_next);
|
||
|
for (;;) {}
|
||
|
physmem_zero_node(NewNode);
|
||
|
|
||
|
g_physalloc_top_node->Next = NewNode;
|
||
|
g_physalloc_top_node = NewNode;
|
||
|
|
||
|
g_physalloc_space_for_next = physmem_allocate_page();
|
||
|
g_physalloc_list_size++;
|
||
|
}
|
||
|
|
||
|
T_PHYSALLOC_NODE *physmem_traverse_list(u64 Index)
|
||
|
{
|
||
|
if (Index > g_physalloc_list_size)
|
||
|
PANIC("Tried to traverse list too far!");
|
||
|
|
||
|
u32 Current = 0;
|
||
|
T_PHYSALLOC_NODE *Node = &g_physalloc_root_node;
|
||
|
|
||
|
while (Current < Index)
|
||
|
Node = Node->Next;
|
||
|
Current++;
|
||
|
|
||
|
return Node;
|
||
|
}
|
||
|
|
||
|
void physmem_set_node_space(u64 Space)
|
||
|
{
|
||
|
g_physalloc_space_for_next = Space;
|
||
|
}
|
||
|
|
||
|
void physmem_mark_as_used(u64 Page)
|
||
|
{
|
||
|
u16 OffsetInBitmaps = Page / (PHYSALLOC_NUM_BITMAPS * 64);
|
||
|
u8 OffsetInBitmap = Page % 64;
|
||
|
|
||
|
kprintf("p: marking %i (%i %i)\n", Page, OffsetInBitmaps, OffsetInBitmap);
|
||
|
|
||
|
T_PHYSALLOC_NODE *Node;
|
||
|
|
||
|
if (g_physalloc_list_size * PHYSALLOC_NUM_BITMAPS * 64 >= Page)
|
||
|
Node = physmem_traverse_list(Page / (PHYSALLOC_NUM_BITMAPS * 64));
|
||
|
else
|
||
|
{
|
||
|
while (g_physalloc_list_size * PHYSALLOC_NUM_BITMAPS * 64 < Page)
|
||
|
{
|
||
|
physmem_create_node();
|
||
|
}
|
||
|
Node = g_physalloc_top_node;
|
||
|
}
|
||
|
|
||
|
u64 Bitmap = Node->Bitmaps[OffsetInBitmaps];
|
||
|
Bitmap |= (1 << OffsetInBitmap);
|
||
|
Node->Bitmaps[OffsetInBitmaps] = Bitmap;
|
||
|
}
|
||
|
|
||
|
u64 physmem_allocate_page(void)
|
||
|
{
|
||
|
T_PHYSALLOC_NODE *Node = &g_physalloc_root_node;
|
||
|
for (u64 nNode = 0; nNode < g_physalloc_list_size; nNode++)
|
||
|
{
|
||
|
for (u16 nBitmap = 0; nBitmap < PHYSALLOC_NUM_BITMAPS; nBitmap++)
|
||
|
{
|
||
|
u64 Bitmap = Node->Bitmaps[nBitmap];
|
||
|
if (Bitmap != 0xFFFFFFFFFFFFFFFF)
|
||
|
{
|
||
|
for (u8 nBit = 0; nBit < 64; nBit++)
|
||
|
{
|
||
|
if ((Bitmap & (1 << nBit)) == 0)
|
||
|
{
|
||
|
Bitmap |= (1 << nBit);
|
||
|
Node->Bitmaps[nBitmap] = Bitmap;
|
||
|
kprintf("physmem: allocated %i, %i, %i\n", nNode, nBitmap, nBit);
|
||
|
return nNode * PHYSALLOC_NUM_BITMAPS + nBitmap * 64 + nBit;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
Node = Node->Next;
|
||
|
}
|
||
|
|
||
|
// Still no space? Create a new node, if there is still space left in the memory
|
||
|
if (g_physalloc_mem_max && ((g_physalloc_list_size + 1) * PHYSALLOC_NUM_BITMAPS * 64 * PHYSALLOC_PAGE_SIZE > g_physalloc_mem_max))
|
||
|
{
|
||
|
kprintf("physmem: extending\n");
|
||
|
physmem_create_node();
|
||
|
Node = g_physalloc_top_node;
|
||
|
Node->Bitmaps[0] = 0x1;
|
||
|
return ((g_physalloc_list_size - 1) * PHYSALLOC_NUM_BITMAPS * 64) + 1;
|
||
|
}
|
||
|
|
||
|
PANIC("Out of memory!");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void physmem_free_page(u64 Page)
|
||
|
{
|
||
|
T_PHYSALLOC_NODE *Node = physmem_traverse_list(Page / (PHYSALLOC_NUM_BITMAPS * 64));
|
||
|
u16 OffsetInBitmaps = Page % (PHYSALLOC_NUM_BITMAPS * 64);
|
||
|
u8 OffsetInBitmap = Page % 64;
|
||
|
|
||
|
u64 Bitmap = Node->Bitmaps[OffsetInBitmaps];
|
||
|
Bitmap ^= (1 << OffsetInBitmap);
|
||
|
Node->Bitmaps[OffsetInBitmaps] = Bitmap;
|
||
|
}
|
||
|
|
||
|
u64 physmem_page_to_physical(u64 Page)
|
||
|
{
|
||
|
return Page * PHYSALLOC_PAGE_SIZE;
|
||
|
}
|
||
|
|
||
|
u64 physmem_physical_to_page(u64 Physical)
|
||
|
{
|
||
|
return Physical / PHYSALLOC_PAGE_SIZE;
|
||
|
}
|