Merge remote branch 'origin/sparc-dev'
[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  * Kevin Klues <klueska@cs.berkeley.edu> (multiboot functions)
8  * Andrew Waterman <waterman@cs.berkeley.edu> (memcpy_to/from_user)
9  * Zach Anderson (zra@cs.berkeley.edu> (user_mem_strlcpy)
10  * See LICENSE for details.
11  *
12  * Physical memory mangement, low-level virtual address space initialization and
13  * management, and other things related to virtual->physical mappings.
14  */
15
16 #ifndef ROS_KERN_PMAP_H
17 #define ROS_KERN_PMAP_H
18
19 #include <ros/memlayout.h>
20 #include <ros/mman.h>
21 #include <sys/queue.h>
22 #include <multiboot.h>
23 #include <atomic.h>
24 #include <process.h>
25 #include <assert.h>
26 #include <page_alloc.h>
27 #include <multiboot.h>
28
29 /* This macro takes a kernel virtual address -- an address that points above
30  * KERNBASE, where the machine's maximum 256MB of physical memory is mapped --
31  * and returns the corresponding physical address.  It panics if you pass it a
32  * non-kernel virtual address.
33  */
34 #define PADDR(kva)                                              \
35 ({                                                              \
36         physaddr_t __m_kva = (physaddr_t) (kva);                \
37         if (__m_kva < KERNBASE)                                 \
38                 panic("PADDR called with invalid kva %08lx", __m_kva);\
39         __m_kva - KERNBASE;                                     \
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 >= npages)                                  \
49                 warn("KADDR called with invalid pa %08lx", __m_pa);\
50         (void*TRUSTED) (__m_pa + KERNBASE);                             \
51 })
52
53 extern char (SNT RO bootstacktop)[], (SNT RO bootstack)[];
54
55 // List of physical pages
56 extern page_t * RO CT(npages) pages;
57
58 extern physaddr_t RO boot_cr3;
59 extern pde_t *CT(NPDENTRIES) RO boot_pgdir;
60
61 extern char *RO BND(end, maxaddrpa_ptr + IVY_KERNBASE) boot_freemem;
62
63 void    multiboot_detect_memory(multiboot_info_t *COUNT(1) mbi);
64 void    multiboot_print_memory_map(multiboot_info_t *COUNT(1) mbi);
65 bool    enable_pse(void);
66 void    vm_init(void);
67
68 void    page_init(void);
69 void    page_check(void);
70 int         page_insert(pde_t *COUNT(NPDENTRIES) pgdir, page_t *pp, void *SNT va, int perm);
71 void*COUNT(PGSIZE) page_insert_in_range(pde_t *COUNT(NPDENTRIES) pgdir, page_t *pp, 
72                              void *SNT vab, void *SNT vae, int perm);
73 void    page_remove(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
74 page_t*COUNT(1) page_lookup(pde_t SSOMELOCK*COUNT(NPDENTRIES) pgdir, void *SNT va, pte_t **pte_store);
75 error_t pagetable_remove(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
76 void    page_decref(page_t *COUNT(1) pp);
77
78 void setup_default_mtrrs(barrier_t* smp_barrier);
79 void    tlb_invalidate(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
80 void tlb_flush_global(void);
81
82 /* TODO: either move these, or make them take a pgdir */
83 void * (DALLOC(len) user_mem_check) (env_t *env, const void *DANGEROUS va,
84                                      size_t len, int perm);
85
86 void * (DALLOC(len) user_mem_assert)(env_t *env, const void *DANGEROUS va,
87                                      size_t len, int perm);
88
89 size_t user_mem_strlcpy(env_t *env, char *NT COUNT(len - 1),
90                         const char *DANGEROUS va, size_t len, int perm);
91
92 error_t
93 memcpy_from_user(env_t* env, void* COUNT(len) dest,
94                  const void *DANGEROUS va, size_t len);
95
96 error_t
97 memcpy_to_user(env_t* env, void*DANGEROUS va,
98                  const void *COUNT(len) src, size_t len);
99                  
100 /* Arch specific implementations for these */
101 pte_t *pgdir_walk(pde_t *COUNT(NPDENTRIES) pgdir, const void *SNT va, int create);
102 int get_va_perms(pde_t *COUNT(NPDENTRIES) pgdir, const void *SNT va);
103 // TODO: should this be per process, per mm, per pgdir, etc?
104 // - can't ask this question without knowing the "context"
105 void *get_free_va_range(pde_t *pgdir, uintptr_t addr, size_t len);
106
107 static inline page_t *SAFE ppn2page(size_t ppn)
108 {
109         if( ppn >= npages )
110                 warn("ppn2page called with ppn (%08u) larger than npages", ppn);
111         return &(pages[ppn]);
112 }
113
114 static inline ppn_t page2ppn(page_t *pp)
115 {
116         return pp - pages;
117 }
118
119 static inline physaddr_t page2pa(page_t *pp)
120 {
121         return page2ppn(pp) << PGSHIFT;
122 }
123
124 static inline page_t*COUNT(1) pa2page(physaddr_t pa)
125 {
126         if (LA2PPN(pa) >= npages)
127                 warn("pa2page called with pa (0x%08x) larger than npages", pa);
128         return &pages[LA2PPN(pa)];
129 }
130
131 static inline void*COUNT(PGSIZE) page2kva(page_t *pp)
132 {
133         return KADDR(page2pa(pp));
134 }
135
136 static inline void*COUNT(PGSIZE) ppn2kva(size_t pp)
137 {
138         return page2kva(ppn2page(pp));
139 }
140
141 static inline page_t* kva2page(void* addr) 
142 {
143         return pa2page(PADDR(addr));
144 }
145
146 static inline ppn_t kva2ppn(void* addr) 
147 {
148         return page2ppn(kva2page(addr));
149 }
150
151 #endif /* !ROS_KERN_PMAP_H */