KVM: arm/arm64: vgic: Allow more than 256 vcpus for KVM_IRQ_LINE
authorMarc Zyngier <maz@kernel.org>
Sun, 18 Aug 2019 13:09:47 +0000 (14:09 +0100)
committerMarc Zyngier <maz@kernel.org>
Mon, 9 Sep 2019 11:29:09 +0000 (12:29 +0100)
While parts of the VGIC support a large number of vcpus (we
bravely allow up to 512), other parts are more limited.

One of these limits is visible in the KVM_IRQ_LINE ioctl, which
only allows 256 vcpus to be signalled when using the CPU or PPI
types. Unfortunately, we've cornered ourselves badly by allocating
all the bits in the irq field.

Since the irq_type subfield (8 bit wide) is currently only taking
the values 0, 1 and 2 (and we have been careful not to allow anything
else), let's reduce this field to only 4 bits, and allocate the
remaining 4 bits to a vcpu2_index, which acts as a multiplier:

  vcpu_id = 256 * vcpu2_index + vcpu_index

With that, and a new capability (KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)
allowing this to be discovered, it becomes possible to inject
PPIs to up to 4096 vcpus. But please just don't.

Whilst we're there, add a clarification about the use of KVM_IRQ_LINE
on arm, which is not completely conditionned by KVM_CAP_IRQCHIP.

Reported-by: Zenghui Yu <yuzenghui@huawei.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Zenghui Yu <yuzenghui@huawei.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Documentation/virt/kvm/api.txt
arch/arm/include/uapi/asm/kvm.h
arch/arm64/include/uapi/asm/kvm.h
include/uapi/linux/kvm.h
virt/kvm/arm/arm.c

index 2d067767b6170249975340d24f9af56c027da5bb..25931ca1cb382c141d6a5cd1904b55bb07325277 100644 (file)
@@ -753,8 +753,8 @@ in-kernel irqchip (GIC), and for in-kernel irqchip can tell the GIC to
 use PPIs designated for specific cpus.  The irq field is interpreted
 like this:
 
-  bits:  | 31 ... 24 | 23  ... 16 | 15    ...    0 |
-  field: | irq_type  | vcpu_index |     irq_id     |
+  bits:  |  31 ... 28  | 27 ... 24 | 23  ... 16 | 15 ... 0 |
+  field: | vcpu2_index | irq_type  | vcpu_index |  irq_id  |
 
 The irq_type field has the following values:
 - irq_type[0]: out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ
@@ -766,6 +766,14 @@ The irq_type field has the following values:
 
 In both cases, level is used to assert/deassert the line.
 
+When KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 is supported, the target vcpu is
+identified as (256 * vcpu2_index + vcpu_index). Otherwise, vcpu2_index
+must be zero.
+
+Note that on arm/arm64, the KVM_CAP_IRQCHIP capability only conditions
+injection of interrupts for the in-kernel irqchip. KVM_IRQ_LINE can always
+be used for a userspace interrupt controller.
+
 struct kvm_irq_level {
        union {
                __u32 irq;     /* GSI */
index a4217c1a5d01178c53346ea3f48ed3415aa956fd..2769360f195cafe1ead78ea917495778a7a52c21 100644 (file)
@@ -266,8 +266,10 @@ struct kvm_vcpu_events {
 #define   KVM_DEV_ARM_ITS_CTRL_RESET           4
 
 /* KVM_IRQ_LINE irq field index values */
+#define KVM_ARM_IRQ_VCPU2_SHIFT                28
+#define KVM_ARM_IRQ_VCPU2_MASK         0xf
 #define KVM_ARM_IRQ_TYPE_SHIFT         24
-#define KVM_ARM_IRQ_TYPE_MASK          0xff
+#define KVM_ARM_IRQ_TYPE_MASK          0xf
 #define KVM_ARM_IRQ_VCPU_SHIFT         16
 #define KVM_ARM_IRQ_VCPU_MASK          0xff
 #define KVM_ARM_IRQ_NUM_SHIFT          0
index 9a507716ae2fe723624d7c7de3c1b88501d5f9a3..67c21f9bdbad2556be4114dfa09b8006a11e708e 100644 (file)
@@ -325,8 +325,10 @@ struct kvm_vcpu_events {
 #define   KVM_ARM_VCPU_TIMER_IRQ_PTIMER                1
 
 /* KVM_IRQ_LINE irq field index values */
+#define KVM_ARM_IRQ_VCPU2_SHIFT                28
+#define KVM_ARM_IRQ_VCPU2_MASK         0xf
 #define KVM_ARM_IRQ_TYPE_SHIFT         24
-#define KVM_ARM_IRQ_TYPE_MASK          0xff
+#define KVM_ARM_IRQ_TYPE_MASK          0xf
 #define KVM_ARM_IRQ_VCPU_SHIFT         16
 #define KVM_ARM_IRQ_VCPU_MASK          0xff
 #define KVM_ARM_IRQ_NUM_SHIFT          0
index 5e3f12d5359e731290e499c0733e9b6fb496158e..5414b6588fbb64571ce502560235e229d658dea9 100644 (file)
@@ -996,6 +996,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_ARM_PTRAUTH_ADDRESS 171
 #define KVM_CAP_ARM_PTRAUTH_GENERIC 172
 #define KVM_CAP_PMU_EVENT_FILTER 173
+#define KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 174
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
index 35a069815baf1a4f970e9707460d677cc0e11907..86c6aa1cb58e2b55a4722ad56aeda13e10b0109e 100644 (file)
@@ -196,6 +196,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_MP_STATE:
        case KVM_CAP_IMMEDIATE_EXIT:
        case KVM_CAP_VCPU_EVENTS:
+       case KVM_CAP_ARM_IRQ_LINE_LAYOUT_2:
                r = 1;
                break;
        case KVM_CAP_ARM_SET_DEVICE_ADDR:
@@ -888,6 +889,7 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
 
        irq_type = (irq >> KVM_ARM_IRQ_TYPE_SHIFT) & KVM_ARM_IRQ_TYPE_MASK;
        vcpu_idx = (irq >> KVM_ARM_IRQ_VCPU_SHIFT) & KVM_ARM_IRQ_VCPU_MASK;
+       vcpu_idx += ((irq >> KVM_ARM_IRQ_VCPU2_SHIFT) & KVM_ARM_IRQ_VCPU2_MASK) * (KVM_ARM_IRQ_VCPU_MASK + 1);
        irq_num = (irq >> KVM_ARM_IRQ_NUM_SHIFT) & KVM_ARM_IRQ_NUM_MASK;
 
        trace_kvm_irq_line(irq_type, vcpu_idx, irq_num, irq_level->level);