Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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) += vgic-v2-switch.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_TIMER) += $(KVM)/arm/arch_timer.o
+8 −1
Original line number Diff line number Diff line
@@ -162,7 +162,11 @@ struct vgic_dist {

	/* Distributor and vcpu interface mapping in the guest */
	phys_addr_t		vgic_dist_base;
	/* GICv2 and GICv3 use different mapped register blocks */
	union {
		phys_addr_t		vgic_cpu_base;
		phys_addr_t		vgic_redist_base;
	};

	/* Distributor enabled */
	u32			enabled;
@@ -224,6 +228,9 @@ struct vgic_dist {
	 */
	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 */
	unsigned long		*irq_pending_on_cpu;

+32 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#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
@@ -41,14 +42,37 @@
#define GICD_ICACTIVER			0x0380
#define GICD_IPRIORITYR			0x0400
#define GICD_ICFGR			0x0C00
#define GICD_IGRPMODR			0x0D00
#define GICD_NSACR			0x0E00
#define GICD_IROUTER			0x6000
#define GICD_IDREGS			0xFFD0
#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_DS			(1U << 6)
#define GICD_CTLR_ARE_NS		(1U << 4)
#define GICD_CTLR_ENABLE_G1A		(1U << 1)
#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_IRQS(typer)		((((typer) & 0x1f) + 1) * 32)
#define GICD_TYPER_LPIS			(1U << 17)
@@ -60,6 +84,8 @@
#define GIC_PIDR2_ARCH_GICv3		0x30
#define GIC_PIDR2_ARCH_GICv4		0x40

#define GIC_V3_DIST_SIZE		0x10000

/*
 * Re-Distributor registers, offsets from RD_base
 */
@@ -78,6 +104,7 @@
#define GICR_SYNCR			0x00C0
#define GICR_MOVLPIR			0x0100
#define GICR_MOVALLR			0x0110
#define GICR_IDREGS			GICD_IDREGS
#define GICR_PIDR2			GICD_PIDR2

#define GICR_CTLR_ENABLE_LPIS		(1UL << 0)
@@ -104,6 +131,7 @@
/*
 * Re-Distributor registers, offsets from SGI_base
 */
#define GICR_IGROUPR0			GICD_IGROUPR
#define GICR_ISENABLER0			GICD_ISENABLER
#define GICR_ICENABLER0			GICD_ICENABLER
#define GICR_ISPENDR0			GICD_ISPENDR
@@ -112,11 +140,15 @@
#define GICR_ICACTIVER0			GICD_ICACTIVER
#define GICR_IPRIORITYR0		GICD_IPRIORITYR
#define GICR_ICFGR0			GICD_ICFGR
#define GICR_IGRPMODR0			GICD_IGRPMODR
#define GICR_NSACR			GICD_NSACR

#define GICR_TYPER_PLPIS		(1U << 0)
#define GICR_TYPER_VLPIS		(1U << 1)
#define GICR_TYPER_LAST			(1U << 4)

#define GIC_V3_REDIST_SIZE		0x20000

#define LPI_PROP_GROUP1			(1 << 1)
#define LPI_PROP_ENABLED		(1 << 0)

+1 −0
Original line number Diff line number Diff line
@@ -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_xics_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

+2 −0
Original line number Diff line number Diff line
@@ -952,6 +952,8 @@ enum kvm_device_type {
#define KVM_DEV_TYPE_ARM_VGIC_V2	KVM_DEV_TYPE_ARM_VGIC_V2
	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,
};

Loading