PKUOS - Pintos
Pintos source browser for PKU Operating System course
process.c
Go to the documentation of this file.
1#include "userprog/process.h"
2#include <debug.h>
3#include <inttypes.h>
4#include <round.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include "userprog/gdt.h"
9#include "userprog/pagedir.h"
10#include "userprog/tss.h"
11#include "filesys/directory.h"
12#include "filesys/file.h"
13#include "filesys/filesys.h"
14#include "threads/flags.h"
15#include "threads/init.h"
16#include "threads/interrupt.h"
17#include "threads/palloc.h"
18#include "threads/thread.h"
19#include "threads/vaddr.h"
20
22static bool load (const char *cmdline, void (**eip) (void), void **esp);
23
24/** Starts a new thread running a user program loaded from
25 FILENAME. The new thread may be scheduled (and may even exit)
26 before process_execute() returns. Returns the new process's
27 thread id, or TID_ERROR if the thread cannot be created. */
30{
31 char *fn_copy;
32 tid_t tid;
33
34 /* Make a copy of FILE_NAME.
35 Otherwise there's a race between the caller and load(). */
36 fn_copy = palloc_get_page (0);
37 if (fn_copy == NULL)
38 return TID_ERROR;
39 strlcpy (fn_copy, file_name, PGSIZE);
40
41 /* Create a new thread to execute FILE_NAME. */
43 if (tid == TID_ERROR)
44 palloc_free_page (fn_copy);
45 return tid;
46}
47
48/** A thread function that loads a user process and starts it
49 running. */
50static void
51start_process (void *file_name_)
52{
53 char *file_name = file_name_;
54 struct intr_frame if_;
55 bool success;
56
57 /* Initialize interrupt frame and load executable. */
58 memset (&if_, 0, sizeof if_);
59 if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
60 if_.cs = SEL_UCSEG;
61 if_.eflags = FLAG_IF | FLAG_MBS;
62 success = load (file_name, &if_.eip, &if_.esp);
63
64 /* If load failed, quit. */
66 if (!success)
67 thread_exit ();
68
69 /* Start the user process by simulating a return from an
70 interrupt, implemented by intr_exit (in
71 threads/intr-stubs.S). Because intr_exit takes all of its
72 arguments on the stack in the form of a `struct intr_frame',
73 we just point the stack pointer (%esp) to our stack frame
74 and jump to it. */
75 asm volatile ("movl %0, %%esp; jmp intr_exit" : : "g" (&if_) : "memory");
76 NOT_REACHED ();
77}
78
79/** Waits for thread TID to die and returns its exit status. If
80 it was terminated by the kernel (i.e. killed due to an
81 exception), returns -1. If TID is invalid or if it was not a
82 child of the calling process, or if process_wait() has already
83 been successfully called for the given TID, returns -1
84 immediately, without waiting.
85
86 This function will be implemented in problem 2-2. For now, it
87 does nothing. */
88int
90{
91 return -1;
92}
93
94/** Free the current process's resources. */
95void
97{
98 struct thread *cur = thread_current ();
99 uint32_t *pd;
100
101 /* Destroy the current process's page directory and switch back
102 to the kernel-only page directory. */
103 pd = cur->pagedir;
104 if (pd != NULL)
105 {
106 /* Correct ordering here is crucial. We must set
107 cur->pagedir to NULL before switching page directories,
108 so that a timer interrupt can't switch back to the
109 process page directory. We must activate the base page
110 directory before destroying the process's page
111 directory, or our active page directory will be one
112 that's been freed (and cleared). */
113 cur->pagedir = NULL;
115 pagedir_destroy (pd);
116 }
117}
118
119/** Sets up the CPU for running user code in the current
120 thread.
121 This function is called on every context switch. */
122void
124{
125 struct thread *t = thread_current ();
126
127 /* Activate thread's page tables. */
128 pagedir_activate (t->pagedir);
129
130 /* Set thread's kernel stack for use in processing
131 interrupts. */
132 tss_update ();
133}
134
135/** We load ELF binaries. The following definitions are taken
136 from the ELF specification, [ELF1], more-or-less verbatim. */
137
138/** ELF types. See [ELF1] 1-2. */
141
142/** For use with ELF types in printf(). */
143#define PE32Wx PRIx32 /**< Print Elf32_Word in hexadecimal. */
144#define PE32Ax PRIx32 /**< Print Elf32_Addr in hexadecimal. */
145#define PE32Ox PRIx32 /**< Print Elf32_Off in hexadecimal. */
146#define PE32Hx PRIx16 /**< Print Elf32_Half in hexadecimal. */
147
148/** Executable header. See [ELF1] 1-4 to 1-8.
149 This appears at the very beginning of an ELF binary. */
151 {
152 unsigned char e_ident[16];
166 };
167
168/** Program header. See [ELF1] 2-2 to 2-4.
169 There are e_phnum of these, starting at file offset e_phoff
170 (see [ELF1] 1-6). */
172 {
181 };
182
183/** Values for p_type. See [ELF1] 2-3. */
184#define PT_NULL 0 /**< Ignore. */
185#define PT_LOAD 1 /**< Loadable segment. */
186#define PT_DYNAMIC 2 /**< Dynamic linking info. */
187#define PT_INTERP 3 /**< Name of dynamic loader. */
188#define PT_NOTE 4 /**< Auxiliary info. */
189#define PT_SHLIB 5 /**< Reserved. */
190#define PT_PHDR 6 /**< Program header table. */
191#define PT_STACK 0x6474e551 /**< Stack segment. */
192
193/** Flags for p_flags. See [ELF3] 2-3 and 2-4. */
194#define PF_X 1 /**< Executable. */
195#define PF_W 2 /**< Writable. */
196#define PF_R 4 /**< Readable. */
197
198static bool setup_stack (void **esp);
199static bool validate_segment (const struct Elf32_Phdr *, struct file *);
200static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
201 uint32_t read_bytes, uint32_t zero_bytes,
202 bool writable);
203
204/** Loads an ELF executable from FILE_NAME into the current thread.
205 Stores the executable's entry point into *EIP
206 and its initial stack pointer into *ESP.
207 Returns true if successful, false otherwise. */
208bool
209load (const char *file_name, void (**eip) (void), void **esp)
210{
211 struct thread *t = thread_current ();
212 struct Elf32_Ehdr ehdr;
213 struct file *file = NULL;
214 off_t file_ofs;
215 bool success = false;
216 int i;
217
218 /* Allocate and activate page directory. */
219 t->pagedir = pagedir_create ();
220 if (t->pagedir == NULL)
221 goto done;
223
224 /* Open executable file. */
226 if (file == NULL)
227 {
228 printf ("load: %s: open failed\n", file_name);
229 goto done;
230 }
231
232 /* Read and verify executable header. */
233 if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
234 || memcmp (ehdr.e_ident, "\177ELF\1\1\1", 7)
235 || ehdr.e_type != 2
236 || ehdr.e_machine != 3
237 || ehdr.e_version != 1
238 || ehdr.e_phentsize != sizeof (struct Elf32_Phdr)
239 || ehdr.e_phnum > 1024)
240 {
241 printf ("load: %s: error loading executable\n", file_name);
242 goto done;
243 }
244
245 /* Read program headers. */
246 file_ofs = ehdr.e_phoff;
247 for (i = 0; i < ehdr.e_phnum; i++)
248 {
249 struct Elf32_Phdr phdr;
250
251 if (file_ofs < 0 || file_ofs > file_length (file))
252 goto done;
253 file_seek (file, file_ofs);
254
255 if (file_read (file, &phdr, sizeof phdr) != sizeof phdr)
256 goto done;
257 file_ofs += sizeof phdr;
258 switch (phdr.p_type)
259 {
260 case PT_NULL:
261 case PT_NOTE:
262 case PT_PHDR:
263 case PT_STACK:
264 default:
265 /* Ignore this segment. */
266 break;
267 case PT_DYNAMIC:
268 case PT_INTERP:
269 case PT_SHLIB:
270 goto done;
271 case PT_LOAD:
272 if (validate_segment (&phdr, file))
273 {
274 bool writable = (phdr.p_flags & PF_W) != 0;
275 uint32_t file_page = phdr.p_offset & ~PGMASK;
276 uint32_t mem_page = phdr.p_vaddr & ~PGMASK;
277 uint32_t page_offset = phdr.p_vaddr & PGMASK;
278 uint32_t read_bytes, zero_bytes;
279 if (phdr.p_filesz > 0)
280 {
281 /* Normal segment.
282 Read initial part from disk and zero the rest. */
283 read_bytes = page_offset + phdr.p_filesz;
284 zero_bytes = (ROUND_UP (page_offset + phdr.p_memsz, PGSIZE)
285 - read_bytes);
286 }
287 else
288 {
289 /* Entirely zero.
290 Don't read anything from disk. */
291 read_bytes = 0;
292 zero_bytes = ROUND_UP (page_offset + phdr.p_memsz, PGSIZE);
293 }
294 if (!load_segment (file, file_page, (void *) mem_page,
295 read_bytes, zero_bytes, writable))
296 goto done;
297 }
298 else
299 goto done;
300 break;
301 }
302 }
303
304 /* Set up stack. */
305 if (!setup_stack (esp))
306 goto done;
307
308 /* Start address. */
309 *eip = (void (*) (void)) ehdr.e_entry;
310
311 success = true;
312
313 done:
314 /* We arrive here whether the load is successful or not. */
316 return success;
317}
318
319/** load() helpers. */
320
321static bool install_page (void *upage, void *kpage, bool writable);
322
323/** Checks whether PHDR describes a valid, loadable segment in
324 FILE and returns true if so, false otherwise. */
325static bool
326validate_segment (const struct Elf32_Phdr *phdr, struct file *file)
327{
328 /* p_offset and p_vaddr must have the same page offset. */
329 if ((phdr->p_offset & PGMASK) != (phdr->p_vaddr & PGMASK))
330 return false;
331
332 /* p_offset must point within FILE. */
333 if (phdr->p_offset > (Elf32_Off) file_length (file))
334 return false;
335
336 /* p_memsz must be at least as big as p_filesz. */
337 if (phdr->p_memsz < phdr->p_filesz)
338 return false;
339
340 /* The segment must not be empty. */
341 if (phdr->p_memsz == 0)
342 return false;
343
344 /* The virtual memory region must both start and end within the
345 user address space range. */
346 if (!is_user_vaddr ((void *) phdr->p_vaddr))
347 return false;
348 if (!is_user_vaddr ((void *) (phdr->p_vaddr + phdr->p_memsz)))
349 return false;
350
351 /* The region cannot "wrap around" across the kernel virtual
352 address space. */
353 if (phdr->p_vaddr + phdr->p_memsz < phdr->p_vaddr)
354 return false;
355
356 /* Disallow mapping page 0.
357 Not only is it a bad idea to map page 0, but if we allowed
358 it then user code that passed a null pointer to system calls
359 could quite likely panic the kernel by way of null pointer
360 assertions in memcpy(), etc. */
361 if (phdr->p_vaddr < PGSIZE)
362 return false;
363
364 /* It's okay. */
365 return true;
366}
367
368/** Loads a segment starting at offset OFS in FILE at address
369 UPAGE. In total, READ_BYTES + ZERO_BYTES bytes of virtual
370 memory are initialized, as follows:
371
372 - READ_BYTES bytes at UPAGE must be read from FILE
373 starting at offset OFS.
374
375 - ZERO_BYTES bytes at UPAGE + READ_BYTES must be zeroed.
376
377 The pages initialized by this function must be writable by the
378 user process if WRITABLE is true, read-only otherwise.
379
380 Return true if successful, false if a memory allocation error
381 or disk read error occurs. */
382static bool
383load_segment (struct file *file, off_t ofs, uint8_t *upage,
384 uint32_t read_bytes, uint32_t zero_bytes, bool writable)
385{
386 ASSERT ((read_bytes + zero_bytes) % PGSIZE == 0);
387 ASSERT (pg_ofs (upage) == 0);
388 ASSERT (ofs % PGSIZE == 0);
389
390 file_seek (file, ofs);
391 while (read_bytes > 0 || zero_bytes > 0)
392 {
393 /* Calculate how to fill this page.
394 We will read PAGE_READ_BYTES bytes from FILE
395 and zero the final PAGE_ZERO_BYTES bytes. */
396 size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
397 size_t page_zero_bytes = PGSIZE - page_read_bytes;
398
399 /* Get a page of memory. */
401 if (kpage == NULL)
402 return false;
403
404 /* Load this page. */
405 if (file_read (file, kpage, page_read_bytes) != (int) page_read_bytes)
406 {
407 palloc_free_page (kpage);
408 return false;
409 }
410 memset (kpage + page_read_bytes, 0, page_zero_bytes);
411
412 /* Add the page to the process's address space. */
413 if (!install_page (upage, kpage, writable))
414 {
415 palloc_free_page (kpage);
416 return false;
417 }
418
419 /* Advance. */
420 read_bytes -= page_read_bytes;
421 zero_bytes -= page_zero_bytes;
422 upage += PGSIZE;
423 }
424 return true;
425}
426
427/** Create a minimal stack by mapping a zeroed page at the top of
428 user virtual memory. */
429static bool
430setup_stack (void **esp)
431{
432 uint8_t *kpage;
433 bool success = false;
434
436 if (kpage != NULL)
437 {
438 success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true);
439 if (success)
440 *esp = PHYS_BASE;
441 else
442 palloc_free_page (kpage);
443 }
444 return success;
445}
446
447/** Adds a mapping from user virtual address UPAGE to kernel
448 virtual address KPAGE to the page table.
449 If WRITABLE is true, the user process may modify the page;
450 otherwise, it is read-only.
451 UPAGE must not already be mapped.
452 KPAGE should probably be a page obtained from the user pool
453 with palloc_get_page().
454 Returns true on success, false if UPAGE is already mapped or
455 if memory allocation fails. */
456static bool
457install_page (void *upage, void *kpage, bool writable)
458{
459 struct thread *t = thread_current ();
460
461 /* Verify that there's not already a page at that virtual
462 address, then map our page there. */
463 return (pagedir_get_page (t->pagedir, upage) == NULL
464 && pagedir_set_page (t->pagedir, upage, kpage, writable));
465}
#define ASSERT(CONDITION)
This is outside the header guard so that debug.h may be included multiple times with different settin...
Definition: debug.h:31
#define NOT_REACHED()
lib/debug.h
Definition: debug.h:35
#define UNUSED
GCC lets us add "attributes" to functions, function parameters, etc.
Definition: debug.h:7
void file_seek(struct file *file, off_t new_pos)
Sets the current position in FILE to NEW_POS bytes from the start of the file.
Definition: file.c:154
void file_close(struct file *file)
Closes FILE.
Definition: file.c:46
off_t file_length(struct file *file)
Returns the size of FILE in bytes.
Definition: file.c:145
off_t file_read(struct file *file, void *buffer, off_t size)
Reads SIZE bytes from FILE into BUFFER, starting at the file's current position.
Definition: file.c:69
struct file * filesys_open(const char *name)
Opens the file with the given NAME.
Definition: filesys.c:67
#define FLAG_IF
Interrupt Flag.
Definition: flags.h:6
#define FLAG_MBS
EFLAGS Register.
Definition: flags.h:5
#define SEL_UCSEG
Segment selectors.
Definition: gdt.h:8
#define SEL_UDSEG
User data selector.
Definition: gdt.h:9
int printf(const char *format,...)
Writes formatted output to the console.
Definition: stdio.c:79
int32_t off_t
An offset within a file.
Definition: off_t.h:9
uint32_t * pagedir_create(void)
Creates a new page directory that has mappings for kernel virtual addresses, but none for user virtua...
Definition: pagedir.c:17
void * pagedir_get_page(uint32_t *pd, const void *uaddr)
Looks up the physical address that corresponds to user virtual address UADDR in PD.
Definition: pagedir.c:126
bool pagedir_set_page(uint32_t *pd, void *upage, void *kpage, bool writable)
Adds a mapping in page directory PD from user virtual page UPAGE to the physical frame identified by ...
Definition: pagedir.c:99
void pagedir_destroy(uint32_t *pd)
Destroys page directory PD, freeing all the pages it references.
Definition: pagedir.c:28
void pagedir_activate(uint32_t *pd)
Loads page directory PD into the CPU's page directory base register.
Definition: pagedir.c:220
void * palloc_get_page(enum palloc_flags flags)
Obtains a single free page and returns its kernel virtual address.
Definition: palloc.c:111
void palloc_free_page(void *page)
Frees the page at PAGE.
Definition: palloc.c:146
@ PAL_ZERO
Zero page contents.
Definition: palloc.h:10
@ PAL_USER
User page.
Definition: palloc.h:11
static thread_func start_process NO_RETURN
Definition: process.c:21
tid_t process_execute(const char *file_name)
Starts a new thread running a user program loaded from FILENAME.
Definition: process.c:29
#define PT_STACK
Stack segment.
Definition: process.c:191
#define PF_W
Writable.
Definition: process.c:195
#define PT_DYNAMIC
Dynamic linking info.
Definition: process.c:186
void process_activate(void)
Sets up the CPU for running user code in the current thread.
Definition: process.c:123
static bool load_segment(struct file *file, off_t ofs, uint8_t *upage, uint32_t read_bytes, uint32_t zero_bytes, bool writable)
Loads a segment starting at offset OFS in FILE at address UPAGE.
Definition: process.c:383
uint16_t Elf32_Half
Definition: process.c:140
uint32_t Elf32_Addr
Definition: process.c:139
int process_wait(tid_t child_tid UNUSED)
Waits for thread TID to die and returns its exit status.
Definition: process.c:89
static bool setup_stack(void **esp)
Create a minimal stack by mapping a zeroed page at the top of user virtual memory.
Definition: process.c:430
#define PT_PHDR
Program header table.
Definition: process.c:190
uint32_t Elf32_Off
Definition: process.c:139
static bool validate_segment(const struct Elf32_Phdr *, struct file *)
Checks whether PHDR describes a valid, loadable segment in FILE and returns true if so,...
Definition: process.c:326
#define PT_NOTE
Auxiliary info.
Definition: process.c:188
#define PT_LOAD
Loadable segment.
Definition: process.c:185
#define PT_NULL
Values for p_type.
Definition: process.c:184
static bool install_page(void *upage, void *kpage, bool writable)
load() helpers.
Definition: process.c:457
#define PT_INTERP
Name of dynamic loader.
Definition: process.c:187
#define PT_SHLIB
Reserved.
Definition: process.c:189
void process_exit(void)
Free the current process's resources.
Definition: process.c:96
uint32_t Elf32_Word
We load ELF binaries.
Definition: process.c:139
static bool load(const char *cmdline, void(**eip)(void), void **esp)
Loads an ELF executable from FILE_NAME into the current thread.
Definition: process.c:209
static void start_process(void *file_name_)
A thread function that loads a user process and starts it running.
Definition: process.c:51
#define ROUND_UP(X, STEP)
Yields X rounded up to the nearest multiple of STEP.
Definition: round.h:6
#define NULL
Definition: stddef.h:4
unsigned int uint32_t
Definition: stdint.h:26
unsigned char uint8_t
Definition: stdint.h:20
unsigned short int uint16_t
Definition: stdint.h:23
int memcmp(const void *a_, const void *b_, size_t size)
Find the first differing byte in the two blocks of SIZE bytes at A and B.
Definition: string.c:53
void * memset(void *dst_, int value, size_t size)
Sets the SIZE bytes in DST to VALUE.
Definition: string.c:279
size_t strlcpy(char *dst, const char *src, size_t size)
Copies string SRC to DST.
Definition: string.c:326
Executable header.
Definition: process.c:151
Elf32_Off e_shoff
Definition: process.c:158
Elf32_Half e_ehsize
Definition: process.c:160
Elf32_Half e_shnum
Definition: process.c:164
Elf32_Half e_machine
Definition: process.c:154
Elf32_Off e_phoff
Definition: process.c:157
Elf32_Half e_phnum
Definition: process.c:162
Elf32_Half e_shstrndx
Definition: process.c:165
Elf32_Half e_type
Definition: process.c:153
unsigned char e_ident[16]
Definition: process.c:152
Elf32_Word e_flags
Definition: process.c:159
Elf32_Word e_version
Definition: process.c:155
Elf32_Half e_shentsize
Definition: process.c:163
Elf32_Addr e_entry
Definition: process.c:156
Elf32_Half e_phentsize
Definition: process.c:161
Program header.
Definition: process.c:172
Elf32_Addr p_vaddr
Definition: process.c:175
Elf32_Word p_flags
Definition: process.c:179
Elf32_Word p_type
Definition: process.c:173
Elf32_Off p_offset
Definition: process.c:174
Elf32_Word p_filesz
Definition: process.c:177
Elf32_Word p_memsz
Definition: process.c:178
Elf32_Addr p_paddr
Definition: process.c:176
Elf32_Word p_align
Definition: process.c:180
An open file.
Definition: file.c:8
Interrupt stack frame.
Definition: interrupt.h:21
uint16_t uint32_t eflags
Code segment for eip.
Definition: interrupt.h:52
uint16_t ss
Definition: interrupt.h:55
void(* eip)(void)
Next instruction to execute.
Definition: interrupt.h:51
uint16_t uint16_t fs
Saved GS segment register.
Definition: interrupt.h:32
uint16_t uint16_t uint16_t es
Saved FS segment register.
Definition: interrupt.h:33
uint16_t uint16_t uint16_t uint16_t ds
Saved ES segment register.
Definition: interrupt.h:34
uint16_t gs
Definition: interrupt.h:32
void * esp
Saved stack pointer.
Definition: interrupt.h:54
uint16_t cs
Definition: interrupt.h:52
A kernel thread or user process.
Definition: thread.h:84
static const char file_name[]
tests/filesys/base/syn-read.h
Definition: syn-read.h:5
struct thread * thread_current(void)
Returns the running thread.
Definition: thread.c:256
void thread_exit(void)
Deschedules the current thread and destroys it.
Definition: thread.c:281
tid_t thread_create(const char *name, int priority, thread_func *function, void *aux)
Creates a new kernel thread named NAME with the given initial PRIORITY, which executes FUNCTION passi...
Definition: thread.c:166
#define PRI_DEFAULT
Default priority.
Definition: thread.h:24
#define TID_ERROR
Error value for tid_t.
Definition: thread.h:20
int tid_t
Thread identifier type.
Definition: thread.h:19
void thread_func(void *aux)
Definition: thread.h:116
void tss_update(void)
Sets the ring 0 stack pointer in the TSS to point to the end of the thread stack.
Definition: tss.c:102
#define PGSIZE
Bytes in a page.
Definition: vaddr.h:20
static bool is_user_vaddr(const void *vaddr)
Returns true if VADDR is a user virtual address.
Definition: vaddr.h:57
#define PHYS_BASE
Base address of the 1:1 physical-to-virtual mapping.
Definition: vaddr.h:53
static unsigned pg_ofs(const void *va)
Offset within a page.
Definition: vaddr.h:24
#define PGMASK
Page offset bits (0:12).
Definition: vaddr.h:21