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

KVM: arm-vgic: Add vgic reg access from dev attr

Add infrastructure to handle distributor and cpu interface register
accesses through the KVM_{GET/SET}_DEVICE_ATTR interface by adding the
KVM_DEV_ARM_VGIC_GRP_DIST_REGS and KVM_DEV_ARM_VGIC_GRP_CPU_REGS groups
and defining the semantics of the attr field to be the MMIO offset as
specified in the GICv2 specs.

Missing register accesses or other changes in individual register access
functions to support save/restore of the VGIC state is added in
subsequent patches.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

+236
+52
Documentation/virtual/kvm/devices/arm-vgic.txt
··· 19 19 KVM_VGIC_V2_ADDR_TYPE_CPU (rw, 64-bit) 20 20 Base address in the guest physical address space of the GIC virtual cpu 21 21 interface register mappings. 22 + 23 + KVM_DEV_ARM_VGIC_GRP_DIST_REGS 24 + Attributes: 25 + The attr field of kvm_device_attr encodes two values: 26 + bits: | 63 .... 40 | 39 .. 32 | 31 .... 0 | 27 + values: | reserved | cpu id | offset | 28 + 29 + All distributor regs are (rw, 32-bit) 30 + 31 + The offset is relative to the "Distributor base address" as defined in the 32 + GICv2 specs. Getting or setting such a register has the same effect as 33 + reading or writing the register on the actual hardware from the cpu 34 + specified with cpu id field. Note that most distributor fields are not 35 + banked, but return the same value regardless of the cpu id used to access 36 + the register. 37 + Limitations: 38 + - Priorities are not implemented, and registers are RAZ/WI 39 + Errors: 40 + -ENODEV: Getting or setting this register is not yet supported 41 + -EBUSY: One or more VCPUs are running 42 + 43 + KVM_DEV_ARM_VGIC_GRP_CPU_REGS 44 + Attributes: 45 + The attr field of kvm_device_attr encodes two values: 46 + bits: | 63 .... 40 | 39 .. 32 | 31 .... 0 | 47 + values: | reserved | cpu id | offset | 48 + 49 + All CPU interface regs are (rw, 32-bit) 50 + 51 + The offset specifies the offset from the "CPU interface base address" as 52 + defined in the GICv2 specs. Getting or setting such a register has the 53 + same effect as reading or writing the register on the actual hardware. 54 + 55 + The Active Priorities Registers APRn are implementation defined, so we set a 56 + fixed format for our implementation that fits with the model of a "GICv2 57 + implementation without the security extensions" which we present to the 58 + guest. This interface always exposes four register APR[0-3] describing the 59 + maximum possible 128 preemption levels. The semantics of the register 60 + indicate if any interrupts in a given preemption level are in the active 61 + state by setting the corresponding bit. 62 + 63 + Thus, preemption level X has one or more active interrupts if and only if: 64 + 65 + APRn[X mod 32] == 0b1, where n = X / 32 66 + 67 + Bits for undefined preemption levels are RAZ/WI. 68 + 69 + Limitations: 70 + - Priorities are not implemented, and registers are RAZ/WI 71 + Errors: 72 + -ENODEV: Getting or setting this register is not yet supported 73 + -EBUSY: One or more VCPUs are running
+6
arch/arm/include/uapi/asm/kvm.h
··· 165 165 166 166 /* Device Control API: ARM VGIC */ 167 167 #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 168 + #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 169 + #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 170 + #define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 171 + #define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) 172 + #define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 173 + #define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) 168 174 169 175 /* KVM_IRQ_LINE irq field index values */ 170 176 #define KVM_ARM_IRQ_TYPE_SHIFT 24
+178
virt/kvm/arm/vgic.c
··· 589 589 return false; 590 590 } 591 591 592 + static bool handle_mmio_sgi_clear(struct kvm_vcpu *vcpu, 593 + struct kvm_exit_mmio *mmio, 594 + phys_addr_t offset) 595 + { 596 + return false; 597 + } 598 + 599 + static bool handle_mmio_sgi_set(struct kvm_vcpu *vcpu, 600 + struct kvm_exit_mmio *mmio, 601 + phys_addr_t offset) 602 + { 603 + return false; 604 + } 605 + 592 606 /* 593 607 * I would have liked to use the kvm_bus_io_*() API instead, but it 594 608 * cannot cope with banked registers (only the VM pointer is passed ··· 676 662 .base = GIC_DIST_SOFTINT, 677 663 .len = 4, 678 664 .handle_mmio = handle_mmio_sgi_reg, 665 + }, 666 + { 667 + .base = GIC_DIST_SGI_PENDING_CLEAR, 668 + .len = VGIC_NR_SGIS, 669 + .handle_mmio = handle_mmio_sgi_clear, 670 + }, 671 + { 672 + .base = GIC_DIST_SGI_PENDING_SET, 673 + .len = VGIC_NR_SGIS, 674 + .handle_mmio = handle_mmio_sgi_set, 679 675 }, 680 676 {} 681 677 }; ··· 1581 1557 return r; 1582 1558 } 1583 1559 1560 + static bool handle_cpu_mmio_misc(struct kvm_vcpu *vcpu, 1561 + struct kvm_exit_mmio *mmio, phys_addr_t offset) 1562 + { 1563 + return true; 1564 + } 1565 + 1566 + static const struct mmio_range vgic_cpu_ranges[] = { 1567 + { 1568 + .base = GIC_CPU_CTRL, 1569 + .len = 12, 1570 + .handle_mmio = handle_cpu_mmio_misc, 1571 + }, 1572 + { 1573 + .base = GIC_CPU_ALIAS_BINPOINT, 1574 + .len = 4, 1575 + .handle_mmio = handle_cpu_mmio_misc, 1576 + }, 1577 + { 1578 + .base = GIC_CPU_ACTIVEPRIO, 1579 + .len = 16, 1580 + .handle_mmio = handle_cpu_mmio_misc, 1581 + }, 1582 + { 1583 + .base = GIC_CPU_IDENT, 1584 + .len = 4, 1585 + .handle_mmio = handle_cpu_mmio_misc, 1586 + }, 1587 + }; 1588 + 1589 + static int vgic_attr_regs_access(struct kvm_device *dev, 1590 + struct kvm_device_attr *attr, 1591 + u32 *reg, bool is_write) 1592 + { 1593 + const struct mmio_range *r = NULL, *ranges; 1594 + phys_addr_t offset; 1595 + int ret, cpuid, c; 1596 + struct kvm_vcpu *vcpu, *tmp_vcpu; 1597 + struct vgic_dist *vgic; 1598 + struct kvm_exit_mmio mmio; 1599 + 1600 + offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK; 1601 + cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >> 1602 + KVM_DEV_ARM_VGIC_CPUID_SHIFT; 1603 + 1604 + mutex_lock(&dev->kvm->lock); 1605 + 1606 + if (cpuid >= atomic_read(&dev->kvm->online_vcpus)) { 1607 + ret = -EINVAL; 1608 + goto out; 1609 + } 1610 + 1611 + vcpu = kvm_get_vcpu(dev->kvm, cpuid); 1612 + vgic = &dev->kvm->arch.vgic; 1613 + 1614 + mmio.len = 4; 1615 + mmio.is_write = is_write; 1616 + if (is_write) 1617 + mmio_data_write(&mmio, ~0, *reg); 1618 + switch (attr->group) { 1619 + case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 1620 + mmio.phys_addr = vgic->vgic_dist_base + offset; 1621 + ranges = vgic_dist_ranges; 1622 + break; 1623 + case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: 1624 + mmio.phys_addr = vgic->vgic_cpu_base + offset; 1625 + ranges = vgic_cpu_ranges; 1626 + break; 1627 + default: 1628 + BUG(); 1629 + } 1630 + r = find_matching_range(ranges, &mmio, offset); 1631 + 1632 + if (unlikely(!r || !r->handle_mmio)) { 1633 + ret = -ENXIO; 1634 + goto out; 1635 + } 1636 + 1637 + 1638 + spin_lock(&vgic->lock); 1639 + 1640 + /* 1641 + * Ensure that no other VCPU is running by checking the vcpu->cpu 1642 + * field. If no other VPCUs are running we can safely access the VGIC 1643 + * state, because even if another VPU is run after this point, that 1644 + * VCPU will not touch the vgic state, because it will block on 1645 + * getting the vgic->lock in kvm_vgic_sync_hwstate(). 1646 + */ 1647 + kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm) { 1648 + if (unlikely(tmp_vcpu->cpu != -1)) { 1649 + ret = -EBUSY; 1650 + goto out_vgic_unlock; 1651 + } 1652 + } 1653 + 1654 + offset -= r->base; 1655 + r->handle_mmio(vcpu, &mmio, offset); 1656 + 1657 + if (!is_write) 1658 + *reg = mmio_data_read(&mmio, ~0); 1659 + 1660 + ret = 0; 1661 + out_vgic_unlock: 1662 + spin_unlock(&vgic->lock); 1663 + out: 1664 + mutex_unlock(&dev->kvm->lock); 1665 + return ret; 1666 + } 1667 + 1584 1668 static int vgic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) 1585 1669 { 1586 1670 int r; ··· 1705 1573 r = kvm_vgic_addr(dev->kvm, type, &addr, true); 1706 1574 return (r == -ENODEV) ? -ENXIO : r; 1707 1575 } 1576 + 1577 + case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 1578 + case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: { 1579 + u32 __user *uaddr = (u32 __user *)(long)attr->addr; 1580 + u32 reg; 1581 + 1582 + if (get_user(reg, uaddr)) 1583 + return -EFAULT; 1584 + 1585 + return vgic_attr_regs_access(dev, attr, &reg, true); 1586 + } 1587 + 1708 1588 } 1709 1589 1710 1590 return -ENXIO; ··· 1738 1594 1739 1595 if (copy_to_user(uaddr, &addr, sizeof(addr))) 1740 1596 return -EFAULT; 1597 + break; 1741 1598 } 1599 + 1600 + case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 1601 + case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: { 1602 + u32 __user *uaddr = (u32 __user *)(long)attr->addr; 1603 + u32 reg = 0; 1604 + 1605 + r = vgic_attr_regs_access(dev, attr, &reg, false); 1606 + if (r) 1607 + return r; 1608 + r = put_user(reg, uaddr); 1609 + break; 1610 + } 1611 + 1742 1612 } 1743 1613 1744 1614 return r; 1745 1615 } 1746 1616 1617 + static int vgic_has_attr_regs(const struct mmio_range *ranges, 1618 + phys_addr_t offset) 1619 + { 1620 + struct kvm_exit_mmio dev_attr_mmio; 1621 + 1622 + dev_attr_mmio.len = 4; 1623 + if (find_matching_range(ranges, &dev_attr_mmio, offset)) 1624 + return 0; 1625 + else 1626 + return -ENXIO; 1627 + } 1628 + 1747 1629 static int vgic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr) 1748 1630 { 1631 + phys_addr_t offset; 1632 + 1749 1633 switch (attr->group) { 1750 1634 case KVM_DEV_ARM_VGIC_GRP_ADDR: 1751 1635 switch (attr->attr) { ··· 1782 1610 return 0; 1783 1611 } 1784 1612 break; 1613 + case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 1614 + offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK; 1615 + return vgic_has_attr_regs(vgic_dist_ranges, offset); 1616 + case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: 1617 + offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK; 1618 + return vgic_has_attr_regs(vgic_cpu_ranges, offset); 1785 1619 } 1786 1620 return -ENXIO; 1787 1621 }