x86/page: add page flagging functions

main
anna 3 years ago
parent ec889c08b9
commit 637ac5ce92
Signed by: fef
GPG Key ID: EC22E476DC2D3D84

@ -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;

@ -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);

Loading…
Cancel
Save