2022-06-06 15:43:20 +03:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/*
|
|
|
|
* QEMU loongson 3a5000 develop board emulation
|
|
|
|
*
|
|
|
|
* Copyright (c) 2021 Loongson Technology Corporation Limited
|
|
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
|
|
#include "qemu/units.h"
|
|
|
|
#include "qemu/datadir.h"
|
|
|
|
#include "qapi/error.h"
|
|
|
|
#include "hw/boards.h"
|
2024-09-05 10:38:32 +03:00
|
|
|
#include "hw/char/serial-mm.h"
|
2024-05-14 05:51:09 +03:00
|
|
|
#include "sysemu/kvm.h"
|
2024-05-28 11:38:55 +03:00
|
|
|
#include "sysemu/tcg.h"
|
2022-06-06 15:43:20 +03:00
|
|
|
#include "sysemu/sysemu.h"
|
|
|
|
#include "sysemu/qtest.h"
|
|
|
|
#include "sysemu/runstate.h"
|
|
|
|
#include "sysemu/reset.h"
|
|
|
|
#include "sysemu/rtc.h"
|
|
|
|
#include "hw/loongarch/virt.h"
|
|
|
|
#include "exec/address-spaces.h"
|
2022-06-06 15:43:27 +03:00
|
|
|
#include "hw/irq.h"
|
|
|
|
#include "net/net.h"
|
2022-06-06 15:43:29 +03:00
|
|
|
#include "hw/loader.h"
|
|
|
|
#include "elf.h"
|
2024-07-15 17:23:48 +03:00
|
|
|
#include "hw/intc/loongarch_ipi.h"
|
2022-06-06 15:43:25 +03:00
|
|
|
#include "hw/intc/loongarch_extioi.h"
|
|
|
|
#include "hw/intc/loongarch_pch_pic.h"
|
|
|
|
#include "hw/intc/loongarch_pch_msi.h"
|
|
|
|
#include "hw/pci-host/ls7a.h"
|
2022-06-06 15:43:27 +03:00
|
|
|
#include "hw/pci-host/gpex.h"
|
|
|
|
#include "hw/misc/unimp.h"
|
2022-07-12 11:32:01 +03:00
|
|
|
#include "hw/loongarch/fw_cfg.h"
|
2022-06-06 15:43:20 +03:00
|
|
|
#include "target/loongarch/cpu.h"
|
2022-07-12 11:32:04 +03:00
|
|
|
#include "hw/firmware/smbios.h"
|
2022-07-12 11:32:05 +03:00
|
|
|
#include "hw/acpi/aml-build.h"
|
|
|
|
#include "qapi/qapi-visit-common.h"
|
|
|
|
#include "hw/acpi/generic_event_device.h"
|
|
|
|
#include "hw/mem/nvdimm.h"
|
2022-07-12 11:32:06 +03:00
|
|
|
#include "sysemu/device_tree.h"
|
|
|
|
#include <libfdt.h>
|
2022-08-10 10:50:35 +03:00
|
|
|
#include "hw/core/sysbus-fdt.h"
|
|
|
|
#include "hw/platform-bus.h"
|
2022-08-10 11:41:52 +03:00
|
|
|
#include "hw/display/ramfb.h"
|
2022-08-25 06:36:59 +03:00
|
|
|
#include "hw/mem/pc-dimm.h"
|
2022-10-28 04:40:07 +03:00
|
|
|
#include "sysemu/tpm.h"
|
2022-11-07 05:09:47 +03:00
|
|
|
#include "sysemu/block-backend.h"
|
|
|
|
#include "hw/block/flash.h"
|
2024-05-28 11:20:53 +03:00
|
|
|
#include "hw/virtio/virtio-iommu.h"
|
2023-03-15 20:43:13 +03:00
|
|
|
#include "qemu/error-report.h"
|
hw/loongarch: virt: pass random seed to fdt
If the FDT contains /chosen/rng-seed, then the Linux RNG will use it to
initialize early. Set this using the usual guest random number
generation function.
This is the same procedure that's done in b91b6b5a2c ("hw/microblaze:
pass random seed to fdt"), e4b4f0b71c ("hw/riscv: virt: pass random seed
to fdt"), c6fe3e6b4c ("hw/openrisc: virt: pass random seed to fdt"),
67f7e426e5 ("hw/i386: pass RNG seed via setup_data entry"), c287941a4d
("hw/rx: pass random seed to fdt"), 5e19cc68fb ("hw/mips: boston: pass
random seed to fdt"), 6b23a67916 ("hw/nios2: virt: pass random seed to fdt")
c4b075318e ("hw/ppc: pass random seed to fdt"), and 5242876f37
("hw/arm/virt: dt: add rng-seed property").
These earlier commits later were amended to rerandomize the RNG seed on
snapshot load, but the LoongArch code somehow already does that, despite
not having this patch here, presumably due to some lucky copy and
pasting.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240905153316.2038769-1-Jason@zx2c4.com>
Signed-off-by: Song Gao <gaosong@loongson.cn>
2024-09-05 18:33:16 +03:00
|
|
|
#include "qemu/guest-random.h"
|
2023-03-15 20:43:13 +03:00
|
|
|
|
2024-05-28 11:38:55 +03:00
|
|
|
static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms)
|
|
|
|
{
|
|
|
|
if (lvms->veiointc == ON_OFF_AUTO_OFF) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virt_get_veiointc(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
|
|
|
|
OnOffAuto veiointc = lvms->veiointc;
|
|
|
|
|
|
|
|
visit_type_OnOffAuto(v, name, &veiointc, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virt_set_veiointc(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
|
|
|
|
|
|
|
|
visit_type_OnOffAuto(v, name, &lvms->veiointc, errp);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static PFlashCFI01 *virt_flash_create1(LoongArchVirtMachineState *lvms,
|
2024-02-19 13:34:14 +03:00
|
|
|
const char *name,
|
|
|
|
const char *alias_prop_name)
|
2022-11-07 05:09:47 +03:00
|
|
|
{
|
|
|
|
DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01);
|
|
|
|
|
|
|
|
qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE);
|
|
|
|
qdev_prop_set_uint8(dev, "width", 4);
|
|
|
|
qdev_prop_set_uint8(dev, "device-width", 2);
|
|
|
|
qdev_prop_set_bit(dev, "big-endian", false);
|
|
|
|
qdev_prop_set_uint16(dev, "id0", 0x89);
|
|
|
|
qdev_prop_set_uint16(dev, "id1", 0x18);
|
|
|
|
qdev_prop_set_uint16(dev, "id2", 0x00);
|
|
|
|
qdev_prop_set_uint16(dev, "id3", 0x00);
|
2024-02-19 13:34:14 +03:00
|
|
|
qdev_prop_set_string(dev, "name", name);
|
2024-05-08 06:11:07 +03:00
|
|
|
object_property_add_child(OBJECT(lvms), name, OBJECT(dev));
|
|
|
|
object_property_add_alias(OBJECT(lvms), alias_prop_name,
|
2022-11-07 05:09:47 +03:00
|
|
|
OBJECT(dev), "drive");
|
2024-02-19 13:34:14 +03:00
|
|
|
return PFLASH_CFI01(dev);
|
|
|
|
}
|
2022-11-07 05:09:47 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_flash_create(LoongArchVirtMachineState *lvms)
|
2024-02-19 13:34:14 +03:00
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
lvms->flash[0] = virt_flash_create1(lvms, "virt.flash0", "pflash0");
|
|
|
|
lvms->flash[1] = virt_flash_create1(lvms, "virt.flash1", "pflash1");
|
2022-11-07 05:09:47 +03:00
|
|
|
}
|
|
|
|
|
2024-02-19 13:34:14 +03:00
|
|
|
static void virt_flash_map1(PFlashCFI01 *flash,
|
|
|
|
hwaddr base, hwaddr size,
|
|
|
|
MemoryRegion *sysmem)
|
2022-11-07 05:09:47 +03:00
|
|
|
{
|
|
|
|
DeviceState *dev = DEVICE(flash);
|
2024-02-19 13:34:14 +03:00
|
|
|
BlockBackend *blk;
|
|
|
|
hwaddr real_size = size;
|
|
|
|
|
|
|
|
blk = pflash_cfi01_get_blk(flash);
|
|
|
|
if (blk) {
|
|
|
|
real_size = blk_getlength(blk);
|
|
|
|
assert(real_size && real_size <= size);
|
|
|
|
}
|
2022-11-07 05:09:47 +03:00
|
|
|
|
2024-02-19 13:34:14 +03:00
|
|
|
assert(QEMU_IS_ALIGNED(real_size, VIRT_FLASH_SECTOR_SIZE));
|
|
|
|
assert(real_size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX);
|
2022-11-07 05:09:47 +03:00
|
|
|
|
2024-02-19 13:34:14 +03:00
|
|
|
qdev_prop_set_uint32(dev, "num-blocks", real_size / VIRT_FLASH_SECTOR_SIZE);
|
2022-11-07 05:09:47 +03:00
|
|
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
|
|
|
memory_region_add_subregion(sysmem, base,
|
|
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
|
2024-02-19 13:34:14 +03:00
|
|
|
}
|
2022-11-07 05:09:47 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_flash_map(LoongArchVirtMachineState *lvms,
|
2024-02-19 13:34:14 +03:00
|
|
|
MemoryRegion *sysmem)
|
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
PFlashCFI01 *flash0 = lvms->flash[0];
|
|
|
|
PFlashCFI01 *flash1 = lvms->flash[1];
|
2024-02-19 13:34:14 +03:00
|
|
|
|
|
|
|
virt_flash_map1(flash0, VIRT_FLASH0_BASE, VIRT_FLASH0_SIZE, sysmem);
|
|
|
|
virt_flash_map1(flash1, VIRT_FLASH1_BASE, VIRT_FLASH1_SIZE, sysmem);
|
2022-11-07 05:09:47 +03:00
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void fdt_add_cpuic_node(LoongArchVirtMachineState *lvms,
|
2024-04-26 12:15:44 +03:00
|
|
|
uint32_t *cpuintc_phandle)
|
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
MachineState *ms = MACHINE(lvms);
|
2024-04-26 12:15:44 +03:00
|
|
|
char *nodename;
|
|
|
|
|
|
|
|
*cpuintc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
|
|
|
nodename = g_strdup_printf("/cpuic");
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, nodename);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *cpuintc_phandle);
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
|
|
|
|
"loongson,cpu-interrupt-controller");
|
|
|
|
qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
|
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void fdt_add_eiointc_node(LoongArchVirtMachineState *lvms,
|
2024-04-26 12:15:45 +03:00
|
|
|
uint32_t *cpuintc_phandle,
|
|
|
|
uint32_t *eiointc_phandle)
|
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
MachineState *ms = MACHINE(lvms);
|
2024-04-26 12:15:45 +03:00
|
|
|
char *nodename;
|
|
|
|
hwaddr extioi_base = APIC_BASE;
|
|
|
|
hwaddr extioi_size = EXTIOI_SIZE;
|
|
|
|
|
|
|
|
*eiointc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
|
|
|
nodename = g_strdup_printf("/eiointc@%" PRIx64, extioi_base);
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, nodename);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *eiointc_phandle);
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
|
|
|
|
"loongson,ls2k2000-eiointc");
|
|
|
|
qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
|
|
|
|
*cpuintc_phandle);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", 3);
|
|
|
|
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0,
|
|
|
|
extioi_base, 0x0, extioi_size);
|
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void fdt_add_pch_pic_node(LoongArchVirtMachineState *lvms,
|
2024-04-26 12:15:46 +03:00
|
|
|
uint32_t *eiointc_phandle,
|
|
|
|
uint32_t *pch_pic_phandle)
|
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
MachineState *ms = MACHINE(lvms);
|
2024-04-26 12:15:46 +03:00
|
|
|
char *nodename;
|
|
|
|
hwaddr pch_pic_base = VIRT_PCH_REG_BASE;
|
|
|
|
hwaddr pch_pic_size = VIRT_PCH_REG_SIZE;
|
|
|
|
|
|
|
|
*pch_pic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
|
|
|
nodename = g_strdup_printf("/platic@%" PRIx64, pch_pic_base);
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, nodename);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_pic_phandle);
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
|
|
|
|
"loongson,pch-pic-1.0");
|
|
|
|
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0,
|
|
|
|
pch_pic_base, 0, pch_pic_size);
|
|
|
|
qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
|
|
|
|
*eiointc_phandle);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,pic-base-vec", 0);
|
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void fdt_add_pch_msi_node(LoongArchVirtMachineState *lvms,
|
2024-04-26 12:15:47 +03:00
|
|
|
uint32_t *eiointc_phandle,
|
|
|
|
uint32_t *pch_msi_phandle)
|
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
MachineState *ms = MACHINE(lvms);
|
2024-04-26 12:15:47 +03:00
|
|
|
char *nodename;
|
|
|
|
hwaddr pch_msi_base = VIRT_PCH_MSI_ADDR_LOW;
|
|
|
|
hwaddr pch_msi_size = VIRT_PCH_MSI_SIZE;
|
|
|
|
|
|
|
|
*pch_msi_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
|
|
|
nodename = g_strdup_printf("/msi@%" PRIx64, pch_msi_base);
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, nodename);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_msi_phandle);
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
|
|
|
|
"loongson,pch-msi-1.0");
|
|
|
|
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg",
|
|
|
|
0, pch_msi_base,
|
|
|
|
0, pch_msi_size);
|
|
|
|
qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
|
|
|
|
*eiointc_phandle);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-base-vec",
|
|
|
|
VIRT_PCH_PIC_IRQ_NUM);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-num-vecs",
|
|
|
|
EXTIOI_IRQS - VIRT_PCH_PIC_IRQ_NUM);
|
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void fdt_add_flash_node(LoongArchVirtMachineState *lvms)
|
2022-11-07 05:09:47 +03:00
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
MachineState *ms = MACHINE(lvms);
|
2022-11-07 05:09:47 +03:00
|
|
|
char *nodename;
|
2024-02-19 13:34:14 +03:00
|
|
|
MemoryRegion *flash_mem;
|
|
|
|
|
|
|
|
hwaddr flash0_base;
|
|
|
|
hwaddr flash0_size;
|
2022-11-07 05:09:47 +03:00
|
|
|
|
2024-02-19 13:34:14 +03:00
|
|
|
hwaddr flash1_base;
|
|
|
|
hwaddr flash1_size;
|
2022-11-07 05:09:47 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
flash_mem = pflash_cfi01_get_memory(lvms->flash[0]);
|
2024-02-19 13:34:14 +03:00
|
|
|
flash0_base = flash_mem->addr;
|
|
|
|
flash0_size = memory_region_size(flash_mem);
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
flash_mem = pflash_cfi01_get_memory(lvms->flash[1]);
|
2024-02-19 13:34:14 +03:00
|
|
|
flash1_base = flash_mem->addr;
|
|
|
|
flash1_size = memory_region_size(flash_mem);
|
|
|
|
|
|
|
|
nodename = g_strdup_printf("/flash@%" PRIx64, flash0_base);
|
2022-11-07 05:09:47 +03:00
|
|
|
qemu_fdt_add_subnode(ms->fdt, nodename);
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cfi-flash");
|
|
|
|
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
2024-02-19 13:34:14 +03:00
|
|
|
2, flash0_base, 2, flash0_size,
|
|
|
|
2, flash1_base, 2, flash1_size);
|
2022-11-07 05:09:47 +03:00
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "bank-width", 4);
|
|
|
|
g_free(nodename);
|
|
|
|
}
|
2022-07-12 11:32:06 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms,
|
2024-04-26 12:15:51 +03:00
|
|
|
uint32_t *pch_pic_phandle)
|
2022-10-28 04:40:06 +03:00
|
|
|
{
|
|
|
|
char *nodename;
|
|
|
|
hwaddr base = VIRT_RTC_REG_BASE;
|
|
|
|
hwaddr size = VIRT_RTC_LEN;
|
2024-05-08 06:11:07 +03:00
|
|
|
MachineState *ms = MACHINE(lvms);
|
2022-10-28 04:40:06 +03:00
|
|
|
|
|
|
|
nodename = g_strdup_printf("/rtc@%" PRIx64, base);
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, nodename);
|
2024-04-26 12:15:51 +03:00
|
|
|
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
|
|
|
|
"loongson,ls7a-rtc");
|
2022-11-16 06:49:35 +03:00
|
|
|
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
|
2024-04-26 12:15:51 +03:00
|
|
|
qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
|
|
|
|
VIRT_RTC_IRQ - VIRT_GSI_BASE , 0x4);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
|
|
|
|
*pch_pic_phandle);
|
2022-10-28 04:40:06 +03:00
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
|
2024-09-18 04:42:06 +03:00
|
|
|
static void fdt_add_ged_reset(LoongArchVirtMachineState *lvms)
|
|
|
|
{
|
|
|
|
char *name;
|
|
|
|
uint32_t ged_handle;
|
|
|
|
MachineState *ms = MACHINE(lvms);
|
|
|
|
hwaddr base = VIRT_GED_REG_ADDR;
|
|
|
|
hwaddr size = ACPI_GED_REG_COUNT;
|
|
|
|
|
|
|
|
ged_handle = qemu_fdt_alloc_phandle(ms->fdt);
|
|
|
|
name = g_strdup_printf("/ged@%" PRIx64, base);
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, name);
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon");
|
|
|
|
qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, base, 0x0, size);
|
|
|
|
/* 8 bit registers */
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, name, "reg-shift", 0);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, name, "reg-io-width", 1);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, name, "phandle", ged_handle);
|
|
|
|
ged_handle = qemu_fdt_get_phandle(ms->fdt, name);
|
|
|
|
g_free(name);
|
|
|
|
|
|
|
|
name = g_strdup_printf("/reboot");
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, name);
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-reboot");
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_RESET);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_RESET_VALUE);
|
|
|
|
g_free(name);
|
|
|
|
|
|
|
|
name = g_strdup_printf("/poweroff");
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, name);
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-poweroff");
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_SLEEP_CTL);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_SLP_EN |
|
|
|
|
(ACPI_GED_SLP_TYP_S5 << ACPI_GED_SLP_TYP_POS));
|
|
|
|
g_free(name);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void fdt_add_uart_node(LoongArchVirtMachineState *lvms,
|
2024-09-07 17:34:39 +03:00
|
|
|
uint32_t *pch_pic_phandle, hwaddr base,
|
|
|
|
int irq, bool chosen)
|
2022-10-28 04:40:06 +03:00
|
|
|
{
|
|
|
|
char *nodename;
|
|
|
|
hwaddr size = VIRT_UART_SIZE;
|
2024-05-08 06:11:07 +03:00
|
|
|
MachineState *ms = MACHINE(lvms);
|
2022-10-28 04:40:06 +03:00
|
|
|
|
|
|
|
nodename = g_strdup_printf("/serial@%" PRIx64, base);
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, nodename);
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "ns16550a");
|
|
|
|
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 100000000);
|
2024-09-07 17:34:39 +03:00
|
|
|
if (chosen)
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
|
|
|
|
qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", irq, 0x4);
|
2024-04-26 12:15:50 +03:00
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
|
|
|
|
*pch_pic_phandle);
|
2022-10-28 04:40:06 +03:00
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void create_fdt(LoongArchVirtMachineState *lvms)
|
2022-07-12 11:32:06 +03:00
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
MachineState *ms = MACHINE(lvms);
|
hw/loongarch: virt: pass random seed to fdt
If the FDT contains /chosen/rng-seed, then the Linux RNG will use it to
initialize early. Set this using the usual guest random number
generation function.
This is the same procedure that's done in b91b6b5a2c ("hw/microblaze:
pass random seed to fdt"), e4b4f0b71c ("hw/riscv: virt: pass random seed
to fdt"), c6fe3e6b4c ("hw/openrisc: virt: pass random seed to fdt"),
67f7e426e5 ("hw/i386: pass RNG seed via setup_data entry"), c287941a4d
("hw/rx: pass random seed to fdt"), 5e19cc68fb ("hw/mips: boston: pass
random seed to fdt"), 6b23a67916 ("hw/nios2: virt: pass random seed to fdt")
c4b075318e ("hw/ppc: pass random seed to fdt"), and 5242876f37
("hw/arm/virt: dt: add rng-seed property").
These earlier commits later were amended to rerandomize the RNG seed on
snapshot load, but the LoongArch code somehow already does that, despite
not having this patch here, presumably due to some lucky copy and
pasting.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240905153316.2038769-1-Jason@zx2c4.com>
Signed-off-by: Song Gao <gaosong@loongson.cn>
2024-09-05 18:33:16 +03:00
|
|
|
uint8_t rng_seed[32];
|
2022-07-12 11:32:06 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
ms->fdt = create_device_tree(&lvms->fdt_size);
|
2022-07-12 11:32:06 +03:00
|
|
|
if (!ms->fdt) {
|
|
|
|
error_report("create_device_tree() failed");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Header */
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, "/", "compatible",
|
|
|
|
"linux,dummy-loongson3");
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2);
|
2022-11-10 09:14:40 +03:00
|
|
|
qemu_fdt_add_subnode(ms->fdt, "/chosen");
|
hw/loongarch: virt: pass random seed to fdt
If the FDT contains /chosen/rng-seed, then the Linux RNG will use it to
initialize early. Set this using the usual guest random number
generation function.
This is the same procedure that's done in b91b6b5a2c ("hw/microblaze:
pass random seed to fdt"), e4b4f0b71c ("hw/riscv: virt: pass random seed
to fdt"), c6fe3e6b4c ("hw/openrisc: virt: pass random seed to fdt"),
67f7e426e5 ("hw/i386: pass RNG seed via setup_data entry"), c287941a4d
("hw/rx: pass random seed to fdt"), 5e19cc68fb ("hw/mips: boston: pass
random seed to fdt"), 6b23a67916 ("hw/nios2: virt: pass random seed to fdt")
c4b075318e ("hw/ppc: pass random seed to fdt"), and 5242876f37
("hw/arm/virt: dt: add rng-seed property").
These earlier commits later were amended to rerandomize the RNG seed on
snapshot load, but the LoongArch code somehow already does that, despite
not having this patch here, presumably due to some lucky copy and
pasting.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20240905153316.2038769-1-Jason@zx2c4.com>
Signed-off-by: Song Gao <gaosong@loongson.cn>
2024-09-05 18:33:16 +03:00
|
|
|
|
|
|
|
/* Pass seed to RNG */
|
|
|
|
qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
|
|
|
|
qemu_fdt_setprop(ms->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
|
2022-07-12 11:32:06 +03:00
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void fdt_add_cpu_nodes(const LoongArchVirtMachineState *lvms)
|
2022-07-12 11:32:06 +03:00
|
|
|
{
|
|
|
|
int num;
|
2024-05-08 06:11:07 +03:00
|
|
|
const MachineState *ms = MACHINE(lvms);
|
2022-07-12 11:32:06 +03:00
|
|
|
int smp_cpus = ms->smp.cpus;
|
|
|
|
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, "/cpus");
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
|
|
|
|
|
|
|
|
/* cpu nodes */
|
|
|
|
for (num = smp_cpus - 1; num >= 0; num--) {
|
|
|
|
char *nodename = g_strdup_printf("/cpus/cpu@%d", num);
|
|
|
|
LoongArchCPU *cpu = LOONGARCH_CPU(qemu_get_cpu(num));
|
2023-05-18 09:58:15 +03:00
|
|
|
CPUState *cs = CPU(cpu);
|
2022-07-12 11:32:06 +03:00
|
|
|
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, nodename);
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
|
|
|
|
cpu->dtb_compatible);
|
2023-05-18 09:58:15 +03:00
|
|
|
if (ms->possible_cpus->cpus[cs->cpu_index].props.has_node_id) {
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id",
|
|
|
|
ms->possible_cpus->cpus[cs->cpu_index].props.node_id);
|
|
|
|
}
|
2022-07-12 11:32:06 +03:00
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle",
|
|
|
|
qemu_fdt_alloc_phandle(ms->fdt));
|
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*cpu map */
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map");
|
|
|
|
|
|
|
|
for (num = smp_cpus - 1; num >= 0; num--) {
|
|
|
|
char *cpu_path = g_strdup_printf("/cpus/cpu@%d", num);
|
|
|
|
char *map_path;
|
|
|
|
|
|
|
|
if (ms->smp.threads > 1) {
|
|
|
|
map_path = g_strdup_printf(
|
|
|
|
"/cpus/cpu-map/socket%d/core%d/thread%d",
|
|
|
|
num / (ms->smp.cores * ms->smp.threads),
|
|
|
|
(num / ms->smp.threads) % ms->smp.cores,
|
|
|
|
num % ms->smp.threads);
|
|
|
|
} else {
|
|
|
|
map_path = g_strdup_printf(
|
|
|
|
"/cpus/cpu-map/socket%d/core%d",
|
|
|
|
num / ms->smp.cores,
|
|
|
|
num % ms->smp.cores);
|
|
|
|
}
|
|
|
|
qemu_fdt_add_path(ms->fdt, map_path);
|
|
|
|
qemu_fdt_setprop_phandle(ms->fdt, map_path, "cpu", cpu_path);
|
|
|
|
|
|
|
|
g_free(map_path);
|
|
|
|
g_free(cpu_path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void fdt_add_fw_cfg_node(const LoongArchVirtMachineState *lvms)
|
2022-07-12 11:32:06 +03:00
|
|
|
{
|
|
|
|
char *nodename;
|
|
|
|
hwaddr base = VIRT_FWCFG_BASE;
|
2024-05-08 06:11:07 +03:00
|
|
|
const MachineState *ms = MACHINE(lvms);
|
2022-07-12 11:32:06 +03:00
|
|
|
|
|
|
|
nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base);
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, nodename);
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, nodename,
|
|
|
|
"compatible", "qemu,fw-cfg-mmio");
|
|
|
|
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
2022-08-10 11:53:36 +03:00
|
|
|
2, base, 2, 0x18);
|
2022-07-12 11:32:06 +03:00
|
|
|
qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
|
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void fdt_add_pcie_irq_map_node(const LoongArchVirtMachineState *lvms,
|
2024-04-26 12:15:48 +03:00
|
|
|
char *nodename,
|
|
|
|
uint32_t *pch_pic_phandle)
|
|
|
|
{
|
|
|
|
int pin, dev;
|
|
|
|
uint32_t irq_map_stride = 0;
|
|
|
|
uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] = {};
|
|
|
|
uint32_t *irq_map = full_irq_map;
|
2024-05-08 06:11:07 +03:00
|
|
|
const MachineState *ms = MACHINE(lvms);
|
2024-04-26 12:15:48 +03:00
|
|
|
|
|
|
|
/* This code creates a standard swizzle of interrupts such that
|
|
|
|
* each device's first interrupt is based on it's PCI_SLOT number.
|
|
|
|
* (See pci_swizzle_map_irq_fn())
|
|
|
|
*
|
|
|
|
* We only need one entry per interrupt in the table (not one per
|
|
|
|
* possible slot) seeing the interrupt-map-mask will allow the table
|
|
|
|
* to wrap to any number of devices.
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
|
|
|
|
int devfn = dev * 0x8;
|
|
|
|
|
|
|
|
for (pin = 0; pin < GPEX_NUM_IRQS; pin++) {
|
|
|
|
int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
/* Fill PCI address cells */
|
|
|
|
irq_map[i] = cpu_to_be32(devfn << 8);
|
|
|
|
i += 3;
|
|
|
|
|
|
|
|
/* Fill PCI Interrupt cells */
|
|
|
|
irq_map[i] = cpu_to_be32(pin + 1);
|
|
|
|
i += 1;
|
|
|
|
|
|
|
|
/* Fill interrupt controller phandle and cells */
|
|
|
|
irq_map[i++] = cpu_to_be32(*pch_pic_phandle);
|
|
|
|
irq_map[i++] = cpu_to_be32(irq_nr);
|
|
|
|
|
|
|
|
if (!irq_map_stride) {
|
|
|
|
irq_map_stride = i;
|
|
|
|
}
|
|
|
|
irq_map += irq_map_stride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map,
|
|
|
|
GPEX_NUM_IRQS * GPEX_NUM_IRQS *
|
|
|
|
irq_map_stride * sizeof(uint32_t));
|
|
|
|
qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask",
|
|
|
|
0x1800, 0, 0, 0x7);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void fdt_add_pcie_node(const LoongArchVirtMachineState *lvms,
|
2024-04-26 12:15:48 +03:00
|
|
|
uint32_t *pch_pic_phandle,
|
|
|
|
uint32_t *pch_msi_phandle)
|
2022-07-12 11:32:06 +03:00
|
|
|
{
|
|
|
|
char *nodename;
|
2022-07-29 10:30:18 +03:00
|
|
|
hwaddr base_mmio = VIRT_PCI_MEM_BASE;
|
|
|
|
hwaddr size_mmio = VIRT_PCI_MEM_SIZE;
|
|
|
|
hwaddr base_pio = VIRT_PCI_IO_BASE;
|
|
|
|
hwaddr size_pio = VIRT_PCI_IO_SIZE;
|
|
|
|
hwaddr base_pcie = VIRT_PCI_CFG_BASE;
|
|
|
|
hwaddr size_pcie = VIRT_PCI_CFG_SIZE;
|
2022-07-12 11:32:06 +03:00
|
|
|
hwaddr base = base_pcie;
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
const MachineState *ms = MACHINE(lvms);
|
2022-07-12 11:32:06 +03:00
|
|
|
|
|
|
|
nodename = g_strdup_printf("/pcie@%" PRIx64, base);
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, nodename);
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, nodename,
|
|
|
|
"compatible", "pci-host-ecam-generic");
|
|
|
|
qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "pci");
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 3);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 2);
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "linux,pci-domain", 0);
|
|
|
|
qemu_fdt_setprop_cells(ms->fdt, nodename, "bus-range", 0,
|
2022-07-29 10:30:18 +03:00
|
|
|
PCIE_MMCFG_BUS(VIRT_PCI_CFG_SIZE - 1));
|
2022-07-12 11:32:06 +03:00
|
|
|
qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
|
|
|
|
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
|
|
|
2, base_pcie, 2, size_pcie);
|
|
|
|
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "ranges",
|
2022-07-29 10:30:18 +03:00
|
|
|
1, FDT_PCI_RANGE_IOPORT, 2, VIRT_PCI_IO_OFFSET,
|
2022-07-12 11:32:06 +03:00
|
|
|
2, base_pio, 2, size_pio,
|
|
|
|
1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
|
|
|
|
2, base_mmio, 2, size_mmio);
|
2024-04-26 12:15:48 +03:00
|
|
|
qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map",
|
|
|
|
0, *pch_msi_phandle, 0, 0x10000);
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
fdt_add_pcie_irq_map_node(lvms, nodename, pch_pic_phandle);
|
2024-04-26 12:15:48 +03:00
|
|
|
|
2022-07-12 11:32:06 +03:00
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
|
2023-05-18 09:58:15 +03:00
|
|
|
static void fdt_add_memory_node(MachineState *ms,
|
|
|
|
uint64_t base, uint64_t size, int node_id)
|
|
|
|
{
|
|
|
|
char *nodename = g_strdup_printf("/memory@%" PRIx64, base);
|
|
|
|
|
|
|
|
qemu_fdt_add_subnode(ms->fdt, nodename);
|
2024-05-21 00:06:31 +03:00
|
|
|
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", base >> 32, base,
|
|
|
|
size >> 32, size);
|
2023-05-18 09:58:15 +03:00
|
|
|
qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory");
|
|
|
|
|
|
|
|
if (ms->numa_state && ms->numa_state->num_nodes) {
|
|
|
|
qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id", node_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
|
2024-05-15 12:39:23 +03:00
|
|
|
static void fdt_add_memory_nodes(MachineState *ms)
|
|
|
|
{
|
|
|
|
hwaddr base, size, ram_size, gap;
|
|
|
|
int i, nb_numa_nodes, nodes;
|
|
|
|
NodeInfo *numa_info;
|
|
|
|
|
|
|
|
ram_size = ms->ram_size;
|
|
|
|
base = VIRT_LOWMEM_BASE;
|
|
|
|
gap = VIRT_LOWMEM_SIZE;
|
|
|
|
nodes = nb_numa_nodes = ms->numa_state->num_nodes;
|
|
|
|
numa_info = ms->numa_state->nodes;
|
|
|
|
if (!nodes) {
|
|
|
|
nodes = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nodes; i++) {
|
|
|
|
if (nb_numa_nodes) {
|
|
|
|
size = numa_info[i].node_mem;
|
|
|
|
} else {
|
|
|
|
size = ram_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* memory for the node splited into two part
|
|
|
|
* lowram: [base, +gap)
|
|
|
|
* highram: [VIRT_HIGHMEM_BASE, +(len - gap))
|
|
|
|
*/
|
|
|
|
if (size >= gap) {
|
|
|
|
fdt_add_memory_node(ms, base, gap, i);
|
|
|
|
size -= gap;
|
|
|
|
base = VIRT_HIGHMEM_BASE;
|
|
|
|
gap = ram_size - VIRT_LOWMEM_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size) {
|
|
|
|
fdt_add_memory_node(ms, base, size, i);
|
|
|
|
base += size;
|
|
|
|
gap -= size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_build_smbios(LoongArchVirtMachineState *lvms)
|
2022-07-12 11:32:04 +03:00
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
MachineState *ms = MACHINE(lvms);
|
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(lvms);
|
2022-07-12 11:32:04 +03:00
|
|
|
uint8_t *smbios_tables, *smbios_anchor;
|
|
|
|
size_t smbios_tables_len, smbios_anchor_len;
|
|
|
|
const char *product = "QEMU Virtual Machine";
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
if (!lvms->fw_cfg) {
|
2022-07-12 11:32:04 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-03-27 12:08:05 +03:00
|
|
|
smbios_set_defaults("QEMU", product, mc->name);
|
2022-07-12 11:32:04 +03:00
|
|
|
|
2024-03-14 18:22:54 +03:00
|
|
|
smbios_get_tables(ms, SMBIOS_ENTRY_POINT_TYPE_64,
|
|
|
|
NULL, 0,
|
|
|
|
&smbios_tables, &smbios_tables_len,
|
2022-07-12 11:32:04 +03:00
|
|
|
&smbios_anchor, &smbios_anchor_len, &error_fatal);
|
|
|
|
|
|
|
|
if (smbios_anchor) {
|
2024-05-08 06:11:07 +03:00
|
|
|
fw_cfg_add_file(lvms->fw_cfg, "etc/smbios/smbios-tables",
|
2022-07-12 11:32:04 +03:00
|
|
|
smbios_tables, smbios_tables_len);
|
2024-05-08 06:11:07 +03:00
|
|
|
fw_cfg_add_file(lvms->fw_cfg, "etc/smbios/smbios-anchor",
|
2022-07-12 11:32:04 +03:00
|
|
|
smbios_anchor, smbios_anchor_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_done(Notifier *notifier, void *data)
|
2022-07-12 11:32:04 +03:00
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
LoongArchVirtMachineState *lvms = container_of(notifier,
|
|
|
|
LoongArchVirtMachineState, machine_done);
|
|
|
|
virt_build_smbios(lvms);
|
|
|
|
loongarch_acpi_setup(lvms);
|
2022-07-12 11:32:04 +03:00
|
|
|
}
|
|
|
|
|
2023-01-10 06:29:16 +03:00
|
|
|
static void virt_powerdown_req(Notifier *notifier, void *opaque)
|
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
LoongArchVirtMachineState *s;
|
2023-01-10 06:29:16 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
s = container_of(notifier, LoongArchVirtMachineState, powerdown_notifier);
|
2023-01-10 06:29:16 +03:00
|
|
|
acpi_send_event(s->acpi_ged, ACPI_POWER_DOWN_STATUS);
|
|
|
|
}
|
|
|
|
|
2022-07-12 11:32:01 +03:00
|
|
|
static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
|
|
|
|
{
|
|
|
|
/* Ensure there are no duplicate entries. */
|
|
|
|
for (unsigned i = 0; i < memmap_entries; i++) {
|
|
|
|
assert(memmap_table[i].address != address);
|
|
|
|
}
|
|
|
|
|
|
|
|
memmap_table = g_renew(struct memmap_entry, memmap_table,
|
|
|
|
memmap_entries + 1);
|
|
|
|
memmap_table[memmap_entries].address = cpu_to_le64(address);
|
|
|
|
memmap_table[memmap_entries].length = cpu_to_le64(length);
|
|
|
|
memmap_table[memmap_entries].type = cpu_to_le32(type);
|
|
|
|
memmap_table[memmap_entries].reserved = 0;
|
|
|
|
memmap_entries++;
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static DeviceState *create_acpi_ged(DeviceState *pch_pic,
|
|
|
|
LoongArchVirtMachineState *lvms)
|
2022-07-12 11:32:05 +03:00
|
|
|
{
|
|
|
|
DeviceState *dev;
|
2024-05-08 06:11:07 +03:00
|
|
|
MachineState *ms = MACHINE(lvms);
|
2022-07-12 11:32:05 +03:00
|
|
|
uint32_t event = ACPI_GED_PWR_DOWN_EVT;
|
|
|
|
|
|
|
|
if (ms->ram_slots) {
|
|
|
|
event |= ACPI_GED_MEM_HOTPLUG_EVT;
|
|
|
|
}
|
|
|
|
dev = qdev_new(TYPE_ACPI_GED);
|
|
|
|
qdev_prop_set_uint32(dev, "ged-event", event);
|
2023-10-18 09:37:06 +03:00
|
|
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
2022-07-12 11:32:05 +03:00
|
|
|
|
|
|
|
/* ged event */
|
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, VIRT_GED_EVT_ADDR);
|
|
|
|
/* memory hotplug */
|
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, VIRT_GED_MEM_ADDR);
|
|
|
|
/* ged regs used for reset and power down */
|
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_GED_REG_ADDR);
|
|
|
|
|
|
|
|
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
|
2022-12-28 06:07:19 +03:00
|
|
|
qdev_get_gpio_in(pch_pic, VIRT_SCI_IRQ - VIRT_GSI_BASE));
|
2022-07-12 11:32:05 +03:00
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
|
2022-08-10 10:50:35 +03:00
|
|
|
static DeviceState *create_platform_bus(DeviceState *pch_pic)
|
|
|
|
{
|
|
|
|
DeviceState *dev;
|
|
|
|
SysBusDevice *sysbus;
|
|
|
|
int i, irq;
|
|
|
|
MemoryRegion *sysmem = get_system_memory();
|
|
|
|
|
|
|
|
dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
|
|
|
|
dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
|
|
|
|
qdev_prop_set_uint32(dev, "num_irqs", VIRT_PLATFORM_BUS_NUM_IRQS);
|
|
|
|
qdev_prop_set_uint32(dev, "mmio_size", VIRT_PLATFORM_BUS_SIZE);
|
|
|
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
|
|
|
|
|
|
|
sysbus = SYS_BUS_DEVICE(dev);
|
|
|
|
for (i = 0; i < VIRT_PLATFORM_BUS_NUM_IRQS; i++) {
|
2022-12-28 06:07:19 +03:00
|
|
|
irq = VIRT_PLATFORM_BUS_IRQ - VIRT_GSI_BASE + i;
|
2022-08-10 10:50:35 +03:00
|
|
|
sysbus_connect_irq(sysbus, i, qdev_get_gpio_in(pch_pic, irq));
|
|
|
|
}
|
|
|
|
|
|
|
|
memory_region_add_subregion(sysmem,
|
|
|
|
VIRT_PLATFORM_BUS_BASEADDRESS,
|
|
|
|
sysbus_mmio_get_region(sysbus, 0));
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_devices_init(DeviceState *pch_pic,
|
|
|
|
LoongArchVirtMachineState *lvms,
|
2024-04-26 12:15:48 +03:00
|
|
|
uint32_t *pch_pic_phandle,
|
|
|
|
uint32_t *pch_msi_phandle)
|
2022-06-06 15:43:27 +03:00
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(lvms);
|
2022-06-06 15:43:27 +03:00
|
|
|
DeviceState *gpex_dev;
|
|
|
|
SysBusDevice *d;
|
|
|
|
PCIBus *pci_bus;
|
|
|
|
MemoryRegion *ecam_alias, *ecam_reg, *pio_alias, *pio_reg;
|
2023-10-12 09:41:23 +03:00
|
|
|
MemoryRegion *mmio_alias, *mmio_reg;
|
2022-06-06 15:43:27 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
gpex_dev = qdev_new(TYPE_GPEX_HOST);
|
|
|
|
d = SYS_BUS_DEVICE(gpex_dev);
|
|
|
|
sysbus_realize_and_unref(d, &error_fatal);
|
|
|
|
pci_bus = PCI_HOST_BRIDGE(gpex_dev)->bus;
|
2024-05-08 06:11:07 +03:00
|
|
|
lvms->pci_bus = pci_bus;
|
2022-06-06 15:43:27 +03:00
|
|
|
|
|
|
|
/* Map only part size_ecam bytes of ECAM space */
|
|
|
|
ecam_alias = g_new0(MemoryRegion, 1);
|
|
|
|
ecam_reg = sysbus_mmio_get_region(d, 0);
|
|
|
|
memory_region_init_alias(ecam_alias, OBJECT(gpex_dev), "pcie-ecam",
|
2022-07-29 10:30:18 +03:00
|
|
|
ecam_reg, 0, VIRT_PCI_CFG_SIZE);
|
|
|
|
memory_region_add_subregion(get_system_memory(), VIRT_PCI_CFG_BASE,
|
2022-06-06 15:43:27 +03:00
|
|
|
ecam_alias);
|
|
|
|
|
|
|
|
/* Map PCI mem space */
|
|
|
|
mmio_alias = g_new0(MemoryRegion, 1);
|
|
|
|
mmio_reg = sysbus_mmio_get_region(d, 1);
|
|
|
|
memory_region_init_alias(mmio_alias, OBJECT(gpex_dev), "pcie-mmio",
|
2022-07-29 10:30:18 +03:00
|
|
|
mmio_reg, VIRT_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
|
|
|
|
memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE,
|
2022-06-06 15:43:27 +03:00
|
|
|
mmio_alias);
|
|
|
|
|
|
|
|
/* Map PCI IO port space. */
|
|
|
|
pio_alias = g_new0(MemoryRegion, 1);
|
|
|
|
pio_reg = sysbus_mmio_get_region(d, 2);
|
|
|
|
memory_region_init_alias(pio_alias, OBJECT(gpex_dev), "pcie-io", pio_reg,
|
2022-07-29 10:30:18 +03:00
|
|
|
VIRT_PCI_IO_OFFSET, VIRT_PCI_IO_SIZE);
|
|
|
|
memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE,
|
2022-06-06 15:43:27 +03:00
|
|
|
pio_alias);
|
|
|
|
|
|
|
|
for (i = 0; i < GPEX_NUM_IRQS; i++) {
|
|
|
|
sysbus_connect_irq(d, i,
|
|
|
|
qdev_get_gpio_in(pch_pic, 16 + i));
|
|
|
|
gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i);
|
|
|
|
}
|
|
|
|
|
2024-04-26 12:15:48 +03:00
|
|
|
/* Add pcie node */
|
2024-05-08 06:11:07 +03:00
|
|
|
fdt_add_pcie_node(lvms, pch_pic_phandle, pch_msi_phandle);
|
2024-04-26 12:15:48 +03:00
|
|
|
|
2024-09-07 17:34:39 +03:00
|
|
|
/*
|
|
|
|
* Create uart fdt node in reverse order so that they appear
|
|
|
|
* in the finished device tree lowest address first
|
|
|
|
*/
|
|
|
|
for (i = VIRT_UART_COUNT; i --> 0;) {
|
|
|
|
hwaddr base = VIRT_UART_BASE + i * VIRT_UART_SIZE;
|
|
|
|
int irq = VIRT_UART_IRQ + i - VIRT_GSI_BASE;
|
|
|
|
serial_mm_init(get_system_memory(), base, 0,
|
|
|
|
qdev_get_gpio_in(pch_pic, irq),
|
|
|
|
115200, serial_hd(i), DEVICE_LITTLE_ENDIAN);
|
|
|
|
fdt_add_uart_node(lvms, pch_pic_phandle, base, irq, i == 0);
|
|
|
|
}
|
2022-06-06 15:43:27 +03:00
|
|
|
|
|
|
|
/* Network init */
|
2023-10-21 23:21:03 +03:00
|
|
|
pci_init_nic_devices(pci_bus, mc->default_nic);
|
2022-06-06 15:43:27 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* There are some invalid guest memory access.
|
|
|
|
* Create some unimplemented devices to emulate this.
|
|
|
|
*/
|
|
|
|
create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
|
2022-07-29 10:30:18 +03:00
|
|
|
sysbus_create_simple("ls7a_rtc", VIRT_RTC_REG_BASE,
|
2022-06-06 15:43:28 +03:00
|
|
|
qdev_get_gpio_in(pch_pic,
|
2022-12-28 06:07:19 +03:00
|
|
|
VIRT_RTC_IRQ - VIRT_GSI_BASE));
|
2024-05-08 06:11:07 +03:00
|
|
|
fdt_add_rtc_node(lvms, pch_pic_phandle);
|
2024-09-18 04:42:06 +03:00
|
|
|
fdt_add_ged_reset(lvms);
|
2022-06-06 15:43:30 +03:00
|
|
|
|
2022-07-12 11:32:05 +03:00
|
|
|
/* acpi ged */
|
2024-05-08 06:11:07 +03:00
|
|
|
lvms->acpi_ged = create_acpi_ged(pch_pic, lvms);
|
2022-08-10 10:50:35 +03:00
|
|
|
/* platform bus */
|
2024-05-08 06:11:07 +03:00
|
|
|
lvms->platform_bus_dev = create_platform_bus(pch_pic);
|
2022-06-06 15:43:27 +03:00
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_irq_init(LoongArchVirtMachineState *lvms)
|
2022-06-06 15:43:25 +03:00
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
MachineState *ms = MACHINE(lvms);
|
2022-06-06 15:43:25 +03:00
|
|
|
DeviceState *pch_pic, *pch_msi, *cpudev;
|
|
|
|
DeviceState *ipi, *extioi;
|
|
|
|
SysBusDevice *d;
|
|
|
|
LoongArchCPU *lacpu;
|
|
|
|
CPULoongArchState *env;
|
|
|
|
CPUState *cpu_state;
|
2022-12-13 15:50:16 +03:00
|
|
|
int cpu, pin, i, start, num;
|
2024-04-26 12:15:47 +03:00
|
|
|
uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle, pch_msi_phandle;
|
2022-06-06 15:43:25 +03:00
|
|
|
|
|
|
|
/*
|
2024-05-28 11:38:53 +03:00
|
|
|
* Extended IRQ model.
|
|
|
|
* |
|
|
|
|
* +-----------+ +-------------|--------+ +-----------+
|
|
|
|
* | IPI/Timer | --> | CPUINTC(0-3)|(4-255) | <-- | IPI/Timer |
|
|
|
|
* +-----------+ +-------------|--------+ +-----------+
|
|
|
|
* ^ |
|
|
|
|
* |
|
|
|
|
* +---------+
|
|
|
|
* | EIOINTC |
|
|
|
|
* +---------+
|
|
|
|
* ^ ^
|
|
|
|
* | |
|
|
|
|
* +---------+ +---------+
|
|
|
|
* | PCH-PIC | | PCH-MSI |
|
|
|
|
* +---------+ +---------+
|
|
|
|
* ^ ^ ^
|
|
|
|
* | | |
|
|
|
|
* +--------+ +---------+ +---------+
|
|
|
|
* | UARTs | | Devices | | Devices |
|
|
|
|
* +--------+ +---------+ +---------+
|
|
|
|
*
|
|
|
|
* Virt extended IRQ model.
|
|
|
|
*
|
|
|
|
* +-----+ +---------------+ +-------+
|
|
|
|
* | IPI |--> | CPUINTC(0-255)| <-- | Timer |
|
|
|
|
* +-----+ +---------------+ +-------+
|
|
|
|
* ^
|
|
|
|
* |
|
|
|
|
* +-----------+
|
|
|
|
* | V-EIOINTC |
|
|
|
|
* +-----------+
|
|
|
|
* ^ ^
|
|
|
|
* | |
|
|
|
|
* +---------+ +---------+
|
|
|
|
* | PCH-PIC | | PCH-MSI |
|
|
|
|
* +---------+ +---------+
|
|
|
|
* ^ ^ ^
|
|
|
|
* | | |
|
|
|
|
* +--------+ +---------+ +---------+
|
|
|
|
* | UARTs | | Devices | | Devices |
|
|
|
|
* +--------+ +---------+ +---------+
|
2022-06-06 15:43:25 +03:00
|
|
|
*/
|
2023-12-13 07:13:14 +03:00
|
|
|
|
|
|
|
/* Create IPI device */
|
2024-07-15 17:23:48 +03:00
|
|
|
ipi = qdev_new(TYPE_LOONGARCH_IPI);
|
2023-12-13 07:13:14 +03:00
|
|
|
qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.cpus);
|
|
|
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
|
|
|
|
|
|
|
|
/* IPI iocsr memory region */
|
2024-05-08 06:11:07 +03:00
|
|
|
memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
|
2023-12-13 07:13:14 +03:00
|
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
|
2024-05-08 06:11:07 +03:00
|
|
|
memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR,
|
2023-12-13 07:13:14 +03:00
|
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
|
|
|
|
|
2024-04-26 12:15:44 +03:00
|
|
|
/* Add cpu interrupt-controller */
|
2024-05-08 06:11:07 +03:00
|
|
|
fdt_add_cpuic_node(lvms, &cpuintc_phandle);
|
2024-04-26 12:15:44 +03:00
|
|
|
|
2022-06-06 15:43:25 +03:00
|
|
|
for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
|
|
|
|
cpu_state = qemu_get_cpu(cpu);
|
|
|
|
cpudev = DEVICE(cpu_state);
|
|
|
|
lacpu = LOONGARCH_CPU(cpu_state);
|
|
|
|
env = &(lacpu->env);
|
2024-05-08 06:11:07 +03:00
|
|
|
env->address_space_iocsr = &lvms->as_iocsr;
|
2023-04-06 09:57:27 +03:00
|
|
|
|
2022-06-06 15:43:25 +03:00
|
|
|
/* connect ipi irq to cpu irq */
|
2023-12-13 07:13:14 +03:00
|
|
|
qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
|
2023-05-17 04:22:00 +03:00
|
|
|
env->ipistate = ipi;
|
2022-06-06 15:43:25 +03:00
|
|
|
}
|
|
|
|
|
2023-12-13 07:13:14 +03:00
|
|
|
/* Create EXTIOI device */
|
|
|
|
extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
|
2023-12-15 06:07:36 +03:00
|
|
|
qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus);
|
2024-05-28 11:38:55 +03:00
|
|
|
if (virt_is_veiointc_enabled(lvms)) {
|
|
|
|
qdev_prop_set_bit(extioi, "has-virtualization-extension", true);
|
|
|
|
}
|
2023-12-13 07:13:14 +03:00
|
|
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
|
2024-05-08 06:11:07 +03:00
|
|
|
memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE,
|
2024-05-28 11:38:55 +03:00
|
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
|
|
|
|
if (virt_is_veiointc_enabled(lvms)) {
|
|
|
|
memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE,
|
|
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
|
|
|
|
}
|
2023-12-13 07:13:14 +03:00
|
|
|
|
2022-06-06 15:43:25 +03:00
|
|
|
/*
|
|
|
|
* connect ext irq to the cpu irq
|
|
|
|
* cpu_pin[9:2] <= intc_pin[7:0]
|
|
|
|
*/
|
2023-12-15 06:07:36 +03:00
|
|
|
for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
|
2022-06-06 15:43:25 +03:00
|
|
|
cpudev = DEVICE(qemu_get_cpu(cpu));
|
|
|
|
for (pin = 0; pin < LS3A_INTC_IP; pin++) {
|
|
|
|
qdev_connect_gpio_out(extioi, (cpu * 8 + pin),
|
|
|
|
qdev_get_gpio_in(cpudev, pin + 2));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-26 12:15:45 +03:00
|
|
|
/* Add Extend I/O Interrupt Controller node */
|
2024-05-08 06:11:07 +03:00
|
|
|
fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle);
|
2024-04-26 12:15:45 +03:00
|
|
|
|
2022-06-06 15:43:25 +03:00
|
|
|
pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
|
2022-12-27 06:19:57 +03:00
|
|
|
num = VIRT_PCH_PIC_IRQ_NUM;
|
2022-12-14 04:57:18 +03:00
|
|
|
qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
|
2022-06-06 15:43:25 +03:00
|
|
|
d = SYS_BUS_DEVICE(pch_pic);
|
|
|
|
sysbus_realize_and_unref(d, &error_fatal);
|
2022-07-29 10:30:18 +03:00
|
|
|
memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
|
2022-06-06 15:43:25 +03:00
|
|
|
sysbus_mmio_get_region(d, 0));
|
|
|
|
memory_region_add_subregion(get_system_memory(),
|
2022-07-29 10:30:18 +03:00
|
|
|
VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET,
|
2022-06-06 15:43:25 +03:00
|
|
|
sysbus_mmio_get_region(d, 1));
|
|
|
|
memory_region_add_subregion(get_system_memory(),
|
2022-07-29 10:30:18 +03:00
|
|
|
VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO,
|
2022-06-06 15:43:25 +03:00
|
|
|
sysbus_mmio_get_region(d, 2));
|
|
|
|
|
2022-12-14 04:57:18 +03:00
|
|
|
/* Connect pch_pic irqs to extioi */
|
2023-09-26 10:12:53 +03:00
|
|
|
for (i = 0; i < num; i++) {
|
2022-06-06 15:43:25 +03:00
|
|
|
qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
|
|
|
|
}
|
|
|
|
|
2024-04-26 12:15:46 +03:00
|
|
|
/* Add PCH PIC node */
|
2024-05-08 06:11:07 +03:00
|
|
|
fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle);
|
2024-04-26 12:15:46 +03:00
|
|
|
|
2022-06-06 15:43:25 +03:00
|
|
|
pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
|
2022-12-14 04:57:18 +03:00
|
|
|
start = num;
|
2022-12-13 15:50:16 +03:00
|
|
|
num = EXTIOI_IRQS - start;
|
|
|
|
qdev_prop_set_uint32(pch_msi, "msi_irq_base", start);
|
|
|
|
qdev_prop_set_uint32(pch_msi, "msi_irq_num", num);
|
2022-06-06 15:43:25 +03:00
|
|
|
d = SYS_BUS_DEVICE(pch_msi);
|
|
|
|
sysbus_realize_and_unref(d, &error_fatal);
|
2022-07-29 10:30:18 +03:00
|
|
|
sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW);
|
2022-12-13 15:50:16 +03:00
|
|
|
for (i = 0; i < num; i++) {
|
|
|
|
/* Connect pch_msi irqs to extioi */
|
2022-06-06 15:43:25 +03:00
|
|
|
qdev_connect_gpio_out(DEVICE(d), i,
|
2022-12-13 15:50:16 +03:00
|
|
|
qdev_get_gpio_in(extioi, i + start));
|
2022-06-06 15:43:25 +03:00
|
|
|
}
|
2022-06-06 15:43:27 +03:00
|
|
|
|
2024-04-26 12:15:47 +03:00
|
|
|
/* Add PCH MSI node */
|
2024-05-08 06:11:07 +03:00
|
|
|
fdt_add_pch_msi_node(lvms, &eiointc_phandle, &pch_msi_phandle);
|
2024-04-26 12:15:47 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
virt_devices_init(pch_pic, lvms, &pch_pic_phandle, &pch_msi_phandle);
|
2022-06-06 15:43:25 +03:00
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_firmware_init(LoongArchVirtMachineState *lvms)
|
2022-07-12 11:32:02 +03:00
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
char *filename = MACHINE(lvms)->firmware;
|
2022-07-12 11:32:02 +03:00
|
|
|
char *bios_name = NULL;
|
2024-02-19 13:34:14 +03:00
|
|
|
int bios_size, i;
|
|
|
|
BlockBackend *pflash_blk0;
|
|
|
|
MemoryRegion *mr;
|
2022-07-12 11:32:02 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
lvms->bios_loaded = false;
|
2022-11-07 05:09:47 +03:00
|
|
|
|
2024-02-19 13:34:14 +03:00
|
|
|
/* Map legacy -drive if=pflash to machine properties */
|
2024-05-08 06:11:07 +03:00
|
|
|
for (i = 0; i < ARRAY_SIZE(lvms->flash); i++) {
|
|
|
|
pflash_cfi01_legacy_drive(lvms->flash[i],
|
2024-02-19 13:34:14 +03:00
|
|
|
drive_get(IF_PFLASH, 0, i));
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
virt_flash_map(lvms, get_system_memory());
|
2022-11-07 05:09:47 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
pflash_blk0 = pflash_cfi01_get_blk(lvms->flash[0]);
|
2024-02-19 13:34:14 +03:00
|
|
|
|
|
|
|
if (pflash_blk0) {
|
|
|
|
if (filename) {
|
|
|
|
error_report("cannot use both '-bios' and '-drive if=pflash'"
|
|
|
|
"options at once");
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-05-08 06:11:07 +03:00
|
|
|
lvms->bios_loaded = true;
|
2024-02-19 13:34:14 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-07-12 11:32:02 +03:00
|
|
|
if (filename) {
|
|
|
|
bios_name = qemu_find_file(QEMU_FILE_TYPE_BIOS, filename);
|
|
|
|
if (!bios_name) {
|
|
|
|
error_report("Could not find ROM image '%s'", filename);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(lvms->flash[0]), 0);
|
2024-02-19 13:34:14 +03:00
|
|
|
bios_size = load_image_mr(bios_name, mr);
|
2022-07-12 11:32:02 +03:00
|
|
|
if (bios_size < 0) {
|
|
|
|
error_report("Could not load ROM image '%s'", bios_name);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
g_free(bios_name);
|
2024-05-08 06:11:07 +03:00
|
|
|
lvms->bios_loaded = true;
|
2022-07-12 11:32:02 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-28 11:38:54 +03:00
|
|
|
static MemTxResult virt_iocsr_misc_write(void *opaque, hwaddr addr,
|
|
|
|
uint64_t val, unsigned size,
|
|
|
|
MemTxAttrs attrs)
|
2023-12-13 07:13:14 +03:00
|
|
|
{
|
2024-05-28 11:38:55 +03:00
|
|
|
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque);
|
|
|
|
uint64_t features;
|
|
|
|
|
|
|
|
switch (addr) {
|
|
|
|
case MISC_FUNC_REG:
|
|
|
|
if (!virt_is_veiointc_enabled(lvms)) {
|
|
|
|
return MEMTX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
features = address_space_ldl(&lvms->as_iocsr,
|
|
|
|
EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG,
|
|
|
|
attrs, NULL);
|
|
|
|
if (val & BIT_ULL(IOCSRM_EXTIOI_EN)) {
|
|
|
|
features |= BIT(EXTIOI_ENABLE);
|
|
|
|
}
|
|
|
|
if (val & BIT_ULL(IOCSRM_EXTIOI_INT_ENCODE)) {
|
|
|
|
features |= BIT(EXTIOI_ENABLE_INT_ENCODE);
|
|
|
|
}
|
|
|
|
|
|
|
|
address_space_stl(&lvms->as_iocsr,
|
|
|
|
EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG,
|
|
|
|
features, attrs, NULL);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
|
2024-05-28 11:38:54 +03:00
|
|
|
return MEMTX_OK;
|
2023-12-13 07:13:14 +03:00
|
|
|
}
|
|
|
|
|
2024-05-28 11:38:54 +03:00
|
|
|
static MemTxResult virt_iocsr_misc_read(void *opaque, hwaddr addr,
|
|
|
|
uint64_t *data,
|
|
|
|
unsigned size, MemTxAttrs attrs)
|
2023-12-13 07:13:14 +03:00
|
|
|
{
|
2024-05-28 11:38:55 +03:00
|
|
|
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque);
|
2024-05-28 11:38:54 +03:00
|
|
|
uint64_t ret = 0;
|
2024-05-28 11:38:55 +03:00
|
|
|
int features;
|
2024-05-14 05:51:09 +03:00
|
|
|
|
2023-12-13 07:13:14 +03:00
|
|
|
switch (addr) {
|
|
|
|
case VERSION_REG:
|
2024-05-28 11:38:54 +03:00
|
|
|
ret = 0x11ULL;
|
|
|
|
break;
|
2023-12-13 07:13:14 +03:00
|
|
|
case FEATURE_REG:
|
2024-05-14 05:51:09 +03:00
|
|
|
ret = BIT(IOCSRF_MSI) | BIT(IOCSRF_EXTIOI) | BIT(IOCSRF_CSRIPI);
|
|
|
|
if (kvm_enabled()) {
|
|
|
|
ret |= BIT(IOCSRF_VM);
|
|
|
|
}
|
2024-05-28 11:38:54 +03:00
|
|
|
break;
|
2023-12-13 07:13:14 +03:00
|
|
|
case VENDOR_REG:
|
2024-05-28 11:38:54 +03:00
|
|
|
ret = 0x6e6f73676e6f6f4cULL; /* "Loongson" */
|
|
|
|
break;
|
2023-12-13 07:13:14 +03:00
|
|
|
case CPUNAME_REG:
|
2024-05-28 11:38:54 +03:00
|
|
|
ret = 0x303030354133ULL; /* "3A5000" */
|
|
|
|
break;
|
2023-12-13 07:13:14 +03:00
|
|
|
case MISC_FUNC_REG:
|
2024-05-28 11:38:55 +03:00
|
|
|
if (!virt_is_veiointc_enabled(lvms)) {
|
|
|
|
ret |= BIT_ULL(IOCSRM_EXTIOI_EN);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
features = address_space_ldl(&lvms->as_iocsr,
|
|
|
|
EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG,
|
|
|
|
attrs, NULL);
|
|
|
|
if (features & BIT(EXTIOI_ENABLE)) {
|
|
|
|
ret |= BIT_ULL(IOCSRM_EXTIOI_EN);
|
|
|
|
}
|
|
|
|
if (features & BIT(EXTIOI_ENABLE_INT_ENCODE)) {
|
|
|
|
ret |= BIT_ULL(IOCSRM_EXTIOI_INT_ENCODE);
|
|
|
|
}
|
2024-05-28 11:38:54 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
2023-12-13 07:13:14 +03:00
|
|
|
}
|
2024-05-28 11:38:54 +03:00
|
|
|
|
|
|
|
*data = ret;
|
|
|
|
return MEMTX_OK;
|
2023-12-13 07:13:14 +03:00
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static const MemoryRegionOps virt_iocsr_misc_ops = {
|
2024-05-28 11:38:54 +03:00
|
|
|
.read_with_attrs = virt_iocsr_misc_read,
|
|
|
|
.write_with_attrs = virt_iocsr_misc_write,
|
2023-12-13 07:13:14 +03:00
|
|
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
|
|
|
.valid = {
|
|
|
|
.min_access_size = 4,
|
|
|
|
.max_access_size = 8,
|
|
|
|
},
|
|
|
|
.impl = {
|
|
|
|
.min_access_size = 8,
|
|
|
|
.max_access_size = 8,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2024-05-15 12:39:24 +03:00
|
|
|
static void fw_cfg_add_memory(MachineState *ms)
|
|
|
|
{
|
|
|
|
hwaddr base, size, ram_size, gap;
|
|
|
|
int nb_numa_nodes, nodes;
|
|
|
|
NodeInfo *numa_info;
|
|
|
|
|
|
|
|
ram_size = ms->ram_size;
|
|
|
|
base = VIRT_LOWMEM_BASE;
|
|
|
|
gap = VIRT_LOWMEM_SIZE;
|
|
|
|
nodes = nb_numa_nodes = ms->numa_state->num_nodes;
|
|
|
|
numa_info = ms->numa_state->nodes;
|
|
|
|
if (!nodes) {
|
|
|
|
nodes = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add fw_cfg memory map of node0 */
|
|
|
|
if (nb_numa_nodes) {
|
|
|
|
size = numa_info[0].node_mem;
|
|
|
|
} else {
|
|
|
|
size = ram_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size >= gap) {
|
|
|
|
memmap_add_entry(base, gap, 1);
|
|
|
|
size -= gap;
|
|
|
|
base = VIRT_HIGHMEM_BASE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size) {
|
|
|
|
memmap_add_entry(base, size, 1);
|
|
|
|
base += size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodes < 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add fw_cfg memory map of other nodes */
|
2024-06-12 06:36:37 +03:00
|
|
|
if (numa_info[0].node_mem < gap && ram_size > gap) {
|
2024-05-15 12:39:24 +03:00
|
|
|
/*
|
|
|
|
* memory map for the maining nodes splited into two part
|
2024-06-12 06:36:37 +03:00
|
|
|
* lowram: [base, +(gap - numa_info[0].node_mem))
|
|
|
|
* highram: [VIRT_HIGHMEM_BASE, +(ram_size - gap))
|
2024-05-15 12:39:24 +03:00
|
|
|
*/
|
2024-06-12 06:36:37 +03:00
|
|
|
memmap_add_entry(base, gap - numa_info[0].node_mem, 1);
|
|
|
|
size = ram_size - gap;
|
2024-05-15 12:39:24 +03:00
|
|
|
base = VIRT_HIGHMEM_BASE;
|
2024-06-12 06:36:37 +03:00
|
|
|
} else {
|
|
|
|
size = ram_size - numa_info[0].node_mem;
|
2024-05-15 12:39:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (size)
|
|
|
|
memmap_add_entry(base, size, 1);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_init(MachineState *machine)
|
2022-06-06 15:43:20 +03:00
|
|
|
{
|
2022-07-12 11:32:03 +03:00
|
|
|
LoongArchCPU *lacpu;
|
2022-06-06 15:43:20 +03:00
|
|
|
const char *cpu_model = machine->cpu_type;
|
|
|
|
MemoryRegion *address_space_mem = get_system_memory();
|
2024-05-08 06:11:07 +03:00
|
|
|
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
|
2022-06-06 15:43:20 +03:00
|
|
|
int i;
|
2024-05-15 12:39:25 +03:00
|
|
|
hwaddr base, size, ram_size = machine->ram_size;
|
2023-05-16 11:27:57 +03:00
|
|
|
const CPUArchIdList *possible_cpus;
|
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
|
|
|
CPUState *cpu;
|
2022-06-06 15:43:20 +03:00
|
|
|
|
|
|
|
if (!cpu_model) {
|
|
|
|
cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
create_fdt(lvms);
|
2023-05-16 11:27:57 +03:00
|
|
|
|
2023-12-13 07:13:14 +03:00
|
|
|
/* Create IOCSR space */
|
2024-05-08 06:11:07 +03:00
|
|
|
memory_region_init_io(&lvms->system_iocsr, OBJECT(machine), NULL,
|
2023-12-13 07:13:14 +03:00
|
|
|
machine, "iocsr", UINT64_MAX);
|
2024-05-08 06:11:07 +03:00
|
|
|
address_space_init(&lvms->as_iocsr, &lvms->system_iocsr, "IOCSR");
|
|
|
|
memory_region_init_io(&lvms->iocsr_mem, OBJECT(machine),
|
|
|
|
&virt_iocsr_misc_ops,
|
2023-12-13 07:13:14 +03:00
|
|
|
machine, "iocsr_misc", 0x428);
|
2024-05-08 06:11:07 +03:00
|
|
|
memory_region_add_subregion(&lvms->system_iocsr, 0, &lvms->iocsr_mem);
|
2023-12-13 07:13:14 +03:00
|
|
|
|
|
|
|
/* Init CPUs */
|
2023-05-16 11:27:57 +03:00
|
|
|
possible_cpus = mc->possible_cpu_arch_ids(machine);
|
|
|
|
for (i = 0; i < possible_cpus->len; i++) {
|
|
|
|
cpu = cpu_create(machine->cpu_type);
|
|
|
|
cpu->cpu_index = i;
|
2024-01-29 19:44:44 +03:00
|
|
|
machine->possible_cpus->cpus[i].cpu = cpu;
|
2023-08-24 03:50:07 +03:00
|
|
|
lacpu = LOONGARCH_CPU(cpu);
|
|
|
|
lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id;
|
2022-06-06 15:43:20 +03:00
|
|
|
}
|
2024-05-08 06:11:07 +03:00
|
|
|
fdt_add_cpu_nodes(lvms);
|
2024-05-15 12:39:23 +03:00
|
|
|
fdt_add_memory_nodes(machine);
|
2024-05-15 12:39:24 +03:00
|
|
|
fw_cfg_add_memory(machine);
|
2023-05-18 09:58:15 +03:00
|
|
|
|
|
|
|
/* Node0 memory */
|
2024-05-15 12:39:25 +03:00
|
|
|
size = ram_size;
|
|
|
|
base = VIRT_LOWMEM_BASE;
|
|
|
|
if (size > VIRT_LOWMEM_SIZE) {
|
|
|
|
size = VIRT_LOWMEM_SIZE;
|
2023-05-18 09:58:15 +03:00
|
|
|
}
|
2024-05-15 12:39:25 +03:00
|
|
|
|
|
|
|
memory_region_init_alias(&lvms->lowmem, NULL, "loongarch.lowram",
|
|
|
|
machine->ram, base, size);
|
|
|
|
memory_region_add_subregion(address_space_mem, base, &lvms->lowmem);
|
|
|
|
base += size;
|
|
|
|
if (ram_size - size) {
|
|
|
|
base = VIRT_HIGHMEM_BASE;
|
|
|
|
memory_region_init_alias(&lvms->highmem, NULL, "loongarch.highram",
|
|
|
|
machine->ram, VIRT_LOWMEM_BASE + size, ram_size - size);
|
|
|
|
memory_region_add_subregion(address_space_mem, base, &lvms->highmem);
|
|
|
|
base += ram_size - size;
|
2023-05-18 09:58:15 +03:00
|
|
|
}
|
2022-08-25 06:36:59 +03:00
|
|
|
|
|
|
|
/* initialize device memory address space */
|
|
|
|
if (machine->ram_size < machine->maxram_size) {
|
|
|
|
ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
|
|
|
|
|
|
|
|
if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) {
|
|
|
|
error_report("unsupported amount of memory slots: %"PRIu64,
|
|
|
|
machine->ram_slots);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (QEMU_ALIGN_UP(machine->maxram_size,
|
|
|
|
TARGET_PAGE_SIZE) != machine->maxram_size) {
|
|
|
|
error_report("maximum memory size must by aligned to multiple of "
|
|
|
|
"%d bytes", TARGET_PAGE_SIZE);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2024-05-15 12:39:25 +03:00
|
|
|
machine_memory_devices_init(machine, base, device_mem_size);
|
2022-08-25 06:36:59 +03:00
|
|
|
}
|
|
|
|
|
2022-07-12 11:32:02 +03:00
|
|
|
/* load the BIOS image. */
|
2024-05-08 06:11:07 +03:00
|
|
|
virt_firmware_init(lvms);
|
2022-07-12 11:32:02 +03:00
|
|
|
|
2022-07-12 11:32:01 +03:00
|
|
|
/* fw_cfg init */
|
2024-05-08 06:11:07 +03:00
|
|
|
lvms->fw_cfg = virt_fw_cfg_init(ram_size, machine);
|
|
|
|
rom_set_fw(lvms->fw_cfg);
|
|
|
|
if (lvms->fw_cfg != NULL) {
|
|
|
|
fw_cfg_add_file(lvms->fw_cfg, "etc/memmap",
|
2022-07-12 11:32:01 +03:00
|
|
|
memmap_table,
|
|
|
|
sizeof(struct memmap_entry) * (memmap_entries));
|
|
|
|
}
|
2024-05-08 06:11:07 +03:00
|
|
|
fdt_add_fw_cfg_node(lvms);
|
|
|
|
fdt_add_flash_node(lvms);
|
2024-04-26 12:15:35 +03:00
|
|
|
|
2022-06-06 15:43:25 +03:00
|
|
|
/* Initialize the IO interrupt subsystem */
|
2024-05-08 06:11:07 +03:00
|
|
|
virt_irq_init(lvms);
|
2024-04-26 12:15:49 +03:00
|
|
|
platform_bus_add_all_fdt_nodes(machine->fdt, "/platic",
|
2022-08-10 10:50:35 +03:00
|
|
|
VIRT_PLATFORM_BUS_BASEADDRESS,
|
|
|
|
VIRT_PLATFORM_BUS_SIZE,
|
|
|
|
VIRT_PLATFORM_BUS_IRQ);
|
2024-05-08 06:11:07 +03:00
|
|
|
lvms->machine_done.notify = virt_done;
|
|
|
|
qemu_add_machine_init_done_notifier(&lvms->machine_done);
|
2023-01-10 06:29:16 +03:00
|
|
|
/* connect powerdown request */
|
2024-05-08 06:11:07 +03:00
|
|
|
lvms->powerdown_notifier.notify = virt_powerdown_req;
|
|
|
|
qemu_register_powerdown_notifier(&lvms->powerdown_notifier);
|
2023-01-10 06:29:16 +03:00
|
|
|
|
2022-10-28 04:40:05 +03:00
|
|
|
/*
|
2022-11-09 05:04:49 +03:00
|
|
|
* Since lowmem region starts from 0 and Linux kernel legacy start address
|
|
|
|
* at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer
|
|
|
|
* access. FDT size limit with 1 MiB.
|
2022-10-28 04:40:05 +03:00
|
|
|
* Put the FDT into the memory map as a ROM image: this will ensure
|
|
|
|
* the FDT is copied again upon reset, even if addr points into RAM.
|
|
|
|
*/
|
2024-05-08 06:11:07 +03:00
|
|
|
qemu_fdt_dumpdtb(machine->fdt, lvms->fdt_size);
|
|
|
|
rom_add_blob_fixed_as("fdt", machine->fdt, lvms->fdt_size, FDT_BASE,
|
2024-04-26 12:15:35 +03:00
|
|
|
&address_space_memory);
|
|
|
|
qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
|
2024-05-08 06:11:07 +03:00
|
|
|
rom_ptr_for_as(&address_space_memory, FDT_BASE, lvms->fdt_size));
|
2024-04-26 12:15:35 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
lvms->bootinfo.ram_size = ram_size;
|
|
|
|
loongarch_load_kernel(machine, &lvms->bootinfo);
|
2022-06-06 15:43:20 +03:00
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_get_acpi(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
2022-07-12 11:32:05 +03:00
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
|
|
|
|
OnOffAuto acpi = lvms->acpi;
|
2022-07-12 11:32:05 +03:00
|
|
|
|
|
|
|
visit_type_OnOffAuto(v, name, &acpi, errp);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_set_acpi(Object *obj, Visitor *v, const char *name,
|
2022-07-12 11:32:05 +03:00
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
|
2022-07-12 11:32:05 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
visit_type_OnOffAuto(v, name, &lvms->acpi, errp);
|
2022-07-12 11:32:05 +03:00
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_initfn(Object *obj)
|
2022-07-12 11:32:05 +03:00
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
|
2022-07-12 11:32:05 +03:00
|
|
|
|
2024-05-28 11:38:55 +03:00
|
|
|
if (tcg_enabled()) {
|
|
|
|
lvms->veiointc = ON_OFF_AUTO_OFF;
|
|
|
|
}
|
2024-05-08 06:11:07 +03:00
|
|
|
lvms->acpi = ON_OFF_AUTO_AUTO;
|
|
|
|
lvms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
|
|
|
|
lvms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
|
|
|
|
virt_flash_create(lvms);
|
2022-07-12 11:32:05 +03:00
|
|
|
}
|
|
|
|
|
2022-08-25 06:36:59 +03:00
|
|
|
static bool memhp_type_supported(DeviceState *dev)
|
|
|
|
{
|
|
|
|
/* we only support pc dimm now */
|
|
|
|
return object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
|
|
|
|
!object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virt_mem_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|
|
|
Error **errp)
|
|
|
|
{
|
2024-02-28 12:26:33 +03:00
|
|
|
pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), errp);
|
2022-08-25 06:36:59 +03:00
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_device_pre_plug(HotplugHandler *hotplug_dev,
|
2022-08-25 06:36:59 +03:00
|
|
|
DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
if (memhp_type_supported(dev)) {
|
|
|
|
virt_mem_pre_plug(hotplug_dev, dev, errp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virt_mem_unplug_request(HotplugHandler *hotplug_dev,
|
|
|
|
DeviceState *dev, Error **errp)
|
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev);
|
2022-08-25 06:36:59 +03:00
|
|
|
|
|
|
|
/* the acpi ged is always exist */
|
2024-05-08 06:11:07 +03:00
|
|
|
hotplug_handler_unplug_request(HOTPLUG_HANDLER(lvms->acpi_ged), dev,
|
2022-08-25 06:36:59 +03:00
|
|
|
errp);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_device_unplug_request(HotplugHandler *hotplug_dev,
|
2022-08-25 06:36:59 +03:00
|
|
|
DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
if (memhp_type_supported(dev)) {
|
|
|
|
virt_mem_unplug_request(hotplug_dev, dev, errp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virt_mem_unplug(HotplugHandler *hotplug_dev,
|
|
|
|
DeviceState *dev, Error **errp)
|
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev);
|
2022-08-25 06:36:59 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, errp);
|
|
|
|
pc_dimm_unplug(PC_DIMM(dev), MACHINE(lvms));
|
2022-08-25 06:36:59 +03:00
|
|
|
qdev_unrealize(dev);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_device_unplug(HotplugHandler *hotplug_dev,
|
2022-08-25 06:36:59 +03:00
|
|
|
DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
if (memhp_type_supported(dev)) {
|
|
|
|
virt_mem_unplug(hotplug_dev, dev, errp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virt_mem_plug(HotplugHandler *hotplug_dev,
|
|
|
|
DeviceState *dev, Error **errp)
|
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev);
|
2022-08-25 06:36:59 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
pc_dimm_plug(PC_DIMM(dev), MACHINE(lvms));
|
|
|
|
hotplug_handler_plug(HOTPLUG_HANDLER(lvms->acpi_ged),
|
2022-08-25 06:36:59 +03:00
|
|
|
dev, &error_abort);
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_device_plug_cb(HotplugHandler *hotplug_dev,
|
2022-08-10 11:37:21 +03:00
|
|
|
DeviceState *dev, Error **errp)
|
|
|
|
{
|
2024-05-08 06:11:07 +03:00
|
|
|
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev);
|
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(lvms);
|
|
|
|
PlatformBusDevice *pbus;
|
2022-08-10 11:37:21 +03:00
|
|
|
|
|
|
|
if (device_is_dynamic_sysbus(mc, dev)) {
|
2024-05-08 06:11:07 +03:00
|
|
|
if (lvms->platform_bus_dev) {
|
|
|
|
pbus = PLATFORM_BUS_DEVICE(lvms->platform_bus_dev);
|
|
|
|
platform_bus_link_device(pbus, SYS_BUS_DEVICE(dev));
|
2022-08-10 11:37:21 +03:00
|
|
|
}
|
2022-08-25 06:36:59 +03:00
|
|
|
} else if (memhp_type_supported(dev)) {
|
|
|
|
virt_mem_plug(hotplug_dev, dev, errp);
|
2022-08-10 11:37:21 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static HotplugHandler *virt_get_hotplug_handler(MachineState *machine,
|
|
|
|
DeviceState *dev)
|
2022-08-10 11:37:21 +03:00
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
|
|
|
|
2022-08-25 06:36:59 +03:00
|
|
|
if (device_is_dynamic_sysbus(mc, dev) ||
|
2024-05-28 11:20:53 +03:00
|
|
|
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) ||
|
2022-08-25 06:36:59 +03:00
|
|
|
memhp_type_supported(dev)) {
|
2022-08-10 11:37:21 +03:00
|
|
|
return HOTPLUG_HANDLER(machine);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-05-16 11:27:57 +03:00
|
|
|
static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
unsigned int max_cpus = ms->smp.max_cpus;
|
|
|
|
|
|
|
|
if (ms->possible_cpus) {
|
|
|
|
assert(ms->possible_cpus->len == max_cpus);
|
|
|
|
return ms->possible_cpus;
|
|
|
|
}
|
|
|
|
|
|
|
|
ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
|
|
|
|
sizeof(CPUArchId) * max_cpus);
|
|
|
|
ms->possible_cpus->len = max_cpus;
|
|
|
|
for (n = 0; n < ms->possible_cpus->len; n++) {
|
|
|
|
ms->possible_cpus->cpus[n].type = ms->cpu_type;
|
|
|
|
ms->possible_cpus->cpus[n].arch_id = n;
|
2023-06-13 14:37:36 +03:00
|
|
|
|
|
|
|
ms->possible_cpus->cpus[n].props.has_socket_id = true;
|
|
|
|
ms->possible_cpus->cpus[n].props.socket_id =
|
|
|
|
n / (ms->smp.cores * ms->smp.threads);
|
2023-05-16 11:27:57 +03:00
|
|
|
ms->possible_cpus->cpus[n].props.has_core_id = true;
|
2023-06-13 14:37:36 +03:00
|
|
|
ms->possible_cpus->cpus[n].props.core_id =
|
|
|
|
n / ms->smp.threads % ms->smp.cores;
|
|
|
|
ms->possible_cpus->cpus[n].props.has_thread_id = true;
|
|
|
|
ms->possible_cpus->cpus[n].props.thread_id = n % ms->smp.threads;
|
2023-05-16 11:27:57 +03:00
|
|
|
}
|
|
|
|
return ms->possible_cpus;
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static CpuInstanceProperties virt_cpu_index_to_props(MachineState *ms,
|
|
|
|
unsigned cpu_index)
|
2023-05-18 09:58:15 +03:00
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
|
|
|
const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
|
|
|
|
|
|
|
|
assert(cpu_index < possible_cpus->len);
|
|
|
|
return possible_cpus->cpus[cpu_index].props;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int64_t virt_get_default_cpu_node_id(const MachineState *ms, int idx)
|
|
|
|
{
|
2024-03-19 05:26:06 +03:00
|
|
|
int64_t socket_id;
|
2023-05-18 09:58:15 +03:00
|
|
|
|
|
|
|
if (ms->numa_state->num_nodes) {
|
2024-03-19 05:26:06 +03:00
|
|
|
socket_id = ms->possible_cpus->cpus[idx].props.socket_id;
|
|
|
|
return socket_id % ms->numa_state->num_nodes;
|
|
|
|
} else {
|
|
|
|
return 0;
|
2023-05-18 09:58:15 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static void virt_class_init(ObjectClass *oc, void *data)
|
2022-06-06 15:43:20 +03:00
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_CLASS(oc);
|
2022-08-10 11:37:21 +03:00
|
|
|
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
|
2022-06-06 15:43:20 +03:00
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
mc->init = virt_init;
|
2022-06-06 15:43:20 +03:00
|
|
|
mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464");
|
|
|
|
mc->default_ram_id = "loongarch.ram";
|
2024-09-13 12:52:02 +03:00
|
|
|
mc->desc = "QEMU LoongArch Virtual Machine";
|
2023-04-06 10:25:28 +03:00
|
|
|
mc->max_cpus = LOONGARCH_MAX_CPUS;
|
2022-06-06 15:43:20 +03:00
|
|
|
mc->is_default = 1;
|
|
|
|
mc->default_kernel_irqchip_split = false;
|
|
|
|
mc->block_default_type = IF_VIRTIO;
|
|
|
|
mc->default_boot_order = "c";
|
|
|
|
mc->no_cdrom = 1;
|
2023-05-16 11:27:57 +03:00
|
|
|
mc->possible_cpu_arch_ids = virt_possible_cpu_arch_ids;
|
2023-05-18 09:58:15 +03:00
|
|
|
mc->cpu_index_to_instance_props = virt_cpu_index_to_props;
|
|
|
|
mc->get_default_cpu_node_id = virt_get_default_cpu_node_id;
|
|
|
|
mc->numa_mem_supported = true;
|
|
|
|
mc->auto_enable_numa_with_memhp = true;
|
|
|
|
mc->auto_enable_numa_with_memdev = true;
|
2024-05-08 06:11:07 +03:00
|
|
|
mc->get_hotplug_handler = virt_get_hotplug_handler;
|
2023-05-23 14:04:34 +03:00
|
|
|
mc->default_nic = "virtio-net-pci";
|
2024-05-08 06:11:07 +03:00
|
|
|
hc->plug = virt_device_plug_cb;
|
|
|
|
hc->pre_plug = virt_device_pre_plug;
|
|
|
|
hc->unplug_request = virt_device_unplug_request;
|
|
|
|
hc->unplug = virt_device_unplug;
|
2022-07-12 11:32:05 +03:00
|
|
|
|
|
|
|
object_class_property_add(oc, "acpi", "OnOffAuto",
|
2024-05-08 06:11:07 +03:00
|
|
|
virt_get_acpi, virt_set_acpi,
|
2022-07-12 11:32:05 +03:00
|
|
|
NULL, NULL);
|
|
|
|
object_class_property_set_description(oc, "acpi",
|
|
|
|
"Enable ACPI");
|
2024-05-28 11:38:55 +03:00
|
|
|
object_class_property_add(oc, "v-eiointc", "OnOffAuto",
|
|
|
|
virt_get_veiointc, virt_set_veiointc,
|
|
|
|
NULL, NULL);
|
|
|
|
object_class_property_set_description(oc, "v-eiointc",
|
|
|
|
"Enable Virt Extend I/O Interrupt Controller.");
|
2022-08-10 11:41:52 +03:00
|
|
|
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
|
2022-10-28 04:40:07 +03:00
|
|
|
#ifdef CONFIG_TPM
|
|
|
|
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
|
|
|
|
#endif
|
2022-06-06 15:43:20 +03:00
|
|
|
}
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
static const TypeInfo virt_machine_types[] = {
|
2022-06-06 15:43:20 +03:00
|
|
|
{
|
2024-05-08 06:11:06 +03:00
|
|
|
.name = TYPE_LOONGARCH_VIRT_MACHINE,
|
2022-06-06 15:43:20 +03:00
|
|
|
.parent = TYPE_MACHINE,
|
2024-05-08 06:11:07 +03:00
|
|
|
.instance_size = sizeof(LoongArchVirtMachineState),
|
|
|
|
.class_init = virt_class_init,
|
|
|
|
.instance_init = virt_initfn,
|
2022-08-10 11:37:21 +03:00
|
|
|
.interfaces = (InterfaceInfo[]) {
|
|
|
|
{ TYPE_HOTPLUG_HANDLER },
|
|
|
|
{ }
|
|
|
|
},
|
2022-06-06 15:43:20 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-05-08 06:11:07 +03:00
|
|
|
DEFINE_TYPES(virt_machine_types)
|