blob: e7639f521db4293122b11ccfbbdc969ee23b630d [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) {
21 if (!fdt_find_child(node, path))
22 return false;
23 path += strlen(path);
24 }
25
26 return true;
27}
28
Wedson Almeida Filho87009642018-07-02 10:20:07 +010029static uint64_t convert_number(const char *data, uint32_t size)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010030{
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010031 union {
32 volatile uint64_t v;
33 char a[8];
34 } t;
35
Wedson Almeida Filho87009642018-07-02 10:20:07 +010036 switch (size) {
37 case sizeof(uint32_t):
Andrew Scull29d40392018-07-16 11:46:59 +010038 return be32toh(*(uint32_t *)data);
Wedson Almeida Filho87009642018-07-02 10:20:07 +010039 case sizeof(uint64_t):
40 memcpy(t.a, data, sizeof(uint64_t));
Andrew Scull29d40392018-07-16 11:46:59 +010041 return be64toh(t.v);
Wedson Almeida Filho87009642018-07-02 10:20:07 +010042 default:
43 return 0;
44 }
45}
46
47static bool fdt_read_number(const struct fdt_node *node, const char *name,
Andrew Scull4f170f52018-07-19 12:58:20 +010048 uint64_t *value)
Wedson Almeida Filho87009642018-07-02 10:20:07 +010049{
50 const char *data;
51 uint32_t size;
52
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010053 if (!fdt_read_property(node, name, &data, &size))
54 return false;
55
56 switch (size) {
57 case sizeof(uint32_t):
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010058 case sizeof(uint64_t):
Wedson Almeida Filho87009642018-07-02 10:20:07 +010059 *value = convert_number(data, size);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010060 break;
61
62 default:
63 return false;
64 }
65
66 return true;
67}
68
69bool fdt_write_number(struct fdt_node *node, const char *name, uint64_t value)
70{
71 const char *data;
72 uint32_t size;
73 union {
74 volatile uint64_t v;
75 char a[8];
76 } t;
77
78 if (!fdt_read_property(node, name, &data, &size))
79 return false;
80
81 switch (size) {
82 case sizeof(uint32_t):
Andrew Scull29d40392018-07-16 11:46:59 +010083 *(uint32_t *)data = be32toh(value);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010084 break;
85
86 case sizeof(uint64_t):
Andrew Scull29d40392018-07-16 11:46:59 +010087 t.v = be64toh(value);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010088 memcpy((void *)data, t.a, sizeof(uint64_t));
89 break;
90
91 default:
92 return false;
93 }
94
95 return true;
96}
97
Wedson Almeida Filhofed69022018-07-11 15:39:12 +010098/**
99 * Copies data to an unmapped location by mapping it for write, copying the
100 * data, then unmapping it.
101 */
102static bool copy_to_unmaped(paddr_t to, const void *from, size_t size)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100103{
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100104 if (!mm_ptable_map(&ptable, (vaddr_t)to, (vaddr_t)to + size, to,
105 MM_MODE_W | MM_MODE_STAGE1))
106 return false;
107
108 memcpy((void *)to, from, size);
109
110 mm_ptable_unmap(&ptable, to, to + size, MM_MODE_STAGE1);
111
112 return true;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100113}
114
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100115static bool relocate(const char *from, size_t size)
116{
117 /* TODO: This is a hack. We must read the alignment from the binary. */
118 extern char bin_end[];
119 size_t tmp = (size_t)&bin_end[0];
120 paddr_t dest = (tmp + 0x80000 - 1) & ~(0x80000 - 1);
121 dlog("bin_end is at %p, copying to %p\n", &bin_end[0], dest);
122 return copy_to_unmaped(dest, from, size);
123}
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100124
125static void find_memory_range(const struct fdt_node *root,
126 uint64_t *block_start, uint64_t *block_size)
127{
128 struct fdt_node n = *root;
129 const char *name;
130 uint64_t address_size;
131 uint64_t size_size;
132 uint64_t entry_size;
133
134 /* Get the sizes of memory range addresses and sizes. */
135 if (fdt_read_number(&n, "#address-cells", &address_size))
136 address_size *= sizeof(uint32_t);
137 else
138 address_size = sizeof(uint32_t);
139
140 if (fdt_read_number(&n, "#size-cells", &size_size))
141 size_size *= sizeof(uint32_t);
142 else
143 size_size = sizeof(uint32_t);
144
145 entry_size = address_size + size_size;
146
147 /* Look for nodes with the device_type set to "memory". */
148 if (!fdt_first_child(&n, &name))
149 return;
150
151 do {
152 const char *data;
153 uint32_t size;
154 if (!fdt_read_property(&n, "device_type", &data, &size) ||
155 size != sizeof("memory") ||
156 memcmp(data, "memory", sizeof("memory")) != 0 ||
157 !fdt_read_property(&n, "reg", &data, &size)) {
158 continue;
159 }
160
161 /* Traverse all memory ranges within this node. */
162 while (size >= entry_size) {
163 uint64_t addr = convert_number(data, address_size);
Andrew Scull4f170f52018-07-19 12:58:20 +0100164 uint64_t len =
165 convert_number(data + address_size, size_size);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100166
167 if (len > *block_size) {
168 /* Remember the largest range we've found. */
169 *block_start = addr;
170 *block_size = len;
171 }
172
173 size -= entry_size;
174 data += entry_size;
175 }
176 } while (fdt_next_sibling(&n, &name));
177
178 /* TODO: Check for "reserved-memory" nodes. */
179}
180
181/**
182 * Finds the memory region where initrd is stored, and udpates the fdt node
183 * cursor to the node called "chosen".
184 */
185static bool find_initrd(struct fdt_node *n, uint64_t *begin, uint64_t *end)
186{
187 if (!fdt_find_node(n, "chosen\0")) {
188 dlog("Unable to find 'chosen'\n");
189 return false;
190 }
191
192 if (!fdt_read_number(n, "linux,initrd-start", begin)) {
193 dlog("Unable to read linux,initrd-start\n");
194 return false;
195 }
196
197 if (!fdt_read_number(n, "linux,initrd-end", end)) {
198 dlog("Unable to read linux,initrd-end\n");
199 return false;
200 }
201
202 return true;
203}
204
205struct memiter {
206 const char *next;
207 const char *limit;
208};
209
210static void memiter_init(struct memiter *it, const void *data, size_t size)
211{
212 it->next = data;
213 it->limit = it->next + size;
214}
215
216static bool memiter_isspace(struct memiter *it)
217{
218 switch (*it->next) {
219 case ' ':
220 case '\t':
221 case '\n':
222 case '\r':
223 return true;
224 default:
225 return false;
226 }
227}
228
229static void memiter_skip_space(struct memiter *it)
230{
231 while (it->next < it->limit && memiter_isspace(it))
232 it->next++;
233}
234
235static bool memiter_iseq(const struct memiter *it, const char *str)
236{
237 size_t len = strlen(str);
238 if (len != it->limit - it->next)
239 return false;
240 return memcmp(it->next, str, len) == 0;
241}
242
243static bool memiter_parse_str(struct memiter *it, struct memiter *str)
244{
245 /* Skip all white space and fail if we reach the end of the buffer. */
246 memiter_skip_space(it);
247 if (it->next >= it->limit)
248 return false;
249
250 str->next = it->next;
251
252 /* Find the end of the string. */
253 while (it->next < it->limit && !memiter_isspace(it))
254 it->next++;
255
256 str->limit = it->next;
257
258 return true;
259}
260
261static bool memiter_parse_uint(struct memiter *it, uint64_t *value)
262{
263 uint64_t v = 0;
264
265 /* Skip all white space and fail if we reach the end of the buffer. */
266 memiter_skip_space(it);
267 if (it->next >= it->limit)
268 return false;
269
270 /* Fail if it's not a number. */
271 if (*it->next < '0' && *it->next > '9')
272 return false;
273
274 /* Parse the number. */
275 do {
276 v = v * 10 + *it->next - '0';
277 it->next++;
278 } while (it->next < it->limit && *it->next >= '0' && *it->next <= '9');
279
280 *value = v;
281
282 return true;
283}
284
285static bool memiter_find_file(struct cpio *c, const struct memiter *filename,
286 struct memiter *it)
287{
288 const char *fname;
289 const void *fcontents;
290 size_t fsize;
291 struct cpio_iter iter;
292
293 cpio_init_iter(c, &iter);
294
295 while (cpio_next(&iter, &fname, &fcontents, &fsize)) {
296 if (memiter_iseq(filename, fname)) {
297 memiter_init(it, fcontents, fsize);
298 return true;
299 }
300 }
301
302 return false;
303}
304
305static bool find_file(struct cpio *c, const char *name, struct memiter *it)
306{
307 const char *fname;
308 const void *fcontents;
309 size_t fsize;
310 struct cpio_iter iter;
311
312 cpio_init_iter(c, &iter);
313
314 while (cpio_next(&iter, &fname, &fcontents, &fsize)) {
315 if (!strcmp(fname, name)) {
316 memiter_init(it, fcontents, fsize);
317 return true;
318 }
319 }
320
321 return false;
322}
323
Andrew Scull4f170f52018-07-19 12:58:20 +0100324static bool load_secondary(struct cpio *c, uint64_t mem_start,
325 uint64_t *mem_size)
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100326{
327 struct memiter it;
328 struct memiter str;
329 uint64_t mem;
330 uint64_t cpu;
331 uint32_t count;
332
333 if (!find_file(c, "vms.txt", &it)) {
334 dlog("Unable to find vms.txt\n");
335 return false;
336 }
337
Andrew Scull4f170f52018-07-19 12:58:20 +0100338 for (count = 0;
339 memiter_parse_uint(&it, &mem) && memiter_parse_uint(&it, &cpu) &&
340 memiter_parse_str(&it, &str) && count < MAX_VMS;
341 count++) {
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100342 struct memiter kernel;
343
344 if (!memiter_find_file(c, &str, &kernel)) {
345 dlog("Unable to load kernel for vm %u\n", count);
346 continue;
347 }
348
349 if (mem > *mem_size) {
350 dlog("Not enough memory for vm %u (%u bytes)\n", count,
351 mem);
352 continue;
353 }
354
355 if (mem < kernel.limit - kernel.next) {
Andrew Scull4f170f52018-07-19 12:58:20 +0100356 dlog("Kernel is larger than available memory for vm "
357 "%u\n",
358 count);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100359 continue;
360 }
361
362 *mem_size -= mem;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100363 if (!copy_to_unmaped(mem_start + *mem_size, kernel.next,
364 kernel.limit - kernel.next)) {
365 dlog("Unable to copy kernel for vm %u\n", count);
366 continue;
367 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100368
369 dlog("Loaded VM%u with %u vcpus, entry at 0x%x\n", count, cpu,
370 mem_start + *mem_size);
371 vm_init(secondary_vm + count, cpu);
Andrew Scull4f170f52018-07-19 12:58:20 +0100372 vm_start_vcpu(secondary_vm + count, 0, mem_start + *mem_size, 0,
373 false);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100374 }
375
376 secondary_vm_count = count;
377
378 return true;
379}
380
381static bool load_primary(struct cpio *c, struct fdt_node *chosen)
382{
383 struct memiter it;
384
385 if (!find_file(c, "vmlinuz", &it)) {
386 dlog("Unable to find vmlinuz\n");
387 return false;
388 }
389
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100390 if (!relocate(it.next, it.limit - it.next)) {
391 dlog("Unable to relocate kernel for primary vm.\n");
392 return false;
393 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100394
395 if (!find_file(c, "initrd.img", &it)) {
396 dlog("Unable to find initrd.img\n");
397 return false;
398 }
399
400 /* Patch FDT to point to new ramdisk. */
401 if (!fdt_write_number(chosen, "linux,initrd-start", (size_t)it.next)) {
402 dlog("Unable to write linux,initrd-start\n");
403 return false;
404 }
405
406 if (!fdt_write_number(chosen, "linux,initrd-end", (size_t)it.limit)) {
407 dlog("Unable to write linux,initrd-end\n");
408 return false;
409 }
410
411 /*
412 * Patch fdt to reserve memory.
413 */
414 {
415 size_t tmp = (size_t)&relocate;
416 tmp = (tmp + 0x80000 - 1) & ~(0x80000 - 1);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100417 fdt_add_mem_reservation(fdt, tmp & ~0xfffff, 0x80000);
418 vm_init(&primary_vm, MAX_CPUS);
419 vm_start_vcpu(&primary_vm, 0, tmp, (size_t)fdt, true);
420 }
421
422 return true;
423}
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100424
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100425/**
426 * Performs one-time initialisation of the hypervisor.
427 */
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100428static void one_time_init(void)
429{
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100430 extern char text_begin[];
431 extern char text_end[];
432 extern char rodata_begin[];
433 extern char rodata_end[];
434 extern char data_begin[];
435 extern char data_end[];
436
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100437 dlog("Initializing hafnium\n");
438
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100439 cpu_module_init();
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100440 halloc_init((size_t)ptable_buf, sizeof(ptable_buf));
441
442 if (!mm_ptable_init(&ptable, MM_MODE_NOSYNC | MM_MODE_STAGE1)) {
443 dlog("Unable to allocate memory for page table.\n");
Andrew Scull4f170f52018-07-19 12:58:20 +0100444 for (;;)
445 ;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100446 }
447
448 dlog("text: 0x%x - 0x%x\n", text_begin, text_end);
449 dlog("rodata: 0x%x - 0x%x\n", rodata_begin, rodata_end);
450 dlog("data: 0x%x - 0x%x\n", data_begin, data_end);
451
Andrew Scull4f170f52018-07-19 12:58:20 +0100452 /* Map page for uart. */
453 mm_ptable_map_page(&ptable, PL011_BASE, PL011_BASE,
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100454 MM_MODE_R | MM_MODE_W | MM_MODE_D | MM_MODE_NOSYNC |
Andrew Scull4f170f52018-07-19 12:58:20 +0100455 MM_MODE_STAGE1);
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100456
Andrew Scull4f170f52018-07-19 12:58:20 +0100457 /* Map each section. */
458 mm_ptable_map(&ptable, (vaddr_t)text_begin, (vaddr_t)text_end,
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100459 (paddr_t)text_begin,
460 MM_MODE_X | MM_MODE_NOSYNC | MM_MODE_STAGE1);
461
Andrew Scull4f170f52018-07-19 12:58:20 +0100462 mm_ptable_map(&ptable, (vaddr_t)rodata_begin, (vaddr_t)rodata_end,
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100463 (paddr_t)rodata_begin,
464 MM_MODE_R | MM_MODE_NOSYNC | MM_MODE_STAGE1);
465
Andrew Scull4f170f52018-07-19 12:58:20 +0100466 mm_ptable_map(&ptable, (vaddr_t)data_begin, (vaddr_t)data_end,
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100467 (paddr_t)data_begin,
468 MM_MODE_R | MM_MODE_W | MM_MODE_NOSYNC | MM_MODE_STAGE1);
469
470 arch_mm_init((paddr_t)ptable.table);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100471
472 /* TODO: Code below this point should be removed from this function. */
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100473 do {
474 struct fdt_node n;
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100475 uint64_t mem_start = 0;
476 uint64_t mem_size = 0;
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100477 uint64_t new_mem_size;
478
479 /* Map in the fdt header. */
480 if (!mm_ptable_map(&ptable, (vaddr_t)fdt,
481 (vaddr_t)fdt + fdt_header_size(),
Andrew Scull4f170f52018-07-19 12:58:20 +0100482 (paddr_t)fdt, MM_MODE_R | MM_MODE_STAGE1)) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100483 dlog("Unable to map FDT header.\n");
484 break;
485 }
486
487 /*
488 * Map the rest of the fdt plus an extra page for adding new
489 * memory reservations.
490 */
491 if (!mm_ptable_map(&ptable, (vaddr_t)fdt,
492 (vaddr_t)fdt + fdt_total_size(fdt),
Andrew Scull4f170f52018-07-19 12:58:20 +0100493 (paddr_t)fdt, MM_MODE_R | MM_MODE_STAGE1)) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100494 dlog("Unable to map FDT.\n");
495 break;
496 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100497
498 fdt_root_node(&n, fdt);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100499 fdt_find_child(&n, "");
500
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100501 find_memory_range(&n, &mem_start, &mem_size);
502 dlog("Memory range: 0x%x - 0x%x\n", mem_start,
503 mem_start + mem_size - 1);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100504
505 uint64_t begin;
506 uint64_t end;
507
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100508 if (!find_initrd(&n, &begin, &end))
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100509 break;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100510
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100511 dlog("Ramdisk range: 0x%x - 0x%x\n", begin, end - 1);
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100512 mm_ptable_map(&ptable, begin, end, begin,
513 MM_MODE_R | MM_MODE_STAGE1);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100514
515 struct cpio c;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100516 cpio_init(&c, (void *)begin, end - begin);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100517
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100518 /* Map the fdt in r/w mode in preparation for extending it. */
Andrew Scull4f170f52018-07-19 12:58:20 +0100519 if (!mm_ptable_map(
520 &ptable, (vaddr_t)fdt,
521 (vaddr_t)fdt + fdt_total_size(fdt) + PAGE_SIZE,
522 (paddr_t)fdt,
523 MM_MODE_R | MM_MODE_W | MM_MODE_STAGE1)) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100524 dlog("Unable to map FDT in r/w mode.\n");
525 break;
526 }
527 new_mem_size = mem_size;
528 load_secondary(&c, mem_start, &new_mem_size);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100529 load_primary(&c, &n);
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100530
531 /* Patch fdt to reserve memory for secondary VMs. */
532 fdt_add_mem_reservation(fdt, mem_start + new_mem_size,
533 mem_size - new_mem_size);
534
535 /* Unmap FDT. */
Andrew Scull4f170f52018-07-19 12:58:20 +0100536 if (!mm_ptable_unmap(
537 &ptable, (vaddr_t)fdt,
538 (vaddr_t)fdt + fdt_total_size(fdt) + PAGE_SIZE,
539 MM_MODE_STAGE1)) {
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100540 dlog("Unable to unmap the FDT.\n");
541 break;
542 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100543 } while (0);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100544
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100545 mm_ptable_defrag(&ptable);
546
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100547 arch_set_vm_mm(&primary_vm.page_table);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100548}
549
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100550/**
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100551 * The entry point of CPUs when they are turned on. It is supposed to initialise
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100552 * all state and return the first vCPU to run.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100553 */
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100554struct vcpu *cpu_main(void)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100555{
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100556 struct cpu *c = cpu();
557
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100558 /* Do global one-time initialization just once. We avoid using atomics
559 * by only touching the variable from cpu 0. */
560 static volatile bool inited = false;
561 if (cpu_index(c) == 0 && !inited) {
562 inited = true;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100563 one_time_init();
Wedson Almeida Filhofed69022018-07-11 15:39:12 +0100564 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100565
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100566 dlog("Starting up cpu %d\n", cpu_index(c));
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100567
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100568 return primary_vm.vcpus + cpu_index(c);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100569}