Re: [PATCH v2 2/3] hw/intc/riscv_aplic: Add in-kernel aplic save and restore function
On Thu, Mar 5, 2026 at 7:24 PM wrote:
>
> From: Xuemei Liu
>
> 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
Acked-by: Alistair Francis
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 (uin
[PATCH v2 2/3] hw/intc/riscv_aplic: Add in-kernel aplic save and restore function
From: Xuemei Liu
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
---
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,
+
