* [Qemu-devel] [RFC PATCH 0/4] GICv3 live migration support
@ 2015-09-30 13:59 Pavel Fedin
2015-09-30 13:59 ` [Qemu-devel] [RFC PATCH 1/4] hw/intc/arm_gicv3_common: Add state information Pavel Fedin
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Pavel Fedin @ 2015-09-30 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Juan Quintela, Shlomo Pongratz, Shlomo Pongratz,
Amit Shah, Diana Craciun
This series introduces support for GICv3 live migration. It is based on
kernel API which is not released yet, therefore i post it as an RFC.
Kernel patches which implement this functionality are:
- [PATCH v4 0/7] KVM: arm64: Implement API for vGICv3 live migration
http://www.spinics.net/lists/kvm/msg121588.html
The main purpose of this RFC is to agree on GICv3 state data format,
because software implementation of GICv3 is also going to use it. In order
to simplify GICv3 software emulation development, part 1 of this patchset
can be accepted right now, without waiting for the kernel part.
The second question which should be addressed is how to correctly describe
bitfields in vmstate. Bitfields are used by this code in order to reflect
per-CPU interrupt status. qemu defines bitfields as arrays of 'long',
therefore element length can be different on different systems. Our vmstate
macros support only types with fixed size, like UINT64 and UINT32. In order
to work around this problem, i relied on __SIZEOF_LONG__ definition.
However, i suppose, it is gcc-specific and this approach is wrong for
mainstream, therefore i'd like to discuss how this could be done better.
Since 'long' maps to something, i think that adding a specific code for it
would be too much anyway. May be add configure test for sizeof(long) ?
Pavel Fedin (4):
hw/intc/arm_gicv3_common: Add state information
kernel: Add definitions for GICv3 attributes
hw/intc/arm_gicv3_kvm: Implement get/put functions
hw/intc/arm_gicv3_common: Add vmstate descriptors
hw/intc/arm_gicv3_common.c | 199 ++++++++++++++++++-
hw/intc/arm_gicv3_kvm.c | 391 ++++++++++++++++++++++++++++++++++++-
hw/intc/gicv3_internal.h | 152 ++++++++++++++
include/hw/intc/arm_gicv3_common.h | 76 +++++++
linux-headers/asm-arm64/kvm.h | 10 +-
5 files changed, 821 insertions(+), 7 deletions(-)
create mode 100644 hw/intc/gicv3_internal.h
--
2.4.4
^ permalink raw reply [flat|nested] 5+ messages in thread
* [Qemu-devel] [RFC PATCH 1/4] hw/intc/arm_gicv3_common: Add state information
2015-09-30 13:59 [Qemu-devel] [RFC PATCH 0/4] GICv3 live migration support Pavel Fedin
@ 2015-09-30 13:59 ` Pavel Fedin
2015-09-30 13:59 ` [Qemu-devel] [RFC PATCH 2/4] kernel: Add definitions for GICv3 attributes Pavel Fedin
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Pavel Fedin @ 2015-09-30 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Juan Quintela, Shlomo Pongratz, Shlomo Pongratz,
Amit Shah, Diana Craciun
Add state information to GICv3 object structure and implement
arm_gicv3_common_reset(). Also, add some functions for registers which are
not stored directly but simulated.
State information includes not only pure GICv3 data, but also some legacy
registers. This will be useful for implementing software emulation of GICv3
with v2 backwards compatilibity mode.
Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
hw/intc/arm_gicv3_common.c | 135 +++++++++++++++++++++++++++++++-
hw/intc/gicv3_internal.h | 152 +++++++++++++++++++++++++++++++++++++
include/hw/intc/arm_gicv3_common.h | 76 +++++++++++++++++++
3 files changed, 362 insertions(+), 1 deletion(-)
create mode 100644 hw/intc/gicv3_internal.h
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 032ece2..0818fb9 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -21,6 +21,7 @@
*/
#include "hw/intc/arm_gicv3_common.h"
+#include "gicv3_internal.h"
static void gicv3_pre_save(void *opaque)
{
@@ -88,6 +89,7 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
{
GICv3State *s = ARM_GICV3_COMMON(dev);
+ int i;
/* revision property is actually reserved and currently used only in order
* to keep the interface compatible with GICv2 code, avoiding extra
@@ -98,11 +100,142 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
error_setg(errp, "unsupported GIC revision %d", s->revision);
return;
}
+
+ if (s->num_irq > GICV3_MAXIRQ) {
+ error_setg(errp,
+ "requested %u interrupt lines exceeds GIC maximum %d",
+ s->num_irq, GICV3_MAXIRQ);
+ return;
+ }
+
+ for (i = 0; i < GICV3_MAXIRQ; i++) {
+ uint32_t mask_size = BITS_TO_LONGS(s->num_cpu);
+
+ s->irq_state[i].mask_size = mask_size;
+ s->irq_state[i].enabled = g_malloc(mask_size * sizeof(unsigned long));
+ s->irq_state[i].pending = g_malloc(mask_size * sizeof(unsigned long));
+ s->irq_state[i].active = g_malloc(mask_size * sizeof(unsigned long));
+ s->irq_state[i].level = g_malloc(mask_size * sizeof(unsigned long));
+ s->irq_state[i].group = g_malloc(mask_size * sizeof(unsigned long));
+ }
+
+ s->cpu = g_malloc(s->num_cpu * sizeof(GICv3CPUState));
}
static void arm_gicv3_common_reset(DeviceState *dev)
{
- /* TODO */
+ GICv3State *s = ARM_GICV3_COMMON(dev);
+ int i;
+
+ for (i = 0; i < s->num_cpu; i++) {
+ GICv3CPUState *c = &s->cpu[i];
+
+ c->cpu_enabled = false;
+ memset(c->priority1, 0, sizeof(c->priority1));
+ memset(c->sgi_pending, 0, sizeof(c->sgi_pending));
+
+ c->ctlr[0] = 0;
+ c->ctlr[1] = 0;
+ c->legacy_ctlr = 0;
+ c->priority_mask = 0;
+ c->bpr[0] = GIC_MIN_BPR0;
+ c->bpr[1] = GIC_MIN_BPR1;
+ memset(c->apr, 0, sizeof(c->apr));
+
+ c->current_pending = 1023;
+ c->running_irq = 1023;
+ c->running_priority = 0x100;
+ memset(c->last_active, 0, sizeof(c->last_active));
+ }
+
+ for (i = 0; i < GICV3_MAXIRQ; i++) {
+ uint32_t mask_size = s->irq_state[i].mask_size;
+
+ memset(s->irq_state[i].enabled, 0, mask_size * sizeof(unsigned long));
+ memset(s->irq_state[i].pending, 0, mask_size * sizeof(unsigned long));
+ memset(s->irq_state[i].active, 0, mask_size * sizeof(unsigned long));
+ memset(s->irq_state[i].level, 0, mask_size * sizeof(unsigned long));
+ memset(s->irq_state[i].group, 0, mask_size * sizeof(unsigned long));
+ s->irq_state[i].edge_trigger = false;
+ }
+
+ /* GIC-500 comment 'j' SGI are always enabled */
+ for (i = 0; i < GIC_NR_SGIS; i++) {
+ set_all_cpus(s, s->irq_state[i].enabled);
+ s->irq_state[i].edge_trigger = true;
+ }
+ /* By default all interrupts always target CPU #0 */
+ for (i = 0; i < GICV3_MAXIRQ; i++) {
+ s->irq_target[i] = 1;
+ }
+ memset(s->irq_route, 0, sizeof(s->irq_route));
+ memset(s->priority2, 0, sizeof(s->priority2));
+
+ /* With all configuration we don't support GICv2 backwards computability */
+ if (s->security_extn) {
+ /* GICv3 5.3.20 With two security So DS is RAZ/WI ARE_NS is RAO/WI
+ * and ARE_S is RAO/WI
+ */
+ s->ctlr = GICD_CTLR_ARE_S | GICD_CTLR_ARE_NS;
+ } else {
+ /* GICv3 5.3.20 With one security So DS is RAO/WI ARE is RAO/WI
+ */
+ s->ctlr = GICD_CTLR_DS | GICD_CTLR_ARE;
+ }
+ /* Workaround!
+ * Linux (drivers/irqchip/irq-gic-v3.c) is enabling only group one,
+ * in gic_cpu_sys_reg_init it calls gic_write_grpen1(1);
+ * but it doesn't conigure any interrupt to be in group one
+ */
+ for (i = 0; i < s->num_irq; i++) {
+ set_all_cpus(s, s->irq_state[i].group);
+ }
+}
+
+void set_irq_bit(GICv3State *s, unsigned long *mask, int irq, int cpu,
+ bool value)
+{
+ if (irq < GIC_INTERNAL) {
+ if (value) {
+ set_bit(cpu, mask);
+ } else {
+ clear_bit(cpu, mask);
+ }
+ } else {
+ if (value) {
+ set_all_cpus(s, mask);
+ } else {
+ clear_all_cpus(s, mask);
+ }
+ }
+}
+
+uint32_t gicv3_get_igrpen0(GICv3State *s, int cpuindex)
+{
+ GICv3CPUState *c = &s->cpu[cpuindex];
+
+ return extract32(c->legacy_ctlr, GICC_CTLR_EN_GRP0_SHIFT, 1);
+}
+
+void gicv3_set_igrpen0(GICv3State *s, int cpuindex, uint32_t val)
+{
+ GICv3CPUState *c = &s->cpu[cpuindex];
+
+ c->legacy_ctlr = deposit32(c->legacy_ctlr, GICC_CTLR_EN_GRP0_SHIFT, 1, val);
+}
+
+uint32_t gicv3_get_igrpen1(GICv3State *s, int cpuindex)
+{
+ GICv3CPUState *c = &s->cpu[cpuindex];
+
+ return extract32(c->legacy_ctlr, GICC_CTLR_EN_GRP1_SHIFT, 1);
+}
+
+void gicv3_set_igrpen1(GICv3State *s, int cpuindex, uint32_t val)
+{
+ GICv3CPUState *c = &s->cpu[cpuindex];
+
+ c->legacy_ctlr = deposit32(c->legacy_ctlr, GICC_CTLR_EN_GRP1_SHIFT, 1, val);
}
static Property arm_gicv3_common_properties[] = {
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
new file mode 100644
index 0000000..218260f
--- /dev/null
+++ b/hw/intc/gicv3_internal.h
@@ -0,0 +1,152 @@
+/*
+ * ARM GICv3 support - internal interfaces
+ *
+ * Copyright (c) 2012 Linaro Limited
+ * Copyright (c) 2015 Huawei.
+ * Written by Peter Maydell
+ * Adapted to GICv3 by Shlomo Pongratz and Pavel Fedin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_ARM_GICV3_INTERNAL_H
+#define QEMU_ARM_GICV3_INTERNAL_H
+
+#include "hw/intc/arm_gicv3_common.h"
+
+#define GIC_GET_PRIORITY(irq) (((irq) < GIC_INTERNAL) ? c->priority1[irq] : \
+ s->priority2[(irq) - GIC_INTERNAL])
+#define GIC_SET_PRIORITY(irq, pri) do { if ((irq) < GIC_INTERNAL) { \
+ c->priority1[(irq)] = (pri); } else { \
+ s->priority2[(irq) - GIC_INTERNAL] = \
+ (pri); } } while (0)
+
+static inline bool gicv3_test_pending(GICv3State *s, int irq, int cpu)
+{
+ /* Edge-triggered interrupts are marked pending on a rising edge, but
+ * level-triggered interrupts are either considered pending when the
+ * level is active or if software has explicitly written to
+ * GICD_ISPENDR to set the state pending.
+ */
+ return test_bit(cpu, s->irq_state[irq].pending) ||
+ (!s->irq_state[irq].edge_trigger &&
+ test_bit(cpu, s->irq_state[irq].level));
+}
+
+static inline void set_all_cpus(GICv3State *s, unsigned long *mask)
+{
+ int i;
+
+ for (i = 0; i < s->num_cpu; i++) {
+ set_bit(i, mask);
+ }
+}
+
+static inline void clear_all_cpus(GICv3State *s, unsigned long *mask)
+{
+ int i;
+
+ for (i = 0; i < s->num_cpu; i++) {
+ clear_bit(i, mask);
+ }
+}
+
+void set_irq_bit(GICv3State *s, unsigned long *mask, int irq, int cpu,
+ bool value);
+
+#define GICD_CTLR 0x0000
+#define GICD_TYPER 0x0004
+#define GICD_IIDR 0x0008
+#define GICD_STATUSR 0x0010
+#define GICD_SETSPI_NSR 0x0040
+#define GICD_CLRSPI_NSR 0x0048
+#define GICD_SETSPI_SR 0x0050
+#define GICD_CLRSPI_SR 0x0058
+#define GICD_SEIR 0x0068
+#define GICD_IGROUPR 0x0080
+#define GICD_ISENABLER 0x0100
+#define GICD_ICENABLER 0x0180
+#define GICD_ISPENDR 0x0200
+#define GICD_ICPENDR 0x0280
+#define GICD_ISACTIVER 0x0300
+#define GICD_ICACTIVER 0x0380
+#define GICD_IPRIORITYR 0x0400
+#define GICD_ITARGETSR 0x0800
+#define GICD_ICFGR 0x0C00
+#define GICD_CPENDSGIR 0x0F10
+#define GICD_SPENDSGIR 0x0F20
+#define GICD_IROUTER 0x6000
+#define GICD_PIDR2 0xFFE8
+
+/* GICD_CTLR fields */
+#define GICD_CTLR_EN_GRP0 (1U << 0)
+#define GICD_CTLR_EN_GRP1NS (1U << 1) /* GICv3 5.3.20 */
+#define GICD_CTLR_EN_GRP1S (1U << 2)
+#define GICD_CTLR_EN_GRP1_ALL (GICD_CTLR_EN_GRP1NS | GICD_CTLR_EN_GRP1S)
+#define GICD_CTLR_ARE (1U << 4)
+#define GICD_CTLR_ARE_S (1U << 4)
+#define GICD_CTLR_ARE_NS (1U << 5)
+#define GICD_CTLR_DS (1U << 6)
+#define GICD_CTLR_RWP (1U << 31)
+
+/*
+ * Redistributor frame offsets from RD_base
+ */
+#define GICR_SGI_OFFSET 0x10000
+
+/*
+ * Re-Distributor registers, offsets from RD_base
+ */
+#define GICR_CTLR GICD_CTLR
+#define GICR_IIDR 0x0004
+#define GICR_TYPER 0x0008
+#define GICR_STATUSR GICD_STATUSR
+#define GICR_WAKER 0x0014
+#define GICR_SETLPIR 0x0040
+#define GICR_CLRLPIR 0x0048
+#define GICR_SEIR GICD_SEIR
+#define GICR_PROPBASER 0x0070
+#define GICR_PENDBASER 0x0078
+#define GICR_INVLPIR 0x00A0
+#define GICR_INVALLR 0x00B0
+#define GICR_SYNCR 0x00C0
+#define GICR_MOVLPIR 0x0100
+#define GICR_MOVALLR 0x0110
+#define GICR_PIDR2 GICD_PIDR2
+
+#define GICR_WAKER_ProcessorSleep (1U << 1)
+#define GICR_WAKER_ChildrenAsleep (1U << 2)
+
+/*
+ * Simulated used system registers
+ */
+#define GICC_CTLR_EN_GRP0_SHIFT 0
+#define GICC_CTLR_EN_GRP0 (1U << GICC_CTLR_EN_GRP0_SHIFT)
+#define GICC_CTLR_EN_GRP1_SHIFT 1
+#define GICC_CTLR_EN_GRP1 (1U << GICC_CTLR_EN_GRP1_SHIFT)
+#define GICC_CTLR_ACK_CTL (1U << 2)
+#define GICC_CTLR_FIQ_EN (1U << 3)
+#define GICC_CTLR_CBPR (1U << 4) /* GICv1: SBPR */
+#define GICC_CTLR_EOIMODE (1U << 9)
+#define GICC_CTLR_EOIMODE_NS (1U << 10)
+
+#define ICC_CTLR_CBPR (1U << 0)
+#define ICC_CTLR_EOIMODE (1U << 1)
+#define ICC_CTLR_PMHE (1U << 6)
+
+#define ICC_PMR_PRIORITY_MASK 0xff
+#define ICC_BPR_BINARYPOINT_MASK 0x07
+#define ICC_IGRPEN_ENABLE 0x01
+
+#endif /* !QEMU_ARM_GIC_INTERNAL_H */
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index c2fd8da..b372566 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -26,6 +26,60 @@
#include "hw/sysbus.h"
#include "hw/intc/arm_gic_common.h"
+/*
+ * Maximum number of possible interrupts, determined by the GIC architecture.
+ * Note that this does not include LPIs. When implemented, these should be
+ * dealt with separately.
+ */
+#define GICV3_MAXIRQ 1020
+
+#define GIC_MIN_BPR0 0
+#define GIC_MIN_BPR1 (GIC_MIN_BPR0 + 1)
+
+struct gicv3_irq_state {
+ /* The enable bits are only banked for per-cpu interrupts. */
+ unsigned long *enabled;
+ unsigned long *pending;
+ unsigned long *active;
+ unsigned long *level;
+ unsigned long *group;
+ bool edge_trigger; /* true: edge-triggered, false: level-triggered */
+ uint32_t mask_size; /* Size of bitfields in long's, for migration */
+};
+
+typedef struct gicv3_irq_state gicv3_irq_state;
+
+struct GICv3CPUState {
+ /* Redistributor */
+ bool cpu_enabled; /* !GICR_WAKER_ProcessorSleep */
+ uint8_t priority1[GIC_INTERNAL]; /* GICR_IPRIORITYR */
+
+ /* CPU interface */
+ uint32_t ctlr[2]; /* ICC_CTLR_EL1, banked */
+ uint32_t priority_mask; /* ICC_PMR_EL1 */
+ uint32_t bpr[2];
+ uint32_t apr[4][2];
+
+ /* Legacy CPU interface */
+ uint32_t legacy_ctlr; /* GICC_CTLR */
+ /* For each SGI on the target CPU, we store bit mask
+ * indicating which source CPUs have made this SGI
+ * pending on the target CPU. These correspond to
+ * the bytes in the GIC_SPENDSGIR* registers as
+ * read by the target CPU.
+ */
+ uint64_t sgi_pending[GIC_NR_SGIS];
+
+ /* Internal state */
+
+ uint16_t current_pending;
+ uint16_t running_irq;
+ uint16_t running_priority;
+ uint16_t last_active[GICV3_MAXIRQ];
+};
+
+typedef struct GICv3CPUState GICv3CPUState;
+
typedef struct GICv3State {
/*< private >*/
SysBusDevice parent_obj;
@@ -43,6 +97,22 @@ typedef struct GICv3State {
bool security_extn;
int dev_fd; /* kvm device fd if backed by kvm vgic support */
+
+ /* Distributor */
+
+ /* GICD_CTLR; for a GIC with the security extensions the NS banked version
+ * of this register is just an alias of bit 1 of the S banked version.
+ */
+ uint32_t ctlr;
+
+ gicv3_irq_state irq_state[GICV3_MAXIRQ];
+ uint64_t irq_route[GICV3_MAXIRQ - GIC_INTERNAL]; /* GICD_IROUTER */
+ uint8_t priority2[GICV3_MAXIRQ - GIC_INTERNAL];
+
+ /* Legacy distributor */
+ uint64_t irq_target[GICV3_MAXIRQ];
+
+ GICv3CPUState *cpu;
} GICv3State;
#define TYPE_ARM_GICV3_COMMON "arm-gicv3-common"
@@ -65,4 +135,10 @@ typedef struct ARMGICv3CommonClass {
void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
const MemoryRegionOps *ops);
+/* Accessors for simulated system registers */
+uint32_t gicv3_get_igrpen0(GICv3State *s, int cpuindex);
+void gicv3_set_igrpen0(GICv3State *s, int cpuindex, uint32_t val);
+uint32_t gicv3_get_igrpen1(GICv3State *s, int cpuindex);
+void gicv3_set_igrpen1(GICv3State *s, int cpuindex, uint32_t val);
+
#endif
--
2.4.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [RFC PATCH 2/4] kernel: Add definitions for GICv3 attributes
2015-09-30 13:59 [Qemu-devel] [RFC PATCH 0/4] GICv3 live migration support Pavel Fedin
2015-09-30 13:59 ` [Qemu-devel] [RFC PATCH 1/4] hw/intc/arm_gicv3_common: Add state information Pavel Fedin
@ 2015-09-30 13:59 ` Pavel Fedin
2015-09-30 13:59 ` [Qemu-devel] [RFC PATCH 3/4] hw/intc/arm_gicv3_kvm: Implement get/put functions Pavel Fedin
2015-09-30 13:59 ` [Qemu-devel] [RFC PATCH 4/4] hw/intc/arm_gicv3_common: Add vmstate descriptors Pavel Fedin
3 siblings, 0 replies; 5+ messages in thread
From: Pavel Fedin @ 2015-09-30 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Juan Quintela, Shlomo Pongratz, Shlomo Pongratz,
Amit Shah, Diana Craciun
This temporary patch adds kernel API definitions. Use proper header update
procedure after these features are released.
Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
| 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
--git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
index c8abf25..2f8e86d 100644
--- a/linux-headers/asm-arm64/kvm.h
+++ b/linux-headers/asm-arm64/kvm.h
@@ -163,13 +163,21 @@ struct kvm_arch_memory_slot {
#define KVM_DEV_ARM_VGIC_GRP_ADDR 0
#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2
+#define KVM_DEV_ARM_VGIC_64BIT (1ULL << 63)
#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32
-#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
+#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xfffffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0
#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
+#define KVM_DEV_ARM_VGIC_REG_MASK (KVM_REG_SIZE_MASK | \
+ KVM_REG_ARM64_SYSREG_OP0_MASK | \
+ KVM_REG_ARM64_SYSREG_OP1_MASK | \
+ KVM_REG_ARM64_SYSREG_CRN_MASK | \
+ KVM_REG_ARM64_SYSREG_CRM_MASK | \
+ KVM_REG_ARM64_SYSREG_OP2_MASK)
#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3
#define KVM_DEV_ARM_VGIC_GRP_CTRL 4
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
+#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
/* KVM_IRQ_LINE irq field index values */
#define KVM_ARM_IRQ_TYPE_SHIFT 24
--
2.4.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [RFC PATCH 3/4] hw/intc/arm_gicv3_kvm: Implement get/put functions
2015-09-30 13:59 [Qemu-devel] [RFC PATCH 0/4] GICv3 live migration support Pavel Fedin
2015-09-30 13:59 ` [Qemu-devel] [RFC PATCH 1/4] hw/intc/arm_gicv3_common: Add state information Pavel Fedin
2015-09-30 13:59 ` [Qemu-devel] [RFC PATCH 2/4] kernel: Add definitions for GICv3 attributes Pavel Fedin
@ 2015-09-30 13:59 ` Pavel Fedin
2015-09-30 13:59 ` [Qemu-devel] [RFC PATCH 4/4] hw/intc/arm_gicv3_common: Add vmstate descriptors Pavel Fedin
3 siblings, 0 replies; 5+ messages in thread
From: Pavel Fedin @ 2015-09-30 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Juan Quintela, Shlomo Pongratz, Shlomo Pongratz,
Amit Shah, Diana Craciun
This actually implements pre_save and post_load methods for in-kernel
vGICv3.
Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
hw/intc/arm_gicv3_kvm.c | 391 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 387 insertions(+), 4 deletions(-)
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index b48f78f..5f268a3 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -21,8 +21,10 @@
#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"
#ifdef DEBUG_GICV3_KVM
@@ -41,6 +43,15 @@
#define KVM_ARM_GICV3_GET_CLASS(obj) \
OBJECT_GET_CLASS(KVMARMGICv3Class, (obj), TYPE_KVM_ARM_GICV3)
+#define ICC_PMR_EL1 ARM64_SYS_REG(0b11, 0b000, 0b0100, 0b0110, 0b000)
+#define ICC_BPR0_EL1 ARM64_SYS_REG(0b11, 0b000, 0b1100, 0b1000, 0b011)
+#define ICC_APR0_EL1(n) ARM64_SYS_REG(0b11, 0b000, 0b1100, 0b1000, 0b100 | n)
+#define ICC_APR1_EL1(n) ARM64_SYS_REG(0b11, 0b000, 0b1100, 0b1001, 0b000 | n)
+#define ICC_BPR1_EL1 ARM64_SYS_REG(0b11, 0b000, 0b1100, 0b1100, 0b011)
+#define ICC_CTLR_EL1 ARM64_SYS_REG(0b11, 0b000, 0b1100, 0b1100, 0b100)
+#define ICC_IGRPEN0_EL1 ARM64_SYS_REG(0b11, 0b000, 0b1100, 0b1100, 0b110)
+#define ICC_IGRPEN1_EL1 ARM64_SYS_REG(0b11, 0b000, 0b1100, 0b1100, 0b111)
+
typedef struct KVMARMGICv3Class {
ARMGICv3CommonClass parent_class;
DeviceRealize parent_realize;
@@ -54,16 +65,382 @@ 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(offset, cpu) \
+ ((((uint64_t)(cpu) << KVM_DEV_ARM_VGIC_CPUID_SHIFT) & \
+ KVM_DEV_ARM_VGIC_CPUID_MASK) | \
+ (((uint64_t)(offset) << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) & \
+ KVM_DEV_ARM_VGIC_OFFSET_MASK))
+
+static inline void kvm_gicd_access(GICv3State *s, int offset, int cpu,
+ uint32_t *val, bool write)
+{
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
+ KVM_VGIC_ATTR(offset, cpu), 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, cpu), 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_REGS,
+ ((((uint64_t)(cpu) << KVM_DEV_ARM_VGIC_CPUID_SHIFT) &
+ KVM_DEV_ARM_VGIC_CPUID_MASK) | reg), val, write);
+}
+
+/*
+ * Translate from the in-kernel field for an IRQ value to/from the qemu
+ * representation.
+ */
+typedef void (*vgic_translate_fn)(GICv3State *s, int irq, int cpu,
+ uint32_t *field, bool to_kernel);
+
+/* synthetic translate function used for clear/set registers to completely
+ * clear a setting using a clear-register before setting the remaining bits
+ * using a set-register */
+static void translate_clear(GICv3State *s, int irq, int cpu,
+ uint32_t *field, bool to_kernel)
+{
+ if (to_kernel) {
+ *field = ~0;
+ } else {
+ /* does not make sense: qemu model doesn't use set/clear regs */
+ abort();
+ }
+}
+
+static void translate_enabled(GICv3State *s, int irq, int cpu,
+ uint32_t *field, bool to_kernel)
+{
+ if (to_kernel) {
+ *field = test_bit(cpu, s->irq_state[irq].enabled);
+ } else {
+ set_irq_bit(s, s->irq_state[irq].enabled, irq, cpu, *field);
+ }
+}
+
+static void translate_group(GICv3State *s, int irq, int cpu,
+ uint32_t *field, bool to_kernel)
+{
+ if (to_kernel) {
+ *field = test_bit(cpu, s->irq_state[irq].group);
+ } else {
+ set_irq_bit(s, s->irq_state[irq].group, irq, cpu, *field);
+ }
+}
+
+static void translate_trigger(GICv3State *s, int irq, int cpu,
+ uint32_t *field, bool to_kernel)
+{
+ if (to_kernel) {
+ *field = s->irq_state[irq].edge_trigger ? 2 : 0;
+ } else {
+ s->irq_state[irq].edge_trigger = (*field & 2) ? true : false;
+ }
+}
+
+static void translate_pending(GICv3State *s, int irq, int cpu,
+ uint32_t *field, bool to_kernel)
+{
+ if (to_kernel) {
+ *field = gicv3_test_pending(s, irq, cpu);
+ } else {
+ set_irq_bit(s, s->irq_state[irq].pending, irq, cpu, *field);
+ /* TODO: Capture if level-line is held high in the kernel */
+ }
+}
+
+static void translate_active(GICv3State *s, int irq, int cpu,
+ uint32_t *field, bool to_kernel)
+{
+ if (to_kernel) {
+ *field = test_bit(cpu, s->irq_state[irq].active);
+ } else {
+ set_irq_bit(s, s->irq_state[irq].active, irq, cpu, *field);
+ }
+}
+
+static void translate_priority(GICv3State *s, int irq, int cpu,
+ uint32_t *field, bool to_kernel)
+{
+ GICv3CPUState *c = &s->cpu[cpu];
+
+ if (to_kernel) {
+ *field = GIC_GET_PRIORITY(irq);
+ } else {
+ GIC_SET_PRIORITY(irq, *field);
+ }
+}
+
+#define for_each_irq_reg(_irq, _max, _field_width) \
+ for (_irq = 0; _irq < _max; _irq += (32 / _field_width))
+
+/* Read a register group from the kernel VGIC */
+static void kvm_dist_get(GICv3State *s, uint32_t offset, int width,
+ vgic_translate_fn translate_fn)
+{
+ uint32_t reg;
+ int j;
+ int irq, cpu, maxcpu;
+ uint32_t field;
+ int regsz = 32 / width; /* irqs per kernel register */
+
+ for_each_irq_reg(irq, s->num_irq, width) {
+ maxcpu = irq < GIC_INTERNAL ? s->num_cpu : 1;
+ for (cpu = 0; cpu < maxcpu; cpu++) {
+ /* In GICv3 SGI/PPIs are stored in redistributor
+ * Offsets in SGI area are the same as in distributor
+ */
+ if (irq < GIC_INTERNAL) {
+ kvm_gicr_access(s, offset + GICR_SGI_OFFSET, cpu, ®, false);
+ } else {
+ kvm_gicd_access(s, offset, cpu, ®, false);
+ }
+ for (j = 0; j < regsz; j++) {
+ field = extract32(reg, j * width, width);
+ translate_fn(s, irq + j, cpu, &field, false);
+ }
+ }
+ offset += 4;
+ }
+}
+
+/* Write a register group to the kernel VGIC */
+static void kvm_dist_put(GICv3State *s, uint32_t offset, int width,
+ vgic_translate_fn translate_fn)
+{
+ uint32_t reg;
+ int j;
+ int irq, cpu, maxcpu;
+ uint32_t field;
+ int regsz = 32 / width; /* irqs per kernel register */
+
+ for_each_irq_reg(irq, s->num_irq, width) {
+ maxcpu = irq < GIC_INTERNAL ? s->num_cpu : 1;
+ for (cpu = 0; cpu < maxcpu; cpu++) {
+ reg = 0;
+ for (j = 0; j < regsz; j++) {
+ translate_fn(s, irq + j, cpu, &field, true);
+ reg = deposit32(reg, j * width, width, field);
+ }
+ /* In GICv3 SGI/PPIs are stored in redistributor
+ * Offsets in SGI area are the same as in distributor
+ */
+ if (irq < GIC_INTERNAL) {
+ kvm_gicr_access(s, offset + GICR_SGI_OFFSET, cpu, ®, true);
+ } else {
+ kvm_gicd_access(s, offset, cpu, ®, true);
+ }
+ }
+ offset += 4;
+ }
+}
+
+static void kvm_arm_gicv3_check(GICv3State *s)
+{
+ uint32_t reg, num_irq;
+
+ /* Sanity checking s->num_irq */
+ kvm_gicd_access(s, GICD_TYPER, 0, ®, false);
+ num_irq = ((reg & 0x1f) + 1) * 32;
+
+ if (num_irq < s->num_irq) {
+ error_report("Model requests %u IRQs, but kernel supports max %u\n",
+ s->num_irq, num_irq);
+ abort();
+ }
+
+ /* TODO: Consider checking compatibility with the IIDR ? */
+}
+
static void kvm_arm_gicv3_put(GICv3State *s)
{
- /* TODO */
- DPRINTF("Cannot put kernel gic state, no kernel interface\n");
+ int ncpu, i;
+
+ kvm_arm_gicv3_check(s);
+
+ /*****************************************************************
+ * (Re)distributor State
+ */
+
+ kvm_gicd_access(s, GICD_CTLR, 0, &s->ctlr, true);
+
+ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+ GICv3CPUState *c = &s->cpu[ncpu];
+ uint32_t reg = c->cpu_enabled ? 0 : GICR_WAKER_ProcessorSleep;
+
+ kvm_gicr_access(s, GICR_WAKER, ncpu, ®, true);
+ }
+
+ /* irq_state[n].enabled -> GICD_ISENABLERn */
+ kvm_dist_put(s, GICD_ICENABLER, 1, translate_clear);
+ kvm_dist_put(s, GICD_ISENABLER, 1, translate_enabled);
+
+ /* irq_state[n].group -> GICD_IGROUPRn */
+ kvm_dist_put(s, GICD_IGROUPR, 1, translate_group);
+
+ /* Restore targets before pending to ensure the pending state is set on
+ * the appropriate CPU interfaces in the kernel */
+
+ /* s->route[irq] -> GICD_IROUTERn */
+ for (i = GIC_INTERNAL; i < s->num_irq; i++) {
+ uint64_t reg;
+ uint32_t offset = GICD_IROUTER + (sizeof(reg) * i);
+
+ reg = s->irq_route[i - GIC_INTERNAL];
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
+ KVM_DEV_ARM_VGIC_64BIT | KVM_VGIC_ATTR(offset, 0),
+ ®, true);
+ }
+
+ /* irq_state[n].trigger -> GICD_ICFGRn
+ * (restore configuration registers before pending IRQs so we treat
+ * level/edge correctly) */
+ kvm_dist_put(s, GICD_ICFGR, 2, translate_trigger);
+
+ /* irq_state[n].pending + irq_state[n].level -> GICD_ISPENDRn */
+ kvm_dist_put(s, GICD_ICPENDR, 1, translate_clear);
+ kvm_dist_put(s, GICD_ISPENDR, 1, translate_pending);
+
+ /* irq_state[n].active -> GICD_ISACTIVERn */
+ kvm_dist_put(s, GICD_ICACTIVER, 1, translate_clear);
+ kvm_dist_put(s, GICD_ISACTIVER, 1, translate_active);
+
+ /* s->priorityX[irq] -> ICD_IPRIORITYRn */
+ kvm_dist_put(s, GICD_IPRIORITYR, 8, translate_priority);
+
+ /*****************************************************************
+ * CPU Interface(s) State
+ */
+
+ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+ GICv3CPUState *c = &s->cpu[ncpu];
+ uint64_t reg;
+
+ reg = c->ctlr[1] & (ICC_CTLR_CBPR | ICC_CTLR_EOIMODE | ICC_CTLR_PMHE);
+ kvm_gicc_access(s, ICC_CTLR_EL1, ncpu, ®, true);
+
+ reg = gicv3_get_igrpen0(s, ncpu);
+ kvm_gicc_access(s, ICC_IGRPEN0_EL1, ncpu, ®, true);
+
+ reg = gicv3_get_igrpen1(s, ncpu);
+ kvm_gicc_access(s, ICC_IGRPEN1_EL1, ncpu, ®, true);
+
+ reg = c->priority_mask;
+ kvm_gicc_access(s, ICC_PMR_EL1, ncpu, ®, true);
+
+ reg = c->bpr[0];
+ kvm_gicc_access(s, ICC_BPR0_EL1, ncpu, ®, true);
+
+ reg = c->bpr[1];
+ kvm_gicc_access(s, ICC_BPR1_EL1, ncpu, ®, true);
+
+ for (i = 0; i < 4; i++) {
+ reg = c->apr[i][0];
+ kvm_gicc_access(s, ICC_APR0_EL1(i), ncpu, ®, true);
+ }
+
+ for (i = 0; i < 4; i++) {
+ reg = c->apr[i][1];
+ kvm_gicc_access(s, ICC_APR1_EL1(i), ncpu, ®, true);
+ }
+ }
}
static void kvm_arm_gicv3_get(GICv3State *s)
{
- /* TODO */
- DPRINTF("Cannot get kernel gic state, no kernel interface\n");
+ int ncpu, i;
+
+ kvm_arm_gicv3_check(s);
+
+ /*****************************************************************
+ * (Re)distributor State
+ */
+
+ /* GICD_CTLR -> s->ctlr */
+ kvm_gicd_access(s, GICD_CTLR, 0, &s->ctlr, false);
+
+ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+ GICv3CPUState *c = &s->cpu[ncpu];
+ uint32_t reg;
+
+ kvm_gicr_access(s, GICR_WAKER, ncpu, ®, false);
+ c->cpu_enabled = !(reg & GICR_WAKER_ProcessorSleep);
+ }
+
+ /* GICD_IIDR -> ? */
+ /* kvm_gicd_access(s, GICD_IIDR, 0, ®, false); */
+
+ /* GICD_IGROUPRn -> irq_state[n].group */
+ kvm_dist_get(s, GICD_IGROUPR, 1, translate_group);
+
+ /* GICD_ISENABLERn -> irq_state[n].enabled */
+ kvm_dist_get(s, GICD_ISENABLER, 1, translate_enabled);
+
+ /* GICD_ISPENDRn -> irq_state[n].pending + irq_state[n].level */
+ kvm_dist_get(s, GICD_ISPENDR, 1, translate_pending);
+
+ /* GICD_ISACTIVERn -> irq_state[n].active */
+ kvm_dist_get(s, GICD_ISACTIVER, 1, translate_active);
+
+ /* GICD_ICFRn -> irq_state[n].trigger */
+ kvm_dist_get(s, GICD_ICFGR, 2, translate_trigger);
+
+ /* GICD_IPRIORITYRn -> s->priorityX[irq] */
+ kvm_dist_get(s, GICD_IPRIORITYR, 8, translate_priority);
+
+ /* GICD_IROUTERn -> s->route[irq] */
+ for (i = GIC_INTERNAL; i < s->num_irq; i++) {
+ uint64_t reg;
+ uint32_t offset = GICD_IROUTER + (sizeof(reg) * i);
+
+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
+ KVM_DEV_ARM_VGIC_64BIT | KVM_VGIC_ATTR(offset, 0),
+ ®, false);
+ s->irq_route[i - GIC_INTERNAL] = reg;
+ }
+
+ /*****************************************************************
+ * CPU Interface(s) State
+ */
+
+ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+ GICv3CPUState *c = &s->cpu[ncpu];
+ uint64_t reg;
+
+ kvm_gicc_access(s, ICC_CTLR_EL1, ncpu, ®, false);
+ c->ctlr[1] = reg & (ICC_CTLR_CBPR | ICC_CTLR_EOIMODE | ICC_CTLR_PMHE);
+
+ kvm_gicc_access(s, ICC_IGRPEN0_EL1, ncpu, ®, false);
+ gicv3_set_igrpen0(s, ncpu, reg);
+
+ kvm_gicc_access(s, ICC_IGRPEN1_EL1, ncpu, ®, false);
+ gicv3_set_igrpen1(s, ncpu, reg);
+
+ kvm_gicc_access(s, ICC_PMR_EL1, ncpu, ®, false);
+ c->priority_mask = reg & ICC_PMR_PRIORITY_MASK;
+
+ kvm_gicc_access(s, ICC_BPR0_EL1, ncpu, ®, false);
+ c->bpr[0] = reg & ICC_BPR_BINARYPOINT_MASK;
+
+ kvm_gicc_access(s, ICC_BPR1_EL1, ncpu, ®, false);
+ c->bpr[1] = reg & ICC_BPR_BINARYPOINT_MASK;
+
+ for (i = 0; i < 4; i++) {
+ kvm_gicc_access(s, ICC_APR0_EL1(i), ncpu, ®, false);
+ c->apr[i][0] = reg;
+ }
+
+ for (i = 0; i < 4; i++) {
+ kvm_gicc_access(s, ICC_APR1_EL1(i), ncpu, ®, false);
+ c->apr[i][1] = reg;
+ }
+ }
}
static void kvm_arm_gicv3_reset(DeviceState *dev)
@@ -74,6 +451,12 @@ static void kvm_arm_gicv3_reset(DeviceState *dev)
DPRINTF("Reset\n");
kgc->parent_reset(dev);
+
+ if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, 0)) {
+ DPRINTF("Cannot put kernel gic state, no kernel interface\n");
+ return;
+ }
+
kvm_arm_gicv3_put(s);
}
--
2.4.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [RFC PATCH 4/4] hw/intc/arm_gicv3_common: Add vmstate descriptors
2015-09-30 13:59 [Qemu-devel] [RFC PATCH 0/4] GICv3 live migration support Pavel Fedin
` (2 preceding siblings ...)
2015-09-30 13:59 ` [Qemu-devel] [RFC PATCH 3/4] hw/intc/arm_gicv3_kvm: Implement get/put functions Pavel Fedin
@ 2015-09-30 13:59 ` Pavel Fedin
3 siblings, 0 replies; 5+ messages in thread
From: Pavel Fedin @ 2015-09-30 13:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Juan Quintela, Shlomo Pongratz, Shlomo Pongratz,
Amit Shah, Diana Craciun
Add state structure descriptors and actually enable live migration.
Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
hw/intc/arm_gicv3_common.c | 64 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 63 insertions(+), 1 deletion(-)
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 0818fb9..71fd9e4 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -44,11 +44,73 @@ static int gicv3_post_load(void *opaque, int version_id)
return 0;
}
+/* Temporary hack */
+#if __SIZEOF_LONG__ == 8
+#define vmstate_info_ulong vmstate_info_uint64
+#else
+#define vmstate_info_ulong vmstate_info_uint32
+#endif
+
+static const VMStateDescription vmstate_gicv3_irq_state = {
+ .name = "arm_gicv3_irq_state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_VARRAY_UINT32(enabled, gicv3_irq_state, mask_size, 1,
+ vmstate_info_ulong, unsigned long),
+ VMSTATE_VARRAY_UINT32(pending, gicv3_irq_state, mask_size, 1,
+ vmstate_info_ulong, unsigned long),
+ VMSTATE_VARRAY_UINT32(active, gicv3_irq_state, mask_size, 1,
+ vmstate_info_ulong, unsigned long),
+ VMSTATE_VARRAY_UINT32(level, gicv3_irq_state, mask_size, 1,
+ vmstate_info_ulong, unsigned long),
+ VMSTATE_VARRAY_UINT32(group, gicv3_irq_state, mask_size, 1,
+ vmstate_info_ulong, unsigned long),
+ VMSTATE_BOOL(edge_trigger, gicv3_irq_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_gicv3_cpu = {
+ .name = "arm_gicv3_cpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(cpu_enabled, GICv3CPUState),
+ VMSTATE_UINT8_ARRAY(priority1, GICv3CPUState, GIC_INTERNAL),
+ VMSTATE_UINT64_ARRAY(sgi_pending, GICv3CPUState, GIC_NR_SGIS),
+ VMSTATE_UINT32_ARRAY(ctlr, GICv3CPUState, 2),
+ VMSTATE_UINT32(priority_mask, GICv3CPUState),
+ VMSTATE_UINT32_ARRAY(bpr, GICv3CPUState, 2),
+ VMSTATE_UINT32_2DARRAY(apr, GICv3CPUState, 4, 2),
+ VMSTATE_UINT32(legacy_ctlr, GICv3CPUState),
+ VMSTATE_UINT16(current_pending, GICv3CPUState),
+ VMSTATE_UINT16(running_irq, GICv3CPUState),
+ VMSTATE_UINT16(running_priority, GICv3CPUState),
+ VMSTATE_UINT16_ARRAY(last_active, GICv3CPUState, GICV3_MAXIRQ),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_gicv3 = {
.name = "arm_gicv3",
- .unmigratable = 1,
+ .version_id = 1,
+ .minimum_version_id = 1,
.pre_save = gicv3_pre_save,
.post_load = gicv3_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(ctlr, GICv3State),
+ VMSTATE_STRUCT_ARRAY(irq_state, GICv3State, GICV3_MAXIRQ, 1,
+ vmstate_gicv3_irq_state, gicv3_irq_state),
+ VMSTATE_UINT64_ARRAY(irq_route, GICv3State,
+ GICV3_MAXIRQ - GIC_INTERNAL),
+ VMSTATE_UINT8_ARRAY(priority2, GICv3State,
+ GICV3_MAXIRQ - GIC_INTERNAL),
+ VMSTATE_UINT64_ARRAY(irq_target, GICv3State, GICV3_MAXIRQ),
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, GICv3State, num_cpu,
+ vmstate_gicv3_cpu, GICv3CPUState),
+ VMSTATE_END_OF_LIST()
+ }
};
void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
--
2.4.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2015-09-30 14:00 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-30 13:59 [Qemu-devel] [RFC PATCH 0/4] GICv3 live migration support Pavel Fedin
2015-09-30 13:59 ` [Qemu-devel] [RFC PATCH 1/4] hw/intc/arm_gicv3_common: Add state information Pavel Fedin
2015-09-30 13:59 ` [Qemu-devel] [RFC PATCH 2/4] kernel: Add definitions for GICv3 attributes Pavel Fedin
2015-09-30 13:59 ` [Qemu-devel] [RFC PATCH 3/4] hw/intc/arm_gicv3_kvm: Implement get/put functions Pavel Fedin
2015-09-30 13:59 ` [Qemu-devel] [RFC PATCH 4/4] hw/intc/arm_gicv3_common: Add vmstate descriptors Pavel Fedin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).