Update to linuxemu syscall structure
[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
12 typedef struct {
13         uint64_t pte[512];
14 } ptp;
15
16 void *setup_paging(struct virtual_machine *vm, bool debug)
17 {
18         ptp *p512, *p1, *p2m;
19         int nptp, npml4, npml3, npml2;
20         uintptr_t memstart = vm->minphys;
21         size_t memsize = vm->maxphys - vm->minphys + 1;
22
23         /* This test is redundant when booting kernels, as it is also
24          * performed in memory(), but not all users call that function,
25          * hence we must do it here too. */
26         checkmemaligned(memstart, memsize);
27
28         /* How many page table pages do we need?  We conservatively
29          * assume that we are in low memory, and hence assume a
30          * 0-based range.  Note that in many cases, kernels will
31          * immediately set up their own map. But for "dune" like
32          * applications, it's necessary. Note also that in most cases,
33          * the total number of pages will be < 16 or so. */
34         npml4 = DIV_ROUND_UP(memstart + memsize, PML4_REACH);
35         nptp = npml4;
36
37         npml3 = DIV_ROUND_UP(memstart + memsize, PML3_REACH);
38         nptp += npml3;
39
40         /* and 1 for each 2 MiB of memory */
41         npml2 = DIV_ROUND_UP(memstart + memsize, PML2_REACH);
42         nptp += npml2;
43
44         fprintf(stderr,
45                 "Memstart is %llx, memsize is %llx, memstart + memsize is %llx; ",
46                 memstart, memsize, memstart + memsize);
47         fprintf(stderr, " %d pml4 %d pml3 %d pml2\n",
48                 npml4, npml3, npml2);
49
50         /* Place these page tables right after VM memory. We
51          * used to use posix_memalign but that puts them
52          * outside EPT-accessible space on some CPUs. */
53         p512 = mmap((void *)memstart + memsize, nptp * 4096, PROT_READ | PROT_WRITE,
54                      MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
55         if (p512 == MAP_FAILED) {
56                 perror("page table page alloc");
57                 exit(1);
58         }
59         p1 = &p512[npml4];
60         p2m = &p1[npml3];
61
62         /* Set up a 1:1 ("identity") page mapping from guest virtual
63          * to guest physical using the (host virtual)
64          * `kerneladdress`. This mapping may be used for only a short
65          * time, until the guest sets up its own page tables. Be aware
66          * that the values stored in the table are physical addresses.
67          * This is subtle and mistakes are easily disguised due to the
68          * identity mapping, so take care when manipulating these
69          * mappings. */
70
71         p2m->pte[PML2(0)] = (uint64_t)0 | PTE_KERN_RW | PTE_PS;
72
73         fprintf(stderr, "Map %p for %zu bytes\n", memstart, memsize);
74         for (uintptr_t p4 = memstart, i4 = PML4(p4);
75                  p4 < memstart + memsize && i4 < NPTENTRIES;
76              p4 = ROUNDUP(p4 + 1, PML4_PTE_REACH), p1++, i4++) {
77                 p512->pte[PML4(p4)] = (uint64_t)p1 | PTE_KERN_RW;
78                 if (debug)
79                         fprintf(stderr, "l4@%p: %p set index 0x%x to 0x%llx\n",
80                                         &p512->pte[PML4(p4)],
81                                         p4, PML4(p4), p512->pte[PML4(p4)]);
82                 for (uintptr_t p3 = p4, i3 = PML3(p3);
83                          p3 < memstart + memsize && i3 < NPTENTRIES;
84                      p3 = ROUNDUP(p3 + 1, PML3_PTE_REACH), p2m++, i3++) {
85                         p1->pte[PML3(p3)] = (uint64_t)p2m | PTE_KERN_RW;
86                         if (debug)
87                                 fprintf(stderr, "\tl3@%p: %p set index 0x%x to 0x%llx\n",
88                                                 &p1->pte[PML3(p3)],
89                                                 p3, PML3(p3), p1->pte[PML3(p3)]);
90                         for (uintptr_t p2 = p3, i2 = PML2(p2);
91                                  p2 < memstart + memsize && i2 < NPTENTRIES;
92                              p2 += PML2_PTE_REACH, i2++) {
93                                 p2m->pte[PML2(p2)] = (uint64_t)p2 | PTE_KERN_RW | PTE_PS;
94                                 if (debug)
95                                         fprintf(stderr, "\t\tl2@%p: %p set index 0x%x to 0x%llx\n",
96                                                         &p2m->pte[PML2(p2)],
97                                                         p2, PML2(p2), p2m->pte[PML2(p2)]);
98                         }
99                 }
100
101         }
102
103         return (void *)p512;
104 }