Skip to content

Commit 49a1a2c

Browse files
author
Marc Zyngier
committed
KVM: arm64: vgic-v3: Advertise GICR_CTLR.{IR, CES} as a new GICD_IIDR revision
Since adversising GICR_CTLR.{IC,CES} is directly observable from a guest, we need to make it selectable from userspace. For that, bump the default GICD_IIDR revision and let userspace downgrade it to the previous default. For GICv2, the two distributor revisions are strictly equivalent. Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20220405182327.205520-5-maz@kernel.org
1 parent 4645d11 commit 49a1a2c

5 files changed

Lines changed: 50 additions & 6 deletions

File tree

arch/arm64/kvm/vgic/vgic-init.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,12 @@ int vgic_init(struct kvm *kvm)
319319

320320
vgic_debug_init(kvm);
321321

322-
dist->implementation_rev = 2;
322+
/*
323+
* If userspace didn't set the GIC implementation revision,
324+
* default to the latest and greatest. You know want it.
325+
*/
326+
if (!dist->implementation_rev)
327+
dist->implementation_rev = KVM_VGIC_IMP_REV_LATEST;
323328
dist->initialized = true;
324329

325330
out:

arch/arm64/kvm/vgic/vgic-mmio-v2.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,13 @@ static int vgic_mmio_uaccess_write_v2_misc(struct kvm_vcpu *vcpu,
7373
gpa_t addr, unsigned int len,
7474
unsigned long val)
7575
{
76+
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
77+
u32 reg;
78+
7679
switch (addr & 0x0c) {
7780
case GIC_DIST_IIDR:
78-
if (val != vgic_mmio_read_v2_misc(vcpu, addr, len))
81+
reg = vgic_mmio_read_v2_misc(vcpu, addr, len);
82+
if ((reg ^ val) & ~GICD_IIDR_REVISION_MASK)
7983
return -EINVAL;
8084

8185
/*
@@ -87,8 +91,16 @@ static int vgic_mmio_uaccess_write_v2_misc(struct kvm_vcpu *vcpu,
8791
* migration from old kernels to new kernels with legacy
8892
* userspace.
8993
*/
90-
vcpu->kvm->arch.vgic.v2_groups_user_writable = true;
91-
return 0;
94+
reg = FIELD_GET(GICD_IIDR_REVISION_MASK, reg);
95+
switch (reg) {
96+
case KVM_VGIC_IMP_REV_2:
97+
case KVM_VGIC_IMP_REV_3:
98+
vcpu->kvm->arch.vgic.v2_groups_user_writable = true;
99+
dist->implementation_rev = reg;
100+
return 0;
101+
default:
102+
return -EINVAL;
103+
}
92104
}
93105

94106
vgic_mmio_write_v2_misc(vcpu, addr, len, val);

arch/arm64/kvm/vgic/vgic-mmio-v3.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,27 @@ static int vgic_mmio_uaccess_write_v3_misc(struct kvm_vcpu *vcpu,
155155
unsigned long val)
156156
{
157157
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
158+
u32 reg;
158159

159160
switch (addr & 0x0c) {
160161
case GICD_TYPER2:
161-
case GICD_IIDR:
162162
if (val != vgic_mmio_read_v3_misc(vcpu, addr, len))
163163
return -EINVAL;
164164
return 0;
165+
case GICD_IIDR:
166+
reg = vgic_mmio_read_v3_misc(vcpu, addr, len);
167+
if ((reg ^ val) & ~GICD_IIDR_REVISION_MASK)
168+
return -EINVAL;
169+
170+
reg = FIELD_GET(GICD_IIDR_REVISION_MASK, reg);
171+
switch (reg) {
172+
case KVM_VGIC_IMP_REV_2:
173+
case KVM_VGIC_IMP_REV_3:
174+
dist->implementation_rev = reg;
175+
return 0;
176+
default:
177+
return -EINVAL;
178+
}
165179
case GICD_CTLR:
166180
/* Not a GICv4.1? No HW SGIs */
167181
if (!kvm_vgic_global_state.has_gicv4_1)
@@ -232,8 +246,13 @@ static unsigned long vgic_mmio_read_v3r_ctlr(struct kvm_vcpu *vcpu,
232246
gpa_t addr, unsigned int len)
233247
{
234248
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
249+
unsigned long val;
250+
251+
val = atomic_read(&vgic_cpu->ctlr);
252+
if (vgic_get_implementation_rev(vcpu) >= KVM_VGIC_IMP_REV_3)
253+
val |= GICR_CTLR_IR | GICR_CTLR_CES;
235254

236-
return vgic_cpu->lpis_enabled ? GICR_CTLR_ENABLE_LPIS : 0;
255+
return val;
237256
}
238257

239258
static void vgic_mmio_write_v3r_ctlr(struct kvm_vcpu *vcpu,

arch/arm64/kvm/vgic/vgic.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@
9898
#define DEBUG_SPINLOCK_BUG_ON(p)
9999
#endif
100100

101+
static inline u32 vgic_get_implementation_rev(struct kvm_vcpu *vcpu)
102+
{
103+
return vcpu->kvm->arch.vgic.implementation_rev;
104+
}
105+
101106
/* Requires the irq_lock to be held by the caller. */
102107
static inline bool irq_is_pending(struct vgic_irq *irq)
103108
{

include/kvm/arm_vgic.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ struct vgic_dist {
231231

232232
/* Implementation revision as reported in the GICD_IIDR */
233233
u32 implementation_rev;
234+
#define KVM_VGIC_IMP_REV_2 2 /* GICv2 restorable groups */
235+
#define KVM_VGIC_IMP_REV_3 3 /* GICv3 GICR_CTLR.{IW,CES,RWP} */
236+
#define KVM_VGIC_IMP_REV_LATEST KVM_VGIC_IMP_REV_3
234237

235238
/* Userspace can write to GICv2 IGROUPR */
236239
bool v2_groups_user_writable;

0 commit comments

Comments
 (0)