3d9e34db4ae41f92ec3bd32566ef1ed9442f39ba
[akaros.git] / kern / include / pmap.h
1 /* See COPYRIGHT for copyright information. */
2
3 #ifndef ROS_KERN_PMAP_H
4 #define ROS_KERN_PMAP_H
5 #ifndef ROS_KERNEL
6 # error "This is a ROS kernel header; user programs should not #include it"
7 #endif
8
9 #include <ros/memlayout.h>
10 #include <multiboot.h>
11 #include <atomic.h>
12 #include <process.h>
13 #include <assert.h>
14 #include <sys/queue.h>
15
16 /* This macro takes a kernel virtual address -- an address that points above
17  * KERNBASE, where the machine's maximum 256MB of physical memory is mapped --
18  * and returns the corresponding physical address.  It panics if you pass it a
19  * non-kernel virtual address.
20  */
21 #define PADDR(kva)                                              \
22 ({                                                              \
23         physaddr_t __m_kva = (physaddr_t) (kva);                \
24         if (__m_kva < KERNBASE)                                 \
25                 panic("PADDR called with invalid kva %08lx", __m_kva);\
26         __m_kva - KERNBASE;                                     \
27 })
28
29 /* This macro takes a physical address and returns the corresponding kernel
30  * virtual address.  It warns if you pass an invalid physical address. */
31 #define KADDR(pa)                                               \
32 ({                                                              \
33         physaddr_t __m_pa = (pa);                               \
34         size_t __m_ppn = PPN(__m_pa);                           \
35         if (__m_ppn >= npage)                                   \
36                 warn("KADDR called with invalid pa %08lx", __m_pa);\
37         (void*TRUSTED) (__m_pa + KERNBASE);                             \
38 })
39
40 /*
41  * Page descriptor structures, mapped at UPAGES.
42  * Read/write to the kernel, read-only to user programs.
43  *
44  * Each Page describes one physical page.
45  * You can map a Page * to the corresponding physical address
46  * with page2pa() in kern/pmap.h.
47  */
48
49 struct Page;
50 typedef struct Page page_t;
51
52 LIST_HEAD(page_list, Page);
53 typedef struct page_list page_list_t;
54 typedef LIST_ENTRY(Page) page_list_entry_t;
55
56 struct Page {
57         page_list_entry_t pp_link;      /* free list link */
58         size_t num_cons_links;
59
60         // pp_ref is the count of pointers (usually in page table entries)
61         // to this page, for pages allocated using page_alloc.
62         // Pages allocated at boot time using pmap.c's
63         // boot_alloc do not have valid reference count fields.
64
65         uint16_t pp_ref;
66 };
67
68
69 extern char (SNT bootstacktop)[], (SNT bootstack)[];
70
71 extern page_t *COUNT(npage) pages;
72 extern size_t npage;
73
74 extern physaddr_t boot_cr3;
75 extern pde_t *COUNT(NPDENTRIES) boot_pgdir;
76
77 extern char (SNT end)[];
78 extern char*BND(end, maxaddrpa_ptr + IVY_KERNBASE) boot_freemem;
79 extern page_list_t page_free_list;
80
81 void*   (DALLOC(n) boot_alloc)(uint32_t n, uint32_t align);
82 void*   (DALLOC(_n*sz) boot_calloc)(uint32_t _n, size_t sz, uint32_t align);
83
84 void    multiboot_detect_memory(multiboot_info_t *COUNT(1) mbi);
85 void    multiboot_print_memory_map(multiboot_info_t *COUNT(1) mbi);
86 bool    enable_pse(void);
87 void    vm_init(void);
88
89 void    page_init(void);
90 void    page_check(void);
91 int         page_alloc(page_t *COUNT(1) *pp_store);
92 int     page_alloc_specific(page_t *COUNT(1) *pp_store, size_t ppn);
93 void    page_free(page_t *COUNT(1) pp);
94 int             page_is_free(size_t ppn);
95 int         page_insert(pde_t *COUNT(NPDENTRIES) pgdir, page_t *pp, void *SNT va, int perm);
96 void*COUNT(PGSIZE) page_insert_in_range(pde_t *COUNT(NPDENTRIES) pgdir, page_t *pp, 
97                              void *SNT vab, void *SNT vae, int perm);
98 void    page_remove(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
99 page_t*COUNT(1) page_lookup(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va, pte_t **pte_store);
100 error_t pagetable_remove(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
101 void    page_decref(page_t *COUNT(1) pp);
102
103 void setup_default_mtrrs(barrier_t* smp_barrier);
104 void    tlb_invalidate(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
105 void tlb_flush_global(void);
106
107 void * (DALLOC(len) user_mem_check) (env_t *env, const void *DANGEROUS va,
108                                      size_t len, int perm);
109
110 void * (DALLOC(len) user_mem_assert)(env_t *env, const void *DANGEROUS va,
111                                      size_t len, int perm);
112
113 size_t user_mem_strlcpy(env_t *env, char *NT COUNT(len - 1),
114                         const char *DANGEROUS va, size_t len, int perm);
115
116 error_t
117 memcpy_from_user(env_t* env, void* COUNT(len) dest,
118                  const void *DANGEROUS va, size_t len);
119
120 static inline page_t*COUNT(1) ppn2page(size_t ppn)
121 {
122         if( ppn >= npage )
123                 warn("ppn2page called with ppn (%08u) larger than npage", ppn);
124         return &(pages[ppn]);
125 }
126
127 static inline ppn_t page2ppn(page_t *pp)
128 {
129         return pp - pages;
130 }
131
132 static inline physaddr_t page2pa(page_t *pp)
133 {
134         return page2ppn(pp) << PGSHIFT;
135 }
136
137 static inline page_t*COUNT(1) pa2page(physaddr_t pa)
138 {
139         if (PPN(pa) >= npage)
140                 warn("pa2page called with pa (0x%08x) larger than npage", pa);
141         return &pages[PPN(pa)];
142 }
143
144 static inline void*COUNT(PGSIZE) page2kva(page_t *pp)
145 {
146         return KADDR(page2pa(pp));
147 }
148
149 static inline void*COUNT(PGSIZE) ppn2kva(size_t pp)
150 {
151         return page2kva(ppn2page(pp));
152 }
153
154 static inline page_t* kva2page(void* addr) 
155 {
156         return pa2page(PADDR(addr));
157 }
158
159 pte_t *pgdir_walk(pde_t *COUNT(NPDENTRIES) pgdir, const void *SNT va, int create);
160
161 #endif /* !ROS_KERN_PMAP_H */