Fix asm constraints to avoid SI, DI for byte and word access.
[pintos-anon] / doc / userprog.texi
index 7322dd52946c2c9b601063bc717dbd2f38d245cf..612bb81ba553166d0796c84a923155a7e404ce45 100644 (file)
@@ -1,4 +1,4 @@
-@node Project 2--User Programs, Project 3--Virtual Memory, Project 1--Threads, Top
+@node Project 2--User Programs
 @chapter Project 2: User Programs
 
 Now that you've worked with Pintos and are becoming familiar with its
@@ -10,15 +10,18 @@ is possible.  In this project, you will enable programs to interact with
 the OS via system calls.
 
 You will be working out of the @file{userprog} directory for this
-assignment.  However, you will also be interacting with almost every
-other part of the code for this assignment. We will describe the
+assignment, but you will also be interacting with almost every
+other part of Pintos.  We will describe the
 relevant parts below.
 
 You can build project 2 on top of your project 1 submission or you can
-start with a fresh copy.  No code from project 1 is required for this
+start fresh.  No code from project 1 is required for this
 assignment.  The ``alarm clock'' functionality may be useful in
 projects 3 and 4, but it is not strictly required.
 
+You might find it useful to go back and reread how to run the tests
+(@pxref{Testing}).
+
 @menu
 * Project 2 Background::        
 * Project 2 Suggested Order of Implementation::  
@@ -35,7 +38,7 @@ of the operating system kernel.  This means, for example, that all the
 test code from the last assignment ran as part of the kernel, with
 full access to privileged parts of the system.  Once we start running
 user programs on top of the operating system, this is no longer true.
-This project deals with consequences of the change.
+This project deals with the consequences.
 
 We allow more than one process to run at a time.  Each process has one
 thread (multithreaded processes are not supported).  User programs are
@@ -75,9 +78,10 @@ Loads ELF binaries and starts processes.
 
 @item pagedir.c
 @itemx pagedir.h
-A simple manager for 80@var{x}86 page directories and page tables.
+A simple manager for 80@var{x}86 hardware page tables.
 Although you probably won't want to modify this code for this project,
 you may want to call some of its functions.
+@xref{Page Tables}, for more information.
 
 @item syscall.c
 @itemx syscall.h
@@ -91,9 +95,9 @@ else needed by system calls.
 @itemx exception.h
 When a user process performs a privileged or prohibited operation, it
 traps into the kernel as an ``exception'' or ``fault.''@footnote{We
-will treat these terms as synonymous.  There is no standard
-distinction between them, although Intel processor manuals define
-them slightly differently on 80@var{x}86.}  These files handle
+will treat these terms as synonyms.  There is no standard
+distinction between them, although Intel processor manuals make 
+a minor distinction between them on 80@var{x}86.}  These files handle
 exceptions.  Currently all exceptions simply print a message and
 terminate the process.  Some, but not all, solutions to project 2
 require modifying @func{page_fault} in this file.
@@ -102,16 +106,16 @@ require modifying @func{page_fault} in this file.
 @itemx gdt.h
 The 80@var{x}86 is a segmented architecture.  The Global Descriptor
 Table (GDT) is a table that describes the segments in use.  These
-files set up the GDT.  @strong{You should not need to modify these
-files for any of the projects.}  You can read the code if
+files set up the GDT.  You should not need to modify these
+files for any of the projects.  You can read the code if
 you're interested in how the GDT works.
 
 @item tss.c
 @itemx tss.h
 The Task-State Segment (TSS) is used for 80@var{x}86 architectural
 task switching.  Pintos uses the TSS only for switching stacks when a
-user process enters an interrupt handler, as does Linux.  @strong{You
-should not need to modify these files for any of the projects.}
+user process enters an interrupt handler, as does Linux.  You
+should not need to modify these files for any of the projects.
 You can read the code if you're interested in how the TSS
 works.
 @end table
@@ -119,23 +123,30 @@ works.
 @node Using the File System
 @subsection Using the File System
 
-You will need to use some file system code for this project.  First,
-user programs are loaded from the file system.  Second, many of the
+You will need to interface to the file system code for this project,
+because
+user programs are loaded from the file system and many of the
 system calls you must implement deal with the file system.  However,
-the focus of this project is not on the file system code, so we have
-provided a simple file system in the @file{filesys} directory.  You
+the focus of this project is not the file system, so we have
+provided a simple but complete file system in the @file{filesys}
+directory.  You
 will want to look over the @file{filesys.h} and @file{file.h}
 interfaces to understand how to use the file system, and especially
-its many limitations.  @strong{You should not modify the file system
-code for this project.}  Proper use of the file system routines now
+its many limitations.
+
+There is no need to modify the file system code for this project, and so
+we recommend that you do not.  Working on the file system is likely to
+distract you from this project's focus.
+
+Proper use of the file system routines now
 will make life much easier for project 4, when you improve the file
-system implementation.  Until then, you will have to put up with the
+system implementation.  Until then, you will have to tolerate the
 following limitations:
 
 @itemize @bullet
 @item
-No synchronization.  Concurrent accesses will interfere with one
-another.  You should use a global lock to ensure that only one process at a
+No internal synchronization.  Concurrent accesses will interfere with one
+another.  You should use synchronization to ensure that only one process at a
 time is executing file system code.
 
 @item
@@ -168,13 +179,13 @@ One important feature is included:
 Unix-like semantics for @func{filesys_remove} are implemented.
 That is, if a file is open when it is removed, its blocks
 are not deallocated and it may still be accessed by any
-threads that have it open until the last one closes it.  @xref{Removing
+threads that have it open, until the last one closes it.  @xref{Removing
 an Open File}, for more information.
 @end itemize
 
 You need to be able to create simulated disks.  The
 @command{pintos-mkdisk} program provides this functionality.  From the
-@file{userprog/build} directory, execute @code{pintos-mkdisk fs.dsk 2}.
+@file{userprog/build} directory, execute @code{pintos-mkdisk fs.dsk@tie{}2}.
 This command creates a 2 MB simulated disk named @file{fs.dsk}.  Then
 format the disk by passing @option{-f -q} on the kernel's command
 line: @code{pintos -f -q}.  The @option{-f} option causes the disk to be
@@ -195,13 +206,13 @@ commands for copying files out of a VM are similar, but substitute
 Incidentally, these commands work by passing special commands
 @command{put} and @command{get} on the kernel's command line and copying
 to and from a special simulated ``scratch'' disk.  If you're very
-curious, you can look at the @command{pintos} program as well as
+curious, you can look at the @command{pintos} script as well as
 @file{filesys/fsutil.c} to learn the implementation details.
 
 Here's a summary of how to create and format a disk, copy the
 @command{echo} program into the new disk, and then run @command{echo},
 passing argument @code{x}.  (Argument passing won't work until
-you've implemented it.)  It assumes
+you implemented it.)  It assumes
 that you've already built the
 examples in @file{examples} and that the current directory is
 @file{userprog/build}:
@@ -222,9 +233,10 @@ pintos -p ../../examples/echo -a echo -- -f -q run 'echo x'
 
 If you don't want to keep the file system disk around for later use or
 inspection, you can even combine all four steps into a single command.
-The @code{--fs-disk=2} option creates a temporary disk just for the
-duration of the @command{pintos} run.  The Pintos automatic test suite
-makes extensive use of this syntax:
+The @code{--fs-disk=@var{n}} option creates a temporary disk
+approximately @var{n} megabytes in size just for the duration of the
+@command{pintos} run.  The Pintos automatic test suite makes extensive
+use of this syntax:
 
 @example
 pintos --fs-disk=2 -p ../../examples/echo -a echo -- -f -q run 'echo x'
@@ -238,8 +250,7 @@ You can delete a file from the Pintos file system using the @code{rm
 @node How User Programs Work
 @subsection How User Programs Work
 
-Pintos can run normal C programs.  In fact, Pintos can run any program
-you want, as long as it's compiled into the proper file format and uses
+Pintos can run normal C programs, as long as they fit into memory and use
 only the system calls you implement.  Notably, @func{malloc} cannot be
 implemented because none of the system calls required for this project
 allow for memory allocation.  Pintos also can't run programs that use
@@ -249,9 +260,11 @@ processor's floating-point unit when switching threads.
 The @file{src/examples} directory contains a few sample user
 programs.  The @file{Makefile} in this directory
 compiles the provided examples, and you can edit it
-compile your own programs as well.
+compile your own programs as well.  Some of the example programs will
+only work once projects 3 or 4 have been implemented.
 
-Pintos loads @dfn{ELF} executables.  ELF is a file format used by Linux,
+Pintos can load @dfn{ELF} executables with the loader provided for you
+in @file{userprog/process.c}.  ELF is a file format used by Linux,
 Solaris, and many other operating systems for object files,
 shared libraries, and executables.  You can actually use any compiler
 and linker that output 80@var{x}86 ELF executables to produce programs
@@ -259,7 +272,7 @@ for Pintos.  (We've provided compilers and linkers that should do just
 fine.)
 
 You should realize immediately that, until you copy a
-test program to the emulated disk, Pintos will be unable to do
+test program to the simulated disk, Pintos will be unable to do
 useful work.  You won't be able to do
 interesting things until you copy a variety of programs to the disk.
 You might want to create a clean reference disk and copy that
@@ -272,7 +285,7 @@ which may happen occasionally while debugging.
 Virtual memory in Pintos is divided into two regions: user virtual
 memory and kernel virtual memory.  User virtual memory ranges from
 virtual address 0 up to @code{PHYS_BASE}, which is defined in
-@file{threads/mmu.h} and defaults to @t{0xc0000000} (3 GB).  Kernel
+@file{threads/vaddr.h} and defaults to @t{0xc0000000} (3 GB).  Kernel
 virtual memory occupies the rest of the virtual address space, from
 @code{PHYS_BASE} up to 4 GB.
 
@@ -281,14 +294,14 @@ When the kernel switches from one process to another, it
 also switches user virtual address spaces by changing the processor's
 page directory base register (see @func{pagedir_activate} in
 @file{userprog/pagedir.c}).  @struct{thread} contains a pointer to a
-process's page directory.
+process's page table.
 
 Kernel virtual memory is global.  It is always mapped the same way,
 regardless of what user process or kernel thread is running.  In
 Pintos, kernel virtual memory is mapped one-to-one to physical
 memory, starting at @code{PHYS_BASE}.  That is, virtual address
-@code{PHYS_ADDR} accesses physical
-address 0, virtual address @code{PHYS_ADDR} + @t{0x1234} access
+@code{PHYS_BASE} accesses physical
+address 0, virtual address @code{PHYS_BASE} + @t{0x1234} accesses
 physical address @t{0x1234}, and so on up to the size of the machine's
 physical memory.
 
@@ -298,12 +311,8 @@ access kernel virtual memory causes a page fault, handled by
 will be terminated.  Kernel threads can access both kernel virtual
 memory and, if a user process is running, the user virtual memory of
 the running process.  However, even in the kernel, an attempt to
-access memory at a user virtual address that doesn't have a page
-mapped into it will cause a page fault.
-
-You must handle memory fragmentation gracefully, that is, a process that
-needs @var{N} pages of user virtual memory must not require those pages
-to be contiguous in kernel virtual memory.
+access memory at an unmapped user virtual address
+will cause a page fault.
 
 @menu
 * Typical Memory Layout::       
@@ -390,20 +399,20 @@ There are at least two reasonable ways to do this correctly.  The
 first method is to verify
 the validity of a user-provided pointer, then dereference it.  If you
 choose this route, you'll want to look at the functions in
-@file{userprog/pagedir.c} and in @file{threads/mmu.h}.  This is the
+@file{userprog/pagedir.c} and in @file{threads/vaddr.h}.  This is the
 simplest way to handle user memory access.
 
 The second method is to check only that a user
 pointer points below @code{PHYS_BASE}, then dereference it.
 An invalid user pointer will cause a ``page fault'' that you can
 handle by modifying the code for @func{page_fault} in
-@file{userprog/exception.cc}.  This technique is normally faster
+@file{userprog/exception.c}.  This technique is normally faster
 because it takes advantage of the processor's MMU, so it tends to be
 used in real kernels (including Linux).
 
 In either case, you need to make sure not to ``leak'' resources.  For
 example, suppose that your system call has acquired a lock or
-allocated a page of memory.  If you encounter an invalid user pointer
+allocated memory with @func{malloc}.  If you encounter an invalid user pointer
 afterward, you must still be sure to release the lock or free the page
 of memory.  If you choose to verify user pointers before dereferencing
 them, this should be straightforward.  It's more difficult to handle
@@ -413,29 +422,37 @@ Therefore, for those who want to try the latter technique, we'll
 provide a little bit of helpful code:
 
 @verbatim
-/* Tries to copy a byte from user address USRC to kernel address KDST.
-   Returns true if successful, false if USRC is invalid. */
-static inline bool get_user (uint8_t *kdst, const uint8_t *usrc) {
-  int eax;
-  asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
-       : "=m" (*kdst), "=&a" (eax) : "m" (*usrc));
-  return eax != 0;
+/* Reads a byte at user virtual address UADDR.
+   UADDR must be below PHYS_BASE.
+   Returns the byte value if successful, -1 if a segfault
+   occurred. */
+static int
+get_user (const uint8_t *uaddr)
+{
+  int result;
+  asm ("movl $1f, %0; movzbl %1, %0; 1:"
+       : "=&a" (result) : "m" (*uaddr));
+  return result;
 }
-
-/* Tries to write BYTE to user address UDST.
-   Returns true if successful, false if UDST is invalid. */
-static inline bool put_user (uint8_t *udst, uint8_t byte) {
-  int eax;
-  asm ("movl $1f, %%eax; movb %b2, %0; 1:"
-       : "=m" (*udst), "=&a" (eax) : "r" (byte));
-  return eax != 0;
+/* Writes BYTE to user address UDST.
+   UDST must be below PHYS_BASE.
+   Returns true if successful, false if a segfault occurred. */
+static bool
+put_user (uint8_t *udst, uint8_t byte)
+{
+  int error_code;
+  asm ("movl $1f, %0; movb %b2, %1; 1:"
+       : "=&a" (error_code), "=m" (*udst) : "q" (byte));
+  return error_code != -1;
 }
 @end verbatim
 
 Each of these functions assumes that the user address has already been
 verified to be below @code{PHYS_BASE}.  They also assume that you've
-modified @func{page_fault} so that a page fault in the kernel causes
-@code{eax} to be set to 0 and its former value copied into @code{eip}.
+modified @func{page_fault} so that a page fault in the kernel merely
+sets @code{eax} to @t{0xffffffff} and copies its former value
+into @code{eip}.
 
 @node Project 2 Suggested Order of Implementation
 @section Suggested Order of Implementation
@@ -445,7 +462,7 @@ parallel:
 
 @itemize
 @item
-Argument passing (@pxref{Argument Passing}).  Every user programs will
+Argument passing (@pxref{Argument Passing}).  Every user program will
 page fault immediately until argument passing is implemented.
 
 For now, you may simply wish to change
@@ -460,6 +477,11 @@ in @func{setup_stack}.  That will work for any test program that doesn't
 examine its arguments, although its name will be printed as
 @code{(null)}.
 
+Until you implement argument passing, you should only run programs
+without passing command-line arguments.  Attempting to pass arguments to
+a program will include those arguments in the name of the program, which
+will probably fail.
+
 @item
 User memory access (@pxref{Accessing User Memory}).  All system calls
 need to read user memory.  Few system calls need to write to user
@@ -481,6 +503,12 @@ The @code{write} system call for writing to fd 1, the system console.
 All of our test programs write to the console (the user process version
 of @func{printf} is implemented this way), so they will all malfunction
 until @code{write} is available.
+
+@item
+For now, change @func{process_wait} to an infinite loop (one that waits
+forever).  The provided implementation returns immediately, so Pintos
+will power off before any processes actually get to run.  You will
+eventually need to provide a correct implementation.
 @end itemize
 
 After the above are implemented, user processes should work minimally.
@@ -538,13 +566,13 @@ word is the program name, the second word is the first argument, and so
 on.  That is, @code{process_execute("grep foo bar")} should run
 @command{grep} passing two arguments @code{foo} and @code{bar}.
 
-Within a command line, multiple spaces are equivalent to a single space,
-so that @code{process_execute("grep foo bar")} is equivalent to our
-original example.  You can impose a reasonable limit on the length of
-the command line arguments.  For example, you could limit the arguments
-to those that will fit in a single page (4 kB).  (There is an unrelated
-limit of 128 bytes on command-line arguments that the @command{pintos}
-utility can pass to the kernel.)
+Within a command line, multiple spaces are equivalent to a single
+space, so that @code{process_execute("grep @w{ }foo @w{ }@w{ }bar")}
+is equivalent to our original example.  You can impose a reasonable
+limit on the length of the command line arguments.  For example, you
+could limit the arguments to those that will fit in a single page (4
+kB).  (There is an unrelated limit of 128 bytes on command-line
+arguments that the @command{pintos} utility can pass to the kernel.)
 
 You can parse argument strings any way you like.  If you're lost,
 look at @func{strtok_r}, prototyped in @file{lib/string.h} and
@@ -561,11 +589,11 @@ need to set up the stack.
 Implement the system call handler in @file{userprog/syscall.c}.  The
 skeleton implementation we provide ``handles'' system calls by
 terminating the process.  It will need to retrieve the system call
-number, then any system call arguments, and carry appropriate actions.
+number, then any system call arguments, and carry out appropriate actions.
 
 Implement the following system calls.  The prototypes listed are those
 seen by a user program that includes @file{lib/user/syscall.h}.  (This
-header and all other files in @file{lib/user} are for use by user
+header, and all others in @file{lib/user}, are for use by user
 programs only.)  System call numbers for each system call are defined in
 @file{lib/syscall-nr.h}:
 
@@ -588,13 +616,17 @@ Runs the executable whose name is given in @var{cmd_line}, passing any
 given arguments, and returns the new process's program id (pid).  Must
 return pid -1, which otherwise should not be a valid pid, if
 the program cannot load or run for any reason.
+Thus, the parent process cannot return from the @code{exec} until it
+knows whether the child process successfully loaded its executable.
+You must use appropriate synchronization to ensure this.
 @end deftypefn
 
 @deftypefn {System Call} int wait (pid_t @var{pid})
-Waits for process @var{pid} to die and returns the status it passed to
-@code{exit}.  Returns -1 if @var{pid}
-was terminated by the kernel (i.e.@: killed due to an exception).  If
-@var{pid} is invalid or if it was not a child of the
+If process @var{pid} is still alive, waits until it dies.
+Then, returns the status that @var{pid} passed to @code{exit},
+or -1 if @var{pid}
+was terminated by the kernel (e.g.@: killed due to an exception).  If
+@var{pid} does not refer to a child of the
 calling thread, or if @code{wait} has already been successfully
 called for the given @var{pid}, returns -1 immediately, without
 waiting.
@@ -618,40 +650,49 @@ when called from @var{A}, even if @var{B} is dead.
 Consider all the ways a wait can occur: nested waits (@var{A} waits
 for @var{B}, then @var{B} waits for @var{C}), multiple waits (@var{A}
 waits for @var{B}, then @var{A} waits for @var{C}), and so on.
+
+Implementing this system call requires considerably more work than any
+of the rest.
 @end deftypefn
 
 @deftypefn {System Call} bool create (const char *@var{file}, unsigned @var{initial_size})
 Creates a new file called @var{file} initially @var{initial_size} bytes
 in size.  Returns true if successful, false otherwise.
-
-Consider implementing this function in terms of @func{filesys_create}.
+Creating a new file does not open it: opening the new file is a
+separate operation which would require a @code{open} system call.
 @end deftypefn
 
 @deftypefn {System Call} bool remove (const char *@var{file})
 Deletes the file called @var{file}.  Returns true if successful, false
 otherwise.
-
-Consider implementing this function in terms of @func{filesys_remove}.
+A file may be removed regardless of whether it is open or closed, and
+removing an open file does not close it.  @xref{Removing an Open
+File}, for details.
 @end deftypefn
 
 @deftypefn {System Call} int open (const char *@var{file})
 Opens the file called @var{file}.  Returns a nonnegative integer handle
 called a ``file descriptor'' (fd), or -1 if the file could not be
-opened.  All open files associated with a process should be closed
-when the process exits or is terminated.
+opened.  
 
 File descriptors numbered 0 and 1 are reserved for the console: fd 0
-is standard input (@code{stdin}), fd 1 is standard output
-(@code{stdout}).  These special file descriptors are valid as system
-call arguments only as explicitly described below.
-
-Consider implementing this function in terms of @func{filesys_open}.
+(@code{STDIN_FILENO}) is standard input, fd 1 (@code{STDOUT_FILENO}) is
+standard output.  The @code{open} system call will never return either
+of these file descriptors, which are valid as system call arguments only
+as explicitly described below.
+
+Each process has an independent set of file descriptors.  File
+descriptors are not inherited by child processes.
+
+When a single file is opened more than once, whether by a single
+process or different processes, each @code{open} returns a new file
+descriptor.  Different file descriptors for a single file are closed
+independently in separate calls to @code{close} and they do not share
+a file position.
 @end deftypefn
 
 @deftypefn {System Call} int filesize (int @var{fd})
 Returns the size, in bytes, of the file open as @var{fd}.
-
-Consider implementing this function in terms of @func{file_length}.
 @end deftypefn
 
 @deftypefn {System Call} int read (int @var{fd}, void *@var{buffer}, unsigned @var{size})
@@ -659,28 +700,25 @@ Reads @var{size} bytes from the file open as @var{fd} into
 @var{buffer}.  Returns the number of bytes actually read (0 at end of
 file), or -1 if the file could not be read (due to a condition other
 than end of file).  Fd 0 reads from the keyboard using
-@func{kbd_getc}.
-
-Consider implementing this function in terms of @func{file_read}.
+@func{input_getc}.
 @end deftypefn
 
 @deftypefn {System Call} int write (int @var{fd}, const void *@var{buffer}, unsigned @var{size})
 Writes @var{size} bytes from @var{buffer} to the open file @var{fd}.
-Returns the number of bytes actually written, or -1 if the file could
-not be written.
+Returns the number of bytes actually written, which may be less than
+@var{size} if some bytes could not be written.
 
 Writing past end-of-file would normally extend the file, but file growth
 is not implemented by the basic file system.  The expected behavior is
 to write as many bytes as possible up to end-of-file and return the
-actual number written, or -1 if no bytes could be written at all.
+actual number written, or 0 if no bytes could be written at all.
 
 Fd 1 writes to the console.  Your code to write to the console should
 write all of @var{buffer} in one call to @func{putbuf}, at least as
-long as @var{size} is not bigger than a few hundred bytes.  Otherwise,
+long as @var{size} is not bigger than a few hundred bytes.  (It is
+reasonable to break up larger buffers.)  Otherwise,
 lines of text output by different processes may end up interleaved on
 the console, confusing both human readers and our grading scripts.
-
-Consider implementing this function in terms of @func{file_write}.
 @end deftypefn
 
 @deftypefn {System Call} void seek (int @var{fd}, unsigned @var{position})
@@ -695,21 +733,17 @@ have a fixed length until project 4 is complete, so writes past end of
 file will return an error.)  These semantics are implemented in the
 file system and do not require any special effort in system call
 implementation.
-
-Consider implementing this function in terms of @func{file_seek}.
 @end deftypefn
 
 @deftypefn {System Call} unsigned tell (int @var{fd})
 Returns the position of the next byte to be read or written in open
 file @var{fd}, expressed in bytes from the beginning of the file.
-
-Consider implementing this function in terms of @func{file_tell}.
 @end deftypefn
 
 @deftypefn {System Call} void close (int @var{fd})
-Closes file descriptor @var{fd}.
-
-Consider implementing this function in terms of @func{file_close}.
+Closes file descriptor @var{fd}.  
+Exiting or terminating a process implicitly closes all its open file
+descriptors, as if by calling this function for each one.
 @end deftypefn
 
 The file defines other syscalls.  Ignore them for now.  You will
@@ -726,17 +760,16 @@ pointer, a pointer into kernel memory, or a block
 partially in one of those regions?  You should handle these cases by
 terminating the user process.  We recommend
 writing and testing this code before implementing any other system
-call functionality.
+call functionality.  @xref{Accessing User Memory}, for more information.
 
 You must synchronize system calls so that
 any number of user processes can make them at once.  In particular, it
 is not safe to call into the file system code provided in the
-@file{filesys} directory from multiple threads at once.  For now, we
-recommend adding a single lock that controls access to the file system
-code.  You should acquire this lock before calling any functions in
-the @file{filesys} directory, and release it afterward.  Don't forget
-that @func{process_execute} also accesses files.  @strong{For now, we
-recommend against modifying code in the @file{filesys} directory.}
+@file{filesys} directory from multiple threads at once.  Your system
+call implementation must treat the file system code as a critical
+section.  Don't forget
+that @func{process_execute} also accesses files.  For now, we
+recommend against modifying code in the @file{filesys} directory.
 
 We have provided you a user-level function for each system call in
 @file{lib/user/syscall.c}.  These provide a way for user processes to
@@ -770,7 +803,8 @@ hurt even now.
 You can use @func{file_deny_write} to prevent writes to an open file.
 Calling @func{file_allow_write} on the file will re-enable them (unless
 the file is denied writes by another opener).  Closing a file will also
-re-enable writes.
+re-enable writes.  Thus, to deny writes to a process's executable, you
+must keep it open as long as the process is still running.
 
 @node Project 2 FAQ
 @section FAQ
@@ -782,6 +816,12 @@ Here's a summary of our reference solution, produced by the
 @command{diffstat} program.  The final row gives total lines inserted
 and deleted; a changed line counts as both an insertion and a deletion.
 
+The reference solution represents just one possible solution.  Many
+other solutions are also possible and many of those differ greatly from
+the reference solution.  Some excellent solutions may not modify all the
+files modified by the reference solution, and some may modify files not
+modified by the reference solution.
+
 @verbatim
  threads/thread.c     |   13 
  threads/thread.h     |   26 +
@@ -832,16 +872,17 @@ call handler just prints @samp{system call!} and terminates the program.
 Until then, you can use @func{hex_dump} to convince yourself that
 argument passing is implemented correctly (@pxref{Program Startup Details}).
 
-@item How can I can disassemble user programs?
+@item How can I disassemble user programs?
 
 The @command{objdump} (80@var{x}86) or @command{i386-elf-objdump}
 (SPARC) utility can disassemble entire user
 programs or object files.  Invoke it as @code{objdump -d
-@var{file}}.  You can use @code{gdb}'s
-@command{disassemble} command to disassemble individual functions
-(@pxref{gdb}).
+@var{file}}.  You can use GDB's
+@code{disassemble} command to disassemble individual functions
+(@pxref{GDB}).
 
 @item Why do many C include files not work in Pintos programs?
+@itemx Can I use lib@var{foo} in my Pintos programs?
 
 The C library we provide is very limited.  It does not include many of
 the features that are expected of a real operating system's C library.
@@ -850,9 +891,7 @@ architecture), since it must make system calls for I/O and memory
 allocation.  (Not all functions do, of course, but usually the library
 is compiled as a unit.)
 
-@item Can I use lib@var{foo} in my Pintos programs?
-
-The chances are good that lib@var{foo} uses parts of the C library
+The chances are good that the library you want uses parts of the C library
 that Pintos doesn't implement.  It will probably take at least some
 porting effort to make it work under Pintos.  Notably, the Pintos
 user program C library does not have a @func{malloc} implementation.
@@ -880,11 +919,6 @@ You can choose whatever suitable types you like for @code{tid_t} and
 @code{pid_t}.  By default, they're both @code{int}.  You can make them
 a one-to-one mapping, so that the same values in both identify the
 same process, or you can use a more complex mapping.  It's up to you.
-
-@item Keyboard input doesn't work with @command{pintos} option @option{-v}.
-
-Serial input isn't implemented.  Don't use @option{-v} if you
-want to use the shell or otherwise need keyboard input.
 @end table
 
 @menu
@@ -896,12 +930,12 @@ want to use the shell or otherwise need keyboard input.
 @subsection Argument Passing FAQ
 
 @table @asis
-@item Isn't the top of stack off the top of user virtual memory?
+@item Isn't the top of stack in kernel virtual memory?
 
 The top of stack is at @code{PHYS_BASE}, typically @t{0xc0000000}, which
 is also where kernel virtual memory starts.
-But when the processor pushes data on the stack, it decrements the stack
-pointer first.  Thus, the first (4-byte) value pushed on the stack
+But before the processor pushes data on the stack, it decrements the stack
+pointer.  Thus, the first (4-byte) value pushed on the stack
 will be at address @t{0xbffffffc}.
 
 @item Is @code{PHYS_BASE} fixed?
@@ -945,6 +979,18 @@ or the machine shuts down.
 You may modify the stack setup code to allocate more than one page of
 stack space for each process.  In the next project, you will implement a
 better solution.
+
+@item What should happen if an @code{exec} fails midway through loading?
+
+@code{exec} should return -1 if the child process fails to load for
+any reason.  This includes the case where the load fails part of the
+way through the process (e.g.@: where it runs out of memory in the
+@code{multi-oom} test).  Therefore, the parent process cannot return
+from the @code{exec} system call until it is established whether the
+load was successful or not.  The child must communicate this
+information to its parent using appropriate synchronization, such as a
+semaphore (@pxref{Semaphores}), to ensure that the information is
+communicated without race conditions.
 @end table
 
 @node 80x86 Calling Convention
@@ -953,9 +999,9 @@ better solution.
 This section summarizes important points of the convention used for
 normal function calls on 32-bit 80@var{x}86 implementations of Unix.
 Some details are omitted for brevity.  If you do want all the details,
-you can refer to @bibref{SysV-i386}.
+refer to @bibref{SysV-i386}.
 
-The basic calling convention works like this:
+The calling convention works like this:
 
 @enumerate 1
 @item
@@ -963,6 +1009,10 @@ The caller pushes each of the function's arguments on the stack one by
 one, normally using the @code{PUSH} assembly language instruction.
 Arguments are pushed in right-to-left order.
 
+The stack grows downward: each push decrements the stack pointer, then
+stores into the location it now points to, like the C expression
+@samp{*--sp = @var{value}}.
+
 @item
 The caller pushes the address of its next instruction (the @dfn{return
 address}) on the stack and jumps to the first instruction of the callee.
@@ -988,7 +1038,7 @@ The caller pops the arguments off the stack.
 Consider a function @func{f} that takes three @code{int} arguments.
 This diagram shows a sample stack frame as seen by the callee at the
 beginning of step 3 above, supposing that @func{f} is invoked as
-@code{f(1, 2, 3)}.  The stack addresses are arbitrary:
+@code{f(1, 2, 3)}.  The initial stack address is arbitrary:
 
 @html
 <CENTER>
@@ -996,11 +1046,8 @@ beginning of step 3 above, supposing that @func{f} is invoked as
 @example
                              +----------------+
                   0xbffffe7c |        3       |
-                             +----------------+
                   0xbffffe78 |        2       |
-                             +----------------+
                   0xbffffe74 |        1       |
-                             +----------------+
 stack pointer --> 0xbffffe70 | return address |
                              +----------------+
 @end example
@@ -1029,30 +1076,32 @@ _start (int argc, char *argv[])
 @}
 @end example
 
-The kernel is responsible for setting up the arguments for the initial
-function on the stack, in accordance with the calling convention
-explained in the preceding section, before it allows the user program to
-begin executing.
+The kernel must put the arguments for the initial function on the stack
+before it allows the user program to begin executing.  The arguments are
+passed in the same way as the normal calling convention (@pxref{80x86
+Calling Convention}).
 
-Consider the following example command: @samp{/bin/ls -l foo bar}.
-First, the kernel must break the command into words, as @samp{/bin/ls},
-@samp{-l}, @samp{foo}, and @samp{bar}, and place them at the top of the
+Consider how to handle arguments for the following example command:
+@samp{/bin/ls -l foo bar}.
+First, break the command into words: @samp{/bin/ls},
+@samp{-l}, @samp{foo}, @samp{bar}.  Place the words at the top of the
 stack.  Order doesn't matter, because they will be referenced through
 pointers.
 
 Then, push the address of each string plus a null pointer sentinel, on
 the stack, in right-to-left order.  These are the elements of
-@code{argv}.  The order ensure that @code{argv[0]} is at the lowest
-virtual address.  Word-aligned accesses are faster than unaligned
-accesses, so for best performance round the stack pointer down to a
-multiple of 4 before the first push.
+@code{argv}.  The null pointer sentinel ensures that @code{argv[argc]}
+is a null pointer, as required by the C standard.  The order ensures
+that @code{argv[0]} is at the lowest virtual address.  Word-aligned
+accesses are faster than unaligned accesses, so for best performance
+round the stack pointer down to a multiple of 4 before the first push.
 
 Then, push @code{argv} (the address of @code{argv[0]}) and @code{argc},
 in that order.  Finally, push a fake ``return address'': although the
 entry function will never return, its stack frame must have the same
 structure as any other.
 
-The table below show the state of the stack and the relevant registers
+The table below shows the state of the stack and the relevant registers
 right before the beginning of the user program, assuming
 @code{PHYS_BASE} is @t{0xc0000000}:
 
@@ -1084,7 +1133,7 @@ In this example, the stack pointer would be initialized to
 
 As shown above, your code should start the stack at the very top of
 the user virtual address space, in the page just below virtual address
-@code{PHYS_BASE} (defined in @file{threads/mmu.h}).
+@code{PHYS_BASE} (defined in @file{threads/vaddr.h}).
 
 You may find the non-standard @func{hex_dump} function, declared in
 @file{<stdio.h>}, useful for debugging your argument passing code.
@@ -1117,7 +1166,7 @@ is handled in the same way as other software exceptions.  In Pintos,
 user programs invoke @samp{int $0x30} to make a system call.  The
 system call number and any additional arguments are expected to be
 pushed on the stack in the normal fashion before invoking the
-interrupt.
+interrupt (@pxref{80x86 Calling Convention}).
 
 Thus, when the system call handler @func{syscall_handler} gets control,
 the system call number is in the 32-bit word at the caller's stack