1 Star 0 Fork 131

alexchen/src-qemu

forked from src-openEuler/qemu 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
hw-loongarch-Add-KVM-IPI-device-support.patch 13.18 KB
一键复制 编辑 原始数据 按行查看 历史
Xianglai Li 提交于 2024-12-13 19:50 +08:00 . QEMU update to version 8.2.0-27:
From 24e4e6742bdc8d804760e84f4e4bde5460e1e024 Mon Sep 17 00:00:00 2001
From: gaosong <gaosong@loongson.cn>
Date: Sun, 8 Sep 2024 09:29:00 +0800
Subject: [PATCH 72/78] hw/loongarch: Add KVM IPI device support
Added ipi interrupt controller for kvm emulation.
The main process is to send the command word for
creating an ipi device to the kernel.
When the VM is saved, the ioctl obtains the ipi
interrupt controller data in the kernel and saves it.
When the VM is recovered, the saved data is sent to the kernel.
Signed-off-by: gaosong <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/intc/Kconfig | 3 +
hw/intc/loongarch_ipi_kvm.c | 207 ++++++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
hw/loongarch/Kconfig | 1 +
hw/loongarch/virt.c | 35 ++++--
include/hw/intc/loongarch_ipi.h | 23 ++++
linux-headers/linux/kvm.h | 2 +
target/loongarch/kvm/kvm.c | 4 +
8 files changed, 263 insertions(+), 13 deletions(-)
create mode 100644 hw/intc/loongarch_ipi_kvm.c
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 97d550b06b..cbba74c22e 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -93,6 +93,9 @@ config NIOS2_VIC
config LOONGARCH_IPI
bool
+config LOONGARCH_IPI_KVM
+ bool
+
config LOONGARCH_PCH_PIC
bool
select UNIMP
diff --git a/hw/intc/loongarch_ipi_kvm.c b/hw/intc/loongarch_ipi_kvm.c
new file mode 100644
index 0000000000..fd308eb0c0
--- /dev/null
+++ b/hw/intc/loongarch_ipi_kvm.c
@@ -0,0 +1,207 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch kvm ipi interrupt support
+ *
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "qemu/typedefs.h"
+#include "hw/intc/loongarch_ipi.h"
+#include "hw/sysbus.h"
+#include "linux/kvm.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "sysemu/kvm.h"
+
+#define IPI_DEV_FD_UNDEF -1
+
+static void kvm_ipi_access_regs(int fd, uint64_t addr,
+ uint32_t *val, int is_write)
+{
+ kvm_device_access(fd, KVM_DEV_LOONGARCH_IPI_GRP_REGS,
+ addr, val, is_write, &error_abort);
+}
+
+static int kvm_loongarch_ipi_pre_save(void *opaque)
+{
+ KVMLoongArchIPI *ipi = (KVMLoongArchIPI *)opaque;
+ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(ipi);
+ IPICore *cpu;
+ uint64_t attr;
+ int cpu_id = 0;
+ int fd = ipi_class->dev_fd;
+
+ for (cpu_id = 0; cpu_id < ipi->num_cpu; cpu_id++) {
+ cpu = &ipi->cpu[cpu_id];
+ attr = (cpu_id << 16) | CORE_STATUS_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->status, false);
+
+ attr = (cpu_id << 16) | CORE_EN_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->en, false);
+
+ attr = (cpu_id << 16) | CORE_SET_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->set, false);
+
+ attr = (cpu_id << 16) | CORE_CLEAR_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->clear, false);
+
+ attr = (cpu_id << 16) | CORE_BUF_20;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[0], false);
+
+ attr = (cpu_id << 16) | CORE_BUF_28;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[2], false);
+
+ attr = (cpu_id << 16) | CORE_BUF_30;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[4], false);
+
+ attr = (cpu_id << 16) | CORE_BUF_38;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[6], false);
+ }
+
+ return 0;
+}
+
+static int kvm_loongarch_ipi_post_load(void *opaque, int version_id)
+{
+ KVMLoongArchIPI *ipi = (KVMLoongArchIPI *)opaque;
+ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(ipi);
+ IPICore *cpu;
+ uint64_t attr;
+ int cpu_id = 0;
+ int fd = ipi_class->dev_fd;
+
+ for (cpu_id = 0; cpu_id < ipi->num_cpu; cpu_id++) {
+ cpu = &ipi->cpu[cpu_id];
+ attr = (cpu_id << 16) | CORE_STATUS_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->status, true);
+
+ attr = (cpu_id << 16) | CORE_EN_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->en, true);
+
+ attr = (cpu_id << 16) | CORE_SET_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->set, true);
+
+ attr = (cpu_id << 16) | CORE_CLEAR_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->clear, true);
+
+ attr = (cpu_id << 16) | CORE_BUF_20;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[0], true);
+
+ attr = (cpu_id << 16) | CORE_BUF_28;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[2], true);
+
+ attr = (cpu_id << 16) | CORE_BUF_30;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[4], true);
+
+ attr = (cpu_id << 16) | CORE_BUF_38;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[6], true);
+ }
+
+ return 0;
+}
+
+static void kvm_loongarch_ipi_realize(DeviceState *dev, Error **errp)
+{
+ KVMLoongArchIPI *ipi = KVM_LOONGARCH_IPI(dev);
+ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(dev);
+ struct kvm_create_device cd = {0};
+ Error *err = NULL;
+ int ret;
+
+ if (ipi->num_cpu == 0) {
+ error_setg(errp, "num-cpu must be at least 1");
+ return;
+ }
+
+ ipi_class->parent_realize(dev, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ ipi->cpu = g_new0(IPICore, ipi->num_cpu);
+ if (ipi->cpu == NULL) {
+ error_setg(errp, "Memory allocation for ExtIOICore faile");
+ return;
+ }
+
+ if (!ipi_class->is_created) {
+ cd.type = KVM_DEV_TYPE_LA_IPI;
+ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
+ if (ret < 0) {
+ error_setg_errno(errp, errno, "Creating the KVM device failed");
+ return;
+ }
+ ipi_class->is_created = true;
+ ipi_class->dev_fd = cd.fd;
+ fprintf(stdout, "Create LoongArch IPI irqchip in KVM done!\n");
+ }
+
+ assert(ipi_class->dev_fd != IPI_DEV_FD_UNDEF);
+}
+
+static Property kvm_loongarch_ipi_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", KVMLoongArchIPI, num_cpu, 1),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static const VMStateDescription vmstate_kvm_ipi_core = {
+ .name = "kvm-ipi-single",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(status, IPICore),
+ VMSTATE_UINT32(en, IPICore),
+ VMSTATE_UINT32(set, IPICore),
+ VMSTATE_UINT32(clear, IPICore),
+ VMSTATE_UINT32_ARRAY(buf, IPICore, 8),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_kvm_loongarch_ipi = {
+ .name = TYPE_KVM_LOONGARCH_IPI,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = kvm_loongarch_ipi_pre_save,
+ .post_load = kvm_loongarch_ipi_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, KVMLoongArchIPI, num_cpu,
+ vmstate_kvm_ipi_core, IPICore),
+
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void kvm_loongarch_ipi_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_CLASS(oc);
+
+ ipi_class->parent_realize = dc->realize;
+ dc->realize = kvm_loongarch_ipi_realize;
+
+ ipi_class->is_created = false;
+ ipi_class->dev_fd = IPI_DEV_FD_UNDEF;
+
+ device_class_set_props(dc, kvm_loongarch_ipi_properties);
+
+ dc->vmsd = &vmstate_kvm_loongarch_ipi;
+}
+
+static const TypeInfo kvm_loongarch_ipi_info = {
+ .name = TYPE_KVM_LOONGARCH_IPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(KVMLoongArchIPI),
+ .class_size = sizeof(KVMLoongArchIPIClass),
+ .class_init = kvm_loongarch_ipi_class_init,
+};
+
+static void kvm_loongarch_ipi_register_types(void)
+{
+ type_register_static(&kvm_loongarch_ipi_info);
+}
+
+type_init(kvm_loongarch_ipi_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index ed355941d1..9deeeb51bb 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -70,6 +70,7 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_IPI_KVM', if_true: files('loongarch_ipi_kvm.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c'))
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index b42a8573d4..1e761624c6 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -14,6 +14,7 @@ config LOONGARCH_VIRT
select LOONGARCH_PCH_PIC
select LOONGARCH_PCH_MSI
select LOONGARCH_EXTIOI
+ select LOONGARCH_IPI_KVM if KVM
select LS7A_RTC
select SMBIOS
select ACPI_CPU_HOTPLUG
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 6159fd9470..f065eb75f8 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -829,16 +829,28 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
* +--------+ +---------+ +---------+
*/
- /* Create IPI device */
- ipi = qdev_new(TYPE_LOONGARCH_IPI);
- qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.max_cpus);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
-
- /* IPI iocsr memory region */
- memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
- memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ ipi = qdev_new(TYPE_KVM_LOONGARCH_IPI);
+ qdev_prop_set_int32(ipi, "num-cpu", ms->smp.max_cpus);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
+ } else {
+ ipi = qdev_new(TYPE_LOONGARCH_IPI);
+ qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.max_cpus);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
+
+ /* IPI iocsr memory region */
+ memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
+ memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
+ for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
+ cpu_state = qemu_get_cpu(cpu);
+ cpudev = DEVICE(cpu_state);
+
+ /* connect ipi irq to cpu irq */
+ qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
+ }
+ }
/* Add cpu interrupt-controller */
fdt_add_cpuic_node(lvms, &cpuintc_phandle);
@@ -849,9 +861,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
lacpu = LOONGARCH_CPU(cpu_state);
env = &(lacpu->env);
env->address_space_iocsr = &lvms->as_iocsr;
-
- /* connect ipi irq to cpu irq */
- qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
env->ipistate = ipi;
}
diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
index 1c1e834849..601b4f18a7 100644
--- a/include/hw/intc/loongarch_ipi.h
+++ b/include/hw/intc/loongarch_ipi.h
@@ -32,6 +32,7 @@
#define TYPE_LOONGARCH_IPI "loongarch_ipi"
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchIPI, LOONGARCH_IPI)
+#define TYPE_KVM_LOONGARCH_IPI "loongarch-ipi-kvm"
typedef struct IPICore {
uint32_t status;
@@ -51,4 +52,26 @@ struct LoongArchIPI {
IPICore *cpu;
};
+struct KVMLoongArchIPI {
+ SysBusDevice parent_obj;
+ uint32_t num_cpu;
+ IPICore *cpu;
+};
+typedef struct KVMLoongArchIPI KVMLoongArchIPI;
+DECLARE_INSTANCE_CHECKER(KVMLoongArchIPI, KVM_LOONGARCH_IPI,
+ TYPE_KVM_LOONGARCH_IPI)
+
+struct KVMLoongArchIPIClass {
+ SysBusDeviceClass parent_class;
+ DeviceRealize parent_realize;
+
+ bool is_created;
+ int dev_fd;
+
+};
+typedef struct KVMLoongArchIPIClass KVMLoongArchIPIClass;
+DECLARE_CLASS_CHECKERS(KVMLoongArchIPIClass, KVM_LOONGARCH_IPI,
+ TYPE_KVM_LOONGARCH_IPI)
+
+
#endif
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index eb30402c2d..ea1f821a9f 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -1470,6 +1470,8 @@ enum kvm_device_type {
#define KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_ARM_PV_TIME
KVM_DEV_TYPE_RISCV_AIA,
#define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA
+ KVM_DEV_TYPE_LA_IPI,
+#define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI
KVM_DEV_TYPE_MAX,
};
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 550f14269e..ab1ea3d4fd 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1066,6 +1066,10 @@ int kvm_arch_get_default_type(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s)
{
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
+ if(!kvm_vm_check_attr(kvm_state, KVM_LOONGARCH_VM_HAVE_IRQCHIP, KVM_LOONGARCH_VM_HAVE_IRQCHIP)) {
+ s->kernel_irqchip_allowed = false;
+ }
+
return 0;
}
--
2.39.1
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/zhendongchen/src-qemu.git
git@gitee.com:zhendongchen/src-qemu.git
zhendongchen
src-qemu
src-qemu
master

搜索帮助