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}). In particular, the tests for project 2 and later
+projects will probably run faster if you use the qemu emulator, e.g.@:
+via @code{make check PINTOSOPTS='--qemu'}. The qemu emulator is
+available only on the Linux machines.
+
@menu
* Project 2 Background::
+* Project 2 Suggested Order of Implementation::
* Project 2 Requirements::
* Project 2 FAQ::
* 80x86 Calling Convention::
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'
compiles the provided examples, and you can edit it
compile your own programs as well.
-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
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} access
physical address @t{0x1234}, and so on up to the size of the machine's
physical memory.
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 0 and copies its former value into @code{eip}.
+
+@node Project 2 Suggested Order of Implementation
+@section Suggested Order of Implementation
+
+We suggest first implementing the following, which can happen in
+parallel:
+
+@itemize
+@item
+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
+@example
+*esp = PHYS_BASE;
+@end example
+@noindent to
+@example
+*esp = PHYS_BASE - 12;
+@end example
+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
+memory.
+
+@item
+System call infrastructure (@pxref{System Calls}). Implement enough
+code to read the system call number from the user stack and dispatch to
+a handler based on it.
+
+@item
+The @code{exit} system call. Every user program that finishes in the
+normal way calls @code{exit}. Even a program that returns from
+@func{main} calls @code{exit} indirectly (see @func{_start} in
+@file{lib/user/entry.c}).
+
+@item
+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.
+At the very least, they can write to the console and exit correctly.
+You can then refine your implementation so that some of the tests start
+to pass.
@node Project 2 Requirements
@section Requirements
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).
+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
number, then any system call arguments, and carry appropriate actions.
Implement the following system calls. The prototypes listed are those
-seen by a user program that includes @file{lib/user/syscall.h}. System
-call numbers for each system call are defined in
+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
+programs only.) System call numbers for each system call are defined in
@file{lib/syscall-nr.h}:
@deftypefn {System Call} void halt (void)
Terminates Pintos by calling @func{power_off} (declared in
-@file{threads/init.h}). Note that this should be seldom used, since
-then you lose some information about possible deadlock situations,
-etc.
+@file{threads/init.h}). This should be seldom used, because you lose
+some information about possible deadlock situations, etc.
@end deftypefn
@deftypefn {System Call} void exit (int @var{status})
@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
+was terminated by the kernel (e.g.@: killed due to an exception). If
+@var{pid} is 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.
@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.
+(@code{stdout}). 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.
Consider implementing this function in terms of @func{filesys_open}.
@end deftypefn
@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}.
+@func{kbd_getc}. (Keyboard input will not work if you pass the
+@option{-v} option to @command{pintos}.)
Consider implementing this function in terms of @func{file_read}.
@end deftypefn
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.
@end deftypefn
@deftypefn {System Call} void close (int @var{fd})
-Closes file descriptor @var{fd}.
+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.
Consider implementing this function in terms of @func{file_close}.
@end deftypefn
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 process's executable, you
+must keep it open as long as the process is still running.
@node Project 2 FAQ
@section FAQ
@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 +