Skip to content

Commit 9482846

Browse files
author
Marc Zyngier
committed
KVM: arm64: vgic-v3: Expose GICR_CTLR.RWP when disabling LPIs
When disabling LPIs, a guest needs to poll GICR_CTLR.RWP in order to be sure that the write has taken effect. We so far reported it as 0, as we didn't advertise that LPIs could be turned off the first place. Start tracking this state during which LPIs are being disabled, and expose the 'in progress' state via the RWP bit. We also take this opportunity to disallow enabling LPIs and programming GICR_{PEND,PROP}BASER while LPI disabling is in progress, as allowed by the architecture (UNPRED behaviour). We don't advertise the feature to the guest yet (which is allowed by the architecture). Reviewed-by: Oliver Upton <oupton@google.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20220405182327.205520-3-maz@kernel.org
1 parent 34453c2 commit 9482846

4 files changed

Lines changed: 31 additions & 12 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ int vgic_its_resolve_lpi(struct kvm *kvm, struct vgic_its *its,
683683
if (!vcpu)
684684
return E_ITS_INT_UNMAPPED_INTERRUPT;
685685

686-
if (!vcpu->arch.vgic_cpu.lpis_enabled)
686+
if (!vgic_lpis_enabled(vcpu))
687687
return -EBUSY;
688688

689689
vgic_its_cache_translation(kvm, its, devid, eventid, ite->irq);

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

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,13 @@ static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
221221
vgic_put_irq(vcpu->kvm, irq);
222222
}
223223

224+
bool vgic_lpis_enabled(struct kvm_vcpu *vcpu)
225+
{
226+
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
227+
228+
return atomic_read(&vgic_cpu->ctlr) == GICR_CTLR_ENABLE_LPIS;
229+
}
230+
224231
static unsigned long vgic_mmio_read_v3r_ctlr(struct kvm_vcpu *vcpu,
225232
gpa_t addr, unsigned int len)
226233
{
@@ -229,26 +236,38 @@ static unsigned long vgic_mmio_read_v3r_ctlr(struct kvm_vcpu *vcpu,
229236
return vgic_cpu->lpis_enabled ? GICR_CTLR_ENABLE_LPIS : 0;
230237
}
231238

232-
233239
static void vgic_mmio_write_v3r_ctlr(struct kvm_vcpu *vcpu,
234240
gpa_t addr, unsigned int len,
235241
unsigned long val)
236242
{
237243
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
238-
bool was_enabled = vgic_cpu->lpis_enabled;
244+
u32 ctlr;
239245

240246
if (!vgic_has_its(vcpu->kvm))
241247
return;
242248

243-
vgic_cpu->lpis_enabled = val & GICR_CTLR_ENABLE_LPIS;
249+
if (!(val & GICR_CTLR_ENABLE_LPIS)) {
250+
/*
251+
* Don't disable if RWP is set, as there already an
252+
* ongoing disable. Funky guest...
253+
*/
254+
ctlr = atomic_cmpxchg_acquire(&vgic_cpu->ctlr,
255+
GICR_CTLR_ENABLE_LPIS,
256+
GICR_CTLR_RWP);
257+
if (ctlr != GICR_CTLR_ENABLE_LPIS)
258+
return;
244259

245-
if (was_enabled && !vgic_cpu->lpis_enabled) {
246260
vgic_flush_pending_lpis(vcpu);
247261
vgic_its_invalidate_cache(vcpu->kvm);
248-
}
262+
atomic_set_release(&vgic_cpu->ctlr, 0);
263+
} else {
264+
ctlr = atomic_cmpxchg_acquire(&vgic_cpu->ctlr, 0,
265+
GICR_CTLR_ENABLE_LPIS);
266+
if (ctlr != 0)
267+
return;
249268

250-
if (!was_enabled && vgic_cpu->lpis_enabled)
251269
vgic_enable_lpis(vcpu);
270+
}
252271
}
253272

254273
static bool vgic_mmio_vcpu_rdist_is_last(struct kvm_vcpu *vcpu)
@@ -478,11 +497,10 @@ static void vgic_mmio_write_propbase(struct kvm_vcpu *vcpu,
478497
unsigned long val)
479498
{
480499
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
481-
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
482500
u64 old_propbaser, propbaser;
483501

484502
/* Storing a value with LPIs already enabled is undefined */
485-
if (vgic_cpu->lpis_enabled)
503+
if (vgic_lpis_enabled(vcpu))
486504
return;
487505

488506
do {
@@ -513,7 +531,7 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
513531
u64 old_pendbaser, pendbaser;
514532

515533
/* Storing a value with LPIs already enabled is undefined */
516-
if (vgic_cpu->lpis_enabled)
534+
if (vgic_lpis_enabled(vcpu))
517535
return;
518536

519537
do {

arch/arm64/kvm/vgic/vgic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ static inline bool vgic_dist_overlap(struct kvm *kvm, gpa_t base, size_t size)
308308
(base < d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE);
309309
}
310310

311+
bool vgic_lpis_enabled(struct kvm_vcpu *vcpu);
311312
int vgic_copy_lpi_list(struct kvm *kvm, struct kvm_vcpu *vcpu, u32 **intid_ptr);
312313
int vgic_its_resolve_lpi(struct kvm *kvm, struct vgic_its *its,
313314
u32 devid, u32 eventid, struct vgic_irq **irq);

include/kvm/arm_vgic.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,8 @@ struct vgic_cpu {
347347

348348
/* Contains the attributes and gpa of the LPI pending tables. */
349349
u64 pendbaser;
350-
351-
bool lpis_enabled;
350+
/* GICR_CTLR.{ENABLE_LPIS,RWP} */
351+
atomic_t ctlr;
352352

353353
/* Cache guest priority bits */
354354
u32 num_pri_bits;

0 commit comments

Comments
 (0)