65c09e41e8be3f38885b2aeffd6fd93d2c28a094
[pintos-anon] / src / userprog / addrspace.c
1 #include "userprog/addrspace.h"
2 #include <debug.h>
3 #include <inttypes.h>
4 #include <round.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include "userprog/tss.h"
8 #include "filesys/file.h"
9 #include "filesys/filesys.h"
10 #include "threads/init.h"
11 #include "threads/mmu.h"
12 #include "threads/paging.h"
13 #include "threads/palloc.h"
14 #include "threads/thread.h"
15
16 /* We load ELF binaries.  The following definitions are taken
17    from the ELF specification, [ELF1], more-or-less verbatim.  */
18
19 /* ELF types.  See [ELF1] 1-2. */
20 typedef uint32_t Elf32_Word, Elf32_Addr, Elf32_Off;
21 typedef uint16_t Elf32_Half;
22
23 /* For use with ELF types in printf(). */
24 #define PE32Wx PRIx32   /* Print Elf32_Word in hexadecimal. */
25 #define PE32Ax PRIx32   /* Print Elf32_Addr in hexadecimal. */
26 #define PE32Ox PRIx32   /* Print Elf32_Off in hexadecimal. */
27 #define PE32Hx PRIx16   /* Print Elf32_Half in hexadecimal. */
28
29 /* Executable header.  See [ELF1] 1-4 to 1-8.
30    This appears at the very beginning of an ELF binary. */
31 struct Elf32_Ehdr
32   {
33     unsigned char e_ident[16];
34     Elf32_Half    e_type;
35     Elf32_Half    e_machine;
36     Elf32_Word    e_version;
37     Elf32_Addr    e_entry;
38     Elf32_Off     e_phoff;
39     Elf32_Off     e_shoff;
40     Elf32_Word    e_flags;
41     Elf32_Half    e_ehsize;
42     Elf32_Half    e_phentsize;
43     Elf32_Half    e_phnum;
44     Elf32_Half    e_shentsize;
45     Elf32_Half    e_shnum;
46     Elf32_Half    e_shstrndx;
47   };
48
49 /* Program header.  See [ELF1] 2-2 to 2-4.
50    There are e_phnum of these, starting at file offset e_phoff
51    (see [ELF1] 1-6). */
52 struct Elf32_Phdr
53   {
54     Elf32_Word p_type;
55     Elf32_Off  p_offset;
56     Elf32_Addr p_vaddr;
57     Elf32_Addr p_paddr;
58     Elf32_Word p_filesz;
59     Elf32_Word p_memsz;
60     Elf32_Word p_flags;
61     Elf32_Word p_align;
62   };
63
64 /* Values for p_type.  See [ELF1] 2-3. */
65 #define PT_NULL    0            /* Ignore. */
66 #define PT_LOAD    1            /* Loadable segment. */
67 #define PT_DYNAMIC 2            /* Dynamic linking info. */
68 #define PT_INTERP  3            /* Name of dynamic loader. */
69 #define PT_NOTE    4            /* Auxiliary info. */
70 #define PT_SHLIB   5            /* Reserved. */
71 #define PT_PHDR    6            /* Program header table. */
72 #define PT_STACK   0x6474e551   /* Stack segment. */
73
74 /* Flags for p_flags.  See [ELF3] 2-3 and 2-4. */
75 #define PF_X 1          /* Executable. */
76 #define PF_W 2          /* Writable. */
77 #define PF_R 4          /* Readable. */
78
79 static bool load_segment (struct thread *, struct file *,
80                           const struct Elf32_Phdr *);
81 static bool setup_stack (struct thread *);
82
83 /* Aborts loading an executable, with an error message. */
84 #define LOAD_ERROR(MSG)                                         \
85         do {                                                    \
86                 printf ("addrspace_load: %s: ", filename);      \
87                 printf MSG;                                     \
88                 printf ("\n");                                  \
89                 goto done;                                     \
90         } while (0)
91
92 /* Loads an ELF executable from FILENAME into T,
93    and stores the executable's entry point into *START.
94    Returns true if successful, false otherwise. */
95 bool
96 addrspace_load (struct thread *t, const char *filename, void (**start) (void)) 
97 {
98   struct Elf32_Ehdr ehdr;
99   struct file *file = NULL;
100   off_t file_ofs;
101   bool success = false;
102   int i;
103
104   /* Allocate page directory. */
105   t->pagedir = pagedir_create ();
106   if (t->pagedir == NULL)
107     LOAD_ERROR (("page directory allocation failed"));
108
109   /* Open executable file. */
110   file = filesys_open (filename);
111   if (file == NULL)
112     LOAD_ERROR (("open failed"));
113
114   /* Read and verify executable header. */
115   if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr) 
116     LOAD_ERROR (("error reading executable header"));
117   if (memcmp (ehdr.e_ident, "\177ELF\1\1\1", 7) != 0)
118     LOAD_ERROR (("file is not ELF"));
119   if (ehdr.e_type != 2)
120     LOAD_ERROR (("ELF file is not an executable"));
121   if (ehdr.e_machine != 3)
122     LOAD_ERROR (("ELF executable is not x86"));
123   if (ehdr.e_version != 1)
124     LOAD_ERROR (("ELF executable hasunknown version %d",
125                  (int) ehdr.e_version));
126   if (ehdr.e_phentsize != sizeof (struct Elf32_Phdr))
127     LOAD_ERROR (("bad ELF program header size"));
128   if (ehdr.e_phnum > 1024)
129     LOAD_ERROR (("too many ELF program headers"));
130
131   /* Read program headers. */
132   file_ofs = ehdr.e_phoff;
133   for (i = 0; i < ehdr.e_phnum; i++) 
134     {
135       struct Elf32_Phdr phdr;
136
137       file_seek (file, file_ofs);
138       if (file_read (file, &phdr, sizeof phdr) != sizeof phdr)
139         LOAD_ERROR (("error reading program header"));
140       file_ofs += sizeof phdr;
141       switch (phdr.p_type) 
142         {
143         case PT_NULL:
144         case PT_NOTE:
145         case PT_PHDR:
146         case PT_STACK:
147           /* Ignore this segment. */
148           break;
149         case PT_DYNAMIC:
150         case PT_INTERP:
151         case PT_SHLIB:
152           /* Reject the executable. */
153           LOAD_ERROR (("unsupported ELF segment type %d\n", phdr.p_type));
154           break;
155         default:
156           printf ("unknown ELF segment type %08x\n", phdr.p_type);
157           break;
158         case PT_LOAD:
159           if (!load_segment (t, file, &phdr))
160             goto done;
161           break;
162         }
163     }
164
165   /* Set up stack. */
166   if (!setup_stack (t))
167     goto done;
168
169   /* Start address. */
170   *start = (void (*) (void)) ehdr.e_entry;
171
172   success = true;
173
174  done:
175   /* We arrive here whether the load is successful or not.
176      We can distinguish based on `success'. */
177   file_close (file);
178   if (!success) 
179     addrspace_destroy (t);
180   return success;
181 }
182
183 /* Destroys the user address space in T and frees all of its
184    resources. */
185 void
186 addrspace_destroy (struct thread *t)
187 {
188   if (t->pagedir != NULL) 
189     {
190       pagedir_destroy (t->pagedir);
191       t->pagedir = NULL; 
192     }
193 }
194
195 /* Sets up the CPU for running user code in thread T, if any. */
196 void
197 addrspace_activate (struct thread *t)
198 {
199   ASSERT (t != NULL);
200
201   /* Activate T's page tables. */
202   pagedir_activate (t->pagedir);
203
204   /* Set T's kernel stack for use in processing interrupts. */
205   tss_set_esp0 ((uint8_t *) t + PGSIZE);
206 }
207 \f
208 /* addrspace_load() helpers. */
209
210 static bool install_page (struct thread *, void *upage, void *kpage);
211
212 /* Loads the segment described by PHDR from FILE into thread T's
213    user address space.  Return true if successful, false
214    otherwise. */
215 static bool
216 load_segment (struct thread *t, struct file *file,
217               const struct Elf32_Phdr *phdr) 
218 {
219   void *start, *end;  /* Page-rounded segment start and end. */
220   uint8_t *upage;     /* Iterator from start to end. */
221   off_t filesz_left;  /* Bytes left of file data (as opposed to
222                          zero-initialized bytes). */
223
224   /* Is this a read-only segment?  Not currently used, so it's
225      commented out.  You'll want to use it when implementing VM
226      to decide whether to page the segment from its executable or
227      from swap. */
228   //bool read_only = (phdr->p_flags & PF_W) == 0;
229
230   ASSERT (t != NULL);
231   ASSERT (file != NULL);
232   ASSERT (phdr != NULL);
233   ASSERT (phdr->p_type == PT_LOAD);
234
235   /* [ELF1] 2-2 says that p_offset and p_vaddr must be congruent
236      modulo PGSIZE. */
237   if (phdr->p_offset % PGSIZE != phdr->p_vaddr % PGSIZE) 
238     {
239       printf ("%#08"PE32Ox" and %#08"PE32Ax" not congruent modulo %#x\n",
240               phdr->p_offset, phdr->p_vaddr, (unsigned) PGSIZE);
241       return false; 
242     }
243
244   /* [ELF1] 2-3 says that p_memsz must be at least as big as
245      p_filesz. */
246   if (phdr->p_memsz < phdr->p_filesz) 
247     {
248       printf ("p_memsz (%08"PE32Wx") < p_filesz (%08"PE32Wx")\n",
249               phdr->p_memsz, phdr->p_filesz);
250       return false; 
251     }
252
253   /* Validate virtual memory region to be mapped.
254      The region must both start and end within the user address
255      space range starting at 0 and ending at PHYS_BASE (typically
256      3 GB == 0xc0000000). */
257   start = pg_round_down ((void *) phdr->p_vaddr);
258   end = pg_round_up ((void *) (phdr->p_vaddr + phdr->p_memsz));
259   if (start >= PHYS_BASE || end >= PHYS_BASE || end < start) 
260     {
261       printf ("bad virtual region %08lx...%08lx\n",
262               (unsigned long) start, (unsigned long) end);
263       return false; 
264     }
265
266   /* Load the segment page-by-page into memory. */
267   filesz_left = phdr->p_filesz + (phdr->p_vaddr & PGMASK);
268   file_seek (file, ROUND_DOWN (phdr->p_offset, PGSIZE));
269   for (upage = start; upage < (uint8_t *) end; upage += PGSIZE) 
270     {
271       /* We want to read min(PGSIZE, filesz_left) bytes from the
272          file into the page and zero the rest. */
273       size_t read_bytes = filesz_left >= PGSIZE ? PGSIZE : filesz_left;
274       size_t zero_bytes = PGSIZE - read_bytes;
275       uint8_t *kpage = palloc_get (PAL_USER);
276       if (kpage == NULL)
277         return false;
278
279       /* Do the reading and zeroing. */
280       if (file_read (file, kpage, read_bytes) != (int) read_bytes) 
281         {
282           palloc_free (kpage);
283           return false; 
284         }
285       memset (kpage + read_bytes, 0, zero_bytes);
286       filesz_left -= read_bytes;
287
288       /* Add the page to the process's address space. */
289       if (!install_page (t, upage, kpage)) 
290         {
291           palloc_free (kpage);
292           return false; 
293         }
294     }
295
296   return true;
297 }
298
299 /* Create a minimal stack for T by mapping a zeroed page at the
300    top of user virtual memory. */
301 static bool
302 setup_stack (struct thread *t) 
303 {
304   uint8_t *kpage;
305   bool success = false;
306
307   kpage = palloc_get (PAL_USER | PAL_ZERO);
308   if (kpage != NULL) 
309     {
310       success = install_page (t, ((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
311       if (!success)
312         palloc_free (kpage);
313     }
314   else
315     printf ("failed to allocate process stack\n");
316
317   return success;
318 }
319
320 /* Adds a mapping from user virtual address UPAGE to kernel
321    virtual address KPAGE to T's page tables.  Fails if UPAGE is
322    already mapped or if memory allocation fails. */
323 static bool
324 install_page (struct thread *t, void *upage, void *kpage)
325 {
326   /* Verify that there's not already a page at that virtual
327      address, then map our page there. */
328   return (pagedir_get_page (t->pagedir, upage) == NULL
329           && pagedir_set_page (t->pagedir, upage, kpage, true));
330 }