int x86_pagedir_map_range (DWORD *pagedir, DWORD virt, DWORD phys, DWORD pages, DWORD flags) { DWORD i; DWORD this_virt, this_phys; DWORD *pagetable; RETURN_ON_FAILURE (x86_prepare_page_table (pagedir, virt)); pagetable = x86_get_page_table (pagedir, virt); for (i = 0; i < pages; i++) { this_virt = virt + (i << 12); this_phys = phys + (i << 12); if (PAGE_ENTRY (this_virt) == 0) { if (x86_prepare_page_table (pagedir, this_virt) == -1) return KERNEL_ERROR_VALUE; pagetable = x86_get_page_table (pagedir, this_virt); } pagetable[PAGE_ENTRY (this_virt)] = this_phys | flags; } return KERNEL_SUCCESS_VALUE; }
int x86_pagedir_unset_flags (DWORD *pagedir, DWORD virt, DWORD pages, DWORD flags) { DWORD i; DWORD this_virt; DWORD *pagetable; ASSERT (x86_page_table_present (pagedir, virt)); pagetable = x86_get_page_table (pagedir, virt); for (i = 0; i < pages; i++) { this_virt = virt + (i << 12); if (PAGE_ENTRY (this_virt) == 0) { ASSERT (x86_page_table_present (pagedir, this_virt)); pagetable = x86_get_page_table (pagedir, this_virt); } pagetable[PAGE_ENTRY (this_virt)] &= ~flags; } return KERNEL_SUCCESS_VALUE; }
static pgentry_t pg_clone_tbl(pgentry_t tblent) { uint32_t flags = (uint32_t)PTE_FLAGS(tblent); paddr_t tblframe = (paddr_t)PTE_ADDR(tblent); if ((flags & PAGE_LINK) != 0) { return tblent; } if ((flags & PAGE_PRESENT) == 0) { // Table not present, but some flags are set return tblent; } paddr_t newtblframe = pg_dir_new(); pgentry_t *tbl = pg_tmp_map((pgaddr_t)tblframe); pgentry_t *newtbl = pg_tmp_map((pgaddr_t)newtblframe); for (int i = 0; i < 1024; i++) { if (tbl[i] != NilPgEnt) { newtbl[i] = pg_clone_page(tbl[i]); } } pg_tmp_unmap(tbl); pg_tmp_unmap(newtbl); return PAGE_ENTRY(newtblframe, flags); }
static pgentry_t pg_clone_page(pgentry_t page) { uint32_t flags = (uint32_t)PTE_FLAGS(page); paddr_t pgframe = (paddr_t)PTE_ADDR(page); if ((flags & PAGE_PRESENT) == 0) { // Page not present, but some flags are set return page; } if ((flags & PAGE_LINK) != 0) { return page; } paddr_t newpgframe = frame_alloc(); frame_set(newpgframe); frame_copy(pgframe, newpgframe); return PAGE_ENTRY(newpgframe, flags); }
static pgentry_t pg_clone_page_4m(pgentry_t page) { uint32_t flags = (uint32_t)PDE_FLAGS(page); paddr_t pgframe = (paddr_t)PDE_ADDR(page); if ((flags & PAGE_PRESENT) == 0) { // Page not present, but some flags are set return page; } if ((flags & PAGE_LINK) != 0) { return page; } paddr_t newpgframe = frame_alloc_4m(); int num_pages = 1024; paddr_t limit = newpgframe + (paddr_t)(num_pages * PAGE_SIZE); frame_set_range(newpgframe, limit); for (int i = 0; i < num_pages; i++) { paddr_t offset = (paddr_t)i * PAGE_SIZE; frame_copy(pgframe + offset, newpgframe + offset); } return PAGE_ENTRY(newpgframe, flags); }