/* * Unmaps all the page table entries and pages and frees the frames for a tid */ void unmap_process(L4_ThreadId_t tid_killed) { //Clear page table for(int i=0;i<numPTE;i++) { if(L4_ThreadNo(page_table[i].tid) == L4_ThreadNo(tid_killed)) { L4_UnmapFpage(page_table[i].tid,page_table[i].pageNo); frame_free(new_low + i * PAGESIZE); page_table[i].tid = L4_nilthread; page_table[i].referenced = 0; page_table[i].dirty = 0; page_table[i].being_updated = 0; page_table[i].error_in_transfer = 0; page_table[i].pinned = 0; } } //Clear swap table for(int i=0;i<MAX_SWAP_ENTRIES;i++) { if(L4_ThreadNo(swap_table[i].tid) == L4_ThreadNo(tid_killed)) { swap_table[i].tid = L4_nilthread; swap_table[i].next_free = head_free_swap; head_free_swap = i; } } //Remove later not required L4_CacheFlushAll(); }
/* * Returns the page table index to be evicted and the static variable * ensures it remembers the last search index for the next eviction * Uses the second chance page replacement algorithm */ static int evictPage(void) { static int evictIndex = 0; int copyIndex = evictIndex; int counter = 0; while(1) { counter++; //Check that a being updated and pinned entry is not evicted if((L4_ThreadNo(page_table[evictIndex].tid) == L4_ThreadNo(L4_nilthread)) || (page_table[evictIndex].referenced == 0 && page_table[evictIndex].being_updated == 0 && page_table[evictIndex].pinned == 0)) return evictIndex; else if(page_table[evictIndex].being_updated == 0 && page_table[evictIndex].pinned == 0){ page_table[evictIndex].referenced = 0; L4_UnmapFpage(page_table[evictIndex].tid,page_table[evictIndex].pageNo); } else if (page_table[evictIndex].being_updated == 1) { copyIndex = (copyIndex + 1) % numPTE; } //Check if we have done one full cycle of page table search without an eviction owing to //updation then bail else we go into an infinite loop if(counter == numPTE) { if(copyIndex == evictIndex) { return -1; } numPTE = 0; copyIndex = evictIndex; } evictIndex = (evictIndex + 1) % numPTE; } }
/** * Dereferences a page. This just unmaps it in the L4 page table. * @param page */ static void dereference(page_queue_item* page) { if(L4_UnmapFpage(page->tid, L4_FpageLog2(page->virtual_address, PAGESIZE_LOG2)) == FALSE) { dprintf(0, "Can't unmap page at 0x%X (error:%d)\n", page->virtual_address, L4_ErrorCode()); } //L4_CacheFlushRange(page->tid, pager_table_lookup(page->tid, page->virtual_address)->address, pager_table_lookup(page->tid, page->virtual_address)->address+PAGESIZE); }
/* * Function to unmap all entries from the page table(used for milestone 2) */ void unmap_all() { for (int i = 0; i < numPTE; i++) { if (L4_ThreadNo(page_table[i].tid) != L4_ThreadNo(L4_nilthread)) { L4_Fpage_t toUnmap = page_table[i].pageNo; L4_UnmapFpage(page_table[i].tid, toUnmap); } } }
/* * This function loads the entire elf file into the phsical frames and * maps fpages corresponding to virtual address in elf file to the process */ int load_code_segment_virtual(char *elfFile,L4_ThreadId_t new_tid) { uint32_t min[2]; uint32_t max[2]; elf_getMemoryBounds(elfFile, 0, (uint64_t*)min, (uint64_t*)max); //Now we need to reserve memory between min and max L4_Word_t lower_address = ((L4_Word_t) min[1] / PAGESIZE) * PAGESIZE; L4_Word_t upper_address = ((L4_Word_t) max[1] / PAGESIZE) * PAGESIZE; while(lower_address <= upper_address) { L4_Word_t frame = frame_alloc(); if(!frame) { //Oops out of frames unmap_process(new_tid); return -1; } else { L4_Fpage_t targetpage = L4_FpageLog2(lower_address,12); lower_address += PAGESIZE; //Now map fpage L4_Set_Rights(&targetpage,L4_FullyAccessible); L4_PhysDesc_t phys = L4_PhysDesc(frame, L4_DefaultMemory); //Map the frame to root task but enter entries in pagetable with tid since we will update the mappings once elf loading is done if (L4_MapFpage(L4_Myself(), targetpage, phys) ) { page_table[(frame-new_low)/PAGESIZE].tid = new_tid; page_table[(frame-new_low)/PAGESIZE].pinned = 1; page_table[(frame-new_low)/PAGESIZE].pageNo = targetpage; } else { unmap_process(new_tid); } } } //Now we have mapped the pages, now load elf_file should work with the virtual addresses if(elf_loadFile(elfFile,0) == 1) { //Elffile was successfully loaded //Map the fpages which were previously mapped to Myself to the tid for(int i=0;i<numPTE;i++) { if(L4_ThreadNo(new_tid) == L4_ThreadNo(page_table[i].tid)) { //Now remap the pages which were mapped to root task to the new tid L4_UnmapFpage(L4_Myself(),page_table[i].pageNo); L4_PhysDesc_t phys = L4_PhysDesc(new_low + i * PAGESIZE, L4_DefaultMemory); if(!L4_MapFpage(new_tid, page_table[i].pageNo, phys)) { unmap_process(new_tid); return -1; } } } } else { unmap_process(new_tid); } //Remove later L4_CacheFlushAll(); return 0; }
/* * Internal function to write a page table location to a swap location and to invoke a read * from swap if necessary which is invoked by the nfs write callback */ static void writeToSwap(int index,int readSwapIndex,L4_ThreadId_t tid,L4_Fpage_t fpage) { if(!swapInitialised) { initialise_swap(); } //Now we need to write the contents of pagetable index to swap file //Get a free location in the swap table int swap_index = head_free_swap; head_free_swap = swap_table[head_free_swap].next_free; if(swap_index >= MAX_SWAP_ENTRIES || swap_index < 0) { printf("Panic !!! Swap table full ! No more swapping possible!\n"); return; } //If a swap location was once used overwrite it to keep a constant swap file size if(swap_table[swap_index].offset == PTE_SENTINEL) { swap_table[swap_index].offset = swap_file_size; swap_file_size += PAGESIZE; } //Now we need to write the file, struct page_token *token_val; page_table[index].being_updated = 1; page_table[index].write_bytes_transferred = 0; page_table[index].error_in_transfer = 0; //Unmap before the first nfs write L4_UnmapFpage(page_table[index].tid,page_table[index].pageNo); for(int i=0;i<PAGESIZE/NFS_WRITE_SIZE;i++) { //Set the token val token_val = (struct page_token *) malloc(sizeof(struct page_token)); //printf("After malloc of page_token for i %d\n",i); token_val -> pageIndex = index; token_val -> swapIndex = swap_index; //Send reply only if there is no read from swap token_val -> send_reply = (readSwapIndex == -1) ? 1 : 0 ; token_val -> chunk_index = i; token_val -> destination_tid = tid; token_val -> destination_page = fpage; token_val -> source_tid = page_table[index].tid; token_val -> source_page = page_table[index].pageNo; token_val -> swapIndexToBeReadIn = readSwapIndex; //All nfs writes for each chunk are issued at once nfs_write(swapcookie,swap_table[swap_index].offset+i*NFS_WRITE_SIZE,NFS_WRITE_SIZE,(void *)(new_low + index*PAGESIZE + i*NFS_WRITE_SIZE),pager_write_callback,(uintptr_t)token_val); } send = 0; }
/* * Callback function to nfs_read from swapfile * Always replies to the thread */ void pager_read_callback(uintptr_t token,int status, fattr_t *attr, int bytes_read,char *data) { struct page_token *token_val = (struct page_token *) token; int pagetableIndex = token_val -> pageIndex; int byte_index = token_val -> chunk_index; int swapIndex = token_val -> swapIndex; if(status != 0) { page_table[pagetableIndex].error_in_transfer = 1; } else { //Copy the data read to memory char *memstart = (char *) (new_low + pagetableIndex * PAGESIZE + byte_index*NFS_READ_SIZE); memcpy(memstart,data,NFS_READ_SIZE); } page_table[pagetableIndex].read_bytes_transferred += NFS_READ_SIZE; //Check if all the callbacks have been received if(page_table[pagetableIndex].read_bytes_transferred == PAGESIZE) { if(page_table[pagetableIndex].error_in_transfer == 1) { //The memory in pagetable is inconsistent so the best thing would be to mark the //page table entry as unreferenced and hopefully its evicted soon //If this occurs for a free frame its best to free the frame //This condition is not required we would always want to free the frame(think and remove) if(!token_val -> writeToSwapIssued) { frame_free(new_low + pagetableIndex * PAGESIZE); } //Unmap the page table page whose memory we corrupted L4_UnmapFpage(page_table[pagetableIndex].tid,page_table[pagetableIndex].pageNo); page_table[pagetableIndex].tid = L4_nilthread; page_table[pagetableIndex].referenced = 0; page_table[pagetableIndex].dirty = 0; } else { //Free up the swap entry from which we read in swap_table[swapIndex].tid = L4_nilthread; swap_table[swapIndex].next_free = head_free_swap; head_free_swap = swapIndex; //Update page table page_table[pagetableIndex].tid = token_val -> destination_tid; page_table[pagetableIndex].pageNo = token_val -> destination_page; page_table[pagetableIndex].referenced = 1; page_table[pagetableIndex].dirty = 0; //Unmap the page which was written out if(token_val -> writeToSwapIssued) { L4_UnmapFpage(token_val -> source_tid,token_val -> source_page); } L4_Set_Rights(&(token_val -> destination_page),L4_Readable); L4_PhysDesc_t phys = L4_PhysDesc(new_low + pagetableIndex * PAGESIZE, L4_DefaultMemory); L4_MapFpage(token_val -> destination_tid, token_val -> destination_page, phys); L4_CacheFlushAll(); //Everything went fine } L4_Msg_t msg; L4_MsgClear(&msg); L4_MsgLoad(&msg); L4_Reply(token_val -> destination_tid); //Update the process table size update_process_table_size(token_val -> destination_tid,1); page_table[pagetableIndex].being_updated = page_table[pagetableIndex].error_in_transfer = 0; } free(token_val); }