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