KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
authorAndre Przywara <andre.przywara@arm.com>
Thu, 3 Dec 2015 11:48:42 +0000 (11:48 +0000)
committerChristoffer Dall <christoffer.dall@linaro.org>
Fri, 20 May 2016 13:40:05 +0000 (15:40 +0200)
Using the VMCR accessors we provide access to GIC CPU interface state
to userland by wiring it up to the existing userland interface.
[Marc: move and make VMCR accessors static, streamline MMIO handlers]

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
virt/kvm/arm/vgic/vgic-kvm-device.c
virt/kvm/arm/vgic/vgic-mmio-v2.c
virt/kvm/arm/vgic/vgic.h

index 9ee27cb5842b8acc220cd33f95f864ec480bfa94..0130c4b147b7db5c080f01ef395bab611e92b714 100644 (file)
@@ -274,7 +274,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
 
        switch (attr->group) {
        case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
-               ret = -EINVAL;
+               ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
                break;
        case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
                ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
index a25512212bc7f1df0abb5ec0280a66f0f33d17d2..a21393637e4b9b25cae9ee038dcfe4f39d1999c7 100644 (file)
@@ -204,6 +204,84 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
        }
 }
 
+static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+       if (kvm_vgic_global_state.type == VGIC_V2)
+               vgic_v2_set_vmcr(vcpu, vmcr);
+       else
+               vgic_v3_set_vmcr(vcpu, vmcr);
+}
+
+static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+       if (kvm_vgic_global_state.type == VGIC_V2)
+               vgic_v2_get_vmcr(vcpu, vmcr);
+       else
+               vgic_v3_get_vmcr(vcpu, vmcr);
+}
+
+#define GICC_ARCH_VERSION_V2   0x2
+
+/* These are for userland accesses only, there is no guest-facing emulation. */
+static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
+                                          gpa_t addr, unsigned int len)
+{
+       struct vgic_vmcr vmcr;
+       u32 val;
+
+       vgic_get_vmcr(vcpu, &vmcr);
+
+       switch (addr & 0xff) {
+       case GIC_CPU_CTRL:
+               val = vmcr.ctlr;
+               break;
+       case GIC_CPU_PRIMASK:
+               val = vmcr.pmr;
+               break;
+       case GIC_CPU_BINPOINT:
+               val = vmcr.bpr;
+               break;
+       case GIC_CPU_ALIAS_BINPOINT:
+               val = vmcr.abpr;
+               break;
+       case GIC_CPU_IDENT:
+               val = ((PRODUCT_ID_KVM << 20) |
+                      (GICC_ARCH_VERSION_V2 << 16) |
+                      IMPLEMENTER_ARM);
+               break;
+       default:
+               return 0;
+       }
+
+       return val;
+}
+
+static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
+                                  gpa_t addr, unsigned int len,
+                                  unsigned long val)
+{
+       struct vgic_vmcr vmcr;
+
+       vgic_get_vmcr(vcpu, &vmcr);
+
+       switch (addr & 0xff) {
+       case GIC_CPU_CTRL:
+               vmcr.ctlr = val;
+               break;
+       case GIC_CPU_PRIMASK:
+               vmcr.pmr = val;
+               break;
+       case GIC_CPU_BINPOINT:
+               vmcr.bpr = val;
+               break;
+       case GIC_CPU_ALIAS_BINPOINT:
+               vmcr.abpr = val;
+               break;
+       }
+
+       vgic_set_vmcr(vcpu, &vmcr);
+}
+
 static const struct vgic_register_region vgic_v2_dist_registers[] = {
        REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
                vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12,
@@ -249,6 +327,27 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
                VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
 };
 
+static const struct vgic_register_region vgic_v2_cpu_registers[] = {
+       REGISTER_DESC_WITH_LENGTH(GIC_CPU_CTRL,
+               vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4,
+               VGIC_ACCESS_32bit),
+       REGISTER_DESC_WITH_LENGTH(GIC_CPU_PRIMASK,
+               vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4,
+               VGIC_ACCESS_32bit),
+       REGISTER_DESC_WITH_LENGTH(GIC_CPU_BINPOINT,
+               vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4,
+               VGIC_ACCESS_32bit),
+       REGISTER_DESC_WITH_LENGTH(GIC_CPU_ALIAS_BINPOINT,
+               vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4,
+               VGIC_ACCESS_32bit),
+       REGISTER_DESC_WITH_LENGTH(GIC_CPU_ACTIVEPRIO,
+               vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
+               VGIC_ACCESS_32bit),
+       REGISTER_DESC_WITH_LENGTH(GIC_CPU_IDENT,
+               vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4,
+               VGIC_ACCESS_32bit),
+};
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
 {
        dev->regions = vgic_v2_dist_registers;
@@ -274,7 +373,9 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
                nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
                break;
        case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
-               return -ENXIO;          /* TODO: describe CPU i/f regs also */
+               regions = vgic_v2_cpu_registers;
+               nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers);
+               break;
        default:
                return -ENXIO;
        }
@@ -322,6 +423,17 @@ static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
        return ret;
 }
 
+int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+                         int offset, u32 *val)
+{
+       struct vgic_io_device dev = {
+               .regions = vgic_v2_cpu_registers,
+               .nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers),
+       };
+
+       return vgic_uaccess(vcpu, &dev, is_write, offset, val);
+}
+
 int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
                         int offset, u32 *val)
 {
index d2c1fd5a795f896b6509b3be0408bd6527a9ed11..de9dc7170c1b1e27a0a53676b9e4432b9fc3d44e 100644 (file)
@@ -47,6 +47,8 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
                         int offset, u32 *val);
+int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+                         int offset, u32 *val);
 void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,