bool from_file (struct spage_entry *se) { struct thread *t = thread_current (); struct file *file = se->myfile; off_t ofs = se->ofs; uint8_t upage = se->upage; uint32_t read_bytes = se->read_bytes; uint32_t zero_bytes = se->zero_bytes; bool writable = se->writable; ASSERT ((read_bytes + zero_bytes) % PGSIZE == 0); ASSERT (pg_ofs (upage) == 0); ASSERT (ofs % PGSIZE == 0); // lock_acquire (&filesys_lock); file_seek (file, ofs); // lock_release (&filesys_lock); if ( !(read_bytes > 0 || zero_bytes > 0) ) return false; /* Calculate how to fill this page. We will read PAGE_READ_BYTES bytes from FILE and zero the final PAGE_ZERO_BYTES bytes. */ size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE; size_t page_zero_bytes = PGSIZE - page_read_bytes; /* Get a page of memory. */ uint8_t *kpage = palloc_get_page (PAL_USER); if (kpage == NULL) return false; /* Load this page. */ // lock_acquire (&filesys_lock); if (file_read (file, kpage, page_read_bytes) != (int) page_read_bytes) { // lock_release (&filesys_lock); palloc_free_page (kpage); return false; } // lock_release (&filesys_lock); memset (kpage + page_read_bytes, 0, page_zero_bytes); /* Add the page to the process's address space. */ if (!install_page (upage, kpage, writable)) { palloc_free_page (kpage); return false; } return true; }
void frame_free(void *frame){ struct list_elem *e; lock_acquire(&frame_table_lock); for(e= list_begin(&frame_table); e!= list_end(&frame_table); e= list_next(e)) { //searh 함수 만들기 struct frame_entry *f= list_entry(e, struct frame_entry, elem); if(f->frame == frame) { list_remove(e); free(f); palloc_free_page(frame); break; } } lock_release(&frame_table_lock); }
/* Open system call. */ static int sys_open (const char *ufile) { char *kfile = copy_in_string (ufile); struct file_descriptor *fd; int handle = -1; fd = calloc (1, sizeof *fd); if (fd != NULL) { struct inode *inode = filesys_open (kfile); if (inode != NULL) { if (inode_get_type (inode) == FILE_INODE) fd->file = file_open (inode); else fd->dir = dir_open (inode); if (fd->file != NULL || fd->dir != NULL) { struct thread *cur = thread_current (); handle = fd->handle = cur->next_handle++; list_push_front (&cur->fds, &fd->elem); } else { free (fd); inode_close (inode); } } } palloc_free_page (kfile); return handle; }
/* Open system call. */ static int sys_open (const char *ufile) { char *kfile = copy_in_string (ufile); struct file_descriptor *fd; int handle = -1; fd = malloc (sizeof *fd); if (fd != NULL) { lock_acquire (&fs_lock); fd->file = filesys_open (kfile); if (fd->file != NULL) { struct thread *cur = thread_current (); handle = fd->handle = cur->next_handle++; list_push_front (&cur->fds, &fd->elem); } else free (fd); lock_release (&fs_lock); } palloc_free_page (kfile); return handle; }
void* frame_victim (enum palloc_flags flag) { lock_acquire(&frame_table_lock); struct list_elem *e= list_begin(&frame_table); //list_ victim_frame=list_pop_front(&frame_table); if(victim_frame ==NULL) { } else { victim_frame->page->valid=false; pagedir_clear_page(victim_frame->thread->pagedir, victim_frame->page->vaddr); palloc_free_page(victim_frame->frame); return palloc_get_page(flag); } lock_release(&frame_table_lock); }
/** * An (internal, private) method -- * Deallocates a frame or page (internal procedure) * MUST BE CALLED with 'frame_lock' held. */ void vm_frame_do_free (void *kpage, bool free_page) { ASSERT (lock_held_by_current_thread(&frame_lock) == true); ASSERT (is_kernel_vaddr(kpage)); ASSERT (pg_ofs (kpage) == 0); // should be aligned // hash lookup : a temporary entry struct frame_table_entry f_tmp; f_tmp.kpage = kpage; struct hash_elem *h = hash_find (&frame_map, &(f_tmp.helem)); if (h == NULL) { PANIC ("The page to be freed is not stored in the table"); } struct frame_table_entry *f; f = hash_entry(h, struct frame_table_entry, helem); hash_delete (&frame_map, &f->helem); list_remove (&f->lelem); // Free resources if(free_page) palloc_free_page(kpage); free(f); }
void do_free_page (struct page *page) { page->vme->is_loaded = false; del_page_from_lru_list(page); pagedir_clear_page(page->thread->pagedir, page->vme->vaddr); palloc_free_page(page->kaddr); free(page); }
/*! Use the clock algorithm to select a frame to evict and execute the eviction. */ void * frame_evict(enum palloc_flags flag) { struct list_elem *ce; struct thread *ct; struct frame_table_entry *cf; int i; if (f_table.lock.holder != thread_current()) lock_acquire(&f_table.lock); /* Get frame table lock */ if (list_empty(&f_table.table)) { lock_release(&f_table.lock); /* Nothing to evict */ return NULL; } f_table.hand = f_table.hand % list_size(&f_table.table); ce = list_begin(&f_table.table); /* Begin iteration */ for (i = 0; i < f_table.hand; i++) { /* Find where the "hand" points to: that is where the iteration starts */ ce = list_next(ce); } while (true) { cf = list_entry(ce, struct frame_table_entry, elem); ct = cf->owner; if (!cf->spt->pinned) { /* If pinned, skip this frame */ if (pagedir_is_accessed(ct->pagedir, cf->spt->upage)) /* If accessed, clear accessed bit */ pagedir_set_accessed(ct->pagedir, cf->spt->upage, false); else { /* Swap out the page! */ if (cf->spt->type != SPT_MMAP) { cf->spt->fr = NULL; cf->spt->type = SPT_SWAP; cf->spt->swap_index = swap_out(cf->physical_addr); } /* Write the frame back to the map'd file */ else if (cf->spt->type == SPT_MMAP && pagedir_is_dirty(ct->pagedir, cf->spt->upage)) { cf->spt->fr = NULL; file_write_at(cf->spt->file, cf->physical_addr, cf->spt->read_bytes, cf->spt->ofs); } /* Clear the frame */ list_remove(ce); pagedir_clear_page(ct->pagedir, cf->spt->upage); palloc_free_page(cf->physical_addr); free(cf); lock_release(&f_table.lock); return palloc_get_page(flag); } } ce = list_next(ce); ++f_table.hand; if (ce == list_end(&f_table.table)) { /* Iterate circularly */ ce = list_begin(&f_table.table); f_table.hand = 0; } } }
void remove_mapping(void *upage, void *kpage, struct list_elem *e,struct thread *t){ /* printf("bool %d \n",list_empty(&framelist)); */ list_remove(e); /* printf("list size %d \n",list_size(&framelist)); */ /* printf("are we here %p ]\n" ,upage); */ pagedir_clear_page(t->pagedir,upage); palloc_free_page(kpage); }
/* Remove system call. */ static int sys_remove (const char *ufile) { char *kfile = copy_in_string (ufile); bool ok = filesys_remove (kfile); palloc_free_page (kfile); return ok; }
/* Create system call. */ static int sys_create (const char *ufile, unsigned initial_size) { char *kfile = copy_in_string (ufile); bool ok = filesys_create (kfile, initial_size, FILE_INODE); palloc_free_page (kfile); return ok; }
/* Loads a segment starting at offset OFS in FILE at address UPAGE. In total, READ_BYTES + ZERO_BYTES bytes of virtual memory are initialized, as follows: - READ_BYTES bytes at UPAGE must be read from FILE starting at offset OFS. - ZERO_BYTES bytes at UPAGE + READ_BYTES must be zeroed. The pages initialized by this function must be writable by the user process if WRITABLE is true, read-only otherwise. Return true if successful, false if a memory allocation error or disk read error occurs. */ static bool load_segment (struct file *file, off_t ofs, uint8_t *upage, uint32_t read_bytes, uint32_t zero_bytes, bool writable) { ASSERT ((read_bytes + zero_bytes) % PGSIZE == 0); ASSERT (pg_ofs (upage) == 0); ASSERT (ofs % PGSIZE == 0); file_seek (file, ofs); while (read_bytes > 0 || zero_bytes > 0) { /* Calculate how to fill this page. We will read PAGE_READ_BYTES bytes from FILE and zero the final PAGE_ZERO_BYTES bytes. */ size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE; size_t page_zero_bytes = PGSIZE - page_read_bytes; /* Get a page of memory. */ uint8_t *kpage = palloc_get_page (PAL_USER); if (kpage == NULL) return false; /* Load this page. */ if (file_read (file, kpage, page_read_bytes) != (int) page_read_bytes) { palloc_free_page (kpage); return false; } memset (kpage + page_read_bytes, 0, page_zero_bytes); /* Add the page to the process's address space. */ if (!install_page (upage, kpage, writable)) { palloc_free_page (kpage); return false; } /* Advance. */ read_bytes -= page_read_bytes; zero_bytes -= page_zero_bytes; upage += PGSIZE; } return true; }
/* Frees the PAGE_CNT pages starting at PAGES. */ void palloc_free_umultiple(void *pages, size_t page_cnt) // NOTE: THIS FUNCTION IS NOT CORRECT!!! { size_t i; for(i = 0; i < page_cnt; i++) { void * kpage =lookup_page(thread_current()->pagedir, pages + i * PGSIZE, false); palloc_free_page(kpage); } }
/* Exec system call. */ static int sys_exec (const char *ufile) { tid_t tid; char *kfile = copy_in_string (ufile); tid = process_execute (kfile); palloc_free_page (kfile); return tid; }
void sys_close(int fd) { lock_acquire (&filesys_lock); struct file_desc* file_d = find_file_desc(thread_current(), fd, FD_FILE | FD_DIRECTORY); if(file_d && file_d->file) { file_close(file_d->file); if(file_d->dir) dir_close(file_d->dir); list_remove(&(file_d->elem)); palloc_free_page(file_d); } lock_release (&filesys_lock); }
/* Release the frame holding the page specified by uaddr */ void frame_release (void* uaddr) { lock_acquire (&frame_table_lock); struct frame_table_entry *fte = frame_lookup_uaddr (uaddr); ASSERT (fte != NULL); list_remove (&fte->elem); palloc_free_page (&fte->uaddr); free (fte); lock_release (&frame_table_lock); }
/* Exec system call. */ static int sys_exec (const char *ufile) { tid_t tid; char *kfile = copy_in_string (ufile); lock_acquire (&fs_lock); tid = process_execute (kfile); lock_release (&fs_lock); palloc_free_page (kfile); return tid; }
/* Create system call. */ static int sys_create (const char *ufile, unsigned initial_size) { char *kfile = copy_in_string (ufile); bool ok; lock_acquire (&fs_lock); ok = filesys_create (kfile, initial_size); lock_release (&fs_lock); palloc_free_page (kfile); return ok; }
/* Remove system call. */ static int sys_remove (const char *ufile) { char *kfile = copy_in_string (ufile); bool ok; lock_acquire (&fs_lock); ok = filesys_remove (kfile); lock_release (&fs_lock); palloc_free_page (kfile); return ok; }
/* Create a minimal stack by mapping a zeroed page at the top of user virtual memory. */ static bool setup_stack (void **esp) { uint8_t *kpage; bool success = false; kpage = palloc_get_page (PAL_USER | PAL_ZERO); if (kpage != NULL) { success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true); if (success) *esp = PHYS_BASE; else palloc_free_page (kpage); } return success; }
/* Frees a frame from the physical memory */ void frame_free_page (uint32_t *kpage) { struct frame_element *fe = frame_table_find (kpage); /* if the frame about to be evicted is pointed at by the clock hand, move the clock hand to the next frame */ if (&fe->frame_elem == clock_hand) clock_hand = list_next (clock_hand); if (fe != NULL) { list_remove (&fe->frame_elem); free (fe); palloc_free_page (kpage); } }
void frame_free(struct frame *f) { // here we free the frame held by the process lock_acquire(&ftable_lock); struct list_elem *elem = list_begin(&frame_list); while (elem != list_end(&frame_list)) { struct frame *fe = list_entry(elem, struct frame, frame_list_elem); if (fe != f) { elem = list_next(elem); continue; } // if current process frame that is to be freed is in the list, then remove it from list and free memory list_remove(elem); pagedir_clear_page(fe->page->frame_holder_thread->pagedir, fe->page->addr); palloc_free_page(fe->base); // free the page currently held by the frame free(fe); // then free the frame break; } lock_release(&ftable_lock); }
/* Evicte random frame */ struct vm_frame *vm_evict_frame(struct supp_page_entry *s){ ASSERT(!list_empty(&vm_frames_list)); /* Choose frame - FIFO */ lock_acquire(&vm_lock); struct list_elem *e = list_front(&vm_frames_list); struct vm_frame *victim = list_entry(e, struct vm_frame, elem); lock_release(&vm_lock); /* Settings */ pagedir_clear_page(victim->thread->pagedir, victim->spte->upage); victim->spte->type = S; victim->spte->swap_idx = vm_swap_out(victim->page); victim->thread = thread_current(); victim->spte = s; palloc_free_page(victim->page); return victim; }
/* Free's all data associated with the frame with kernel virtual address PG. */ void frame_free(struct frame *f) { struct hash_elem *e; ASSERT(lock_held_by_current_thread(&f->evicting)); /* Delete frame from frame table. */ lock_acquire(&ft_lock); ASSERT(hash_delete(&frame_table, &f->elem) != NULL); /* Evict page from frame. */ if(f->page != NULL) evict(f); ASSERT(list_empty(&f->evicting.semaphore.waiters)); /* Free resources */ palloc_free_page(f->addr); free(f); lock_release(&ft_lock); }
void * frame_evict (enum palloc_flags flags) { lock_acquire (&frame_table_lock); struct list_elem *e = list_begin (&frame_table); while (true) { struct frame_entry *frame_entry = list_entry (e, struct frame_entry, elem); struct SP_entry *page_entry = frame_entry->page_entry; if (!page_entry->pinned) { struct thread *t = frame_entry->thread; if (pagedir_is_accessed (t->pagedir, page_entry->page)) { pagedir_set_accessed (t->pagedir, page_entry->page, false); } else { if (pagedir_is_dirty (t->pagedir, page_entry->page) || page_entry->type == SP_SWAP) { if (page_entry->type == SP_MMAP) { lock_acquire (&filesys_lock); file_write_at (page_entry->file, frame_entry->frame, page_entry->read_bytes, page_entry->offset); lock_release (&filesys_lock); } else { page_entry->type = SP_SWAP; page_entry->swap_index = swap_out (frame_entry->frame); } } page_entry->is_loaded = false; list_remove (&frame_entry->elem); pagedir_clear_page (t->pagedir, page_entry->page); palloc_free_page (frame_entry->frame); free (frame_entry); lock_release (&frame_table_lock); return palloc_get_page (flags); } } e = list_next (e); if (e == list_end (&frame_table)) { e = list_begin (&frame_table); } } }
/** * \page_munmap * \unmap the page * * \param table supplemental page table * \param spte supplemental page table entry * \param pagedir pagedirectory of corresponding process * * \retval void */ void page_munmap (struct hash *table, struct page_entry *spte, void *pagedir) { /* If page is loaded in memory, free it */ if (spte->is_loaded) { void *paddr = pagedir_get_page (pagedir, spte->vaddr); /* If this page is dirty, write back to file */ if (pagedir_is_dirty (pagedir, spte->vaddr)) { file_write_at (spte->file, paddr, spte->read_bytes, spte->ofs); } palloc_free_page (paddr); } /* Delete entry and set vaddr regin to be not present */ hash_delete (table, &spte->elem); pagedir_clear_page (pagedir, spte->vaddr); free (spte); }
void * swap (void) { struct frame_entry *victim_frame = find_victim(); struct spage_entry *victim_spage_entry = victim_frame->spe; uint32_t sectornum = swap_out(victim_frame->frame); pagedir_clear_page(victim_frame->t->pagedir,victim_spage_entry->uaddr); victim_spage_entry->indisk = true; victim_spage_entry->sec_no = sectornum; palloc_free_page(victim_frame->frame); falloc_free_frame(victim_frame->frame); void *kpage = palloc_get_page(PAL_USER|PAL_ZERO); ASSERT(kpage != NULL); return kpage; }
int sys_open(const char* file) { // memory validation check_user((const uint8_t*) file); struct file* file_opened; struct file_desc* fd = palloc_get_page(0); if (!fd) { return -1; } lock_acquire (&filesys_lock); file_opened = filesys_open(file); if (!file_opened) { palloc_free_page (fd); lock_release (&filesys_lock); return -1; } fd->file = file_opened; //file save // directory handling struct inode *inode = file_get_inode(fd->file); if(inode != NULL && inode_is_directory(inode)) { fd->dir = dir_open( inode_reopen(inode) ); } else fd->dir = NULL; struct list* fd_list = &thread_current()->file_descriptors; if (list_empty(fd_list)) { // 0, 1, 2 are reserved for stdin, stdout, stderr fd->id = 3; } else { fd->id = (list_entry(list_back(fd_list), struct file_desc, elem)->id) + 1; } list_push_back(fd_list, &(fd->elem)); lock_release (&filesys_lock); return fd->id; }
/* The implementation of LRU 'clock' algorithm follows.. we make use of the PTE's accessed bit and dirty bit: on any read or write to a page ==> accessed bit = 1; on any write ==> dirty bit = 1; Step 1: We navigate through the pages in a circular order.. i.e., if we hit the end of the frame list, we circle back to the start and continue our processing.. Step 2: If the accessed bit is 'accessed', turn it to 'not accessed', skip the page and proceed to look-up the next one in the list Step 3: If the accessed bit is 'not accessed', we can proceed with our page replacement */ void evict_page() { struct list_elem *e; int count = 0; lock_acquire(&ftable_lock); for (e = list_begin(&frame_list); e != list_end(&frame_list); e = list_next(e)) { struct frame *frame = list_entry(e, struct frame, frame_list_elem); // printf ("\n%d , %d", count, list_size(&frame_list) - 1); if (count != list_size(&frame_list) - 1) { // get the accessed flag for the current page bool accessed_flag = pagedir_is_accessed( frame->page->frame_holder_thread->pagedir, frame->page->addr); if (accessed_flag) pagedir_set_accessed(frame->page->frame_holder_thread->pagedir, frame->page->addr, !accessed_flag); else { // we need to page replace.. i.e., // step 1: remove the existing page from the frame (swap_out call) // step 2: remove the existing page from the page directory // step 3: set the accessed flag of the page to 'accessed' // step 4: free the page and free the frame, for subsequent use list_remove(e); swap_out(frame->page); frame->page->swap_flag = 1; pagedir_clear_page(frame->page->frame_holder_thread->pagedir, frame->page->addr); palloc_free_page(frame->base); free(frame); // frame->page->swap_flag = 1; break; } count++; } else { count = 0; e = list_begin(&frame_list); } } lock_release(&ftable_lock); }
/* Creates a copy of user string US in kernel memory and returns it as a page that must be freed with palloc_free_page(). Truncates the string at PGSIZE bytes in size. Call thread_exit() if any of the user accesses are invalid. */ static char * copy_in_string (const char *us) { char *ks; char *upage; size_t length; ks = palloc_get_page (0); if (ks == NULL) thread_exit (); length = 0; for (;;) { upage = pg_round_down (us); if (!page_lock (upage, false)) goto lock_error; for (; us < upage + PGSIZE; us++) { ks[length++] = *us; if (*us == '\0') { page_unlock (upage); return ks; } else if (length >= PGSIZE) goto too_long_error; } page_unlock (upage); } too_long_error: page_unlock (upage); lock_error: palloc_free_page (ks); thread_exit (); }