diff --git a/kernel/arch/aarch64/mmu.c b/kernel/arch/aarch64/mmu.c index e537efba..a2a0c6e9 100644 --- a/kernel/arch/aarch64/mmu.c +++ b/kernel/arch/aarch64/mmu.c @@ -643,6 +643,24 @@ void mmu_set_directory(union PML * new_pml) { void mmu_invalidate(uintptr_t addr) { } +void mmu_unmap_user(uintptr_t addr, size_t size) { + for (uintptr_t a = addr; a < addr + size; a += PAGE_SIZE) { + if (a >= USER_DEVICE_MAP && a <= USER_SHM_HIGH) continue; + union PML * page = mmu_get_page(a, 0); + spin_lock(frame_alloc_lock); + if (page && page->bits.present) { + if (page->bits.ap & 1) { + mmu_frame_clear((uintptr_t)page->bits.page << PAGE_SHIFT); + page->bits.present = 0; + page->bits.ap = 0; + } + } + mmu_invalidate(a); + spin_unlock(frame_alloc_lock); + } +} + + static char * heapStart = NULL; extern char end[]; diff --git a/kernel/arch/x86_64/mmu.c b/kernel/arch/x86_64/mmu.c index 2272b8ca..2be737f4 100644 --- a/kernel/arch/x86_64/mmu.c +++ b/kernel/arch/x86_64/mmu.c @@ -836,6 +836,27 @@ void mmu_invalidate(uintptr_t addr) { arch_tlb_shootdown(addr); } +void mmu_unmap_user(uintptr_t addr, size_t size) { + for (uintptr_t a = addr; a < addr + size; a += PAGE_SIZE) { + if (a >= USER_DEVICE_MAP && a <= USER_SHM_HIGH) continue; + spin_lock(frame_alloc_lock); + union PML * page = mmu_get_page(a, 0); + if (page && page->bits.present && page->bits.user) { + if (page->bits.writable) { + assert(mem_refcounts[page->bits.page] == 0); + mmu_frame_clear((uintptr_t)page->bits.page << PAGE_SHIFT); + } else if (refcount_dec(page->bits.page) == 0) { + mmu_frame_clear((uintptr_t)page->bits.page << PAGE_SHIFT); + } + page->bits.present = 0; + page->bits.writable = 0; + } + mmu_invalidate(a); + spin_unlock(frame_alloc_lock); + } +} + + static char * heapStart = NULL; extern char end[]; diff --git a/kernel/sys/syscall.c b/kernel/sys/syscall.c index 8fbe1425..f896a386 100644 --- a/kernel/sys/syscall.c +++ b/kernel/sys/syscall.c @@ -104,6 +104,14 @@ long sys_sysfunc(long fn, char ** args) { #endif return 0; + case 43: { + extern void mmu_unmap_user(uintptr_t addr, size_t size); + PTR_VALIDATE(&args[0]); + PTR_VALIDATE(&args[1]); + mmu_unmap_user((uintptr_t)args[0], (size_t)args[1]); + return 0; + } + case TOARU_SYS_FUNC_INSMOD: /* Linux has init_module as a system call? */ if (this_core->current_process->user != 0) return -EACCES;