blob: e0949d67cb8801756bad5c473e368df59aa19240 [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 */
47static bool memiter_find_file(struct cpio *c, const struct memiter *filename,
48 struct memiter *it)
49{
50 const char *fname;
51 const void *fcontents;
52 size_t fsize;
53 struct cpio_iter iter;
54
55 cpio_init_iter(c, &iter);
56
57 while (cpio_next(&iter, &fname, &fcontents, &fsize)) {
58 if (memiter_iseq(filename, fname)) {
59 memiter_init(it, fcontents, fsize);
60 return true;
61 }
62 }
63
64 return false;
65}
66
67/**
68 * Looks for a file in the given cpio archive. The file, if found, is returned
69 * in the "it" argument.
70 */
71static bool find_file(struct cpio *c, const char *name, struct memiter *it)
72{
73 const char *fname;
74 const void *fcontents;
75 size_t fsize;
76 struct cpio_iter iter;
77
78 cpio_init_iter(c, &iter);
79
80 while (cpio_next(&iter, &fname, &fcontents, &fsize)) {
81 if (!strcmp(fname, name)) {
82 memiter_init(it, fcontents, fsize);
83 return true;
84 }
85 }
86
87 return false;
88}
89
90/**
91 * Loads the primary VM.
92 */
93bool load_primary(struct cpio *c, size_t kernel_arg, struct memiter *initrd)
94{
95 struct memiter it;
96
97 if (!find_file(c, "vmlinuz", &it)) {
98 dlog("Unable to find vmlinuz\n");
99 return false;
100 }
101
102 if (!relocate(it.next, it.limit - it.next)) {
103 dlog("Unable to relocate kernel for primary vm.\n");
104 return false;
105 }
106
107 if (!find_file(c, "initrd.img", initrd)) {
108 dlog("Unable to find initrd.img\n");
109 return false;
110 }
111
112 {
113 size_t tmp = (size_t)&load_primary;
114 tmp = (tmp + 0x80000 - 1) & ~(0x80000 - 1);
115 vm_init(&primary_vm, MAX_CPUS);
116 vm_start_vcpu(&primary_vm, 0, tmp, kernel_arg, true);
117 }
118
119 arch_set_vm_mm(&primary_vm.page_table);
120
121 return true;
122}
123
124/**
125 * Loads all secondary VMs in the given memory range. "mem_end" is updated to
126 * reflect the fact that some of the memory isn't available to the primary VM
127 * anymore.
128 */
129bool load_secondary(struct cpio *c, uint64_t mem_begin, uint64_t *mem_end)
130{
131 struct memiter it;
132 struct memiter str;
133 uint64_t mem;
134 uint64_t cpu;
135 uint32_t count;
136
137 if (!find_file(c, "vms.txt", &it)) {
138 dlog("vms.txt is missing\n");
139 return true;
140 }
141
142 for (count = 0;
143 memiter_parse_uint(&it, &mem) && memiter_parse_uint(&it, &cpu) &&
144 memiter_parse_str(&it, &str) && count < MAX_VMS;
145 count++) {
146 struct memiter kernel;
147
148 if (!memiter_find_file(c, &str, &kernel)) {
149 dlog("Unable to load kernel for vm %u\n", count);
150 continue;
151 }
152
153 if (mem > *mem_end - mem_begin) {
154 dlog("Not enough memory for vm %u (%u bytes)\n", count,
155 mem);
156 continue;
157 }
158
159 if (mem < kernel.limit - kernel.next) {
160 dlog("Kernel is larger than available memory for vm "
161 "%u\n",
162 count);
163 continue;
164 }
165
166 *mem_end -= mem;
167 if (!copy_to_unmaped(*mem_end, kernel.next,
168 kernel.limit - kernel.next)) {
169 dlog("Unable to copy kernel for vm %u\n", count);
170 continue;
171 }
172
173 dlog("Loaded VM%u with %u vcpus, entry at 0x%x\n", count, cpu,
174 *mem_end);
175
176 /* TODO: Update page table to reflect the memory range. */
177 vm_init(secondary_vm + count, cpu);
178 vm_start_vcpu(secondary_vm + count, 0, *mem_end, 0, false);
179 }
180
181 secondary_vm_count = count;
182
183 return true;
184}