1 #include "userprog/process.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"
20 static thread_func execute_thread NO_RETURN;
21 static bool load (const char *cmdline, void (**eip) (void), void **esp);
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. */
28 process_execute (const char *filename)
33 /* Make a copy of FILENAME.
34 Otherwise there's a race between the caller and load(). */
35 fn_copy = palloc_get_page (0);
38 strlcpy (fn_copy, filename, PGSIZE);
40 /* Create a new thread to execute FILENAME. */
41 tid = thread_create (filename, PRI_DEFAULT, execute_thread, fn_copy);
43 palloc_free_page (fn_copy);
47 /* A thread function that loads a user process and starts it
50 execute_thread (void *filename_)
52 char *filename = filename_;
53 struct intr_frame if_;
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;
60 if_.eflags = FLAG_IF | FLAG_MBS;
61 success = load (filename, &if_.eip, &if_.esp);
63 /* If load failed, quit. */
64 palloc_free_page (filename);
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
74 asm ("mov %%esp, %0; jmp intr_exit" :: "g" (&if_));
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.
85 This function will be implemented in problem 2-2. For now, it
88 process_wait (tid_t child_tid UNUSED)
93 /* Free the current process's resources. */
97 struct thread *cur = thread_current ();
100 /* Destroy the current process's page directory and switch back
101 to the kernel-only page directory. */
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). */
112 pagedir_activate (NULL);
113 pagedir_destroy (pd);
117 /* Sets up the CPU for running user code in the current
120 process_activate (void)
122 struct thread *t = thread_current ();
124 /* Activate thread's page tables. */
125 pagedir_activate (t->pagedir);
127 /* Set thread's kernel stack for use in processing
129 tss_set_esp0 ((uint8_t *) t + PGSIZE);
132 /* We load ELF binaries. The following definitions are taken
133 from the ELF specification, [ELF1], more-or-less verbatim. */
135 /* ELF types. See [ELF1] 1-2. */
136 typedef uint32_t Elf32_Word, Elf32_Addr, Elf32_Off;
137 typedef uint16_t Elf32_Half;
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. */
145 /* Executable header. See [ELF1] 1-4 to 1-8.
146 This appears at the very beginning of an ELF binary. */
149 unsigned char e_ident[16];
151 Elf32_Half e_machine;
152 Elf32_Word e_version;
158 Elf32_Half e_phentsize;
160 Elf32_Half e_shentsize;
162 Elf32_Half e_shstrndx;
165 /* Program header. See [ELF1] 2-2 to 2-4.
166 There are e_phnum of these, starting at file offset e_phoff
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. */
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. */
195 static bool load_segment (struct file *, const struct Elf32_Phdr *);
196 static bool setup_stack (void **esp);
198 /* Aborts loading an executable, with an error message. */
199 #define LOAD_ERROR(MSG) \
201 printf ("load: %s: ", filename); \
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. */
212 load (const char *filename, void (**eip) (void), void **esp)
214 struct thread *t = thread_current ();
215 struct Elf32_Ehdr ehdr;
216 struct file *file = NULL;
218 bool success = false;
221 /* Allocate and activate page directory. */
222 t->pagedir = pagedir_create ();
223 if (t->pagedir == NULL)
224 LOAD_ERROR (("page directory allocation failed"));
227 /* Open executable file. */
228 file = filesys_open (filename);
230 LOAD_ERROR (("open failed"));
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"));
249 /* Read program headers. */
250 file_ofs = ehdr.e_phoff;
251 for (i = 0; i < ehdr.e_phnum; i++)
253 struct Elf32_Phdr phdr;
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);
259 if (file_read (file, &phdr, sizeof phdr) != sizeof phdr)
260 LOAD_ERROR (("error reading program header"));
261 file_ofs += sizeof phdr;
268 /* Ignore this segment. */
273 /* Reject the executable. */
274 LOAD_ERROR (("unsupported ELF segment type %d\n", phdr.p_type));
277 printf ("unknown ELF segment type %08x\n", phdr.p_type);
280 if (!load_segment (file, &phdr))
287 if (!setup_stack (esp))
291 *eip = (void (*) (void)) ehdr.e_entry;
296 /* We arrive here whether the load is successful or not. */
301 /* load() helpers. */
303 static bool install_page (void *upage, void *kpage);
305 /* Loads the segment described by PHDR from FILE into user
306 address space. Return true if successful, false otherwise. */
308 load_segment (struct file *file, const struct Elf32_Phdr *phdr)
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). */
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
319 //bool read_only = (phdr->p_flags & PF_W) == 0;
321 ASSERT (file != NULL);
322 ASSERT (phdr != NULL);
323 ASSERT (phdr->p_type == PT_LOAD);
325 /* [ELF1] 2-2 says that p_offset and p_vaddr must be congruent
327 if (phdr->p_offset % PGSIZE != phdr->p_vaddr % PGSIZE)
329 printf ("%#08"PE32Ox" and %#08"PE32Ax" not congruent modulo %#x\n",
330 phdr->p_offset, phdr->p_vaddr, (unsigned) PGSIZE);
334 /* p_offset must point within file. */
335 if (phdr->p_offset > (Elf32_Off) file_length (file))
337 printf ("bad p_offset %"PE32Ox, phdr->p_offset);
341 /* [ELF1] 2-3 says that p_memsz must be at least as big as
343 if (phdr->p_memsz < phdr->p_filesz)
345 printf ("p_memsz (%08"PE32Wx") < p_filesz (%08"PE32Wx")\n",
346 phdr->p_memsz, phdr->p_filesz);
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)
358 printf ("bad virtual region %08lx...%08lx\n",
359 (unsigned long) start, (unsigned long) end);
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)
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);
376 /* Do the reading and zeroing. */
377 if (file_read (file, kpage, read_bytes) != (int) read_bytes)
379 palloc_free_page (kpage);
382 memset (kpage + read_bytes, 0, zero_bytes);
383 filesz_left -= read_bytes;
385 /* Add the page to the process's address space. */
386 if (!install_page (upage, kpage))
388 palloc_free_page (kpage);
396 /* Create a minimal stack by mapping a zeroed page at the top of
397 user virtual memory. */
399 setup_stack (void **esp)
402 bool success = false;
404 kpage = palloc_get_page (PAL_USER | PAL_ZERO);
407 success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
411 palloc_free_page (kpage);
414 printf ("failed to allocate process stack\n");
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. */
423 install_page (void *upage, void *kpage)
425 struct thread *t = thread_current ();
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));