Treat tabs as having eight spaces instead of four
[akaros.git] / kern / arch / riscv / pmap.c
1 /* See COPYRIGHT for copyright information. */
2 #include <arch/arch.h>
3 #include <arch/mmu.h>
4
5 #include <error.h>
6 #include <sys/queue.h>
7
8 #include <assert.h>
9 #include <atomic.h>
10 #include <env.h>
11 #include <kmalloc.h>
12 #include <page_alloc.h>
13 #include <pmap.h>
14 #include <stdio.h>
15 #include <string.h>
16
17 #warning "convert pgdir* to pgdir_t"
18 pgdir_t *boot_pgdir; // Virtual address of boot time page directory
19 physaddr_t boot_cr3; // Physical address of boot time page directory
20
21 // --------------------------------------------------------------
22 // Set up initial memory mappings and turn on MMU.
23 // --------------------------------------------------------------
24
25 void vm_init(void)
26 {
27         // we already set up our page tables before jumping
28         // into the kernel, so there's not much going on here
29
30         extern pte_t l1pt[NPTENTRIES];
31         boot_pgdir = l1pt;
32         boot_cr3 = PADDR(boot_pgdir);
33 }
34
35 // Given 'pgdir', a pointer to a page directory, pgdir_walk returns
36 // a pointer to the page table entry (PTE) for linear address 'va'.
37 // This requires walking the two-level page table structure.
38 //
39 // If the relevant page table doesn't exist in the page directory, then:
40 //    - If create == 0, pgdir_walk returns NULL.
41 //    - Otherwise, pgdir_walk tries to allocate a new page table
42 //      with page_alloc.  If this fails, pgdir_walk returns NULL.
43 //    - Otherwise, pgdir_walk returns a pointer into the new page table.
44 //
45 // This is boot_pgdir_walk, but using page_alloc() instead of boot_alloc().
46 // Unlike boot_pgdir_walk, pgdir_walk can fail.
47 pte_t *pgdir_walk(pgdir_t *pgdir, const void *va, int create)
48 {
49         pte_t *ppte;
50         pte_t *pt;
51
52         pt = pgdir;
53         for (int i = 0; i < NPTLEVELS - 1; i++) {
54                 // this code relies upon the fact that all page tables are the
55                 // same size
56                 uintptr_t idx = (uintptr_t)va >>
57                         (L1PGSHIFT - i * (L1PGSHIFT - L2PGSHIFT));
58                 idx = idx & (NPTENTRIES - 1);
59
60                 ppte = &pt[idx];
61
62                 if (*ppte & PTE_E)
63                         return ppte;
64
65                 if (!(*ppte & PTE_T)) {
66                         if (!create)
67                                 return NULL;
68
69                         page_t *new_table;
70                         if (kpage_alloc(&new_table))
71                                 return NULL;
72                         memset(page2kva(new_table), 0, PGSIZE);
73
74                         *ppte = PTD(page2pa(new_table));
75                 }
76
77                 pt = (pte_t *)KADDR(PTD_ADDR(*ppte));
78         }
79
80         uintptr_t idx = (uintptr_t)va >>
81                         (L1PGSHIFT - (NPTLEVELS - 1) * (L1PGSHIFT - L2PGSHIFT));
82         idx = idx & (NPTENTRIES - 1);
83         return &pt[idx];
84 }
85
86 /* Returns the effective permissions for PTE_U, PTE_W, and PTE_P on a given
87  * virtual address. */
88 int get_va_perms(pgdir_t *pgdir, const void *va)
89 {
90         pte_t *pte = pgdir_walk(pgdir, va, 0);
91         return pte == NULL ? 0 : (*pte & (PTE_PERM | PTE_E));
92 }
93
94 void page_check(void)
95 {
96 }
97
98 uintptr_t gva2gpa(struct proc *p, uintptr_t cr3, uintptr_t gva)
99 {
100         panic("Unimplemented");
101         return 0;
102 }
103
104 int arch_pgdir_setup(pgdir_t boot_copy, pgdir_t *new_pd)
105 {
106         pte_t *kpt = kpage_alloc_addr();
107         if (!kpt)
108                 return -ENOMEM;
109         memcpy(kpt, (pte_t *)boot_copy, PGSIZE);
110
111         /* TODO: VPT/UVPT mappings */
112
113         *new_pd = (pgdir_t)kpt;
114         return 0;
115 }
116
117 physaddr_t arch_pgdir_get_cr3(pgdir_t pd)
118 {
119         return PADDR((pte_t *)pd);
120 }
121
122 void arch_pgdir_clear(pgdir_t *pd)
123 {
124         *pd = 0;
125 }
126
127 /* Returns the page shift of the largest jumbo supported */
128 int arch_max_jumbo_page_shift(void)
129 {
130 #warning "What jumbo page sizes does RISC support?"
131         return PGSHIFT;
132 }
133
134 #warning                                                                       \
135     "Not sure where you do your PT destruction.  Be sure to not unmap any intermediate page tables for kernel mappings.  At least not the PML(n-1) maps"
136
137 void arch_add_intermediate_pts(pgdir_t pgdir, uintptr_t va, size_t len)
138 {
139 #error "Implement me"
140 }
141
142 void map_segment(pgdir_t pgdir, uintptr_t va, size_t size, physaddr_t pa,
143                  int perm, int pml_shift)
144 {
145 #error "Implement me"
146 }
147
148 int unmap_segment(pgdir_t pgdir, uintptr_t va, size_t size)
149 {
150 #error "Implement me"
151 }