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, or a timer interrupt might switch back to
107 the process page directory. The asm statement prevents
108 GCC from reordering the assignment and the function
113 pagedir_activate (NULL);
114 pagedir_destroy (pd);
118 /* Sets up the CPU for running user code in the current
121 process_activate (void)
123 struct thread *t = thread_current ();
125 /* Activate thread's page tables. */
126 pagedir_activate (t->pagedir);
128 /* Set thread's kernel stack for use in processing
130 tss_set_esp0 ((uint8_t *) t + PGSIZE);
133 /* We load ELF binaries. The following definitions are taken
134 from the ELF specification, [ELF1], more-or-less verbatim. */
136 /* ELF types. See [ELF1] 1-2. */
137 typedef uint32_t Elf32_Word, Elf32_Addr, Elf32_Off;
138 typedef uint16_t Elf32_Half;
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. */
146 /* Executable header. See [ELF1] 1-4 to 1-8.
147 This appears at the very beginning of an ELF binary. */
150 unsigned char e_ident[16];
152 Elf32_Half e_machine;
153 Elf32_Word e_version;
159 Elf32_Half e_phentsize;
161 Elf32_Half e_shentsize;
163 Elf32_Half e_shstrndx;
166 /* Program header. See [ELF1] 2-2 to 2-4.
167 There are e_phnum of these, starting at file offset e_phoff
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. */
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. */
196 static bool load_segment (struct file *, const struct Elf32_Phdr *);
197 static bool setup_stack (void **esp);
199 /* Aborts loading an executable, with an error message. */
200 #define LOAD_ERROR(MSG) \
202 printf ("load: %s: ", filename); \
208 /* Loads an ELF executable from FILENAME into the current thread.
209 Stores the executable's entry point into *EIP
210 and its initial stack pointer into *ESP.
211 Returns true if successful, false otherwise. */
213 load (const char *filename, void (**eip) (void), void **esp)
215 struct thread *t = thread_current ();
216 struct Elf32_Ehdr ehdr;
217 struct file *file = NULL;
219 bool success = false;
222 /* Allocate and activate page directory. */
223 t->pagedir = pagedir_create ();
224 if (t->pagedir == NULL)
225 LOAD_ERROR (("page directory allocation failed"));
228 /* Open executable file. */
229 file = filesys_open (filename);
231 LOAD_ERROR (("open failed"));
233 /* Read and verify executable header. */
234 if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr)
235 LOAD_ERROR (("error reading executable header"));
236 if (memcmp (ehdr.e_ident, "\177ELF\1\1\1", 7) != 0)
237 LOAD_ERROR (("file is not ELF"));
238 if (ehdr.e_type != 2)
239 LOAD_ERROR (("ELF file is not an executable"));
240 if (ehdr.e_machine != 3)
241 LOAD_ERROR (("ELF executable is not x86"));
242 if (ehdr.e_version != 1)
243 LOAD_ERROR (("ELF executable has unknown version %d",
244 (int) ehdr.e_version));
245 if (ehdr.e_phentsize != sizeof (struct Elf32_Phdr))
246 LOAD_ERROR (("bad ELF program header size"));
247 if (ehdr.e_phnum > 1024)
248 LOAD_ERROR (("too many ELF program headers"));
250 /* Read program headers. */
251 file_ofs = ehdr.e_phoff;
252 for (i = 0; i < ehdr.e_phnum; i++)
254 struct Elf32_Phdr phdr;
256 if (file_ofs < 0 || file_ofs > file_length (file))
257 LOAD_ERROR (("bad file offset %ld", (long) file_ofs));
258 file_seek (file, file_ofs);
260 if (file_read (file, &phdr, sizeof phdr) != sizeof phdr)
261 LOAD_ERROR (("error reading program header"));
262 file_ofs += sizeof phdr;
269 /* Ignore this segment. */
274 /* Reject the executable. */
275 LOAD_ERROR (("unsupported ELF segment type %d\n", phdr.p_type));
278 printf ("unknown ELF segment type %08x\n", phdr.p_type);
281 if (!load_segment (file, &phdr))
288 if (!setup_stack (esp))
292 *eip = (void (*) (void)) ehdr.e_entry;
297 /* We arrive here whether the load is successful or not. */
302 /* load() helpers. */
304 static bool install_page (void *upage, void *kpage);
306 /* Loads the segment described by PHDR from FILE into user
307 address space. Return true if successful, false otherwise. */
309 load_segment (struct file *file, const struct Elf32_Phdr *phdr)
311 void *start, *end; /* Page-rounded segment start and end. */
312 uint8_t *upage; /* Iterator from start to end. */
313 off_t filesz_left; /* Bytes left of file data (as opposed to
314 zero-initialized bytes). */
316 /* Is this a read-only segment? Not currently used, so it's
317 commented out. You'll want to use it when implementing VM
318 to decide whether to page the segment from its executable or
320 //bool read_only = (phdr->p_flags & PF_W) == 0;
322 ASSERT (file != NULL);
323 ASSERT (phdr != NULL);
324 ASSERT (phdr->p_type == PT_LOAD);
326 /* [ELF1] 2-2 says that p_offset and p_vaddr must be congruent
328 if (phdr->p_offset % PGSIZE != phdr->p_vaddr % PGSIZE)
330 printf ("%#08"PE32Ox" and %#08"PE32Ax" not congruent modulo %#x\n",
331 phdr->p_offset, phdr->p_vaddr, (unsigned) PGSIZE);
335 /* p_offset must point within file. */
336 if (phdr->p_offset > (Elf32_Off) file_length (file))
338 printf ("bad p_offset %"PE32Ox, phdr->p_offset);
342 /* [ELF1] 2-3 says that p_memsz must be at least as big as
344 if (phdr->p_memsz < phdr->p_filesz)
346 printf ("p_memsz (%08"PE32Wx") < p_filesz (%08"PE32Wx")\n",
347 phdr->p_memsz, phdr->p_filesz);
351 /* Validate virtual memory region to be mapped.
352 The region must both start and end within the user address
353 space range starting at 0 and ending at PHYS_BASE (typically
354 3 GB == 0xc0000000). */
355 start = pg_round_down ((void *) phdr->p_vaddr);
356 end = pg_round_up ((void *) (phdr->p_vaddr + phdr->p_memsz));
357 if (start >= PHYS_BASE || end >= PHYS_BASE || end < start)
359 printf ("bad virtual region %08lx...%08lx\n",
360 (unsigned long) start, (unsigned long) end);
364 /* Load the segment page-by-page into memory. */
365 filesz_left = phdr->p_filesz + (phdr->p_vaddr & PGMASK);
366 file_seek (file, ROUND_DOWN (phdr->p_offset, PGSIZE));
367 for (upage = start; upage < (uint8_t *) end; upage += PGSIZE)
369 /* We want to read min(PGSIZE, filesz_left) bytes from the
370 file into the page and zero the rest. */
371 size_t read_bytes = filesz_left >= PGSIZE ? PGSIZE : filesz_left;
372 size_t zero_bytes = PGSIZE - read_bytes;
373 uint8_t *kpage = palloc_get_page (PAL_USER);
377 /* Do the reading and zeroing. */
378 if (file_read (file, kpage, read_bytes) != (int) read_bytes)
380 palloc_free_page (kpage);
383 memset (kpage + read_bytes, 0, zero_bytes);
384 filesz_left -= read_bytes;
386 /* Add the page to the process's address space. */
387 if (!install_page (upage, kpage))
389 palloc_free_page (kpage);
397 /* Create a minimal stack by mapping a zeroed page at the top of
398 user virtual memory. */
400 setup_stack (void **esp)
403 bool success = false;
405 kpage = palloc_get_page (PAL_USER | PAL_ZERO);
408 success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
412 palloc_free_page (kpage);
415 printf ("failed to allocate process stack\n");
420 /* Adds a mapping from user virtual address UPAGE to kernel
421 virtual address KPAGE to the page table. Fails if UPAGE is
422 already mapped or if memory allocation fails. */
424 install_page (void *upage, void *kpage)
426 struct thread *t = thread_current ();
428 /* Verify that there's not already a page at that virtual
429 address, then map our page there. */
430 return (pagedir_get_page (t->pagedir, upage) == NULL
431 && pagedir_set_page (t->pagedir, upage, kpage, true));