relevant parts below. If you are confident in your HW1 code, you can
build on top of it. However, if you wish you can start with a fresh
copy of the code and re-implement @code{thread_join()}, which is the
-only part of project #1 required for this assignment.
+only part of project #1 required for this assignment. Your submission
+should define @code{THREAD_JOIN_IMPLEMENTED} in @file{constants.h}
+(@pxref{Conditional Compilation}).
Up to now, all of the code you have written for Pintos has been part
of the operating system kernel. This means, for example, that all the
* Project 2 Code::
* Using the File System::
* How User Programs Work::
+* Virtual Memory Layout::
* Global Requirements::
* Problem 2-1 Argument Passing::
* Problem 2-2 System Calls::
where the bulk of your work will be:
@table @file
-@item addrspace.c
-@itemx addrspace.h
-An address space keeps track of all the data necessary to execute a
-user program. Address space data is stored in @code{struct thread},
-but manipulated only by @file{addrspace.c}. Address spaces need to
-keep track of things like paging information for the process (so that
-it knows which memory the process is using). Address spaces also
-handle loading the program into memory and starting up the process's
-execution.
+@item process.c
+@itemx process.h
+Loads ELF binaries and starts processes.
@item pagedir.c
@itemx pagedir.h
can't run programs using floating point operations, since it doesn't
include the necessary kernel functionality to save and restore the
processor's floating-point unit when switching threads. You can look
-in @file{test} directory for some examples.
+in @file{tests/userprog} directory for some examples.
Pintos loads ELF executables, where ELF is an executable format used
by Linux, Solaris, and many other Unix and Unix-like systems.
Therefore, you can use any compiler and linker that produce
80@var{x}86 ELF executables to produce programs for Pintos. We
-recommend using the tools we provide in the @file{tests} 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.
+recommend using the tools we provide in the @file{tests/userprog}
+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
@code{page_fault()} in @file{userprog/exception.c}, and the process
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, an attempt to access memory at a user
-virtual address that doesn't have a page mapped into it will also
-cause a page fault.
+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.
@node Global Requirements
@section Global Requirements
@node Problem 2-1 Argument Passing
@section Problem 2-1: Argument Passing
-Currently, @code{thread_execute()} does not support passing arguments
+Currently, @code{process_execute()} does not support passing arguments
to new processes. UNIX and other operating systems do allow passing
command line arguments to a program, which accesses them via the argc,
argv arguments to main. You must implement this functionality by
-extending @code{thread_execute()} so that instead of simply taking a
+extending @code{process_execute()} so that instead of simply taking a
program file name, it can take a program name with arguments as a
-single string. That is, @code{thread_execute("grep foo *.c")} should
+single string. That is, @code{process_execute("grep foo *.c")} should
be a legal call. @xref{80x86 Calling Convention}, for information on
exactly how this works.
recommend adding a single lock that controls access to the filesystem
code. You should acquire this lock before calling any functions in
the @file{filesys} directory, and release it afterward. Don't forget
-that @file{addrspace_load()} also accesses files. @strong{For now, we
+that @file{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
@node User Programs FAQ
@section FAQ
-@enumerate 1
-@item General FAQs
-
@enumerate 1
@item
@b{Do we need a working project 1 to implement project 2?}
@b{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
-process running in it (if created with @code{thread_execute()}) or not
+process running in it (if created with @code{process_execute()}) or not
(if created with @code{thread_create()}). It is a data type used only
in the kernel.
@b{I can't seem to figure out how to read from and write to user
memory. What should I do?}
-The kernel must treat user memory delicately. The user can pass a
-null pointer or an invalid pointer (one that doesn't point to any
-memory at all), or a kernel pointer (above @code{PHYS_BASE}). All of
-these must be rejected without harm to the kernel or other running
-processes.
+The kernel must treat user memory delicately. As part of a system
+call, the user can pass to the kernel a null pointer, a pointer to
+unmapped virtual memory, or a pointer to kernel virtual address space
+(above @code{PHYS_BASE}). All of these types of invalid pointers must
+be rejected without harm to the kernel or other running processes. At
+your option, the kernel may handle invalid pointers by terminating the
+process or returning from the system call with an error.
+
+There are at least two reasonable ways to do this correctly. The
+first method is to ``verify then access'':@footnote{These terms are
+made up for this document. They are not standard terminology.} 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
+simplest way to handle user memory access.
+
+The second method is to ``assume and react'': directly dereference
+user pointers, after checking that they point below @code{PHYS_BASE}.
+Invalid user pointers will then cause a ``page fault'' that you can
+handle by modifying the code for @code{page_fault()} in
+@file{userprog/exception.cc}. 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
+afterward, you must still be sure to release the lock or free the page
+of memory. If you choose to ``verify then access,'' then this should
+be straightforward, but for ``assume and react'' it's more difficult,
+because there's no way to return an error code from a memory access.
+Therefore, for those who want to try the latter technique, we'll
+provide a little bit of helpful code:
+
+@example
+/* Tries to copy a byte from user address USRC to kernel address DST.
+ Returns true if successful, false if USRC is invalid. */
+static inline bool get_user (uint8_t *dst, const uint8_t *usrc) @{
+ int eax;
+ asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
+ : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
+ return eax != 0;
+@}
+
+/* Tries 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;
+@}
+@end example
-There are at least two reasonable ways to access user memory. First,
-you can translate user addresses (below @code{PHYS_BASE}) into kernel
-addresses (above @code{PHYS_BASE}) using the functions in
-@file{pagedir.c}, and then access kernel memory. Second, you can
-dereference user pointers directly and handle page faults by
-terminating the process. In either case, you'll need to reject kernel
-pointers as a special case.
+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 @code{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}.
@item
@b{I'm also confused about reading from and writing to the stack. Can
@item
Each character is 1 byte.
@end itemize
+
+@item
+@b{Why doesn't keyboard input work with @option{-v}?}
+
+Serial input isn't implemented. Don't use @option{-v} if you want to
+use the shell or otherwise type at the keyboard.
@end enumerate
-@item Argument Passing FAQs
+@menu
+* Problem 2-1 Argument Passing FAQ::
+* Problem 2-2 System Calls FAQ::
+@end menu
+
+@node Problem 2-1 Argument Passing FAQ
+@subsection Problem 2-1: Argument Passing FAQ
@enumerate 1
@item
simply via recompilation.
@end enumerate
-@item System Calls FAQs
+@node Problem 2-2 System Calls FAQ
+@subsection Problem 2-2: System Calls FAQ
@enumerate 1
@item
limit of 128 open files per process (as the Solaris machines here do).
@item
+@anchor{Removing an Open File}
@b{What happens when two (or more) processes have a file open and one of
them removes it?}
@code{SYS_exec} call) followed by the exit status code,
e.g.@: @samp{example 1 2 3 4: 0}.
@end enumerate
-@end enumerate
@node 80x86 Calling Convention
@section 80@var{x}86 Calling Convention
have seen even more of it. I've omitted some of the complexity, since
this isn't a class in how function calls work, so don't expect this to
be exactly correct in full, gory detail. If you do want all the
-details, you can refer to @cite{[SysV-i386]}.
+details, you can refer to @bibref{SysV-i386}.
Whenever a function call happens, you need to put the arguments on the
call stack for that function, before the code for that function