blob: 1b750083c0d5c8bdb4869383d708a4a43a6eef91 [file] [log] [blame]
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +01001#include "load.h"
2
3#include <stdbool.h>
4
5#include "api.h"
6#include "dlog.h"
7#include "memiter.h"
8#include "mm.h"
9#include "std.h"
10#include "vm.h"
11
12/**
13 * Copies data to an unmapped location by mapping it for write, copying the
14 * data, then unmapping it.
15 */
16static bool copy_to_unmaped(paddr_t to, const void *from, size_t size)
17{
18 if (!mm_map((vaddr_t)to, (vaddr_t)to + size, to, MM_MODE_W)) {
19 return false;
20 }
21
22 memcpy((void *)to, from, size);
23
24 mm_unmap(to, to + size, 0);
25
26 return true;
27}
28
29/**
30 * Moves the kernel of the primary VM to its final destination.
31 */
32static bool relocate(const char *from, size_t size)
33{
34 /* TODO: This is a hack. We must read the alignment from the binary. */
35 extern char bin_end[];
36 size_t tmp = (size_t)&bin_end[0];
37 paddr_t dest = (tmp + 0x80000 - 1) & ~(0x80000 - 1);
38 dlog("bin_end is at %p, copying to %p\n", &bin_end[0], dest);
39 return copy_to_unmaped(dest, from, size);
40}
41
42/**
43 * Looks for a file in the given cpio archive. The filename is not
44 * null-terminated, so we use a memory iterator to represent it. The file, if
45 * found, is returned in the "it" argument.
46 */
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +010047static bool memiter_find_file(const struct memiter *cpio,
48 const struct memiter *filename,
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +010049 struct memiter *it)
50{
51 const char *fname;
52 const void *fcontents;
53 size_t fsize;
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +010054 struct memiter iter = *cpio;
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +010055
56 while (cpio_next(&iter, &fname, &fcontents, &fsize)) {
57 if (memiter_iseq(filename, fname)) {
58 memiter_init(it, fcontents, fsize);
59 return true;
60 }
61 }
62
63 return false;
64}
65
66/**
67 * Looks for a file in the given cpio archive. The file, if found, is returned
68 * in the "it" argument.
69 */
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +010070static bool find_file(const struct memiter *cpio, const char *name,
71 struct memiter *it)
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +010072{
73 const char *fname;
74 const void *fcontents;
75 size_t fsize;
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +010076 struct memiter iter = *cpio;
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +010077
78 while (cpio_next(&iter, &fname, &fcontents, &fsize)) {
79 if (!strcmp(fname, name)) {
80 memiter_init(it, fcontents, fsize);
81 return true;
82 }
83 }
84
85 return false;
86}
87
88/**
89 * Loads the primary VM.
90 */
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +010091bool load_primary(const struct memiter *cpio, size_t kernel_arg,
92 struct memiter *initrd)
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +010093{
94 struct memiter it;
95
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +010096 if (!find_file(cpio, "vmlinuz", &it)) {
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +010097 dlog("Unable to find vmlinuz\n");
98 return false;
99 }
100
101 if (!relocate(it.next, it.limit - it.next)) {
102 dlog("Unable to relocate kernel for primary vm.\n");
103 return false;
104 }
105
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +0100106 if (!find_file(cpio, "initrd.img", initrd)) {
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100107 dlog("Unable to find initrd.img\n");
108 return false;
109 }
110
111 {
112 size_t tmp = (size_t)&load_primary;
113 tmp = (tmp + 0x80000 - 1) & ~(0x80000 - 1);
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100114 if (!vm_init(&primary_vm, 0, MAX_CPUS)) {
115 dlog("Unable to initialise primary vm\n");
116 return false;
117 }
118
119 /* Map the 1TB of memory. */
120 /* TODO: We should do a whitelist rather than a blacklist. */
121 if (!mm_ptable_map(&primary_vm.ptable, 0,
122 1024ull * 1024 * 1024 * 1024, 0,
123 MM_MODE_R | MM_MODE_W | MM_MODE_X |
124 MM_MODE_NOINVALIDATE)) {
125 dlog("Unable to initialise memory for primary vm\n");
126 return false;
127 }
128
129 if (!mm_ptable_unmap_hypervisor(&primary_vm.ptable,
130 MM_MODE_NOINVALIDATE)) {
131 dlog("Unable to unmap hypervisor from primary vm\n");
132 return false;
133 }
134
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100135 vm_start_vcpu(&primary_vm, 0, tmp, kernel_arg, true);
136 }
137
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100138 vm_set_current(&primary_vm);
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100139
140 return true;
141}
142
143/**
144 * Loads all secondary VMs in the given memory range. "mem_end" is updated to
145 * reflect the fact that some of the memory isn't available to the primary VM
146 * anymore.
147 */
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +0100148bool load_secondary(const struct memiter *cpio, uint64_t mem_begin,
149 uint64_t *mem_end)
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100150{
151 struct memiter it;
152 struct memiter str;
153 uint64_t mem;
154 uint64_t cpu;
155 uint32_t count;
156
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +0100157 if (!find_file(cpio, "vms.txt", &it)) {
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100158 dlog("vms.txt is missing\n");
159 return true;
160 }
161
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100162 /* Round the last address down to the page size. */
163 *mem_end &= ~(PAGE_SIZE - 1);
164
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100165 for (count = 0;
166 memiter_parse_uint(&it, &mem) && memiter_parse_uint(&it, &cpu) &&
167 memiter_parse_str(&it, &str) && count < MAX_VMS;
168 count++) {
169 struct memiter kernel;
170
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +0100171 if (!memiter_find_file(cpio, &str, &kernel)) {
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100172 dlog("Unable to load kernel for vm %u\n", count);
173 continue;
174 }
175
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100176 /* Round up to page size. */
177 mem = (mem + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100178 if (mem > *mem_end - mem_begin) {
179 dlog("Not enough memory for vm %u (%u bytes)\n", count,
180 mem);
181 continue;
182 }
183
184 if (mem < kernel.limit - kernel.next) {
185 dlog("Kernel is larger than available memory for vm "
186 "%u\n",
187 count);
188 continue;
189 }
190
191 *mem_end -= mem;
192 if (!copy_to_unmaped(*mem_end, kernel.next,
193 kernel.limit - kernel.next)) {
194 dlog("Unable to copy kernel for vm %u\n", count);
195 continue;
196 }
197
Wedson Almeida Filho84a30a02018-07-23 20:05:05 +0100198 if (!vm_init(secondary_vm + count, count + 1, cpu)) {
199 dlog("Unable to initialise vm %u\n", count);
200 continue;
201 }
202
203 /* TODO: Remove this. */
204 /* Grant VM access to uart. */
205 mm_ptable_map_page(&secondary_vm[count].ptable, PL011_BASE,
206 PL011_BASE,
207 MM_MODE_R | MM_MODE_W | MM_MODE_D |
208 MM_MODE_NOINVALIDATE);
209
210 /* Grant the VM access to the memory. */
211 if (!mm_ptable_map(&secondary_vm[count].ptable, *mem_end,
212 *mem_end + mem, *mem_end,
213 MM_MODE_R | MM_MODE_W | MM_MODE_X |
214 MM_MODE_NOINVALIDATE)) {
215 dlog("Unable to initialise memory for vm %u\n", count);
216 continue;
217 }
218
219 /* Deny the primary VM access to this memory. */
220 if (!mm_ptable_unmap(&primary_vm.ptable, *mem_end,
221 *mem_end + mem, MM_MODE_NOINVALIDATE)) {
222 dlog("Unable to unmap secondary VM from primary VM\n");
223 return false;
224 }
225
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100226 dlog("Loaded VM%u with %u vcpus, entry at 0x%x\n", count, cpu,
227 *mem_end);
228
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100229 vm_start_vcpu(secondary_vm + count, 0, *mem_end, 0, false);
230 }
231
232 secondary_vm_count = count;
233
234 return true;
235}