Re: [Qemu-devel] [PATCH v8 3/5] hw/intc/arm_gicv3_kvm: Implement get/put functions
Hi, On 17/02/2017 07:31, vijay.kil...@gmail.com wrote: > From: Vijaya Kumar K> > This actually implements pre_save and post_load methods for in-kernel > vGICv3. > > Signed-off-by: Pavel Fedin > Signed-off-by: Peter Maydell I noticed some saved/restored registers are not really emulated on kernel side (see below) but looks a good practice to do the job according to the spec anyway. Reviewed-by: Eric Auger Thanks Eric > [PMM: > * use decimal, not 0bnnn > * fixed typo in names of ICC_APR0R_EL1 and ICC_AP1R_EL1 > * completely rearranged the get and put functions to read and write >the state in a natural order, rather than mixing distributor and >redistributor state together] > Signed-off-by: Vijaya Kumar K > [Vijay: > * Update macro KVM_VGIC_ATTR > * Use 32 bit access for gicd and gicr > * GICD_IROUTER, GICD_TYPER, GICR_PROPBASER and GICR_PENDBASER reg >access are changed from 64-bit to 32-bit access > * Add ICC_SRE_EL1 save and restore > * Dropped translate_fn mechanism and coded functions to handle >save and restore of edge_trigger and priority > * Number of APnR register saved/restored based on number of >priority bits supported] > Reviewed-by: Peter Maydell > --- > --- > hw/intc/arm_gicv3_kvm.c | 573 > +-- > hw/intc/gicv3_internal.h | 1 + > 2 files changed, 558 insertions(+), 16 deletions(-) > > diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c > index d69dc47..cda1af4 100644 > --- a/hw/intc/arm_gicv3_kvm.c > +++ b/hw/intc/arm_gicv3_kvm.c > @@ -23,8 +23,10 @@ > #include "qapi/error.h" > #include "hw/intc/arm_gicv3_common.h" > #include "hw/sysbus.h" > +#include "qemu/error-report.h" > #include "sysemu/kvm.h" > #include "kvm_arm.h" > +#include "gicv3_internal.h" > #include "vgic_common.h" > #include "migration/migration.h" > > @@ -44,6 +46,32 @@ > #define KVM_ARM_GICV3_GET_CLASS(obj) \ > OBJECT_GET_CLASS(KVMARMGICv3Class, (obj), TYPE_KVM_ARM_GICV3) > > +#define KVM_DEV_ARM_VGIC_SYSREG(op0, op1, crn, crm, op2) \ > + (ARM64_SYS_REG_SHIFT_MASK(op0, OP0) | \ > + ARM64_SYS_REG_SHIFT_MASK(op1, OP1) | \ > + ARM64_SYS_REG_SHIFT_MASK(crn, CRN) | \ > + ARM64_SYS_REG_SHIFT_MASK(crm, CRM) | \ > + ARM64_SYS_REG_SHIFT_MASK(op2, OP2)) > + > +#define ICC_PMR_EL1 \ > +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 4, 6, 0) > +#define ICC_BPR0_EL1\ > +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 8, 3) > +#define ICC_AP0R_EL1(n) \ > +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 8, 4 | n) > +#define ICC_AP1R_EL1(n) \ > +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 9, n) > +#define ICC_BPR1_EL1\ > +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 3) > +#define ICC_CTLR_EL1\ > +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 4) > +#define ICC_SRE_EL1 \ > +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 5) > +#define ICC_IGRPEN0_EL1 \ > +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 6) > +#define ICC_IGRPEN1_EL1 \ > +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 7) > + > typedef struct KVMARMGICv3Class { > ARMGICv3CommonClass parent_class; > DeviceRealize parent_realize; > @@ -57,16 +85,523 @@ static void kvm_arm_gicv3_set_irq(void *opaque, int irq, > int level) > kvm_arm_gic_set_irq(s->num_irq, irq, level); > } > > +#define KVM_VGIC_ATTR(reg, typer) \ > +((typer & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) | (reg)) > + > +static inline void kvm_gicd_access(GICv3State *s, int offset, > + uint32_t *val, bool write) > +{ > +kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, > + KVM_VGIC_ATTR(offset, 0), > + val, write); > +} > + > +static inline void kvm_gicr_access(GICv3State *s, int offset, int cpu, > + uint32_t *val, bool write) > +{ > +kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, > + KVM_VGIC_ATTR(offset, s->cpu[cpu].gicr_typer), > + val, write); > +} > + > +static inline void kvm_gicc_access(GICv3State *s, uint64_t reg, int cpu, > + uint64_t *val, bool write) > +{ > +kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, > + KVM_VGIC_ATTR(reg, s->cpu[cpu].gicr_typer), > + val, write); > +} > + > +static inline void kvm_gic_line_level_access(GICv3State *s, int irq, int cpu, > + uint32_t *val, bool write) > +{ > +kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO, > + KVM_VGIC_ATTR(irq, s->cpu[cpu].gicr_typer) | > + (VGIC_LEVEL_INFO_LINE_LEVEL << > +
[Qemu-devel] [PATCH v8 3/5] hw/intc/arm_gicv3_kvm: Implement get/put functions
From: Vijaya Kumar KThis actually implements pre_save and post_load methods for in-kernel vGICv3. Signed-off-by: Pavel Fedin Signed-off-by: Peter Maydell [PMM: * use decimal, not 0bnnn * fixed typo in names of ICC_APR0R_EL1 and ICC_AP1R_EL1 * completely rearranged the get and put functions to read and write the state in a natural order, rather than mixing distributor and redistributor state together] Signed-off-by: Vijaya Kumar K [Vijay: * Update macro KVM_VGIC_ATTR * Use 32 bit access for gicd and gicr * GICD_IROUTER, GICD_TYPER, GICR_PROPBASER and GICR_PENDBASER reg access are changed from 64-bit to 32-bit access * Add ICC_SRE_EL1 save and restore * Dropped translate_fn mechanism and coded functions to handle save and restore of edge_trigger and priority * Number of APnR register saved/restored based on number of priority bits supported] Reviewed-by: Peter Maydell --- --- hw/intc/arm_gicv3_kvm.c | 573 +-- hw/intc/gicv3_internal.h | 1 + 2 files changed, 558 insertions(+), 16 deletions(-) diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index d69dc47..cda1af4 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -23,8 +23,10 @@ #include "qapi/error.h" #include "hw/intc/arm_gicv3_common.h" #include "hw/sysbus.h" +#include "qemu/error-report.h" #include "sysemu/kvm.h" #include "kvm_arm.h" +#include "gicv3_internal.h" #include "vgic_common.h" #include "migration/migration.h" @@ -44,6 +46,32 @@ #define KVM_ARM_GICV3_GET_CLASS(obj) \ OBJECT_GET_CLASS(KVMARMGICv3Class, (obj), TYPE_KVM_ARM_GICV3) +#define KVM_DEV_ARM_VGIC_SYSREG(op0, op1, crn, crm, op2) \ + (ARM64_SYS_REG_SHIFT_MASK(op0, OP0) | \ + ARM64_SYS_REG_SHIFT_MASK(op1, OP1) | \ + ARM64_SYS_REG_SHIFT_MASK(crn, CRN) | \ + ARM64_SYS_REG_SHIFT_MASK(crm, CRM) | \ + ARM64_SYS_REG_SHIFT_MASK(op2, OP2)) + +#define ICC_PMR_EL1 \ +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 4, 6, 0) +#define ICC_BPR0_EL1\ +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 8, 3) +#define ICC_AP0R_EL1(n) \ +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 8, 4 | n) +#define ICC_AP1R_EL1(n) \ +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 9, n) +#define ICC_BPR1_EL1\ +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 3) +#define ICC_CTLR_EL1\ +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 4) +#define ICC_SRE_EL1 \ +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 5) +#define ICC_IGRPEN0_EL1 \ +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 6) +#define ICC_IGRPEN1_EL1 \ +KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 7) + typedef struct KVMARMGICv3Class { ARMGICv3CommonClass parent_class; DeviceRealize parent_realize; @@ -57,16 +85,523 @@ static void kvm_arm_gicv3_set_irq(void *opaque, int irq, int level) kvm_arm_gic_set_irq(s->num_irq, irq, level); } +#define KVM_VGIC_ATTR(reg, typer) \ +((typer & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) | (reg)) + +static inline void kvm_gicd_access(GICv3State *s, int offset, + uint32_t *val, bool write) +{ +kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, + KVM_VGIC_ATTR(offset, 0), + val, write); +} + +static inline void kvm_gicr_access(GICv3State *s, int offset, int cpu, + uint32_t *val, bool write) +{ +kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, + KVM_VGIC_ATTR(offset, s->cpu[cpu].gicr_typer), + val, write); +} + +static inline void kvm_gicc_access(GICv3State *s, uint64_t reg, int cpu, + uint64_t *val, bool write) +{ +kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, + KVM_VGIC_ATTR(reg, s->cpu[cpu].gicr_typer), + val, write); +} + +static inline void kvm_gic_line_level_access(GICv3State *s, int irq, int cpu, + uint32_t *val, bool write) +{ +kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO, + KVM_VGIC_ATTR(irq, s->cpu[cpu].gicr_typer) | + (VGIC_LEVEL_INFO_LINE_LEVEL << + KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT), + val, write); +} + +/* Loop through each distributor IRQ related register; since bits + * corresponding to SPIs and PPIs are RAZ/WI when affinity routing + * is enabled, we skip those. + */ +#define for_each_dist_irq_reg(_irq, _max, _field_width) \ +for (_irq = GIC_INTERNAL; _irq < _max; _irq += (32 / _field_width)) + +static void kvm_dist_get_priority(GICv3State *s, uint32_t offset, uint8_t *bmp) +{ +uint32_t reg, *field; +int irq; + +