/** * Fills a page of memory with repeating data, used to fill empty tables in * * @param page the page number to fill in * @param data the address of data to fill with * @param data_size the size of each copt of data stored */ void fill_page_with_data(unsigned int page, void * data, unsigned int data_size) { void * phys; struct mmu_L1_4k_desc * L1_table; struct mmu_L2_4k_desc * L2_table; unsigned int L1_index; unsigned int L2_index; unsigned int i; unsigned int j; unsigned int entries; //get physical address of the page phys = page_number_to_address(page); //set up a temporary manual mapping into kernel memory L1_index = get_L1_index((void*)MMU_TEMP_MAP); L2_index = get_L2_index((void*)MMU_TEMP_MAP); //get the L1 table and set the entry to map to the L2 base address L1_table = (struct mmu_L1_4k_desc *)get_page_table_addr(); fill_L1_index(L1_table, L1_index, MMU_L1_COURSE_TYPE, 0, 0, (void*)MMU_TEMP_L2_ADDR); //get the L2 table and set the entry to map to the physical base address L2_table = (struct mmu_L2_4k_desc *)(L1_table[L1_index].L2_base_addr << 10); fill_L2_index(L2_table, L2_index, MMU_L2_SMALL_TYPE, 0, 0, MMU_AP_USER_NONE, phys); //write the data out to the page entries = PAGE_SIZE / data_size; for(i = 0; i < entries; ++i) for(j = 0; j < data_size; ++j) ((char *)MMU_TEMP_MAP)[data_size*i+j] = ((char *)data)[j]; //remove the manual mapping from the mmu (done here!) L2_table[L2_index].type = MMU_L2_NOMAP_TYPE; //set L2 entry to nomap L1_table[L1_index].type = MMU_L1_NOMAP_TYPE; //set L1 entry to nomap }
/** * Gets the L1 description for a virtual memory address * * @param addr the virtual memory address to look up * * @return L1 description for the given address */ struct mmu_L1_4k_desc * get_L1_desc(void * addr) { struct mmu_L1_4k_desc * table; //get the page table address table = (struct mmu_L1_4k_desc *)get_page_table_addr(); //return the single L1 description return &(table[get_L1_index(addr)]); }
// This clears a page table entry by clearing its present bit. // It is called by the OS (in kernel.c) when a page is evicted // from a page frame. void pt_clear_page_table_entry(VPAGE_NUMBER vpage) { int L1_index = get_L1_index(vpage); int L2_index = get_L2_index(vpage); PT_ENTRY* table_L2 = first_level_page_table[L1_index]; if(table_L2 == NULL) { /* Control should never reach here */ SAY("Tried to remove a vpage that does not exist!\n"); return; } table_L2[L2_index] = 0; //clear the entry }
// This inserts into the page table an entry mapping of the // the specified virtual page to the specified page frame. // It might require the creation of a second-level page table // to hold the entry, if it doesn't already exist. void pt_update_pagetable(VPAGE_NUMBER vpage, PAGEFRAME_NUMBER pframe) { int L1_index = get_L1_index(vpage); int L2_index = get_L2_index(vpage); PT_ENTRY* table_L2 = first_level_page_table[L1_index]; if(table_L2 == NULL) { table_L2 = create_L2_page_table(L1_index); } unsigned int value = pframe | PRESENT_BIT_MASK; table_L2[L2_index] = value; }
//This is called when there is a TLB_miss. // Using the page table, this looks up the page frame // corresponding to the specified virtual page. // If the desired page is not present, the variable page_fault // should be set to TRUE (otherwise FALSE). PAGEFRAME_NUMBER pt_get_pageframe(VPAGE_NUMBER vpage) { int L1_index = get_L1_index(vpage); int L2_index = get_L2_index(vpage); PAGEFRAME_NUMBER pf_number = find_pf_number(L1_index,L2_index); if (pf_number == -1) { //could not be found page_fault = TRUE; } else{ page_fault = FALSE; return pf_number; } }