Get rid of unnecessary barrier. Improve comment.
[pintos-anon] / src / userprog / process.c
1 #include "userprog/process.h"
2 #include <debug.h>
3 #include <inttypes.h>
4 #include <round.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include "userprog/gdt.h"
8 #include "userprog/pagedir.h"
9 #include "userprog/tss.h"
10 #include "filesys/directory.h"
11 #include "filesys/file.h"
12 #include "filesys/filesys.h"
13 #include "threads/flags.h"
14 #include "threads/init.h"
15 #include "threads/interrupt.h"
16 #include "threads/mmu.h"
17 #include "threads/palloc.h"
18 #include "threads/thread.h"
19
20 static thread_func execute_thread NO_RETURN;
21 static bool load (const char *cmdline, void (**eip) (void), void **esp);
22
23 /* Starts a new thread running a user program loaded from
24    FILENAME.  The new thread may be scheduled (and may even exit)
25    before process_execute() returns.  Returns the new process's
26    thread id, or TID_ERROR if the thread cannot be created. */
27 tid_t
28 process_execute (const char *filename) 
29 {
30   char *fn_copy;
31   tid_t tid;
32
33   /* Make a copy of FILENAME.
34      Otherwise there's a race between the caller and load(). */
35   fn_copy = palloc_get_page (0);
36   if (fn_copy == NULL)
37     return TID_ERROR;
38   strlcpy (fn_copy, filename, PGSIZE);
39
40   /* Create a new thread to execute FILENAME. */
41   tid = thread_create (filename, PRI_DEFAULT, execute_thread, fn_copy);
42   if (tid == TID_ERROR)
43     palloc_free_page (fn_copy); 
44   return tid;
45 }
46
47 /* A thread function that loads a user process and starts it
48    running. */
49 static void
50 execute_thread (void *filename_)
51 {
52   char *filename = filename_;
53   struct intr_frame if_;
54   bool success;
55
56   /* Initialize interrupt frame and load executable. */
57   memset (&if_, 0, sizeof if_);
58   if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
59   if_.cs = SEL_UCSEG;
60   if_.eflags = FLAG_IF | FLAG_MBS;
61   success = load (filename, &if_.eip, &if_.esp);
62
63   /* If load failed, quit. */
64   palloc_free_page (filename);
65   if (!success) 
66     thread_exit ();
67
68   /* Start the user process by simulating a return from an
69      interrupt, implemented by intr_exit (in
70      threads/intr-stubs.S).  Because intr_exit takes all of its
71      arguments on the stack in the form of a `struct intr_frame',
72      we just point the stack pointer (%esp) to our stack frame
73      and jump to it. */
74   asm ("mov %%esp, %0; jmp intr_exit" :: "g" (&if_));
75   NOT_REACHED ();
76 }
77
78 /* Waits for thread TID to die and returns its exit status.  If
79    it was terminated by the kernel (i.e. killed due to an
80    exception), returns -1.  If TID is invalid or if it was not a
81    child of the calling process, or if process_wait() has already
82    been successfully called for the given TID, returns -1
83    immediately, without waiting.
84
85    This function will be implemented in problem 2-2.  For now, it
86    does nothing. */
87 int
88 process_wait (tid_t child_tid UNUSED) 
89 {
90   return -1;
91 }
92
93 /* Free the current process's resources. */
94 void
95 process_exit (void)
96 {
97   struct thread *cur = thread_current ();
98   uint32_t *pd;
99
100   /* Destroy the current process's page directory and switch back
101      to the kernel-only page directory. */
102   pd = cur->pagedir;
103   if (pd != NULL) 
104     {
105       /* We must set cur->pagedir to NULL before switching page
106          directories, so that a timer interrupt can't switch back
107          to the process page directory.  We must activate the
108          base page directory before destroying the process's page
109          directory, or our active page directory will be one
110          that's been freed (and cleared). */
111       cur->pagedir = NULL;
112       pagedir_activate (NULL);
113       pagedir_destroy (pd);
114     }
115 }
116
117 /* Sets up the CPU for running user code in the current
118    thread. */
119 void
120 process_activate (void)
121 {
122   struct thread *t = thread_current ();
123
124   /* Activate thread's page tables. */
125   pagedir_activate (t->pagedir);
126
127   /* Set thread's kernel stack for use in processing
128      interrupts. */
129   tss_set_esp0 ((uint8_t *) t + PGSIZE);
130 }
131 \f
132 /* We load ELF binaries.  The following definitions are taken
133    from the ELF specification, [ELF1], more-or-less verbatim.  */
134
135 /* ELF types.  See [ELF1] 1-2. */
136 typedef uint32_t Elf32_Word, Elf32_Addr, Elf32_Off;
137 typedef uint16_t Elf32_Half;
138
139 /* For use with ELF types in printf(). */
140 #define PE32Wx PRIx32   /* Print Elf32_Word in hexadecimal. */
141 #define PE32Ax PRIx32   /* Print Elf32_Addr in hexadecimal. */
142 #define PE32Ox PRIx32   /* Print Elf32_Off in hexadecimal. */
143 #define PE32Hx PRIx16   /* Print Elf32_Half in hexadecimal. */
144
145 /* Executable header.  See [ELF1] 1-4 to 1-8.
146    This appears at the very beginning of an ELF binary. */
147 struct Elf32_Ehdr
148   {
149     unsigned char e_ident[16];
150     Elf32_Half    e_type;
151     Elf32_Half    e_machine;
152     Elf32_Word    e_version;
153     Elf32_Addr    e_entry;
154     Elf32_Off     e_phoff;
155     Elf32_Off     e_shoff;
156     Elf32_Word    e_flags;
157     Elf32_Half    e_ehsize;
158     Elf32_Half    e_phentsize;
159     Elf32_Half    e_phnum;
160     Elf32_Half    e_shentsize;
161     Elf32_Half    e_shnum;
162     Elf32_Half    e_shstrndx;
163   };
164
165 /* Program header.  See [ELF1] 2-2 to 2-4.
166    There are e_phnum of these, starting at file offset e_phoff
167    (see [ELF1] 1-6). */
168 struct Elf32_Phdr
169   {
170     Elf32_Word p_type;
171     Elf32_Off  p_offset;
172     Elf32_Addr p_vaddr;
173     Elf32_Addr p_paddr;
174     Elf32_Word p_filesz;
175     Elf32_Word p_memsz;
176     Elf32_Word p_flags;
177     Elf32_Word p_align;
178   };
179
180 /* Values for p_type.  See [ELF1] 2-3. */
181 #define PT_NULL    0            /* Ignore. */
182 #define PT_LOAD    1            /* Loadable segment. */
183 #define PT_DYNAMIC 2            /* Dynamic linking info. */
184 #define PT_INTERP  3            /* Name of dynamic loader. */
185 #define PT_NOTE    4            /* Auxiliary info. */
186 #define PT_SHLIB   5            /* Reserved. */
187 #define PT_PHDR    6            /* Program header table. */
188 #define PT_STACK   0x6474e551   /* Stack segment. */
189
190 /* Flags for p_flags.  See [ELF3] 2-3 and 2-4. */
191 #define PF_X 1          /* Executable. */
192 #define PF_W 2          /* Writable. */
193 #define PF_R 4          /* Readable. */
194
195 static bool load_segment (struct file *, const struct Elf32_Phdr *);
196 static bool setup_stack (void **esp);
197
198 /* Aborts loading an executable, with an error message. */
199 #define LOAD_ERROR(MSG)                                 \
200         do {                                            \
201                 printf ("load: %s: ", filename);        \
202                 printf MSG;                             \
203                 printf ("\n");                          \
204                 goto done;                              \
205         } while (0)
206
207 /* Loads an ELF executable from FILENAME into the current thread.
208    Stores the executable's entry point into *EIP
209    and its initial stack pointer into *ESP.
210    Returns true if successful, false otherwise. */
211 bool
212 load (const char *filename, void (**eip) (void), void **esp) 
213 {
214   struct thread *t = thread_current ();
215   struct Elf32_Ehdr ehdr;
216   struct file *file = NULL;
217   off_t file_ofs;
218   bool success = false;
219   int i;
220
221   /* Allocate and activate page directory. */
222   t->pagedir = pagedir_create ();
223   if (t->pagedir == NULL)
224     LOAD_ERROR (("page directory allocation failed"));
225   process_activate ();
226
227   /* Open executable file. */
228   file = filesys_open (filename);
229   if (file == NULL)
230     LOAD_ERROR (("open failed"));
231
232   /* Read and verify executable header. */
233   if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr) 
234     LOAD_ERROR (("error reading executable header"));
235   if (memcmp (ehdr.e_ident, "\177ELF\1\1\1", 7) != 0)
236     LOAD_ERROR (("file is not ELF"));
237   if (ehdr.e_type != 2)
238     LOAD_ERROR (("ELF file is not an executable"));
239   if (ehdr.e_machine != 3)
240     LOAD_ERROR (("ELF executable is not x86"));
241   if (ehdr.e_version != 1)
242     LOAD_ERROR (("ELF executable has unknown version %d",
243                  (int) ehdr.e_version));
244   if (ehdr.e_phentsize != sizeof (struct Elf32_Phdr))
245     LOAD_ERROR (("bad ELF program header size"));
246   if (ehdr.e_phnum > 1024)
247     LOAD_ERROR (("too many ELF program headers"));
248
249   /* Read program headers. */
250   file_ofs = ehdr.e_phoff;
251   for (i = 0; i < ehdr.e_phnum; i++) 
252     {
253       struct Elf32_Phdr phdr;
254
255       if (file_ofs < 0 || file_ofs > file_length (file))
256         LOAD_ERROR (("bad file offset %ld", (long) file_ofs));
257       file_seek (file, file_ofs);
258
259       if (file_read (file, &phdr, sizeof phdr) != sizeof phdr)
260         LOAD_ERROR (("error reading program header"));
261       file_ofs += sizeof phdr;
262       switch (phdr.p_type) 
263         {
264         case PT_NULL:
265         case PT_NOTE:
266         case PT_PHDR:
267         case PT_STACK:
268           /* Ignore this segment. */
269           break;
270         case PT_DYNAMIC:
271         case PT_INTERP:
272         case PT_SHLIB:
273           /* Reject the executable. */
274           LOAD_ERROR (("unsupported ELF segment type %d\n", phdr.p_type));
275           break;
276         default:
277           printf ("unknown ELF segment type %08x\n", phdr.p_type);
278           break;
279         case PT_LOAD:
280           if (!load_segment (file, &phdr))
281             goto done;
282           break;
283         }
284     }
285
286   /* Set up stack. */
287   if (!setup_stack (esp))
288     goto done;
289
290   /* Start address. */
291   *eip = (void (*) (void)) ehdr.e_entry;
292
293   success = true;
294
295  done:
296   /* We arrive here whether the load is successful or not. */
297   file_close (file);
298   return success;
299 }
300 \f
301 /* load() helpers. */
302
303 static bool install_page (void *upage, void *kpage);
304
305 /* Loads the segment described by PHDR from FILE into user
306    address space.  Return true if successful, false otherwise. */
307 static bool
308 load_segment (struct file *file, const struct Elf32_Phdr *phdr) 
309 {
310   void *start, *end;  /* Page-rounded segment start and end. */
311   uint8_t *upage;     /* Iterator from start to end. */
312   off_t filesz_left;  /* Bytes left of file data (as opposed to
313                          zero-initialized bytes). */
314
315   /* Is this a read-only segment?  Not currently used, so it's
316      commented out.  You'll want to use it when implementing VM
317      to decide whether to page the segment from its executable or
318      from swap. */
319   //bool read_only = (phdr->p_flags & PF_W) == 0;
320
321   ASSERT (file != NULL);
322   ASSERT (phdr != NULL);
323   ASSERT (phdr->p_type == PT_LOAD);
324
325   /* [ELF1] 2-2 says that p_offset and p_vaddr must be congruent
326      modulo PGSIZE. */
327   if (phdr->p_offset % PGSIZE != phdr->p_vaddr % PGSIZE) 
328     {
329       printf ("%#08"PE32Ox" and %#08"PE32Ax" not congruent modulo %#x\n",
330               phdr->p_offset, phdr->p_vaddr, (unsigned) PGSIZE);
331       return false; 
332     }
333
334   /* p_offset must point within file. */
335   if (phdr->p_offset > (Elf32_Off) file_length (file)) 
336     {
337       printf ("bad p_offset %"PE32Ox, phdr->p_offset);
338       return false;
339     }
340
341   /* [ELF1] 2-3 says that p_memsz must be at least as big as
342      p_filesz. */
343   if (phdr->p_memsz < phdr->p_filesz) 
344     {
345       printf ("p_memsz (%08"PE32Wx") < p_filesz (%08"PE32Wx")\n",
346               phdr->p_memsz, phdr->p_filesz);
347       return false; 
348     }
349
350   /* Validate virtual memory region to be mapped.
351      The region must both start and end within the user address
352      space range starting at 0 and ending at PHYS_BASE (typically
353      3 GB == 0xc0000000).  We don't allow mapping page 0 .*/
354   start = pg_round_down ((void *) phdr->p_vaddr);
355   end = pg_round_up ((void *) (phdr->p_vaddr + phdr->p_memsz));
356   if (start == 0 || start >= PHYS_BASE || end >= PHYS_BASE || end < start) 
357     {
358       printf ("bad virtual region %08lx...%08lx\n",
359               (unsigned long) start, (unsigned long) end);
360       return false; 
361     }
362
363   /* Load the segment page-by-page into memory. */
364   filesz_left = phdr->p_filesz + (phdr->p_vaddr & PGMASK);
365   file_seek (file, ROUND_DOWN (phdr->p_offset, PGSIZE));
366   for (upage = start; upage < (uint8_t *) end; upage += PGSIZE) 
367     {
368       /* We want to read min(PGSIZE, filesz_left) bytes from the
369          file into the page and zero the rest. */
370       size_t read_bytes = filesz_left >= PGSIZE ? PGSIZE : filesz_left;
371       size_t zero_bytes = PGSIZE - read_bytes;
372       uint8_t *kpage = palloc_get_page (PAL_USER);
373       if (kpage == NULL)
374         return false;
375
376       /* Do the reading and zeroing. */
377       if (file_read (file, kpage, read_bytes) != (int) read_bytes) 
378         {
379           palloc_free_page (kpage);
380           return false; 
381         }
382       memset (kpage + read_bytes, 0, zero_bytes);
383       filesz_left -= read_bytes;
384
385       /* Add the page to the process's address space. */
386       if (!install_page (upage, kpage)) 
387         {
388           palloc_free_page (kpage);
389           return false; 
390         }
391     }
392
393   return true;
394 }
395
396 /* Create a minimal stack by mapping a zeroed page at the top of
397    user virtual memory. */
398 static bool
399 setup_stack (void **esp) 
400 {
401   uint8_t *kpage;
402   bool success = false;
403
404   kpage = palloc_get_page (PAL_USER | PAL_ZERO);
405   if (kpage != NULL) 
406     {
407       success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
408       if (success)
409         *esp = PHYS_BASE;
410       else
411         palloc_free_page (kpage);
412     }
413   else
414     printf ("failed to allocate process stack\n");
415
416   return success;
417 }
418
419 /* Adds a mapping from user virtual address UPAGE to kernel
420    virtual address KPAGE to the page table.  Fails if UPAGE is
421    already mapped or if memory allocation fails. */
422 static bool
423 install_page (void *upage, void *kpage)
424 {
425   struct thread *t = thread_current ();
426
427   /* Verify that there's not already a page at that virtual
428      address, then map our page there. */
429   return (pagedir_get_page (t->pagedir, upage) == NULL
430           && pagedir_set_page (t->pagedir, upage, kpage, true));
431 }