From 54d636d25cda432fd411ce3d5d73a74c8a082506 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Thu, 24 Feb 2011 18:32:58 +0100 Subject: [PATCH] after process termination, the PGD and its PGTs will be freed --- arch/x86/include/asm/page.h | 5 +++++ arch/x86/mm/page.c | 25 +++++++++++++++++++++++++ include/metalsvm/mmu.h | 2 ++ include/metalsvm/tasks.h | 5 ++++- kernel/syscall.c | 4 +++- kernel/tasks.c | 25 +++++++++++++++++-------- kernel/tests.c | 2 +- mm/memory.c | 21 ++++++++++++++++++++- 8 files changed, 77 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h index bf7ba801..9b00f891 100644 --- a/arch/x86/include/asm/page.h +++ b/arch/x86/include/asm/page.h @@ -110,6 +110,11 @@ int get_kernel_pgd(task_t* task); */ int get_user_pgd(task_t* task); +/* + * Delete page directory and its page tables + */ +int drop_pgd(void); + /* * Change the page permission in the page tables of the current task */ diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index c274ecbb..64d3af48 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -116,6 +116,31 @@ int get_user_pgd(task_t* task) return 0; } +int drop_pgd(void) +{ + uint32_t i; + page_dir_t* pgd = per_core(current_task)->pgd; + size_t phy_pgd = virt_to_phys((size_t) pgd); + + if (BUILTIN_EXPECT(pgd == &boot_pgd, 0)) + return -EINVAL; + + spinlock_lock(per_core(current_task)->pgd_lock); + + for(i=KERNEL_SPACE/(1024*PAGE_SIZE); i<1024; i++) + if (pgd->entries[i] & 0xFFFFF000) + put_page(pgd->entries[i] & 0xFFFFF000); + + // freeing the page directory + put_page(phy_pgd); + + per_core(current_task)->pgd = NULL; + + spinlock_unlock(per_core(current_task)->pgd_lock); + + return 0; +} + size_t virt_to_phys(size_t viraddr) { task_t* task = per_core(current_task); diff --git a/include/metalsvm/mmu.h b/include/metalsvm/mmu.h index a0cf78b5..96220b3d 100644 --- a/include/metalsvm/mmu.h +++ b/include/metalsvm/mmu.h @@ -34,6 +34,8 @@ extern atomic_int32_t total_available_pages; int mmu_init(void); size_t get_pages(uint32_t no_pages); +static inline size_t get_page(void) { return get_pages(1); } +int put_page(size_t phyaddr); #ifdef __cplusplus } diff --git a/include/metalsvm/tasks.h b/include/metalsvm/tasks.h index 1aae59d4..19e13e6b 100644 --- a/include/metalsvm/tasks.h +++ b/include/metalsvm/tasks.h @@ -64,9 +64,12 @@ void NORETURN leave_kernel_task(void); /* by leaving user level task, this function will be called */ void NORETURN leave_user_task(void); -/* system call to terminate a user level task */ +/* system call to terminate a user level process */ void NORETURN sys_exit(int); +/* system call to create a new child process */ +int sys_fork(void); + #ifdef __cplusplus } #endif diff --git a/kernel/syscall.c b/kernel/syscall.c index aadca322..d79eae6f 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -68,10 +68,12 @@ int syscall_handler(uint32_t sys_nr, ...) ret = per_core(current_task)->id; break; case __NR_fork: + ret = sys_fork(); + break; case __NR_fstat: default: kputs("invalid system call\n"); - ret = -EINVAL; + ret = -ENOSYS; break; }; diff --git a/kernel/tasks.c b/kernel/tasks.c index 2e8cbe6f..7410c4d7 100644 --- a/kernel/tasks.c +++ b/kernel/tasks.c @@ -38,8 +38,7 @@ static spinlock_t table_lock = SPINLOCK_INIT; /* * helper function for the assembly code to determine the current task */ -task_t* get_current_task(void) -{ +task_t* get_current_task(void) { return per_core(current_task); } @@ -83,6 +82,8 @@ static void NORETURN do_exit(int arg) { kprintf("Terminate task: %u, return value %d\n", per_core(current_task)->id, arg); + wakeup_blocked_tasks(arg); + //vma_dump(per_core(current_task)); spinlock_lock(&(per_core(current_task)->vma_lock)); @@ -95,7 +96,8 @@ static void NORETURN do_exit(int arg) { spinlock_unlock(&(per_core(current_task)->vma_lock)); - wakeup_blocked_tasks(arg); + drop_pgd(); // delete page directory and its page tables + if (atomic_int32_read(&per_core(current_task)->mem_usage)) kprintf("Memory leak! Task %d did not release %d pages\n", per_core(current_task)->id, atomic_int32_read(&per_core(current_task)->mem_usage)); per_core(current_task)->status = TASK_FINISHED; @@ -114,8 +116,7 @@ void NORETURN leave_kernel_task(void) { do_exit(result); } -void NORETURN sys_exit(int arg) -{ +void NORETURN sys_exit(int arg) { do_exit(arg); } @@ -135,10 +136,14 @@ static int create_task(tid_t* id, entry_point_t ep, void* arg, int user) for(i=0; i #include #include +#include #ifdef CONFIG_MULTIBOOT #include #endif @@ -235,6 +236,25 @@ oom: return ret; } +int put_page(size_t phyaddr) +{ + uint32_t index = phyaddr / PAGE_SIZE; + task_t* task = per_core(current_task); + + if (BUILTIN_EXPECT(!phyaddr, 0)) + return -EINVAL; + + spinlock_lock(&bitmap_lock); + page_clear_mark(index); + spinlock_unlock(&bitmap_lock); + + atomic_int32_sub(&total_allocated_pages, 1); + atomic_int32_add(&total_available_pages, 1); + atomic_int32_sub(&(task->mem_usage), 1); + + return 0; +} + void* mem_allocation(size_t sz, uint32_t flags) { size_t phyaddr, viraddr; @@ -273,7 +293,6 @@ void kfree(void* addr, size_t sz) if (sz % PAGE_SIZE) npages++; - spinlock_lock(&bitmap_lock); for(i=0; i