Move pagedir stuff into userprog.
[pintos-anon] / src / threads / mmu.h
index 4e9340abe962242b01e43b1a03e264252c04910d..304053bfdaba9ccd5721e19f929d9380e9358beb 100644 (file)
@@ -1,13 +1,60 @@
 #ifndef THREADS_MMU_H
 #define THREADS_MMU_H
 
-#ifndef __ASSEMBLER__
 #include <debug.h>
 #include <stdint.h>
-#endif
+#include <stdbool.h>
 
 #include "threads/loader.h"
 
+/* Virtual to physical translation works like this on an x86:
+
+   - The top 10 bits of the virtual address (bits 22:31) are used
+     to index into 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) are
+     used to index into 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 bottom 12 bits of the virtual address (bits 0:11) are
+     added to the data page's physical base address, producing
+     the final physical address.
+
+
+   32                    22                     12                      0
+   +--------------------------------------------------------------------+
+   | Page Directory Index |   Page Table Index   |    Page Offset       |
+   +--------------------------------------------------------------------+
+                |                    |                     |
+        _______/             _______/                _____/
+       /                    /                       /
+      /    Page Directory  /      Page Table       /    Data Page
+     /     .____________. /     .____________.    /   .____________.
+     |1,023|____________| |1,023|____________|    |   |____________|
+     |1,022|____________| |1,022|____________|    |   |____________|
+     |1,021|____________| |1,021|____________|    \__\|____________|
+     |1,020|____________| |1,020|____________|       /|____________|
+     |     |            | |     |            |        |            |
+     |     |            | \____\|            |_       |            |
+     |     |      .     |      /|      .     | \      |      .     |
+     \____\|      .     |_      |      .     |  |     |      .     |
+          /|      .     | \     |      .     |  |     |      .     |
+           |      .     |  |    |      .     |  |     |      .     |
+           |            |  |    |            |  |     |            |
+           |____________|  |    |____________|  |     |____________|
+          4|____________|  |   4|____________|  |     |____________|
+          3|____________|  |   3|____________|  |     |____________|
+          2|____________|  |   2|____________|  |     |____________|
+          1|____________|  |   1|____________|  |     |____________|
+          0|____________|  \__\0|____________|  \____\|____________|
+                              /                      /
+*/
+
 #define MASK(SHIFT, CNT) (((1ul << (CNT)) - 1) << (SHIFT))
 
 /* Page offset (bits 0:11). */
 #define PDBITS          10                 /* Number of page dir bits. */
 #define PDMASK          MASK(PDSHIFT, PDBITS)
 
-#ifndef __ASSEMBLER__
 /* Offset within a page. */
 static inline unsigned pg_ofs (void *va) { return (uintptr_t) va & PGMASK; }
 
-/* Page number. */
+/* Virtual page number. */
 static inline uintptr_t pg_no (void *va) { return (uintptr_t) va >> PTSHIFT; }
 
-/* Page table number. */
-static inline unsigned pt_no (void *va) {
-  return ((uintptr_t) va & PTMASK) >> PTSHIFT;
-}
-
-/* Page directory number. */
-static inline uintptr_t pd_no (void *va) { return (uintptr_t) va >> PDSHIFT; }
-
 /* Round up to nearest page boundary. */
 static inline void *pg_round_up (void *va) {
   return (void *) (((uintptr_t) va + PGSIZE - 1) & ~PGMASK);
@@ -72,17 +110,74 @@ vtop (void *vaddr)
 
   return (uintptr_t) vaddr - (uintptr_t) PHYS_BASE;
 }
-#endif
+\f
+/* Page directories and page tables.
 
-/* Page Directory Entry (PDE) and Page Table Entry (PTE) flags. */
+   For more information see [IA32-v3] pages 3-23 to 3-28.
+
+   PDEs and PTEs share a common format:
+
+   32                                   12                       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 PG_P 0x1               /* 1=present, 0=not present. */
 #define PG_W 0x2               /* 1=read/write, 0=read-only. */
 #define PG_U 0x4               /* 1=user/kernel, 0=kernel only. */
 #define PG_A 0x20              /* 1=accessed, 0=not acccessed. */
-#define PG_D 0x40              /* 1=dirty, 0=not dirty. */
+#define PG_D 0x40              /* 1=dirty, 0=not dirty (PTEs only). */
 
-/* EFLAGS Register. */
-#define FLAG_MBS  0x00000002    /* Must be set. */
-#define FLAG_IF   0x00000200    /* Interrupt Flag. */
+/* Obtains page directory index from a virtual address. */
+static inline uintptr_t pd_no (void *va) { return (uintptr_t) va >> PDSHIFT; }
+
+/* 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) | PG_U | PG_P | PG_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 & PG_P);
+  return ptov (pde & ~PGMASK);
+}
+
+/* Obtains page table index from a virtual address. */
+static inline unsigned pt_no (void *va) {
+  return ((uintptr_t) va & PTMASK) >> PTSHIFT;
+}
+
+/* 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) | PG_P | (writable ? PG_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) | PG_U;
+}
+
+/* Returns a pointer to the page that page table entry PTE, which
+   must "present", points to. */
+static inline void *pte_get_page (uint32_t pte) {
+  ASSERT (pte & PG_P);
+  return ptov (pte & ~PGMASK);
+}
 
 #endif /* threads/mmu.h */