diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h index ef989927..f996d7e1 100644 --- a/arch/x86/include/asm/page.h +++ b/arch/x86/include/asm/page.h @@ -110,4 +110,9 @@ int get_kernel_pgd(task_t* task); */ int get_user_pgd(task_t* task); +/* + * Change the page permission in the page tables of the current task + */ +int change_page_permissions(size_t start, size_t end, uint32_t flags); + #endif diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index 8371212a..589cdbc1 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -235,6 +236,55 @@ size_t map_region(task_t* task, size_t viraddr, size_t phyaddr, uint32_t npages, return ret; } +int change_page_permissions(size_t start, size_t end, uint32_t flags) +{ + uint32_t index1, index2, newflags; + size_t viraddr = start & 0xFFFFF000; + size_t phyaddr; + page_table_t* pgt; + page_dir_t* pgd; + + if (BUILTIN_EXPECT(!paging_enabled, 0)) + return -EINVAL; + + pgd = per_core(current_task)->pgd; + if (BUILTIN_EXPECT(!pgd, 0)) + return -EINVAL; + + spinlock_lock(per_core(current_task)->pgd_lock); + + while (viraddr < end) + { + index1 = viraddr >> 22; + index2 = (viraddr >> 12) & 0x3FF; + + while ((viraddr < end) && (index2 < 1024)) { + pgt = (page_table_t*) (page_table_t*) ((KERNEL_SPACE - 1024*PAGE_SIZE + index1*PAGE_SIZE) & 0xFFFFF000); + if (pgt && pgt->entries[index2]) { + phyaddr = pgt->entries[index2] & 0xFFFFF000; + newflags = pgt->entries[index2] & 0xFFF; // get old flags + + // update flags + if (!(flags & VMA_WRITE)) + newflags &= ~PG_RW; + else + newflags |= PG_RW; + + pgt->entries[index2] = (newflags & 0xFFF) | (phyaddr & 0xFFFFF000); + + tlb_flush_one_page(viraddr); + } + + index2++; + viraddr += PAGE_SIZE; + } + } + + spinlock_unlock(per_core(current_task)->pgd_lock); + + return 0; +} + /* * Use the first fit algorithm to find a valid address range *