Explicitly check page boundaries when adding bootloader-provided memory regions

This commit is contained in:
Josh Holtrop 2021-08-16 17:35:11 -04:00
parent ebfeca47b5
commit 6b1de7c9d4
2 changed files with 38 additions and 18 deletions

View File

@ -1,15 +1,15 @@
#include "mm.h"
#define PAGE_SIZE 4096u
typedef struct mm_page_entry_s {
size_t count;
struct mm_page_entry_s * next;
} mm_region_entry_t;
static mm_region_entry_t * mm_next_free_region;
static size_t mm_free_page_count;
static size_t mm_free_pages;
static size_t mm_total_ram;
static size_t kernel_start_address;
static size_t kernel_size;
extern uint8_t _hos_mem_start;
extern uint8_t _hos_mem_end;
@ -22,12 +22,11 @@ static void mm_add_ram_region(size_t base, size_t size)
region->next = mm_next_free_region;
mm_next_free_region = region;
mm_total_ram += size;
mm_free_page_count = pages;
mm_free_pages = pages;
}
void mm_register_ram_region(uint64_t base, size_t size)
{
size &= ~(PAGE_SIZE - 1u);
/* Ignore any RAM region above 4GB. */
if (base >= 0x100000000ull)
{
@ -37,34 +36,43 @@ void mm_register_ram_region(uint64_t base, size_t size)
{
size = (size_t)(0x100000000ull - base);
}
size_t end_address = mm_page_floor((size_t)base + size);
size_t start_address = mm_page_ceil(base);
size = end_address - start_address;
if (size < PAGE_SIZE)
{
return;
}
size_t kernel_end_address = kernel_start_address + kernel_size;
/* Add regions before and after kernel RAM. */
size_t region_base = (size_t)base;
if (region_base < (size_t)&_hos_mem_start)
if (start_address < kernel_start_address)
{
/* RAM region begins before kernel RAM. */
size_t this_sz = size;
if ((region_base + this_sz) > (size_t)&_hos_mem_start)
if ((start_address + this_sz) > kernel_start_address)
{
this_sz = (size_t)&_hos_mem_start - region_base;
this_sz = kernel_start_address - start_address;
}
mm_add_ram_region(region_base, this_sz);
mm_add_ram_region(start_address, this_sz);
}
if ((region_base + size) > (size_t)&_hos_mem_end)
if ((start_address + size) > kernel_end_address)
{
/* RAM region ends after kernel RAM. */
size_t this_sz = size;
if (region_base < (size_t)&_hos_mem_end)
if (start_address < kernel_end_address)
{
this_sz = (region_base + size) - (size_t)&_hos_mem_end;
region_base = (size_t)&_hos_mem_end;
this_sz = (start_address + size) - kernel_end_address;
start_address = kernel_end_address;
}
mm_add_ram_region(region_base, this_sz);
mm_add_ram_region(start_address, this_sz);
}
}
void mm_init(void)
{
mm_total_ram = mm_get_kernel_size();;
kernel_start_address = mm_page_floor((size_t)&_hos_mem_start);
kernel_size = mm_page_ceil((size_t)&_hos_mem_end - kernel_start_address);
mm_total_ram = kernel_size;
}
size_t mm_get_total_ram(void)
@ -74,10 +82,10 @@ size_t mm_get_total_ram(void)
size_t mm_get_kernel_address(void)
{
return (size_t)&_hos_mem_start;
return kernel_start_address;
}
size_t mm_get_kernel_size(void)
{
return &_hos_mem_end - &_hos_mem_start;
return kernel_size;
}

View File

@ -4,6 +4,18 @@
#include <stdint.h>
#include <stddef.h>
#define PAGE_SIZE 4096u
static inline size_t mm_page_floor(size_t bytes)
{
return bytes & ~(PAGE_SIZE - 1u);
}
static inline size_t mm_page_ceil(size_t bytes)
{
return (bytes + PAGE_SIZE - 1u) & ~(PAGE_SIZE - 1u);
}
void mm_init(void);
void mm_register_ram_region(uint64_t base, size_t size);
size_t mm_get_total_ram(void);