blob: 39de7d1b179134c36e22d2247f547889cf7178a7 [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);
114 vm_init(&primary_vm, MAX_CPUS);
115 vm_start_vcpu(&primary_vm, 0, tmp, kernel_arg, true);
116 }
117
118 arch_set_vm_mm(&primary_vm.page_table);
119
120 return true;
121}
122
123/**
124 * Loads all secondary VMs in the given memory range. "mem_end" is updated to
125 * reflect the fact that some of the memory isn't available to the primary VM
126 * anymore.
127 */
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +0100128bool load_secondary(const struct memiter *cpio, uint64_t mem_begin,
129 uint64_t *mem_end)
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100130{
131 struct memiter it;
132 struct memiter str;
133 uint64_t mem;
134 uint64_t cpu;
135 uint32_t count;
136
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +0100137 if (!find_file(cpio, "vms.txt", &it)) {
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100138 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
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +0100148 if (!memiter_find_file(cpio, &str, &kernel)) {
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100149 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}