Skip to content

Commit 0d46e32

Browse files
committed
Merge branch 'kvm-arm64/vgic-v4-ctl' into kvmarm/next
* kvm-arm64/vgic-v4-ctl: : Userspace control of nASSGIcap, courtesy of Raghavendra Rao Ananta : : Allow userspace to decide if support for SGIs without an active state is : advertised to the guest, allowing VMs from GICv3-only hardware to be : migrated to to GICv4.1 capable machines. Documentation: KVM: arm64: Describe VGICv3 registers writable pre-init KVM: arm64: selftests: Add test for nASSGIcap attribute KVM: arm64: vgic-v3: Allow userspace to write GICD_TYPER2.nASSGIcap KVM: arm64: vgic-v3: Allow access to GICD_IIDR prior to initialization KVM: arm64: vgic-v3: Consolidate MAINT_IRQ handling KVM: arm64: Disambiguate support for vSGIs v. vLPIs Signed-off-by: Oliver Upton <[email protected]>
2 parents a7f49a9 + eed9b14 commit 0d46e32

File tree

9 files changed

+158
-50
lines changed

9 files changed

+158
-50
lines changed

Documentation/virt/kvm/devices/arm-vgic-v3.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ Groups:
7878
-ENXIO The group or attribute is unknown/unsupported for this device
7979
or hardware support is missing.
8080
-EFAULT Invalid user pointer for attr->addr.
81+
-EBUSY Attempt to write a register that is read-only after
82+
initialization
8183
======= =============================================================
8284

8385

@@ -120,6 +122,15 @@ Groups:
120122
Note that distributor fields are not banked, but return the same value
121123
regardless of the mpidr used to access the register.
122124

125+
Userspace is allowed to write the following register fields prior to
126+
initialization of the VGIC:
127+
128+
=====================
129+
GICD_IIDR.Revision
130+
GICD_TYPER2.nASSGIcap
131+
=====================
132+
133+
123134
GICD_IIDR.Revision is updated when the KVM implementation is changed in a
124135
way directly observable by the guest or userspace. Userspace should read
125136
GICD_IIDR from KVM and write back the read value to confirm its expected
@@ -128,6 +139,12 @@ Groups:
128139
behavior.
129140

130141

142+
GICD_TYPER2.nASSGIcap allows userspace to control the support of SGIs
143+
without an active state. At VGIC creation the field resets to the
144+
maximum capability of the system. Userspace is expected to read the field
145+
to determine the supported value(s) before writing to the field.
146+
147+
131148
The GICD_STATUSR and GICR_STATUSR registers are architecturally defined such
132149
that a write of a clear bit has no effect, whereas a write with a set bit
133150
clears that value. To allow userspace to freely set the values of these two

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

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
157157

158158
kvm->arch.vgic.in_kernel = true;
159159
kvm->arch.vgic.vgic_model = type;
160+
kvm->arch.vgic.implementation_rev = KVM_VGIC_IMP_REV_LATEST;
160161

161162
kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
162163

@@ -165,6 +166,9 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
165166
else
166167
INIT_LIST_HEAD(&kvm->arch.vgic.rd_regions);
167168

169+
if (type == KVM_DEV_TYPE_ARM_VGIC_V3)
170+
kvm->arch.vgic.nassgicap = system_supports_direct_sgis();
171+
168172
out_unlock:
169173
mutex_unlock(&kvm->arch.config_lock);
170174
kvm_unlock_all_vcpus(kvm);
@@ -391,11 +395,10 @@ int vgic_init(struct kvm *kvm)
391395
goto out;
392396

393397
/*
394-
* If we have GICv4.1 enabled, unconditionally request enable the
395-
* v4 support so that we get HW-accelerated vSGIs. Otherwise, only
396-
* enable it if we present a virtual ITS to the guest.
398+
* Ensure vPEs are allocated if direct IRQ injection (e.g. vSGIs,
399+
* vLPIs) is supported.
397400
*/
398-
if (vgic_supports_direct_msis(kvm)) {
401+
if (vgic_supports_direct_irqs(kvm)) {
399402
ret = vgic_v4_init(kvm);
400403
if (ret)
401404
goto out;
@@ -409,15 +412,7 @@ int vgic_init(struct kvm *kvm)
409412
goto out;
410413

411414
vgic_debug_init(kvm);
412-
413-
/*
414-
* If userspace didn't set the GIC implementation revision,
415-
* default to the latest and greatest. You know want it.
416-
*/
417-
if (!dist->implementation_rev)
418-
dist->implementation_rev = KVM_VGIC_IMP_REV_LATEST;
419415
dist->initialized = true;
420-
421416
out:
422417
return ret;
423418
}
@@ -443,7 +438,7 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm)
443438
dist->vgic_cpu_base = VGIC_ADDR_UNDEF;
444439
}
445440

446-
if (vgic_supports_direct_msis(kvm))
441+
if (vgic_supports_direct_irqs(kvm))
447442
vgic_v4_teardown(kvm);
448443

449444
xa_destroy(&dist->lpi_xa);

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

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* Copyright (C) 2015 ARM Ltd.
66
* Author: Marc Zyngier <[email protected]>
77
*/
8+
#include <linux/irqchip/arm-gic-v3.h>
89
#include <linux/kvm_host.h>
910
#include <kvm/arm_vgic.h>
1011
#include <linux/uaccess.h>
@@ -303,12 +304,6 @@ static int vgic_get_common_attr(struct kvm_device *dev,
303304
VGIC_NR_PRIVATE_IRQS, uaddr);
304305
break;
305306
}
306-
case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ: {
307-
u32 __user *uaddr = (u32 __user *)(long)attr->addr;
308-
309-
r = put_user(dev->kvm->arch.vgic.mi_intid, uaddr);
310-
break;
311-
}
312307
}
313308

314309
return r;
@@ -509,6 +504,24 @@ int vgic_v3_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr,
509504
return 0;
510505
}
511506

507+
/*
508+
* Allow access to certain ID-like registers prior to VGIC initialization,
509+
* thereby allowing the VMM to provision the features / sizing of the VGIC.
510+
*/
511+
static bool reg_allowed_pre_init(struct kvm_device_attr *attr)
512+
{
513+
if (attr->group != KVM_DEV_ARM_VGIC_GRP_DIST_REGS)
514+
return false;
515+
516+
switch (attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK) {
517+
case GICD_IIDR:
518+
case GICD_TYPER2:
519+
return true;
520+
default:
521+
return false;
522+
}
523+
}
524+
512525
/*
513526
* vgic_v3_attr_regs_access - allows user space to access VGIC v3 state
514527
*
@@ -523,7 +536,7 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
523536
struct vgic_reg_attr reg_attr;
524537
gpa_t addr;
525538
struct kvm_vcpu *vcpu;
526-
bool uaccess, post_init = true;
539+
bool uaccess;
527540
u32 val;
528541
int ret;
529542

@@ -539,9 +552,6 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
539552
/* Sysregs uaccess is performed by the sysreg handling code */
540553
uaccess = false;
541554
break;
542-
case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ:
543-
post_init = false;
544-
fallthrough;
545555
default:
546556
uaccess = true;
547557
}
@@ -561,7 +571,7 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
561571

562572
mutex_lock(&dev->kvm->arch.config_lock);
563573

564-
if (post_init != vgic_initialized(dev->kvm)) {
574+
if (!(vgic_initialized(dev->kvm) || reg_allowed_pre_init(attr))) {
565575
ret = -EBUSY;
566576
goto out;
567577
}
@@ -591,19 +601,6 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
591601
}
592602
break;
593603
}
594-
case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ:
595-
if (!is_write) {
596-
val = dev->kvm->arch.vgic.mi_intid;
597-
ret = 0;
598-
break;
599-
}
600-
601-
ret = -EINVAL;
602-
if ((val < VGIC_NR_PRIVATE_IRQS) && (val >= VGIC_NR_SGIS)) {
603-
dev->kvm->arch.vgic.mi_intid = val;
604-
ret = 0;
605-
}
606-
break;
607604
default:
608605
ret = -EINVAL;
609606
break;
@@ -630,8 +627,24 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
630627
case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
631628
case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
632629
case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO:
633-
case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ:
634630
return vgic_v3_attr_regs_access(dev, attr, true);
631+
case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ: {
632+
u32 __user *uaddr = (u32 __user *)attr->addr;
633+
u32 val;
634+
635+
if (get_user(val, uaddr))
636+
return -EFAULT;
637+
638+
guard(mutex)(&dev->kvm->arch.config_lock);
639+
if (vgic_initialized(dev->kvm))
640+
return -EBUSY;
641+
642+
if (!irq_is_ppi(val))
643+
return -EINVAL;
644+
645+
dev->kvm->arch.vgic.mi_intid = val;
646+
return 0;
647+
}
635648
default:
636649
return vgic_set_common_attr(dev, attr);
637650
}
@@ -645,8 +658,13 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
645658
case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
646659
case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
647660
case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO:
648-
case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ:
649661
return vgic_v3_attr_regs_access(dev, attr, false);
662+
case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ: {
663+
u32 __user *uaddr = (u32 __user *)(long)attr->addr;
664+
665+
guard(mutex)(&dev->kvm->arch.config_lock);
666+
return put_user(dev->kvm->arch.vgic.mi_intid, uaddr);
667+
}
650668
default:
651669
return vgic_get_common_attr(dev, attr);
652670
}

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

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,17 @@ bool vgic_has_its(struct kvm *kvm)
5050

5151
bool vgic_supports_direct_msis(struct kvm *kvm)
5252
{
53-
return (kvm_vgic_global_state.has_gicv4_1 ||
54-
(kvm_vgic_global_state.has_gicv4 && vgic_has_its(kvm)));
53+
return kvm_vgic_global_state.has_gicv4 && vgic_has_its(kvm);
54+
}
55+
56+
bool system_supports_direct_sgis(void)
57+
{
58+
return kvm_vgic_global_state.has_gicv4_1 && gic_cpuif_has_vsgi();
59+
}
60+
61+
bool vgic_supports_direct_sgis(struct kvm *kvm)
62+
{
63+
return kvm->arch.vgic.nassgicap;
5564
}
5665

5766
/*
@@ -86,7 +95,7 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
8695
}
8796
break;
8897
case GICD_TYPER2:
89-
if (kvm_vgic_global_state.has_gicv4_1 && gic_cpuif_has_vsgi())
98+
if (vgic_supports_direct_sgis(vcpu->kvm))
9099
value = GICD_TYPER2_nASSGIcap;
91100
break;
92101
case GICD_IIDR:
@@ -119,7 +128,7 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
119128
dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
120129

121130
/* Not a GICv4.1? No HW SGIs */
122-
if (!kvm_vgic_global_state.has_gicv4_1 || !gic_cpuif_has_vsgi())
131+
if (!vgic_supports_direct_sgis(vcpu->kvm))
123132
val &= ~GICD_CTLR_nASSGIreq;
124133

125134
/* Dist stays enabled? nASSGIreq is RO */
@@ -133,7 +142,7 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
133142
if (is_hwsgi != dist->nassgireq)
134143
vgic_v4_configure_vsgis(vcpu->kvm);
135144

136-
if (kvm_vgic_global_state.has_gicv4_1 &&
145+
if (vgic_supports_direct_sgis(vcpu->kvm) &&
137146
was_enabled != dist->enabled)
138147
kvm_make_all_cpus_request(vcpu->kvm, KVM_REQ_RELOAD_GICv4);
139148
else if (!was_enabled && dist->enabled)
@@ -159,8 +168,18 @@ static int vgic_mmio_uaccess_write_v3_misc(struct kvm_vcpu *vcpu,
159168

160169
switch (addr & 0x0c) {
161170
case GICD_TYPER2:
162-
if (val != vgic_mmio_read_v3_misc(vcpu, addr, len))
171+
reg = vgic_mmio_read_v3_misc(vcpu, addr, len);
172+
173+
if (reg == val)
174+
return 0;
175+
if (vgic_initialized(vcpu->kvm))
176+
return -EBUSY;
177+
if ((reg ^ val) & ~GICD_TYPER2_nASSGIcap)
163178
return -EINVAL;
179+
if (!system_supports_direct_sgis() && val)
180+
return -EINVAL;
181+
182+
dist->nassgicap = val & GICD_TYPER2_nASSGIcap;
164183
return 0;
165184
case GICD_IIDR:
166185
reg = vgic_mmio_read_v3_misc(vcpu, addr, len);
@@ -178,7 +197,7 @@ static int vgic_mmio_uaccess_write_v3_misc(struct kvm_vcpu *vcpu,
178197
}
179198
case GICD_CTLR:
180199
/* Not a GICv4.1? No HW SGIs */
181-
if (!kvm_vgic_global_state.has_gicv4_1)
200+
if (!vgic_supports_direct_sgis(vcpu->kvm))
182201
val &= ~GICD_CTLR_nASSGIreq;
183202

184203
dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ int vgic_v4_put(struct kvm_vcpu *vcpu)
356356
{
357357
struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe;
358358

359-
if (!vgic_supports_direct_msis(vcpu->kvm) || !vpe->resident)
359+
if (!vgic_supports_direct_irqs(vcpu->kvm) || !vpe->resident)
360360
return 0;
361361

362362
return its_make_vpe_non_resident(vpe, vgic_v4_want_doorbell(vcpu));
@@ -367,7 +367,7 @@ int vgic_v4_load(struct kvm_vcpu *vcpu)
367367
struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe;
368368
int err;
369369

370-
if (!vgic_supports_direct_msis(vcpu->kvm) || vpe->resident)
370+
if (!vgic_supports_direct_irqs(vcpu->kvm) || vpe->resident)
371371
return 0;
372372

373373
if (vcpu_get_flag(vcpu, IN_WFI))

arch/arm64/kvm/vgic/vgic.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,7 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
951951
* can be directly injected (GICv4).
952952
*/
953953
if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head) &&
954-
!vgic_supports_direct_msis(vcpu->kvm))
954+
!vgic_supports_direct_irqs(vcpu->kvm))
955955
return;
956956

957957
DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
@@ -965,7 +965,7 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
965965
if (can_access_vgic_from_kernel())
966966
vgic_restore_state(vcpu);
967967

968-
if (vgic_supports_direct_msis(vcpu->kvm))
968+
if (vgic_supports_direct_irqs(vcpu->kvm))
969969
vgic_v4_commit(vcpu);
970970
}
971971

arch/arm64/kvm/vgic/vgic.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,23 @@ void vgic_its_invalidate_all_caches(struct kvm *kvm);
390390
int vgic_its_inv_lpi(struct kvm *kvm, struct vgic_irq *irq);
391391
int vgic_its_invall(struct kvm_vcpu *vcpu);
392392

393+
bool system_supports_direct_sgis(void);
393394
bool vgic_supports_direct_msis(struct kvm *kvm);
395+
bool vgic_supports_direct_sgis(struct kvm *kvm);
396+
397+
static inline bool vgic_supports_direct_irqs(struct kvm *kvm)
398+
{
399+
/*
400+
* Deliberately conflate vLPI and vSGI support on GICv4.1 hardware,
401+
* indirectly allowing userspace to control whether or not vPEs are
402+
* allocated for the VM.
403+
*/
404+
if (system_supports_direct_sgis())
405+
return vgic_supports_direct_sgis(kvm);
406+
407+
return vgic_supports_direct_msis(kvm);
408+
}
409+
394410
int vgic_v4_init(struct kvm *kvm);
395411
void vgic_v4_teardown(struct kvm *kvm);
396412
void vgic_v4_configure_vsgis(struct kvm *kvm);

include/kvm/arm_vgic.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ struct vgic_dist {
268268
/* distributor enabled */
269269
bool enabled;
270270

271+
/* Supports SGIs without active state */
272+
bool nassgicap;
273+
271274
/* Wants SGIs without active state */
272275
bool nassgireq;
273276

0 commit comments

Comments
 (0)