diff options
| author | Filip Strömbäck <filip.stromback@liu.se> | 2020-03-31 15:44:39 +0200 |
|---|---|---|
| committer | Filip Strömbäck <filip.stromback@liu.se> | 2020-03-31 15:44:39 +0200 |
| commit | fa7324110fccec3c9c9ede4cf85b06e7bd0efe23 (patch) | |
| tree | 6bdc08de23ae061da6be1d420f3519d7c8e0af4b /src | |
| parent | c61658249181f54b30da6a096b0e46f620113fec (diff) | |
| download | pintos-rs-fa7324110fccec3c9c9ede4cf85b06e7bd0efe23.tar.gz | |
Patched the loader for newer GCC on Ubuntu 19.10.
It seems like the linker now splits sections in pieces that may be smaller than a page, causing the
loader to try to load the same page multiple times and fail. Now, offsets are handled properly, and
loading of the new kind of files work properly. If the first part of the page is read only, and the
second is read-write, then the entire page will not be read-write, which could cause issues. At the
moment, it seems this only happens for the text section, which is read only anyway, so it should not
be a big issue in the near future at least.
Signed-off-by: Filip Strömbäck <filip.stromback@liu.se>
Diffstat (limited to 'src')
| -rw-r--r-- | src/userprog/load.c | 65 |
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; |
