ea8767c84e2f4f33e5bd4e5a1f28f20c59960c62
[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;
100   bool file_open = false;
101   off_t file_ofs;
102   bool success = false;
103   int i;
104
105   /* Allocate page directory. */
106   t->pagedir = pagedir_create ();
107   if (t->pagedir == NULL)
108     LOAD_ERROR (("page directory allocation failed"));
109
110   /* Open executable file. */
111   file_open = filesys_open (filename, &file);
112   if (!file_open)
113     LOAD_ERROR (("open failed"));
114
115   /* Read and verify executable header. */
116   if (file_read (&file, &ehdr, sizeof ehdr) != sizeof ehdr) 
117     LOAD_ERROR (("error reading executable header"));
118   if (memcmp (ehdr.e_ident, "\177ELF\1\1\1", 7) != 0)
119     LOAD_ERROR (("file is not ELF"));
120   if (ehdr.e_type != 2)
121     LOAD_ERROR (("ELF file is not an executable"));
122   if (ehdr.e_machine != 3)
123     LOAD_ERROR (("ELF executable is not x86"));
124   if (ehdr.e_version != 1)
125     LOAD_ERROR (("ELF executable hasunknown version %d",
126                  (int) ehdr.e_version));
127   if (ehdr.e_phentsize != sizeof (struct Elf32_Phdr))
128     LOAD_ERROR (("bad ELF program header size"));
129   if (ehdr.e_phnum > 1024)
130     LOAD_ERROR (("too many ELF program headers"));
131
132   /* Read program headers. */
133   file_ofs = ehdr.e_phoff;
134   for (i = 0; i < ehdr.e_phnum; i++) 
135     {
136       struct Elf32_Phdr phdr;
137
138       file_seek (&file, file_ofs);
139       if (file_read (&file, &phdr, sizeof phdr) != sizeof phdr)
140         LOAD_ERROR (("error reading program header"));
141       file_ofs += sizeof phdr;
142       switch (phdr.p_type) 
143         {
144         case PT_NULL:
145         case PT_NOTE:
146         case PT_PHDR:
147         case PT_STACK:
148           /* Ignore this segment. */
149           break;
150         case PT_DYNAMIC:
151         case PT_INTERP:
152         case PT_SHLIB:
153           /* Reject the executable. */
154           LOAD_ERROR (("unsupported ELF segment type %d\n", phdr.p_type));
155           break;
156         default:
157           printf ("unknown ELF segment type %08x\n", phdr.p_type);
158           break;
159         case PT_LOAD:
160           if (!load_segment (t, &file, &phdr))
161             goto done;
162           break;
163         }
164     }
165
166   /* Set up stack. */
167   if (!setup_stack (t))
168     goto done;
169
170   /* Start address. */
171   *start = (void (*) (void)) ehdr.e_entry;
172
173   success = true;
174
175  done:
176   /* We arrive here whether the load is successful or not.
177      We can distinguish based on `success'. */
178   if (file_open)
179     file_close (&file);
180   if (!success) 
181     addrspace_destroy (t);
182   return success;
183 }
184
185 /* Destroys the user address space in T and frees all of its
186    resources. */
187 void
188 addrspace_destroy (struct thread *t)
189 {
190   if (t->pagedir != NULL) 
191     {
192       pagedir_destroy (t->pagedir);
193       t->pagedir = NULL; 
194     }
195 }
196
197 /* Sets up the CPU for running user code in thread T, if any. */
198 void
199 addrspace_activate (struct thread *t)
200 {
201   ASSERT (t != NULL);
202
203   /* Activate T's page tables. */
204   pagedir_activate (t->pagedir);
205
206   /* Set T's kernel stack for use in processing interrupts. */
207   tss_set_esp0 ((uint8_t *) t + PGSIZE);
208 }
209 \f
210 /* addrspace_load() helpers. */
211
212 static bool install_page (struct thread *, void *upage, void *kpage);
213
214 /* Loads the segment described by PHDR from FILE into thread T's
215    user address space.  Return true if successful, false
216    otherwise. */
217 static bool
218 load_segment (struct thread *t, struct file *file,
219               const struct Elf32_Phdr *phdr) 
220 {
221   void *start, *end;  /* Page-rounded segment start and end. */
222   uint8_t *upage;     /* Iterator from start to end. */
223   off_t filesz_left;  /* Bytes left of file data (as opposed to
224                          zero-initialized bytes). */
225
226   /* Is this a read-only segment?  Not currently used, so it's
227      commented out.  You'll want to use it when implementing VM
228      to decide whether to page the segment from its executable or
229      from swap. */
230   //bool read_only = (phdr->p_flags & PF_W) == 0;
231
232   ASSERT (t != NULL);
233   ASSERT (file != NULL);
234   ASSERT (phdr != NULL);
235   ASSERT (phdr->p_type == PT_LOAD);
236
237   /* [ELF1] 2-2 says that p_offset and p_vaddr must be congruent
238      modulo PGSIZE. */
239   if (phdr->p_offset % PGSIZE != phdr->p_vaddr % PGSIZE) 
240     {
241       printf ("%#08"PE32Ox" and %#08"PE32Ax" not congruent modulo %#x\n",
242               phdr->p_offset, phdr->p_vaddr, (unsigned) PGSIZE);
243       return false; 
244     }
245
246   /* [ELF1] 2-3 says that p_memsz must be at least as big as
247      p_filesz. */
248   if (phdr->p_memsz < phdr->p_filesz) 
249     {
250       printf ("p_memsz (%08"PE32Wx") < p_filesz (%08"PE32Wx")\n",
251               phdr->p_memsz, phdr->p_filesz);
252       return false; 
253     }
254
255   /* Validate virtual memory region to be mapped.
256      The region must both start and end within the user address
257      space range starting at 0 and ending at PHYS_BASE (typically
258      3 GB == 0xc0000000). */
259   start = pg_round_down ((void *) phdr->p_vaddr);
260   end = pg_round_up ((void *) (phdr->p_vaddr + phdr->p_memsz));
261   if (start >= PHYS_BASE || end >= PHYS_BASE || end < start) 
262     {
263       printf ("bad virtual region %08lx...%08lx\n",
264               (unsigned long) start, (unsigned long) end);
265       return false; 
266     }
267
268   /* Load the segment page-by-page into memory. */
269   filesz_left = phdr->p_filesz + (phdr->p_vaddr & PGMASK);
270   file_seek (file, ROUND_DOWN (phdr->p_offset, PGSIZE));
271   for (upage = start; upage < (uint8_t *) end; upage += PGSIZE) 
272     {
273       /* We want to read min(PGSIZE, filesz_left) bytes from the
274          file into the page and zero the rest. */
275       size_t read_bytes = filesz_left >= PGSIZE ? PGSIZE : filesz_left;
276       size_t zero_bytes = PGSIZE - read_bytes;
277       uint8_t *kpage = palloc_get (0);
278       if (kpage == NULL)
279         return false;
280
281       /* Do the reading and zeroing. */
282       if (file_read (file, kpage, read_bytes) != (int) read_bytes) 
283         {
284           palloc_free (kpage);
285           return false; 
286         }
287       memset (kpage + read_bytes, 0, zero_bytes);
288       filesz_left -= read_bytes;
289
290       /* Add the page to the process's address space. */
291       if (!install_page (t, upage, kpage)) 
292         {
293           palloc_free (kpage);
294           return false; 
295         }
296     }
297
298   return true;
299 }
300
301 /* Create a minimal stack for T by mapping a zeroed page at the
302    top of user virtual memory. */
303 static bool
304 setup_stack (struct thread *t) 
305 {
306   uint8_t *kpage;
307   bool success = false;
308
309   kpage = palloc_get (PAL_ZERO);
310   if (kpage != NULL) 
311     {
312       success = install_page (t, ((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
313       if (!success)
314         palloc_free (kpage);
315     }
316   else
317     printf ("failed to allocate process stack\n");
318
319   return success;
320 }
321
322 /* Adds a mapping from user virtual address UPAGE to kernel
323    virtual address KPAGE to T's page tables.  Fails if UPAGE is
324    already mapped or if memory allocation fails. */
325 static bool
326 install_page (struct thread *t, void *upage, void *kpage)
327 {
328   /* Verify that there's not already a page at that virtual
329      address, then map our page there. */
330   return (pagedir_get_page (t->pagedir, upage) == NULL
331           && pagedir_set_page (t->pagedir, upage, kpage, true));
332 }