xref: /openbmc/qemu/hw/loongarch/virt-fdt-build.c (revision 8109ebdb95c45d9062c7e6e7beae0ee571fca4f8)
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