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), ®); 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