xref: /freebsd/usr.sbin/bhyve/aarch64/fdt.c (revision 7a7741af18d6c8a804cc643cb7ecda9d730c6aa6)
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 "bhyverun.h"
43 #include "fdt.h"
44 
45 #define	SET_PROP_U32(prop, idx, val)	\
46     ((uint32_t *)(prop))[(idx)] = cpu_to_fdt32(val)
47 #define	SET_PROP_U64(prop, idx, val)	\
48     ((uint64_t *)(prop))[(idx)] = cpu_to_fdt64(val)
49 
50 #define	GIC_SPI			0
51 #define	GIC_PPI			1
52 #define	IRQ_TYPE_LEVEL_HIGH	4
53 #define	IRQ_TYPE_LEVEL_LOW	8
54 
55 #define	GIC_FIRST_PPI		16
56 #define	GIC_FIRST_SPI		32
57 
58 static void *fdtroot;
59 static uint32_t gic_phandle = 0;
60 static uint32_t apb_pclk_phandle;
61 
62 static uint32_t
63 assign_phandle(void *fdt)
64 {
65 	static uint32_t next_phandle = 1;
66 	uint32_t phandle;
67 
68 	phandle = next_phandle;
69 	next_phandle++;
70 	fdt_property_u32(fdt, "phandle", phandle);
71 
72 	return (phandle);
73 }
74 
75 static void
76 set_single_reg(void *fdt, uint64_t start, uint64_t len)
77 {
78 	void *reg;
79 
80 	fdt_property_placeholder(fdt, "reg", 2 * sizeof(uint64_t), &reg);
81 	SET_PROP_U64(reg, 0, start);
82 	SET_PROP_U64(reg, 1, len);
83 }
84 
85 static void
86 add_cpu(void *fdt, int cpuid)
87 {
88 	char node_name[16];
89 
90 	snprintf(node_name, sizeof(node_name), "cpu@%d", cpuid);
91 
92 	fdt_begin_node(fdt, node_name);
93 	fdt_property_string(fdt, "device_type", "cpu");
94 	fdt_property_string(fdt, "compatible", "arm,armv8");
95 	fdt_property_u64(fdt, "reg", cpuid);
96 	fdt_property_string(fdt, "enable-method", "psci");
97 	fdt_end_node(fdt);
98 }
99 
100 static void
101 add_cpus(void *fdt, int ncpu)
102 {
103 	int cpuid;
104 
105 	fdt_begin_node(fdt, "cpus");
106 	/* XXX: Needed given the root #address-cells? */
107 	fdt_property_u32(fdt, "#address-cells", 2);
108 	fdt_property_u32(fdt, "#size-cells", 0);
109 
110 	for (cpuid = 0; cpuid < ncpu; cpuid++) {
111 		add_cpu(fdt, cpuid);
112 	}
113 	fdt_end_node(fdt);
114 }
115 
116 int
117 fdt_init(struct vmctx *ctx, int ncpu, vm_paddr_t fdtaddr, vm_size_t fdtsize)
118 {
119 	void *fdt;
120 	const char *bootargs;
121 
122 	fdt = paddr_guest2host(ctx, fdtaddr, fdtsize);
123 	if (fdt == NULL)
124 		return (EFAULT);
125 
126 	fdt_create(fdt, (int)fdtsize);
127 
128 	/* Add the memory reserve map (needed even if none is reserved) */
129 	fdt_finish_reservemap(fdt);
130 
131 	/* Create the root node */
132 	fdt_begin_node(fdt, "");
133 
134 	fdt_property_string(fdt, "compatible", "freebsd,bhyve");
135 	fdt_property_u32(fdt, "#address-cells", 2);
136 	fdt_property_u32(fdt, "#size-cells", 2);
137 
138 	fdt_begin_node(fdt, "chosen");
139 	fdt_property_string(fdt, "stdout-path", "serial0:115200n8");
140 	bootargs = get_config_value("fdt.bootargs");
141 	if (bootargs != NULL)
142 		fdt_property_string(fdt, "bootargs", bootargs);
143 	fdt_end_node(fdt);
144 
145 	fdt_begin_node(fdt, "memory");
146 	fdt_property_string(fdt, "device_type", "memory");
147 	/* There is no lowmem on arm64. */
148 	assert(vm_get_lowmem_size(ctx) == 0);
149 	set_single_reg(fdt, vm_get_highmem_base(ctx), vm_get_highmem_size(ctx));
150 	fdt_end_node(fdt);
151 
152 	add_cpus(fdt, ncpu);
153 
154 	fdt_begin_node(fdt, "psci");
155 	fdt_property_string(fdt, "compatible", "arm,psci-1.0");
156 	fdt_property_string(fdt, "method", "hvc");
157 	fdt_end_node(fdt);
158 
159 	fdt_begin_node(fdt, "apb-pclk");
160 	fdt_property_string(fdt, "compatible", "fixed-clock");
161 	fdt_property_string(fdt, "clock-output-names", "clk24mhz");
162 	fdt_property_u32(fdt, "#clock-cells", 0);
163 	fdt_property_u32(fdt, "clock-frequency", 24000000);
164 	apb_pclk_phandle = assign_phandle(fdt);
165 	fdt_end_node(fdt);
166 
167 	/* Finalized by fdt_finalized(). */
168 	fdtroot = fdt;
169 
170 	return (0);
171 }
172 
173 void
174 fdt_add_gic(uint64_t dist_base, uint64_t dist_size,
175     uint64_t redist_base, uint64_t redist_size)
176 {
177 	char node_name[32];
178 	void *fdt, *prop;
179 
180 	fdt = fdtroot;
181 
182 	snprintf(node_name, sizeof(node_name), "interrupt-controller@%lx",
183 	    (unsigned long)dist_base);
184 	fdt_begin_node(fdt, node_name);
185 
186 	gic_phandle = assign_phandle(fdt);
187 	fdt_property_string(fdt, "compatible", "arm,gic-v3");
188 	fdt_property(fdt, "interrupt-controller", NULL, 0);
189 	fdt_property(fdt, "msi-controller", NULL, 0);
190 	/* XXX: Needed given the root #address-cells? */
191 	fdt_property_u32(fdt, "#address-cells", 2);
192 	fdt_property_u32(fdt, "#interrupt-cells", 3);
193 	fdt_property_placeholder(fdt, "reg", 4 * sizeof(uint64_t), &prop);
194 	/* GICD */
195 	SET_PROP_U64(prop, 0, dist_base);
196 	SET_PROP_U64(prop, 1, dist_size);
197 	/* GICR */
198 	SET_PROP_U64(prop, 2, redist_base);
199 	SET_PROP_U64(prop, 3, redist_size);
200 
201 	fdt_property_placeholder(fdt, "mbi-ranges", 2 * sizeof(uint32_t),
202 	    &prop);
203 	SET_PROP_U32(prop, 0, 256);
204 	SET_PROP_U32(prop, 1, 64);
205 
206 	fdt_end_node(fdt);
207 
208 	fdt_property_u32(fdt, "interrupt-parent", gic_phandle);
209 }
210 
211 void
212 fdt_add_uart(uint64_t uart_base, uint64_t uart_size, int intr)
213 {
214 	void *fdt, *interrupts, *prop;
215 	char node_name[32];
216 
217 	assert(gic_phandle != 0);
218 	assert(apb_pclk_phandle != 0);
219 	assert(intr >= GIC_FIRST_SPI);
220 
221 	fdt = fdtroot;
222 
223 	snprintf(node_name, sizeof(node_name), "serial@%lx", uart_base);
224 	fdt_begin_node(fdt, node_name);
225 #define	UART_COMPAT	"arm,pl011\0arm,primecell"
226 	fdt_property(fdt, "compatible", UART_COMPAT, sizeof(UART_COMPAT));
227 #undef UART_COMPAT
228 	set_single_reg(fdt, uart_base, uart_size);
229 	fdt_property_u32(fdt, "interrupt-parent", gic_phandle);
230 	fdt_property_placeholder(fdt, "interrupts", 3 * sizeof(uint32_t),
231 	    &interrupts);
232 	SET_PROP_U32(interrupts, 0, GIC_SPI);
233 	SET_PROP_U32(interrupts, 1, intr - GIC_FIRST_SPI);
234 	SET_PROP_U32(interrupts, 2, IRQ_TYPE_LEVEL_HIGH);
235 	fdt_property_placeholder(fdt, "clocks", 2 * sizeof(uint32_t), &prop);
236 	SET_PROP_U32(prop, 0, apb_pclk_phandle);
237 	SET_PROP_U32(prop, 1, apb_pclk_phandle);
238 #define	UART_CLK_NAMES	"uartclk\0apb_pclk"
239 	fdt_property(fdt, "clock-names", UART_CLK_NAMES,
240 	    sizeof(UART_CLK_NAMES));
241 #undef UART_CLK_NAMES
242 
243 	fdt_end_node(fdt);
244 
245 	snprintf(node_name, sizeof(node_name), "/serial@%lx", uart_base);
246 	fdt_begin_node(fdt, "aliases");
247 	fdt_property_string(fdt, "serial0", node_name);
248 	fdt_end_node(fdt);
249 }
250 
251 void
252 fdt_add_rtc(uint64_t rtc_base, uint64_t rtc_size, int intr)
253 {
254 	void *fdt, *interrupts, *prop;
255 	char node_name[32];
256 
257 	assert(gic_phandle != 0);
258 	assert(apb_pclk_phandle != 0);
259 	assert(intr >= GIC_FIRST_SPI);
260 
261 	fdt = fdtroot;
262 
263 	snprintf(node_name, sizeof(node_name), "rtc@%lx", rtc_base);
264 	fdt_begin_node(fdt, node_name);
265 #define	RTC_COMPAT	"arm,pl031\0arm,primecell"
266 	fdt_property(fdt, "compatible", RTC_COMPAT, sizeof(RTC_COMPAT));
267 #undef RTC_COMPAT
268 	set_single_reg(fdt, rtc_base, rtc_size);
269 	fdt_property_u32(fdt, "interrupt-parent", gic_phandle);
270 	fdt_property_placeholder(fdt, "interrupts", 3 * sizeof(uint32_t),
271 	    &interrupts);
272 	SET_PROP_U32(interrupts, 0, GIC_SPI);
273 	SET_PROP_U32(interrupts, 1, intr - GIC_FIRST_SPI);
274 	SET_PROP_U32(interrupts, 2, IRQ_TYPE_LEVEL_HIGH);
275 	fdt_property_placeholder(fdt, "clocks", sizeof(uint32_t), &prop);
276 	SET_PROP_U32(prop, 0, apb_pclk_phandle);
277 	fdt_property_string(fdt, "clock-names", "apb_pclk");
278 
279 	fdt_end_node(fdt);
280 }
281 
282 void
283 fdt_add_timer(void)
284 {
285 	void *fdt, *interrupts;
286 	uint32_t irqs[] = { 13, 14, 11 };
287 
288 	assert(gic_phandle != 0);
289 
290 	fdt = fdtroot;
291 
292 	fdt_begin_node(fdt, "timer");
293 	fdt_property_string(fdt, "compatible", "arm,armv8-timer");
294 	fdt_property_u32(fdt, "interrupt-parent", gic_phandle);
295 	fdt_property_placeholder(fdt, "interrupts", 9 * sizeof(uint32_t),
296 	    &interrupts);
297 	for (u_int i = 0; i < nitems(irqs); i++) {
298 		SET_PROP_U32(interrupts, i * 3 + 0, GIC_PPI);
299 		SET_PROP_U32(interrupts, i * 3 + 1, irqs[i]);
300 		SET_PROP_U32(interrupts, i * 3 + 2, IRQ_TYPE_LEVEL_LOW);
301 	}
302 	fdt_end_node(fdt);
303 }
304 
305 void
306 fdt_add_pcie(int intrs[static 4])
307 {
308 	void *fdt, *prop;
309 	int slot, pin, intr, i;
310 
311 	assert(gic_phandle != 0);
312 
313 	fdt = fdtroot;
314 
315 	fdt_begin_node(fdt, "pcie@1f0000000");
316 	fdt_property_string(fdt, "compatible", "pci-host-ecam-generic");
317 	fdt_property_u32(fdt, "#address-cells", 3);
318 	fdt_property_u32(fdt, "#size-cells", 2);
319 	fdt_property_string(fdt, "device_type", "pci");
320 	fdt_property_u64(fdt, "bus-range", (0ul << 32) | 1);
321 	set_single_reg(fdt, 0xe0000000, 0x10000000);
322 	fdt_property_placeholder(fdt, "ranges",
323 	    2 * 7 * sizeof(uint32_t), &prop);
324 	SET_PROP_U32(prop, 0, 0x01000000);
325 
326 	SET_PROP_U32(prop, 1, 0);
327 	SET_PROP_U32(prop, 2, 0xdf000000);
328 
329 	SET_PROP_U32(prop, 3, 0);
330 	SET_PROP_U32(prop, 4, 0xdf000000);
331 
332 	SET_PROP_U32(prop, 5, 0);
333 	SET_PROP_U32(prop, 6, 0x01000000);
334 
335 	SET_PROP_U32(prop, 7, 0x02000000);
336 
337 	SET_PROP_U32(prop, 8, 0);
338 	SET_PROP_U32(prop, 9, 0xa0000000);
339 
340 	SET_PROP_U32(prop, 10, 0);
341 	SET_PROP_U32(prop, 11, 0xa0000000);
342 
343 	SET_PROP_U32(prop, 12, 0);
344 	SET_PROP_U32(prop, 13, 0x3f000000);
345 
346 	fdt_property_placeholder(fdt, "msi-map", 4 * sizeof(uint32_t), &prop);
347 	SET_PROP_U32(prop, 0, 0);		/* RID base */
348 	SET_PROP_U32(prop, 1, gic_phandle);	/* MSI parent */
349 	SET_PROP_U32(prop, 2, 0);		/* MSI base */
350 	SET_PROP_U32(prop, 3, 0x10000);		/* RID length */
351 	fdt_property_u32(fdt, "msi-parent", gic_phandle);
352 
353 	fdt_property_u32(fdt, "#interrupt-cells", 1);
354 	fdt_property_u32(fdt, "interrupt-parent", gic_phandle);
355 
356 	/*
357 	 * Describe standard swizzled interrupts routing (pins rotated by one
358 	 * for each consecutive slot). Must match pci_irq_route().
359 	 */
360 	fdt_property_placeholder(fdt, "interrupt-map-mask",
361 	    4 * sizeof(uint32_t), &prop);
362 	SET_PROP_U32(prop, 0, 3 << 11);
363 	SET_PROP_U32(prop, 1, 0);
364 	SET_PROP_U32(prop, 2, 0);
365 	SET_PROP_U32(prop, 3, 7);
366 	fdt_property_placeholder(fdt, "interrupt-map",
367 	    160 * sizeof(uint32_t), &prop);
368 	for (i = 0; i < 16; ++i) {
369 		pin = i % 4;
370 		slot = i / 4;
371 		intr = intrs[(pin + slot) % 4];
372 		assert(intr >= GIC_FIRST_SPI);
373 		SET_PROP_U32(prop, 10 * i + 0, slot << 11);
374 		SET_PROP_U32(prop, 10 * i + 1, 0);
375 		SET_PROP_U32(prop, 10 * i + 2, 0);
376 		SET_PROP_U32(prop, 10 * i + 3, pin + 1);
377 		SET_PROP_U32(prop, 10 * i + 4, gic_phandle);
378 		SET_PROP_U32(prop, 10 * i + 5, 0);
379 		SET_PROP_U32(prop, 10 * i + 6, 0);
380 		SET_PROP_U32(prop, 10 * i + 7, GIC_SPI);
381 		SET_PROP_U32(prop, 10 * i + 8, intr - GIC_FIRST_SPI);
382 		SET_PROP_U32(prop, 10 * i + 9, IRQ_TYPE_LEVEL_HIGH);
383 	}
384 
385 	fdt_end_node(fdt);
386 }
387 
388 void
389 fdt_finalize(void)
390 {
391 	fdt_end_node(fdtroot);
392 
393 	fdt_finish(fdtroot);
394 }
395