mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
vmm: copy on write and changes to how page faults are handled
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include <logging.h>
|
||||
#include <kernel/interrupt.h>
|
||||
#include <kernel/vmm.h>
|
||||
#include <arch/cpu.h>
|
||||
|
||||
#define ADDRMASK (uint64_t)0x7ffffffffffff000
|
||||
#define PTMASK (uint64_t)0b111111111000000000000
|
||||
@@ -162,6 +163,16 @@ void *arch_mmu_getphysical(pagetableptr_t table, void *vaddr) {
|
||||
return (void *)(*entry & ADDRMASK);
|
||||
}
|
||||
|
||||
bool arch_mmu_ispresent(pagetableptr_t table, void *vaddr) {
|
||||
uint64_t *entry = get_page(table, vaddr);
|
||||
return entry == NULL ? false : *entry & ARCH_MMU_FLAGS_READ;
|
||||
}
|
||||
|
||||
bool arch_mmu_iswritable(pagetableptr_t table, void *vaddr) {
|
||||
uint64_t *entry = get_page(table, vaddr);
|
||||
return entry == NULL ? false : *entry & ARCH_MMU_FLAGS_WRITE;
|
||||
}
|
||||
|
||||
void arch_mmu_switch(pagetableptr_t table) {
|
||||
asm volatile("mov %%rax, %%cr3" : : "a"(table));
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ void arch_mmu_unmap(pagetableptr_t table, void *vaddr);
|
||||
void arch_mmu_remap(pagetableptr_t table, void *paddr, void *vaddr, mmuflags_t flags);
|
||||
void arch_mmu_switch(pagetableptr_t table);
|
||||
void *arch_mmu_getphysical(pagetableptr_t table, void *vaddr);
|
||||
bool arch_mmu_ispresent(pagetableptr_t table, void *vaddr);
|
||||
bool arch_mmu_iswritable(pagetableptr_t table, void *vaddr);
|
||||
pagetableptr_t arch_mmu_newtable();
|
||||
void arch_mmu_init();
|
||||
|
||||
|
||||
+1
-1
@@ -184,7 +184,7 @@ void pmm_init() {
|
||||
|
||||
pages = MAKE_HHDM((page_t *)biggest->base);
|
||||
pagecount = ROUND_UP(top, PAGE_SIZE) / PAGE_SIZE;
|
||||
memset(pages, 0, pagecount / sizeof(page_t));
|
||||
memset(pages, 0, pagecount * sizeof(page_t));
|
||||
printf("pmm: %d pages used for page list\n", ROUND_UP(pagecount * sizeof(page_t), PAGE_SIZE) / PAGE_SIZE);
|
||||
|
||||
// place pages in free lists
|
||||
|
||||
+43
-9
@@ -285,6 +285,8 @@ static void unmap(vmmspace_t *space, void *address, size_t size) {
|
||||
|
||||
}
|
||||
|
||||
static void *zeropage;
|
||||
|
||||
bool vmm_pagefault(void *addr, bool user, int actions) {
|
||||
if (user == false && addr > USERSPACE_END)
|
||||
return false;
|
||||
@@ -320,20 +322,45 @@ bool vmm_pagefault(void *addr, bool user, int actions) {
|
||||
if (invalidactions & actions)
|
||||
goto cleanup;
|
||||
|
||||
// TODO CoW
|
||||
thread_t *thread = _cpu()->thread;
|
||||
proc_t *proc = thread ? thread->proc : NULL;
|
||||
cred_t *cred = proc ? &proc->cred : NULL;
|
||||
|
||||
if (range->flags & VMM_FLAGS_FILE) {
|
||||
uintmax_t mapoffset = (uintptr_t)addr - (uintptr_t)range->start;
|
||||
__assert(VOP_MMAP(range->vnode, addr, range->offset + mapoffset, mmuflagstovnodeflags(range->mmuflags) | (range->flags & VMM_FLAGS_SHARED ? V_FFLAGS_SHARED : 0), cred) == 0);
|
||||
status = true;
|
||||
if (arch_mmu_ispresent(_cpu()->vmmctx->pagetable, addr) == false) {
|
||||
// page not present in the page tables
|
||||
if (range->flags & VMM_FLAGS_FILE) {
|
||||
uintmax_t mapoffset = (uintptr_t)addr - (uintptr_t)range->start;
|
||||
__assert(VOP_MMAP(range->vnode, addr, range->offset + mapoffset, mmuflagstovnodeflags(range->mmuflags) | (range->flags & VMM_FLAGS_SHARED ? V_FFLAGS_SHARED : 0), cred) == 0);
|
||||
status = true;
|
||||
} else {
|
||||
// anonymous memory. map the zero'd page
|
||||
status = arch_mmu_map(_cpu()->vmmctx->pagetable, zeropage, addr, range->mmuflags & ~ARCH_MMU_FLAGS_WRITE);
|
||||
if (!status)
|
||||
printf("vmm: out of memory to map zero page into address space\n");
|
||||
else
|
||||
pmm_hold(zeropage);
|
||||
}
|
||||
} else if (arch_mmu_iswritable(_cpu()->vmmctx->pagetable, addr) == false){
|
||||
// page present but not writeable in the page tables
|
||||
if ((range->flags & VMM_FLAGS_FILE) && (range->flags & VMM_FLAGS_SHARED)) {
|
||||
// TODO shared file mappings (set as dirty and set as writable on PTE)
|
||||
} else {
|
||||
void *oldphys = arch_mmu_getphysical(_cpu()->vmmctx->pagetable, addr);
|
||||
// do copy on write
|
||||
void *newphys = pmm_allocpage(PMM_SECTION_DEFAULT);
|
||||
if (newphys == NULL) {
|
||||
printf("vmm: out of memory to do copy on write on address space\n");
|
||||
status = false;
|
||||
} else {
|
||||
// this assert should always succeed, here just to make sure
|
||||
memcpy(MAKE_HHDM(newphys), MAKE_HHDM(oldphys), PAGE_SIZE);
|
||||
__assert(arch_mmu_map(_cpu()->vmmctx->pagetable, newphys, addr, range->mmuflags));
|
||||
pmm_release(oldphys);
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
void *paddr = pmm_allocpage(PMM_SECTION_DEFAULT);
|
||||
__assert(paddr); // XXX handle these better than an assert once there are signals and such
|
||||
__assert(arch_mmu_map(_cpu()->vmmctx->pagetable, paddr, addr, range->mmuflags));
|
||||
memset(MAKE_HHDM(paddr), 0, PAGE_SIZE);
|
||||
// another thread already did the work, so just return success
|
||||
status = true;
|
||||
}
|
||||
|
||||
@@ -576,6 +603,7 @@ extern void *_rodata_end;
|
||||
extern volatile struct limine_memmap_request pmm_liminemap;
|
||||
|
||||
void vmm_init() {
|
||||
// set up initial state
|
||||
__assert(sizeof(vmmcache_t) <= PAGE_SIZE);
|
||||
MUTEX_INIT(&kernelspace.lock);
|
||||
MUTEX_INIT(&kernelspace.pflock);
|
||||
@@ -589,12 +617,14 @@ void vmm_init() {
|
||||
|
||||
vmm_switchcontext(&vmm_kernelctx);
|
||||
|
||||
// map HHDM
|
||||
for (uint64_t i = 0; i < pmm_liminemap.response->entry_count; ++i) {
|
||||
struct limine_memmap_entry *e = pmm_liminemap.response->entries[i];
|
||||
mmuflags_t mmuflags = ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC;
|
||||
__assert(vmm_map(MAKE_HHDM(e->base), e->length, VMM_FLAGS_EXACT, mmuflags, NULL));
|
||||
}
|
||||
|
||||
// map kernel
|
||||
__assert(vmm_map(&_text_start, (uintptr_t)&_text_end - (uintptr_t)&_text_start, VMM_FLAGS_EXACT, ARCH_MMU_FLAGS_READ, NULL));
|
||||
__assert(vmm_map(&_rodata_start, (uintptr_t)&_rodata_end - (uintptr_t)&_rodata_start, VMM_FLAGS_EXACT, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_NOEXEC, NULL));
|
||||
__assert(vmm_map(&_data_start, (uintptr_t)&_data_end - (uintptr_t)&_data_start, VMM_FLAGS_EXACT, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, NULL));
|
||||
@@ -602,5 +632,9 @@ void vmm_init() {
|
||||
// null page
|
||||
vmm_map(MAKE_HHDM(NULL), PAGE_SIZE, VMM_FLAGS_EXACT, ARCH_MMU_FLAGS_NOEXEC, NULL);
|
||||
|
||||
// zero page
|
||||
zeropage = pmm_allocpage(PMM_SECTION_DEFAULT);
|
||||
memset(MAKE_HHDM(zeropage), 0, PAGE_SIZE);
|
||||
|
||||
printspace(&kernelspace);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user