1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * QEMU loongson 3a5000 develop board emulation
5 * Copyright (c) 2021 Loongson Technology Corporation Limited
7 #include "qemu/osdep.h"
8 #include "qemu/units.h"
9 #include "qemu/datadir.h"
10 #include "qapi/error.h"
11 #include "hw/boards.h"
12 #include "hw/char/serial.h"
13 #include "sysemu/sysemu.h"
14 #include "sysemu/qtest.h"
15 #include "sysemu/runstate.h"
16 #include "sysemu/reset.h"
17 #include "sysemu/rtc.h"
18 #include "hw/loongarch/virt.h"
19 #include "exec/address-spaces.h"
22 #include "hw/loader.h"
24 #include "hw/intc/loongarch_ipi.h"
25 #include "hw/intc/loongarch_extioi.h"
26 #include "hw/intc/loongarch_pch_pic.h"
27 #include "hw/intc/loongarch_pch_msi.h"
28 #include "hw/pci-host/ls7a.h"
29 #include "hw/pci-host/gpex.h"
30 #include "hw/misc/unimp.h"
31 #include "hw/loongarch/fw_cfg.h"
32 #include "target/loongarch/cpu.h"
33 #include "hw/firmware/smbios.h"
34 #include "hw/acpi/aml-build.h"
35 #include "qapi/qapi-visit-common.h"
36 #include "hw/acpi/generic_event_device.h"
37 #include "hw/mem/nvdimm.h"
38 #include "sysemu/device_tree.h"
40 #include "hw/core/sysbus-fdt.h"
41 #include "hw/platform-bus.h"
42 #include "hw/display/ramfb.h"
43 #include "hw/mem/pc-dimm.h"
44 #include "sysemu/tpm.h"
45 #include "sysemu/block-backend.h"
46 #include "hw/block/flash.h"
47 #include "qemu/error-report.h"
49 static PFlashCFI01
*virt_flash_create1(LoongArchVirtMachineState
*lvms
,
51 const char *alias_prop_name
)
53 DeviceState
*dev
= qdev_new(TYPE_PFLASH_CFI01
);
55 qdev_prop_set_uint64(dev
, "sector-length", VIRT_FLASH_SECTOR_SIZE
);
56 qdev_prop_set_uint8(dev
, "width", 4);
57 qdev_prop_set_uint8(dev
, "device-width", 2);
58 qdev_prop_set_bit(dev
, "big-endian", false);
59 qdev_prop_set_uint16(dev
, "id0", 0x89);
60 qdev_prop_set_uint16(dev
, "id1", 0x18);
61 qdev_prop_set_uint16(dev
, "id2", 0x00);
62 qdev_prop_set_uint16(dev
, "id3", 0x00);
63 qdev_prop_set_string(dev
, "name", name
);
64 object_property_add_child(OBJECT(lvms
), name
, OBJECT(dev
));
65 object_property_add_alias(OBJECT(lvms
), alias_prop_name
,
66 OBJECT(dev
), "drive");
67 return PFLASH_CFI01(dev
);
70 static void virt_flash_create(LoongArchVirtMachineState
*lvms
)
72 lvms
->flash
[0] = virt_flash_create1(lvms
, "virt.flash0", "pflash0");
73 lvms
->flash
[1] = virt_flash_create1(lvms
, "virt.flash1", "pflash1");
76 static void virt_flash_map1(PFlashCFI01
*flash
,
77 hwaddr base
, hwaddr size
,
80 DeviceState
*dev
= DEVICE(flash
);
82 hwaddr real_size
= size
;
84 blk
= pflash_cfi01_get_blk(flash
);
86 real_size
= blk_getlength(blk
);
87 assert(real_size
&& real_size
<= size
);
90 assert(QEMU_IS_ALIGNED(real_size
, VIRT_FLASH_SECTOR_SIZE
));
91 assert(real_size
/ VIRT_FLASH_SECTOR_SIZE
<= UINT32_MAX
);
93 qdev_prop_set_uint32(dev
, "num-blocks", real_size
/ VIRT_FLASH_SECTOR_SIZE
);
94 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev
), &error_fatal
);
95 memory_region_add_subregion(sysmem
, base
,
96 sysbus_mmio_get_region(SYS_BUS_DEVICE(dev
), 0));
99 static void virt_flash_map(LoongArchVirtMachineState
*lvms
,
100 MemoryRegion
*sysmem
)
102 PFlashCFI01
*flash0
= lvms
->flash
[0];
103 PFlashCFI01
*flash1
= lvms
->flash
[1];
105 virt_flash_map1(flash0
, VIRT_FLASH0_BASE
, VIRT_FLASH0_SIZE
, sysmem
);
106 virt_flash_map1(flash1
, VIRT_FLASH1_BASE
, VIRT_FLASH1_SIZE
, sysmem
);
109 static void fdt_add_cpuic_node(LoongArchVirtMachineState
*lvms
,
110 uint32_t *cpuintc_phandle
)
112 MachineState
*ms
= MACHINE(lvms
);
115 *cpuintc_phandle
= qemu_fdt_alloc_phandle(ms
->fdt
);
116 nodename
= g_strdup_printf("/cpuic");
117 qemu_fdt_add_subnode(ms
->fdt
, nodename
);
118 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "phandle", *cpuintc_phandle
);
119 qemu_fdt_setprop_string(ms
->fdt
, nodename
, "compatible",
120 "loongson,cpu-interrupt-controller");
121 qemu_fdt_setprop(ms
->fdt
, nodename
, "interrupt-controller", NULL
, 0);
122 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "#interrupt-cells", 1);
126 static void fdt_add_eiointc_node(LoongArchVirtMachineState
*lvms
,
127 uint32_t *cpuintc_phandle
,
128 uint32_t *eiointc_phandle
)
130 MachineState
*ms
= MACHINE(lvms
);
132 hwaddr extioi_base
= APIC_BASE
;
133 hwaddr extioi_size
= EXTIOI_SIZE
;
135 *eiointc_phandle
= qemu_fdt_alloc_phandle(ms
->fdt
);
136 nodename
= g_strdup_printf("/eiointc@%" PRIx64
, extioi_base
);
137 qemu_fdt_add_subnode(ms
->fdt
, nodename
);
138 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "phandle", *eiointc_phandle
);
139 qemu_fdt_setprop_string(ms
->fdt
, nodename
, "compatible",
140 "loongson,ls2k2000-eiointc");
141 qemu_fdt_setprop(ms
->fdt
, nodename
, "interrupt-controller", NULL
, 0);
142 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "#interrupt-cells", 1);
143 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "interrupt-parent",
145 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "interrupts", 3);
146 qemu_fdt_setprop_cells(ms
->fdt
, nodename
, "reg", 0x0,
147 extioi_base
, 0x0, extioi_size
);
151 static void fdt_add_pch_pic_node(LoongArchVirtMachineState
*lvms
,
152 uint32_t *eiointc_phandle
,
153 uint32_t *pch_pic_phandle
)
155 MachineState
*ms
= MACHINE(lvms
);
157 hwaddr pch_pic_base
= VIRT_PCH_REG_BASE
;
158 hwaddr pch_pic_size
= VIRT_PCH_REG_SIZE
;
160 *pch_pic_phandle
= qemu_fdt_alloc_phandle(ms
->fdt
);
161 nodename
= g_strdup_printf("/platic@%" PRIx64
, pch_pic_base
);
162 qemu_fdt_add_subnode(ms
->fdt
, nodename
);
163 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "phandle", *pch_pic_phandle
);
164 qemu_fdt_setprop_string(ms
->fdt
, nodename
, "compatible",
165 "loongson,pch-pic-1.0");
166 qemu_fdt_setprop_cells(ms
->fdt
, nodename
, "reg", 0,
167 pch_pic_base
, 0, pch_pic_size
);
168 qemu_fdt_setprop(ms
->fdt
, nodename
, "interrupt-controller", NULL
, 0);
169 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "#interrupt-cells", 2);
170 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "interrupt-parent",
172 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "loongson,pic-base-vec", 0);
176 static void fdt_add_pch_msi_node(LoongArchVirtMachineState
*lvms
,
177 uint32_t *eiointc_phandle
,
178 uint32_t *pch_msi_phandle
)
180 MachineState
*ms
= MACHINE(lvms
);
182 hwaddr pch_msi_base
= VIRT_PCH_MSI_ADDR_LOW
;
183 hwaddr pch_msi_size
= VIRT_PCH_MSI_SIZE
;
185 *pch_msi_phandle
= qemu_fdt_alloc_phandle(ms
->fdt
);
186 nodename
= g_strdup_printf("/msi@%" PRIx64
, pch_msi_base
);
187 qemu_fdt_add_subnode(ms
->fdt
, nodename
);
188 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "phandle", *pch_msi_phandle
);
189 qemu_fdt_setprop_string(ms
->fdt
, nodename
, "compatible",
190 "loongson,pch-msi-1.0");
191 qemu_fdt_setprop_cells(ms
->fdt
, nodename
, "reg",
194 qemu_fdt_setprop(ms
->fdt
, nodename
, "interrupt-controller", NULL
, 0);
195 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "interrupt-parent",
197 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "loongson,msi-base-vec",
198 VIRT_PCH_PIC_IRQ_NUM
);
199 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "loongson,msi-num-vecs",
200 EXTIOI_IRQS
- VIRT_PCH_PIC_IRQ_NUM
);
204 static void fdt_add_flash_node(LoongArchVirtMachineState
*lvms
)
206 MachineState
*ms
= MACHINE(lvms
);
208 MemoryRegion
*flash_mem
;
216 flash_mem
= pflash_cfi01_get_memory(lvms
->flash
[0]);
217 flash0_base
= flash_mem
->addr
;
218 flash0_size
= memory_region_size(flash_mem
);
220 flash_mem
= pflash_cfi01_get_memory(lvms
->flash
[1]);
221 flash1_base
= flash_mem
->addr
;
222 flash1_size
= memory_region_size(flash_mem
);
224 nodename
= g_strdup_printf("/flash@%" PRIx64
, flash0_base
);
225 qemu_fdt_add_subnode(ms
->fdt
, nodename
);
226 qemu_fdt_setprop_string(ms
->fdt
, nodename
, "compatible", "cfi-flash");
227 qemu_fdt_setprop_sized_cells(ms
->fdt
, nodename
, "reg",
228 2, flash0_base
, 2, flash0_size
,
229 2, flash1_base
, 2, flash1_size
);
230 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "bank-width", 4);
234 static void fdt_add_rtc_node(LoongArchVirtMachineState
*lvms
,
235 uint32_t *pch_pic_phandle
)
238 hwaddr base
= VIRT_RTC_REG_BASE
;
239 hwaddr size
= VIRT_RTC_LEN
;
240 MachineState
*ms
= MACHINE(lvms
);
242 nodename
= g_strdup_printf("/rtc@%" PRIx64
, base
);
243 qemu_fdt_add_subnode(ms
->fdt
, nodename
);
244 qemu_fdt_setprop_string(ms
->fdt
, nodename
, "compatible",
245 "loongson,ls7a-rtc");
246 qemu_fdt_setprop_sized_cells(ms
->fdt
, nodename
, "reg", 2, base
, 2, size
);
247 qemu_fdt_setprop_cells(ms
->fdt
, nodename
, "interrupts",
248 VIRT_RTC_IRQ
- VIRT_GSI_BASE
, 0x4);
249 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "interrupt-parent",
254 static void fdt_add_uart_node(LoongArchVirtMachineState
*lvms
,
255 uint32_t *pch_pic_phandle
)
258 hwaddr base
= VIRT_UART_BASE
;
259 hwaddr size
= VIRT_UART_SIZE
;
260 MachineState
*ms
= MACHINE(lvms
);
262 nodename
= g_strdup_printf("/serial@%" PRIx64
, base
);
263 qemu_fdt_add_subnode(ms
->fdt
, nodename
);
264 qemu_fdt_setprop_string(ms
->fdt
, nodename
, "compatible", "ns16550a");
265 qemu_fdt_setprop_cells(ms
->fdt
, nodename
, "reg", 0x0, base
, 0x0, size
);
266 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "clock-frequency", 100000000);
267 qemu_fdt_setprop_string(ms
->fdt
, "/chosen", "stdout-path", nodename
);
268 qemu_fdt_setprop_cells(ms
->fdt
, nodename
, "interrupts",
269 VIRT_UART_IRQ
- VIRT_GSI_BASE
, 0x4);
270 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "interrupt-parent",
275 static void create_fdt(LoongArchVirtMachineState
*lvms
)
277 MachineState
*ms
= MACHINE(lvms
);
279 ms
->fdt
= create_device_tree(&lvms
->fdt_size
);
281 error_report("create_device_tree() failed");
286 qemu_fdt_setprop_string(ms
->fdt
, "/", "compatible",
287 "linux,dummy-loongson3");
288 qemu_fdt_setprop_cell(ms
->fdt
, "/", "#address-cells", 0x2);
289 qemu_fdt_setprop_cell(ms
->fdt
, "/", "#size-cells", 0x2);
290 qemu_fdt_add_subnode(ms
->fdt
, "/chosen");
293 static void fdt_add_cpu_nodes(const LoongArchVirtMachineState
*lvms
)
296 const MachineState
*ms
= MACHINE(lvms
);
297 int smp_cpus
= ms
->smp
.cpus
;
299 qemu_fdt_add_subnode(ms
->fdt
, "/cpus");
300 qemu_fdt_setprop_cell(ms
->fdt
, "/cpus", "#address-cells", 0x1);
301 qemu_fdt_setprop_cell(ms
->fdt
, "/cpus", "#size-cells", 0x0);
304 for (num
= smp_cpus
- 1; num
>= 0; num
--) {
305 char *nodename
= g_strdup_printf("/cpus/cpu@%d", num
);
306 LoongArchCPU
*cpu
= LOONGARCH_CPU(qemu_get_cpu(num
));
307 CPUState
*cs
= CPU(cpu
);
309 qemu_fdt_add_subnode(ms
->fdt
, nodename
);
310 qemu_fdt_setprop_string(ms
->fdt
, nodename
, "device_type", "cpu");
311 qemu_fdt_setprop_string(ms
->fdt
, nodename
, "compatible",
312 cpu
->dtb_compatible
);
313 if (ms
->possible_cpus
->cpus
[cs
->cpu_index
].props
.has_node_id
) {
314 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "numa-node-id",
315 ms
->possible_cpus
->cpus
[cs
->cpu_index
].props
.node_id
);
317 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "reg", num
);
318 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "phandle",
319 qemu_fdt_alloc_phandle(ms
->fdt
));
324 qemu_fdt_add_subnode(ms
->fdt
, "/cpus/cpu-map");
326 for (num
= smp_cpus
- 1; num
>= 0; num
--) {
327 char *cpu_path
= g_strdup_printf("/cpus/cpu@%d", num
);
330 if (ms
->smp
.threads
> 1) {
331 map_path
= g_strdup_printf(
332 "/cpus/cpu-map/socket%d/core%d/thread%d",
333 num
/ (ms
->smp
.cores
* ms
->smp
.threads
),
334 (num
/ ms
->smp
.threads
) % ms
->smp
.cores
,
335 num
% ms
->smp
.threads
);
337 map_path
= g_strdup_printf(
338 "/cpus/cpu-map/socket%d/core%d",
340 num
% ms
->smp
.cores
);
342 qemu_fdt_add_path(ms
->fdt
, map_path
);
343 qemu_fdt_setprop_phandle(ms
->fdt
, map_path
, "cpu", cpu_path
);
350 static void fdt_add_fw_cfg_node(const LoongArchVirtMachineState
*lvms
)
353 hwaddr base
= VIRT_FWCFG_BASE
;
354 const MachineState
*ms
= MACHINE(lvms
);
356 nodename
= g_strdup_printf("/fw_cfg@%" PRIx64
, base
);
357 qemu_fdt_add_subnode(ms
->fdt
, nodename
);
358 qemu_fdt_setprop_string(ms
->fdt
, nodename
,
359 "compatible", "qemu,fw-cfg-mmio");
360 qemu_fdt_setprop_sized_cells(ms
->fdt
, nodename
, "reg",
362 qemu_fdt_setprop(ms
->fdt
, nodename
, "dma-coherent", NULL
, 0);
366 static void fdt_add_pcie_irq_map_node(const LoongArchVirtMachineState
*lvms
,
368 uint32_t *pch_pic_phandle
)
371 uint32_t irq_map_stride
= 0;
372 uint32_t full_irq_map
[GPEX_NUM_IRQS
*GPEX_NUM_IRQS
* 10] = {};
373 uint32_t *irq_map
= full_irq_map
;
374 const MachineState
*ms
= MACHINE(lvms
);
376 /* This code creates a standard swizzle of interrupts such that
377 * each device's first interrupt is based on it's PCI_SLOT number.
378 * (See pci_swizzle_map_irq_fn())
380 * We only need one entry per interrupt in the table (not one per
381 * possible slot) seeing the interrupt-map-mask will allow the table
382 * to wrap to any number of devices.
385 for (dev
= 0; dev
< GPEX_NUM_IRQS
; dev
++) {
386 int devfn
= dev
* 0x8;
388 for (pin
= 0; pin
< GPEX_NUM_IRQS
; pin
++) {
389 int irq_nr
= 16 + ((pin
+ PCI_SLOT(devfn
)) % GPEX_NUM_IRQS
);
392 /* Fill PCI address cells */
393 irq_map
[i
] = cpu_to_be32(devfn
<< 8);
396 /* Fill PCI Interrupt cells */
397 irq_map
[i
] = cpu_to_be32(pin
+ 1);
400 /* Fill interrupt controller phandle and cells */
401 irq_map
[i
++] = cpu_to_be32(*pch_pic_phandle
);
402 irq_map
[i
++] = cpu_to_be32(irq_nr
);
404 if (!irq_map_stride
) {
407 irq_map
+= irq_map_stride
;
412 qemu_fdt_setprop(ms
->fdt
, nodename
, "interrupt-map", full_irq_map
,
413 GPEX_NUM_IRQS
* GPEX_NUM_IRQS
*
414 irq_map_stride
* sizeof(uint32_t));
415 qemu_fdt_setprop_cells(ms
->fdt
, nodename
, "interrupt-map-mask",
419 static void fdt_add_pcie_node(const LoongArchVirtMachineState
*lvms
,
420 uint32_t *pch_pic_phandle
,
421 uint32_t *pch_msi_phandle
)
424 hwaddr base_mmio
= VIRT_PCI_MEM_BASE
;
425 hwaddr size_mmio
= VIRT_PCI_MEM_SIZE
;
426 hwaddr base_pio
= VIRT_PCI_IO_BASE
;
427 hwaddr size_pio
= VIRT_PCI_IO_SIZE
;
428 hwaddr base_pcie
= VIRT_PCI_CFG_BASE
;
429 hwaddr size_pcie
= VIRT_PCI_CFG_SIZE
;
430 hwaddr base
= base_pcie
;
432 const MachineState
*ms
= MACHINE(lvms
);
434 nodename
= g_strdup_printf("/pcie@%" PRIx64
, base
);
435 qemu_fdt_add_subnode(ms
->fdt
, nodename
);
436 qemu_fdt_setprop_string(ms
->fdt
, nodename
,
437 "compatible", "pci-host-ecam-generic");
438 qemu_fdt_setprop_string(ms
->fdt
, nodename
, "device_type", "pci");
439 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "#address-cells", 3);
440 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "#size-cells", 2);
441 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "linux,pci-domain", 0);
442 qemu_fdt_setprop_cells(ms
->fdt
, nodename
, "bus-range", 0,
443 PCIE_MMCFG_BUS(VIRT_PCI_CFG_SIZE
- 1));
444 qemu_fdt_setprop(ms
->fdt
, nodename
, "dma-coherent", NULL
, 0);
445 qemu_fdt_setprop_sized_cells(ms
->fdt
, nodename
, "reg",
446 2, base_pcie
, 2, size_pcie
);
447 qemu_fdt_setprop_sized_cells(ms
->fdt
, nodename
, "ranges",
448 1, FDT_PCI_RANGE_IOPORT
, 2, VIRT_PCI_IO_OFFSET
,
449 2, base_pio
, 2, size_pio
,
450 1, FDT_PCI_RANGE_MMIO
, 2, base_mmio
,
451 2, base_mmio
, 2, size_mmio
);
452 qemu_fdt_setprop_cells(ms
->fdt
, nodename
, "msi-map",
453 0, *pch_msi_phandle
, 0, 0x10000);
455 fdt_add_pcie_irq_map_node(lvms
, nodename
, pch_pic_phandle
);
460 static void fdt_add_memory_node(MachineState
*ms
,
461 uint64_t base
, uint64_t size
, int node_id
)
463 char *nodename
= g_strdup_printf("/memory@%" PRIx64
, base
);
465 qemu_fdt_add_subnode(ms
->fdt
, nodename
);
466 qemu_fdt_setprop_cells(ms
->fdt
, nodename
, "reg", 0, base
, 0, size
);
467 qemu_fdt_setprop_string(ms
->fdt
, nodename
, "device_type", "memory");
469 if (ms
->numa_state
&& ms
->numa_state
->num_nodes
) {
470 qemu_fdt_setprop_cell(ms
->fdt
, nodename
, "numa-node-id", node_id
);
476 static void virt_build_smbios(LoongArchVirtMachineState
*lvms
)
478 MachineState
*ms
= MACHINE(lvms
);
479 MachineClass
*mc
= MACHINE_GET_CLASS(lvms
);
480 uint8_t *smbios_tables
, *smbios_anchor
;
481 size_t smbios_tables_len
, smbios_anchor_len
;
482 const char *product
= "QEMU Virtual Machine";
488 smbios_set_defaults("QEMU", product
, mc
->name
, true);
490 smbios_get_tables(ms
, SMBIOS_ENTRY_POINT_TYPE_64
,
492 &smbios_tables
, &smbios_tables_len
,
493 &smbios_anchor
, &smbios_anchor_len
, &error_fatal
);
496 fw_cfg_add_file(lvms
->fw_cfg
, "etc/smbios/smbios-tables",
497 smbios_tables
, smbios_tables_len
);
498 fw_cfg_add_file(lvms
->fw_cfg
, "etc/smbios/smbios-anchor",
499 smbios_anchor
, smbios_anchor_len
);
503 static void virt_done(Notifier
*notifier
, void *data
)
505 LoongArchVirtMachineState
*lvms
= container_of(notifier
,
506 LoongArchVirtMachineState
, machine_done
);
507 virt_build_smbios(lvms
);
508 loongarch_acpi_setup(lvms
);
511 static void virt_powerdown_req(Notifier
*notifier
, void *opaque
)
513 LoongArchVirtMachineState
*s
;
515 s
= container_of(notifier
, LoongArchVirtMachineState
, powerdown_notifier
);
516 acpi_send_event(s
->acpi_ged
, ACPI_POWER_DOWN_STATUS
);
519 static void memmap_add_entry(uint64_t address
, uint64_t length
, uint32_t type
)
521 /* Ensure there are no duplicate entries. */
522 for (unsigned i
= 0; i
< memmap_entries
; i
++) {
523 assert(memmap_table
[i
].address
!= address
);
526 memmap_table
= g_renew(struct memmap_entry
, memmap_table
,
528 memmap_table
[memmap_entries
].address
= cpu_to_le64(address
);
529 memmap_table
[memmap_entries
].length
= cpu_to_le64(length
);
530 memmap_table
[memmap_entries
].type
= cpu_to_le32(type
);
531 memmap_table
[memmap_entries
].reserved
= 0;
535 static DeviceState
*create_acpi_ged(DeviceState
*pch_pic
,
536 LoongArchVirtMachineState
*lvms
)
539 MachineState
*ms
= MACHINE(lvms
);
540 uint32_t event
= ACPI_GED_PWR_DOWN_EVT
;
543 event
|= ACPI_GED_MEM_HOTPLUG_EVT
;
545 dev
= qdev_new(TYPE_ACPI_GED
);
546 qdev_prop_set_uint32(dev
, "ged-event", event
);
547 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev
), &error_fatal
);
550 sysbus_mmio_map(SYS_BUS_DEVICE(dev
), 0, VIRT_GED_EVT_ADDR
);
552 sysbus_mmio_map(SYS_BUS_DEVICE(dev
), 1, VIRT_GED_MEM_ADDR
);
553 /* ged regs used for reset and power down */
554 sysbus_mmio_map(SYS_BUS_DEVICE(dev
), 2, VIRT_GED_REG_ADDR
);
556 sysbus_connect_irq(SYS_BUS_DEVICE(dev
), 0,
557 qdev_get_gpio_in(pch_pic
, VIRT_SCI_IRQ
- VIRT_GSI_BASE
));
561 static DeviceState
*create_platform_bus(DeviceState
*pch_pic
)
564 SysBusDevice
*sysbus
;
566 MemoryRegion
*sysmem
= get_system_memory();
568 dev
= qdev_new(TYPE_PLATFORM_BUS_DEVICE
);
569 dev
->id
= g_strdup(TYPE_PLATFORM_BUS_DEVICE
);
570 qdev_prop_set_uint32(dev
, "num_irqs", VIRT_PLATFORM_BUS_NUM_IRQS
);
571 qdev_prop_set_uint32(dev
, "mmio_size", VIRT_PLATFORM_BUS_SIZE
);
572 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev
), &error_fatal
);
574 sysbus
= SYS_BUS_DEVICE(dev
);
575 for (i
= 0; i
< VIRT_PLATFORM_BUS_NUM_IRQS
; i
++) {
576 irq
= VIRT_PLATFORM_BUS_IRQ
- VIRT_GSI_BASE
+ i
;
577 sysbus_connect_irq(sysbus
, i
, qdev_get_gpio_in(pch_pic
, irq
));
580 memory_region_add_subregion(sysmem
,
581 VIRT_PLATFORM_BUS_BASEADDRESS
,
582 sysbus_mmio_get_region(sysbus
, 0));
586 static void virt_devices_init(DeviceState
*pch_pic
,
587 LoongArchVirtMachineState
*lvms
,
588 uint32_t *pch_pic_phandle
,
589 uint32_t *pch_msi_phandle
)
591 MachineClass
*mc
= MACHINE_GET_CLASS(lvms
);
592 DeviceState
*gpex_dev
;
595 MemoryRegion
*ecam_alias
, *ecam_reg
, *pio_alias
, *pio_reg
;
596 MemoryRegion
*mmio_alias
, *mmio_reg
;
599 gpex_dev
= qdev_new(TYPE_GPEX_HOST
);
600 d
= SYS_BUS_DEVICE(gpex_dev
);
601 sysbus_realize_and_unref(d
, &error_fatal
);
602 pci_bus
= PCI_HOST_BRIDGE(gpex_dev
)->bus
;
603 lvms
->pci_bus
= pci_bus
;
605 /* Map only part size_ecam bytes of ECAM space */
606 ecam_alias
= g_new0(MemoryRegion
, 1);
607 ecam_reg
= sysbus_mmio_get_region(d
, 0);
608 memory_region_init_alias(ecam_alias
, OBJECT(gpex_dev
), "pcie-ecam",
609 ecam_reg
, 0, VIRT_PCI_CFG_SIZE
);
610 memory_region_add_subregion(get_system_memory(), VIRT_PCI_CFG_BASE
,
613 /* Map PCI mem space */
614 mmio_alias
= g_new0(MemoryRegion
, 1);
615 mmio_reg
= sysbus_mmio_get_region(d
, 1);
616 memory_region_init_alias(mmio_alias
, OBJECT(gpex_dev
), "pcie-mmio",
617 mmio_reg
, VIRT_PCI_MEM_BASE
, VIRT_PCI_MEM_SIZE
);
618 memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE
,
621 /* Map PCI IO port space. */
622 pio_alias
= g_new0(MemoryRegion
, 1);
623 pio_reg
= sysbus_mmio_get_region(d
, 2);
624 memory_region_init_alias(pio_alias
, OBJECT(gpex_dev
), "pcie-io", pio_reg
,
625 VIRT_PCI_IO_OFFSET
, VIRT_PCI_IO_SIZE
);
626 memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE
,
629 for (i
= 0; i
< GPEX_NUM_IRQS
; i
++) {
630 sysbus_connect_irq(d
, i
,
631 qdev_get_gpio_in(pch_pic
, 16 + i
));
632 gpex_set_irq_num(GPEX_HOST(gpex_dev
), i
, 16 + i
);
636 fdt_add_pcie_node(lvms
, pch_pic_phandle
, pch_msi_phandle
);
638 serial_mm_init(get_system_memory(), VIRT_UART_BASE
, 0,
639 qdev_get_gpio_in(pch_pic
,
640 VIRT_UART_IRQ
- VIRT_GSI_BASE
),
641 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN
);
642 fdt_add_uart_node(lvms
, pch_pic_phandle
);
645 pci_init_nic_devices(pci_bus
, mc
->default_nic
);
648 * There are some invalid guest memory access.
649 * Create some unimplemented devices to emulate this.
651 create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
652 sysbus_create_simple("ls7a_rtc", VIRT_RTC_REG_BASE
,
653 qdev_get_gpio_in(pch_pic
,
654 VIRT_RTC_IRQ
- VIRT_GSI_BASE
));
655 fdt_add_rtc_node(lvms
, pch_pic_phandle
);
658 lvms
->acpi_ged
= create_acpi_ged(pch_pic
, lvms
);
660 lvms
->platform_bus_dev
= create_platform_bus(pch_pic
);
663 static void virt_irq_init(LoongArchVirtMachineState
*lvms
)
665 MachineState
*ms
= MACHINE(lvms
);
666 DeviceState
*pch_pic
, *pch_msi
, *cpudev
;
667 DeviceState
*ipi
, *extioi
;
670 CPULoongArchState
*env
;
672 int cpu
, pin
, i
, start
, num
;
673 uint32_t cpuintc_phandle
, eiointc_phandle
, pch_pic_phandle
, pch_msi_phandle
;
676 * The connection of interrupts:
677 * +-----+ +---------+ +-------+
678 * | IPI |--> | CPUINTC | <-- | Timer |
679 * +-----+ +---------+ +-------+
687 * +---------+ +---------+
688 * | PCH-PIC | | PCH-MSI |
689 * +---------+ +---------+
692 * +--------+ +---------+ +---------+
693 * | UARTs | | Devices | | Devices |
694 * +--------+ +---------+ +---------+
697 /* Create IPI device */
698 ipi
= qdev_new(TYPE_LOONGARCH_IPI
);
699 qdev_prop_set_uint32(ipi
, "num-cpu", ms
->smp
.cpus
);
700 sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi
), &error_fatal
);
702 /* IPI iocsr memory region */
703 memory_region_add_subregion(&lvms
->system_iocsr
, SMP_IPI_MAILBOX
,
704 sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi
), 0));
705 memory_region_add_subregion(&lvms
->system_iocsr
, MAIL_SEND_ADDR
,
706 sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi
), 1));
708 /* Add cpu interrupt-controller */
709 fdt_add_cpuic_node(lvms
, &cpuintc_phandle
);
711 for (cpu
= 0; cpu
< ms
->smp
.cpus
; cpu
++) {
712 cpu_state
= qemu_get_cpu(cpu
);
713 cpudev
= DEVICE(cpu_state
);
714 lacpu
= LOONGARCH_CPU(cpu_state
);
716 env
->address_space_iocsr
= &lvms
->as_iocsr
;
718 /* connect ipi irq to cpu irq */
719 qdev_connect_gpio_out(ipi
, cpu
, qdev_get_gpio_in(cpudev
, IRQ_IPI
));
723 /* Create EXTIOI device */
724 extioi
= qdev_new(TYPE_LOONGARCH_EXTIOI
);
725 qdev_prop_set_uint32(extioi
, "num-cpu", ms
->smp
.cpus
);
726 sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi
), &error_fatal
);
727 memory_region_add_subregion(&lvms
->system_iocsr
, APIC_BASE
,
728 sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi
), 0));
731 * connect ext irq to the cpu irq
732 * cpu_pin[9:2] <= intc_pin[7:0]
734 for (cpu
= 0; cpu
< ms
->smp
.cpus
; cpu
++) {
735 cpudev
= DEVICE(qemu_get_cpu(cpu
));
736 for (pin
= 0; pin
< LS3A_INTC_IP
; pin
++) {
737 qdev_connect_gpio_out(extioi
, (cpu
* 8 + pin
),
738 qdev_get_gpio_in(cpudev
, pin
+ 2));
742 /* Add Extend I/O Interrupt Controller node */
743 fdt_add_eiointc_node(lvms
, &cpuintc_phandle
, &eiointc_phandle
);
745 pch_pic
= qdev_new(TYPE_LOONGARCH_PCH_PIC
);
746 num
= VIRT_PCH_PIC_IRQ_NUM
;
747 qdev_prop_set_uint32(pch_pic
, "pch_pic_irq_num", num
);
748 d
= SYS_BUS_DEVICE(pch_pic
);
749 sysbus_realize_and_unref(d
, &error_fatal
);
750 memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE
,
751 sysbus_mmio_get_region(d
, 0));
752 memory_region_add_subregion(get_system_memory(),
753 VIRT_IOAPIC_REG_BASE
+ PCH_PIC_ROUTE_ENTRY_OFFSET
,
754 sysbus_mmio_get_region(d
, 1));
755 memory_region_add_subregion(get_system_memory(),
756 VIRT_IOAPIC_REG_BASE
+ PCH_PIC_INT_STATUS_LO
,
757 sysbus_mmio_get_region(d
, 2));
759 /* Connect pch_pic irqs to extioi */
760 for (i
= 0; i
< num
; i
++) {
761 qdev_connect_gpio_out(DEVICE(d
), i
, qdev_get_gpio_in(extioi
, i
));
764 /* Add PCH PIC node */
765 fdt_add_pch_pic_node(lvms
, &eiointc_phandle
, &pch_pic_phandle
);
767 pch_msi
= qdev_new(TYPE_LOONGARCH_PCH_MSI
);
769 num
= EXTIOI_IRQS
- start
;
770 qdev_prop_set_uint32(pch_msi
, "msi_irq_base", start
);
771 qdev_prop_set_uint32(pch_msi
, "msi_irq_num", num
);
772 d
= SYS_BUS_DEVICE(pch_msi
);
773 sysbus_realize_and_unref(d
, &error_fatal
);
774 sysbus_mmio_map(d
, 0, VIRT_PCH_MSI_ADDR_LOW
);
775 for (i
= 0; i
< num
; i
++) {
776 /* Connect pch_msi irqs to extioi */
777 qdev_connect_gpio_out(DEVICE(d
), i
,
778 qdev_get_gpio_in(extioi
, i
+ start
));
781 /* Add PCH MSI node */
782 fdt_add_pch_msi_node(lvms
, &eiointc_phandle
, &pch_msi_phandle
);
784 virt_devices_init(pch_pic
, lvms
, &pch_pic_phandle
, &pch_msi_phandle
);
787 static void virt_firmware_init(LoongArchVirtMachineState
*lvms
)
789 char *filename
= MACHINE(lvms
)->firmware
;
790 char *bios_name
= NULL
;
792 BlockBackend
*pflash_blk0
;
795 lvms
->bios_loaded
= false;
797 /* Map legacy -drive if=pflash to machine properties */
798 for (i
= 0; i
< ARRAY_SIZE(lvms
->flash
); i
++) {
799 pflash_cfi01_legacy_drive(lvms
->flash
[i
],
800 drive_get(IF_PFLASH
, 0, i
));
803 virt_flash_map(lvms
, get_system_memory());
805 pflash_blk0
= pflash_cfi01_get_blk(lvms
->flash
[0]);
809 error_report("cannot use both '-bios' and '-drive if=pflash'"
813 lvms
->bios_loaded
= true;
818 bios_name
= qemu_find_file(QEMU_FILE_TYPE_BIOS
, filename
);
820 error_report("Could not find ROM image '%s'", filename
);
824 mr
= sysbus_mmio_get_region(SYS_BUS_DEVICE(lvms
->flash
[0]), 0);
825 bios_size
= load_image_mr(bios_name
, mr
);
827 error_report("Could not load ROM image '%s'", bios_name
);
831 lvms
->bios_loaded
= true;
836 static void virt_iocsr_misc_write(void *opaque
, hwaddr addr
,
837 uint64_t val
, unsigned size
)
841 static uint64_t virt_iocsr_misc_read(void *opaque
, hwaddr addr
, unsigned size
)
847 return 1ULL << IOCSRF_MSI
| 1ULL << IOCSRF_EXTIOI
|
848 1ULL << IOCSRF_CSRIPI
;
850 return 0x6e6f73676e6f6f4cULL
; /* "Loongson" */
852 return 0x303030354133ULL
; /* "3A5000" */
854 return 1ULL << IOCSRM_EXTIOI_EN
;
859 static const MemoryRegionOps virt_iocsr_misc_ops
= {
860 .read
= virt_iocsr_misc_read
,
861 .write
= virt_iocsr_misc_write
,
862 .endianness
= DEVICE_LITTLE_ENDIAN
,
864 .min_access_size
= 4,
865 .max_access_size
= 8,
868 .min_access_size
= 8,
869 .max_access_size
= 8,
873 static void virt_init(MachineState
*machine
)
876 const char *cpu_model
= machine
->cpu_type
;
877 ram_addr_t offset
= 0;
878 ram_addr_t ram_size
= machine
->ram_size
;
879 uint64_t highram_size
= 0, phyAddr
= 0;
880 MemoryRegion
*address_space_mem
= get_system_memory();
881 LoongArchVirtMachineState
*lvms
= LOONGARCH_VIRT_MACHINE(machine
);
882 int nb_numa_nodes
= machine
->numa_state
->num_nodes
;
883 NodeInfo
*numa_info
= machine
->numa_state
->nodes
;
885 const CPUArchIdList
*possible_cpus
;
886 MachineClass
*mc
= MACHINE_GET_CLASS(machine
);
890 cpu_model
= LOONGARCH_CPU_TYPE_NAME("la464");
893 if (ram_size
< 1 * GiB
) {
894 error_report("ram_size must be greater than 1G.");
899 /* Create IOCSR space */
900 memory_region_init_io(&lvms
->system_iocsr
, OBJECT(machine
), NULL
,
901 machine
, "iocsr", UINT64_MAX
);
902 address_space_init(&lvms
->as_iocsr
, &lvms
->system_iocsr
, "IOCSR");
903 memory_region_init_io(&lvms
->iocsr_mem
, OBJECT(machine
),
904 &virt_iocsr_misc_ops
,
905 machine
, "iocsr_misc", 0x428);
906 memory_region_add_subregion(&lvms
->system_iocsr
, 0, &lvms
->iocsr_mem
);
909 possible_cpus
= mc
->possible_cpu_arch_ids(machine
);
910 for (i
= 0; i
< possible_cpus
->len
; i
++) {
911 cpu
= cpu_create(machine
->cpu_type
);
913 machine
->possible_cpus
->cpus
[i
].cpu
= cpu
;
914 lacpu
= LOONGARCH_CPU(cpu
);
915 lacpu
->phy_id
= machine
->possible_cpus
->cpus
[i
].arch_id
;
917 fdt_add_cpu_nodes(lvms
);
920 memmap_add_entry(VIRT_LOWMEM_BASE
, VIRT_LOWMEM_SIZE
, 1);
921 fdt_add_memory_node(machine
, VIRT_LOWMEM_BASE
, VIRT_LOWMEM_SIZE
, 0);
922 memory_region_init_alias(&lvms
->lowmem
, NULL
, "loongarch.node0.lowram",
923 machine
->ram
, offset
, VIRT_LOWMEM_SIZE
);
924 memory_region_add_subregion(address_space_mem
, phyAddr
, &lvms
->lowmem
);
926 offset
+= VIRT_LOWMEM_SIZE
;
927 if (nb_numa_nodes
> 0) {
928 assert(numa_info
[0].node_mem
> VIRT_LOWMEM_SIZE
);
929 highram_size
= numa_info
[0].node_mem
- VIRT_LOWMEM_SIZE
;
931 highram_size
= ram_size
- VIRT_LOWMEM_SIZE
;
933 phyAddr
= VIRT_HIGHMEM_BASE
;
934 memmap_add_entry(phyAddr
, highram_size
, 1);
935 fdt_add_memory_node(machine
, phyAddr
, highram_size
, 0);
936 memory_region_init_alias(&lvms
->highmem
, NULL
, "loongarch.node0.highram",
937 machine
->ram
, offset
, highram_size
);
938 memory_region_add_subregion(address_space_mem
, phyAddr
, &lvms
->highmem
);
940 /* Node1 - Nodemax memory */
941 offset
+= highram_size
;
942 phyAddr
+= highram_size
;
944 for (i
= 1; i
< nb_numa_nodes
; i
++) {
945 MemoryRegion
*nodemem
= g_new(MemoryRegion
, 1);
946 g_autofree
char *ramName
= g_strdup_printf("loongarch.node%d.ram", i
);
947 memory_region_init_alias(nodemem
, NULL
, ramName
, machine
->ram
,
948 offset
, numa_info
[i
].node_mem
);
949 memory_region_add_subregion(address_space_mem
, phyAddr
, nodemem
);
950 memmap_add_entry(phyAddr
, numa_info
[i
].node_mem
, 1);
951 fdt_add_memory_node(machine
, phyAddr
, numa_info
[i
].node_mem
, i
);
952 offset
+= numa_info
[i
].node_mem
;
953 phyAddr
+= numa_info
[i
].node_mem
;
956 /* initialize device memory address space */
957 if (machine
->ram_size
< machine
->maxram_size
) {
958 ram_addr_t device_mem_size
= machine
->maxram_size
- machine
->ram_size
;
959 hwaddr device_mem_base
;
961 if (machine
->ram_slots
> ACPI_MAX_RAM_SLOTS
) {
962 error_report("unsupported amount of memory slots: %"PRIu64
,
967 if (QEMU_ALIGN_UP(machine
->maxram_size
,
968 TARGET_PAGE_SIZE
) != machine
->maxram_size
) {
969 error_report("maximum memory size must by aligned to multiple of "
970 "%d bytes", TARGET_PAGE_SIZE
);
973 /* device memory base is the top of high memory address. */
974 device_mem_base
= ROUND_UP(VIRT_HIGHMEM_BASE
+ highram_size
, 1 * GiB
);
975 machine_memory_devices_init(machine
, device_mem_base
, device_mem_size
);
978 /* load the BIOS image. */
979 virt_firmware_init(lvms
);
982 lvms
->fw_cfg
= virt_fw_cfg_init(ram_size
, machine
);
983 rom_set_fw(lvms
->fw_cfg
);
984 if (lvms
->fw_cfg
!= NULL
) {
985 fw_cfg_add_file(lvms
->fw_cfg
, "etc/memmap",
987 sizeof(struct memmap_entry
) * (memmap_entries
));
989 fdt_add_fw_cfg_node(lvms
);
990 fdt_add_flash_node(lvms
);
992 /* Initialize the IO interrupt subsystem */
994 platform_bus_add_all_fdt_nodes(machine
->fdt
, "/platic",
995 VIRT_PLATFORM_BUS_BASEADDRESS
,
996 VIRT_PLATFORM_BUS_SIZE
,
997 VIRT_PLATFORM_BUS_IRQ
);
998 lvms
->machine_done
.notify
= virt_done
;
999 qemu_add_machine_init_done_notifier(&lvms
->machine_done
);
1000 /* connect powerdown request */
1001 lvms
->powerdown_notifier
.notify
= virt_powerdown_req
;
1002 qemu_register_powerdown_notifier(&lvms
->powerdown_notifier
);
1005 * Since lowmem region starts from 0 and Linux kernel legacy start address
1006 * at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer
1007 * access. FDT size limit with 1 MiB.
1008 * Put the FDT into the memory map as a ROM image: this will ensure
1009 * the FDT is copied again upon reset, even if addr points into RAM.
1011 qemu_fdt_dumpdtb(machine
->fdt
, lvms
->fdt_size
);
1012 rom_add_blob_fixed_as("fdt", machine
->fdt
, lvms
->fdt_size
, FDT_BASE
,
1013 &address_space_memory
);
1014 qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds
,
1015 rom_ptr_for_as(&address_space_memory
, FDT_BASE
, lvms
->fdt_size
));
1017 lvms
->bootinfo
.ram_size
= ram_size
;
1018 loongarch_load_kernel(machine
, &lvms
->bootinfo
);
1021 static void virt_get_acpi(Object
*obj
, Visitor
*v
, const char *name
,
1022 void *opaque
, Error
**errp
)
1024 LoongArchVirtMachineState
*lvms
= LOONGARCH_VIRT_MACHINE(obj
);
1025 OnOffAuto acpi
= lvms
->acpi
;
1027 visit_type_OnOffAuto(v
, name
, &acpi
, errp
);
1030 static void virt_set_acpi(Object
*obj
, Visitor
*v
, const char *name
,
1031 void *opaque
, Error
**errp
)
1033 LoongArchVirtMachineState
*lvms
= LOONGARCH_VIRT_MACHINE(obj
);
1035 visit_type_OnOffAuto(v
, name
, &lvms
->acpi
, errp
);
1038 static void virt_initfn(Object
*obj
)
1040 LoongArchVirtMachineState
*lvms
= LOONGARCH_VIRT_MACHINE(obj
);
1042 lvms
->acpi
= ON_OFF_AUTO_AUTO
;
1043 lvms
->oem_id
= g_strndup(ACPI_BUILD_APPNAME6
, 6);
1044 lvms
->oem_table_id
= g_strndup(ACPI_BUILD_APPNAME8
, 8);
1045 virt_flash_create(lvms
);
1048 static bool memhp_type_supported(DeviceState
*dev
)
1050 /* we only support pc dimm now */
1051 return object_dynamic_cast(OBJECT(dev
), TYPE_PC_DIMM
) &&
1052 !object_dynamic_cast(OBJECT(dev
), TYPE_NVDIMM
);
1055 static void virt_mem_pre_plug(HotplugHandler
*hotplug_dev
, DeviceState
*dev
,
1058 pc_dimm_pre_plug(PC_DIMM(dev
), MACHINE(hotplug_dev
), NULL
, errp
);
1061 static void virt_device_pre_plug(HotplugHandler
*hotplug_dev
,
1062 DeviceState
*dev
, Error
**errp
)
1064 if (memhp_type_supported(dev
)) {
1065 virt_mem_pre_plug(hotplug_dev
, dev
, errp
);
1069 static void virt_mem_unplug_request(HotplugHandler
*hotplug_dev
,
1070 DeviceState
*dev
, Error
**errp
)
1072 LoongArchVirtMachineState
*lvms
= LOONGARCH_VIRT_MACHINE(hotplug_dev
);
1074 /* the acpi ged is always exist */
1075 hotplug_handler_unplug_request(HOTPLUG_HANDLER(lvms
->acpi_ged
), dev
,
1079 static void virt_device_unplug_request(HotplugHandler
*hotplug_dev
,
1080 DeviceState
*dev
, Error
**errp
)
1082 if (memhp_type_supported(dev
)) {
1083 virt_mem_unplug_request(hotplug_dev
, dev
, errp
);
1087 static void virt_mem_unplug(HotplugHandler
*hotplug_dev
,
1088 DeviceState
*dev
, Error
**errp
)
1090 LoongArchVirtMachineState
*lvms
= LOONGARCH_VIRT_MACHINE(hotplug_dev
);
1092 hotplug_handler_unplug(HOTPLUG_HANDLER(lvms
->acpi_ged
), dev
, errp
);
1093 pc_dimm_unplug(PC_DIMM(dev
), MACHINE(lvms
));
1094 qdev_unrealize(dev
);
1097 static void virt_device_unplug(HotplugHandler
*hotplug_dev
,
1098 DeviceState
*dev
, Error
**errp
)
1100 if (memhp_type_supported(dev
)) {
1101 virt_mem_unplug(hotplug_dev
, dev
, errp
);
1105 static void virt_mem_plug(HotplugHandler
*hotplug_dev
,
1106 DeviceState
*dev
, Error
**errp
)
1108 LoongArchVirtMachineState
*lvms
= LOONGARCH_VIRT_MACHINE(hotplug_dev
);
1110 pc_dimm_plug(PC_DIMM(dev
), MACHINE(lvms
));
1111 hotplug_handler_plug(HOTPLUG_HANDLER(lvms
->acpi_ged
),
1115 static void virt_device_plug_cb(HotplugHandler
*hotplug_dev
,
1116 DeviceState
*dev
, Error
**errp
)
1118 LoongArchVirtMachineState
*lvms
= LOONGARCH_VIRT_MACHINE(hotplug_dev
);
1119 MachineClass
*mc
= MACHINE_GET_CLASS(lvms
);
1120 PlatformBusDevice
*pbus
;
1122 if (device_is_dynamic_sysbus(mc
, dev
)) {
1123 if (lvms
->platform_bus_dev
) {
1124 pbus
= PLATFORM_BUS_DEVICE(lvms
->platform_bus_dev
);
1125 platform_bus_link_device(pbus
, SYS_BUS_DEVICE(dev
));
1127 } else if (memhp_type_supported(dev
)) {
1128 virt_mem_plug(hotplug_dev
, dev
, errp
);
1132 static HotplugHandler
*virt_get_hotplug_handler(MachineState
*machine
,
1135 MachineClass
*mc
= MACHINE_GET_CLASS(machine
);
1137 if (device_is_dynamic_sysbus(mc
, dev
) ||
1138 memhp_type_supported(dev
)) {
1139 return HOTPLUG_HANDLER(machine
);
1144 static const CPUArchIdList
*virt_possible_cpu_arch_ids(MachineState
*ms
)
1147 unsigned int max_cpus
= ms
->smp
.max_cpus
;
1149 if (ms
->possible_cpus
) {
1150 assert(ms
->possible_cpus
->len
== max_cpus
);
1151 return ms
->possible_cpus
;
1154 ms
->possible_cpus
= g_malloc0(sizeof(CPUArchIdList
) +
1155 sizeof(CPUArchId
) * max_cpus
);
1156 ms
->possible_cpus
->len
= max_cpus
;
1157 for (n
= 0; n
< ms
->possible_cpus
->len
; n
++) {
1158 ms
->possible_cpus
->cpus
[n
].type
= ms
->cpu_type
;
1159 ms
->possible_cpus
->cpus
[n
].arch_id
= n
;
1161 ms
->possible_cpus
->cpus
[n
].props
.has_socket_id
= true;
1162 ms
->possible_cpus
->cpus
[n
].props
.socket_id
=
1163 n
/ (ms
->smp
.cores
* ms
->smp
.threads
);
1164 ms
->possible_cpus
->cpus
[n
].props
.has_core_id
= true;
1165 ms
->possible_cpus
->cpus
[n
].props
.core_id
=
1166 n
/ ms
->smp
.threads
% ms
->smp
.cores
;
1167 ms
->possible_cpus
->cpus
[n
].props
.has_thread_id
= true;
1168 ms
->possible_cpus
->cpus
[n
].props
.thread_id
= n
% ms
->smp
.threads
;
1170 return ms
->possible_cpus
;
1173 static CpuInstanceProperties
virt_cpu_index_to_props(MachineState
*ms
,
1176 MachineClass
*mc
= MACHINE_GET_CLASS(ms
);
1177 const CPUArchIdList
*possible_cpus
= mc
->possible_cpu_arch_ids(ms
);
1179 assert(cpu_index
< possible_cpus
->len
);
1180 return possible_cpus
->cpus
[cpu_index
].props
;
1183 static int64_t virt_get_default_cpu_node_id(const MachineState
*ms
, int idx
)
1187 if (ms
->numa_state
->num_nodes
) {
1188 nidx
= idx
/ (ms
->smp
.cpus
/ ms
->numa_state
->num_nodes
);
1189 if (ms
->numa_state
->num_nodes
<= nidx
) {
1190 nidx
= ms
->numa_state
->num_nodes
- 1;
1196 static void virt_class_init(ObjectClass
*oc
, void *data
)
1198 MachineClass
*mc
= MACHINE_CLASS(oc
);
1199 HotplugHandlerClass
*hc
= HOTPLUG_HANDLER_CLASS(oc
);
1201 mc
->init
= virt_init
;
1202 mc
->default_ram_size
= 1 * GiB
;
1203 mc
->default_cpu_type
= LOONGARCH_CPU_TYPE_NAME("la464");
1204 mc
->default_ram_id
= "loongarch.ram";
1205 mc
->max_cpus
= LOONGARCH_MAX_CPUS
;
1207 mc
->default_kernel_irqchip_split
= false;
1208 mc
->block_default_type
= IF_VIRTIO
;
1209 mc
->default_boot_order
= "c";
1211 mc
->possible_cpu_arch_ids
= virt_possible_cpu_arch_ids
;
1212 mc
->cpu_index_to_instance_props
= virt_cpu_index_to_props
;
1213 mc
->get_default_cpu_node_id
= virt_get_default_cpu_node_id
;
1214 mc
->numa_mem_supported
= true;
1215 mc
->auto_enable_numa_with_memhp
= true;
1216 mc
->auto_enable_numa_with_memdev
= true;
1217 mc
->get_hotplug_handler
= virt_get_hotplug_handler
;
1218 mc
->default_nic
= "virtio-net-pci";
1219 hc
->plug
= virt_device_plug_cb
;
1220 hc
->pre_plug
= virt_device_pre_plug
;
1221 hc
->unplug_request
= virt_device_unplug_request
;
1222 hc
->unplug
= virt_device_unplug
;
1224 object_class_property_add(oc
, "acpi", "OnOffAuto",
1225 virt_get_acpi
, virt_set_acpi
,
1227 object_class_property_set_description(oc
, "acpi",
1229 machine_class_allow_dynamic_sysbus_dev(mc
, TYPE_RAMFB_DEVICE
);
1231 machine_class_allow_dynamic_sysbus_dev(mc
, TYPE_TPM_TIS_SYSBUS
);
1235 static const TypeInfo virt_machine_types
[] = {
1237 .name
= TYPE_LOONGARCH_VIRT_MACHINE
,
1238 .parent
= TYPE_MACHINE
,
1239 .instance_size
= sizeof(LoongArchVirtMachineState
),
1240 .class_init
= virt_class_init
,
1241 .instance_init
= virt_initfn
,
1242 .interfaces
= (InterfaceInfo
[]) {
1243 { TYPE_HOTPLUG_HANDLER
},
1249 DEFINE_TYPES(virt_machine_types
)