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
58static void *fdtroot;
59static uint32_t gic_phandle = 0;
60static uint32_t apb_pclk_phandle;
61
62static uint32_t
63assign_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
75static void
76set_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
85static void
86add_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
100static void
101add_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
116int
117fdt_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
173void
174fdt_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
211void
212fdt_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
251void
252fdt_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
282void
283fdt_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
305void
306fdt_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
388void
389fdt_finalize(void)
390{
391	fdt_end_node(fdtroot);
392
393	fdt_finish(fdtroot);
394}
395