Makes pte_t an opaque type
[akaros.git] / kern / include / pmap.h
1 /* See COPYRIGHT for copyright information.
2  * Inlines, macros, and most function prototypes (c) the JOS project.
3  *
4  * Actual implementation:
5  * Copyright (c) 2009 The Regents of the University of California
6  * Barret Rhoden <brho@cs.berkeley.edu>
7  * See LICENSE for details.
8  *
9  * Physical memory mangement, low-level virtual address space initialization and
10  * management, and other things related to virtual->physical mappings.
11  */
12
13 #ifndef ROS_KERN_PMAP_H
14 #define ROS_KERN_PMAP_H
15
16 #include <ros/memlayout.h>
17 #include <sys/queue.h>
18 #include <multiboot.h>
19 #include <atomic.h>
20 #include <process.h>
21 #include <assert.h>
22 #include <page_alloc.h>
23 #include <multiboot.h>
24 #include <arch/pmap.h>
25
26 /* This macro takes a kernel virtual address -- an address that points above
27  * KERNBASE, where the machine's maximum 256MB of physical memory is mapped --
28  * and returns the corresponding physical address.  It panics if you pass it a
29  * non-kernel virtual address.
30  */
31 #define PADDR(kva)                                              \
32 ({                                                              \
33         physaddr_t __m_pa, __m_kva = (physaddr_t) (kva);                \
34         if (__m_kva < KERNBASE)                                 \
35                 panic("PADDR called with invalid kva %p", __m_kva);\
36         if(__m_kva >= KERN_LOAD_ADDR)                                   \
37                 __m_pa = __m_kva - KERN_LOAD_ADDR;                                      \
38         else                                    \
39                 __m_pa = __m_kva - KERNBASE;                                    \
40         __m_pa; \
41 })
42
43 #define paddr_low32(p) ((uint32_t)(uintptr_t)PADDR(p))
44 #define paddr_high32(p) ((uint32_t)((uint64_t)PADDR(p) >> 32))
45
46 /* This macro takes a physical address and returns the corresponding kernel
47  * virtual address.  It warns if you pass an invalid physical address. */
48 #define KADDR(pa)                                               \
49 ({                                                              \
50         physaddr_t __m_pa = (pa);                               \
51         size_t __m_ppn = LA2PPN(__m_pa);                        \
52         if (__m_ppn > max_nr_pages)                                     \
53                 warn("KADDR called with invalid pa %p", __m_pa);\
54         (void*TRUSTED) (__m_pa + KERNBASE);                             \
55 })
56
57 #define KADDR_NOCHECK(pa) ((void*)(pa + KERNBASE))
58 #define KBASEADDR(kla) KADDR(PADDR(kla))
59
60 extern char (SNT RO bootstacktop)[], (SNT RO bootstack)[];
61
62 extern physaddr_t max_pmem;             /* Total amount of physical memory */
63 extern size_t max_nr_pages;             /* Total number of physical memory pages */
64 extern physaddr_t max_paddr;    /* Maximum addressable physical address */
65 extern size_t nr_free_pages;
66 extern struct multiboot_info *multiboot_kaddr;
67 extern uintptr_t boot_freemem;
68 extern uintptr_t boot_freelimit;
69
70 /* Pages are stored in an array, including for pages that we can never touch
71  * (like reserved memory from the BIOS, fake regions, etc).  Pages are reference
72  * counted, and free pages are kept on a linked list. */
73 extern struct page *pages;
74
75 extern physaddr_t RO boot_cr3;
76 extern pde_t *CT(NPDENTRIES) RO boot_pgdir;
77
78 bool enable_pse(void);
79 void vm_init(void);
80
81 void pmem_init(struct multiboot_info *mbi);
82 void *boot_alloc(size_t amt, size_t align);
83 void *boot_zalloc(size_t amt, size_t align);
84
85 void page_check(void);
86 int      page_insert(pde_t *pgdir, struct page *page, void *SNT va, int perm);
87 void page_remove(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
88 page_t* page_lookup(pde_t *pgdir, void *va, pte_t *pte_store);
89 error_t pagetable_remove(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
90 void    page_decref(page_t *COUNT(1) pp);
91
92 void    tlb_invalidate(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
93 void tlb_flush_global(void);
94 bool regions_collide_unsafe(uintptr_t start1, uintptr_t end1, 
95                             uintptr_t start2, uintptr_t end2);
96
97 /* Arch specific implementations for these */
98 pte_t pgdir_walk(pde_t *pgdir, const void *va, int create);
99 int get_va_perms(pde_t *pgdir, const void *va);
100
101 static inline page_t *SAFE ppn2page(size_t ppn)
102 {
103         if (ppn >= max_nr_pages)
104                 warn("ppn2page called with ppn (%08lu) larger than max_nr_pages", ppn);
105         return &(pages[ppn]);
106 }
107
108 static inline ppn_t page2ppn(page_t *pp)
109 {
110         return pp - pages;
111 }
112
113 static inline physaddr_t page2pa(page_t *pp)
114 {
115         return page2ppn(pp) << PGSHIFT;
116 }
117
118 static inline page_t*COUNT(1) pa2page(physaddr_t pa)
119 {
120         if (LA2PPN(pa) >= max_nr_pages)
121                 warn("pa2page called with pa (%p) larger than max_nr_pages", pa);
122         return &pages[LA2PPN(pa)];
123 }
124
125 static inline ppn_t pa2ppn(physaddr_t pa)
126 {
127         return pa >> PGSHIFT;
128 }
129
130 static inline void*COUNT(PGSIZE) page2kva(page_t *pp)
131 {
132         return KADDR(page2pa(pp));
133 }
134
135 static inline void*COUNT(PGSIZE) ppn2kva(size_t pp)
136 {
137         return page2kva(ppn2page(pp));
138 }
139
140 static inline page_t* kva2page(void* addr) 
141 {
142         return pa2page(PADDR(addr));
143 }
144
145 static inline ppn_t kva2ppn(void* addr) 
146 {
147         return page2ppn(kva2page(addr));
148 }
149
150 static inline bool is_kaddr(void *addr)
151 {
152         return (uintptr_t)addr >= KERNBASE;
153 }
154
155 static inline unsigned long nr_pages(size_t nr_bytes)
156 {
157         return (nr_bytes >> PGSHIFT) + (PGOFF(nr_bytes) ? 1 : 0);
158 }
159
160 static inline bool pte_walk_okay(pte_t pte)
161 {
162         return pte ? TRUE : FALSE;
163 }
164
165 /* PTE states:
166  *  - present: the PTE is involved in a valid page table walk, with the physaddr
167  *  part pointing to a physical page.
168  *
169  *      - mapped: the PTE is involved in some sort of mapping, e.g. a VMR.  We're
170  *      storing something in the PTE, but it is isn't necessarily present and
171  *      pointing to an actual physical page.  All present are mapped, but not vice
172  *      versa.  Mapped could also include paged-out, if we support that later.
173  *
174  *      - unmapped: completely unused. (0 value) */
175 static inline bool pte_is_present(pte_t pte)
176 {
177         return *(kpte_t*)pte & PTE_P ? TRUE : FALSE;
178 }
179
180 static inline bool pte_is_unmapped(pte_t pte)
181 {
182         return PAGE_UNMAPPED(*(kpte_t*)pte);
183 }
184
185 static inline bool pte_is_mapped(pte_t pte)
186 {
187         return !PAGE_UNMAPPED(*(kpte_t*)pte);
188 }
189
190 static inline bool pte_is_paged_out(pte_t pte)
191 {
192         return PAGE_PAGED_OUT(*(kpte_t*)pte);
193 }
194
195 static inline bool pte_is_dirty(pte_t pte)
196 {
197         return *(kpte_t*)pte & PTE_D ? TRUE : FALSE;
198 }
199
200 static inline bool pte_is_accessed(pte_t pte)
201 {
202         return *(kpte_t*)pte & PTE_A ? TRUE : FALSE;
203 }
204
205 /* Used in debugging code - want something better involving the walk */
206 static inline bool pte_is_jumbo(pte_t pte)
207 {
208         return *(kpte_t*)pte & PTE_PS ? TRUE : FALSE;
209 }
210
211 static inline physaddr_t pte_get_paddr(pte_t pte)
212 {
213         return PTE_ADDR(*(kpte_t*)pte);
214 }
215
216 /* Returns the PTE in an unsigned long, for debugging mostly. */
217 static inline unsigned long pte_print(pte_t pte)
218 {
219         return *(kpte_t*)pte;
220 }
221
222 static inline void pte_write(pte_t pte, physaddr_t pa, int perm)
223 {
224         *(kpte_t*)pte = PTE(pa2ppn(pa), perm);
225 }
226
227 static inline void pte_clear_present(pte_t pte)
228 {
229         *(kpte_t*)pte &= ~PTE_P;
230 }
231
232 static inline void pte_clear(pte_t pte)
233 {
234         *(kpte_t*)pte = 0;
235 }
236
237 /* These are used by memcpy_*_user, but are very dangerous (and possibly used
238  * incorrectly there).  These aren't the overall perms for a VA.  For U and W,
239  * we need the intersection of the PTEs along the walk and not just the last
240  * one.  It just so happens that the W is only cleared on the last PTE, so the
241  * check works for that.  But if there was a page under ULIM that wasn't U due
242  * to an intermediate PTE, we'd miss that. */
243 static inline bool pte_has_perm_ur(pte_t pte)
244 {
245         return *(kpte_t*)pte & PTE_USER_RO ? TRUE : FALSE;
246 }
247
248 static inline bool pte_has_perm_urw(pte_t pte)
249 {
250         return *(kpte_t*)pte & PTE_USER_RW ? TRUE : FALSE;
251 }
252
253 /* return the arch-independent format for prots - whatever you'd expect to
254  * receive for pte_write.  Careful with the ret, since a valid type is 0. */
255 static inline int pte_get_perm(pte_t pte)
256 {
257         return *(kpte_t*)pte & PTE_PERM;
258 }
259
260 static inline void pte_replace_perm(pte_t pte, int perm)
261 {
262         *(kpte_t*)pte = (*(kpte_t*)pte & ~PTE_PERM) | perm;
263 }
264
265 #endif /* !ROS_KERN_PMAP_H */