Skip to content

Commit d53c2c2

Browse files
christofferdall-armMarc Zyngier
authored andcommitted
KVM: arm/arm64: vgic: Allow configuration of interrupt groups
Implement the required MMIO accessors for GICv2 and GICv3 for the IGROUPR distributor and redistributor registers. This can allow guests to change behavior compared to running on previous versions of KVM, but only to align with the architecture and hardware implementations. This also allows userspace to configure the interrupts groups for GICv3. We don't allow userspace to write the groups on GICv2 just yet, because that would result in GICv2 guests not receiving interrupts after migrating from an older kernel that exposes GICv2 interrupts as group 1. Reviewed-by: Andrew Jones <[email protected]> Signed-off-by: Christoffer Dall <[email protected]> Signed-off-by: Marc Zyngier <[email protected]>
1 parent b489edc commit d53c2c2

File tree

5 files changed

+66
-4
lines changed

5 files changed

+66
-4
lines changed

virt/kvm/arm/vgic/vgic-init.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ int vgic_init(struct kvm *kvm)
313313

314314
vgic_debug_init(kvm);
315315

316-
dist->implementation_rev = 1;
316+
dist->implementation_rev = 2;
317317
dist->initialized = true;
318318

319319
out:

virt/kvm/arm/vgic/vgic-mmio-v2.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
* The Revision field in the IIDR have the following meanings:
2727
*
2828
* Revision 1: Report GICv2 interrupts as group 0 instead of group 1
29+
* Revision 2: Interrupt groups are guest-configurable and signaled using
30+
* their configured groups.
2931
*/
3032

3133
static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
@@ -89,6 +91,14 @@ static int vgic_mmio_uaccess_write_v2_misc(struct kvm_vcpu *vcpu,
8991
return 0;
9092
}
9193

94+
static int vgic_mmio_uaccess_write_v2_group(struct kvm_vcpu *vcpu,
95+
gpa_t addr, unsigned int len,
96+
unsigned long val)
97+
{
98+
/* Ignore writes from userspace */
99+
return 0;
100+
}
101+
92102
static void vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
93103
gpa_t addr, unsigned int len,
94104
unsigned long val)
@@ -386,7 +396,8 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
386396
NULL, vgic_mmio_uaccess_write_v2_misc,
387397
12, VGIC_ACCESS_32bit),
388398
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
389-
vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
399+
vgic_mmio_read_group, vgic_mmio_write_group,
400+
NULL, vgic_mmio_uaccess_write_v2_group, 1,
390401
VGIC_ACCESS_32bit),
391402
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
392403
vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,

virt/kvm/arm/vgic/vgic-mmio-v3.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ bool vgic_supports_direct_msis(struct kvm *kvm)
5959
return kvm_vgic_global_state.has_gicv4 && vgic_has_its(kvm);
6060
}
6161

62+
/*
63+
* The Revision field in the IIDR have the following meanings:
64+
*
65+
* Revision 2: Interrupt groups are guest-configurable and signaled using
66+
* their configured groups.
67+
*/
68+
6269
static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
6370
gpa_t addr, unsigned int len)
6471
{
@@ -471,7 +478,7 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
471478
vgic_mmio_read_rao, vgic_mmio_write_wi, 4,
472479
VGIC_ACCESS_32bit),
473480
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
474-
vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
481+
vgic_mmio_read_group, vgic_mmio_write_group, NULL, NULL, 1,
475482
VGIC_ACCESS_32bit),
476483
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
477484
vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
@@ -544,7 +551,7 @@ static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
544551

545552
static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
546553
REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
547-
vgic_mmio_read_rao, vgic_mmio_write_wi, 4,
554+
vgic_mmio_read_group, vgic_mmio_write_group, 4,
548555
VGIC_ACCESS_32bit),
549556
REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
550557
vgic_mmio_read_enable, vgic_mmio_write_senable, 4,

virt/kvm/arm/vgic/vgic-mmio.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,44 @@ int vgic_mmio_uaccess_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
4747
return 0;
4848
}
4949

50+
unsigned long vgic_mmio_read_group(struct kvm_vcpu *vcpu,
51+
gpa_t addr, unsigned int len)
52+
{
53+
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
54+
u32 value = 0;
55+
int i;
56+
57+
/* Loop over all IRQs affected by this read */
58+
for (i = 0; i < len * 8; i++) {
59+
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
60+
61+
if (irq->group)
62+
value |= BIT(i);
63+
64+
vgic_put_irq(vcpu->kvm, irq);
65+
}
66+
67+
return value;
68+
}
69+
70+
void vgic_mmio_write_group(struct kvm_vcpu *vcpu, gpa_t addr,
71+
unsigned int len, unsigned long val)
72+
{
73+
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
74+
int i;
75+
unsigned long flags;
76+
77+
for (i = 0; i < len * 8; i++) {
78+
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
79+
80+
spin_lock_irqsave(&irq->irq_lock, flags);
81+
irq->group = !!(val & BIT(i));
82+
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
83+
84+
vgic_put_irq(vcpu->kvm, irq);
85+
}
86+
}
87+
5088
/*
5189
* Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
5290
* of the enabled bit, so there is only one function for both here.

virt/kvm/arm/vgic/vgic-mmio.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
137137
int vgic_mmio_uaccess_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
138138
unsigned int len, unsigned long val);
139139

140+
unsigned long vgic_mmio_read_group(struct kvm_vcpu *vcpu, gpa_t addr,
141+
unsigned int len);
142+
143+
void vgic_mmio_write_group(struct kvm_vcpu *vcpu, gpa_t addr,
144+
unsigned int len, unsigned long val);
145+
140146
unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
141147
gpa_t addr, unsigned int len);
142148

0 commit comments

Comments
 (0)