diff --git a/src/arch/x86_64/include/arch/mmu.h b/src/arch/x86_64/include/arch/mmu.h index 80c14521..6a14da62 100644 --- a/src/arch/x86_64/include/arch/mmu.h +++ b/src/arch/x86_64/include/arch/mmu.h @@ -3,6 +3,7 @@ #include #include +#include #define PAGE_SIZE 4096 @@ -11,10 +12,13 @@ #define ARCH_MMU_MAP_USER (uint64_t)(1 << 2) #define ARCH_MMU_MAP_NOEXEC (uint64_t)(1 << 63) #define ARCH_MMU_MAP_PAGESIZE (uint64_t)(1 << 7) +#define ARCH_MMU_MAP_ACCESSED (uint64_t)(1 << 5) typedef uint64_t* arch_mmu_tableptr; int arch_mmu_map(arch_mmu_tableptr, void*, void*, size_t); +bool arch_mmu_isaccessed(arch_mmu_tableptr, void*); +void* arch_mmu_getphysicaladdr(arch_mmu_tableptr, void*); void arch_mmu_unmap(arch_mmu_tableptr, void*); void arch_mmu_init(); diff --git a/src/arch/x86_64/mmu.c b/src/arch/x86_64/mmu.c index 53f4668d..ca7cef4f 100644 --- a/src/arch/x86_64/mmu.c +++ b/src/arch/x86_64/mmu.c @@ -31,6 +31,22 @@ static void invalidate(void* addr){ asm("invlpg (%%rax)" : : "a"(addr)); } + +static uint64_t* next(uint64_t* table, size_t offset){ + + table = (uint64_t)table & ~(0xFFF); + + if(table < limine_hhdm_offset){ + table = (uint64_t)table & ~(1 << 63); // remove NX + table = (uint64_t)table + (uint64_t)limine_hhdm_offset; + } + + return table[offset]; + +} + +// FIXME make the accessed addresses be in the limine hhdm + static bool setpage(arch_mmu_tableptr context, void* vaddr, uint64_t entry){ uint64_t addr = (uint64_t)vaddr; size_t pdpt = (addr >> 39) & 0b111111111; @@ -81,6 +97,40 @@ static bool setpage(arch_mmu_tableptr context, void* vaddr, uint64_t entry){ +static uint64_t getmapping(arch_mmu_tableptr context, void* vaddr){ + uint64_t addr = (uint64_t)vaddr; + size_t pdpt = (addr >> 39) & 0b111111111; + size_t pd = (addr >> 30) & 0b111111111; + size_t pt = (addr >> 21) & 0b111111111; + size_t page = (addr >> 12) & 0b111111111; + + if(!context[pdpt]) return 0; + + uint64_t* table = next(context, pd); + + if(!table) return 0; + + table = next(table, pt); + + if(!table) return 0; + + table = next(table, page); + + return table; + +} + +void* arch_mmu_getphysicaladdr(arch_mmu_tableptr context, void* addr){ + uint64_t paddr = getmapping(context, addr); + paddr &= ~(0xFFF); + paddr &= ~ARCH_MMU_MAP_NOEXEC; + return paddr; +} + +bool arch_mmu_isaccessed(arch_mmu_tableptr context, void* addr){ + return (getmapping(context, addr) & ARCH_MMU_MAP_ACCESSED) != 0; +} + int arch_mmu_map(arch_mmu_tableptr context, void* paddr, void* vaddr, size_t flags){ uint64_t entry; changeentry(&entry, paddr, flags); diff --git a/src/include/kernel/vmm.h b/src/include/kernel/vmm.h index f45bf743..ba0a11ab 100644 --- a/src/include/kernel/vmm.h +++ b/src/include/kernel/vmm.h @@ -55,5 +55,5 @@ bool vmm_setused(void* addr, size_t pagec, size_t mmuflags); bool vmm_unmap(void* addr, size_t pagec); bool vmm_map(void* paddr, void* vaddr, size_t pagec, size_t mmuflags); void* vmm_alloc(size_t pagec, size_t mmuflags); - +bool vmm_setfree(void* addr, size_t pagec); #endif diff --git a/src/sys/mm/vmm.c b/src/sys/mm/vmm.c index 941f1f43..d123d694 100644 --- a/src/sys/mm/vmm.c +++ b/src/sys/mm/vmm.c @@ -303,8 +303,36 @@ static void* findfirstfreearea(vmm_mapping* map, size_t pagec){ } -static bool unmap(vmm_mapping* start, void* addr, size_t pagec){ +static bool unmap(vmm_mapping** mapstart, void* addr, size_t pagec){ + if(pagec == 0) return true; + vmm_mapping *map = *mapstart; + void* savedaddr = addr; + arch_mmu_tableptr context = arch_getcls()->context->context; + for(size_t page = 0; page < pagec; ++page, addr += PAGE_SIZE){ + map = findmappingfromaddr(map, addr); + switch(map->type){ + case VMM_TYPE_ANON: + if(arch_mmu_isaccessed(context, addr)){ + void* paddr = arch_mmu_getphysicaladdr(context, addr); + pmm_free(paddr, 1); + } + break; + + case VMM_TYPE_FILE: + _panic("File mappings not supported!", 0); + + default: + continue; + + } + } + + + setmap(mapstart, savedaddr, pagec, 0, VMM_TYPE_FREE, 0, 0); + + return true; + } @@ -340,6 +368,35 @@ bool vmm_unmap(void* addr, size_t pagec){ } +bool vmm_setused(void* addr, size_t pagec, size_t mmuflags){ + spinlock_acquire(&klock); + + bool result = setmap(&kmapstart, addr, pagec, mmuflags, VMM_TYPE_ANON, 0, 0); + + spinlock_release(&klock); + return result; +} + +bool vmm_setfree(void* addr, size_t pagec){ + spinlock_acquire(&klock); + + bool result = setmap(&kmapstart, addr, pagec, 0, VMM_TYPE_FREE, 0, 0); + + spinlock_release(&klock); + return result; +} + +bool vmm_map(void* paddr, void* vaddr, size_t pagec, size_t mmuflags){ + spinlock_acquire(&klock); + bool result = setmap(&kmapstart, vaddr, pagec, mmuflags, VMM_TYPE_ANON, 0, 0); + + for(size_t page = 0; page < pagec && result; ++page) + result = arch_mmu_map(arch_getcls()->context->context, paddr + page*PAGE_SIZE, vaddr + page*PAGE_SIZE, mmuflags); + + spinlock_release(&klock); + return result; +} + // called by the page fault handler bool vmm_dealwithrequest(void* addr){ @@ -425,20 +482,8 @@ void vmm_init(){ setmap(&kmapstart, datastart, (dataend - datastart) / PAGE_SIZE, ARCH_MMU_MAP_READ | ARCH_MMU_MAP_WRITE | ARCH_MMU_MAP_NOEXEC, VMM_TYPE_ANON, 0, 0); - - debug_dumpkernelmappings(); - - printf("Writing to 10 demand paged pages\n"); - - volatile char* all = vmm_alloc(10, ARCH_MMU_MAP_READ | ARCH_MMU_MAP_WRITE); - printf("Alloc at %p\n", all); + - for(size_t i = 0; i < PAGE_SIZE*10; ++i) - *(all + i) = 0; - - - printf("WOOOOOO!!!\n"); - }