Helpers for the PGSHIFT of the largest jumbo page
[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 <atomic.h>
9 #include <string.h>
10 #include <assert.h>
11 #include <pmap.h>
12 #include <kclock.h>
13 #include <env.h>
14 #include <stdio.h>
15 #include <kmalloc.h>
16 #include <page_alloc.h>
17
18 #warning "convert pgdir* to pgdir_t"
19 pgdir_t* boot_pgdir;            // Virtual address of boot time page directory
20 physaddr_t boot_cr3;            // Physical address of boot time page directory
21
22 // --------------------------------------------------------------
23 // Set up initial memory mappings and turn on MMU.
24 // --------------------------------------------------------------
25
26 void
27 vm_init(void)
28 {
29         // we already set up our page tables before jumping
30         // into the kernel, so there's not much going on here
31
32         extern pte_t l1pt[NPTENTRIES];
33         boot_pgdir = l1pt;
34         boot_cr3 = PADDR(boot_pgdir);
35 }
36
37 // Given 'pgdir', a pointer to a page directory, pgdir_walk returns
38 // a pointer to the page table entry (PTE) for linear address 'va'.
39 // This requires walking the two-level page table structure.
40 //
41 // If the relevant page table doesn't exist in the page directory, then:
42 //    - If create == 0, pgdir_walk returns NULL.
43 //    - Otherwise, pgdir_walk tries to allocate a new page table
44 //      with page_alloc.  If this fails, pgdir_walk returns NULL.
45 //    - Otherwise, pgdir_walk returns a pointer into the new page table.
46 //
47 // This is boot_pgdir_walk, but using page_alloc() instead of boot_alloc().
48 // Unlike boot_pgdir_walk, pgdir_walk can fail.
49 pte_t*
50 pgdir_walk(pgdir_t *pgdir, const void *va, int create)
51 {
52         pte_t* ppte;
53         pte_t* pt;
54
55         pt = pgdir;
56         for(int i = 0; i < NPTLEVELS-1; i++)
57         {
58                 // this code relies upon the fact that all page tables are the same size
59                 uintptr_t idx = (uintptr_t)va >> (L1PGSHIFT - i*(L1PGSHIFT-L2PGSHIFT));
60                 idx = idx & (NPTENTRIES-1);
61
62                 ppte = &pt[idx];
63
64                 if(*ppte & PTE_E)
65                         return ppte;
66
67                 if(!(*ppte & PTE_T))
68                 {
69                         if(!create)
70                                 return NULL;
71
72                         page_t *new_table;
73                         if(kpage_alloc(&new_table))
74                                 return NULL;
75                         memset(page2kva(new_table), 0, PGSIZE);
76
77                         *ppte = PTD(page2pa(new_table));
78                 }
79
80                 pt = (pte_t*)KADDR(PTD_ADDR(*ppte));
81         }
82
83         uintptr_t idx = (uintptr_t)va >> (L1PGSHIFT - (NPTLEVELS-1)*(L1PGSHIFT-L2PGSHIFT));
84         idx = idx & (NPTENTRIES-1);
85   return &pt[idx];
86 }
87
88 /* Returns the effective permissions for PTE_U, PTE_W, and PTE_P on a given
89  * virtual address. */
90 int get_va_perms(pgdir_t *pgdir, const void *va)
91 {
92         pte_t* pte = pgdir_walk(pgdir, va, 0);
93         return pte == NULL ? 0 : (*pte & (PTE_PERM | PTE_E));
94 }
95
96 void
97 page_check(void)
98 {
99 }
100
101 int arch_pgdir_setup(pgdir_t boot_copy, pgdir_t *new_pd)
102 {
103         pte_t *kpt = kpage_alloc_addr();
104         if (!kpt)
105                 return -ENOMEM;
106         memcpy(kpt, (pte_t*)boot_copy, PGSIZE);
107
108         /* TODO: VPT/UVPT mappings */
109
110         *new_pd = (pgdir_t)kpt;
111         return 0;
112 }
113
114 physaddr_t arch_pgdir_get_cr3(pgdir_t pd)
115 {
116         return PADDR((pte_t*)pd);
117 }
118
119 void arch_pgdir_clear(pgdir_t *pd)
120 {
121         *pd = 0;
122 }
123
124 /* Returns the page shift of the largest jumbo supported */
125 int arch_max_jumbo_page_shift(void)
126 {
127         #warning "What jumbo page sizes does RISC support?"
128         return PGSHIFT;
129 }