From 637ac5ce9223dc085a9be15f91527272ef080fb3 Mon Sep 17 00:00:00 2001 From: fef Date: Wed, 10 Nov 2021 02:03:41 +0100 Subject: [PATCH] x86/page: add page flagging functions --- arch/x86/mm/page.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ include/gay/mm.h | 26 ++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index cf088b4..f159644 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -165,6 +165,50 @@ uintptr_t unmap_page(void *virt) return phys; } +enum pflags get_pflags(void *page) +{ + usize pd_index = ((uintptr_t)page >> PAGE_SHIFT) / 1024; + usize pt_index = ((uintptr_t)page >> PAGE_SHIFT) % 1024; + + struct x86_page_directory_entry *pde = &X86_CURRENT_PD->entries[pd_index]; + if (pde->huge) { + return *(unsigned long *)pde & ~PAGE_MASK; + } else if (pde->present) { + struct x86_page_table_entry *pte = &X86_CURRENT_PT(pd_index)->entries[pt_index]; + return *(unsigned long *)pte & ~PAGE_MASK; + } else { + return 0; + } +} + +int set_pflags(void *page, enum pflags pflags) +{ + usize pd_index = ((uintptr_t)page >> PAGE_SHIFT) / 1024; + usize pt_index = ((uintptr_t)page >> PAGE_SHIFT) % 1024; + + struct x86_page_directory_entry *pde = &X86_CURRENT_PD->entries[pd_index]; + if (pflags & P_HUGE) { + /* if the PDE referred to a Page Table, free it first */ + if (pde->present && !pde->huge) + free_pages((void *)((uintptr_t)pde->shifted_address << PAGE_SHIFT)); + + unsigned long pde_raw = *(unsigned long *)pde; + pde_raw &= PAGE_MASK; + pde_raw |= (pflags & ~PAGE_MASK); + *(unsigned long *)pde = pde_raw; + } else if (pde->present) { + struct x86_page_table_entry *pte = X86_CURRENT_PTE(pd_index, pt_index); + unsigned long pte_raw = *(unsigned long *)pte; + pte_raw &= PAGE_MASK; + pte_raw |= (pflags & ~PAGE_MASK); + *(unsigned long *)pte = pte_raw; + } else { + return -EEXIST; + } + + return 0; +} + void x86_isr_page_fault(trap_frame_t *frame, u32 error_code) { void *address; diff --git a/include/gay/mm.h b/include/gay/mm.h index 295d2ae..4045c1c 100644 --- a/include/gay/mm.h +++ b/include/gay/mm.h @@ -116,6 +116,32 @@ int map_page(uintptr_t phys, void *virt, enum pflags flags); */ uintptr_t unmap_page(void *virt); +/** + * @brief Get a page's flags in the page tables. + * + * @param page Page to get the flags of (if the page is in a hugepage area, + * the flags for that hugepage will be returned with `P_HUGE = 1`) + * @return The flags, as currently stored in the page table structures + * (but not necessarily applied if they have been modified and `vm_flush()` + * has not been called yet!) + */ +enum pflags get_pflags(void *page); + +/** + * @brief Update a page's flags in the page tables. + * You should always use this in conjunction with `get_pflags()`, as in getting + * the flags first, then toggling the flags you need to, and then setting them + * in the tables again. This is because this method will clear *any* previous + * flags. + * + * @param page Page to set flags for (if flags has `P_HUGE` set, must be + * `HUGEPAGE_SIZE` aligned, otherwise `PAGE_SIZE` aligned) + * @param flags Flags to set + * @return 0 on success, or a negative value if either a page table allocation + * failed or + */ +int set_pflags(void *page, enum pflags flags); + /** @brief Flush the TLB. */ void vm_flush(void);