diff --git a/kernel-src/arch/x86-64/mmu.c b/kernel-src/arch/x86-64/mmu.c index 9151a34c..657284ec 100644 --- a/kernel-src/arch/x86-64/mmu.c +++ b/kernel-src/arch/x86-64/mmu.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #define ADDRMASK (uint64_t)0x7ffffffffffff000 #define PTMASK (uint64_t)0b111111111000000000000 @@ -186,6 +188,24 @@ static volatile struct limine_kernel_address_request kaddrreq = { .revision = 0 }; +#define ERROR_PRESENT 1 +#define ERROR_WRITE 2 +#define ERROR_FETCH 16 + +static void pfisr(isr_t *self, context_t *ctx) { + int vmmerror = 0; + if (ctx->error & ERROR_PRESENT) + vmmerror |= VMM_ACTION_READ; + + if (ctx->error & ERROR_WRITE) + vmmerror |= VMM_ACTION_WRITE; + + if (ctx->error & ERROR_FETCH) + vmmerror |= VMM_ACTION_EXEC; + + __assert(vmm_pagefault((void *)ctx->cr2, ctx->cs == 8, vmmerror)); +} + void arch_mmu_init() { template = pmm_alloc(1, PMM_SECTION_DEFAULT); __assert(template); @@ -226,4 +246,5 @@ void arch_mmu_init() { } arch_mmu_switch(FROM_HHDM(template)); + interrupt_register(14, pfisr, NULL, 0); // FIXME still haven't decided if priorities grow up or down. should be max priority } diff --git a/kernel-src/include/kernel/vmm.h b/kernel-src/include/kernel/vmm.h index d44a0908..2754d820 100644 --- a/kernel-src/include/kernel/vmm.h +++ b/kernel-src/include/kernel/vmm.h @@ -13,6 +13,10 @@ #define VMM_PERMANENT_FLAGS_MASK (VMM_FLAGS_FILE | VMM_FLAGS_SHARED | VMM_FLAGS_COPY) +#define VMM_ACTION_READ 1 +#define VMM_ACTION_WRITE 2 +#define VMM_ACTION_EXEC 4 + struct vmmcache_t; typedef struct vmmrange_t{ struct vmmrange_t *next; @@ -51,6 +55,7 @@ typedef struct { void *vmm_map(void *addr, size_t size, int flags, mmuflags_t mmuflags, void *private); void vmm_unmap(void *addr, size_t size, int flags); +bool vmm_pagefault(void *addr, bool user, int actions); vmmcontext_t *vmm_newcontext(); void vmm_init(); diff --git a/kernel-src/mm/vmm.c b/kernel-src/mm/vmm.c index 69ad2c24..5ffb7890 100644 --- a/kernel-src/mm/vmm.c +++ b/kernel-src/mm/vmm.c @@ -4,6 +4,7 @@ #include #include #include +#include #define RANGE_TOP(x) (void *)((uintptr_t)x->start + x->size) @@ -161,6 +162,55 @@ static void insertrange(vmmspace_t *space, vmmrange_t *newrange) { newrange->next = NULL; } +bool vmm_pagefault(void *addr, bool user, int actions) { + if (user == false) + return false; + + addr = (void *)ROUND_DOWN((uintptr_t)addr, PAGE_SIZE); + + vmmspace_t *space = getspace(addr); + + if (space == NULL || (space == &kernelspace && user)) + return false; + + // TODO lock + vmmrange_t *range = getrange(space, addr); + + bool status = false; + + if (range == NULL) + goto cleanup; + + // check if valid + + int invalidactions = 0; + + if ((range->mmuflags & ARCH_MMU_FLAG_READ) == 0) + invalidactions |= VMM_ACTION_READ; + + if ((range->mmuflags & ARCH_MMU_FLAG_WRITE) == 0) + invalidactions |= VMM_ACTION_WRITE; + + if ((range->mmuflags & ARCH_MMU_FLAG_NOEXEC)) + invalidactions |= VMM_ACTION_EXEC; + + if (invalidactions & actions) + goto cleanup; + + // TODO file/CoW + + void *paddr = pmm_alloc(1, 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(addr, 0, PAGE_SIZE); + + status = true; + + cleanup: + // TODO unlock + return status; +} + void *vmm_map(void *addr, volatile size_t size, int flags, mmuflags_t mmuflags, void *private) { addr = (void *)ROUND_DOWN((uintptr_t)addr, PAGE_SIZE); if (flags & VMM_FLAGS_PAGESIZE) @@ -220,6 +270,7 @@ void *vmm_map(void *addr, volatile size_t size, int flags, mmuflags_t mmuflags, goto cleanup; } + memset(MAKE_HHDM(allocated), 0, PAGE_SIZE); } } @@ -250,7 +301,7 @@ static void printspace(vmmspace_t *space) { printf("vmm: ranges:\n"); vmmrange_t *range = space->ranges; while (range) { - printf("vmm: address %p size %p flags %p\n", range->start, range->size, range->flags); + printf("vmm: address %p size %lx flags %x\n", range->start, range->size, range->flags); range = range->next; } }