HIPPO: store memory regions in addition to individual free pages
This commit is contained in:
parent
30078417b6
commit
b2497d1ee0
@ -7,21 +7,38 @@
|
|||||||
*/
|
*/
|
||||||
module hulk.hippo;
|
module hulk.hippo;
|
||||||
|
|
||||||
|
import hulk.hurl;
|
||||||
|
import hulk.klog;
|
||||||
|
|
||||||
struct Hippo
|
struct Hippo
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Linked list node entry for a physical page.
|
* Linked list node entry for a single page.
|
||||||
*/
|
*/
|
||||||
private static struct PhysicalPage
|
private static struct PhysicalPage
|
||||||
{
|
{
|
||||||
PhysicalPage * next;
|
PhysicalPage * next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Linked list node entry for a region.
|
||||||
|
*/
|
||||||
|
private static struct Region
|
||||||
|
{
|
||||||
|
ulong size;
|
||||||
|
Region * next;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Linked list of free physical pages.
|
* Linked list of free physical pages.
|
||||||
*/
|
*/
|
||||||
private static __gshared PhysicalPage * free_pages;
|
private static __gshared PhysicalPage * free_pages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Linked list of free regions.
|
||||||
|
*/
|
||||||
|
private static __gshared Region * regions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of free physical pages.
|
* Number of free physical pages.
|
||||||
*/
|
*/
|
||||||
@ -48,22 +65,82 @@ struct Hippo
|
|||||||
public static void * allocate_page()
|
public static void * allocate_page()
|
||||||
{
|
{
|
||||||
PhysicalPage * pp;
|
PhysicalPage * pp;
|
||||||
if (free_pages != null)
|
if (free_pages !is null)
|
||||||
{
|
{
|
||||||
pp = free_pages;
|
pp = free_pages;
|
||||||
free_pages = free_pages.next;
|
free_pages = free_pages.next;
|
||||||
m_n_free_pages--;
|
m_n_free_pages--;
|
||||||
}
|
}
|
||||||
|
else if (regions !is null)
|
||||||
|
{
|
||||||
|
pp = cast(PhysicalPage *)(cast(ulong)regions + regions.size - PAGE_SIZE);
|
||||||
|
regions.size -= PAGE_SIZE;
|
||||||
|
if (regions.size == 0)
|
||||||
|
{
|
||||||
|
regions = regions.next;
|
||||||
|
}
|
||||||
|
m_n_free_pages--;
|
||||||
|
}
|
||||||
return cast(void *)pp;
|
return cast(void *)pp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a physical memory region.
|
||||||
|
*/
|
||||||
|
public static void free_region(T)(T start, ulong size)
|
||||||
|
{
|
||||||
|
if (regions is null)
|
||||||
|
{
|
||||||
|
/* The free regions list is empty. Append this new region. */
|
||||||
|
regions = cast(Region *)start;
|
||||||
|
regions.size = size;
|
||||||
|
regions.next = null;
|
||||||
|
}
|
||||||
|
else if (size < regions.size)
|
||||||
|
{
|
||||||
|
/* The new region is smaller than the first one in the list.
|
||||||
|
* Add the new region to the beginning of the list. */
|
||||||
|
Region * new_region = cast(Region *)start;
|
||||||
|
new_region.size = size;
|
||||||
|
new_region.next = regions;
|
||||||
|
regions = new_region;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Find the last free region that is smaller than this one. */
|
||||||
|
Region * region = regions;
|
||||||
|
while (region.next !is null && region.next.size < size)
|
||||||
|
{
|
||||||
|
region = region.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the new region after this entry. */
|
||||||
|
Region * new_region = cast(Region *)start;
|
||||||
|
new_region.size = size;
|
||||||
|
new_region.next = region.next;
|
||||||
|
region.next = new_region;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_n_free_pages += size >> 12;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of free pages.
|
* Get the number of free pages.
|
||||||
*
|
*
|
||||||
* @return The number of free pages.
|
* @return The number of free pages.
|
||||||
*/
|
*/
|
||||||
public @property size_t n_free_pages() const
|
public static @property size_t n_free_pages()
|
||||||
{
|
{
|
||||||
return m_n_free_pages;
|
return m_n_free_pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void dump_regions()
|
||||||
|
{
|
||||||
|
Region * region = regions;
|
||||||
|
while (region !is null)
|
||||||
|
{
|
||||||
|
Klog.writefln("HIPPO free region: %p %uKB", region, region.size >> 10);
|
||||||
|
region = region.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,13 +157,14 @@ struct Hurl
|
|||||||
size_t usable_memory;
|
size_t usable_memory;
|
||||||
size_t physical_address_limit;
|
size_t physical_address_limit;
|
||||||
const(size_t) fb_size = round_up_power_2(header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u, PAGE_SIZE);
|
const(size_t) fb_size = round_up_power_2(header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u, PAGE_SIZE);
|
||||||
ulong[2][2] reserved = [
|
ulong[2][2] reserved_regions = [
|
||||||
[header.bootinfo.hulk_phys, LinkerAddresses.hulk_binary_size],
|
[header.bootinfo.hulk_phys, LinkerAddresses.hulk_binary_size],
|
||||||
[cast(ulong)header.bootinfo.fb.buffer, fb_size],
|
[cast(ulong)header.bootinfo.fb.buffer, fb_size],
|
||||||
];
|
];
|
||||||
for (size_t ri = 0u; ri < reserved.length; ri++)
|
for (size_t ri = 0u; ri < reserved_regions.length; ri++)
|
||||||
{
|
{
|
||||||
reserved[ri][1] += reserved[ri][0];
|
Klog.writefln("Reserved region %p %uKB", reserved_regions[ri][0], reserved_regions[ri][1] >> 10);
|
||||||
|
reserved_regions[ri][1] += reserved_regions[ri][0];
|
||||||
}
|
}
|
||||||
for (size_t bii = 0u; bii < header.bootinfo.memory_map_count; bii++)
|
for (size_t bii = 0u; bii < header.bootinfo.memory_map_count; bii++)
|
||||||
{
|
{
|
||||||
@ -171,29 +172,14 @@ struct Hurl
|
|||||||
(header.bootinfo.memory_map[bii].type == BootInfo.MemoryRegion.Type.Conventional))
|
(header.bootinfo.memory_map[bii].type == BootInfo.MemoryRegion.Type.Conventional))
|
||||||
{
|
{
|
||||||
ulong phys = header.bootinfo.memory_map[bii].base;
|
ulong phys = header.bootinfo.memory_map[bii].base;
|
||||||
ulong phys_end = phys + header.bootinfo.memory_map[bii].size;
|
ulong size = header.bootinfo.memory_map[bii].size;
|
||||||
|
ulong phys_end = phys + size;
|
||||||
if (phys_end > physical_address_limit)
|
if (phys_end > physical_address_limit)
|
||||||
{
|
{
|
||||||
physical_address_limit = phys_end;
|
physical_address_limit = phys_end;
|
||||||
}
|
}
|
||||||
usable_memory += header.bootinfo.memory_map[bii].size;
|
usable_memory += header.bootinfo.memory_map[bii].size;
|
||||||
while (phys < phys_end)
|
add_region(phys, size, reserved_regions);
|
||||||
{
|
|
||||||
bool is_reserved = false;
|
|
||||||
for (size_t ri = 0u; ri < reserved.length; ri++)
|
|
||||||
{
|
|
||||||
if ((reserved[ri][0] <= phys) && (phys < reserved[ri][1]))
|
|
||||||
{
|
|
||||||
is_reserved = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!is_reserved)
|
|
||||||
{
|
|
||||||
Hippo.free_page(phys);
|
|
||||||
}
|
|
||||||
phys += PAGE_SIZE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,6 +209,60 @@ struct Hurl
|
|||||||
usable_memory += fb_size;
|
usable_memory += fb_size;
|
||||||
Klog.writefln("Usable memory: %uKB", usable_memory >> 10u);
|
Klog.writefln("Usable memory: %uKB", usable_memory >> 10u);
|
||||||
Klog.writefln("Kernel size: %uKB", (LinkerAddresses.hulk_binary_size + LinkerAddresses.hulk_bss_size + header.stack_size) >> 10u);
|
Klog.writefln("Kernel size: %uKB", (LinkerAddresses.hulk_binary_size + LinkerAddresses.hulk_bss_size + header.stack_size) >> 10u);
|
||||||
|
Klog.writefln("Free pages: %u", Hippo.n_free_pages);
|
||||||
|
// Hippo.dump_regions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a region of available physical memory.
|
||||||
|
*
|
||||||
|
* @param start Start address of region.
|
||||||
|
* @param size Size of region.
|
||||||
|
* @param reserved_regions List of reserved regions to exclude.
|
||||||
|
*/
|
||||||
|
private static void add_region(ulong start, ulong size, ulong[2][] reserved_regions)
|
||||||
|
{
|
||||||
|
ulong end = start + size;
|
||||||
|
bool split;
|
||||||
|
|
||||||
|
/* Skip empty regions. */
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t rri = 0; rri < reserved_regions.length; rri++)
|
||||||
|
{
|
||||||
|
/* Skip this region if it is entirely within a reserved region. */
|
||||||
|
if (reserved_regions[rri][0] <= start && reserved_regions[rri][1] >= end)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the region is partly reserved but the beginning is free. */
|
||||||
|
if (reserved_regions[rri][0] > start && reserved_regions[rri][0] < end)
|
||||||
|
{
|
||||||
|
split = true;
|
||||||
|
add_region(start, reserved_regions[rri][0] - start, reserved_regions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the region is partly reserved but the end is free. */
|
||||||
|
if (reserved_regions[rri][1] > start && reserved_regions[rri][1] < end)
|
||||||
|
{
|
||||||
|
split = true;
|
||||||
|
add_region(reserved_regions[rri][1], end - reserved_regions[rri][1], reserved_regions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (split)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If a region makes it here, it did not overlap with any reserved
|
||||||
|
* region, so the entire region can be used. */
|
||||||
|
// Klog.writefln("HURL: freeing region %p %uKB", start, size >> 10);
|
||||||
|
Hippo.free_region(start, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void map(ulong virtual, ulong physical, ulong flags)
|
public static void map(ulong virtual, ulong physical, ulong flags)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user