unsigned int kheap_virtual_address(unsigned int physical_address) { //TODO: [PROJECT 2016 - Kernel Dynamic Allocation/Deallocation] kheap_virtual_address() // Write your code here, remove the panic and write your code //panic("kheap_virtual_address() is not implemented yet...!!"); //return the virtual address corresponding to given physical_address //refer to the project documentation for the detailed steps //sacn the whole kernel heap to find the mapped virtual address uint32 va; for(va = KERNEL_HEAP_START; va < (uint32) keepBlocks[nextBlock - 1].blockStartVirtualAddress + keepBlocks[nextBlock - 1].blockSize; va += PAGE_SIZE){ //use kheap_physical_address uint32 framePhysicalAddress = kheap_physical_address(va); if(framePhysicalAddress == physical_address) return va; } //change this "return" according to your answer return 0; }
// Allocates a new env and loads the named user program into it. struct Env* env_create(char* user_program_name, unsigned int page_WS_size) { //[1] get pointer to the start of the "user_program_name" program in memory // Hint: use "get_user_program_info" function, // you should set the following "ptr_program_start" by the start address of the user program uint8* ptr_program_start = 0; struct UserProgramInfo* ptr_user_program_info = get_user_program_info(user_program_name); if(ptr_user_program_info == 0) return NULL; ptr_program_start = ptr_user_program_info->ptr_start ; // if(ptr_user_program_info->environment != NULL) // { // cprintf("env_create: an old environment already exist for [%s]!! \nfreeing the old one by calling start_env_free....\n", ptr_user_program_info->environment->prog_name); // start_env_free(ptr_user_program_info->environment); // // //return ptr_user_program_info; // } //[2] allocate new environment, (from the free environment list) //if there's no one, return NULL // Hint: use "allocate_environment" function struct Env* e = NULL; if(allocate_environment(&e) < 0) { return 0; } //[2.5 - 2012] Set program name inside the environment e->prog_name = ptr_user_program_info->name ; //[3] allocate a frame for the page directory, Don't forget to set the references of the allocated frame. //REMEMBER: "allocate_frame" should always return a free frame uint32* ptr_user_page_directory; unsigned int phys_user_page_directory; if(USE_KHEAP) { ptr_user_page_directory = create_user_directory(); phys_user_page_directory = kheap_physical_address((uint32)ptr_user_page_directory); } else { int r; struct Frame_Info *p = NULL; allocate_frame(&p) ; p->references = 1; ptr_user_page_directory = STATIC_KERNEL_VIRTUAL_ADDRESS(to_physical_address(p)); phys_user_page_directory = to_physical_address(p); } //[4] initialize the new environment by the virtual address of the page directory // Hint: use "initialize_environment" function //2016 e->page_WS_max_size = page_WS_size; initialize_environment(e, ptr_user_page_directory, phys_user_page_directory); // We want to load the program into the user virtual space // each program is constructed from one or more segments, // each segment has the following information grouped in "struct ProgramSegment" // 1- uint8 *ptr_start: start address of this segment in memory // 2- uint32 size_in_file: size occupied by this segment inside the program file, // 3- uint32 size_in_memory: actual size required by this segment in memory // usually size_in_file < or = size_in_memory // 4- uint8 *virtual_address: start virtual address that this segment should be copied to it //[6] switch to user page directory // Hint: use rcr3() and lcr3() uint32 kern_phys_pgdir = rcr3() ; lcr3(e->env_cr3) ; //[7] load each program segment into user virtual space struct ProgramSegment* seg = NULL; //use inside PROGRAM_SEGMENT_FOREACH as current segment information int segment_counter=0; uint32 remaining_ws_pages = (e->page_WS_max_size)-1; // we are reserving 1 page of WS for the stack that will be allocated just before the end of this function uint32 lastTableNumber=0xffffffff; PROGRAM_SEGMENT_FOREACH(seg, ptr_program_start) { segment_counter++; //allocate space for current program segment and map it at seg->virtual_address then copy its content // from seg->ptr_start to seg->virtual_address //Hint: use program_segment_alloc_map_copy_workingset() //cprintf("SEGMENT #%d, dest start va = %x, dest end va = %x\n",segment_counter, seg->virtual_address, (seg->virtual_address + seg->size_in_memory)); LOG_STRING("==============================================================================="); LOG_STATMENT(cprintf("SEGMENT #%d, size_in_file = %d, size_in_memory= %d, dest va = %x",segment_counter,seg->size_in_file, seg->size_in_memory, seg->virtual_address)); LOG_STRING("==============================================================================="); uint32 allocated_pages=0; program_segment_alloc_map_copy_workingset(e, seg, &allocated_pages, remaining_ws_pages, &lastTableNumber); remaining_ws_pages -= allocated_pages; LOG_STATMENT(cprintf("SEGMENT: allocated pages in WS = %d",allocated_pages)); LOG_STATMENT(cprintf("SEGMENT: remaining WS pages after allocation = %d",remaining_ws_pages)); ///[1] temporary initialize 1st page in memory then writing it on page file uint32 dataSrc_va = (uint32) seg->ptr_start; uint32 seg_va = (uint32) seg->virtual_address ; uint32 start_first_page = ROUNDDOWN(seg_va , PAGE_SIZE); uint32 end_first_page = ROUNDUP(seg_va , PAGE_SIZE); uint32 offset_first_page = seg_va - start_first_page ; memset(ptr_temp_page , 0, PAGE_SIZE); uint8 *src_ptr = (uint8*) dataSrc_va; uint8 *dst_ptr = (uint8*) (ptr_temp_page + offset_first_page); int i; for (i = seg_va ; i < end_first_page ; i++, src_ptr++,dst_ptr++ ) { *dst_ptr = *src_ptr ; } if (pf_add_env_page(e, start_first_page, ptr_temp_page) == E_NO_PAGE_FILE_SPACE) panic("ERROR: Page File OUT OF SPACE. can't load the program in Page file!!"); //LOG_STRING(" -------------------- PAGE FILE: 1st page is written"); ///[2] Start writing the segment ,from 2nd page until before last page, to page file ... uint32 start_last_page = ROUNDDOWN(seg_va + seg->size_in_file, PAGE_SIZE) ; uint32 end_last_page = seg_va + seg->size_in_file; for (i = end_first_page ; i < start_last_page ; i+= PAGE_SIZE, src_ptr+= PAGE_SIZE) { if (pf_add_env_page(e, i, src_ptr) == E_NO_PAGE_FILE_SPACE) panic("ERROR: Page File OUT OF SPACE. can't load the program in Page file!!"); } //LOG_STRING(" -------------------- PAGE FILE: 2nd page --> before last page are written"); ///[3] temporary initialize last page in memory then writing it on page file dst_ptr = (uint8*) ptr_temp_page; memset(dst_ptr, 0, PAGE_SIZE); for (i = start_last_page ; i < end_last_page ; i++, src_ptr++,dst_ptr++ ) { *dst_ptr = *src_ptr; } if (pf_add_env_page(e, start_last_page, ptr_temp_page) == E_NO_PAGE_FILE_SPACE) panic("ERROR: Page File OUT OF SPACE. can't load the program in Page file!!"); //LOG_STRING(" -------------------- PAGE FILE: last page is written"); ///[4] writing the remaining seg->size_in_memory pages to disk uint32 start_remaining_area = ROUNDUP(seg_va + seg->size_in_file,PAGE_SIZE) ; uint32 remainingLength = (seg_va + seg->size_in_memory) - start_remaining_area ; for (i=0 ; i < ROUNDUP(remainingLength,PAGE_SIZE) ;i+= PAGE_SIZE, start_remaining_area += PAGE_SIZE) { if (pf_add_empty_env_page(e, start_remaining_area, 1) == E_NO_PAGE_FILE_SPACE) panic("ERROR: Page File OUT OF SPACE. can't load the program in Page file!!"); } //LOG_STRING(" -------------------- PAGE FILE: segment remaining area is written (the zeros) "); }
// // Initialize the kernel virtual memory layout for environment e. // Given a pointer to an allocated page directory, set the e->env_pgdir and e->env_cr3 accordingly, // and initialize the kernel portion of the new environment's address space. // Do NOT (yet) map anything into the user portion // of the environment's virtual address space. // void initialize_environment(struct Env* e, uint32* ptr_user_page_directory , unsigned int phys_user_page_directory) { //panic("initialize_environment function is not completed yet") ; // [1] initialize the kernel portion of the new environment's address space. // [2] set e->env_pgdir and e->env_cr3 accordingly, int i; e->env_page_directory = ptr_user_page_directory; e->env_cr3 = phys_user_page_directory; //[TODODONE]: copy the kernel area only (to avoid copying the currently shared objects) for (i = 0 ; i < PDX(USER_TOP) ; i++) { e->env_page_directory[i] = 0 ; } for (i = PDX(USER_TOP) ; i < 1024 ; i++) { e->env_page_directory[i] = ptr_page_directory[i] ; } // Allocate the page working set for both kernel and user #if USE_KHEAP == 1 { e->__uptr_pws = (struct WorkingSetElement*) USER_PAGES_WS_START; e->ptr_pageWorkingSet = create_user_page_WS(e->page_WS_max_size); unsigned int sva = (unsigned int)e->ptr_pageWorkingSet; uint32 nBytes = sizeof(struct WorkingSetElement) * e->page_WS_max_size; unsigned int dva = (unsigned int) (e->__uptr_pws); for(sva = (uint32)(e->ptr_pageWorkingSet); sva < ((uint32)(e->ptr_pageWorkingSet) + nBytes) ; sva+=PAGE_SIZE, dva+=PAGE_SIZE) { unsigned int pa = kheap_physical_address(sva); map_frame(e->env_page_directory, to_frame_info(pa), (void*)dva, PERM_USER); } } #else { uint32 env_index = (uint32)(e-envs); e->__uptr_pws = (struct WorkingSetElement*) ( ((struct Env*)(UENVS+sizeof(struct Env)*env_index))->ptr_pageWorkingSet ); } #endif //initialize environment working set for(i=0; i< (e->page_WS_max_size); i++) { e->ptr_pageWorkingSet[i].virtual_address = 0; e->ptr_pageWorkingSet[i].empty = 1; e->ptr_pageWorkingSet[i].time_stamp = 0 ; } e->page_last_WS_index = 0; for(i=0; i< __TWS_MAX_SIZE; i++) { e->__ptr_tws[i].virtual_address = 0; e->__ptr_tws[i].empty = 1; e->__ptr_tws[i].time_stamp = 0 ; } e->table_last_WS_index = 0; e->pageFaultsCounter=0; e->tableFaultsCounter=0; e->nModifiedPages=0; e->nNotModifiedPages=0; e->shared_free_address = USER_SHARED_MEM_START; //Completes other environment initializations, (envID, status and most of registers) complete_environment_initialization(e); }