process. Whenever the processor needed to look up a translation, it
consulted the page table. As long as the process only accessed
memory that it didn't own, all was well. If the process accessed
-memory it didn't own, it ``page faulted'' and @code{page_fault()}
+memory it didn't own, it ``page faulted'' and @func{page_fault}
terminated the process.
When we implement virtual memory, the rules have to change. A page
@end enumerate
@example
+@group
32 22 12 0
+--------------------------------------------------------------------+
| Page Directory Index | Page Table Index | Page Offset |
1|____________| | 1|____________| | |____________|
0|____________| \__\0|____________| \____\|____________|
/ /
+@end group
@end example
Header @file{threads/mmu.h} has useful functions for various
idea.
@end itemize
-The page fault handler, @code{page_fault()} in
+The page fault handler, @func{page_fault} in
@file{threads/exception.c}, needs to do roughly the following:
@enumerate 1
use your new page table management code to construct the page tables
only as page faults occur for them.
+You should use the @func{palloc_get_page} function to get the page
+frames that you use for storing user virtual pages. Be sure to pass
+the @code{PAL_USER} flag to this function when you do so, because that
+allocates pages from a ``user pool'' separate from the ``kernel pool''
+that other calls to @func{palloc_get_page} make.
+
There are many possible ways to implement virtual memory. The above
is simply an outline of our suggested implementation.
segments won't change.
There are a few special cases. Look at the loop in
-@code{load_segment()} in @file{userprog/process.c}. Each time
+@func{load_segment} in @file{userprog/process.c}. Each time
around the loop, @code{read_bytes} represents the number of bytes to
read from the executable file and @code{zero_bytes} represents the number
of bytes to initialize to zero following the bytes read. The two
to be compatible with the prototypes for @code{hash_hash_func} and
@code{hash_less_func} in @file{lib/kernel/hash.h}.
-Here's a quick example. Suppose you want to put @code{struct thread}s
+Here's a quick example. Suppose you want to put @struct{thread}s
in a hash table. First, add a @code{hash_elem} to the thread
structure by adding a line to its definition:
hash_elem h_elem; /* Hash table element. */
@end example
-We'll choose the @code{tid} member in @code{struct thread} as the key,
+We'll choose the @code{tid} member in @struct{thread} as the key,
and write a hash function and a comparison function:
@example
/* Returns true if A's tid is less than B's tid. */
bool
-thread_less (const hash_elem *a_, const hash_elem *b_, void *aux UNUSED)
+thread_less (const hash_elem *a_, const hash_elem *b_,
+ void *aux UNUSED)
@{
struct thread *a = hash_entry (a_, struct thread, h_elem);
struct thread *b = hash_entry (b_, struct thread, h_elem);
hash_init (&threads, thread_hash, thread_less, NULL);
@end example
-Finally, if @code{@var{t}} is a pointer to a @code{struct thread},
+Finally, if @code{@var{t}} is a pointer to a @struct{thread},
then we can insert it into the hash table with:
@example
for?}
In simple cases you won't have any need for the @var{aux} parameters.
-In these cases you can just pass a null pointer to @code{hash_init()}
+In these cases you can just pass a null pointer to @func{hash_init}
for @var{aux} and ignore the values passed to the hash function and
comparison functions. (You'll get a compiler warning if you don't use
the @var{aux} parameter, but you can turn that off with the
Make a reasonable decision and document it in your code and in
your design document. Please make sure to justify your decision.
+
+@item
+@b{Why do I need to pass @code{PAL_USER} to @func{palloc_get_page}
+when I allocate physical page frames?}@anchor{Why PAL_USER?}
+
+You can layer some other allocator on top of @func{palloc_get_page}
+if you like, but it should be the underlying mechanism, directly or
+indirectly, for two reasons. First, running out of pages in the user
+pool just causes user programs to page, but running out of pages in
+the kernel pool will cause all kinds of problems, because many kernel
+functions depend on being able to allocate memory. Second, you can
+use the @option{-ul} option to @command{pintos} to limit the size of
+the user pool, which makes it easy to test your VM implementation with
+various user memory sizes.
@end enumerate
@node Problem 3-3 Memory Mapped File FAQ