Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: arm64: nv: Allow userland to set VGIC maintenance IRQ

The VGIC maintenance IRQ signals various conditions about the LRs, when
the GIC's virtualization extension is used.
So far we didn't need it, but nested virtualization needs to know about
this interrupt, so add a userland interface to setup the IRQ number.
The architecture mandates that it must be a PPI, on top of that this code
only exports a per-device option, so the PPI is the same on all VCPUs.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
[added some bits of documentation]
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250225172930.1850838-16-maz@kernel.org
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>

authored by

Andre Przywara and committed by
Oliver Upton
faf7714a 89896cc1

+40 -3
+11 -1
Documentation/virt/kvm/devices/arm-vgic-v3.rst
··· 291 291 | Aff3 | Aff2 | Aff1 | Aff0 | 292 292 293 293 Errors: 294 - 295 294 ======= ============================================= 296 295 -EINVAL vINTID is not multiple of 32 or info field is 297 296 not VGIC_LEVEL_INFO_LINE_LEVEL 298 297 ======= ============================================= 298 + 299 + KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ 300 + Attributes: 301 + 302 + The attr field of kvm_device_attr encodes the following values: 303 + 304 + bits: | 31 .... 5 | 4 .... 0 | 305 + values: | RES0 | vINTID | 306 + 307 + The vINTID specifies which interrupt is generated when the vGIC 308 + must generate a maintenance interrupt. This must be a PPI.
+1
arch/arm64/include/uapi/asm/kvm.h
··· 403 403 #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 404 404 #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 405 405 #define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8 406 + #define KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ 9 406 407 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 407 408 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ 408 409 (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
+27 -2
arch/arm64/kvm/vgic/vgic-kvm-device.c
··· 303 303 VGIC_NR_PRIVATE_IRQS, uaddr); 304 304 break; 305 305 } 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 + } 306 312 } 307 313 308 314 return r; ··· 523 517 struct vgic_reg_attr reg_attr; 524 518 gpa_t addr; 525 519 struct kvm_vcpu *vcpu; 526 - bool uaccess; 520 + bool uaccess, post_init = true; 527 521 u32 val; 528 522 int ret; 529 523 ··· 539 533 /* Sysregs uaccess is performed by the sysreg handling code */ 540 534 uaccess = false; 541 535 break; 536 + case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ: 537 + post_init = false; 538 + fallthrough; 542 539 default: 543 540 uaccess = true; 544 541 } ··· 561 552 562 553 mutex_lock(&dev->kvm->arch.config_lock); 563 554 564 - if (unlikely(!vgic_initialized(dev->kvm))) { 555 + if (post_init != vgic_initialized(dev->kvm)) { 565 556 ret = -EBUSY; 566 557 goto out; 567 558 } ··· 591 582 } 592 583 break; 593 584 } 585 + case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ: 586 + if (!is_write) { 587 + val = dev->kvm->arch.vgic.mi_intid; 588 + ret = 0; 589 + break; 590 + } 591 + 592 + ret = -EINVAL; 593 + if ((val < VGIC_NR_PRIVATE_IRQS) && (val >= VGIC_NR_SGIS)) { 594 + dev->kvm->arch.vgic.mi_intid = val; 595 + ret = 0; 596 + } 597 + break; 594 598 default: 595 599 ret = -EINVAL; 596 600 break; ··· 630 608 case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: 631 609 case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: 632 610 case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: 611 + case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ: 633 612 return vgic_v3_attr_regs_access(dev, attr, true); 634 613 default: 635 614 return vgic_set_common_attr(dev, attr); ··· 645 622 case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: 646 623 case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: 647 624 case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: 625 + case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ: 648 626 return vgic_v3_attr_regs_access(dev, attr, false); 649 627 default: 650 628 return vgic_get_common_attr(dev, attr); ··· 669 645 case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: 670 646 return vgic_v3_has_attr_regs(dev, attr); 671 647 case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: 648 + case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ: 672 649 return 0; 673 650 case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { 674 651 if (((attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
+1
tools/arch/arm/include/uapi/asm/kvm.h
··· 246 246 #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 247 247 #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 248 248 #define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8 249 + #define KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ 9 249 250 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 250 251 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ 251 252 (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)