2022-11-19 16:59:49 +00:00
|
|
|
#include "memory/MemoryManager.h"
|
2022-11-30 16:16:36 +00:00
|
|
|
#include "Log.h"
|
2022-12-04 14:14:07 +00:00
|
|
|
#include "arch/CPU.h"
|
2022-11-13 13:29:15 +00:00
|
|
|
#include "arch/MMU.h"
|
2022-11-19 16:59:49 +00:00
|
|
|
#include "boot/bootboot.h"
|
2022-12-04 11:42:43 +00:00
|
|
|
#include <luna/Alignment.h>
|
2022-12-04 14:14:07 +00:00
|
|
|
#include <luna/Bitmap.h>
|
2022-12-04 11:42:43 +00:00
|
|
|
#include <luna/String.h>
|
|
|
|
#include <luna/SystemError.h>
|
|
|
|
#include <luna/Types.h>
|
2022-12-04 14:14:07 +00:00
|
|
|
#include <luna/Units.h>
|
2022-11-13 13:29:15 +00:00
|
|
|
|
|
|
|
extern BOOTBOOT bootboot;
|
|
|
|
|
2022-11-13 15:54:07 +00:00
|
|
|
extern u8 start_of_kernel_rodata[1];
|
|
|
|
extern u8 end_of_kernel_rodata[1];
|
|
|
|
extern u8 start_of_kernel_data[1];
|
|
|
|
extern u8 end_of_kernel_data[1];
|
|
|
|
|
2022-11-13 13:29:15 +00:00
|
|
|
static u64 free_mem = 0;
|
|
|
|
static u64 used_mem = 0;
|
|
|
|
static u64 reserved_mem = 0;
|
|
|
|
|
|
|
|
static u64 start_index = 0;
|
|
|
|
|
2022-12-04 14:14:07 +00:00
|
|
|
static Bitmap g_frame_bitmap;
|
2022-11-13 13:29:15 +00:00
|
|
|
|
2022-12-04 14:14:07 +00:00
|
|
|
#define CHECK_PAGE_ALIGNED(address) check(is_aligned(address, ARCH_PAGE_SIZE))
|
|
|
|
|
|
|
|
static usize get_physical_address_space_size()
|
2022-11-13 13:29:15 +00:00
|
|
|
{
|
2022-12-04 14:14:07 +00:00
|
|
|
MMapEnt* ptr = &bootboot.mmap;
|
|
|
|
u64 biggest_ptr = 0;
|
|
|
|
u64 biggest_ptr_size = 0;
|
|
|
|
u64 mmap_entries = (bootboot.size - 128) / 16;
|
|
|
|
for (u64 i = 0; i < mmap_entries; i++)
|
|
|
|
{
|
|
|
|
if (MMapEnt_Ptr(ptr) > biggest_ptr)
|
|
|
|
{
|
|
|
|
biggest_ptr = MMapEnt_Ptr(ptr);
|
|
|
|
biggest_ptr_size = MMapEnt_Size(ptr);
|
|
|
|
}
|
2022-11-13 13:29:15 +00:00
|
|
|
|
2022-12-04 14:14:07 +00:00
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return biggest_ptr + biggest_ptr_size; // This would be the address at the end of the last entry, thus the whole
|
|
|
|
// address space that was passed to us.
|
|
|
|
}
|
2022-11-19 21:28:45 +00:00
|
|
|
|
2022-11-13 13:29:15 +00:00
|
|
|
namespace MemoryManager
|
|
|
|
{
|
2022-11-16 19:02:04 +00:00
|
|
|
Result<void> protect_kernel_sections()
|
|
|
|
{
|
2022-11-19 21:27:59 +00:00
|
|
|
const u64 rodata_size = (u64)(end_of_kernel_rodata - start_of_kernel_rodata);
|
|
|
|
const u64 rodata_pages = get_blocks_from_size(rodata_size, ARCH_PAGE_SIZE);
|
2022-11-16 19:02:04 +00:00
|
|
|
TRY(remap((u64)start_of_kernel_rodata, rodata_pages, MMU::NoExecute));
|
|
|
|
|
2022-11-19 21:27:59 +00:00
|
|
|
const u64 data_size = (u64)(end_of_kernel_data - start_of_kernel_data);
|
|
|
|
const u64 data_pages = get_blocks_from_size(data_size, ARCH_PAGE_SIZE);
|
2022-11-16 19:02:04 +00:00
|
|
|
TRY(remap((u64)start_of_kernel_data, data_pages, MMU::NoExecute | MMU::ReadWrite));
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-12-04 14:14:07 +00:00
|
|
|
void init_physical_frame_allocator()
|
2022-11-13 13:29:15 +00:00
|
|
|
{
|
|
|
|
u64 total_mem = 0;
|
|
|
|
|
2022-12-04 14:14:07 +00:00
|
|
|
void* biggest_usable_memory_block = nullptr;
|
|
|
|
u64 biggest_usable_memory_block_size = 0;
|
2022-11-13 13:29:15 +00:00
|
|
|
|
|
|
|
// walk the memory map
|
|
|
|
MMapEnt* ptr = &bootboot.mmap;
|
2022-11-19 21:25:03 +00:00
|
|
|
u64 mmap_entries = (bootboot.size - 128) / 16;
|
2022-11-13 13:29:15 +00:00
|
|
|
for (u64 i = 0; i < mmap_entries; i++)
|
|
|
|
{
|
|
|
|
u64 size = MMapEnt_Size(ptr);
|
|
|
|
total_mem += size;
|
|
|
|
if (!MMapEnt_IsFree(ptr))
|
|
|
|
{
|
|
|
|
ptr++;
|
|
|
|
continue;
|
|
|
|
}
|
2022-12-04 14:14:07 +00:00
|
|
|
if (size > biggest_usable_memory_block_size)
|
2022-11-13 13:29:15 +00:00
|
|
|
{
|
2022-12-04 14:14:07 +00:00
|
|
|
biggest_usable_memory_block = (void*)MMapEnt_Ptr(ptr);
|
|
|
|
biggest_usable_memory_block_size = MMapEnt_Size(ptr);
|
2022-11-13 13:29:15 +00:00
|
|
|
}
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
2022-12-04 14:14:07 +00:00
|
|
|
// The entire physical address space. May contain inexistent memory holes, thus differs from total_mem which
|
|
|
|
// only counts existent memory. Our bitmap needs to have space for all of the physical address space, since
|
|
|
|
// usable addresses will be scattered across it.
|
|
|
|
usize physical_address_space_size = get_physical_address_space_size();
|
|
|
|
|
|
|
|
char* frame_bitmap_addr = (char*)biggest_usable_memory_block;
|
|
|
|
usize frame_bitmap_size = physical_address_space_size / ARCH_PAGE_SIZE / 8 + 1;
|
|
|
|
|
|
|
|
// This should never happen, unless memory is very fragmented. Usually there is always a very big block of
|
|
|
|
// usable memory and then some tiny blocks around it.
|
|
|
|
if (frame_bitmap_size >= biggest_usable_memory_block_size) [[unlikely]]
|
2022-11-13 13:29:15 +00:00
|
|
|
{
|
2022-12-04 14:14:07 +00:00
|
|
|
kerrorln("ERROR: No single memory block is enough to hold the frame bitmap");
|
|
|
|
CPU::efficient_halt();
|
2022-11-13 13:29:15 +00:00
|
|
|
}
|
|
|
|
|
2022-12-04 14:14:07 +00:00
|
|
|
g_frame_bitmap.initialize(frame_bitmap_addr, frame_bitmap_size);
|
|
|
|
|
|
|
|
g_frame_bitmap.clear(true); // Set all pages to used/reserved by default, then clear out the free ones
|
2022-11-13 13:29:15 +00:00
|
|
|
|
|
|
|
ptr = &bootboot.mmap;
|
2022-11-19 21:25:03 +00:00
|
|
|
for (u64 i = 0; i < mmap_entries; i++)
|
2022-11-13 13:29:15 +00:00
|
|
|
{
|
2022-11-19 21:25:03 +00:00
|
|
|
u64 index = MMapEnt_Ptr(ptr) / ARCH_PAGE_SIZE;
|
2022-12-04 14:14:07 +00:00
|
|
|
u64 pages = MMapEnt_Size(ptr) / ARCH_PAGE_SIZE;
|
2022-11-13 13:29:15 +00:00
|
|
|
if (!MMapEnt_IsFree(ptr)) { reserved_mem += MMapEnt_Size(ptr); }
|
|
|
|
else
|
|
|
|
{
|
|
|
|
free_mem += MMapEnt_Size(ptr);
|
2022-12-04 14:14:07 +00:00
|
|
|
g_frame_bitmap.clear_region(index, pages, false);
|
2022-11-13 13:29:15 +00:00
|
|
|
}
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
2022-12-04 14:14:07 +00:00
|
|
|
lock_frames((u64)frame_bitmap_addr, frame_bitmap_size / ARCH_PAGE_SIZE + 1);
|
2022-11-13 13:29:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void init()
|
|
|
|
{
|
2022-12-04 14:14:07 +00:00
|
|
|
init_physical_frame_allocator();
|
2022-11-13 13:29:15 +00:00
|
|
|
MMU::setup_initial_page_directory();
|
|
|
|
}
|
|
|
|
|
2022-11-19 21:27:08 +00:00
|
|
|
void lock_frame(u64 frame)
|
2022-11-13 13:29:15 +00:00
|
|
|
{
|
2022-11-19 21:27:08 +00:00
|
|
|
const u64 index = ((u64)frame) / ARCH_PAGE_SIZE;
|
2022-12-04 14:14:07 +00:00
|
|
|
if (g_frame_bitmap.get(index)) return;
|
|
|
|
g_frame_bitmap.set(index, true);
|
2022-11-16 19:37:32 +00:00
|
|
|
used_mem += ARCH_PAGE_SIZE;
|
|
|
|
free_mem -= ARCH_PAGE_SIZE;
|
2022-11-13 13:29:15 +00:00
|
|
|
}
|
|
|
|
|
2022-11-19 21:27:08 +00:00
|
|
|
void lock_frames(u64 frames, u64 count)
|
2022-11-13 13:29:15 +00:00
|
|
|
{
|
2022-11-19 21:27:08 +00:00
|
|
|
for (u64 index = 0; index < count; index++) { lock_frame(frames + (index * ARCH_PAGE_SIZE)); }
|
2022-11-13 13:29:15 +00:00
|
|
|
}
|
|
|
|
|
2022-11-19 21:27:08 +00:00
|
|
|
Result<u64> alloc_frame()
|
2022-11-13 13:29:15 +00:00
|
|
|
{
|
2022-12-04 14:14:07 +00:00
|
|
|
for (u64 index = start_index; index < g_frame_bitmap.size(); index++)
|
2022-11-13 13:29:15 +00:00
|
|
|
{
|
2022-12-04 14:14:07 +00:00
|
|
|
if (g_frame_bitmap.get(index)) continue;
|
|
|
|
g_frame_bitmap.set(index, true);
|
2022-11-13 13:29:15 +00:00
|
|
|
start_index = index + 1;
|
2022-11-16 19:37:32 +00:00
|
|
|
free_mem -= ARCH_PAGE_SIZE;
|
|
|
|
used_mem += ARCH_PAGE_SIZE;
|
|
|
|
return index * ARCH_PAGE_SIZE;
|
2022-11-13 13:29:15 +00:00
|
|
|
}
|
|
|
|
|
2022-11-30 16:13:59 +00:00
|
|
|
return err(ENOMEM);
|
2022-11-13 13:29:15 +00:00
|
|
|
}
|
|
|
|
|
2022-11-19 21:27:08 +00:00
|
|
|
Result<void> free_frame(u64 frame)
|
2022-11-13 13:29:15 +00:00
|
|
|
{
|
2022-11-19 21:27:08 +00:00
|
|
|
const u64 index = frame / ARCH_PAGE_SIZE;
|
2022-12-04 14:14:07 +00:00
|
|
|
if (index > g_frame_bitmap.size()) return err(EFAULT);
|
|
|
|
if (!g_frame_bitmap.get(index)) return err(EFAULT);
|
|
|
|
g_frame_bitmap.set(index, false);
|
2022-11-16 19:37:32 +00:00
|
|
|
used_mem -= ARCH_PAGE_SIZE;
|
|
|
|
free_mem += ARCH_PAGE_SIZE;
|
2022-11-13 13:29:15 +00:00
|
|
|
if (start_index > index) start_index = index;
|
|
|
|
return {};
|
|
|
|
}
|
2022-11-13 15:56:03 +00:00
|
|
|
|
2022-11-16 19:30:34 +00:00
|
|
|
Result<void> remap(u64 address, usize count, int flags)
|
2022-11-16 19:02:04 +00:00
|
|
|
{
|
2022-11-19 21:28:45 +00:00
|
|
|
CHECK_PAGE_ALIGNED(address);
|
2022-11-16 19:02:04 +00:00
|
|
|
|
|
|
|
while (count--)
|
|
|
|
{
|
|
|
|
TRY(MMU::remap(address, flags));
|
2022-11-16 19:37:32 +00:00
|
|
|
address += ARCH_PAGE_SIZE;
|
2022-11-16 19:02:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-11-19 21:32:48 +00:00
|
|
|
Result<void> map_frames_at(u64 virt, u64 phys, usize count, int flags)
|
2022-11-19 21:28:45 +00:00
|
|
|
{
|
|
|
|
CHECK_PAGE_ALIGNED(virt);
|
|
|
|
CHECK_PAGE_ALIGNED(phys);
|
|
|
|
|
|
|
|
while (count--)
|
|
|
|
{
|
|
|
|
TRY(MMU::map(virt, phys, flags));
|
|
|
|
virt += ARCH_PAGE_SIZE;
|
|
|
|
phys += ARCH_PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<u64> alloc_at(u64 virt, usize count, int flags)
|
|
|
|
{
|
|
|
|
CHECK_PAGE_ALIGNED(virt);
|
|
|
|
|
2022-11-20 14:11:53 +00:00
|
|
|
u64 start = virt;
|
|
|
|
|
2022-11-19 21:28:45 +00:00
|
|
|
while (count--)
|
|
|
|
{
|
|
|
|
u64 frame = TRY(alloc_frame());
|
|
|
|
TRY(MMU::map(virt, frame, flags));
|
|
|
|
virt += ARCH_PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
2022-11-20 14:11:53 +00:00
|
|
|
return start;
|
2022-11-19 21:28:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Result<void> unmap_owned(u64 virt, usize count)
|
|
|
|
{
|
|
|
|
CHECK_PAGE_ALIGNED(virt);
|
|
|
|
|
|
|
|
while (count--)
|
|
|
|
{
|
|
|
|
u64 frame = TRY(MMU::unmap(virt));
|
|
|
|
TRY(free_frame(frame));
|
|
|
|
virt += ARCH_PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<void> unmap_weak(u64 virt, usize count)
|
|
|
|
{
|
|
|
|
CHECK_PAGE_ALIGNED(virt);
|
|
|
|
|
|
|
|
while (count--)
|
|
|
|
{
|
|
|
|
TRY(MMU::unmap(virt));
|
|
|
|
virt += ARCH_PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-11-16 19:30:34 +00:00
|
|
|
Result<void> remap_unaligned(u64 address, usize count, int flags)
|
2022-11-16 19:02:04 +00:00
|
|
|
{
|
2022-11-16 19:37:32 +00:00
|
|
|
if (!is_aligned(address, ARCH_PAGE_SIZE)) count++;
|
|
|
|
address = align_down(address, ARCH_PAGE_SIZE);
|
2022-11-16 19:02:04 +00:00
|
|
|
|
|
|
|
while (count--)
|
|
|
|
{
|
|
|
|
TRY(MMU::remap(address, flags));
|
2022-11-16 19:37:32 +00:00
|
|
|
address += ARCH_PAGE_SIZE;
|
2022-11-16 19:02:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-11-19 17:38:47 +00:00
|
|
|
bool validate_readable_page(u64 address)
|
|
|
|
{
|
|
|
|
auto rc = MMU::get_flags(address);
|
|
|
|
if (rc.has_error()) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool validate_writable_page(u64 address)
|
|
|
|
{
|
|
|
|
auto rc = MMU::get_flags(address);
|
|
|
|
if (rc.has_error()) return false;
|
|
|
|
if (rc.release_value() & MMU::ReadWrite) return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-11-13 15:56:03 +00:00
|
|
|
u64 free()
|
|
|
|
{
|
|
|
|
return free_mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 used()
|
|
|
|
{
|
|
|
|
return used_mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 reserved()
|
|
|
|
{
|
|
|
|
return reserved_mem;
|
|
|
|
}
|
2022-11-30 15:30:42 +00:00
|
|
|
|
|
|
|
u64 total()
|
|
|
|
{
|
|
|
|
return free_mem + used_mem + reserved_mem;
|
|
|
|
}
|
2022-11-13 13:29:15 +00:00
|
|
|
}
|