1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * Copyright (c) 2025 Loongson Technology Corporation Limited 4 */ 5 #include "qemu/osdep.h" 6 #include "qemu/error-report.h" 7 #include "qemu/guest-random.h" 8 #include <libfdt.h> 9 #include "hw/acpi/generic_event_device.h" 10 #include "hw/core/sysbus-fdt.h" 11 #include "hw/intc/loongarch_extioi.h" 12 #include "hw/loader.h" 13 #include "hw/loongarch/virt.h" 14 #include "hw/pci-host/gpex.h" 15 #include "hw/pci-host/ls7a.h" 16 #include "system/device_tree.h" 17 #include "system/reset.h" 18 #include "target/loongarch/cpu.h" 19 20 static void create_fdt(LoongArchVirtMachineState *lvms) 21 { 22 MachineState *ms = MACHINE(lvms); 23 uint8_t rng_seed[32]; 24 25 ms->fdt = create_device_tree(&lvms->fdt_size); 26 if (!ms->fdt) { 27 error_report("create_device_tree() failed"); 28 exit(1); 29 } 30 31 /* Header */ 32 qemu_fdt_setprop_string(ms->fdt, "/", "compatible", 33 "linux,dummy-loongson3"); 34 qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2); 35 qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2); 36 qemu_fdt_add_subnode(ms->fdt, "/chosen"); 37 38 /* Pass seed to RNG */ 39 qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); 40 qemu_fdt_setprop(ms->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); 41 } 42 43 static void fdt_add_cpu_nodes(const LoongArchVirtMachineState *lvms) 44 { 45 int num; 46 MachineState *ms = MACHINE(lvms); 47 MachineClass *mc = MACHINE_GET_CLASS(ms); 48 const CPUArchIdList *possible_cpus; 49 LoongArchCPU *cpu; 50 CPUState *cs; 51 char *nodename, *map_path; 52 53 qemu_fdt_add_subnode(ms->fdt, "/cpus"); 54 qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1); 55 qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0); 56 57 /* cpu nodes */ 58 possible_cpus = mc->possible_cpu_arch_ids(ms); 59 for (num = 0; num < possible_cpus->len; num++) { 60 cs = possible_cpus->cpus[num].cpu; 61 if (cs == NULL) { 62 continue; 63 } 64 65 nodename = g_strdup_printf("/cpus/cpu@%d", num); 66 cpu = LOONGARCH_CPU(cs); 67 68 qemu_fdt_add_subnode(ms->fdt, nodename); 69 qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu"); 70 qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 71 cpu->dtb_compatible); 72 if (possible_cpus->cpus[num].props.has_node_id) { 73 qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id", 74 possible_cpus->cpus[num].props.node_id); 75 } 76 qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num); 77 qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", 78 qemu_fdt_alloc_phandle(ms->fdt)); 79 g_free(nodename); 80 } 81 82 /*cpu map */ 83 qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map"); 84 for (num = 0; num < possible_cpus->len; num++) { 85 cs = possible_cpus->cpus[num].cpu; 86 if (cs == NULL) { 87 continue; 88 } 89 90 nodename = g_strdup_printf("/cpus/cpu@%d", num); 91 if (ms->smp.threads > 1) { 92 map_path = g_strdup_printf( 93 "/cpus/cpu-map/socket%d/core%d/thread%d", 94 num / (ms->smp.cores * ms->smp.threads), 95 (num / ms->smp.threads) % ms->smp.cores, 96 num % ms->smp.threads); 97 } else { 98 map_path = g_strdup_printf( 99 "/cpus/cpu-map/socket%d/core%d", 100 num / ms->smp.cores, 101 num % ms->smp.cores); 102 } 103 qemu_fdt_add_path(ms->fdt, map_path); 104 qemu_fdt_setprop_phandle(ms->fdt, map_path, "cpu", nodename); 105 106 g_free(map_path); 107 g_free(nodename); 108 } 109 } 110 111 static void fdt_add_memory_node(MachineState *ms, 112 uint64_t base, uint64_t size, int node_id) 113 { 114 char *nodename = g_strdup_printf("/memory@%" PRIx64, base); 115 116 qemu_fdt_add_subnode(ms->fdt, nodename); 117 qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", base >> 32, base, 118 size >> 32, size); 119 qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory"); 120 121 if (ms->numa_state && ms->numa_state->num_nodes) { 122 qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id", node_id); 123 } 124 125 g_free(nodename); 126 } 127 128 static void fdt_add_memory_nodes(MachineState *ms) 129 { 130 hwaddr base, size, ram_size, gap; 131 int i, nb_numa_nodes, nodes; 132 NodeInfo *numa_info; 133 134 ram_size = ms->ram_size; 135 base = VIRT_LOWMEM_BASE; 136 gap = VIRT_LOWMEM_SIZE; 137 nodes = nb_numa_nodes = ms->numa_state->num_nodes; 138 numa_info = ms->numa_state->nodes; 139 if (!nodes) { 140 nodes = 1; 141 } 142 143 for (i = 0; i < nodes; i++) { 144 if (nb_numa_nodes) { 145 size = numa_info[i].node_mem; 146 } else { 147 size = ram_size; 148 } 149 150 /* 151 * memory for the node splited into two part 152 * lowram: [base, +gap) 153 * highram: [VIRT_HIGHMEM_BASE, +(len - gap)) 154 */ 155 if (size >= gap) { 156 fdt_add_memory_node(ms, base, gap, i); 157 size -= gap; 158 base = VIRT_HIGHMEM_BASE; 159 gap = ram_size - VIRT_LOWMEM_SIZE; 160 } 161 162 if (size) { 163 fdt_add_memory_node(ms, base, size, i); 164 base += size; 165 gap -= size; 166 } 167 } 168 } 169 170 static void fdt_add_fw_cfg_node(const LoongArchVirtMachineState *lvms) 171 { 172 char *nodename; 173 hwaddr base = VIRT_FWCFG_BASE; 174 const MachineState *ms = MACHINE(lvms); 175 176 nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base); 177 qemu_fdt_add_subnode(ms->fdt, nodename); 178 qemu_fdt_setprop_string(ms->fdt, nodename, 179 "compatible", "qemu,fw-cfg-mmio"); 180 qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 181 2, base, 2, 0x18); 182 qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0); 183 g_free(nodename); 184 } 185 186 static void fdt_add_flash_node(LoongArchVirtMachineState *lvms) 187 { 188 MachineState *ms = MACHINE(lvms); 189 char *nodename; 190 MemoryRegion *flash_mem; 191 192 hwaddr flash0_base; 193 hwaddr flash0_size; 194 195 hwaddr flash1_base; 196 hwaddr flash1_size; 197 198 flash_mem = pflash_cfi01_get_memory(lvms->flash[0]); 199 flash0_base = flash_mem->addr; 200 flash0_size = memory_region_size(flash_mem); 201 202 flash_mem = pflash_cfi01_get_memory(lvms->flash[1]); 203 flash1_base = flash_mem->addr; 204 flash1_size = memory_region_size(flash_mem); 205 206 nodename = g_strdup_printf("/flash@%" PRIx64, flash0_base); 207 qemu_fdt_add_subnode(ms->fdt, nodename); 208 qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cfi-flash"); 209 qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 210 2, flash0_base, 2, flash0_size, 211 2, flash1_base, 2, flash1_size); 212 qemu_fdt_setprop_cell(ms->fdt, nodename, "bank-width", 4); 213 g_free(nodename); 214 } 215 216 static void fdt_add_cpuic_node(LoongArchVirtMachineState *lvms, 217 uint32_t *cpuintc_phandle) 218 { 219 MachineState *ms = MACHINE(lvms); 220 char *nodename; 221 222 *cpuintc_phandle = qemu_fdt_alloc_phandle(ms->fdt); 223 nodename = g_strdup_printf("/cpuic"); 224 qemu_fdt_add_subnode(ms->fdt, nodename); 225 qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *cpuintc_phandle); 226 qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 227 "loongson,cpu-interrupt-controller"); 228 qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); 229 qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1); 230 g_free(nodename); 231 } 232 233 static void fdt_add_eiointc_node(LoongArchVirtMachineState *lvms, 234 uint32_t *cpuintc_phandle, 235 uint32_t *eiointc_phandle) 236 { 237 MachineState *ms = MACHINE(lvms); 238 char *nodename; 239 hwaddr extioi_base = APIC_BASE; 240 hwaddr extioi_size = EXTIOI_SIZE; 241 242 *eiointc_phandle = qemu_fdt_alloc_phandle(ms->fdt); 243 nodename = g_strdup_printf("/eiointc@%" PRIx64, extioi_base); 244 qemu_fdt_add_subnode(ms->fdt, nodename); 245 qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *eiointc_phandle); 246 qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 247 "loongson,ls2k2000-eiointc"); 248 qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); 249 qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1); 250 qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", 251 *cpuintc_phandle); 252 qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", 3); 253 qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, 254 extioi_base, 0x0, extioi_size); 255 g_free(nodename); 256 } 257 258 static void fdt_add_pch_pic_node(LoongArchVirtMachineState *lvms, 259 uint32_t *eiointc_phandle, 260 uint32_t *pch_pic_phandle) 261 { 262 MachineState *ms = MACHINE(lvms); 263 char *nodename; 264 hwaddr pch_pic_base = VIRT_PCH_REG_BASE; 265 hwaddr pch_pic_size = VIRT_PCH_REG_SIZE; 266 267 *pch_pic_phandle = qemu_fdt_alloc_phandle(ms->fdt); 268 nodename = g_strdup_printf("/platic@%" PRIx64, pch_pic_base); 269 qemu_fdt_add_subnode(ms->fdt, nodename); 270 qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_pic_phandle); 271 qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 272 "loongson,pch-pic-1.0"); 273 qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, 274 pch_pic_base, 0, pch_pic_size); 275 qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); 276 qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2); 277 qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", 278 *eiointc_phandle); 279 qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,pic-base-vec", 0); 280 g_free(nodename); 281 } 282 283 static void fdt_add_pch_msi_node(LoongArchVirtMachineState *lvms, 284 uint32_t *eiointc_phandle, 285 uint32_t *pch_msi_phandle) 286 { 287 MachineState *ms = MACHINE(lvms); 288 char *nodename; 289 hwaddr pch_msi_base = VIRT_PCH_MSI_ADDR_LOW; 290 hwaddr pch_msi_size = VIRT_PCH_MSI_SIZE; 291 292 *pch_msi_phandle = qemu_fdt_alloc_phandle(ms->fdt); 293 nodename = g_strdup_printf("/msi@%" PRIx64, pch_msi_base); 294 qemu_fdt_add_subnode(ms->fdt, nodename); 295 qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_msi_phandle); 296 qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 297 "loongson,pch-msi-1.0"); 298 qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 299 0, pch_msi_base, 300 0, pch_msi_size); 301 qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); 302 qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", 303 *eiointc_phandle); 304 qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-base-vec", 305 VIRT_PCH_PIC_IRQ_NUM); 306 qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-num-vecs", 307 EXTIOI_IRQS - VIRT_PCH_PIC_IRQ_NUM); 308 g_free(nodename); 309 } 310 311 static void fdt_add_pcie_irq_map_node(const LoongArchVirtMachineState *lvms, 312 char *nodename, 313 uint32_t *pch_pic_phandle) 314 { 315 int pin, dev; 316 uint32_t irq_map_stride = 0; 317 uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 10] = {}; 318 uint32_t *irq_map = full_irq_map; 319 const MachineState *ms = MACHINE(lvms); 320 321 /* 322 * This code creates a standard swizzle of interrupts such that 323 * each device's first interrupt is based on it's PCI_SLOT number. 324 * (See pci_swizzle_map_irq_fn()) 325 * 326 * We only need one entry per interrupt in the table (not one per 327 * possible slot) seeing the interrupt-map-mask will allow the table 328 * to wrap to any number of devices. 329 */ 330 331 for (dev = 0; dev < PCI_NUM_PINS; dev++) { 332 int devfn = dev * 0x8; 333 334 for (pin = 0; pin < PCI_NUM_PINS; pin++) { 335 int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); 336 int i = 0; 337 338 /* Fill PCI address cells */ 339 irq_map[i] = cpu_to_be32(devfn << 8); 340 i += 3; 341 342 /* Fill PCI Interrupt cells */ 343 irq_map[i] = cpu_to_be32(pin + 1); 344 i += 1; 345 346 /* Fill interrupt controller phandle and cells */ 347 irq_map[i++] = cpu_to_be32(*pch_pic_phandle); 348 irq_map[i++] = cpu_to_be32(irq_nr); 349 350 if (!irq_map_stride) { 351 irq_map_stride = i; 352 } 353 irq_map += irq_map_stride; 354 } 355 } 356 357 358 qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map, 359 PCI_NUM_PINS * PCI_NUM_PINS * 360 irq_map_stride * sizeof(uint32_t)); 361 qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask", 362 0x1800, 0, 0, 0x7); 363 } 364 365 static void fdt_add_pcie_node(const LoongArchVirtMachineState *lvms, 366 uint32_t *pch_pic_phandle, 367 uint32_t *pch_msi_phandle) 368 { 369 char *nodename; 370 hwaddr base_mmio = VIRT_PCI_MEM_BASE; 371 hwaddr size_mmio = VIRT_PCI_MEM_SIZE; 372 hwaddr base_pio = VIRT_PCI_IO_BASE; 373 hwaddr size_pio = VIRT_PCI_IO_SIZE; 374 hwaddr base_pcie = VIRT_PCI_CFG_BASE; 375 hwaddr size_pcie = VIRT_PCI_CFG_SIZE; 376 hwaddr base = base_pcie; 377 const MachineState *ms = MACHINE(lvms); 378 379 nodename = g_strdup_printf("/pcie@%" PRIx64, base); 380 qemu_fdt_add_subnode(ms->fdt, nodename); 381 qemu_fdt_setprop_string(ms->fdt, nodename, 382 "compatible", "pci-host-ecam-generic"); 383 qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "pci"); 384 qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 3); 385 qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 2); 386 qemu_fdt_setprop_cell(ms->fdt, nodename, "linux,pci-domain", 0); 387 qemu_fdt_setprop_cells(ms->fdt, nodename, "bus-range", 0, 388 PCIE_MMCFG_BUS(VIRT_PCI_CFG_SIZE - 1)); 389 qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0); 390 qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 391 2, base_pcie, 2, size_pcie); 392 qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "ranges", 393 1, FDT_PCI_RANGE_IOPORT, 2, VIRT_PCI_IO_OFFSET, 394 2, base_pio, 2, size_pio, 395 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, 396 2, base_mmio, 2, size_mmio); 397 qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map", 398 0, *pch_msi_phandle, 0, 0x10000); 399 fdt_add_pcie_irq_map_node(lvms, nodename, pch_pic_phandle); 400 g_free(nodename); 401 } 402 403 static void fdt_add_uart_node(LoongArchVirtMachineState *lvms, 404 uint32_t *pch_pic_phandle, hwaddr base, 405 int irq, bool chosen) 406 { 407 char *nodename; 408 hwaddr size = VIRT_UART_SIZE; 409 MachineState *ms = MACHINE(lvms); 410 411 nodename = g_strdup_printf("/serial@%" PRIx64, base); 412 qemu_fdt_add_subnode(ms->fdt, nodename); 413 qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "ns16550a"); 414 qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size); 415 qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 100000000); 416 if (chosen) { 417 qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename); 418 } 419 qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", irq, 0x4); 420 qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", 421 *pch_pic_phandle); 422 g_free(nodename); 423 } 424 425 static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms, 426 uint32_t *pch_pic_phandle) 427 { 428 char *nodename; 429 hwaddr base = VIRT_RTC_REG_BASE; 430 hwaddr size = VIRT_RTC_LEN; 431 MachineState *ms = MACHINE(lvms); 432 433 nodename = g_strdup_printf("/rtc@%" PRIx64, base); 434 qemu_fdt_add_subnode(ms->fdt, nodename); 435 qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 436 "loongson,ls7a-rtc"); 437 qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size); 438 qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", 439 VIRT_RTC_IRQ - VIRT_GSI_BASE , 0x4); 440 qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", 441 *pch_pic_phandle); 442 g_free(nodename); 443 } 444 445 static void fdt_add_ged_reset(LoongArchVirtMachineState *lvms) 446 { 447 char *name; 448 uint32_t ged_handle; 449 MachineState *ms = MACHINE(lvms); 450 hwaddr base = VIRT_GED_REG_ADDR; 451 hwaddr size = ACPI_GED_REG_COUNT; 452 453 ged_handle = qemu_fdt_alloc_phandle(ms->fdt); 454 name = g_strdup_printf("/ged@%" PRIx64, base); 455 qemu_fdt_add_subnode(ms->fdt, name); 456 qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon"); 457 qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, base, 0x0, size); 458 /* 8 bit registers */ 459 qemu_fdt_setprop_cell(ms->fdt, name, "reg-shift", 0); 460 qemu_fdt_setprop_cell(ms->fdt, name, "reg-io-width", 1); 461 qemu_fdt_setprop_cell(ms->fdt, name, "phandle", ged_handle); 462 ged_handle = qemu_fdt_get_phandle(ms->fdt, name); 463 g_free(name); 464 465 name = g_strdup_printf("/reboot"); 466 qemu_fdt_add_subnode(ms->fdt, name); 467 qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-reboot"); 468 qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle); 469 qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_RESET); 470 qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_RESET_VALUE); 471 g_free(name); 472 473 name = g_strdup_printf("/poweroff"); 474 qemu_fdt_add_subnode(ms->fdt, name); 475 qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-poweroff"); 476 qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle); 477 qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_SLEEP_CTL); 478 qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_SLP_EN | 479 (ACPI_GED_SLP_TYP_S5 << ACPI_GED_SLP_TYP_POS)); 480 g_free(name); 481 } 482 483 void virt_fdt_setup(LoongArchVirtMachineState *lvms) 484 { 485 MachineState *machine = MACHINE(lvms); 486 uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle, pch_msi_phandle; 487 int i; 488 489 create_fdt(lvms); 490 fdt_add_cpu_nodes(lvms); 491 fdt_add_memory_nodes(machine); 492 fdt_add_fw_cfg_node(lvms); 493 fdt_add_flash_node(lvms); 494 495 /* Add cpu interrupt-controller */ 496 fdt_add_cpuic_node(lvms, &cpuintc_phandle); 497 /* Add Extend I/O Interrupt Controller node */ 498 fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle); 499 /* Add PCH PIC node */ 500 fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle); 501 /* Add PCH MSI node */ 502 fdt_add_pch_msi_node(lvms, &eiointc_phandle, &pch_msi_phandle); 503 /* Add pcie node */ 504 fdt_add_pcie_node(lvms, &pch_pic_phandle, &pch_msi_phandle); 505 506 /* 507 * Create uart fdt node in reverse order so that they appear 508 * in the finished device tree lowest address first 509 */ 510 for (i = VIRT_UART_COUNT; i-- > 0;) { 511 hwaddr base = VIRT_UART_BASE + i * VIRT_UART_SIZE; 512 int irq = VIRT_UART_IRQ + i - VIRT_GSI_BASE; 513 fdt_add_uart_node(lvms, &pch_pic_phandle, base, irq, i == 0); 514 } 515 516 fdt_add_rtc_node(lvms, &pch_pic_phandle); 517 fdt_add_ged_reset(lvms); 518 platform_bus_add_all_fdt_nodes(machine->fdt, "/platic", 519 VIRT_PLATFORM_BUS_BASEADDRESS, 520 VIRT_PLATFORM_BUS_SIZE, 521 VIRT_PLATFORM_BUS_IRQ); 522 523 /* 524 * Since lowmem region starts from 0 and Linux kernel legacy start address 525 * at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer 526 * access. FDT size limit with 1 MiB. 527 * Put the FDT into the memory map as a ROM image: this will ensure 528 * the FDT is copied again upon reset, even if addr points into RAM. 529 */ 530 qemu_fdt_dumpdtb(machine->fdt, lvms->fdt_size); 531 rom_add_blob_fixed_as("fdt", machine->fdt, lvms->fdt_size, FDT_BASE, 532 &address_space_memory); 533 qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, 534 rom_ptr_for_as(&address_space_memory, FDT_BASE, lvms->fdt_size)); 535 } 536