On Thu, Mar 5, 2026 at 7:24 PM <[email protected]> wrote: > > From: Xuemei Liu <[email protected]> > > 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 <[email protected]>
Acked-by: Alistair Francis <[email protected]> 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 >
