#include #include "filesys/file.h" #include "userprog/process.h" #include "threads/thread.h" #include "threads/malloc.h" #include "threads/palloc.h" #include "vm/page.h" static void page_table_entry_free (struct hash_elem *e, void *aux UNUSED); static unsigned page_table_hash (const struct hash_elem *e, void *aux UNUSED); static bool page_table_cmp_less (const struct hash_elem *a, const struct hash_elem *b, void *aux UNUSED); static bool page_table_insert (struct hash *ht, struct page_table_entry *pte); static bool page_load_segment (struct page_table_entry *pte); static bool page_load_mmf (struct page_table_entry *pte); void page_table_init (struct hash *ht) { hash_init (ht, page_table_hash, page_table_cmp_less, NULL); } unsigned page_table_hash (const struct hash_elem *e, void *aux UNUSED) { const struct page_table_entry *pte = hash_entry (e, struct page_table_entry, elem); return hash_bytes (&pte->uvaddr, sizeof pte->uvaddr); } bool page_table_cmp_less (const struct hash_elem *a, const struct hash_elem *b, void *aux UNUSED) { const struct page_table_entry *pte1 = hash_entry (a, struct page_table_entry, elem); const struct page_table_entry *pte2 = hash_entry (b, struct page_table_entry, elem); return (pte1->uvaddr < pte2->uvaddr); } void page_table_free (struct hash *ht) { hash_destroy (ht, page_table_entry_free); } void page_table_entry_free (struct hash_elem *e, void *aux UNUSED) { struct page_table_entry *pte = hash_entry (e, struct page_table_entry, elem); free (pte); } bool page_table_insert (struct hash *ht, struct page_table_entry *pte) { if (pte == NULL) return false; return (hash_insert (ht, &pte->elem) == NULL); } bool page_table_insert_segment (struct file *file, off_t ofs, uint8_t *upage, uint32_t read_bytes, uint32_t zero_bytes, bool writable) { struct page_table_entry *pte = malloc (sizeof *pte); if (pte == NULL) return false; pte->uvaddr = upage; pte->type = PAGE_SEGMENT; pte->loaded = false; pte->segment.file = file; pte->segment.ofs = ofs; pte->segment.read_bytes = read_bytes; pte->segment.zero_bytes = zero_bytes; pte->segment.writable = writable; return page_table_insert (&thread_current ()->page_table, pte); } struct page_table_entry * page_table_fetch (struct hash *ht, void *uvaddr) { struct page_table_entry pte; struct hash_elem *e; pte.uvaddr = uvaddr; e = hash_find (ht, &pte.elem); return ((e != NULL) ? hash_entry (e, struct page_table_entry, elem) : NULL); } bool page_load (struct page_table_entry *pte) { if (pte->loaded) return true; switch (pte->type) { case PAGE_SEGMENT: return page_load_segment (pte); case PAGE_MEMORY_MAPPED_FILE: return page_load_mmf (pte); default: ASSERT (false); break; } return false; } bool page_load_segment (struct page_table_entry *pte) { struct segment *data = &pte->segment; file_seek (data->file, data->ofs); /* Get a page of memory. */ uint8_t *kpage = palloc_get_page (PAL_USER); if (kpage == NULL) return false; /* Load this page. */ if (file_read (data->file, kpage, data->read_bytes) != (int) data->read_bytes) { palloc_free_page (kpage); return false; } memset (kpage + data->read_bytes, 0, data->zero_bytes); /* Add the page to the process's address space. */ if (!process_install_page (pte->uvaddr, kpage, data->writable)) { palloc_free_page (kpage); return false; } pte->loaded = true; return true; } bool page_load_mmf (struct page_table_entry *pte) { //TODO: implement return false; }