[kernel] Add VMA interface
Finished the VMA kobject and added the related syscalls. Processes can now allocate memory! Other changes in this commit: - stop using g_frame_allocator and add frame_allocator::get() - make sure to release all handles in the process dtor - fix kutil::map::iterator never comparing to end()
This commit is contained in:
@@ -5,8 +5,6 @@
|
||||
#include "objects/vm_area.h"
|
||||
#include "vm_space.h"
|
||||
|
||||
extern frame_allocator &g_frame_allocator;
|
||||
|
||||
int
|
||||
vm_space::area::compare(const vm_space::area &o) const
|
||||
{
|
||||
@@ -91,6 +89,21 @@ vm_space::get(uintptr_t addr, uintptr_t *base)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
vm_space::copy_from(const vm_space &source, uintptr_t from, uintptr_t to, size_t count)
|
||||
{
|
||||
page_table::iterator sit {from, source.m_pml4};
|
||||
page_table::iterator dit {to, m_pml4};
|
||||
|
||||
while (count--) {
|
||||
uint64_t &e = dit.entry(page_table::level::pt);
|
||||
if (e & page_table::flag::present) {
|
||||
// TODO: handle clobbering mapping
|
||||
}
|
||||
e = sit.entry(page_table::level::pt);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
vm_space::page_in(uintptr_t virt, uintptr_t phys, size_t count)
|
||||
{
|
||||
@@ -107,17 +120,37 @@ vm_space::page_in(uintptr_t virt, uintptr_t phys, size_t count)
|
||||
void
|
||||
vm_space::clear(uintptr_t addr, size_t count)
|
||||
{
|
||||
using memory::frame_size;
|
||||
|
||||
uintptr_t free_start = 0;
|
||||
size_t free_count = 0;
|
||||
|
||||
frame_allocator &fa = frame_allocator::get();
|
||||
page_table::iterator it {addr, m_pml4};
|
||||
|
||||
while (count--) {
|
||||
uint64_t &e = it.entry(page_table::level::pt);
|
||||
if (e & page_table::flag::present) {
|
||||
g_frame_allocator.free(e & ~0xfffull, 1);
|
||||
}
|
||||
bool allowed = (e & page_table::flag::allowed);
|
||||
e = 0;
|
||||
if (allowed) e |= page_table::flag::allowed;
|
||||
uintptr_t phys = e & ~0xfffull;
|
||||
|
||||
if (e & page_table::flag::present) {
|
||||
if (free_count && phys == free_start + (free_count * frame_size)) {
|
||||
++free_count;
|
||||
} else {
|
||||
if (free_count)
|
||||
fa.free(free_start, free_count);
|
||||
free_start = phys;
|
||||
free_count = 1;
|
||||
}
|
||||
fa.free(e & ~0xfffull, 1);
|
||||
}
|
||||
|
||||
e = 0 | (allowed ? page_table::flag::allowed : page_table::flag::none);
|
||||
++it;
|
||||
}
|
||||
|
||||
if (free_count)
|
||||
fa.free(free_start, free_count);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -173,22 +206,32 @@ vm_space::handle_fault(uintptr_t addr, fault_type fault)
|
||||
if (fault && fault_type::present)
|
||||
return false;
|
||||
|
||||
if (!it.allowed())
|
||||
uintptr_t base = 0;
|
||||
vm_area *area = get(addr, &base);
|
||||
|
||||
if (!area && !it.allowed())
|
||||
return false;
|
||||
|
||||
uintptr_t phys = 0;
|
||||
size_t n = g_frame_allocator.allocate(1, &phys);
|
||||
size_t n = frame_allocator::get().allocate(1, &phys);
|
||||
kassert(n, "Failed to allocate a new page during page fault");
|
||||
|
||||
page_table::flag flags =
|
||||
page_table::flag::present |
|
||||
page_table::flag::write |
|
||||
page_table::flag::allowed |
|
||||
(area
|
||||
? page_table::flag::none
|
||||
: page_table::flag::allowed) |
|
||||
(is_kernel()
|
||||
? page_table::flag::global
|
||||
: page_table::flag::user);
|
||||
|
||||
it.entry(page_table::level::pt) = phys | flags;
|
||||
if (area) {
|
||||
uintptr_t offset = page - base;
|
||||
area->commit(phys, offset, 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user