* [PATCH v2 0/3] riscv: AIA: Add in-kernel irqchips save and restore function support
@ 2026-03-05 9:17 liu.xuemei1
2026-03-05 9:19 ` [PATCH v2 1/3] target/riscv/kvm: create kvm_riscv_aia_access_reg liu.xuemei1
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: liu.xuemei1 @ 2026-03-05 9:17 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, dbarboza, zhiwei_liu, peterx,
farosas, chao.liu.zevorn
Cc: qemu-riscv, qemu-devel, liu.xuemei1
From: Xuemei Liu <liu.xuemei1@zte.com.cn>
This series adds support for in-kernel AIA irqchips save and restore
on RISC-V.
Changes in v2:
- Added the BITS_TO_U64S macro
- Added the nr_eix field and dynamically allocated the eie/eip arrays
- Replaced the CONFIG_32BIT macro with is_32bit boolean flag
- Link to v1: https://lore.kernel.org/qemu-devel/20260227180104794YvW9Rb2I_kAGzUruZL11Q@zte.com.cn/
Xuemei Liu (3):
target/riscv/kvm: create kvm_riscv_aia_access_reg
hw/intc/riscv_aplic: Add in-kernel aplic save and restore function
hw/intc/imsic: Add in-kernel imsic save and restore function
hw/intc/riscv_aplic.c | 200 ++++++++++++++++++++++++++++------
hw/intc/riscv_imsic.c | 171 ++++++++++++++++++++++++++---
include/hw/intc/riscv_aplic.h | 4 +
include/hw/intc/riscv_imsic.h | 3 +
include/qemu/bitops.h | 9 +-
migration/vmstate-types.c | 1 -
target/riscv/kvm/kvm-cpu.c | 7 +-
target/riscv/kvm/kvm_riscv.h | 1 +
8 files changed, 345 insertions(+), 51 deletions(-)
--
2.27.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/3] target/riscv/kvm: create kvm_riscv_aia_access_reg
2026-03-05 9:17 [PATCH v2 0/3] riscv: AIA: Add in-kernel irqchips save and restore function support liu.xuemei1
@ 2026-03-05 9:19 ` liu.xuemei1
2026-03-11 23:46 ` Alistair Francis
2026-03-05 9:22 ` [PATCH v2 2/3] hw/intc/riscv_aplic: Add in-kernel aplic save and restore function liu.xuemei1
2026-03-05 9:26 ` [PATCH v2 3/3] hw/intc/imsic: Add in-kernel imsic " liu.xuemei1
2 siblings, 1 reply; 7+ messages in thread
From: liu.xuemei1 @ 2026-03-05 9:19 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, dbarboza, zhiwei_liu, peterx,
farosas, chao.liu.zevorn
Cc: qemu-riscv, qemu-devel, liu.xuemei1
From: Xuemei Liu <liu.xuemei1@zte.com.cn>
Create common function kvm_riscv_aia_access_reg to access APLIC
and IMSIC regs
Signed-off-by: Xuemei Liu <liu.xuemei1@zte.com.cn>
---
target/riscv/kvm/kvm-cpu.c | 7 ++++++-
target/riscv/kvm/kvm_riscv.h | 1 +
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index befcbb0a9a..2c29d8d07c 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -58,6 +58,7 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level)
}
static bool cap_has_mp_state;
+static int aia_fd = -1;
#define KVM_RISCV_REG_ID_U32(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U32 | \
type | idx)
@@ -1842,13 +1843,17 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
"auto");
}
+void kvm_riscv_aia_access_reg(int group, uint64_t addr, void *val, bool write)
+{
+ kvm_device_access(aia_fd, group, addr, val, write, &error_abort);
+}
+
void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
uint64_t aia_irq_num, uint64_t aia_msi_num,
uint64_t aplic_base, uint64_t imsic_base,
uint64_t guest_num)
{
int ret, i;
- int aia_fd = -1;
uint64_t default_aia_mode;
uint64_t socket_count = riscv_socket_count(machine);
uint64_t max_hart_per_socket = 0;
diff --git a/target/riscv/kvm/kvm_riscv.h b/target/riscv/kvm/kvm_riscv.h
index 953db94160..cec13d9f31 100644
--- a/target/riscv/kvm/kvm_riscv.h
+++ b/target/riscv/kvm/kvm_riscv.h
@@ -23,6 +23,7 @@
void kvm_riscv_reset_vcpu(RISCVCPU *cpu);
void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level);
+void kvm_riscv_aia_access_reg(int group, uint64_t addr, void *val, bool write);
void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
uint64_t aia_irq_num, uint64_t aia_msi_num,
uint64_t aplic_base, uint64_t imsic_base,
--
2.27.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/3] hw/intc/riscv_aplic: Add in-kernel aplic save and restore function
2026-03-05 9:17 [PATCH v2 0/3] riscv: AIA: Add in-kernel irqchips save and restore function support liu.xuemei1
2026-03-05 9:19 ` [PATCH v2 1/3] target/riscv/kvm: create kvm_riscv_aia_access_reg liu.xuemei1
@ 2026-03-05 9:22 ` liu.xuemei1
2026-03-11 23:52 ` Alistair Francis
2026-03-05 9:26 ` [PATCH v2 3/3] hw/intc/imsic: Add in-kernel imsic " liu.xuemei1
2 siblings, 1 reply; 7+ messages in thread
From: liu.xuemei1 @ 2026-03-05 9:22 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, dbarboza, zhiwei_liu, peterx,
farosas, chao.liu.zevorn
Cc: qemu-riscv, qemu-devel, liu.xuemei1
From: Xuemei Liu <liu.xuemei1@zte.com.cn>
Add save and restore function if riscv_use_emulated_aplic return
false, it is to get and set APLIC irqchip state from KVM kernel.
Signed-off-by: Xuemei Liu <liu.xuemei1@zte.com.cn>
---
hw/intc/riscv_aplic.c | 200 ++++++++++++++++++++++++++++------
include/hw/intc/riscv_aplic.h | 4 +
2 files changed, 173 insertions(+), 31 deletions(-)
diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c
index 8f70043111..88b79e9ab2 100644
--- a/hw/intc/riscv_aplic.c
+++ b/hw/intc/riscv_aplic.c
@@ -922,14 +922,7 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp)
}
aplic->bitfield_words = (aplic->num_irqs + 31) >> 5;
- aplic->sourcecfg = g_new0(uint32_t, aplic->num_irqs);
aplic->state = g_new0(uint32_t, aplic->num_irqs);
- aplic->target = g_new0(uint32_t, aplic->num_irqs);
- if (!aplic->msimode) {
- for (i = 0; i < aplic->num_irqs; i++) {
- aplic->target[i] = 1;
- }
- }
aplic->idelivery = g_new0(uint32_t, aplic->num_harts);
aplic->iforce = g_new0(uint32_t, aplic->num_harts);
aplic->ithreshold = g_new0(uint32_t, aplic->num_harts);
@@ -941,6 +934,19 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp)
if (kvm_enabled()) {
aplic->kvm_splitmode = true;
}
+ } else {
+ aplic->nr_words = BITS_TO_U32S(aplic->num_irqs);
+ aplic->setip = g_new0(uint32_t, aplic->nr_words);
+ aplic->clrip = g_new0(uint32_t, aplic->nr_words);
+ aplic->setie = g_new0(uint32_t, aplic->nr_words);
+ }
+
+ aplic->sourcecfg = g_new0(uint32_t, aplic->num_irqs);
+ aplic->target = g_new0(uint32_t, aplic->num_irqs);
+ if (!aplic->msimode) {
+ for (i = 0; i < aplic->num_irqs; i++) {
+ aplic->target[i] = 1;
+ }
}
/*
@@ -968,47 +974,179 @@ static const Property riscv_aplic_properties[] = {
DEFINE_PROP_BOOL("mmode", RISCVAPLICState, mmode, 0),
};
-static bool riscv_aplic_state_needed(void *opaque)
+static bool riscv_aplic_emul_state_needed(void *opaque)
{
RISCVAPLICState *aplic = opaque;
return riscv_use_emulated_aplic(aplic->msimode);
}
+static const VMStateDescription vmstate_riscv_aplic_emul = {
+ .name = "riscv_aplic_emul",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = riscv_aplic_emul_state_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_VARRAY_UINT32(state, RISCVAPLICState,
+ num_irqs, 0,
+ vmstate_info_uint32, uint32_t),
+ VMSTATE_UINT32(mmsicfgaddr, RISCVAPLICState),
+ VMSTATE_UINT32(mmsicfgaddrH, RISCVAPLICState),
+ VMSTATE_UINT32(smsicfgaddr, RISCVAPLICState),
+ VMSTATE_UINT32(smsicfgaddrH, RISCVAPLICState),
+ VMSTATE_UINT32(kvm_msicfgaddr, RISCVAPLICState),
+ VMSTATE_UINT32(kvm_msicfgaddrH, RISCVAPLICState),
+ VMSTATE_VARRAY_UINT32(idelivery, RISCVAPLICState,
+ num_harts, 0,
+ vmstate_info_uint32, uint32_t),
+ VMSTATE_VARRAY_UINT32(iforce, RISCVAPLICState,
+ num_harts, 0,
+ vmstate_info_uint32, uint32_t),
+ VMSTATE_VARRAY_UINT32(ithreshold, RISCVAPLICState,
+ num_harts, 0,
+ vmstate_info_uint32, uint32_t),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool riscv_aplic_in_kernel_state_needed(void *opaque)
+{
+ RISCVAPLICState *aplic = opaque;
+
+ return !riscv_use_emulated_aplic(aplic->msimode);
+}
+
+static int riscv_aplic_in_kernel_pre_save(void *opaque)
+{
+ RISCVAPLICState *aplic = opaque;
+
+ if (!riscv_use_emulated_aplic(aplic->msimode)) {
+ for (uint32_t i = 0; i < aplic->nr_words; i++) {
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
+ APLIC_SETIP_BASE + i * 4,
+ aplic->setip + i, false);
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
+ APLIC_CLRIP_BASE + i * 4,
+ aplic->clrip + i, false);
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
+ APLIC_SETIE_BASE + i * 4,
+ aplic->setie + i, false);
+ }
+ }
+
+ return 0;
+}
+
+static int riscv_aplic_in_kernel_post_load(void *opaque, int version_id)
+{
+ RISCVAPLICState *aplic = opaque;
+
+ if (!riscv_use_emulated_aplic(aplic->msimode)) {
+ for (uint32_t i = 0; i < aplic->nr_words; i++) {
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
+ APLIC_SETIP_BASE + i * 4,
+ aplic->setip + i, true);
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
+ APLIC_CLRIP_BASE + i * 4,
+ aplic->clrip + i, true);
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
+ APLIC_SETIE_BASE + i * 4,
+ aplic->setie + i, true);
+ }
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_riscv_aplic_in_kernel = {
+ .name = "riscv_aplic_in_kernel",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = riscv_aplic_in_kernel_state_needed,
+ .pre_save = riscv_aplic_in_kernel_pre_save,
+ .post_load = riscv_aplic_in_kernel_post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_VARRAY_UINT32(setip, RISCVAPLICState,
+ nr_words, 0,
+ vmstate_info_uint32, uint32_t),
+ VMSTATE_VARRAY_UINT32(clrip, RISCVAPLICState,
+ nr_words, 0,
+ vmstate_info_uint32, uint32_t),
+ VMSTATE_VARRAY_UINT32(setie, RISCVAPLICState,
+ nr_words, 0,
+ vmstate_info_uint32, uint32_t),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int riscv_aplic_pre_save(void *opaque)
+{
+ RISCVAPLICState *aplic = opaque;
+
+ if (!riscv_use_emulated_aplic(aplic->msimode)) {
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC, APLIC_DOMAINCFG,
+ &aplic->domaincfg, false);
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC, APLIC_GENMSI,
+ &aplic->genmsi, false);
+
+ for (uint32_t i = 1; i < aplic->num_irqs; i++) {
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
+ APLIC_SOURCECFG_BASE + (i - 1) * 4,
+ aplic->sourcecfg + i, false);
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
+ APLIC_TARGET_BASE + (i - 1) * 4,
+ aplic->target + i, false);
+ }
+ }
+
+ return 0;
+}
+
+static int riscv_aplic_post_load(void *opaque, int version_id)
+{
+ RISCVAPLICState *aplic = opaque;
+
+ if (!riscv_use_emulated_aplic(aplic->msimode)) {
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC, APLIC_DOMAINCFG,
+ &aplic->domaincfg, true);
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC, APLIC_GENMSI,
+ &aplic->genmsi, true);
+
+ for (uint32_t i = 1; i < aplic->num_irqs; i++) {
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
+ APLIC_SOURCECFG_BASE + (i - 1) * 4,
+ aplic->sourcecfg + i, true);
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
+ APLIC_TARGET_BASE + (i - 1) * 4,
+ aplic->target + i, true);
+ }
+ }
+
+ return 0;
+}
+
static const VMStateDescription vmstate_riscv_aplic = {
.name = "riscv_aplic",
- .version_id = 3,
- .minimum_version_id = 3,
- .needed = riscv_aplic_state_needed,
+ .version_id = 4,
+ .minimum_version_id = 4,
+ .pre_save = riscv_aplic_pre_save,
+ .post_load = riscv_aplic_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(domaincfg, RISCVAPLICState),
- VMSTATE_UINT32(mmsicfgaddr, RISCVAPLICState),
- VMSTATE_UINT32(mmsicfgaddrH, RISCVAPLICState),
- VMSTATE_UINT32(smsicfgaddr, RISCVAPLICState),
- VMSTATE_UINT32(smsicfgaddrH, RISCVAPLICState),
VMSTATE_UINT32(genmsi, RISCVAPLICState),
- VMSTATE_UINT32(kvm_msicfgaddr, RISCVAPLICState),
- VMSTATE_UINT32(kvm_msicfgaddrH, RISCVAPLICState),
- VMSTATE_VARRAY_UINT32(sourcecfg, RISCVAPLICState,
- num_irqs, 0,
- vmstate_info_uint32, uint32_t),
- VMSTATE_VARRAY_UINT32(state, RISCVAPLICState,
+ VMSTATE_VARRAY_UINT32(sourcecfg , RISCVAPLICState,
num_irqs, 0,
vmstate_info_uint32, uint32_t),
VMSTATE_VARRAY_UINT32(target, RISCVAPLICState,
num_irqs, 0,
vmstate_info_uint32, uint32_t),
- VMSTATE_VARRAY_UINT32(idelivery, RISCVAPLICState,
- num_harts, 0,
- vmstate_info_uint32, uint32_t),
- VMSTATE_VARRAY_UINT32(iforce, RISCVAPLICState,
- num_harts, 0,
- vmstate_info_uint32, uint32_t),
- VMSTATE_VARRAY_UINT32(ithreshold, RISCVAPLICState,
- num_harts, 0,
- vmstate_info_uint32, uint32_t),
VMSTATE_END_OF_LIST()
- }
+ },
+ .subsections = (const VMStateDescription * const []) {
+ &vmstate_riscv_aplic_emul,
+ &vmstate_riscv_aplic_in_kernel,
+ NULL
+ }
};
static void riscv_aplic_class_init(ObjectClass *klass, const void *data)
diff --git a/include/hw/intc/riscv_aplic.h b/include/hw/intc/riscv_aplic.h
index c7a4d4ad01..1976bea68c 100644
--- a/include/hw/intc/riscv_aplic.h
+++ b/include/hw/intc/riscv_aplic.h
@@ -53,6 +53,9 @@ struct RISCVAPLICState {
uint32_t *idelivery;
uint32_t *iforce;
uint32_t *ithreshold;
+ uint32_t *setip;
+ uint32_t *clrip;
+ uint32_t *setie;
/* topology */
#define QEMU_APLIC_MAX_CHILDREN 16
@@ -66,6 +69,7 @@ struct RISCVAPLICState {
uint32_t num_harts;
uint32_t iprio_mask;
uint32_t num_irqs;
+ uint32_t nr_words;
bool msimode;
bool mmode;
--
2.27.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 3/3] hw/intc/imsic: Add in-kernel imsic save and restore function
2026-03-05 9:17 [PATCH v2 0/3] riscv: AIA: Add in-kernel irqchips save and restore function support liu.xuemei1
2026-03-05 9:19 ` [PATCH v2 1/3] target/riscv/kvm: create kvm_riscv_aia_access_reg liu.xuemei1
2026-03-05 9:22 ` [PATCH v2 2/3] hw/intc/riscv_aplic: Add in-kernel aplic save and restore function liu.xuemei1
@ 2026-03-05 9:26 ` liu.xuemei1
2026-03-11 23:56 ` Alistair Francis
2 siblings, 1 reply; 7+ messages in thread
From: liu.xuemei1 @ 2026-03-05 9:26 UTC (permalink / raw)
To: palmer, alistair.francis, liwei1518, dbarboza, zhiwei_liu, peterx,
farosas, chao.liu.zevorn
Cc: qemu-riscv, qemu-devel, liu.xuemei1
From: Xuemei Liu <liu.xuemei1@zte.com.cn>
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 <liu.xuemei1@zte.com.cn>
---
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 + i);
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
+ imsic->eip + i, true);
+ }
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_riscv_imsic_in_kernel = {
+ .name = "riscv_imsic_in_kernel",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = riscv_imsic_in_kernel_state_needed,
+ .pre_save = riscv_imsic_in_kernel_pre_save,
+ .post_load = riscv_imsic_in_kernel_post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_VARRAY_UINT32(eie, RISCVIMSICState,
+ nr_eix, 0,
+ vmstate_info_uint32, uint32_t),
+ VMSTATE_VARRAY_UINT32(eip, RISCVIMSICState,
+ nr_eix, 0,
+ vmstate_info_uint32, uint32_t),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int riscv_imsic_pre_save(void *opaque)
+{
+ RISCVIMSICState *imsic = opaque;
+ uint64_t attr;
+
+ if (kvm_irqchip_in_kernel()) {
+ attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
+ ISELECT_IMSIC_EIDELIVERY);
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
+ imsic->eidelivery, false);
+
+ attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
+ ISELECT_IMSIC_EITHRESHOLD);
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
+ imsic->eithreshold, false);
+ }
+
+ return 0;
+}
+
+static int riscv_imsic_post_load(void *opaque, int version_id)
+{
+ RISCVIMSICState *imsic = opaque;
+ uint64_t attr;
+
+ if (kvm_irqchip_in_kernel()) {
+ attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
+ ISELECT_IMSIC_EIDELIVERY);
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
+ imsic->eidelivery, true);
+
+ attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
+ ISELECT_IMSIC_EITHRESHOLD);
+ kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
+ imsic->eithreshold, true);
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_riscv_imsic = {
+ .name = "riscv_imsic",
+ .version_id = 3,
+ .minimum_version_id = 3,
+ .pre_save = riscv_imsic_pre_save,
+ .post_load = riscv_imsic_post_load,
+ .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_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * const []) {
+ &vmstate_riscv_imsic_emul,
+ &vmstate_riscv_imsic_in_kernel,
+ NULL
+ }
+};
+
static void riscv_imsic_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/include/hw/intc/riscv_imsic.h b/include/hw/intc/riscv_imsic.h
index fae999731d..2206d82e0c 100644
--- a/include/hw/intc/riscv_imsic.h
+++ b/include/hw/intc/riscv_imsic.h
@@ -54,12 +54,15 @@ struct RISCVIMSICState {
uint32_t *eidelivery;
uint32_t *eithreshold;
uint32_t *eistate;
+ uint32_t *eip;
+ uint32_t *eie;
/* config */
bool mmode;
uint32_t hartid;
uint32_t num_pages;
uint32_t num_irqs;
+ uint32_t nr_eix;
};
DeviceState *riscv_imsic_create(hwaddr addr, uint32_t hartid, bool mmode,
diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
index c7b838a628..4b9b40f4c0 100644
--- a/include/qemu/bitops.h
+++ b/include/qemu/bitops.h
@@ -16,10 +16,11 @@
#include "host-utils.h"
#include "atomic.h"
-#define BITS_PER_BYTE CHAR_BIT
-#define BITS_PER_LONG (sizeof (unsigned long) * BITS_PER_BYTE)
-#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
-#define BITS_TO_U32S(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(uint32_t))
+#define BITS_PER_BYTE CHAR_BIT
+#define BITS_PER_LONG (sizeof(unsigned long) * BITS_PER_BYTE)
+#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
+#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(uint64_t))
+#define BITS_TO_U32S(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(uint32_t))
#define BIT(nr) (1UL << (nr))
#define BIT_ULL(nr) (1ULL << (nr))
diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c
index 89cb211472..368a2922aa 100644
--- a/migration/vmstate-types.c
+++ b/migration/vmstate-types.c
@@ -599,7 +599,6 @@ const VMStateInfo vmstate_info_tmp = {
* is an array of 'unsigned long', which may be either 32 or 64 bits.
*/
/* This is the number of 64 bit words sent over the wire */
-#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
static int get_bitmap(QEMUFile *f, void *pv, size_t size,
const VMStateField *field)
{
--
2.27.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/3] target/riscv/kvm: create kvm_riscv_aia_access_reg
2026-03-05 9:19 ` [PATCH v2 1/3] target/riscv/kvm: create kvm_riscv_aia_access_reg liu.xuemei1
@ 2026-03-11 23:46 ` Alistair Francis
0 siblings, 0 replies; 7+ messages in thread
From: Alistair Francis @ 2026-03-11 23:46 UTC (permalink / raw)
To: liu.xuemei1
Cc: palmer, alistair.francis, liwei1518, dbarboza, zhiwei_liu, peterx,
farosas, chao.liu.zevorn, qemu-riscv, qemu-devel
On Thu, Mar 5, 2026 at 7:21 PM <liu.xuemei1@zte.com.cn> wrote:
>
> From: Xuemei Liu <liu.xuemei1@zte.com.cn>
>
> Create common function kvm_riscv_aia_access_reg to access APLIC
> and IMSIC regs
>
> Signed-off-by: Xuemei Liu <liu.xuemei1@zte.com.cn>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> target/riscv/kvm/kvm-cpu.c | 7 ++++++-
> target/riscv/kvm/kvm_riscv.h | 1 +
> 2 files changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
> index befcbb0a9a..2c29d8d07c 100644
> --- a/target/riscv/kvm/kvm-cpu.c
> +++ b/target/riscv/kvm/kvm-cpu.c
> @@ -58,6 +58,7 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level)
> }
>
> static bool cap_has_mp_state;
> +static int aia_fd = -1;
>
> #define KVM_RISCV_REG_ID_U32(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U32 | \
> type | idx)
> @@ -1842,13 +1843,17 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
> "auto");
> }
>
> +void kvm_riscv_aia_access_reg(int group, uint64_t addr, void *val, bool write)
> +{
> + kvm_device_access(aia_fd, group, addr, val, write, &error_abort);
> +}
> +
> void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
> uint64_t aia_irq_num, uint64_t aia_msi_num,
> uint64_t aplic_base, uint64_t imsic_base,
> uint64_t guest_num)
> {
> int ret, i;
> - int aia_fd = -1;
> uint64_t default_aia_mode;
> uint64_t socket_count = riscv_socket_count(machine);
> uint64_t max_hart_per_socket = 0;
> diff --git a/target/riscv/kvm/kvm_riscv.h b/target/riscv/kvm/kvm_riscv.h
> index 953db94160..cec13d9f31 100644
> --- a/target/riscv/kvm/kvm_riscv.h
> +++ b/target/riscv/kvm/kvm_riscv.h
> @@ -23,6 +23,7 @@
>
> void kvm_riscv_reset_vcpu(RISCVCPU *cpu);
> void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level);
> +void kvm_riscv_aia_access_reg(int group, uint64_t addr, void *val, bool write);
> void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
> uint64_t aia_irq_num, uint64_t aia_msi_num,
> uint64_t aplic_base, uint64_t imsic_base,
> --
> 2.27.0
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/3] hw/intc/riscv_aplic: Add in-kernel aplic save and restore function
2026-03-05 9:22 ` [PATCH v2 2/3] hw/intc/riscv_aplic: Add in-kernel aplic save and restore function liu.xuemei1
@ 2026-03-11 23:52 ` Alistair Francis
0 siblings, 0 replies; 7+ messages in thread
From: Alistair Francis @ 2026-03-11 23:52 UTC (permalink / raw)
To: liu.xuemei1
Cc: palmer, alistair.francis, liwei1518, dbarboza, zhiwei_liu, peterx,
farosas, chao.liu.zevorn, qemu-riscv, qemu-devel
On Thu, Mar 5, 2026 at 7:24 PM <liu.xuemei1@zte.com.cn> wrote:
>
> From: Xuemei Liu <liu.xuemei1@zte.com.cn>
>
> Add save and restore function if riscv_use_emulated_aplic return
> false, it is to get and set APLIC irqchip state from KVM kernel.
>
> Signed-off-by: Xuemei Liu <liu.xuemei1@zte.com.cn>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/intc/riscv_aplic.c | 200 ++++++++++++++++++++++++++++------
> include/hw/intc/riscv_aplic.h | 4 +
> 2 files changed, 173 insertions(+), 31 deletions(-)
>
> diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c
> index 8f70043111..88b79e9ab2 100644
> --- a/hw/intc/riscv_aplic.c
> +++ b/hw/intc/riscv_aplic.c
> @@ -922,14 +922,7 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp)
> }
>
> aplic->bitfield_words = (aplic->num_irqs + 31) >> 5;
> - aplic->sourcecfg = g_new0(uint32_t, aplic->num_irqs);
> aplic->state = g_new0(uint32_t, aplic->num_irqs);
> - aplic->target = g_new0(uint32_t, aplic->num_irqs);
> - if (!aplic->msimode) {
> - for (i = 0; i < aplic->num_irqs; i++) {
> - aplic->target[i] = 1;
> - }
> - }
> aplic->idelivery = g_new0(uint32_t, aplic->num_harts);
> aplic->iforce = g_new0(uint32_t, aplic->num_harts);
> aplic->ithreshold = g_new0(uint32_t, aplic->num_harts);
> @@ -941,6 +934,19 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp)
> if (kvm_enabled()) {
> aplic->kvm_splitmode = true;
> }
> + } else {
> + aplic->nr_words = BITS_TO_U32S(aplic->num_irqs);
> + aplic->setip = g_new0(uint32_t, aplic->nr_words);
> + aplic->clrip = g_new0(uint32_t, aplic->nr_words);
> + aplic->setie = g_new0(uint32_t, aplic->nr_words);
> + }
> +
> + aplic->sourcecfg = g_new0(uint32_t, aplic->num_irqs);
> + aplic->target = g_new0(uint32_t, aplic->num_irqs);
> + if (!aplic->msimode) {
> + for (i = 0; i < aplic->num_irqs; i++) {
> + aplic->target[i] = 1;
> + }
> }
>
> /*
> @@ -968,47 +974,179 @@ static const Property riscv_aplic_properties[] = {
> DEFINE_PROP_BOOL("mmode", RISCVAPLICState, mmode, 0),
> };
>
> -static bool riscv_aplic_state_needed(void *opaque)
> +static bool riscv_aplic_emul_state_needed(void *opaque)
> {
> RISCVAPLICState *aplic = opaque;
>
> return riscv_use_emulated_aplic(aplic->msimode);
> }
>
> +static const VMStateDescription vmstate_riscv_aplic_emul = {
> + .name = "riscv_aplic_emul",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .needed = riscv_aplic_emul_state_needed,
> + .fields = (const VMStateField[]) {
> + VMSTATE_VARRAY_UINT32(state, RISCVAPLICState,
> + num_irqs, 0,
> + vmstate_info_uint32, uint32_t),
> + VMSTATE_UINT32(mmsicfgaddr, RISCVAPLICState),
> + VMSTATE_UINT32(mmsicfgaddrH, RISCVAPLICState),
> + VMSTATE_UINT32(smsicfgaddr, RISCVAPLICState),
> + VMSTATE_UINT32(smsicfgaddrH, RISCVAPLICState),
> + VMSTATE_UINT32(kvm_msicfgaddr, RISCVAPLICState),
> + VMSTATE_UINT32(kvm_msicfgaddrH, RISCVAPLICState),
> + VMSTATE_VARRAY_UINT32(idelivery, RISCVAPLICState,
> + num_harts, 0,
> + vmstate_info_uint32, uint32_t),
> + VMSTATE_VARRAY_UINT32(iforce, RISCVAPLICState,
> + num_harts, 0,
> + vmstate_info_uint32, uint32_t),
> + VMSTATE_VARRAY_UINT32(ithreshold, RISCVAPLICState,
> + num_harts, 0,
> + vmstate_info_uint32, uint32_t),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static bool riscv_aplic_in_kernel_state_needed(void *opaque)
> +{
> + RISCVAPLICState *aplic = opaque;
> +
> + return !riscv_use_emulated_aplic(aplic->msimode);
> +}
> +
> +static int riscv_aplic_in_kernel_pre_save(void *opaque)
> +{
> + RISCVAPLICState *aplic = opaque;
> +
> + if (!riscv_use_emulated_aplic(aplic->msimode)) {
> + for (uint32_t i = 0; i < aplic->nr_words; i++) {
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
> + APLIC_SETIP_BASE + i * 4,
> + aplic->setip + i, false);
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
> + APLIC_CLRIP_BASE + i * 4,
> + aplic->clrip + i, false);
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
> + APLIC_SETIE_BASE + i * 4,
> + aplic->setie + i, false);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int riscv_aplic_in_kernel_post_load(void *opaque, int version_id)
> +{
> + RISCVAPLICState *aplic = opaque;
> +
> + if (!riscv_use_emulated_aplic(aplic->msimode)) {
> + for (uint32_t i = 0; i < aplic->nr_words; i++) {
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
> + APLIC_SETIP_BASE + i * 4,
> + aplic->setip + i, true);
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
> + APLIC_CLRIP_BASE + i * 4,
> + aplic->clrip + i, true);
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
> + APLIC_SETIE_BASE + i * 4,
> + aplic->setie + i, true);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static const VMStateDescription vmstate_riscv_aplic_in_kernel = {
> + .name = "riscv_aplic_in_kernel",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .needed = riscv_aplic_in_kernel_state_needed,
> + .pre_save = riscv_aplic_in_kernel_pre_save,
> + .post_load = riscv_aplic_in_kernel_post_load,
> + .fields = (const VMStateField[]) {
> + VMSTATE_VARRAY_UINT32(setip, RISCVAPLICState,
> + nr_words, 0,
> + vmstate_info_uint32, uint32_t),
> + VMSTATE_VARRAY_UINT32(clrip, RISCVAPLICState,
> + nr_words, 0,
> + vmstate_info_uint32, uint32_t),
> + VMSTATE_VARRAY_UINT32(setie, RISCVAPLICState,
> + nr_words, 0,
> + vmstate_info_uint32, uint32_t),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static int riscv_aplic_pre_save(void *opaque)
> +{
> + RISCVAPLICState *aplic = opaque;
> +
> + if (!riscv_use_emulated_aplic(aplic->msimode)) {
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC, APLIC_DOMAINCFG,
> + &aplic->domaincfg, false);
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC, APLIC_GENMSI,
> + &aplic->genmsi, false);
> +
> + for (uint32_t i = 1; i < aplic->num_irqs; i++) {
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
> + APLIC_SOURCECFG_BASE + (i - 1) * 4,
> + aplic->sourcecfg + i, false);
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
> + APLIC_TARGET_BASE + (i - 1) * 4,
> + aplic->target + i, false);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int riscv_aplic_post_load(void *opaque, int version_id)
> +{
> + RISCVAPLICState *aplic = opaque;
> +
> + if (!riscv_use_emulated_aplic(aplic->msimode)) {
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC, APLIC_DOMAINCFG,
> + &aplic->domaincfg, true);
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC, APLIC_GENMSI,
> + &aplic->genmsi, true);
> +
> + for (uint32_t i = 1; i < aplic->num_irqs; i++) {
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
> + APLIC_SOURCECFG_BASE + (i - 1) * 4,
> + aplic->sourcecfg + i, true);
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_APLIC,
> + APLIC_TARGET_BASE + (i - 1) * 4,
> + aplic->target + i, true);
> + }
> + }
> +
> + return 0;
> +}
> +
> static const VMStateDescription vmstate_riscv_aplic = {
> .name = "riscv_aplic",
> - .version_id = 3,
> - .minimum_version_id = 3,
> - .needed = riscv_aplic_state_needed,
> + .version_id = 4,
> + .minimum_version_id = 4,
> + .pre_save = riscv_aplic_pre_save,
> + .post_load = riscv_aplic_post_load,
> .fields = (const VMStateField[]) {
> VMSTATE_UINT32(domaincfg, RISCVAPLICState),
> - VMSTATE_UINT32(mmsicfgaddr, RISCVAPLICState),
> - VMSTATE_UINT32(mmsicfgaddrH, RISCVAPLICState),
> - VMSTATE_UINT32(smsicfgaddr, RISCVAPLICState),
> - VMSTATE_UINT32(smsicfgaddrH, RISCVAPLICState),
> VMSTATE_UINT32(genmsi, RISCVAPLICState),
> - VMSTATE_UINT32(kvm_msicfgaddr, RISCVAPLICState),
> - VMSTATE_UINT32(kvm_msicfgaddrH, RISCVAPLICState),
> - VMSTATE_VARRAY_UINT32(sourcecfg, RISCVAPLICState,
> - num_irqs, 0,
> - vmstate_info_uint32, uint32_t),
> - VMSTATE_VARRAY_UINT32(state, RISCVAPLICState,
> + VMSTATE_VARRAY_UINT32(sourcecfg , RISCVAPLICState,
> num_irqs, 0,
> vmstate_info_uint32, uint32_t),
> VMSTATE_VARRAY_UINT32(target, RISCVAPLICState,
> num_irqs, 0,
> vmstate_info_uint32, uint32_t),
> - VMSTATE_VARRAY_UINT32(idelivery, RISCVAPLICState,
> - num_harts, 0,
> - vmstate_info_uint32, uint32_t),
> - VMSTATE_VARRAY_UINT32(iforce, RISCVAPLICState,
> - num_harts, 0,
> - vmstate_info_uint32, uint32_t),
> - VMSTATE_VARRAY_UINT32(ithreshold, RISCVAPLICState,
> - num_harts, 0,
> - vmstate_info_uint32, uint32_t),
> VMSTATE_END_OF_LIST()
> - }
> + },
> + .subsections = (const VMStateDescription * const []) {
> + &vmstate_riscv_aplic_emul,
> + &vmstate_riscv_aplic_in_kernel,
> + NULL
> + }
> };
>
> static void riscv_aplic_class_init(ObjectClass *klass, const void *data)
> diff --git a/include/hw/intc/riscv_aplic.h b/include/hw/intc/riscv_aplic.h
> index c7a4d4ad01..1976bea68c 100644
> --- a/include/hw/intc/riscv_aplic.h
> +++ b/include/hw/intc/riscv_aplic.h
> @@ -53,6 +53,9 @@ struct RISCVAPLICState {
> uint32_t *idelivery;
> uint32_t *iforce;
> uint32_t *ithreshold;
> + uint32_t *setip;
> + uint32_t *clrip;
> + uint32_t *setie;
>
> /* topology */
> #define QEMU_APLIC_MAX_CHILDREN 16
> @@ -66,6 +69,7 @@ struct RISCVAPLICState {
> uint32_t num_harts;
> uint32_t iprio_mask;
> uint32_t num_irqs;
> + uint32_t nr_words;
> bool msimode;
> bool mmode;
>
> --
> 2.27.0
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 3/3] hw/intc/imsic: Add in-kernel imsic save and restore function
2026-03-05 9:26 ` [PATCH v2 3/3] hw/intc/imsic: Add in-kernel imsic " liu.xuemei1
@ 2026-03-11 23:56 ` Alistair Francis
0 siblings, 0 replies; 7+ messages in thread
From: Alistair Francis @ 2026-03-11 23:56 UTC (permalink / raw)
To: liu.xuemei1
Cc: palmer, alistair.francis, liwei1518, dbarboza, zhiwei_liu, peterx,
farosas, chao.liu.zevorn, qemu-riscv, qemu-devel
On Thu, Mar 5, 2026 at 7:28 PM <liu.xuemei1@zte.com.cn> wrote:
>
> From: Xuemei Liu <liu.xuemei1@zte.com.cn>
>
> 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 <liu.xuemei1@zte.com.cn>
> ---
> 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 + i);
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
> + imsic->eip + i, true);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static const VMStateDescription vmstate_riscv_imsic_in_kernel = {
> + .name = "riscv_imsic_in_kernel",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .needed = riscv_imsic_in_kernel_state_needed,
> + .pre_save = riscv_imsic_in_kernel_pre_save,
> + .post_load = riscv_imsic_in_kernel_post_load,
> + .fields = (const VMStateField[]) {
> + VMSTATE_VARRAY_UINT32(eie, RISCVIMSICState,
> + nr_eix, 0,
> + vmstate_info_uint32, uint32_t),
> + VMSTATE_VARRAY_UINT32(eip, RISCVIMSICState,
> + nr_eix, 0,
> + vmstate_info_uint32, uint32_t),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static int riscv_imsic_pre_save(void *opaque)
> +{
> + RISCVIMSICState *imsic = opaque;
> + uint64_t attr;
> +
> + if (kvm_irqchip_in_kernel()) {
> + attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
> + ISELECT_IMSIC_EIDELIVERY);
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
> + imsic->eidelivery, false);
> +
> + attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
> + ISELECT_IMSIC_EITHRESHOLD);
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
> + imsic->eithreshold, false);
> + }
> +
> + return 0;
> +}
> +
> +static int riscv_imsic_post_load(void *opaque, int version_id)
> +{
> + RISCVIMSICState *imsic = opaque;
> + uint64_t attr;
> +
> + if (kvm_irqchip_in_kernel()) {
> + attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
> + ISELECT_IMSIC_EIDELIVERY);
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
> + imsic->eidelivery, true);
> +
> + attr = KVM_DEV_RISCV_AIA_IMSIC_MKATTR(imsic->hartid,
> + ISELECT_IMSIC_EITHRESHOLD);
> + kvm_riscv_aia_access_reg(KVM_DEV_RISCV_AIA_GRP_IMSIC, attr,
> + imsic->eithreshold, true);
> + }
> +
> + return 0;
> +}
> +
> +static const VMStateDescription vmstate_riscv_imsic = {
> + .name = "riscv_imsic",
> + .version_id = 3,
> + .minimum_version_id = 3,
> + .pre_save = riscv_imsic_pre_save,
> + .post_load = riscv_imsic_post_load,
> + .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_END_OF_LIST()
> + },
> + .subsections = (const VMStateDescription * const []) {
> + &vmstate_riscv_imsic_emul,
> + &vmstate_riscv_imsic_in_kernel,
> + NULL
> + }
> +};
> +
> static void riscv_imsic_class_init(ObjectClass *klass, const void *data)
> {
> DeviceClass *dc = DEVICE_CLASS(klass);
> diff --git a/include/hw/intc/riscv_imsic.h b/include/hw/intc/riscv_imsic.h
> index fae999731d..2206d82e0c 100644
> --- a/include/hw/intc/riscv_imsic.h
> +++ b/include/hw/intc/riscv_imsic.h
> @@ -54,12 +54,15 @@ struct RISCVIMSICState {
> uint32_t *eidelivery;
> uint32_t *eithreshold;
> uint32_t *eistate;
> + uint32_t *eip;
> + uint32_t *eie;
>
> /* config */
> bool mmode;
> uint32_t hartid;
> uint32_t num_pages;
> uint32_t num_irqs;
> + uint32_t nr_eix;
> };
>
> DeviceState *riscv_imsic_create(hwaddr addr, uint32_t hartid, bool mmode,
> diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
> index c7b838a628..4b9b40f4c0 100644
> --- a/include/qemu/bitops.h
> +++ b/include/qemu/bitops.h
> @@ -16,10 +16,11 @@
> #include "host-utils.h"
> #include "atomic.h"
>
> -#define BITS_PER_BYTE CHAR_BIT
> -#define BITS_PER_LONG (sizeof (unsigned long) * BITS_PER_BYTE)
> -#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
> -#define BITS_TO_U32S(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(uint32_t))
> +#define BITS_PER_BYTE CHAR_BIT
> +#define BITS_PER_LONG (sizeof(unsigned long) * BITS_PER_BYTE)
> +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
> +#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(uint64_t))
> +#define BITS_TO_U32S(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(uint32_t))
This shouldn't be changed
Alistair
>
> #define BIT(nr) (1UL << (nr))
> #define BIT_ULL(nr) (1ULL << (nr))
> diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c
> index 89cb211472..368a2922aa 100644
> --- a/migration/vmstate-types.c
> +++ b/migration/vmstate-types.c
> @@ -599,7 +599,6 @@ const VMStateInfo vmstate_info_tmp = {
> * is an array of 'unsigned long', which may be either 32 or 64 bits.
> */
> /* This is the number of 64 bit words sent over the wire */
> -#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
> static int get_bitmap(QEMUFile *f, void *pv, size_t size,
> const VMStateField *field)
> {
> --
> 2.27.0
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-03-11 23:57 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-05 9:17 [PATCH v2 0/3] riscv: AIA: Add in-kernel irqchips save and restore function support liu.xuemei1
2026-03-05 9:19 ` [PATCH v2 1/3] target/riscv/kvm: create kvm_riscv_aia_access_reg liu.xuemei1
2026-03-11 23:46 ` Alistair Francis
2026-03-05 9:22 ` [PATCH v2 2/3] hw/intc/riscv_aplic: Add in-kernel aplic save and restore function liu.xuemei1
2026-03-11 23:52 ` Alistair Francis
2026-03-05 9:26 ` [PATCH v2 3/3] hw/intc/imsic: Add in-kernel imsic " liu.xuemei1
2026-03-11 23:56 ` Alistair Francis
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox