fixed typo.
[pintos-anon] / doc / userprog.texi
index bab70ec7c178094f1e1ef581b8dc18648c761acc..ff98074f8de198ea6465271848f573e7d5c73d7d 100644 (file)
@@ -16,11 +16,18 @@ 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
-assignment.  The ``alarm clock'' functionality may be useful in later
-projects, but it is not strictly required.
+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::    
@@ -36,11 +43,12 @@ 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.
 
-We allow more than one user program to run at a time.  User
-programs are written and compiled to work under the illusion that they
-have the entire machine.  This means that when you load and
-run multiple processes at a time, you must manage memory, scheduling,
-and other state correctly to maintain this illusion.
+We allow more than one process to run at a time.  Each process has one
+thread (multithreaded processes are not supported).  User programs are
+written under the illusion that they have the entire machine.  This
+means that when you load and run multiple processes at a time, you must
+manage memory, scheduling, and other state correctly to maintain this
+illusion.
 
 In the previous project, we compiled our test code directly into your
 kernel, so we had to require certain specific function interfaces within
@@ -220,9 +228,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'
@@ -249,7 +258,8 @@ programs.  The @file{Makefile} in this directory
 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
@@ -285,8 +295,8 @@ 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} access
 physical address @t{0x1234}, and so on up to the size of the machine's
 physical memory.
 
@@ -415,7 +425,7 @@ provide a little bit of helpful code:
    Returns true if successful, false if USRC is invalid. */
 static inline bool get_user (uint8_t *kdst, const uint8_t *usrc) {
   int eax;
-  asm ("mov %%eax, offset 1f; mov %%al, %2; mov %0, %%al; 1:"
+  asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
        : "=m" (*kdst), "=&a" (eax) : "m" (*usrc));
   return eax != 0;
 }
@@ -424,7 +434,7 @@ static inline bool get_user (uint8_t *kdst, const uint8_t *usrc) {
    Returns true if successful, false if UDST is invalid. */
 static inline bool put_user (uint8_t *udst, uint8_t byte) {
   int eax;
-  asm ("mov %%eax, offset 1f; mov %0, %b2; 1:"
+  asm ("movl $1f, %%eax; movb %b2, %0; 1:"
        : "=m" (*udst), "=&a" (eax) : "r" (byte));
   return eax != 0;
 }
@@ -435,6 +445,68 @@ 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}.
 
+@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
 
@@ -489,7 +561,9 @@ 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).
+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
@@ -509,15 +583,15 @@ terminating the process.  It will need to retrieve the system call
 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})
@@ -538,8 +612,8 @@ the program cannot load or run for any reason.
 @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.
@@ -568,11 +642,15 @@ waits for @var{B}, then @var{A} waits for @var{C}), and so on.
 @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}.
 @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}.
 @end deftypefn
 
 @deftypefn {System Call} int open (const char *@var{file})
@@ -585,10 +663,14 @@ 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}.
 @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})
@@ -596,7 +678,10 @@ 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}.
+@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
 
 @deftypefn {System Call} int write (int @var{fd}, const void *@var{buffer}, unsigned @var{size})
@@ -604,11 +689,19 @@ 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.
 
+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.
+
 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})
@@ -623,30 +716,36 @@ 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}.
 @end deftypefn
 
 The file defines other syscalls.  Ignore them for now.  You will
 implement some of them in project 3 and the rest in project 4, so be
 sure to design your system with extensibility in mind.
 
-To implement syscalls, you need to provide ways to copy data
-from user virtual address space into the kernel and vice versa.
+To implement syscalls, you need to provide ways to read and write data
+in user virtual address space.
 You need this ability before you can
 even obtain the system call number, because the system call number is
 on the user's stack in the user's virtual address space.
 This can be a bit tricky: what if the user provides an invalid
 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
+terminating the user process.  We recommend
 writing and testing this code before implementing any other system
 call functionality.
 
@@ -692,7 +791,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 process's executable, you
+must keep it open as long as the process is still running.
 
 @node Project 2 FAQ
 @section FAQ
@@ -704,6 +804,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 +
@@ -783,6 +889,10 @@ user program C library does not have a @func{malloc} implementation.
 
 Modify @file{src/examples/Makefile}, then run @command{make}.
 
+@item Can I run user programs under a debugger?
+
+Yes, with some limitations.  @xref{Debugging User Programs}.
+
 @item What's the difference between @code{tid_t} and @code{pid_t}?
 
 A @code{tid_t} identifies a kernel thread, which may have a user
@@ -1041,8 +1151,9 @@ 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
 pointer, the first argument is in the 32-bit word at the next higher
 address, and so on.  The caller's stack pointer is accessible to
-@func{syscall_handler} as the @samp{esp} member of the @code{struct
-intr_frame} passed to it.
+@func{syscall_handler} as the @samp{esp} member of the
+@struct{intr_frame} passed to it.  (@struct{intr_frame} is on the kernel
+stack.)
 
 The 80@var{x}86 convention for function return values is to place them
 in the @code{EAX} register.  System calls that return a value can do