Skip to content

Commit

Permalink
KVM: arm: vgic: Only use the virtual state when userspace accesses en…
Browse files Browse the repository at this point in the history
…able bits

There is no point in accessing the HW when writing to any of the
ISENABLER/ICENABLER registers from userspace, as only the guest
should be allowed to change the HW state.

Introduce new userspace-specific accessors that deal solely with
the virtual state.

Reported-by: James Morse <[email protected]>
Tested-by: James Morse <[email protected]>
Reviewed-by: James Morse <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
  • Loading branch information
Marc Zyngier committed Apr 22, 2020
1 parent 9a50ebb commit 41ee52e
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 8 deletions.
6 changes: 4 additions & 2 deletions virt/kvm/arm/vgic/vgic-mmio-v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,10 +409,12 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
NULL, vgic_mmio_uaccess_write_v2_group, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
vgic_mmio_read_enable, vgic_mmio_write_senable,
NULL, vgic_uaccess_write_senable, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
vgic_mmio_read_enable, vgic_mmio_write_cenable,
NULL, vgic_uaccess_write_cenable, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
vgic_mmio_read_pending, vgic_mmio_write_spending, NULL, NULL, 1,
Expand Down
16 changes: 10 additions & 6 deletions virt/kvm/arm/vgic/vgic-mmio-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -538,10 +538,12 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
vgic_mmio_read_group, vgic_mmio_write_group, NULL, NULL, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
vgic_mmio_read_enable, vgic_mmio_write_senable,
NULL, vgic_uaccess_write_senable, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
vgic_mmio_read_enable, vgic_mmio_write_cenable,
NULL, vgic_uaccess_write_cenable, 1,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
vgic_mmio_read_pending, vgic_mmio_write_spending,
Expand Down Expand Up @@ -609,11 +611,13 @@ static const struct vgic_register_region vgic_v3_rd_registers[] = {
REGISTER_DESC_WITH_LENGTH(SZ_64K + GICR_IGROUPR0,
vgic_mmio_read_group, vgic_mmio_write_group, 4,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_LENGTH(SZ_64K + GICR_ISENABLER0,
vgic_mmio_read_enable, vgic_mmio_write_senable, 4,
REGISTER_DESC_WITH_LENGTH_UACCESS(SZ_64K + GICR_ISENABLER0,
vgic_mmio_read_enable, vgic_mmio_write_senable,
NULL, vgic_uaccess_write_senable, 4,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_LENGTH(SZ_64K + GICR_ICENABLER0,
vgic_mmio_read_enable, vgic_mmio_write_cenable, 4,
REGISTER_DESC_WITH_LENGTH_UACCESS(SZ_64K + GICR_ICENABLER0,
vgic_mmio_read_enable, vgic_mmio_write_cenable,
NULL, vgic_uaccess_write_cenable, 4,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_LENGTH_UACCESS(SZ_64K + GICR_ISPENDR0,
vgic_mmio_read_pending, vgic_mmio_write_spending,
Expand Down
42 changes: 42 additions & 0 deletions virt/kvm/arm/vgic/vgic-mmio.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,48 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
}
}

int vgic_uaccess_write_senable(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val)
{
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
int i;
unsigned long flags;

for_each_set_bit(i, &val, len * 8) {
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);

raw_spin_lock_irqsave(&irq->irq_lock, flags);
irq->enabled = true;
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);

vgic_put_irq(vcpu->kvm, irq);
}

return 0;
}

int vgic_uaccess_write_cenable(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val)
{
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
int i;
unsigned long flags;

for_each_set_bit(i, &val, len * 8) {
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);

raw_spin_lock_irqsave(&irq->irq_lock, flags);
irq->enabled = false;
raw_spin_unlock_irqrestore(&irq->irq_lock, flags);

vgic_put_irq(vcpu->kvm, irq);
}

return 0;
}

unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len)
{
Expand Down
8 changes: 8 additions & 0 deletions virt/kvm/arm/vgic/vgic-mmio.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,14 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val);

int vgic_uaccess_write_senable(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val);

int vgic_uaccess_write_cenable(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val);

unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len);

Expand Down

0 comments on commit 41ee52e

Please sign in to comment.