pt_entry* vmmngr_ptable_lookup_entry(ptable* p, virtual_addr addr) { if (p) return &p->entries[PAGE_TABLE_INDEX(addr)]; set_last_error(EINVAL, VMEM_BAD_ARGUMENT, EO_VMMNGR); return 0; }
inline pt_entry * vmmngr_ptable_lookup_entry(ptable * p, virtual_addr addr) { if (p) { return &p->m_entries[ PAGE_TABLE_INDEX(addr) ]; } return 0; }
void vmmngr_free_page(virtual_addr addr) { pt_entry * pte; pte = (pt_entry *) ((uint32_t) vmmngr_get_ptable_address(addr) + PAGE_TABLE_INDEX(addr)); pmmngr_free_block((void *) pt_entry_pfn(*pte)); pt_entry_del_attrib(pte, I86_PTE_PRESENT); }
int vmmngr_alloc_page(virtual_addr virt) { pdirectory * pd = (pdirectory *) PAGE_DIRECTORY_ADDRESS; pd_entry * pde = &pd->m_entries[PAGE_DIRECTORY_INDEX(virt)]; if ((!pd) || (!pde)) { return 0; } if (!pd_entry_is_present(*pde)) { ptable *newpt = pmmngr_alloc_block(); if (!newpt) { return 0; } *pde = (pd_entry) 0; pd_entry_add_attrib(pde, I86_PDE_PRESENT); pd_entry_add_attrib(pde, I86_PDE_WRITABLE); pd_entry_set_frame(pde, (physical_addr) newpt); memset(vmmngr_get_ptable_address(virt), 0, sizeof(ptable)); } ptable * pt = vmmngr_get_ptable_address(virt); pt_entry *pte = &pt->m_entries[PAGE_TABLE_INDEX(virt)]; if (pt_entry_is_present(*pte)) { return 1; } if (!vmmngr_commit_page(pte)) { return 0; } return 1; }
void vmmngr_map_page(void * phys, void * virt) { pageinfo pginf = vmmngr_virt_to_page_index(virt); pdirectory * page_directory = kernel_page_dir; //vmmngr_get_directory(); pd_entry * e = &page_directory->m_entries[PAGE_DIRECTORY_INDEX((uint32_t) virt)]; if (!pd_entry_is_present(*e)) { ptable * new_table = (ptable *) pmmngr_alloc_block(); if (!new_table) { return; } ptable * virtual_table = (ptable *) (0xFFC00000 + (pginf.pagetable * 0x1000)); pd_entry * entry = &kernel_page_dir->m_entries[pginf.pagetable]; pd_entry_add_attrib(entry, I86_PDE_PRESENT); pd_entry_add_attrib(entry, I86_PDE_WRITABLE); pd_entry_set_frame(entry, (physical_addr) new_table); memset(virtual_table, 0, sizeof(ptable)); pt_entry * page = &virtual_table->m_entries[pginf.page]; pt_entry_set_frame(page, (physical_addr) phys); pt_entry_add_attrib(page, I86_PTE_PRESENT); pt_entry_add_attrib(page, I86_PTE_WRITABLE); return; } ptable * table = (ptable *) PAGE_GET_PHYSICAL_ADDRESS(e); pt_entry * page = &table->m_entries[PAGE_TABLE_INDEX((uint32_t) virt)]; pt_entry_set_frame(page, (physical_addr) phys); pt_entry_add_attrib(page, I86_PTE_PRESENT); pt_entry_add_attrib(page, I86_PTE_WRITABLE); }
void vmmngr_initialize(physical_addr dir_address) { int i = 0; int frame = 0; int virt = 0; ptable * table = (ptable *) pmmngr_alloc_block(); if (!table) { return; } ptable * table2 = (ptable *) pmmngr_alloc_block(); if (!table2) { pmmngr_free_block(table); return; } memset(table, 0, sizeof(ptable)); for (i = 0, frame = 0x0, virt = 0x00000000; i < 1024; ++i, frame+=4096, virt+=4096) { pt_entry page = 0; pt_entry_add_attrib(&page, I86_PTE_PRESENT); pt_entry_set_frame(&page, frame); table->m_entries[PAGE_TABLE_INDEX(virt)] = page; } for (i = 0, frame = 0x0, virt = 0xc0000000; i < 1024; ++i, frame+=4096, virt+=4096) { pt_entry page = 0; pt_entry_add_attrib(&page, I86_PTE_PRESENT); pt_entry_set_frame(&page, frame); table2->m_entries[PAGE_TABLE_INDEX(virt)] = page; } pdirectory * dir = (pdirectory *) dir_address;// pmmngr_alloc_block(); if (!dir) { pmmngr_free_block(table); pmmngr_free_block(table2); return; } memset(dir, 0, sizeof(pdirectory)); pd_entry * entry = &dir->m_entries[PAGE_DIRECTORY_INDEX(0x00000000)]; pd_entry_add_attrib(entry, I86_PDE_PRESENT); pd_entry_add_attrib(entry, I86_PDE_WRITABLE); pd_entry_set_frame(entry, (physical_addr) table); pd_entry * entry2 = &dir->m_entries[PAGE_DIRECTORY_INDEX(0xc0000000)]; pd_entry_add_attrib(entry2, I86_PDE_PRESENT); pd_entry_add_attrib(entry2, I86_PDE_WRITABLE); pd_entry_set_frame(entry2, (physical_addr) table2); pd_entry * entry3 = &dir->m_entries[PAGE_DIRECTORY_INDEX(0xFFC00000)]; pd_entry_add_attrib(entry3, I86_PDE_PRESENT); pd_entry_add_attrib(entry3, I86_PDE_WRITABLE); pd_entry_set_frame(entry3, (physical_addr) dir); vmmngr_switch_pdirectory(dir); pmmngr_paging_enable(1); }
void do_page_fault (process_t *proc, unsigned int linear_addr, long error_code) { page_frame_t *new_page, *page_frame; unsigned int phys_frame_addr; pagetable_entry_t *pte; int pf_ok; //Only handle usermode writes to present pages (not present ones later (pagein)) //if ((error_code & PAGE_FAULT_P) && // (error_code & PAGE_FAULT_RW) && // (error_code & PAGE_FAULT_US)) if (error_code & PAGE_FAULT_P) { // // CHECK IF WE REALLY SHOULD COPY THIS // (with vm_blocks) // pf_ok = 0; //Only write pagefaults handled if (error_code & PAGE_FAULT_RW) { if ((linear_addr >= proc->vm_data.vm_start) && (linear_addr < proc->vm_data.vm_end) && (proc->vm_data.vm_flags & VM_READWRITE)) pf_ok = 1; if ((linear_addr >= proc->vm_stack.vm_start) && (linear_addr < proc->vm_stack.vm_end) && (proc->vm_stack.vm_flags & VM_READWRITE)) pf_ok = 1; if ((linear_addr >= proc->vm_kernel_stack.vm_start) && (linear_addr < proc->vm_kernel_stack.vm_end) && (proc->vm_kernel_stack.vm_flags & VM_READWRITE)) pf_ok = 1; } if (!pf_ok) { printf ("*real* page fault (out of bounds), should terminate task!\n"); printf ("present=%s, write=%s, usermode=%s, address=0x%x, dir=0x%x\n", ((int) error_code & PAGE_FAULT_P) ? "true" : "false", ((int) error_code & PAGE_FAULT_RW) ? "true" : "false", ((int) error_code & PAGE_FAULT_US) ? "true" : "false", linear_addr, (int) (proc->tss.cr3)); printf ("data start 0x%x, data end 0x%x, flags 0x%x\n", (int) proc->vm_data.vm_start, (int) proc->vm_data.vm_end, (int) proc->vm_data.vm_flags); printf ("stack start 0x%x, stack end 0x%x, flags 0x%x\n", (int) proc->vm_stack.vm_start, (int) proc->vm_stack.vm_end, (int) proc->vm_stack.vm_flags); while(1); } //Get dir pte = (pagetable_entry_t *) proc->tss.cr3; //Get table from dir pte = (pagetable_entry_t *) PTE_TO_PHYSICAL(pte[PAGE_DIR_INDEX(linear_addr)]); //Get page from table phys_frame_addr = PTE_TO_PHYSICAL(pte[PAGE_TABLE_INDEX(linear_addr)]); //Check use count of this page frame page_frame = &page_frames[PHYS_TO_FRAME_NR (phys_frame_addr)]; if (page_frame->count > 1) { //Page in use by others, we need to copy new_page = get_free_page(); if (new_page == NULL) panic ("Can't COW, no free pages!"); //Copy page //printf ("COW(copy, 0x%x->0x%x)\n", phys_frame_addr, new_page->page_frame_nr * PAGE_SIZE); copy_page (phys_frame_addr, new_page->page_frame_nr * PAGE_SIZE); //Remap pagetable map_page (proc, new_page->page_frame_nr * PAGE_SIZE, linear_addr & PHYS_PAGE_MASK, PAGE_PRESENT | PAGE_USER | PAGE_WRITEABLE); //Decrease use count page_frame->count--; } else if (page_frame->count == 1) { //The page is not in use by others, just remap //printf ("COW(remap, 0x%x)\n", linear_addr); //Remap pagetable map_page (proc, phys_frame_addr, linear_addr & PHYS_PAGE_MASK, PAGE_PRESENT | PAGE_USER | PAGE_WRITEABLE); } else { printf ("Page frame has invalid use count!\n"); while (1); } //Schedule next process schedule(); } else { printf ("*real* page fault (page not present), should terminate task!\n"); printf ("present=%s, write=%s, usermode=%s, address=0x%x, dir=0x%x\n", ((int) error_code & PAGE_FAULT_P) ? "true" : "false", ((int) error_code & PAGE_FAULT_RW) ? "true" : "false", ((int) error_code & PAGE_FAULT_US) ? "true" : "false", linear_addr, (int) (proc->tss.cr3)); printf ("data start 0x%x, data end 0x%x, flags 0x%x\n", (int) proc->vm_data.vm_start, (int) proc->vm_data.vm_end, (int) proc->vm_data.vm_flags); printf ("stack start 0x%x, stack end 0x%x, flags 0x%x\n", (int) proc->vm_stack.vm_start, (int) proc->vm_stack.vm_end, (int) proc->vm_stack.vm_flags); while(1); } }