vmm: add helpers for making more memory
[akaros.git] / user / vmm / memory.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 <pthread.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include <parlib/arch/arch.h>
12 #include <parlib/ros_debug.h>
13 #include <unistd.h>
14 #include <errno.h>
15 #include <dirent.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <ros/syscall.h>
19 #include <sys/mman.h>
20 #include <vmm/vmm.h>
21 #include <vmm/acpi/acpi.h>
22 #include <ros/arch/mmu.h>
23 #include <ros/arch/membar.h>
24 #include <ros/vmm.h>
25 #include <parlib/uthread.h>
26 #include <vmm/linux_bootparam.h>
27 #include <getopt.h>
28
29 #include <vmm/sched.h>
30 #include <vmm/net.h>
31 #include <sys/eventfd.h>
32 #include <sys/uio.h>
33 #include <sys/param.h>
34 #include <parlib/opts.h>
35
36 static char *entrynames[] = {
37         [E820_RAM] "E820_RAM",
38         [E820_RESERVED] "E820_RESERVED",
39         [E820_ACPI] "E820_ACPI",
40         [E820_NVS] "E820_NVS",
41         [E820_UNUSABLE] "E820_UNUSABLE",
42 };
43
44 static void dumpe820(struct e820entry *e, int nr)
45 {
46         for (int i = 0; i < nr; i++) {
47                 fprintf(stderr, "%d:%p %p %p %s\n",
48                         i, e[i].addr, e[i].size, e[i].type,
49                         entrynames[e[i].type]);
50         }
51 }
52
53 // e820map creates an e820 map in the bootparams struct.  If we've
54 // gotten here, then memsize and memstart are valid.  It returns
55 // pointer to the first page after the map for our bump allocator.  We
56 // assume the ranges passed in are validated already.
57 void *init_e820map(struct boot_params *bp,
58                    unsigned long long memstart,
59                    unsigned long long memsize)
60 {
61         unsigned long long lowmem = 0;
62         // Everything in Linux at this level is PGSIZE.
63         memset(bp, 0, PGSIZE);
64
65         bp->e820_entries = 0;
66
67         // The first page is always reserved.
68         bp->e820_map[bp->e820_entries].addr = 0;
69         bp->e820_map[bp->e820_entries].size = PGSIZE;
70         bp->e820_map[bp->e820_entries++].type = E820_RESERVED;
71
72         /* Give it just a tiny bit of memory -- 60k -- at low memory. */
73         bp->e820_map[bp->e820_entries].addr = PGSIZE;
74         bp->e820_map[bp->e820_entries].size = LOW64K - PGSIZE;
75         bp->e820_map[bp->e820_entries++].type = E820_RAM;
76
77         // All other memory from 64k to memstart is reserved.
78         bp->e820_map[bp->e820_entries].addr = LOW64K;
79         bp->e820_map[bp->e820_entries].size = memstart - LOW64K;
80         bp->e820_map[bp->e820_entries++].type = E820_RESERVED;
81
82         // If memory starts below RESERVED, then add an entry for memstart to
83         // the smaller of RESERVED or memsize.
84         if (memstart < RESERVED) {
85                 bp->e820_map[bp->e820_entries].addr = memstart;
86                 if (memstart + memsize > RESERVED)
87                         bp->e820_map[bp->e820_entries].size = RESERVED - memstart;
88                 else
89                         bp->e820_map[bp->e820_entries].size = memsize;
90                 lowmem = bp->e820_map[bp->e820_entries].size;
91                 bp->e820_map[bp->e820_entries++].type = E820_RAM;
92         }
93
94         bp->e820_map[bp->e820_entries].addr = RESERVED;
95         bp->e820_map[bp->e820_entries].size = RESERVEDSIZE;
96         bp->e820_map[bp->e820_entries++].type = E820_RESERVED;
97
98         if ((memstart + memsize) > RESERVED) {
99                 bp->e820_map[bp->e820_entries].addr = MAX(memstart, _4GiB);
100                 bp->e820_map[bp->e820_entries].size = memsize - lowmem;
101                 bp->e820_map[bp->e820_entries++].type = E820_RAM;
102         }
103
104         dumpe820(bp->e820_map, bp->e820_entries);
105         return (void *)bp + PGSIZE;
106 }
107
108 // memory allocates memory for the VM. It's a complicated mess because of the
109 // break for APIC and other things. We just go ahead and leave the region from
110 // RESERVED to _4GiB for that.  The memory is either split, all low, or all
111 // high.
112 void mmap_memory(unsigned long long memstart, unsigned long long memsize)
113 {
114         void *r1, *r2;
115         unsigned long r1size = memsize;
116
117         // Let's do some minimal validation, so we don't drive
118         // people crazy.
119         if ((memstart >= RESERVED) && (memstart < _4GiB))
120                 errx(1, "memstart (%#x) wrong: must be < %#x or >= %#x\n",
121                      memstart, RESERVED, _4GiB);
122         if (memstart < MinMemory)
123                 errx(1, "memstart (%#x) wrong: must be > %#x\n",
124                      memstart, MinMemory);
125
126         // Note: this test covers the split case as well as the
127         // 'all above 4G' case.
128         if ((memstart + memsize) > RESERVED) {
129                 unsigned long long r2start = MAX(memstart, _4GiB);
130
131                 r1size = memstart < RESERVED ? RESERVED - memstart : 0;
132                 r2 = mmap((void *)r2start, memsize - r1size,
133                           PROT_READ | PROT_WRITE | PROT_EXEC,
134                           MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
135                 if (r2 != (void *)r2start) {
136                         fprintf(stderr,
137                                 "High region: Could not mmap 0x%lx bytes at 0x%lx\n",
138                                 memsize, r2start);
139                         exit(1);
140                 }
141                 if (memstart >= _4GiB)
142                         return;
143         }
144
145         r1 = mmap((void *)memstart, r1size,
146                       PROT_READ | PROT_WRITE | PROT_EXEC,
147                       MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
148         if (r1 != (void *)memstart) {
149                 fprintf(stderr, "Low region: Could not mmap 0x%lx bytes at 0x%lx\n",
150                         memsize, memstart);
151                 exit(1);
152         }
153 }