Physical memory init uses multiboot info
[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 pde_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
26 vm_init(void)
27 {
28         // we already set up our page tables before jumping
29         // into the kernel, so there's not much going on here
30
31         extern pte_t l1pt[NPTENTRIES];
32         boot_pgdir = l1pt;
33         boot_cr3 = PADDR(boot_pgdir);
34 }
35
36 // Given 'pgdir', a pointer to a page directory, pgdir_walk returns
37 // a pointer to the page table entry (PTE) for linear address 'va'.
38 // This requires walking the two-level page table structure.
39 //
40 // If the relevant page table doesn't exist in the page directory, then:
41 //    - If create == 0, pgdir_walk returns NULL.
42 //    - Otherwise, pgdir_walk tries to allocate a new page table
43 //      with page_alloc.  If this fails, pgdir_walk returns NULL.
44 //    - Otherwise, pgdir_walk returns a pointer into the new page table.
45 //
46 // This is boot_pgdir_walk, but using page_alloc() instead of boot_alloc().
47 // Unlike boot_pgdir_walk, pgdir_walk can fail.
48 pte_t*
49 pgdir_walk(pde_t *pgdir, const void *SNT va, int create)
50 {
51         pte_t* ppte;
52         pte_t* pt;
53
54         pt = pgdir;
55         for(int i = 0; i < NPTLEVELS-1; i++)
56         {
57                 // this code relies upon the fact that all page tables are the same size
58                 uintptr_t idx = (uintptr_t)va >> (L1PGSHIFT - i*(L1PGSHIFT-L2PGSHIFT));
59                 idx = idx & (NPTENTRIES-1);
60
61                 ppte = &pt[idx];
62
63                 if(*ppte & PTE_E)
64                         return ppte;
65
66                 if(!(*ppte & PTE_T))
67                 {
68                         if(!create)
69                                 return NULL;
70
71                         page_t *new_table;
72                         if(kpage_alloc(&new_table))
73                                 return NULL;
74                         memset(page2kva(new_table), 0, PGSIZE);
75
76                         *ppte = PTD(page2pa(new_table));
77                 }
78
79                 pt = (pte_t*)KADDR(PTD_ADDR(*ppte));
80         }
81
82         uintptr_t idx = (uintptr_t)va >> (L1PGSHIFT - (NPTLEVELS-1)*(L1PGSHIFT-L2PGSHIFT));
83         idx = idx & (NPTENTRIES-1);
84   return &pt[idx];
85 }
86
87 /* Returns the effective permissions for PTE_U, PTE_W, and PTE_P on a given
88  * virtual address. */
89 int get_va_perms(pde_t *pgdir, const void *SNT va)
90 {
91         pte_t* pte = pgdir_walk(pgdir, va, 0);
92         return pte == NULL ? 0 : (*pte & (PTE_PERM | PTE_E));
93 }
94
95 void
96 page_check(void)
97 {
98 }