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 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 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 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 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 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 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 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 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 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 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 390 fdt_finalize(void) 391 { 392 fdt_end_node(fdtroot); 393 394 fdt_finish(fdtroot); 395 } 396