+@node Working with Virtual Addresses
+@subsubsection Working with Virtual Addresses
+
+Header @file{threads/mmu.h} has useful functions for various
+operations on virtual addresses. You should look over the header
+yourself. The most important functions are described below.
+
+@deftypefun uintptr_t pd_no (const void *@var{va})
+Returns the page directory index for virtual address @var{va}.
+@end deftypefun
+
+@deftypefun uintptr_t pt_no (const void *@var{va})
+Returns the page table index for virtual address @var{va}.
+@end deftypefun
+
+@deftypefun unsigned pg_ofs (const void *@var{va})
+Returns the page offset of virtual address @var{va}.
+@end deftypefun
+
+@deftypefun {void *} pg_round_down (const void *@var{va})
+Returns @var{va} rounded down to the nearest page boundary, that is,
+@var{va} with its page offset set to 0.
+@end deftypefun
+
+@deftypefun {void *} pg_round_up (const void *@var{va})
+Returns @var{va} rounded up to the nearest page boundary.
+@end deftypefun
+
+@node Accessed and Dirty Bits
+@subsubsection Accessed and Dirty Bits
+
+Most of the page table is under the control of the operating system, but
+two bits in each page table entry are also manipulated by the CPU. On
+any read or write to the page referenced by a PTE, the CPU sets the
+PTE's @dfn{accessed bit} to 1; on any write, the CPU sets the @dfn{dirty
+bit} to 1. The CPU never resets these bits to 0, but the OS may do so.
+
+You will need to use the accessed and dirty bits in your submission to
+choose which pages to evict from memory and to decide whether evicted
+pages need to be written to disk. The page table code in
+@file{userprog/pagedir.c} provides functions for checking and setting
+these bits. These functions are described at the end of this section.
+
+You need to watch out for @dfn{aliases}, that is, two (or more)
+different virtual pages that refer to the same physical page frame.
+When an aliased page is accessed, the accessed and dirty bits are
+updated in only one page table entry (the one for the virtual address
+used to access the page). The accessed and dirty bits for the other
+aliased virtual addresses are not updated.
+
+In Pintos, every user virtual page is aliased to its kernel virtual
+address. You must manage these aliases somehow. For example, your code
+could check and update the accessed and dirty bits for both addresses.
+Alternatively, the kernel could avoid the problem by only accessing user
+data through the user virtual address.
+
+Other aliases should only arise if you implement sharing, as extra
+credit (@pxref{VM Extra Credit}), or as bugs elsewhere in your code.
+
+@deftypefun bool pagedir_is_dirty (uint32_t *@var{pd}, const void *@var{vpage})
+@deftypefunx bool pagedir_is_accessed (uint32_t *@var{pd}, const void *@var{vpage})
+Returns true if page directory @var{pd} contains a page table entry for
+virtual page @var{vpage} that is marked dirty (or accessed). Otherwise,
+returns false.
+@end deftypefun
+
+@deftypefun void pagedir_set_dirty (uint32_t *@var{pd}, const void *@var{vpage}, bool @var{value})
+@deftypefunx void pagedir_set_accessed (uint32_t *@var{pd}, const void *@var{vpage}, bool @var{value})
+If page directory @var{pd} has a page table entry for @var{vpage}, then
+its dirty (or accessed) bit is set to @var{value}.
+@end deftypefun
+