--- /dev/null
+#ifndef THREADS_PTE_H
+#define THREADS_PTE_H
+
+#include "threads/vaddr.h"
+
+/* Functions and macros for working with x86 hardware page
+ tables.
+
+ See vaddr.h for more generic functions and macros for virtual
+ addresses.
+
+ Virtual addresses are structured as follows:
+
+ 31 22 21 12 11 0
+ +----------------------+----------------------+----------------------+
+ | Page Directory Index | Page Table Index | Page Offset |
+ +----------------------+----------------------+----------------------+
+*/
+
+/* Page table index (bits 12:21). */
+#define PTSHIFT PGBITS /* First page table bit. */
+#define PTBITS 10 /* Number of page table bits. */
+#define PTSPAN (1 << PTBITS << PGBITS) /* Bytes covered by a page table. */
+#define PTMASK BITMASK(PTSHIFT, PTBITS) /* Page table bits (12:21). */
+
+/* Page directory index (bits 22:31). */
+#define PDSHIFT (PTSHIFT + PTBITS) /* First page directory bit. */
+#define PDBITS 10 /* Number of page dir bits. */
+#define PDMASK BITMASK(PDSHIFT, PDBITS) /* Page directory bits (22:31). */
+
+/* Obtains page table index from a virtual address. */
+static inline unsigned pt_no (const void *va) {
+ return ((uintptr_t) va & PTMASK) >> PTSHIFT;
+}
+
+/* Obtains page directory index from a virtual address. */
+static inline uintptr_t pd_no (const void *va) {
+ return (uintptr_t) va >> PDSHIFT;
+}
+
+/* Page directory and page table entries.
+
+ For more information see the section on page tables in the
+ Pintos reference guide chapter, or [IA32-v3a] 3.7.6
+ "Page-Directory and Page-Table Entries".
+
+ PDEs and PTEs share a common format:
+
+ 31 12 11 0
+ +------------------------------------+------------------------+
+ | Physical Address | Flags |
+ +------------------------------------+------------------------+
+
+ In a PDE, the physical address points to a page table.
+ In a PTE, the physical address points to a data or code page.
+ The important flags are listed below.
+ When a PDE or PTE is not "present", the other flags are
+ ignored.
+ A PDE or PTE that is initialized to 0 will be interpreted as
+ "not present", which is just fine. */
+#define PTE_FLAGS 0x00000fff /* Flag bits. */
+#define PTE_ADDR 0xfffff000 /* Address bits. */
+#define PTE_AVL 0x00000e00 /* Bits available for OS use. */
+#define PTE_P 0x1 /* 1=present, 0=not present. */
+#define PTE_W 0x2 /* 1=read/write, 0=read-only. */
+#define PTE_U 0x4 /* 1=user/kernel, 0=kernel only. */
+#define PTE_A 0x20 /* 1=accessed, 0=not acccessed. */
+#define PTE_D 0x40 /* 1=dirty, 0=not dirty (PTEs only). */
+
+/* Returns a PDE that points to page table PT. */
+static inline uint32_t pde_create (uint32_t *pt) {
+ ASSERT (pg_ofs (pt) == 0);
+ return vtop (pt) | PTE_U | PTE_P | PTE_W;
+}
+
+/* Returns a pointer to the page table that page directory entry
+ PDE, which must "present", points to. */
+static inline uint32_t *pde_get_pt (uint32_t pde) {
+ ASSERT (pde & PTE_P);
+ return ptov (pde & PTE_ADDR);
+}
+
+/* Returns a PTE that points to PAGE.
+ The PTE's page is readable.
+ If WRITABLE is true then it will be writable as well.
+ The page will be usable only by ring 0 code (the kernel). */
+static inline uint32_t pte_create_kernel (uint32_t *page, bool writable) {
+ ASSERT (pg_ofs (page) == 0);
+ return vtop (page) | PTE_P | (writable ? PTE_W : 0);
+}
+
+/* Returns a PTE that points to PAGE.
+ The PTE's page is readable.
+ If WRITABLE is true then it will be writable as well.
+ The page will be usable by both user and kernel code. */
+static inline uint32_t pte_create_user (uint32_t *page, bool writable) {
+ return pte_create_kernel (page, writable) | PTE_U;
+}
+
+/* Returns a pointer to the page that page table entry PTE points
+ to. */
+static inline void *pte_get_page (uint32_t pte) {
+ return ptov (pte & PTE_ADDR);
+}
+
+#endif /* threads/pte.h */
+