From e88a8c4c379d721e9901752d440a05295087da11 Mon Sep 17 00:00:00 2001 From: manuel Date: Tue, 19 Jun 2012 01:44:56 +0200 Subject: implement page table and use it for lazy loading of segments --- vm/page.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 vm/page.c (limited to 'vm/page.c') diff --git a/vm/page.c b/vm/page.c new file mode 100644 index 0000000..fa2433d --- /dev/null +++ b/vm/page.c @@ -0,0 +1,147 @@ +#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; +} -- cgit v1.2.3