Revert Intel-style assembly back to AT&T-style.
[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 ("movl %0, %%esp; 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       /* Correct ordering here is crucial.  We must set
106          cur->pagedir to NULL before switching page directories,
107          so that a timer interrupt can't switch back to the
108          process page directory.  We must activate the base page
109          directory before destroying the process's page
110          directory, or our active page directory will be one
111          that's been freed (and cleared). */
112       cur->pagedir = NULL;
113       pagedir_activate (NULL);
114       pagedir_destroy (pd);
115     }
116 }
117
118 /* Sets up the CPU for running user code in the current
119    thread. */
120 void
121 process_activate (void)
122 {
123   struct thread *t = thread_current ();
124
125   /* Activate thread's page tables. */
126   pagedir_activate (t->pagedir);
127
128   /* Set thread's kernel stack for use in processing
129      interrupts. */
130   tss_set_esp0 ((uint8_t *) t + PGSIZE);
131 }
132 \f
133 /* We load ELF binaries.  The following definitions are taken
134    from the ELF specification, [ELF1], more-or-less verbatim.  */
135
136 /* ELF types.  See [ELF1] 1-2. */
137 typedef uint32_t Elf32_Word, Elf32_Addr, Elf32_Off;
138 typedef uint16_t Elf32_Half;
139
140 /* For use with ELF types in printf(). */
141 #define PE32Wx PRIx32   /* Print Elf32_Word in hexadecimal. */
142 #define PE32Ax PRIx32   /* Print Elf32_Addr in hexadecimal. */
143 #define PE32Ox PRIx32   /* Print Elf32_Off in hexadecimal. */
144 #define PE32Hx PRIx16   /* Print Elf32_Half in hexadecimal. */
145
146 /* Executable header.  See [ELF1] 1-4 to 1-8.
147    This appears at the very beginning of an ELF binary. */
148 struct Elf32_Ehdr
149   {
150     unsigned char e_ident[16];
151     Elf32_Half    e_type;
152     Elf32_Half    e_machine;
153     Elf32_Word    e_version;
154     Elf32_Addr    e_entry;
155     Elf32_Off     e_phoff;
156     Elf32_Off     e_shoff;
157     Elf32_Word    e_flags;
158     Elf32_Half    e_ehsize;
159     Elf32_Half    e_phentsize;
160     Elf32_Half    e_phnum;
161     Elf32_Half    e_shentsize;
162     Elf32_Half    e_shnum;
163     Elf32_Half    e_shstrndx;
164   };
165
166 /* Program header.  See [ELF1] 2-2 to 2-4.
167    There are e_phnum of these, starting at file offset e_phoff
168    (see [ELF1] 1-6). */
169 struct Elf32_Phdr
170   {
171     Elf32_Word p_type;
172     Elf32_Off  p_offset;
173     Elf32_Addr p_vaddr;
174     Elf32_Addr p_paddr;
175     Elf32_Word p_filesz;
176     Elf32_Word p_memsz;
177     Elf32_Word p_flags;
178     Elf32_Word p_align;
179   };
180
181 /* Values for p_type.  See [ELF1] 2-3. */
182 #define PT_NULL    0            /* Ignore. */
183 #define PT_LOAD    1            /* Loadable segment. */
184 #define PT_DYNAMIC 2            /* Dynamic linking info. */
185 #define PT_INTERP  3            /* Name of dynamic loader. */
186 #define PT_NOTE    4            /* Auxiliary info. */
187 #define PT_SHLIB   5            /* Reserved. */
188 #define PT_PHDR    6            /* Program header table. */
189 #define PT_STACK   0x6474e551   /* Stack segment. */
190
191 /* Flags for p_flags.  See [ELF3] 2-3 and 2-4. */
192 #define PF_X 1          /* Executable. */
193 #define PF_W 2          /* Writable. */
194 #define PF_R 4          /* Readable. */
195
196 static bool load_segment (struct file *, const struct Elf32_Phdr *);
197 static bool setup_stack (void **esp);
198
199 /* Loads an ELF executable from FILENAME into the current thread.
200    Stores the executable's entry point into *EIP
201    and its initial stack pointer into *ESP.
202    Returns true if successful, false otherwise. */
203 bool
204 load (const char *filename, void (**eip) (void), void **esp) 
205 {
206   struct thread *t = thread_current ();
207   struct Elf32_Ehdr ehdr;
208   struct file *file = NULL;
209   off_t file_ofs;
210   bool success = false;
211   int i;
212
213   /* Allocate and activate page directory. */
214   t->pagedir = pagedir_create ();
215   if (t->pagedir == NULL) 
216     goto done;
217   process_activate ();
218
219   /* Open executable file. */
220   file = filesys_open (filename);
221   if (file == NULL) 
222     {
223       printf ("load: %s: open failed\n", filename);
224       goto done; 
225     }
226
227   /* Read and verify executable header. */
228   if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
229       || memcmp (ehdr.e_ident, "\177ELF\1\1\1", 7)
230       || ehdr.e_type != 2
231       || ehdr.e_machine != 3
232       || ehdr.e_version != 1
233       || ehdr.e_phentsize != sizeof (struct Elf32_Phdr)
234       || ehdr.e_phnum > 1024) 
235     {
236       printf ("load: %s: error loading executable\n", filename);
237       goto done; 
238     }
239
240   /* Read program headers. */
241   file_ofs = ehdr.e_phoff;
242   for (i = 0; i < ehdr.e_phnum; i++) 
243     {
244       struct Elf32_Phdr phdr;
245
246       if (file_ofs < 0 || file_ofs > file_length (file))
247         goto done;
248       file_seek (file, file_ofs);
249
250       if (file_read (file, &phdr, sizeof phdr) != sizeof phdr)
251         goto done;
252       file_ofs += sizeof phdr;
253       switch (phdr.p_type) 
254         {
255         case PT_NULL:
256         case PT_NOTE:
257         case PT_PHDR:
258         case PT_STACK:
259         default:
260           /* Ignore this segment. */
261           break;
262         case PT_DYNAMIC:
263         case PT_INTERP:
264         case PT_SHLIB:
265           goto done;
266         case PT_LOAD:
267           if (!load_segment (file, &phdr))
268             goto done;
269           break;
270         }
271     }
272
273   /* Set up stack. */
274   if (!setup_stack (esp))
275     goto done;
276
277   /* Start address. */
278   *eip = (void (*) (void)) ehdr.e_entry;
279
280   success = true;
281
282  done:
283   /* We arrive here whether the load is successful or not. */
284   file_close (file);
285   return success;
286 }
287 \f
288 /* load() helpers. */
289
290 static bool install_page (void *upage, void *kpage);
291
292 /* Loads the segment described by PHDR from FILE into user
293    address space.  Return true if successful, false otherwise. */
294 static bool
295 load_segment (struct file *file, const struct Elf32_Phdr *phdr) 
296 {
297   void *start, *end;  /* Page-rounded segment start and end. */
298   uint8_t *upage;     /* Iterator from start to end. */
299   off_t filesz_left;  /* Bytes left of file data (as opposed to
300                          zero-initialized bytes). */
301
302   /* Is this a read-only segment?  Not currently used, so it's
303      commented out.  You'll want to use it when implementing VM
304      to decide whether to page the segment from its executable or
305      from swap. */
306   //bool read_only = (phdr->p_flags & PF_W) == 0;
307
308   ASSERT (file != NULL);
309   ASSERT (phdr != NULL);
310   ASSERT (phdr->p_type == PT_LOAD);
311
312   /* [ELF1] 2-2 says that p_offset and p_vaddr must be congruent
313      modulo PGSIZE. */
314   if (phdr->p_offset % PGSIZE != phdr->p_vaddr % PGSIZE) 
315     return false; 
316
317   /* p_offset must point within file. */
318   if (phdr->p_offset > (Elf32_Off) file_length (file)) 
319     return false;
320
321   /* [ELF1] 2-3 says that p_memsz must be at least as big as
322      p_filesz. */
323   if (phdr->p_memsz < phdr->p_filesz) 
324     return false; 
325
326   /* Validate virtual memory region to be mapped.
327      The region must both start and end within the user address
328      space range.  We don't allow mapping page 0.*/
329   start = pg_round_down ((void *) phdr->p_vaddr);
330   end = pg_round_up ((void *) (phdr->p_vaddr + phdr->p_memsz));
331   if (!is_user_vaddr (start) || !is_user_vaddr (end) || end < start
332       || start == 0)
333     return false; 
334
335   /* Load the segment page-by-page into memory. */
336   filesz_left = phdr->p_filesz + (phdr->p_vaddr & PGMASK);
337   file_seek (file, ROUND_DOWN (phdr->p_offset, PGSIZE));
338   for (upage = start; upage < (uint8_t *) end; upage += PGSIZE) 
339     {
340       /* We want to read min(PGSIZE, filesz_left) bytes from the
341          file into the page and zero the rest. */
342       size_t read_bytes = filesz_left >= PGSIZE ? PGSIZE : filesz_left;
343       size_t zero_bytes = PGSIZE - read_bytes;
344       uint8_t *kpage = palloc_get_page (PAL_USER);
345       if (kpage == NULL)
346         return false;
347
348       /* Do the reading and zeroing. */
349       if (file_read (file, kpage, read_bytes) != (int) read_bytes) 
350         {
351           palloc_free_page (kpage);
352           return false; 
353         }
354       memset (kpage + read_bytes, 0, zero_bytes);
355       filesz_left -= read_bytes;
356
357       /* Add the page to the process's address space. */
358       if (!install_page (upage, kpage)) 
359         {
360           palloc_free_page (kpage);
361           return false; 
362         }
363     }
364
365   return true;
366 }
367
368 /* Create a minimal stack by mapping a zeroed page at the top of
369    user virtual memory. */
370 static bool
371 setup_stack (void **esp) 
372 {
373   uint8_t *kpage;
374   bool success = false;
375
376   kpage = palloc_get_page (PAL_USER | PAL_ZERO);
377   if (kpage != NULL) 
378     {
379       success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
380       if (success)
381         *esp = PHYS_BASE;
382       else
383         palloc_free_page (kpage);
384     }
385   return success;
386 }
387
388 /* Adds a mapping from user virtual address UPAGE to kernel
389    virtual address KPAGE to the page table.  Fails if UPAGE is
390    already mapped or if memory allocation fails. */
391 static bool
392 install_page (void *upage, void *kpage)
393 {
394   struct thread *t = thread_current ();
395
396   /* Verify that there's not already a page at that virtual
397      address, then map our page there. */
398   return (pagedir_get_page (t->pagedir, upage) == NULL
399           && pagedir_set_page (t->pagedir, upage, kpage, true));
400 }