1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2022 The FreeBSD Foundation
5 *
6 * This software was developed by Andrew Turner under sponsorship from
7 * the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/param.h>
32
33 #include <assert.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <unistd.h>
37
38 #include <libfdt.h>
39 #include <vmmapi.h>
40
41 #include "config.h"
42 #include "bhyve_machdep.h"
43 #include "bhyverun.h"
44 #include "fdt.h"
45
46 #define SET_PROP_U32(prop, idx, val) \
47 ((uint32_t *)(prop))[(idx)] = cpu_to_fdt32(val)
48 #define SET_PROP_U64(prop, idx, val) \
49 ((uint64_t *)(prop))[(idx)] = cpu_to_fdt64(val)
50
51 #define GIC_SPI 0
52 #define GIC_PPI 1
53 #define IRQ_TYPE_LEVEL_HIGH 4
54 #define IRQ_TYPE_LEVEL_LOW 8
55
56 #define GIC_FIRST_PPI 16
57 #define GIC_FIRST_SPI 32
58
59 static void *fdtroot;
60 static uint32_t gic_phandle = 0;
61 static uint32_t apb_pclk_phandle;
62
63 static uint32_t
assign_phandle(void * fdt)64 assign_phandle(void *fdt)
65 {
66 static uint32_t next_phandle = 1;
67 uint32_t phandle;
68
69 phandle = next_phandle;
70 next_phandle++;
71 fdt_property_u32(fdt, "phandle", phandle);
72
73 return (phandle);
74 }
75
76 static void
set_single_reg(void * fdt,uint64_t start,uint64_t len)77 set_single_reg(void *fdt, uint64_t start, uint64_t len)
78 {
79 void *reg;
80
81 fdt_property_placeholder(fdt, "reg", 2 * sizeof(uint64_t), ®);
82 SET_PROP_U64(reg, 0, start);
83 SET_PROP_U64(reg, 1, len);
84 }
85
86 static void
add_cpu(void * fdt,int cpuid)87 add_cpu(void *fdt, int cpuid)
88 {
89 char node_name[16];
90
91 snprintf(node_name, sizeof(node_name), "cpu@%d", cpuid);
92
93 fdt_begin_node(fdt, node_name);
94 fdt_property_string(fdt, "device_type", "cpu");
95 fdt_property_string(fdt, "compatible", "arm,armv8");
96 fdt_property_u64(fdt, "reg", cpu_to_mpidr[cpuid]);
97 fdt_property_string(fdt, "enable-method", "psci");
98 fdt_end_node(fdt);
99 }
100
101 static void
add_cpus(void * fdt,int ncpu)102 add_cpus(void *fdt, int ncpu)
103 {
104 int cpuid;
105
106 fdt_begin_node(fdt, "cpus");
107 /* XXX: Needed given the root #address-cells? */
108 fdt_property_u32(fdt, "#address-cells", 2);
109 fdt_property_u32(fdt, "#size-cells", 0);
110
111 for (cpuid = 0; cpuid < ncpu; cpuid++) {
112 add_cpu(fdt, cpuid);
113 }
114 fdt_end_node(fdt);
115 }
116
117 int
fdt_init(struct vmctx * ctx,int ncpu,vm_paddr_t fdtaddr,vm_size_t fdtsize)118 fdt_init(struct vmctx *ctx, int ncpu, vm_paddr_t fdtaddr, vm_size_t fdtsize)
119 {
120 void *fdt;
121 const char *bootargs;
122
123 fdt = paddr_guest2host(ctx, fdtaddr, fdtsize);
124 if (fdt == NULL)
125 return (EFAULT);
126
127 fdt_create(fdt, (int)fdtsize);
128
129 /* Add the memory reserve map (needed even if none is reserved) */
130 fdt_finish_reservemap(fdt);
131
132 /* Create the root node */
133 fdt_begin_node(fdt, "");
134
135 fdt_property_string(fdt, "compatible", "freebsd,bhyve");
136 fdt_property_u32(fdt, "#address-cells", 2);
137 fdt_property_u32(fdt, "#size-cells", 2);
138
139 fdt_begin_node(fdt, "chosen");
140 fdt_property_string(fdt, "stdout-path", "serial0:115200n8");
141 bootargs = get_config_value("fdt.bootargs");
142 if (bootargs != NULL)
143 fdt_property_string(fdt, "bootargs", bootargs);
144 fdt_end_node(fdt);
145
146 fdt_begin_node(fdt, "memory");
147 fdt_property_string(fdt, "device_type", "memory");
148 /* There is no lowmem on arm64. */
149 assert(vm_get_lowmem_size(ctx) == 0);
150 set_single_reg(fdt, vm_get_highmem_base(ctx), vm_get_highmem_size(ctx));
151 fdt_end_node(fdt);
152
153 add_cpus(fdt, ncpu);
154
155 fdt_begin_node(fdt, "psci");
156 fdt_property_string(fdt, "compatible", "arm,psci-1.0");
157 fdt_property_string(fdt, "method", "hvc");
158 fdt_end_node(fdt);
159
160 fdt_begin_node(fdt, "apb-pclk");
161 fdt_property_string(fdt, "compatible", "fixed-clock");
162 fdt_property_string(fdt, "clock-output-names", "clk24mhz");
163 fdt_property_u32(fdt, "#clock-cells", 0);
164 fdt_property_u32(fdt, "clock-frequency", 24000000);
165 apb_pclk_phandle = assign_phandle(fdt);
166 fdt_end_node(fdt);
167
168 /* Finalized by fdt_finalized(). */
169 fdtroot = fdt;
170
171 return (0);
172 }
173
174 void
fdt_add_gic(uint64_t dist_base,uint64_t dist_size,uint64_t redist_base,uint64_t redist_size)175 fdt_add_gic(uint64_t dist_base, uint64_t dist_size,
176 uint64_t redist_base, uint64_t redist_size)
177 {
178 char node_name[32];
179 void *fdt, *prop;
180
181 fdt = fdtroot;
182
183 snprintf(node_name, sizeof(node_name), "interrupt-controller@%lx",
184 (unsigned long)dist_base);
185 fdt_begin_node(fdt, node_name);
186
187 gic_phandle = assign_phandle(fdt);
188 fdt_property_string(fdt, "compatible", "arm,gic-v3");
189 fdt_property(fdt, "interrupt-controller", NULL, 0);
190 fdt_property(fdt, "msi-controller", NULL, 0);
191 /* XXX: Needed given the root #address-cells? */
192 fdt_property_u32(fdt, "#address-cells", 2);
193 fdt_property_u32(fdt, "#interrupt-cells", 3);
194 fdt_property_placeholder(fdt, "reg", 4 * sizeof(uint64_t), &prop);
195 /* GICD */
196 SET_PROP_U64(prop, 0, dist_base);
197 SET_PROP_U64(prop, 1, dist_size);
198 /* GICR */
199 SET_PROP_U64(prop, 2, redist_base);
200 SET_PROP_U64(prop, 3, redist_size);
201
202 fdt_property_placeholder(fdt, "mbi-ranges", 2 * sizeof(uint32_t),
203 &prop);
204 SET_PROP_U32(prop, 0, 256);
205 SET_PROP_U32(prop, 1, 64);
206
207 fdt_end_node(fdt);
208
209 fdt_property_u32(fdt, "interrupt-parent", gic_phandle);
210 }
211
212 void
fdt_add_uart(uint64_t uart_base,uint64_t uart_size,int intr)213 fdt_add_uart(uint64_t uart_base, uint64_t uart_size, int intr)
214 {
215 void *fdt, *interrupts, *prop;
216 char node_name[32];
217
218 assert(gic_phandle != 0);
219 assert(apb_pclk_phandle != 0);
220 assert(intr >= GIC_FIRST_SPI);
221
222 fdt = fdtroot;
223
224 snprintf(node_name, sizeof(node_name), "serial@%lx", uart_base);
225 fdt_begin_node(fdt, node_name);
226 #define UART_COMPAT "arm,pl011\0arm,primecell"
227 fdt_property(fdt, "compatible", UART_COMPAT, sizeof(UART_COMPAT));
228 #undef UART_COMPAT
229 set_single_reg(fdt, uart_base, uart_size);
230 fdt_property_u32(fdt, "interrupt-parent", gic_phandle);
231 fdt_property_placeholder(fdt, "interrupts", 3 * sizeof(uint32_t),
232 &interrupts);
233 SET_PROP_U32(interrupts, 0, GIC_SPI);
234 SET_PROP_U32(interrupts, 1, intr - GIC_FIRST_SPI);
235 SET_PROP_U32(interrupts, 2, IRQ_TYPE_LEVEL_HIGH);
236 fdt_property_placeholder(fdt, "clocks", 2 * sizeof(uint32_t), &prop);
237 SET_PROP_U32(prop, 0, apb_pclk_phandle);
238 SET_PROP_U32(prop, 1, apb_pclk_phandle);
239 #define UART_CLK_NAMES "uartclk\0apb_pclk"
240 fdt_property(fdt, "clock-names", UART_CLK_NAMES,
241 sizeof(UART_CLK_NAMES));
242 #undef UART_CLK_NAMES
243
244 fdt_end_node(fdt);
245
246 snprintf(node_name, sizeof(node_name), "/serial@%lx", uart_base);
247 fdt_begin_node(fdt, "aliases");
248 fdt_property_string(fdt, "serial0", node_name);
249 fdt_end_node(fdt);
250 }
251
252 void
fdt_add_rtc(uint64_t rtc_base,uint64_t rtc_size,int intr)253 fdt_add_rtc(uint64_t rtc_base, uint64_t rtc_size, int intr)
254 {
255 void *fdt, *interrupts, *prop;
256 char node_name[32];
257
258 assert(gic_phandle != 0);
259 assert(apb_pclk_phandle != 0);
260 assert(intr >= GIC_FIRST_SPI);
261
262 fdt = fdtroot;
263
264 snprintf(node_name, sizeof(node_name), "rtc@%lx", rtc_base);
265 fdt_begin_node(fdt, node_name);
266 #define RTC_COMPAT "arm,pl031\0arm,primecell"
267 fdt_property(fdt, "compatible", RTC_COMPAT, sizeof(RTC_COMPAT));
268 #undef RTC_COMPAT
269 set_single_reg(fdt, rtc_base, rtc_size);
270 fdt_property_u32(fdt, "interrupt-parent", gic_phandle);
271 fdt_property_placeholder(fdt, "interrupts", 3 * sizeof(uint32_t),
272 &interrupts);
273 SET_PROP_U32(interrupts, 0, GIC_SPI);
274 SET_PROP_U32(interrupts, 1, intr - GIC_FIRST_SPI);
275 SET_PROP_U32(interrupts, 2, IRQ_TYPE_LEVEL_HIGH);
276 fdt_property_placeholder(fdt, "clocks", sizeof(uint32_t), &prop);
277 SET_PROP_U32(prop, 0, apb_pclk_phandle);
278 fdt_property_string(fdt, "clock-names", "apb_pclk");
279
280 fdt_end_node(fdt);
281 }
282
283 void
fdt_add_timer(void)284 fdt_add_timer(void)
285 {
286 void *fdt, *interrupts;
287 uint32_t irqs[] = { 13, 14, 11 };
288
289 assert(gic_phandle != 0);
290
291 fdt = fdtroot;
292
293 fdt_begin_node(fdt, "timer");
294 fdt_property_string(fdt, "compatible", "arm,armv8-timer");
295 fdt_property_u32(fdt, "interrupt-parent", gic_phandle);
296 fdt_property_placeholder(fdt, "interrupts", 9 * sizeof(uint32_t),
297 &interrupts);
298 for (u_int i = 0; i < nitems(irqs); i++) {
299 SET_PROP_U32(interrupts, i * 3 + 0, GIC_PPI);
300 SET_PROP_U32(interrupts, i * 3 + 1, irqs[i]);
301 SET_PROP_U32(interrupts, i * 3 + 2, IRQ_TYPE_LEVEL_LOW);
302 }
303 fdt_end_node(fdt);
304 }
305
306 void
fdt_add_pcie(int intrs[static4])307 fdt_add_pcie(int intrs[static 4])
308 {
309 void *fdt, *prop;
310 int slot, pin, intr, i;
311
312 assert(gic_phandle != 0);
313
314 fdt = fdtroot;
315
316 fdt_begin_node(fdt, "pcie@1f0000000");
317 fdt_property_string(fdt, "compatible", "pci-host-ecam-generic");
318 fdt_property_u32(fdt, "#address-cells", 3);
319 fdt_property_u32(fdt, "#size-cells", 2);
320 fdt_property_string(fdt, "device_type", "pci");
321 fdt_property_u64(fdt, "bus-range", (0ul << 32) | 1);
322 set_single_reg(fdt, 0xe0000000, 0x10000000);
323 fdt_property_placeholder(fdt, "ranges",
324 2 * 7 * sizeof(uint32_t), &prop);
325 SET_PROP_U32(prop, 0, 0x01000000);
326
327 SET_PROP_U32(prop, 1, 0);
328 SET_PROP_U32(prop, 2, 0xdf000000);
329
330 SET_PROP_U32(prop, 3, 0);
331 SET_PROP_U32(prop, 4, 0xdf000000);
332
333 SET_PROP_U32(prop, 5, 0);
334 SET_PROP_U32(prop, 6, 0x01000000);
335
336 SET_PROP_U32(prop, 7, 0x02000000);
337
338 SET_PROP_U32(prop, 8, 0);
339 SET_PROP_U32(prop, 9, 0xa0000000);
340
341 SET_PROP_U32(prop, 10, 0);
342 SET_PROP_U32(prop, 11, 0xa0000000);
343
344 SET_PROP_U32(prop, 12, 0);
345 SET_PROP_U32(prop, 13, 0x3f000000);
346
347 fdt_property_placeholder(fdt, "msi-map", 4 * sizeof(uint32_t), &prop);
348 SET_PROP_U32(prop, 0, 0); /* RID base */
349 SET_PROP_U32(prop, 1, gic_phandle); /* MSI parent */
350 SET_PROP_U32(prop, 2, 0); /* MSI base */
351 SET_PROP_U32(prop, 3, 0x10000); /* RID length */
352 fdt_property_u32(fdt, "msi-parent", gic_phandle);
353
354 fdt_property_u32(fdt, "#interrupt-cells", 1);
355 fdt_property_u32(fdt, "interrupt-parent", gic_phandle);
356
357 /*
358 * Describe standard swizzled interrupts routing (pins rotated by one
359 * for each consecutive slot). Must match pci_irq_route().
360 */
361 fdt_property_placeholder(fdt, "interrupt-map-mask",
362 4 * sizeof(uint32_t), &prop);
363 SET_PROP_U32(prop, 0, 3 << 11);
364 SET_PROP_U32(prop, 1, 0);
365 SET_PROP_U32(prop, 2, 0);
366 SET_PROP_U32(prop, 3, 7);
367 fdt_property_placeholder(fdt, "interrupt-map",
368 160 * sizeof(uint32_t), &prop);
369 for (i = 0; i < 16; ++i) {
370 pin = i % 4;
371 slot = i / 4;
372 intr = intrs[(pin + slot) % 4];
373 assert(intr >= GIC_FIRST_SPI);
374 SET_PROP_U32(prop, 10 * i + 0, slot << 11);
375 SET_PROP_U32(prop, 10 * i + 1, 0);
376 SET_PROP_U32(prop, 10 * i + 2, 0);
377 SET_PROP_U32(prop, 10 * i + 3, pin + 1);
378 SET_PROP_U32(prop, 10 * i + 4, gic_phandle);
379 SET_PROP_U32(prop, 10 * i + 5, 0);
380 SET_PROP_U32(prop, 10 * i + 6, 0);
381 SET_PROP_U32(prop, 10 * i + 7, GIC_SPI);
382 SET_PROP_U32(prop, 10 * i + 8, intr - GIC_FIRST_SPI);
383 SET_PROP_U32(prop, 10 * i + 9, IRQ_TYPE_LEVEL_HIGH);
384 }
385
386 fdt_end_node(fdt);
387 }
388
389 void
fdt_finalize(void)390 fdt_finalize(void)
391 {
392 fdt_end_node(fdtroot);
393
394 fdt_finish(fdtroot);
395 }
396