7e6707dbd105ec186575a62eb3dc85fc71d868b2
[akaros.git] / user / vmm / pagetables.c
1 /* Copyright (c) 2017 Google Inc.
2  * See LICENSE for details.
3  *
4  * Set up paging, using the minphys and maxphys in the vm struct. */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <sys/mman.h>
9 #include <ros/arch/mmu.h>
10 #include <vmm/vmm.h>
11 #include <vmm/util.h>
12 #include <string.h>
13 #include <stdint.h>
14 #include <errno.h>
15 #include <parlib/uthread.h>
16 #include <parlib/arch/arch.h>
17
18 static bool debug;
19
20 struct ptp {
21         uintptr_t pte[NPTENTRIES];
22 };
23
24 #define PAGE_RESOLUTION PML3_PTE_REACH
25
26 /* We put the page tables after 4Gb, where it exactly is doesn't matter as long
27  * as it's accessible by the guest. */
28 #define PAGE_TABLE_ROOT_START 0x100000000
29
30 static void check_jumbo_pages(void *arg)
31 {
32         uint32_t edx;
33
34         parlib_cpuid(0x80000001, 0x0, NULL, NULL, NULL, &edx);
35         if (!(edx & (1 << 26)))
36                 panic("1 GB Jumbo Pages are not supported on this hardware!");
37 }
38
39 /*
40  * This function assumes that after the p512 page table, there is memory mapped
41  * (though not necessarily populated) for each PML3 page table. This assumes
42  * a total of 2M + 4K memory mapped. PML3 table n is located at 4K*(n+1) from
43  * the start of the p512 table.
44  * This function does a 1:1 mapping of va to pa. vm->root must be set
45  * */
46 void add_pte_entries(struct virtual_machine *vm, uintptr_t start, uintptr_t end)
47 {
48         struct ptp *p512;
49         uintptr_t cur_page, aligned_start, aligned_end, pml4, pml3;
50         static parlib_once_t once = PARLIB_ONCE_INIT;
51
52         /* We check once if we can use 1Gb pages and die if we can't. */
53         parlib_run_once(&once, check_jumbo_pages, NULL);
54
55         uth_mutex_lock(&vm->mtx);
56         p512 = vm->root;
57         if (!p512)
58                 panic("vm->root page table pointer was not set!");
59
60         /* We align the start down and the end up to make sure we cover the full
61          * area. */
62         aligned_start = ALIGN_DOWN(start, PAGE_RESOLUTION);
63         aligned_end = ALIGN(end, PAGE_RESOLUTION);
64
65         cur_page = aligned_start;
66         /* We always do end-1 because end from /proc/self/maps is not inclusive
67          * */
68         for (pml4 = PML4(start); pml4 <= PML4(end - 1); pml4++) {
69                 struct ptp *p1 = p512 + pml4 + 1;
70
71                 /* Create the PML4 entry. Rather than check, I just overwrite
72                  * it. */
73                 p512->pte[pml4] = (uintptr_t) p1 | PTE_KERN_RW;
74
75                 for (pml3 = PML3(cur_page);
76                      pml3 < NPTENTRIES && cur_page < aligned_end;
77                      pml3++, cur_page += PML3_PTE_REACH) {
78                         /* Create the PML3 entry. */
79                         p1->pte[pml3] = cur_page | PTE_KERN_RW | PTE_PS;
80                 }
81         }
82         uth_mutex_unlock(&vm->mtx);
83 }
84
85 /* This function sets up the default page tables for the guest. It parses
86  * /proc/self/maps to figure out what pages are mapped for the uthread, and
87  * sets up a 1:1 mapping for the vm guest. This function can be called
88  * multiple times after startup to update the page tables, though regular
89  * vmms should call add_pte_entries if they mmap something for the guest after
90  * calling setup_paging to avoid having to parse /proc/self/maps again. */
91 void setup_paging(struct virtual_machine *vm)
92 {
93         FILE *maps;
94         char *line = NULL;
95         size_t line_sz;
96         char *strtok_save;
97         char *p;
98         uintptr_t first, second;
99
100         /* How many page table pages do we need?
101          * If we create 1G PTEs for the whole space, it just takes 2M + 4k worth
102          * of memory. Perhaps we should just identity map the whole space
103          * upfront.  Right now we don't MAP_POPULATE because we don't expect all
104          * the PTEs to be used. */
105         if (!vm->root)
106                 vm->root = mmap((void *)PAGE_TABLE_ROOT_START, 0x201000,
107                                 PROT_READ | PROT_WRITE,
108                                 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
109
110         if (vm->root == MAP_FAILED || (uintptr_t)vm->root >= BRK_START)
111                 panic("page table page alloc");
112
113         /* We parse /proc/self/maps to figure out the currently mapped memory.
114          * This way all the memory that's available to the HR3 process is also
115          * reflected in the page tables. Our smallest PTEs here are 1Gb so there
116          * may be memory locations described in the page tables that are not
117          * mapped though. /proc/self/maps parsing code courtesy of Barret. */
118         maps = fopen("/proc/self/maps", "r");
119         if (!maps)
120                 panic("unable to open /proc/self/maps");
121
122         /* returns -1 on error or EOF. */
123         while (getline(&line, &line_sz, maps) >= 0) {
124                 if (debug)
125                         fprintf(stderr, "Got line %s", line);
126
127                 p = strchr(line, ' ');
128                 /* No space, probably an error */
129                 if (!p)
130                         continue;
131                 *p = '\0';
132                 p = strtok_r(line, "-", &strtok_save);
133                 /* No first element! */
134                 if (!p)
135                         continue;
136                 first = strtoul(p, NULL, 16);
137                 p = strtok_r(NULL, "-", &strtok_save);
138                 /* No second element! */
139                 if (!p)
140                         continue;
141                 second = strtoul(p, NULL, 16);
142
143                 if (debug)
144                         printf("first %p, second %p\n\n", first, second);
145
146                 add_pte_entries(vm, first, second);
147
148         }
149         free(line);
150         fclose(maps);
151 }