8 #include "threads/loader.h"
10 /* Virtual to physical translation works like this on an x86:
12 - The top 10 bits of the virtual address (bits 22:32) are used
13 to index into the page directory. If the PDE is marked
14 "present," the physical address of a page table is read from
15 the PDE thus obtained. If the PDE is marked "not present"
16 then a page fault occurs.
18 - The next 10 bits of the virtual address (bits 12:22) are
19 used to index into the page table. If the PTE is marked
20 "present," the physical address of a data page is read from
21 the PTE thus obtained. If the PTE is marked "not present"
22 then a page fault occurs.
24 - The bottom 12 bits of the virtual address (bits 0:12) are
25 added to the data page's physical base address, producing
26 the final physical address.
30 +--------------------------------------------------------------------+
31 | Page Directory Index | Page Table Index | Page Offset |
32 +--------------------------------------------------------------------+
34 _______/ _______/ _____/
36 / Page Directory / Page Table / Data Page
37 / .____________. / .____________. / .____________.
38 |1,023|____________| |1,023|____________| | |____________|
39 |1,022|____________| |1,022|____________| | |____________|
40 |1,021|____________| |1,021|____________| \__\|____________|
41 |1,020|____________| |1,020|____________| /|____________|
44 | | . | /| . | \ | . |
45 \____\| . |_ | . | | | . |
46 /| . | \ | . | | | . |
49 |____________| | |____________| | |____________|
50 4|____________| | 4|____________| | |____________|
51 3|____________| | 3|____________| | |____________|
52 2|____________| | 2|____________| | |____________|
53 1|____________| | 1|____________| | |____________|
54 0|____________| \__\0|____________| \____\|____________|
58 #define MASK(SHIFT, CNT) (((1ul << (CNT)) - 1) << (SHIFT))
60 /* Page offset (bits 0:12). */
61 #define PGSHIFT 0 /* Index of first offset bit. */
62 #define PGBITS 12 /* Number of offset bits. */
63 #define PGMASK MASK(PGSHIFT, PGBITS) /* Page offset bits (0:12). */
64 #define PGSIZE (1 << PGBITS) /* Bytes in a page. */
66 /* Page table (bits 12:22). */
67 #define PTSHIFT PGBITS /* Index of first page table bit. */
68 #define PTBITS 10 /* Number of page table bits. */
69 #define PTMASK MASK(PTSHIFT, PTBITS) /* Page table bits (12:22). */
70 #define PTSPAN (1 << PTBITS << PGBITS) /* Bytes covered by a page table. */
72 /* Page directory (bits 22:32). */
73 #define PDSHIFT (PTSHIFT + PTBITS) /* First page dir bit. */
74 #define PDBITS 10 /* Number of page dir bits. */
75 #define PDMASK MASK(PDSHIFT, PDBITS) /* Page directory bits (22:32). */
77 /* Offset within a page. */
78 static inline unsigned pg_ofs (const void *va) {
79 return (uintptr_t) va & PGMASK;
82 /* Virtual page number. */
83 static inline uintptr_t pg_no (const void *va) {
84 return (uintptr_t) va >> PTSHIFT;
87 /* Round up to nearest page boundary. */
88 static inline void *pg_round_up (const void *va) {
89 return (void *) (((uintptr_t) va + PGSIZE - 1) & ~PGMASK);
92 /* Round down to nearest page boundary. */
93 static inline void *pg_round_down (const void *va) {
94 return (void *) ((uintptr_t) va & ~PGMASK);
97 /* Base address of the 1:1 physical-to-virtual mapping. Physical
98 memory is mapped starting at this virtual address. Thus,
99 physical address 0 is accessible at PHYS_BASE, physical
100 address address 0x1234 at (uint8_t *) PHYS_BASE + 0x1234, and
103 This address also marks the end of user programs' address
104 space. Up to this point in memory, user programs are allowed
105 to map whatever they like. At this point and above, the
106 virtual address space belongs to the kernel. */
107 #define PHYS_BASE ((void *) LOADER_PHYS_BASE)
109 /* Returns true if VADDR is a user virtual address. */
111 is_user_vaddr (const void *vaddr)
113 return vaddr < PHYS_BASE;
116 /* Returns true if VADDR is a kernel virtual address. */
118 is_kernel_vaddr (const void *vaddr)
120 return vaddr >= PHYS_BASE;
123 /* Returns kernel virtual address at which physical address PADDR
126 ptov (uintptr_t paddr)
128 ASSERT ((void *) paddr < PHYS_BASE);
130 return (void *) (paddr + PHYS_BASE);
133 /* Returns physical address at which kernel virtual address VADDR
135 static inline uintptr_t
136 vtop (const void *vaddr)
138 ASSERT (is_kernel_vaddr (vaddr));
140 return (uintptr_t) vaddr - (uintptr_t) PHYS_BASE;
143 /* Page directories and page tables.
145 For more information see [IA32-v3] pages 3-23 to 3-28.
147 PDEs and PTEs share a common format:
150 +------------------------------------+------------------------+
151 | Physical Address | Flags |
152 +------------------------------------+------------------------+
154 In a PDE, the physical address points to a page table.
155 In a PTE, the physical address points to a data or code page.
156 The important flags are listed below.
157 When a PDE or PTE is not "present", the other flags are
159 A PDE or PTE that is initialized to 0 will be interpreted as
160 "not present", which is just fine. */
161 #define PG_P 0x1 /* 1=present, 0=not present. */
162 #define PG_W 0x2 /* 1=read/write, 0=read-only. */
163 #define PG_U 0x4 /* 1=user/kernel, 0=kernel only. */
164 #define PG_A 0x20 /* 1=accessed, 0=not acccessed. */
165 #define PG_D 0x40 /* 1=dirty, 0=not dirty (PTEs only). */
167 /* Obtains page directory index from a virtual address. */
168 static inline uintptr_t pd_no (const void *va) {
169 return (uintptr_t) va >> PDSHIFT;
172 /* Returns a PDE that points to page table PT. */
173 static inline uint32_t pde_create (uint32_t *pt) {
174 ASSERT (pg_ofs (pt) == 0);
175 return vtop (pt) | PG_U | PG_P | PG_W;
178 /* Returns a pointer to the page table that page directory entry
179 PDE, which must "present", points to. */
180 static inline uint32_t *pde_get_pt (uint32_t pde) {
182 return ptov (pde & ~PGMASK);
185 /* Obtains page table index from a virtual address. */
186 static inline unsigned pt_no (const void *va) {
187 return ((uintptr_t) va & PTMASK) >> PTSHIFT;
190 /* Returns a PTE that points to PAGE.
191 The PTE's page is readable.
192 If WRITABLE is true then it will be writable as well.
193 The page will be usable only by ring 0 code (the kernel). */
194 static inline uint32_t pte_create_kernel (uint32_t *page, bool writable) {
195 ASSERT (pg_ofs (page) == 0);
196 return vtop (page) | PG_P | (writable ? PG_W : 0);
199 /* Returns a PTE that points to PAGE.
200 The PTE's page is readable.
201 If WRITABLE is true then it will be writable as well.
202 The page will be usable by both user and kernel code. */
203 static inline uint32_t pte_create_user (uint32_t *page, bool writable) {
204 return pte_create_kernel (page, writable) | PG_U;
207 /* Returns a pointer to the page that page table entry PTE points
209 static inline void *pte_get_page (uint32_t pte) {
210 return ptov (pte & ~PGMASK);
213 #endif /* threads/mmu.h */