Physical memory init uses multiboot info
[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
25 /* This macro takes a kernel virtual address -- an address that points above
26  * KERNBASE, where the machine's maximum 256MB of physical memory is mapped --
27  * and returns the corresponding physical address.  It panics if you pass it a
28  * non-kernel virtual address.
29  */
30 #define PADDR(kva)                                              \
31 ({                                                              \
32         physaddr_t __m_pa, __m_kva = (physaddr_t) (kva);                \
33         if (__m_kva < KERNBASE)                                 \
34                 panic("PADDR called with invalid kva %p", __m_kva);\
35         if(__m_kva >= KERN_LOAD_ADDR)                                   \
36                 __m_pa = __m_kva - KERN_LOAD_ADDR;                                      \
37         else                                    \
38                 __m_pa = __m_kva - KERNBASE;                                    \
39         __m_pa; \
40 })
41
42 /* This macro takes a physical address and returns the corresponding kernel
43  * virtual address.  It warns if you pass an invalid physical address. */
44 #define KADDR(pa)                                               \
45 ({                                                              \
46         physaddr_t __m_pa = (pa);                               \
47         size_t __m_ppn = LA2PPN(__m_pa);                        \
48         if (__m_ppn > max_nr_pages)                                     \
49                 warn("KADDR called with invalid pa %p", __m_pa);\
50         (void*TRUSTED) (__m_pa + KERNBASE);                             \
51 })
52
53 #define KBASEADDR(kla) KADDR(PADDR(kla))
54
55 extern char (SNT RO bootstacktop)[], (SNT RO bootstack)[];
56
57 extern physaddr_t max_pmem;             /* Total amount of physical memory */
58 extern size_t max_nr_pages;             /* Total number of physical memory pages */
59 extern physaddr_t max_paddr;    /* Maximum addressable physical address */
60 extern size_t nr_free_pages;
61 extern struct multiboot_info *multiboot_kaddr;
62 extern uintptr_t boot_freemem;
63 extern uintptr_t boot_freelimit;
64
65 /* Pages are stored in an array, including for pages that we can never touch
66  * (like reserved memory from the BIOS, fake regions, etc).  Pages are reference
67  * counted, and free pages are kept on a linked list. */
68 extern struct page *pages;
69
70 extern physaddr_t RO boot_cr3;
71 extern pde_t *CT(NPDENTRIES) RO boot_pgdir;
72
73 bool enable_pse(void);
74 void vm_init(void);
75
76 void pmem_init(struct multiboot_info *mbi);
77 void *boot_alloc(size_t amt, size_t align);
78 void *boot_zalloc(size_t amt, size_t align);
79
80 void page_check(void);
81 int      page_insert(pde_t *pgdir, struct page *page, void *SNT va, int perm);
82 void page_remove(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
83 page_t*COUNT(1) page_lookup(pde_t SSOMELOCK*COUNT(NPDENTRIES) pgdir, void *SNT va, pte_t **pte_store);
84 error_t pagetable_remove(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
85 void    page_decref(page_t *COUNT(1) pp);
86
87 void setup_default_mtrrs(barrier_t* smp_barrier);
88 void    tlb_invalidate(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
89 void tlb_flush_global(void);
90 bool regions_collide_unsafe(uintptr_t start1, uintptr_t end1, 
91                             uintptr_t start2, uintptr_t end2);
92
93 /* Arch specific implementations for these */
94 pte_t *pgdir_walk(pde_t *COUNT(NPDENTRIES) pgdir, const void *SNT va, int create);
95 int get_va_perms(pde_t *COUNT(NPDENTRIES) pgdir, const void *SNT va);
96
97 static inline page_t *SAFE ppn2page(size_t ppn)
98 {
99         if (ppn >= max_nr_pages)
100                 warn("ppn2page called with ppn (%08lu) larger than max_nr_pages", ppn);
101         return &(pages[ppn]);
102 }
103
104 static inline ppn_t page2ppn(page_t *pp)
105 {
106         return pp - pages;
107 }
108
109 static inline physaddr_t page2pa(page_t *pp)
110 {
111         return page2ppn(pp) << PGSHIFT;
112 }
113
114 static inline page_t*COUNT(1) pa2page(physaddr_t pa)
115 {
116         if (LA2PPN(pa) >= max_nr_pages)
117                 warn("pa2page called with pa (%p) larger than max_nr_pages", pa);
118         return &pages[LA2PPN(pa)];
119 }
120
121 static inline ppn_t pa2ppn(physaddr_t pa)
122 {
123         return pa >> PGSHIFT;
124 }
125
126 static inline void*COUNT(PGSIZE) page2kva(page_t *pp)
127 {
128         return KADDR(page2pa(pp));
129 }
130
131 static inline void*COUNT(PGSIZE) ppn2kva(size_t pp)
132 {
133         return page2kva(ppn2page(pp));
134 }
135
136 static inline page_t* kva2page(void* addr) 
137 {
138         return pa2page(PADDR(addr));
139 }
140
141 static inline ppn_t kva2ppn(void* addr) 
142 {
143         return page2ppn(kva2page(addr));
144 }
145
146 #endif /* !ROS_KERN_PMAP_H */