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