Page Table
The code in pagedir.c
is an abstract interface to the 80x86 hardware page table, also called a "page directory" by Intel processor documentation.
The page table interface uses a
uint32_t *
to represent a page table because this is convenient for accessing their internal structure.The sections below describe the page table interface and internals.
Creation, Destruction, and Activation
These functions create, destroy, and activate page tables. The base Pintos code already calls these functions where necessary, so it should not be necessary to call them yourself.
Function: uint32_t *pagedir_create (void)
Creates and returns a new page table.
The new page table contains Pintos's normal kernel virtual page mappings, but no user virtual mappings.
Returns a null pointer if memory cannot be obtained.
Function: void pagedir_destroy (uint32_t *pd)
Frees all of the resources held by pd, including the page table itself and the frames that it maps.
Function: void pagedir_activate (uint32_t *pd)
Activates pd.
The active page table is the one used by the CPU to translate memory references.
Inspection and Updates
These functions examine or update the mappings from pages to frames encapsulated by a page table. They work on both active and inactive page tables (that is, those for running and suspended processes), flushing the TLB as necessary.
Function: bool pagedir_set_page (uint32_t *pd, void *upage, void *kpage, bool writable)
Adds to pd a mapping from user page upage to the frame identified by kernel virtual address kpage. If writable is true, the page is mapped read/write; otherwise, it is mapped read-only.
User page upage must not already be mapped in pd.
Kernel page kpage should be a kernel virtual address obtained from the user pool with
palloc_get_page(PAL_USER)
.Returns true if successful, false on failure. Failure will occur if additional memory required for the page table cannot be obtained.
Function: void *pagedir_get_page (uint32_t *pd, const void *uaddr)
Looks up the frame mapped to uaddr in pd.
Returns the kernel virtual address for that frame, if uaddr is mapped, or a null pointer if it is not.
Function: void pagedir_clear_page (uint32_t *pd, void *page)
Marks page "not present" in pd. Later accesses to the page will fault.
Other bits in the page table for page are preserved, permitting the accessed and dirty bits (see the next section) to be checked.
This function has no effect if page is not mapped.
Accessed and Dirty Bits
80x86 hardware provides some assistance for implementing page replacement algorithms, through a pair of bits in the page table entry (PTE) for each page.
On any read or write to a page, the CPU sets the accessed bit to 1 in the page's PTE, and on any write, the CPU sets the dirty bit to 1.
The CPU never resets these bits to 0, but the OS may do so.
Proper interpretation of these bits requires understanding of aliases, that is, two (or more) pages that refer to the same frame. When an aliased frame is accessed, the accessed and dirty bits are updated in only one page table entry (the one for the page used for access). The accessed and dirty bits for the other aliases are not updated.
In project 3, you will apply these bits in implementing page replacement algorithms.
The followings are some functions related to accessed and dirty bits:
Function: bool pagedir_is_dirty (uint32_t *pd, const void *page)
Function: bool pagedir_is_accessed (uint32_t *pd, const void *page)
Returns true if page directory pd contains a page table entry for page that is marked dirty (or accessed). Otherwise, returns false.
Function: void pagedir_set_dirty (uint32_t *pd, const void *page, bool value)
Function: void pagedir_set_accessed (uint32_t *pd, const void *page, bool value)
If page directory pd has a page table entry for page, then its dirty (or accessed) bit is set to value.
Page Table Details
The functions provided with Pintos are sufficient to implement the projects. However, you may still find it worthwhile to understand the hardware page table format, so we'll go into a little detail in this section.
Structure
The top-level paging data structure is a page called the "page directory" (PD) arranged as an array of 1,024 32-bit page directory entries (PDEs), each of which represents 4 MB of virtual memory.
Each PDE may point to the physical address of another page called a "page table" (PT) arranged, similarly, as an array of 1,024 32-bit page table entries (PTEs), each of which translates a single 4 kB virtual page to a physical page.
Address Translation
Translation of a virtual address into a physical address follows the three-step process illustrated in the diagram below:
Actually, virtual to physical translation on the 80x86 architecture occurs via an intermediate "linear address," but Pintos (and most modern 80x86 OSes) set up the CPU so that linear and virtual addresses are one and the same. Thus, you can effectively ignore this CPU feature.
The most-significant 10 bits of the virtual address (bits 22...31) index the page directory.
If the PDE is marked "present," the physical address of a page table is read from the PDE thus obtained.
If the PDE is marked "not present," then a page fault occurs.
The next 10 bits of the virtual address (bits 12...21) index the page table.
If the PTE is marked "present," the physical address of a data page is read from the PTE thus obtained.
If the PTE is marked "not present," then a page fault occurs.
The least-significant 12 bits of the virtual address (bits 0...11) are added to the data page's physical base address, yielding the final physical address.
Pintos provides some macros and functions that are useful for working with raw page tables:
Page Table Entry Format
You do not need to understand the PTE format to do the Pintos projects, unless you wish to incorporate the page table into your supplemental page table in project 3.
The actual format of a page table entry is summarized below. For complete information, refer to section 3.7, "Page Translation Using 32-Bit Physical Addressing," in [IA32-v3a].
Some more information on each bit is given below. The names are threads/pte.h
macros that represent the bits' values:
Page Directory Entry Format
Page directory entries have the same format as PTEs, except that the physical address points to a page table page instead of a frame. Header threads/pte.h
defines two functions for working with page directory entries:
Function: uint32_t pde_create (uint32_t *pt)
Returns a page directory that points to pt, which should be the kernel virtual address of a page table page.
The PDE's present bit will be set, it will be marked to allow user-mode access, and it will be marked read/write.
Function: uint32_t *pde_get_pt (uint32_t pde)
Returns the kernel virtual address for the page table page that pde, which must be marked present, points to.
Last updated