Skip to content

Commit 5618514

Browse files
ouptonMarc Zyngier
authored andcommitted
KVM: arm64: vgic: Use common accessor for writes to ICPENDR
Fold MMIO and user accessors into a common helper while maintaining the distinction between the two. Signed-off-by: Oliver Upton <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 13886f3 commit 5618514

File tree

1 file changed

+22
-29
lines changed

1 file changed

+22
-29
lines changed

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

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -386,9 +386,9 @@ static void vgic_hw_irq_cpending(struct kvm_vcpu *vcpu, struct vgic_irq *irq)
386386
vgic_irq_set_phys_active(irq, false);
387387
}
388388

389-
void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
390-
gpa_t addr, unsigned int len,
391-
unsigned long val)
389+
static void __clear_pending(struct kvm_vcpu *vcpu,
390+
gpa_t addr, unsigned int len,
391+
unsigned long val, bool is_user)
392392
{
393393
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
394394
int i;
@@ -397,14 +397,22 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
397397
for_each_set_bit(i, &val, len * 8) {
398398
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
399399

400-
/* GICD_ICPENDR0 SGI bits are WI */
401-
if (is_vgic_v2_sgi(vcpu, irq)) {
400+
/* GICD_ICPENDR0 SGI bits are WI when written from the guest. */
401+
if (is_vgic_v2_sgi(vcpu, irq) && !is_user) {
402402
vgic_put_irq(vcpu->kvm, irq);
403403
continue;
404404
}
405405

406406
raw_spin_lock_irqsave(&irq->irq_lock, flags);
407407

408+
/*
409+
* More fun with GICv2 SGIs! If we're clearing one of them
410+
* from userspace, which source vcpu to clear? Let's not
411+
* even think of it, and blow the whole set.
412+
*/
413+
if (is_vgic_v2_sgi(vcpu, irq))
414+
irq->source = 0;
415+
408416
if (irq->hw && vgic_irq_is_sgi(irq->intid)) {
409417
/* HW SGI? Ask the GIC to clear its pending bit */
410418
int err;
@@ -419,7 +427,7 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
419427
continue;
420428
}
421429

422-
if (irq->hw)
430+
if (irq->hw && !is_user)
423431
vgic_hw_irq_cpending(vcpu, irq);
424432
else
425433
irq->pending_latch = false;
@@ -429,33 +437,18 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
429437
}
430438
}
431439

440+
void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
441+
gpa_t addr, unsigned int len,
442+
unsigned long val)
443+
{
444+
__clear_pending(vcpu, addr, len, val, false);
445+
}
446+
432447
int vgic_uaccess_write_cpending(struct kvm_vcpu *vcpu,
433448
gpa_t addr, unsigned int len,
434449
unsigned long val)
435450
{
436-
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
437-
int i;
438-
unsigned long flags;
439-
440-
for_each_set_bit(i, &val, len * 8) {
441-
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
442-
443-
raw_spin_lock_irqsave(&irq->irq_lock, flags);
444-
/*
445-
* More fun with GICv2 SGIs! If we're clearing one of them
446-
* from userspace, which source vcpu to clear? Let's not
447-
* even think of it, and blow the whole set.
448-
*/
449-
if (is_vgic_v2_sgi(vcpu, irq))
450-
irq->source = 0;
451-
452-
irq->pending_latch = false;
453-
454-
raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
455-
456-
vgic_put_irq(vcpu->kvm, irq);
457-
}
458-
451+
__clear_pending(vcpu, addr, len, val, true);
459452
return 0;
460453
}
461454

0 commit comments

Comments
 (0)