Clarifications.
[pintos-anon] / doc / userprog.texi
index 031efdfa08c72457813a92ffa1a6a3b0234c6aba..0746b2e68f791af7545793a3458bd5d6ed4851a3 100644 (file)
@@ -151,6 +151,19 @@ you're very curious, you can look at the @command{pintos} program as
 well as @file{filesys/fsutil.c} to learn the implementation details,
 but it's really not relevant for this project.
 
+Here's a summary of how you would create and format a disk, copy the
+@command{echo} program into the new disk, and then run @command{echo}.
+It assumes that you've already built the tests in
+@file{tests/userprog} and that the current directory is
+@file{userprog/build}:
+
+@example
+pintos make-disk fs.dsk 2
+pintos run -f
+pintos put ../../tests/userprog/echo echo
+pintos run -ex echo
+@end example
+
 You can delete a file from the Pintos file system using the @option{-r
 @var{file}} kernel option, e.g.@: @code{pintos run -r @var{file}}.
 Also, @option{-ls} lists the files in the file system and @option{-p
@@ -178,14 +191,13 @@ directory.  By default, the @file{Makefile} in this directory will
 compile the test programs we provide.  You can edit the
 @file{Makefile} to compile your own test programs as well.
 
-One thing you should realize immediately is that, until you use the
-above operation to copy a test program to the emulated disk, Pintos
-will be unable to do very much useful work.  You will also find that
-you won't be able to do interesting things until you copy a variety of
-programs to the disk.  A useful technique is to create a clean
-reference disk and copy that over whenever you trash your
-@file{fs.dsk} beyond a useful state, which may happen occasionally
-while debugging.
+One thing you should realize immediately is that, until you copy a
+test program to the emulated disk, Pintos will be unable to do very
+much useful work.  You will also find that you won't be able to do
+interesting things until you copy a variety of programs to the disk.
+A useful technique is to create a clean reference disk and copy that
+over whenever you trash your @file{fs.dsk} beyond a useful state,
+which may happen occasionally while debugging.
 
 @node Virtual Memory Layout
 @section Virtual Memory Layout
@@ -202,7 +214,8 @@ free to use the entire space of user virtual memory however it
 chooses.  When the kernel switches from one process to another, it
 also switches user virtual address spaces by switching the processor's
 page directory base register (see @func{pagedir_activate in
-@file{userprog/pagedir.c}}.
+@file{userprog/pagedir.c}}.  @struct{thread} contains a pointer to a
+process's page directory.
 
 Kernel virtual memory is global.  It is always mapped the same way,
 regardless of what user process or kernel thread is running.  In
@@ -221,19 +234,45 @@ 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 memory must not require that all @var{N}
+be contiguous.  In fact, it must not require that any of the pages be
+contiguous.
+
 @node Global Requirements
 @section Global Requirements
 
-For testing and grading purposes, we have some simple requirements for
-your output:
+For testing and grading purposes, we have some simple overall
+requirements:
 
 @itemize @bullet
 @item
-The kernel should print out the program's name and exit status
-whenever a process exits, e.g.@: @code{shell: exit(-1)}.  The name
-printed should be the full name passed to @func{process_execute},
-except that it is acceptable to truncate it to 15 characters to allow
-for the limited space in @struct{thread}.
+The kernel should print out the program's name and exit status whenever
+a process terminates, whether termination is caused by the @code{exit}
+system call or for another reason.
+
+@itemize @minus
+@item
+The message must be formatted exactly as if it was printed with
+@code{printf ("%s: exit(%d)\n", @dots{});} given appropriate arguments.
+
+@item
+The name printed should be the full name passed to
+@func{process_execute}, except that it is acceptable to truncate it to
+15 characters to allow for the limited space in @struct{thread}.  The
+name printed need not include arguments.
+
+@item
+Do not print a message when a kernel thread that is not a process
+terminates.
+
+@item
+Do not print messages about process termination for the @code{halt}
+system call.
+
+@item
+No message need be printed when a process fails to load.
+@end itemize
 
 @item
 Aside from this, the kernel should print out no other messages that
@@ -261,7 +300,7 @@ extending @func{process_execute} so that instead of simply taking a
 program file name as its argument, it divides it into words at spaces.
 The first 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 @program{grep} passing two arguments @code{foo} and
+should run @command{grep} passing two arguments @code{foo} and
 @file{bar}.  A few details:
 
 @itemize
@@ -323,10 +362,11 @@ a successful exit.  Other values may be used to indicate user-defined
 conditions (usually errors).
 
 @item SYS_exec
-@itemx pid_t exec (const char *@var{file})
-Run the executable in @var{file} and return the new process's program
-id (pid).  If there is an error loading this program, returns pid -1,
-which otherwise should not be a valid id number.
+@itemx pid_t exec (const char *@var{cmd_line})
+Runs the executable whose name is given in @var{cmd_line}, passing any
+given arguments, and returns the new process's program id (pid).  If
+there is an error loading this program, may return pid -1, which
+otherwise should not be a valid id number.
 
 @item SYS_join
 @itemx int join (pid_t @var{pid})
@@ -340,11 +380,12 @@ be disrupted).
 @item SYS_create
 @itemx bool create (const char *@var{file}, unsigned @var{initial_size})
 Create a new file called @var{file} initially @var{initial_size} bytes
-in size.  Returns -1 if failed, 0 if OK.
+in size.  Returns true if successful, false otherwise.
 
 @item SYS_remove
 @itemx bool remove (const char *@var{file})
-Delete the file called @var{file}.  Returns -1 if failed, 0 if OK.
+Delete the file called @var{file}.  Returns true if successful, false
+otherwise.
 
 @item SYS_open
 @itemx int open (const char *@var{file})
@@ -365,8 +406,9 @@ Returns the size, in bytes, of the file open as @var{fd}.
 @item SYS_read
 @itemx int read (int @var{fd}, void *@var{buffer}, unsigned @var{size})
 Read @var{size} bytes from the file open as @var{fd} into
-@var{buffer}.  Returns the number of bytes actually read, or -1 if the
-file could not be read.  Fd 0 reads from the keyboard using
+@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}.
 
 @item SYS_write
@@ -381,6 +423,14 @@ Changes the next byte to be read or written in open file @var{fd} to
 @var{position}, expressed in bytes from the beginning of the file.
 (Thus, a @var{position} of 0 is the file's start.)
 
+A seek past the current end of a file is not an error.  A later read
+obtains 0 bytes, indicating end of file.  A later write extends the
+file, filling any unwritten gap with zeros.  (However, in Pintos files
+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.
+
 @item SYS_tell
 @itemx unsigned tell (int @var{fd})
 Returns the position of the next byte to be read or written in open
@@ -416,7 +466,7 @@ 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.}
 
-We have provided you a function for each system call in
+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
 invoke each system call from a C program.  Each of them calls an
 assembly language routine in @file{lib/user/syscall-stub.S}, which in
@@ -476,6 +526,15 @@ isn't properly set up yet, this causes a page fault.
 @b{I implemented 2-1 and now all my user programs die with
 @samp{system call!}.}
 
+Every reasonable program tries to make at least one system call
+(@func{exit}) and most programs make more than that.  Notably,
+@func{printf} invokes the @code{write} system call.  The default
+system call handler just prints @samp{system call!} and terminates the
+program.  You'll have to implement 2-2 before you see anything more
+interesting.  Until then, you can use @func{hex_dump} to convince
+yourself that 2-1 is implemented correctly (@pxref{Argument Passing to
+main}).
+
 @item
 @b{Is there a way I can disassemble user programs?}
 
@@ -611,10 +670,10 @@ Each character is 1 byte.
 @end itemize
 
 @item
-@b{Why doesn't keyboard input work with @option{-v}?}
+@b{Why doesn't keyboard input work with @samp{pintos -v}?}
 
-Serial input isn't implemented.  Don't use @option{-v} if you want to
-use the shell or otherwise type at the keyboard.
+Serial input isn't implemented.  Don't use @samp{pintos -v} if you
+want to use the shell or otherwise provide keyboard input.
 @end enumerate
 
 @menu
@@ -780,7 +839,7 @@ After we push all of the strings onto the stack, we adjust the stack
 pointer so that it is word-aligned: that is, we move it down to the
 next 4-byte boundary.  This is required because we will next be
 placing several words of data on the stack, and they must be aligned
-in order to be read correctly.  In our example, as you'll see below,
+to be read correctly.  In our example, as you'll see below,
 the strings start at address @t{0xffed}.  One word below that would be
 at @t{0xffe9}, so we could in theory put the next word on the stack
 there.  However, since the stack pointer should always be
@@ -912,3 +971,9 @@ In this example, the caller's stack pointer would be at
 The 80@var{x}86 convention for function return values is to place them
 in the @samp{EAX} register.  System calls that return a value can do
 so by modifying the @samp{eax} member of @struct{intr_frame}.
+
+You should try to avoid writing large amounts of repetitive code for
+implementing system calls.  Each system call argument, whether an
+integer or a pointer, takes up 4 bytes on the stack.  You should be able
+to take advantage of this to avoid writing much near-identical code for
+retrieving each system call's arguments from the stack.