X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fuserprog%2Faddrspace.c;h=1170f16ab92a7f61f1a93ad381ea49ff38208e63;hb=a051c001c942a1f9cce57b1beec79794f9c7089f;hp=3837d4ed00a6e6edce942bdd2dcd25840041acee;hpb=a98578bf3b6b5c946713654b404a886a7199dbee;p=pintos-anon diff --git a/src/userprog/addrspace.c b/src/userprog/addrspace.c index 3837d4e..1170f16 100644 --- a/src/userprog/addrspace.c +++ b/src/userprog/addrspace.c @@ -3,11 +3,13 @@ #include "debug.h" #include "file.h" #include "filesys.h" +#include "init.h" #include "lib.h" #include "mmu.h" -#include "malloc.h" #include "paging.h" #include "palloc.h" +#include "thread.h" +#include "tss.h" /* We load ELF binaries. The following definitions are taken from the ELF specification more-or-less verbatim. */ @@ -79,14 +81,29 @@ struct Elf32_Phdr } while (0) static bool -load_segment (struct addrspace *as, struct file *file, +install_page (struct thread *t, void *upage, void *kpage) +{ + /* Verify that there's not already a page at that virtual + address, then map our page there. */ + if (pagedir_get_page (t->pagedir, upage) == NULL + && pagedir_set_page (t->pagedir, upage, kpage, true)) + return true; + else + { + palloc_free (kpage); + return false; + } +} + +static bool +load_segment (struct thread *t, struct file *file, const struct Elf32_Phdr *phdr) { void *start, *end; uint8_t *upage; off_t filesz_left; - ASSERT (as != NULL); + ASSERT (t != NULL); ASSERT (file != NULL); ASSERT (phdr != NULL); ASSERT (phdr->p_type == PT_LOAD); @@ -132,34 +149,49 @@ load_segment (struct addrspace *as, struct file *file, memset (kpage + read_bytes, 0, zero_bytes); filesz_left -= read_bytes; - if (pagedir_get_page (as->pagedir, upage)) - { - palloc_free (kpage); - return false; - } - pagedir_set_page (as->pagedir, upage, kpage, true); + if (!install_page (t, upage, kpage)) + return false; } return true; } +static bool +setup_stack (struct thread *t) +{ + uint8_t *kpage = palloc_get (PAL_ZERO); + if (kpage == NULL) + { + printk ("failed to allocate process stack\n"); + return false; + } + + return install_page (t, ((uint8_t *) PHYS_BASE) - PGSIZE, kpage); +} + bool -addrspace_load (struct addrspace *as, const char *filename) +addrspace_load (struct thread *t, const char *filename, + void (**start) (void)) { struct Elf32_Ehdr ehdr; - struct file *file = NULL; + struct file file; + bool file_open = false; off_t file_ofs; bool success = false; int i; - as->pagedir = pagedir_create (); + /* Allocate page directory. */ + t->pagedir = pagedir_create (); + if (t->pagedir == NULL) + LOAD_ERROR (("page directory allocation failed")); - file = filesys_open (filename); - if (file == NULL) + /* Open executable file. */ + file_open = filesys_open (filename, &file); + if (!file_open) LOAD_ERROR (("open failed")); /* Read and verify executable header. */ - if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr) + if (file_read (&file, &ehdr, sizeof ehdr) != sizeof ehdr) LOAD_ERROR (("error reading executable header")); if (memcmp (ehdr.e_ident, "\177ELF\1\1\1", 7) != 0) LOAD_ERROR (("file is not ELF")); @@ -177,26 +209,20 @@ addrspace_load (struct addrspace *as, const char *filename) /* Read program headers. */ file_ofs = ehdr.e_phoff; - printk ("e_phnum=%d\n", ehdr.e_phnum); for (i = 0; i < ehdr.e_phnum; i++) { struct Elf32_Phdr phdr; - file_seek (file, file_ofs); - if (file_read (file, &phdr, sizeof phdr) != sizeof phdr) + file_seek (&file, file_ofs); + if (file_read (&file, &phdr, sizeof phdr) != sizeof phdr) LOAD_ERROR (("error reading program header")); - printk ("%x: %08x, %08x %08x %08x %05x %05x\n", - file_tell (file), - phdr.p_type, - phdr.p_offset, phdr.p_vaddr, phdr.p_paddr, - phdr.p_filesz, phdr.p_memsz); file_ofs += sizeof phdr; switch (phdr.p_type) { case PT_NULL: case PT_NOTE: case PT_PHDR: - case PT_STACK: /* Stack segment. */ + case PT_STACK: /* Ignore this segment. */ break; case PT_DYNAMIC: @@ -209,24 +235,45 @@ addrspace_load (struct addrspace *as, const char *filename) printk ("unknown ELF segment type %08x\n", phdr.p_type); break; case PT_LOAD: - if (!load_segment (as, file, &phdr)) + if (!load_segment (t, &file, &phdr)) goto error; break; } } + + /* Set up stack. */ + if (!setup_stack (t)) + goto error; + + /* Start address. */ + *start = (void (*) (void)) ehdr.e_entry; + success = true; error: - if (file != NULL) - file_close (file); + if (file_open) + file_close (&file); if (!success) - addrspace_destroy (as); + addrspace_destroy (t); return success; } void -addrspace_destroy (struct addrspace *as) +addrspace_destroy (struct thread *t) +{ + if (t->pagedir != NULL) + { + pagedir_destroy (t->pagedir); + t->pagedir = NULL; + } +} + +void +addrspace_activate (struct thread *t) { - if (as != NULL && as->pagedir != NULL) - pagedir_destroy (as->pagedir); + ASSERT (t != NULL); + + if (t->pagedir != NULL) + pagedir_activate (t->pagedir); + tss_set_esp0 ((uint8_t *) t + PGSIZE); }