Commit a0675c25 authored by Andre Przywara's avatar Andre Przywara Committed by Christoffer Dall

arm/arm64: KVM: add virtual GICv3 distributor emulation

With everything separated and prepared, we implement a model of a
GICv3 distributor and redistributors by using the existing framework
to provide handler functions for each register group.

Currently we limit the emulation to a model enforcing a single
security state, with SRE==1 (forcing system register access) and
ARE==1 (allowing more than 8 VCPUs).

We share some of the functions provided for GICv2 emulation, but take
the different ways of addressing (v)CPUs into account.
Save and restore is currently not implemented.

Similar to the split-off of the GICv2 specific code, the new emulation
code goes into a new file (vgic-v3-emul.c).
Signed-off-by: default avatarAndre Przywara <andre.przywara@arm.com>
Signed-off-by: default avatarChristoffer Dall <christoffer.dall@linaro.org>
parent 9fedf146
...@@ -24,5 +24,6 @@ kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o ...@@ -24,5 +24,6 @@ kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o
kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2-emul.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2-emul.o
kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v2-switch.o kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v2-switch.o
kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v3.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v3.o
kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v3-emul.o
kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v3-switch.o kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v3-switch.o
kvm-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o kvm-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
...@@ -162,7 +162,11 @@ struct vgic_dist { ...@@ -162,7 +162,11 @@ struct vgic_dist {
/* Distributor and vcpu interface mapping in the guest */ /* Distributor and vcpu interface mapping in the guest */
phys_addr_t vgic_dist_base; phys_addr_t vgic_dist_base;
phys_addr_t vgic_cpu_base; /* GICv2 and GICv3 use different mapped register blocks */
union {
phys_addr_t vgic_cpu_base;
phys_addr_t vgic_redist_base;
};
/* Distributor enabled */ /* Distributor enabled */
u32 enabled; u32 enabled;
...@@ -224,6 +228,9 @@ struct vgic_dist { ...@@ -224,6 +228,9 @@ struct vgic_dist {
*/ */
struct vgic_bitmap *irq_spi_target; struct vgic_bitmap *irq_spi_target;
/* Target MPIDR for each IRQ (needed for GICv3 IROUTERn) only */
u32 *irq_spi_mpidr;
/* Bitmap indicating which CPU has something pending */ /* Bitmap indicating which CPU has something pending */
unsigned long *irq_pending_on_cpu; unsigned long *irq_pending_on_cpu;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define GICD_SETSPI_SR 0x0050 #define GICD_SETSPI_SR 0x0050
#define GICD_CLRSPI_SR 0x0058 #define GICD_CLRSPI_SR 0x0058
#define GICD_SEIR 0x0068 #define GICD_SEIR 0x0068
#define GICD_IGROUPR 0x0080
#define GICD_ISENABLER 0x0100 #define GICD_ISENABLER 0x0100
#define GICD_ICENABLER 0x0180 #define GICD_ICENABLER 0x0180
#define GICD_ISPENDR 0x0200 #define GICD_ISPENDR 0x0200
...@@ -41,14 +42,37 @@ ...@@ -41,14 +42,37 @@
#define GICD_ICACTIVER 0x0380 #define GICD_ICACTIVER 0x0380
#define GICD_IPRIORITYR 0x0400 #define GICD_IPRIORITYR 0x0400
#define GICD_ICFGR 0x0C00 #define GICD_ICFGR 0x0C00
#define GICD_IGRPMODR 0x0D00
#define GICD_NSACR 0x0E00
#define GICD_IROUTER 0x6000 #define GICD_IROUTER 0x6000
#define GICD_IDREGS 0xFFD0
#define GICD_PIDR2 0xFFE8 #define GICD_PIDR2 0xFFE8
/*
* Those registers are actually from GICv2, but the spec demands that they
* are implemented as RES0 if ARE is 1 (which we do in KVM's emulated GICv3).
*/
#define GICD_ITARGETSR 0x0800
#define GICD_SGIR 0x0F00
#define GICD_CPENDSGIR 0x0F10
#define GICD_SPENDSGIR 0x0F20
#define GICD_CTLR_RWP (1U << 31) #define GICD_CTLR_RWP (1U << 31)
#define GICD_CTLR_DS (1U << 6)
#define GICD_CTLR_ARE_NS (1U << 4) #define GICD_CTLR_ARE_NS (1U << 4)
#define GICD_CTLR_ENABLE_G1A (1U << 1) #define GICD_CTLR_ENABLE_G1A (1U << 1)
#define GICD_CTLR_ENABLE_G1 (1U << 0) #define GICD_CTLR_ENABLE_G1 (1U << 0)
/*
* In systems with a single security state (what we emulate in KVM)
* the meaning of the interrupt group enable bits is slightly different
*/
#define GICD_CTLR_ENABLE_SS_G1 (1U << 1)
#define GICD_CTLR_ENABLE_SS_G0 (1U << 0)
#define GICD_TYPER_LPIS (1U << 17)
#define GICD_TYPER_MBIS (1U << 16)
#define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1) #define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1)
#define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32) #define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32)
#define GICD_TYPER_LPIS (1U << 17) #define GICD_TYPER_LPIS (1U << 17)
...@@ -60,6 +84,8 @@ ...@@ -60,6 +84,8 @@
#define GIC_PIDR2_ARCH_GICv3 0x30 #define GIC_PIDR2_ARCH_GICv3 0x30
#define GIC_PIDR2_ARCH_GICv4 0x40 #define GIC_PIDR2_ARCH_GICv4 0x40
#define GIC_V3_DIST_SIZE 0x10000
/* /*
* Re-Distributor registers, offsets from RD_base * Re-Distributor registers, offsets from RD_base
*/ */
...@@ -78,6 +104,7 @@ ...@@ -78,6 +104,7 @@
#define GICR_SYNCR 0x00C0 #define GICR_SYNCR 0x00C0
#define GICR_MOVLPIR 0x0100 #define GICR_MOVLPIR 0x0100
#define GICR_MOVALLR 0x0110 #define GICR_MOVALLR 0x0110
#define GICR_IDREGS GICD_IDREGS
#define GICR_PIDR2 GICD_PIDR2 #define GICR_PIDR2 GICD_PIDR2
#define GICR_CTLR_ENABLE_LPIS (1UL << 0) #define GICR_CTLR_ENABLE_LPIS (1UL << 0)
...@@ -104,6 +131,7 @@ ...@@ -104,6 +131,7 @@
/* /*
* Re-Distributor registers, offsets from SGI_base * Re-Distributor registers, offsets from SGI_base
*/ */
#define GICR_IGROUPR0 GICD_IGROUPR
#define GICR_ISENABLER0 GICD_ISENABLER #define GICR_ISENABLER0 GICD_ISENABLER
#define GICR_ICENABLER0 GICD_ICENABLER #define GICR_ICENABLER0 GICD_ICENABLER
#define GICR_ISPENDR0 GICD_ISPENDR #define GICR_ISPENDR0 GICD_ISPENDR
...@@ -112,11 +140,15 @@ ...@@ -112,11 +140,15 @@
#define GICR_ICACTIVER0 GICD_ICACTIVER #define GICR_ICACTIVER0 GICD_ICACTIVER
#define GICR_IPRIORITYR0 GICD_IPRIORITYR #define GICR_IPRIORITYR0 GICD_IPRIORITYR
#define GICR_ICFGR0 GICD_ICFGR #define GICR_ICFGR0 GICD_ICFGR
#define GICR_IGRPMODR0 GICD_IGRPMODR
#define GICR_NSACR GICD_NSACR
#define GICR_TYPER_PLPIS (1U << 0) #define GICR_TYPER_PLPIS (1U << 0)
#define GICR_TYPER_VLPIS (1U << 1) #define GICR_TYPER_VLPIS (1U << 1)
#define GICR_TYPER_LAST (1U << 4) #define GICR_TYPER_LAST (1U << 4)
#define GIC_V3_REDIST_SIZE 0x20000
#define LPI_PROP_GROUP1 (1 << 1) #define LPI_PROP_GROUP1 (1 << 1)
#define LPI_PROP_ENABLED (1 << 0) #define LPI_PROP_ENABLED (1 << 0)
......
...@@ -1052,6 +1052,7 @@ void kvm_unregister_device_ops(u32 type); ...@@ -1052,6 +1052,7 @@ void kvm_unregister_device_ops(u32 type);
extern struct kvm_device_ops kvm_mpic_ops; extern struct kvm_device_ops kvm_mpic_ops;
extern struct kvm_device_ops kvm_xics_ops; extern struct kvm_device_ops kvm_xics_ops;
extern struct kvm_device_ops kvm_arm_vgic_v2_ops; extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
......
...@@ -952,6 +952,8 @@ enum kvm_device_type { ...@@ -952,6 +952,8 @@ enum kvm_device_type {
#define KVM_DEV_TYPE_ARM_VGIC_V2 KVM_DEV_TYPE_ARM_VGIC_V2 #define KVM_DEV_TYPE_ARM_VGIC_V2 KVM_DEV_TYPE_ARM_VGIC_V2
KVM_DEV_TYPE_FLIC, KVM_DEV_TYPE_FLIC,
#define KVM_DEV_TYPE_FLIC KVM_DEV_TYPE_FLIC #define KVM_DEV_TYPE_FLIC KVM_DEV_TYPE_FLIC
KVM_DEV_TYPE_ARM_VGIC_V3,
#define KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_V3
KVM_DEV_TYPE_MAX, KVM_DEV_TYPE_MAX,
}; };
......
This diff is collapsed.
...@@ -1249,7 +1249,7 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid, ...@@ -1249,7 +1249,7 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
int edge_triggered, level_triggered; int edge_triggered, level_triggered;
int enabled; int enabled;
bool ret = true; bool ret = true, can_inject = true;
spin_lock(&dist->lock); spin_lock(&dist->lock);
...@@ -1264,6 +1264,11 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid, ...@@ -1264,6 +1264,11 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
if (irq_num >= VGIC_NR_PRIVATE_IRQS) { if (irq_num >= VGIC_NR_PRIVATE_IRQS) {
cpuid = dist->irq_spi_cpu[irq_num - VGIC_NR_PRIVATE_IRQS]; cpuid = dist->irq_spi_cpu[irq_num - VGIC_NR_PRIVATE_IRQS];
if (cpuid == VCPU_NOT_ALLOCATED) {
/* Pretend we use CPU0, and prevent injection */
cpuid = 0;
can_inject = false;
}
vcpu = kvm_get_vcpu(kvm, cpuid); vcpu = kvm_get_vcpu(kvm, cpuid);
} }
...@@ -1286,7 +1291,7 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid, ...@@ -1286,7 +1291,7 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
enabled = vgic_irq_is_enabled(vcpu, irq_num); enabled = vgic_irq_is_enabled(vcpu, irq_num);
if (!enabled) { if (!enabled || !can_inject) {
ret = false; ret = false;
goto out; goto out;
} }
...@@ -1439,6 +1444,7 @@ void kvm_vgic_destroy(struct kvm *kvm) ...@@ -1439,6 +1444,7 @@ void kvm_vgic_destroy(struct kvm *kvm)
} }
kfree(dist->irq_sgi_sources); kfree(dist->irq_sgi_sources);
kfree(dist->irq_spi_cpu); kfree(dist->irq_spi_cpu);
kfree(dist->irq_spi_mpidr);
kfree(dist->irq_spi_target); kfree(dist->irq_spi_target);
kfree(dist->irq_pending_on_cpu); kfree(dist->irq_pending_on_cpu);
dist->irq_sgi_sources = NULL; dist->irq_sgi_sources = NULL;
...@@ -1594,6 +1600,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type) ...@@ -1594,6 +1600,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
kvm->arch.vgic.vctrl_base = vgic->vctrl_base; kvm->arch.vgic.vctrl_base = vgic->vctrl_base;
kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF; kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF; kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
out_unlock: out_unlock:
for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) { for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#define ACCESS_WRITE_VALUE (3 << 1) #define ACCESS_WRITE_VALUE (3 << 1)
#define ACCESS_WRITE_MASK(x) ((x) & (3 << 1)) #define ACCESS_WRITE_MASK(x) ((x) & (3 << 1))
#define VCPU_NOT_ALLOCATED ((u8)-1)
unsigned long *vgic_bitmap_get_shared_map(struct vgic_bitmap *x); unsigned long *vgic_bitmap_get_shared_map(struct vgic_bitmap *x);
void vgic_update_state(struct kvm *kvm); void vgic_update_state(struct kvm *kvm);
...@@ -116,5 +118,6 @@ int vgic_get_common_attr(struct kvm_device *dev, struct kvm_device_attr *attr); ...@@ -116,5 +118,6 @@ int vgic_get_common_attr(struct kvm_device *dev, struct kvm_device_attr *attr);
int vgic_init(struct kvm *kvm); int vgic_init(struct kvm *kvm);
void vgic_v2_init_emulation(struct kvm *kvm); void vgic_v2_init_emulation(struct kvm *kvm);
void vgic_v3_init_emulation(struct kvm *kvm);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment