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