[RFC PATCH 37/45] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
From: andre.przywara@arm.com (Andre Przywara)
Date: 2016-03-25 02:05:00
Also in:
kvm, kvmarm
Subsystem:
kernel virtual machine (kvm), the rest · Maintainers:
Paolo Bonzini, Linus Torvalds
Signed-off-by: Andre Przywara <andre.przywara@arm.com> --- virt/kvm/arm/vgic/vgic_kvm_device.c | 72 ++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-)
diff --git a/virt/kvm/arm/vgic/vgic_kvm_device.c b/virt/kvm/arm/vgic/vgic_kvm_device.c
index 2e2f8b6..7f78a16 100644
--- a/virt/kvm/arm/vgic/vgic_kvm_device.c
+++ b/virt/kvm/arm/vgic/vgic_kvm_device.c@@ -17,8 +17,11 @@ #include <kvm/vgic/vgic.h> #include <linux/uaccess.h> #include <asm/kvm_mmu.h> +#include <linux/irqchip/arm-gic.h> #include "vgic.h" +#define GICC_ARCH_VERSION_V2 0x2 + /* common helpers */ static int vgic_ioaddr_overlap(struct kvm *kvm)
@@ -252,6 +255,69 @@ void kvm_register_vgic_device(unsigned long type) } } +static u32 vgic_read_vcpuif(struct kvm_vcpu *vcpu, int offset) +{ + struct vgic_vmcr vmcr; + u32 *field; + + switch (offset) { + case GIC_CPU_CTRL: + field = &vmcr.ctlr; + break; + case GIC_CPU_PRIMASK: + field = &vmcr.pmr; + break; + case GIC_CPU_BINPOINT: + field = &vmcr.bpr; + break; + case GIC_CPU_ALIAS_BINPOINT: + field = &vmcr.abpr; + break; + case GIC_CPU_IDENT: + return (PRODUCT_ID_KVM << 20) | + (GICC_ARCH_VERSION_V2 << 16) | + (IMPLEMENTER_ARM << 0); + default: + return 0; + } + + vgic_get_vmcr(vcpu, &vmcr); + + return *field; +} + +static bool vgic_write_vcpuif(struct kvm_vcpu *vcpu, int offset, u32 value) +{ + struct vgic_vmcr vmcr; + u32 *field; + + switch (offset) { + case GIC_CPU_CTRL: + field = &vmcr.ctlr; + break; + case GIC_CPU_PRIMASK: + field = &vmcr.pmr; + break; + case GIC_CPU_BINPOINT: + field = &vmcr.bpr; + break; + case GIC_CPU_ALIAS_BINPOINT: + field = &vmcr.abpr; + break; + default: + return false; + } + + vgic_get_vmcr(vcpu, &vmcr); + if (*field == value) + return false; + + *field = value; + vgic_set_vmcr(vcpu, &vmcr); + + return true; +} + /** vgic_attr_regs_access: allows user space to read/write VGIC registers * * @dev: kvm device handle
@@ -300,7 +366,11 @@ static int vgic_attr_regs_access(struct kvm_device *dev, switch (attr->group) { case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: - ret = -EINVAL; + ret = 0; + if (is_write) + vgic_write_vcpuif(vcpu, addr, *reg); + else + *reg = vgic_read_vcpuif(vcpu, addr); break; case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: ret = vgic_v2_dist_access(vcpu, is_write, addr, 4, reg);
--
2.7.3