blob: 346c79818ff1f35bf1e7c6559af555e87a27e374 [file] [log] [blame]
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +01001#include <stdalign.h>
2#include <stdatomic.h>
3#include <stddef.h>
4
5#include "cpio.h"
6#include "cpu.h"
7#include "dlog.h"
8#include "fdt.h"
9#include "irq.h"
10#include "std.h"
11#include "timer.h"
12#include "vm.h"
13
14void *fdt;
15
16/* The stack to be used by the CPUs. */
17alignas(2 * sizeof(size_t)) char callstacks[STACK_SIZE * MAX_CPUS];
18
19/* State of all supported CPUs. The stack of the first one is initialized. */
20struct cpu cpus[MAX_CPUS] = {
21 {
22 .cpu_on_count = 1,
23 .stack_bottom = callstacks + STACK_SIZE,
24 },
25};
26
27bool fdt_find_node(struct fdt_node *node, const char *path)
28{
29 if (!fdt_find_child(node, ""))
30 return false;
31
32 while (*path) {
33 if (!fdt_find_child(node, path))
34 return false;
35 path += strlen(path);
36 }
37
38 return true;
39}
40
41bool fdt_read_number(struct fdt_node *node, const char *name, uint64_t *value)
42{
43 const char *data;
44 uint32_t size;
45 union {
46 volatile uint64_t v;
47 char a[8];
48 } t;
49
50 if (!fdt_read_property(node, name, &data, &size))
51 return false;
52
53 switch (size) {
54 case sizeof(uint32_t):
55 *value = ntohl(*(uint32_t *)data);
56 break;
57
58 case sizeof(uint64_t):
59 memcpy(t.a, data, sizeof(uint64_t));
60 *value = ntohll(t.v);
61 break;
62
63 default:
64 return false;
65 }
66
67 return true;
68}
69
70bool fdt_write_number(struct fdt_node *node, const char *name, uint64_t value)
71{
72 const char *data;
73 uint32_t size;
74 union {
75 volatile uint64_t v;
76 char a[8];
77 } t;
78
79 if (!fdt_read_property(node, name, &data, &size))
80 return false;
81
82 switch (size) {
83 case sizeof(uint32_t):
84 *(uint32_t *)data = ntohl(value);
85 break;
86
87 case sizeof(uint64_t):
88 t.v = ntohll(value);
89 memcpy((void *)data, t.a, sizeof(uint64_t));
90 break;
91
92 default:
93 return false;
94 }
95
96 return true;
97}
98
99static void relocate(const char *from, size_t size)
100{
101 extern char bin_end[];
102 size_t tmp = (size_t)&bin_end[0];
103 char *dest = (char *)((tmp + 0x80000 - 1) & ~(0x80000 - 1));
104 dlog("bin_end is at %p, copying to %p\n", &bin_end[0], dest);
105 memcpy(dest, from, size);
106}
107
108/* TODO: Remove this. */
109struct vm vm0;
110
111static void one_time_init(void)
112{
113 size_t i;
114
115 dlog("Initializing hafnium\n");
116
117 /*
118 * TODO: Re-enable this.
119 irq_init();
120 timer_init();
121 */
122
123 /* Initialize all CPUs. */
124 for (i = 0; i < MAX_CPUS; i++) {
125 struct cpu *c = cpus + i;
126 cpu_init(c);
127 c->id = i; /* TODO: Initialize ID. */
128 c->stack_bottom = callstacks + STACK_SIZE * (i + 1);
129 }
130
131 /* TODO: Code below this point should be removed from this function. */
132 /* TODO: Remove this. */
133
134 do {
135 struct fdt_node n;
136
137 fdt_root_node(&n, fdt);
138 if (!fdt_find_node(&n, "chosen\0")) {
139 dlog("Unable to find 'chosen'\n");
140 break;
141 }
142
143 uint64_t begin;
144 uint64_t end;
145
146 if (!fdt_read_number(&n, "linux,initrd-start", &begin)) {
147 dlog("Unable to read linux,initrd-start\n");
148 break;
149 }
150
151 if (!fdt_read_number(&n, "linux,initrd-end", &end)) {
152 dlog("Unable to read linux,initrd-end\n");
153 break;
154 }
155
156 dlog("Ramdisk: from %x to %x\n", begin, end);
157
158 struct cpio c;
159 struct cpio_iter iter;
160 cpio_init(&c, (void *)begin, end - begin);
161 cpio_init_iter(&c, &iter);
162
163 const char *name;
164 const void *fcontents;
165 size_t ramdisk = 0;
166 size_t ramdisk_end = 0;
167 size_t fsize;
168 while (cpio_next(&iter, &name, &fcontents, &fsize)) {
169 dlog("File: %s, size=%u\n", name, fsize);
170 if (!strcmp(name, "vm/vmlinuz")) {
171 relocate(fcontents, fsize);
172 continue;
173 }
174
175 if (!strcmp(name, "vm/initrd.img")) {
176 dlog("Found vm/ramdisk @ %p, %u bytes\n", fcontents, fsize);
177 ramdisk = (size_t)fcontents;
178 ramdisk_end = ramdisk + fsize;
179 continue;
180 }
181 }
182
183 dlog("Ramdisk; %p\n", ramdisk);
184
185 /* Patch FDT to point to new ramdisk. */
186 if (!fdt_write_number(&n, "linux,initrd-start", ramdisk)) {
187 dlog("Unable to write linux,initrd-start\n");
188 break;
189 }
190
191 if (!fdt_write_number(&n, "linux,initrd-end", ramdisk_end)) {
192 dlog("Unable to write linux,initrd-end\n");
193 break;
194 }
195
196 /*
197 * Patch fdt to point remove memory.
198 */
199 {
200 size_t tmp = (size_t)&relocate;
201 tmp = (tmp + 0x80000 - 1) & ~(0x80000 - 1);
202
203
204 fdt_add_mem_reservation(fdt, tmp & ~0xfffff, 0x80000);
205 vm_init(&vm0, cpus);
206 vm_start_vcpu(&vm0, 0, tmp, (size_t)fdt);
207 }
208 } while (0);
209}
210
211/*
212 * The entry point of CPUs when they are turned on. It is supposed to initialise
213 * all state and return; the caller will ensure that the next vcpu runs.
214 */
215void cpu_main(void)
216{
217 /* Do global one-time initialization just once. */
218 static atomic_flag inited = ATOMIC_FLAG_INIT;
219 if (!atomic_flag_test_and_set_explicit(&inited, memory_order_acq_rel))
220 one_time_init();
221
222 dlog("Starting up cpu %d\n", cpu() - cpus);
223
224 /* Do per-cpu initialization. */
225 /* TODO: What to do here? */
226 /*
227 irq_init_percpu();
228 timer_init_percpu();
229 */
230}