Re: [PATCH v2 3/3] hw/intc/imsic: Add in-kernel imsic save and restore function

2026-03-11 Thread Alistair Francis
On Thu, Mar 5, 2026 at 7:28 PM  wrote:
>
> From: Xuemei Liu 
>
> Add save and restore funtction if kvm_irqchip_in_kernel() return
> true, it is to get and set IMSIC irqchip state from KVM kernel.
>
> Signed-off-by: Xuemei Liu 
> ---
>  hw/intc/riscv_imsic.c | 171 +++---
>  include/hw/intc/riscv_imsic.h |   3 +
>  include/qemu/bitops.h |   9 +-
>  migration/vmstate-types.c |   1 -
>  4 files changed, 165 insertions(+), 19 deletions(-)
>
> diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c
> index 7c9a012033..1c9c706b03 100644
> --- a/hw/intc/riscv_imsic.c
> +++ b/hw/intc/riscv_imsic.c
> @@ -34,6 +34,7 @@
>  #include "system/system.h"
>  #include "system/kvm.h"
>  #include "migration/vmstate.h"
> +#include "kvm/kvm_riscv.h"
>
>  #define IMSIC_MMIO_PAGE_LE 0x00
>  #define IMSIC_MMIO_PAGE_BE 0x04
> @@ -363,11 +364,16 @@ static void riscv_imsic_realize(DeviceState *dev, Error 
> **errp)
>  qdev_init_gpio_out(dev, imsic->external_irqs, imsic->num_pages);
>
>  imsic->num_eistate = imsic->num_pages * imsic->num_irqs;
> -imsic->eidelivery = g_new0(uint32_t, imsic->num_pages);
> -imsic->eithreshold = g_new0(uint32_t, imsic->num_pages);
>  imsic->eistate = g_new0(uint32_t, imsic->num_eistate);
> +} else {
> +imsic->nr_eix = 2 * BITS_TO_U64S(imsic->num_irqs);
> +imsic->eie = g_new0(uint32_t, imsic->nr_eix);
> +imsic->eip = g_new0(uint32_t, imsic->nr_eix);
>  }
>
> +imsic->eidelivery = g_new0(uint32_t, imsic->num_pages);
> +imsic->eithreshold = g_new0(uint32_t, imsic->num_pages);
> +
>  memory_region_init_io(&imsic->mmio, OBJECT(dev), &riscv_imsic_ops,
>imsic, TYPE_RISCV_IMSIC,
>IMSIC_MMIO_SIZE(imsic->num_pages));
> @@ -398,23 +404,17 @@ static const Property riscv_imsic_properties[] = {
>  DEFINE_PROP_UINT32("num-irqs", RISCVIMSICState, num_irqs, 0),
>  };
>
> -static bool riscv_imsic_state_needed(void *opaque)
> +static bool riscv_imsic_emul_state_needed(void *opaque)
>  {
>  return !kvm_irqchip_in_kernel();
>  }
>
> -static const VMStateDescription vmstate_riscv_imsic = {
> -.name = "riscv_imsic",
> -.version_id = 2,
> -.minimum_version_id = 2,
> -.needed = riscv_imsic_state_needed,
> +static const VMStateDescription vmstate_riscv_imsic_emul = {
> +.name = "riscv_imsic_emul",
> +.version_id = 1,
> +.minimum_version_id = 1,
> +.needed = riscv_imsic_emul_state_needed,
>  .fields = (const VMStateField[]) {
> -VMSTATE_VARRAY_UINT32(eidelivery, RISCVIMSICState,
> -  num_pages, 0,
> -  vmstate_info_uint32, uint32_t),
> -VMSTATE_VARRAY_UINT32(eithreshold, RISCVIMSICState,
> -  num_pages, 0,
> -  vmstate_info_uint32, uint32_t),
>  VMSTATE_VARRAY_UINT32(eistate, RISCVIMSICState,
>num_eistate, 0,
>vmstate_info_uint32, uint32_t),
> @@ -422,6 +422,149 @@ static const VMStateDescription vmstate_riscv_imsic = {
>  }
>  };
>
> +static bool riscv_imsic_in_kernel_state_needed(void *opaque)
> +{
> +return kvm_irqchip_in_kernel();
> +}
> +
> +static int riscv_imsic_in_kernel_pre_save(void *opaque)
> +{
> +RISCVIMSICState *imsic = opaque;
> +RISCVCPU *rcpu = RISCV_CPU(cpu_by_arch_id(imsic->hartid));
> +bool is_32bit = riscv_cpu_is_32bit(rcpu);
> +uint32_t inc = 2;
> +uint64_t attr;
> +
> +if (is_32bit) {
> +inc = 1;
> +}
> +
> +if (kvm_irqchip_in_kernel()) {
> +for (uint32_t i = 0; i < imsic->nr_eix; i += inc) {
> +attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
> +  ISELECT_IMSIC_EIE0 + i);
> +kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
> + imsic->eie + i, false);
> +
> +attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
> +  ISELECT_IMSIC_EIP0 + i);
> +kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
> + imsic->eip + i, false);
> +}
> +}
> +
> +return 0;
> +}
> +
> +static int riscv_imsic_in_kernel_post_load(void *opaque, int version_id)
> +{
> +RISCVIMSICState *imsic = opaque;
> +RISCVCPU *rcpu = RISCV_CPU(cpu_by_arch_id(imsic->hartid));
> +bool is_32bit = riscv_cpu_is_32bit(rcpu);
> +uint32_t inc = 2;
> +uint64_t attr;
> +
> +if (is_32bit) {
> +inc = 1;
> +}
> +
> +if (kvm_irqchip_in_kernel()) {
> +for (uint32_t i = 0; i < imsic->nr_eix; i += inc) {
> +attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
> +  ISELEC

[PATCH v2 3/3] hw/intc/imsic: Add in-kernel imsic save and restore function

2026-03-05 Thread liu.xuemei1
From: Xuemei Liu 

Add save and restore funtction if kvm_irqchip_in_kernel() return
true, it is to get and set IMSIC irqchip state from KVM kernel.

Signed-off-by: Xuemei Liu 
---
 hw/intc/riscv_imsic.c | 171 +++---
 include/hw/intc/riscv_imsic.h |   3 +
 include/qemu/bitops.h |   9 +-
 migration/vmstate-types.c |   1 -
 4 files changed, 165 insertions(+), 19 deletions(-)

diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c
index 7c9a012033..1c9c706b03 100644
--- a/hw/intc/riscv_imsic.c
+++ b/hw/intc/riscv_imsic.c
@@ -34,6 +34,7 @@
 #include "system/system.h"
 #include "system/kvm.h"
 #include "migration/vmstate.h"
+#include "kvm/kvm_riscv.h"

 #define IMSIC_MMIO_PAGE_LE 0x00
 #define IMSIC_MMIO_PAGE_BE 0x04
@@ -363,11 +364,16 @@ static void riscv_imsic_realize(DeviceState *dev, Error 
**errp)
 qdev_init_gpio_out(dev, imsic->external_irqs, imsic->num_pages);

 imsic->num_eistate = imsic->num_pages * imsic->num_irqs;
-imsic->eidelivery = g_new0(uint32_t, imsic->num_pages);
-imsic->eithreshold = g_new0(uint32_t, imsic->num_pages);
 imsic->eistate = g_new0(uint32_t, imsic->num_eistate);
+} else {
+imsic->nr_eix = 2 * BITS_TO_U64S(imsic->num_irqs);
+imsic->eie = g_new0(uint32_t, imsic->nr_eix);
+imsic->eip = g_new0(uint32_t, imsic->nr_eix);
 }

+imsic->eidelivery = g_new0(uint32_t, imsic->num_pages);
+imsic->eithreshold = g_new0(uint32_t, imsic->num_pages);
+
 memory_region_init_io(&imsic->mmio, OBJECT(dev), &riscv_imsic_ops,
   imsic, TYPE_RISCV_IMSIC,
   IMSIC_MMIO_SIZE(imsic->num_pages));
@@ -398,23 +404,17 @@ static const Property riscv_imsic_properties[] = {
 DEFINE_PROP_UINT32("num-irqs", RISCVIMSICState, num_irqs, 0),
 };

-static bool riscv_imsic_state_needed(void *opaque)
+static bool riscv_imsic_emul_state_needed(void *opaque)
 {
 return !kvm_irqchip_in_kernel();
 }

-static const VMStateDescription vmstate_riscv_imsic = {
-.name = "riscv_imsic",
-.version_id = 2,
-.minimum_version_id = 2,
-.needed = riscv_imsic_state_needed,
+static const VMStateDescription vmstate_riscv_imsic_emul = {
+.name = "riscv_imsic_emul",
+.version_id = 1,
+.minimum_version_id = 1,
+.needed = riscv_imsic_emul_state_needed,
 .fields = (const VMStateField[]) {
-VMSTATE_VARRAY_UINT32(eidelivery, RISCVIMSICState,
-  num_pages, 0,
-  vmstate_info_uint32, uint32_t),
-VMSTATE_VARRAY_UINT32(eithreshold, RISCVIMSICState,
-  num_pages, 0,
-  vmstate_info_uint32, uint32_t),
 VMSTATE_VARRAY_UINT32(eistate, RISCVIMSICState,
   num_eistate, 0,
   vmstate_info_uint32, uint32_t),
@@ -422,6 +422,149 @@ static const VMStateDescription vmstate_riscv_imsic = {
 }
 };

+static bool riscv_imsic_in_kernel_state_needed(void *opaque)
+{
+return kvm_irqchip_in_kernel();
+}
+
+static int riscv_imsic_in_kernel_pre_save(void *opaque)
+{
+RISCVIMSICState *imsic = opaque;
+RISCVCPU *rcpu = RISCV_CPU(cpu_by_arch_id(imsic->hartid));
+bool is_32bit = riscv_cpu_is_32bit(rcpu);
+uint32_t inc = 2;
+uint64_t attr;
+
+if (is_32bit) {
+inc = 1;
+}
+
+if (kvm_irqchip_in_kernel()) {
+for (uint32_t i = 0; i < imsic->nr_eix; i += inc) {
+attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
+  ISELECT_IMSIC_EIE0 + i);
+kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
+ imsic->eie + i, false);
+
+attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
+  ISELECT_IMSIC_EIP0 + i);
+kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
+ imsic->eip + i, false);
+}
+}
+
+return 0;
+}
+
+static int riscv_imsic_in_kernel_post_load(void *opaque, int version_id)
+{
+RISCVIMSICState *imsic = opaque;
+RISCVCPU *rcpu = RISCV_CPU(cpu_by_arch_id(imsic->hartid));
+bool is_32bit = riscv_cpu_is_32bit(rcpu);
+uint32_t inc = 2;
+uint64_t attr;
+
+if (is_32bit) {
+inc = 1;
+}
+
+if (kvm_irqchip_in_kernel()) {
+for (uint32_t i = 0; i < imsic->nr_eix; i += inc) {
+attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
+  ISELECT_IMSIC_EIE0 + i);
+kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
+ imsic->eie + i, true);
+
+attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
+  ISELECT_IMSIC_EIP0