blob: a23c7e80d7d65d9afa88ba3941857099cc0b6333 [file] [log] [blame]
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +01001#include <stdalign.h>
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +01002#include <stddef.h>
3
Wedson Almeida Filhofed69022018-07-11 15:39:12 +01004#include "alloc.h"
5#include "api.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +01006#include "cpio.h"
7#include "cpu.h"
8#include "dlog.h"
9#include "fdt.h"
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010010#include "mm.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010011#include "std.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010012#include "vm.h"
13
14void *fdt;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010015char ptable_buf[PAGE_SIZE * 20];
16struct mm_ptable ptable;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010017
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010018bool fdt_find_node(struct fdt_node *node, const char *path)
19{
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010020 while (*path) {
Andrew Scull7364a8e2018-07-19 15:39:29 +010021 if (!fdt_find_child(node, path)) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010022 return false;
Andrew Scull7364a8e2018-07-19 15:39:29 +010023 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010024 path += strlen(path);
25 }
26
27 return true;
28}
29
Wedson Almeida Filho87009642018-07-02 10:20:07 +010030static uint64_t convert_number(const char *data, uint32_t size)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010031{
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010032 union {
33 volatile uint64_t v;
34 char a[8];
35 } t;
36
Wedson Almeida Filho87009642018-07-02 10:20:07 +010037 switch (size) {
38 case sizeof(uint32_t):
Andrew Scull29d40392018-07-16 11:46:59 +010039 return be32toh(*(uint32_t *)data);
Wedson Almeida Filho87009642018-07-02 10:20:07 +010040 case sizeof(uint64_t):
41 memcpy(t.a, data, sizeof(uint64_t));
Andrew Scull29d40392018-07-16 11:46:59 +010042 return be64toh(t.v);
Wedson Almeida Filho87009642018-07-02 10:20:07 +010043 default:
44 return 0;
45 }
46}
47
48static bool fdt_read_number(const struct fdt_node *node, const char *name,
Andrew Scull4f170f52018-07-19 12:58:20 +010049 uint64_t *value)
Wedson Almeida Filho87009642018-07-02 10:20:07 +010050{
51 const char *data;
52 uint32_t size;
53
Andrew Scull7364a8e2018-07-19 15:39:29 +010054 if (!fdt_read_property(node, name, &data, &size)) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010055 return false;
Andrew Scull7364a8e2018-07-19 15:39:29 +010056 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010057
58 switch (size) {
59 case sizeof(uint32_t):
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010060 case sizeof(uint64_t):
Wedson Almeida Filho87009642018-07-02 10:20:07 +010061 *value = convert_number(data, size);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010062 break;
63
64 default:
65 return false;
66 }
67
68 return true;
69}
70
71bool fdt_write_number(struct fdt_node *node, const char *name, uint64_t value)
72{
73 const char *data;
74 uint32_t size;
75 union {
76 volatile uint64_t v;
77 char a[8];
78 } t;
79
Andrew Scull7364a8e2018-07-19 15:39:29 +010080 if (!fdt_read_property(node, name, &data, &size)) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010081 return false;
Andrew Scull7364a8e2018-07-19 15:39:29 +010082 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010083
84 switch (size) {
85 case sizeof(uint32_t):
Andrew Scull29d40392018-07-16 11:46:59 +010086 *(uint32_t *)data = be32toh(value);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010087 break;
88
89 case sizeof(uint64_t):
Andrew Scull29d40392018-07-16 11:46:59 +010090 t.v = be64toh(value);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010091 memcpy((void *)data, t.a, sizeof(uint64_t));
92 break;
93
94 default:
95 return false;
96 }
97
98 return true;
99}
100
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100101/**
102 * Copies data to an unmapped location by mapping it for write, copying the
103 * data, then unmapping it.
104 */
105static bool copy_to_unmaped(paddr_t to, const void *from, size_t size)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100106{
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100107 if (!mm_ptable_map(&ptable, (vaddr_t)to, (vaddr_t)to + size, to,
Andrew Scull7364a8e2018-07-19 15:39:29 +0100108 MM_MODE_W | MM_MODE_STAGE1)) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100109 return false;
Andrew Scull7364a8e2018-07-19 15:39:29 +0100110 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100111
112 memcpy((void *)to, from, size);
113
114 mm_ptable_unmap(&ptable, to, to + size, MM_MODE_STAGE1);
115
116 return true;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100117}
118
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100119static bool relocate(const char *from, size_t size)
120{
121 /* TODO: This is a hack. We must read the alignment from the binary. */
122 extern char bin_end[];
123 size_t tmp = (size_t)&bin_end[0];
124 paddr_t dest = (tmp + 0x80000 - 1) & ~(0x80000 - 1);
125 dlog("bin_end is at %p, copying to %p\n", &bin_end[0], dest);
126 return copy_to_unmaped(dest, from, size);
127}
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100128
129static void find_memory_range(const struct fdt_node *root,
130 uint64_t *block_start, uint64_t *block_size)
131{
132 struct fdt_node n = *root;
133 const char *name;
134 uint64_t address_size;
135 uint64_t size_size;
136 uint64_t entry_size;
137
138 /* Get the sizes of memory range addresses and sizes. */
Andrew Scull7364a8e2018-07-19 15:39:29 +0100139 if (fdt_read_number(&n, "#address-cells", &address_size)) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100140 address_size *= sizeof(uint32_t);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100141 } else {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100142 address_size = sizeof(uint32_t);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100143 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100144
Andrew Scull7364a8e2018-07-19 15:39:29 +0100145 if (fdt_read_number(&n, "#size-cells", &size_size)) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100146 size_size *= sizeof(uint32_t);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100147 } else {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100148 size_size = sizeof(uint32_t);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100149 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100150
151 entry_size = address_size + size_size;
152
153 /* Look for nodes with the device_type set to "memory". */
Andrew Scull7364a8e2018-07-19 15:39:29 +0100154 if (!fdt_first_child(&n, &name)) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100155 return;
Andrew Scull7364a8e2018-07-19 15:39:29 +0100156 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100157
158 do {
159 const char *data;
160 uint32_t size;
161 if (!fdt_read_property(&n, "device_type", &data, &size) ||
162 size != sizeof("memory") ||
163 memcmp(data, "memory", sizeof("memory")) != 0 ||
164 !fdt_read_property(&n, "reg", &data, &size)) {
165 continue;
166 }
167
168 /* Traverse all memory ranges within this node. */
169 while (size >= entry_size) {
170 uint64_t addr = convert_number(data, address_size);
Andrew Scull4f170f52018-07-19 12:58:20 +0100171 uint64_t len =
172 convert_number(data + address_size, size_size);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100173
174 if (len > *block_size) {
175 /* Remember the largest range we've found. */
176 *block_start = addr;
177 *block_size = len;
178 }
179
180 size -= entry_size;
181 data += entry_size;
182 }
183 } while (fdt_next_sibling(&n, &name));
184
185 /* TODO: Check for "reserved-memory" nodes. */
186}
187
188/**
189 * Finds the memory region where initrd is stored, and udpates the fdt node
190 * cursor to the node called "chosen".
191 */
192static bool find_initrd(struct fdt_node *n, uint64_t *begin, uint64_t *end)
193{
194 if (!fdt_find_node(n, "chosen\0")) {
195 dlog("Unable to find 'chosen'\n");
196 return false;
197 }
198
199 if (!fdt_read_number(n, "linux,initrd-start", begin)) {
200 dlog("Unable to read linux,initrd-start\n");
201 return false;
202 }
203
204 if (!fdt_read_number(n, "linux,initrd-end", end)) {
205 dlog("Unable to read linux,initrd-end\n");
206 return false;
207 }
208
209 return true;
210}
211
212struct memiter {
213 const char *next;
214 const char *limit;
215};
216
217static void memiter_init(struct memiter *it, const void *data, size_t size)
218{
219 it->next = data;
220 it->limit = it->next + size;
221}
222
223static bool memiter_isspace(struct memiter *it)
224{
225 switch (*it->next) {
226 case ' ':
227 case '\t':
228 case '\n':
229 case '\r':
230 return true;
231 default:
232 return false;
233 }
234}
235
236static void memiter_skip_space(struct memiter *it)
237{
Andrew Scull7364a8e2018-07-19 15:39:29 +0100238 while (it->next < it->limit && memiter_isspace(it)) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100239 it->next++;
Andrew Scull7364a8e2018-07-19 15:39:29 +0100240 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100241}
242
243static bool memiter_iseq(const struct memiter *it, const char *str)
244{
245 size_t len = strlen(str);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100246 if (len != it->limit - it->next) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100247 return false;
Andrew Scull7364a8e2018-07-19 15:39:29 +0100248 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100249 return memcmp(it->next, str, len) == 0;
250}
251
252static bool memiter_parse_str(struct memiter *it, struct memiter *str)
253{
254 /* Skip all white space and fail if we reach the end of the buffer. */
255 memiter_skip_space(it);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100256 if (it->next >= it->limit) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100257 return false;
Andrew Scull7364a8e2018-07-19 15:39:29 +0100258 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100259
260 str->next = it->next;
261
262 /* Find the end of the string. */
Andrew Scull7364a8e2018-07-19 15:39:29 +0100263 while (it->next < it->limit && !memiter_isspace(it)) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100264 it->next++;
Andrew Scull7364a8e2018-07-19 15:39:29 +0100265 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100266
267 str->limit = it->next;
268
269 return true;
270}
271
272static bool memiter_parse_uint(struct memiter *it, uint64_t *value)
273{
274 uint64_t v = 0;
275
276 /* Skip all white space and fail if we reach the end of the buffer. */
277 memiter_skip_space(it);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100278 if (it->next >= it->limit) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100279 return false;
Andrew Scull7364a8e2018-07-19 15:39:29 +0100280 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100281
282 /* Fail if it's not a number. */
Andrew Scull7364a8e2018-07-19 15:39:29 +0100283 if (*it->next < '0' && *it->next > '9') {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100284 return false;
Andrew Scull7364a8e2018-07-19 15:39:29 +0100285 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100286
287 /* Parse the number. */
288 do {
289 v = v * 10 + *it->next - '0';
290 it->next++;
291 } while (it->next < it->limit && *it->next >= '0' && *it->next <= '9');
292
293 *value = v;
294
295 return true;
296}
297
298static bool memiter_find_file(struct cpio *c, const struct memiter *filename,
299 struct memiter *it)
300{
301 const char *fname;
302 const void *fcontents;
303 size_t fsize;
304 struct cpio_iter iter;
305
306 cpio_init_iter(c, &iter);
307
308 while (cpio_next(&iter, &fname, &fcontents, &fsize)) {
309 if (memiter_iseq(filename, fname)) {
310 memiter_init(it, fcontents, fsize);
311 return true;
312 }
313 }
314
315 return false;
316}
317
318static bool find_file(struct cpio *c, const char *name, struct memiter *it)
319{
320 const char *fname;
321 const void *fcontents;
322 size_t fsize;
323 struct cpio_iter iter;
324
325 cpio_init_iter(c, &iter);
326
327 while (cpio_next(&iter, &fname, &fcontents, &fsize)) {
328 if (!strcmp(fname, name)) {
329 memiter_init(it, fcontents, fsize);
330 return true;
331 }
332 }
333
334 return false;
335}
336
Andrew Scull4f170f52018-07-19 12:58:20 +0100337static bool load_secondary(struct cpio *c, uint64_t mem_start,
338 uint64_t *mem_size)
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100339{
340 struct memiter it;
341 struct memiter str;
342 uint64_t mem;
343 uint64_t cpu;
344 uint32_t count;
345
346 if (!find_file(c, "vms.txt", &it)) {
347 dlog("Unable to find vms.txt\n");
348 return false;
349 }
350
Andrew Scull4f170f52018-07-19 12:58:20 +0100351 for (count = 0;
352 memiter_parse_uint(&it, &mem) && memiter_parse_uint(&it, &cpu) &&
353 memiter_parse_str(&it, &str) && count < MAX_VMS;
354 count++) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100355 struct memiter kernel;
356
357 if (!memiter_find_file(c, &str, &kernel)) {
358 dlog("Unable to load kernel for vm %u\n", count);
359 continue;
360 }
361
362 if (mem > *mem_size) {
363 dlog("Not enough memory for vm %u (%u bytes)\n", count,
364 mem);
365 continue;
366 }
367
368 if (mem < kernel.limit - kernel.next) {
Andrew Scull4f170f52018-07-19 12:58:20 +0100369 dlog("Kernel is larger than available memory for vm "
370 "%u\n",
371 count);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100372 continue;
373 }
374
375 *mem_size -= mem;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100376 if (!copy_to_unmaped(mem_start + *mem_size, kernel.next,
377 kernel.limit - kernel.next)) {
378 dlog("Unable to copy kernel for vm %u\n", count);
379 continue;
380 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100381
382 dlog("Loaded VM%u with %u vcpus, entry at 0x%x\n", count, cpu,
383 mem_start + *mem_size);
384 vm_init(secondary_vm + count, cpu);
Andrew Scull4f170f52018-07-19 12:58:20 +0100385 vm_start_vcpu(secondary_vm + count, 0, mem_start + *mem_size, 0,
386 false);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100387 }
388
389 secondary_vm_count = count;
390
391 return true;
392}
393
394static bool load_primary(struct cpio *c, struct fdt_node *chosen)
395{
396 struct memiter it;
397
398 if (!find_file(c, "vmlinuz", &it)) {
399 dlog("Unable to find vmlinuz\n");
400 return false;
401 }
402
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100403 if (!relocate(it.next, it.limit - it.next)) {
404 dlog("Unable to relocate kernel for primary vm.\n");
405 return false;
406 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100407
408 if (!find_file(c, "initrd.img", &it)) {
409 dlog("Unable to find initrd.img\n");
410 return false;
411 }
412
413 /* Patch FDT to point to new ramdisk. */
414 if (!fdt_write_number(chosen, "linux,initrd-start", (size_t)it.next)) {
415 dlog("Unable to write linux,initrd-start\n");
416 return false;
417 }
418
419 if (!fdt_write_number(chosen, "linux,initrd-end", (size_t)it.limit)) {
420 dlog("Unable to write linux,initrd-end\n");
421 return false;
422 }
423
424 /*
425 * Patch fdt to reserve memory.
426 */
427 {
428 size_t tmp = (size_t)&relocate;
429 tmp = (tmp + 0x80000 - 1) & ~(0x80000 - 1);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100430 fdt_add_mem_reservation(fdt, tmp & ~0xfffff, 0x80000);
431 vm_init(&primary_vm, MAX_CPUS);
432 vm_start_vcpu(&primary_vm, 0, tmp, (size_t)fdt, true);
433 }
434
435 return true;
436}
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100437
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100438/**
439 * Performs one-time initialisation of the hypervisor.
440 */
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100441static void one_time_init(void)
442{
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100443 extern char text_begin[];
444 extern char text_end[];
445 extern char rodata_begin[];
446 extern char rodata_end[];
447 extern char data_begin[];
448 extern char data_end[];
449
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100450 dlog("Initializing hafnium\n");
451
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100452 cpu_module_init();
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100453 halloc_init((size_t)ptable_buf, sizeof(ptable_buf));
454
455 if (!mm_ptable_init(&ptable, MM_MODE_NOSYNC | MM_MODE_STAGE1)) {
456 dlog("Unable to allocate memory for page table.\n");
Andrew Scull7364a8e2018-07-19 15:39:29 +0100457 for (;;) {
458 /* do nothing */
459 }
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100460 }
461
462 dlog("text: 0x%x - 0x%x\n", text_begin, text_end);
463 dlog("rodata: 0x%x - 0x%x\n", rodata_begin, rodata_end);
464 dlog("data: 0x%x - 0x%x\n", data_begin, data_end);
465
Andrew Scull4f170f52018-07-19 12:58:20 +0100466 /* Map page for uart. */
467 mm_ptable_map_page(&ptable, PL011_BASE, PL011_BASE,
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100468 MM_MODE_R | MM_MODE_W | MM_MODE_D | MM_MODE_NOSYNC |
Andrew Scull4f170f52018-07-19 12:58:20 +0100469 MM_MODE_STAGE1);
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100470
Andrew Scull4f170f52018-07-19 12:58:20 +0100471 /* Map each section. */
472 mm_ptable_map(&ptable, (vaddr_t)text_begin, (vaddr_t)text_end,
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100473 (paddr_t)text_begin,
474 MM_MODE_X | MM_MODE_NOSYNC | MM_MODE_STAGE1);
475
Andrew Scull4f170f52018-07-19 12:58:20 +0100476 mm_ptable_map(&ptable, (vaddr_t)rodata_begin, (vaddr_t)rodata_end,
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100477 (paddr_t)rodata_begin,
478 MM_MODE_R | MM_MODE_NOSYNC | MM_MODE_STAGE1);
479
Andrew Scull4f170f52018-07-19 12:58:20 +0100480 mm_ptable_map(&ptable, (vaddr_t)data_begin, (vaddr_t)data_end,
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100481 (paddr_t)data_begin,
482 MM_MODE_R | MM_MODE_W | MM_MODE_NOSYNC | MM_MODE_STAGE1);
483
484 arch_mm_init((paddr_t)ptable.table);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100485
486 /* TODO: Code below this point should be removed from this function. */
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100487 do {
488 struct fdt_node n;
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100489 uint64_t mem_start = 0;
490 uint64_t mem_size = 0;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100491 uint64_t new_mem_size;
492
493 /* Map in the fdt header. */
494 if (!mm_ptable_map(&ptable, (vaddr_t)fdt,
495 (vaddr_t)fdt + fdt_header_size(),
Andrew Scull4f170f52018-07-19 12:58:20 +0100496 (paddr_t)fdt, MM_MODE_R | MM_MODE_STAGE1)) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100497 dlog("Unable to map FDT header.\n");
498 break;
499 }
500
501 /*
502 * Map the rest of the fdt plus an extra page for adding new
503 * memory reservations.
504 */
505 if (!mm_ptable_map(&ptable, (vaddr_t)fdt,
506 (vaddr_t)fdt + fdt_total_size(fdt),
Andrew Scull4f170f52018-07-19 12:58:20 +0100507 (paddr_t)fdt, MM_MODE_R | MM_MODE_STAGE1)) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100508 dlog("Unable to map FDT.\n");
509 break;
510 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100511
512 fdt_root_node(&n, fdt);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100513 fdt_find_child(&n, "");
514
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100515 find_memory_range(&n, &mem_start, &mem_size);
516 dlog("Memory range: 0x%x - 0x%x\n", mem_start,
517 mem_start + mem_size - 1);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100518
519 uint64_t begin;
520 uint64_t end;
521
Andrew Scull7364a8e2018-07-19 15:39:29 +0100522 if (!find_initrd(&n, &begin, &end)) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100523 break;
Andrew Scull7364a8e2018-07-19 15:39:29 +0100524 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100525
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100526 dlog("Ramdisk range: 0x%x - 0x%x\n", begin, end - 1);
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100527 mm_ptable_map(&ptable, begin, end, begin,
528 MM_MODE_R | MM_MODE_STAGE1);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100529
530 struct cpio c;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100531 cpio_init(&c, (void *)begin, end - begin);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100532
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100533 /* Map the fdt in r/w mode in preparation for extending it. */
Andrew Scull4f170f52018-07-19 12:58:20 +0100534 if (!mm_ptable_map(
535 &ptable, (vaddr_t)fdt,
536 (vaddr_t)fdt + fdt_total_size(fdt) + PAGE_SIZE,
537 (paddr_t)fdt,
538 MM_MODE_R | MM_MODE_W | MM_MODE_STAGE1)) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100539 dlog("Unable to map FDT in r/w mode.\n");
540 break;
541 }
542 new_mem_size = mem_size;
543 load_secondary(&c, mem_start, &new_mem_size);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100544 load_primary(&c, &n);
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100545
546 /* Patch fdt to reserve memory for secondary VMs. */
547 fdt_add_mem_reservation(fdt, mem_start + new_mem_size,
548 mem_size - new_mem_size);
549
550 /* Unmap FDT. */
Andrew Scull4f170f52018-07-19 12:58:20 +0100551 if (!mm_ptable_unmap(
552 &ptable, (vaddr_t)fdt,
553 (vaddr_t)fdt + fdt_total_size(fdt) + PAGE_SIZE,
554 MM_MODE_STAGE1)) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100555 dlog("Unable to unmap the FDT.\n");
556 break;
557 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100558 } while (0);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100559
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100560 mm_ptable_defrag(&ptable);
561
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100562 arch_set_vm_mm(&primary_vm.page_table);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100563}
564
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100565/**
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100566 * The entry point of CPUs when they are turned on. It is supposed to initialise
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100567 * all state and return the first vCPU to run.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100568 */
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100569struct vcpu *cpu_main(void)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100570{
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100571 struct cpu *c = cpu();
572
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100573 /* Do global one-time initialization just once. We avoid using atomics
574 * by only touching the variable from cpu 0. */
575 static volatile bool inited = false;
576 if (cpu_index(c) == 0 && !inited) {
577 inited = true;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100578 one_time_init();
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100579 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100580
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100581 dlog("Starting up cpu %d\n", cpu_index(c));
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100582
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100583 return primary_vm.vcpus + cpu_index(c);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100584}