aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/userprog/load.c65
1 files changed, 40 insertions, 25 deletions
diff --git a/src/userprog/load.c b/src/userprog/load.c
index eabc056..32bc42e 100644
--- a/src/userprog/load.c
+++ b/src/userprog/load.c
@@ -77,7 +77,7 @@ struct Elf32_Phdr
static bool setup_stack (void **esp);
static bool validate_segment (const struct Elf32_Phdr *, struct file *);
-static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
+static bool load_segment (struct file *file, off_t ofs, uint8_t *upage, uint32_t uoffset,
uint32_t read_bytes, uint32_t zero_bytes,
bool writable);
@@ -157,7 +157,7 @@ load (const char *file_name, void (**eip) (void), void **esp)
if (validate_segment (&phdr, file))
{
bool writable = (phdr.p_flags & PF_W) != 0;
- uint32_t file_page = phdr.p_offset & ~PGMASK;
+ uint32_t file_offset = phdr.p_offset;
uint32_t mem_page = phdr.p_vaddr & ~PGMASK;
uint32_t page_offset = phdr.p_vaddr & PGMASK;
uint32_t read_bytes, zero_bytes;
@@ -165,18 +165,18 @@ load (const char *file_name, void (**eip) (void), void **esp)
{
/* Normal segment.
Read initial part from disk and zero the rest. */
- read_bytes = page_offset + phdr.p_filesz;
+ read_bytes = phdr.p_filesz;
zero_bytes = (ROUND_UP (page_offset + phdr.p_memsz, PGSIZE)
- - read_bytes);
+ - read_bytes - page_offset);
}
- else
+ else
{
/* Entirely zero.
Don't read anything from disk. */
read_bytes = 0;
- zero_bytes = ROUND_UP (page_offset + phdr.p_memsz, PGSIZE);
+ zero_bytes = ROUND_UP (page_offset + phdr.p_memsz, PGSIZE) - page_offset;
}
- if (!load_segment (file, file_page, (void *) mem_page,
+ if (!load_segment (file, file_offset, (void *) mem_page, page_offset,
read_bytes, zero_bytes, writable))
goto done;
}
@@ -261,45 +261,60 @@ validate_segment (const struct Elf32_Phdr *phdr, struct file *file)
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)
+load_segment (struct file *file, off_t ofs, uint8_t *upage, uint32_t page_offset,
+ uint32_t read_bytes, uint32_t zero_bytes, bool writable)
{
- ASSERT ((read_bytes + zero_bytes) % PGSIZE == 0);
+ ASSERT ((page_offset + read_bytes + zero_bytes) % PGSIZE == 0);
ASSERT (pg_ofs (upage) == 0);
- ASSERT (ofs % PGSIZE == 0);
+
+ struct thread *t = thread_current();
file_seek (file, ofs);
- while (read_bytes > 0 || zero_bytes > 0)
+ 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_read_bytes = page_offset + read_bytes;
+ if (page_read_bytes > PGSIZE)
+ page_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);
+ /* Get a page of memory.
+ * If it was present previously at the indicated address in userspace, then we use that. */
+ bool new_kpage = false;
+ uint8_t *kpage = pagedir_get_page (t->pagedir, upage);
+ if (!kpage)
+ {
+ new_kpage = true;
+ 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)
+ if (file_read (file, kpage + page_offset, page_read_bytes - page_offset) != (int) (page_read_bytes - page_offset))
{
- palloc_free_page (kpage);
- return false;
+ if (new_kpage)
+ 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;
- }
+ /* Add the page to the process's address space if not done already */
+ if (new_kpage)
+ {
+ if (!install_page (upage, kpage, writable))
+ {
+ palloc_free_page (kpage);
+ return false;
+ }
+ }
/* Advance. */
- read_bytes -= page_read_bytes;
+ read_bytes -= page_read_bytes - page_offset;
zero_bytes -= page_zero_bytes;
+ page_offset = 0;
upage += PGSIZE;
}
return true;