/******************************************************************************* * Page fault handler. When the CPU encounters an invalid address mapping in a * process' page table, it invokes the CPU via this handler. The OS then * allocates a physical frame for the requested page (either by using a free * frame or evicting one), changes the process' page table to reflect the * mapping and then restarts the interrupted process. * * @param vpn The virtual page number requested from the current process. * @param write If the CPU is writing to the page, this is 1. Otherwise, it's 0. * @return The physical frame the OS has mapped to the virtual page. */ pfn_t pagefault_handler(vpn_t request_vpn, int write) { pfn_t victim_pfn; vpn_t victim_vpn; pcb_t *victim_pcb; /* Sanity Check */ assert(current_pagetable != NULL); /* Find a free frame */ victim_pfn = get_free_frame(); assert(victim_pfn < CPU_NUM_FRAMES); /* make sure the victim_pfn is valid */ /* Use the reverse lookup table to find the victim. */ victim_vpn = rlt[victim_pfn].vpn; victim_pcb = rlt[victim_pfn].pcb; /* * FIX ME : Problem 4 * If victim page is occupied - if it is not the pcb will be NULL: * * 1) If it's dirty, save it to disk with page_to_disk() * 2) Invalidate the page's entry in the victim's page table. * 3) Clear the victim page's TLB entry using the function tlb_clearone(). */ pte_t *victim_entry; if (victim_pcb != NULL) { victim_entry = victim_pcb->pagetable + victim_vpn; if (victim_entry->dirty == 1) { page_to_disk(victim_pfn, victim_vpn, victim_pcb->pid); victim_entry->dirty = 0; } victim_entry->valid = 0; //victim_entry->used = 0; tlb_clearone(victim_vpn); } printf("PAGE FAULT (VPN %u), evicting (PFN %u VPN %u)\n", request_vpn, victim_pfn, victim_vpn); /* FIX ME */ /* Update the reverse lookup table to replace the victim entry info with this * process' info instead (pcb and vpn) * Update the current process' page table (pfn and valid) */ rlt_t *rlt_entry = rlt + victim_pfn; rlt_entry->vpn = request_vpn; rlt_entry->pcb = current; pte_t *current_entry = current_pagetable + request_vpn; current_entry->valid = 1; current_entry->pfn = victim_pfn; /* * Retreive the page from disk. Note that is really a lie: we save pages in * memory (since doing file I/O for this simulation would be annoying and * wouldn't add that much to the learning). Also, if the page technically * does't exist yet (i.e., the page has never been accessed yet, we return a * blank page. Real systems would check for invalid pages and possibly read * stuff like code pages from disk. For purposes of this simulation, we won't * worry about that. =) */ page_from_disk(victim_pfn, request_vpn, current->pid); return victim_pfn; }
/******************************************************************************* * Page fault handler. When the CPU encounters an invalid address mapping in a * process' page table, it invokes the CPU via this handler. The OS then * allocates a physical frame for the requested page (either by using a free * frame or evicting one), changes the process' page table to reflect the * mapping and then restarts the interrupted process. * * @param vpn The virtual page number requested. * @param write If the CPU is writing to the page, this is 1. Otherwise, it's 0. * @return The physical frame the OS has mapped to the virtual page. */ pfn_t pagefault_handler(vpn_t request_vpn, int write) { pfn_t victim_pfn; vpn_t victim_vpn; pcb_t *victim_pcb; /* Sanity Check */ assert(current_pagetable != NULL); /* Find a free frame */ victim_pfn = get_free_frame(); assert(victim_pfn < CPU_NUM_FRAMES); /* make sure the victim_pfn is valid */ /* Use the reverse lookup table to find the victim. */ victim_vpn = rlt[victim_pfn].vpn; victim_pcb = rlt[victim_pfn].pcb; /* * FIX ME : Problem 4 * If victim page is occupied: * * 1) If it's dirty, save it to disk with page_to_disk() * 2) Invalidate the page's entry in the victim's page table. * 3) Clear the victim page's TLB entry (hint: tlb_clearone()). */ pte_t* victim; pte_t current_v; if (victim_pcb != NULL) { victim = victim_pcb -> pagetable; current_v = victim[victim_vpn]; if (current_v.dirty && current_v.valid) { page_to_disk(victim_pfn, victim_vpn, victim_pcb ->pid); } victim[victim_vpn].valid = 0; tlb_clearone(victim_vpn); } printf("****PAGE FAULT has occurred at VPN %u. Evicting (PFN %u VPN %u) as victim.\n", request_vpn, victim_pfn, victim_vpn); /* Update the reverse lookup table so that it knows about the requesting process */ /* FIX ME */ rlt[victim_pfn].pcb = current; rlt[victim_pfn].vpn = request_vpn; /* Update the requesting process' page table */ /* FIX ME */ current_pagetable[request_vpn].pfn = victim_pfn; current_pagetable[request_vpn].valid = 1; current_pagetable[request_vpn].dirty = write; current_pagetable[request_vpn].used = 1; /* * Retreive the page from disk. Note that is really a lie: we save pages in * memory (since doing file I/O for this simulation would be annoying and * wouldn't add that much to the learning). Also, if the page technically * does't exist yet (i.e., the page has never been accessed yet, we return a * blank page. Real systems would check for invalid pages and possibly read * stuff like code pages from disk. For purposes of this simulation, we won't * worry about that. =) */ page_from_disk(victim_pfn, request_vpn, current->pid); return victim_pfn; }