From patchwork Sat Nov 10 15:43:35 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoffer Dall X-Patchwork-Id: 1723971 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 54B933FC8F for ; Sat, 10 Nov 2012 15:43:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752066Ab2KJPnj (ORCPT ); Sat, 10 Nov 2012 10:43:39 -0500 Received: from mail-wg0-f44.google.com ([74.125.82.44]:46098 "EHLO mail-wg0-f44.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752060Ab2KJPni (ORCPT ); Sat, 10 Nov 2012 10:43:38 -0500 Received: by mail-wg0-f44.google.com with SMTP id dr13so3214992wgb.1 for ; Sat, 10 Nov 2012 07:43:36 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=subject:to:from:cc:date:message-id:in-reply-to:references :user-agent:mime-version:content-type:content-transfer-encoding :x-gm-message-state; bh=hFO1zxa3ooBy7UgWbYXHduEnNWRRXpdGnmNrplp55Eo=; b=GcU3g+4dXgVj1SXRfTOMzXme37K9qvg2PbZEmZIJbobMinbmdtkW/QMOzRPAf5K+Zq ufMQexUv9lbk3XRDKL5/79Xj3K20DT4y2d0+17tpUsFemXFYcIwAelh/d90fulZO5Df6 nxh9eB+tsLrd/1nMTb4wiwz4+8zuH7i21iOWp9dnaWkrmg0ljX4JwQFCG/+fYNbipvSf FYYvRJQzUd225lqxN6fyGF7HaKs+R55Xs6DK+jlBXrek+RovzljNorT+CNkzq+/gqCaT XDbfdnlkhKkfgvuOpEd5xys+u/QmpLOR9PVbLC2Gsfl3sa2GdbGC6v/PrGqUlISvYaOe n0bw== Received: by 10.216.218.105 with SMTP id j83mr5444648wep.164.1352562216854; Sat, 10 Nov 2012 07:43:36 -0800 (PST) Received: from [127.0.1.1] (ip1.c116.obr91.cust.comxnet.dk. [87.72.8.103]) by mx.google.com with ESMTPS id az2sm6721300wib.7.2012.11.10.07.43.35 (version=TLSv1/SSLv3 cipher=OTHER); Sat, 10 Nov 2012 07:43:36 -0800 (PST) Subject: [PATCH v4 12/14] KVM: ARM: VFP userspace interface To: kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, kvmarm@lists.cs.columbia.edu From: Christoffer Dall Cc: Rusty Russell , Marcelo Tosatti Date: Sat, 10 Nov 2012 16:43:35 +0100 Message-ID: <20121110154335.2836.50894.stgit@chazy-air> In-Reply-To: <20121110154203.2836.46686.stgit@chazy-air> References: <20121110154203.2836.46686.stgit@chazy-air> User-Agent: StGit/0.15 MIME-Version: 1.0 X-Gm-Message-State: ALoCoQnOHca+uIsiqMw34euUTrHaArvqMe1bJTVDndmSsVLMndau9w0cRcHwzM2cGFrXtHYesImX Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org From: Rusty Russell We use space #18 for floating point regs. Reviewed-by: Marcelo Tosatti Signed-off-by: Rusty Russell Signed-off-by: Christoffer Dall --- Documentation/virtual/kvm/api.txt | 6 + arch/arm/include/uapi/asm/kvm.h | 12 ++ arch/arm/kvm/coproc.c | 178 +++++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index bf8f99c..9ffd702 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1807,6 +1807,12 @@ ARM 64-bit CP15 registers have the following id bit patterns: ARM CCSIDR registers are demultiplexed by CSSELR value: 0x4002 0000 0011 00 +ARM 32-bit VFP control registers have the following id bit patterns: + 0x4002 0000 0012 1 + +ARM 64-bit FP registers have the following id bit patterns: + 0x4002 0000 0012 0 + 4.69 KVM_GET_ONE_REG Capability: KVM_CAP_ONE_REG diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index 78a629c..5142cab 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -88,6 +88,18 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_DEMUX_VAL_MASK 0x00000000000000FF #define KVM_REG_ARM_DEMUX_VAL_SHIFT 0 +/* VFP registers: we could overload CP10 like ARM does, but that's ugly. */ +#define KVM_REG_ARM_VFP (0x0012 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_VFP_MASK 0x000000000000FFFF +#define KVM_REG_ARM_VFP_BASE_REG 0x0 +#define KVM_REG_ARM_VFP_FPSID 0x1000 +#define KVM_REG_ARM_VFP_FPSCR 0x1001 +#define KVM_REG_ARM_VFP_MVFR1 0x1006 +#define KVM_REG_ARM_VFP_MVFR0 0x1007 +#define KVM_REG_ARM_VFP_FPEXC 0x1008 +#define KVM_REG_ARM_VFP_FPINST 0x1009 +#define KVM_REG_ARM_VFP_FPINST2 0x100A + /* KVM_IRQ_LINE irq field index values */ #define KVM_ARM_IRQ_TYPE_SHIFT 24 diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c index 9ce5861..0b9b521 100644 --- a/arch/arm/kvm/coproc.c +++ b/arch/arm/kvm/coproc.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include "../vfp/vfpinstr.h" #include "trace.h" #include "coproc.h" @@ -652,6 +654,170 @@ static int demux_c15_set(u64 id, void __user *uaddr) } } +#ifdef CONFIG_VFPv3 +static const int vfp_sysregs[] = { KVM_REG_ARM_VFP_FPEXC, + KVM_REG_ARM_VFP_FPSCR, + KVM_REG_ARM_VFP_FPINST, + KVM_REG_ARM_VFP_FPINST2, + KVM_REG_ARM_VFP_MVFR0, + KVM_REG_ARM_VFP_MVFR1, + KVM_REG_ARM_VFP_FPSID }; + +static unsigned int num_fp_regs(void) +{ + if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK) >> MVFR0_A_SIMD_BIT) == 2) + return 32; + else + return 16; +} + +static unsigned int num_vfp_regs(void) +{ + /* Normal FP regs + control regs. */ + return num_fp_regs() + ARRAY_SIZE(vfp_sysregs); +} + +static int copy_vfp_regids(u64 __user *uindices) +{ + unsigned int i; + const u64 u32reg = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP; + const u64 u64reg = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP; + + for (i = 0; i < num_fp_regs(); i++) { + if (put_user((u64reg | KVM_REG_ARM_VFP_BASE_REG) + i, + uindices)) + return -EFAULT; + uindices++; + } + + for (i = 0; i < ARRAY_SIZE(vfp_sysregs); i++) { + if (put_user(u32reg | vfp_sysregs[i], uindices)) + return -EFAULT; + uindices++; + } + + return num_vfp_regs(); +} + +static int vfp_get_reg(const struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) +{ + u32 vfpid = (id & KVM_REG_ARM_VFP_MASK); + u32 val; + + /* Fail if we have unknown bits set. */ + if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK + | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1))) + return -ENOENT; + + if (vfpid < num_fp_regs()) { + if (KVM_REG_SIZE(id) != 8) + return -ENOENT; + return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpregs[vfpid], + id); + } + + /* FP control registers are all 32 bit. */ + if (KVM_REG_SIZE(id) != 4) + return -ENOENT; + + switch (vfpid) { + case KVM_REG_ARM_VFP_FPEXC: + return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpexc, id); + case KVM_REG_ARM_VFP_FPSCR: + return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpscr, id); + case KVM_REG_ARM_VFP_FPINST: + return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpinst, id); + case KVM_REG_ARM_VFP_FPINST2: + return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpinst2, id); + case KVM_REG_ARM_VFP_MVFR0: + val = fmrx(MVFR0); + return reg_to_user(uaddr, &val, id); + case KVM_REG_ARM_VFP_MVFR1: + val = fmrx(MVFR1); + return reg_to_user(uaddr, &val, id); + case KVM_REG_ARM_VFP_FPSID: + val = fmrx(FPSID); + return reg_to_user(uaddr, &val, id); + default: + return -ENOENT; + } +} + +static int vfp_set_reg(struct kvm_vcpu *vcpu, u64 id, const void __user *uaddr) +{ + u32 vfpid = (id & KVM_REG_ARM_VFP_MASK); + u32 val; + + /* Fail if we have unknown bits set. */ + if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK + | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1))) + return -ENOENT; + + if (vfpid < num_fp_regs()) { + if (KVM_REG_SIZE(id) != 8) + return -ENOENT; + return reg_from_user(&vcpu->arch.vfp_guest.fpregs[vfpid], + uaddr, id); + } + + /* FP control registers are all 32 bit. */ + if (KVM_REG_SIZE(id) != 4) + return -ENOENT; + + switch (vfpid) { + case KVM_REG_ARM_VFP_FPEXC: + return reg_from_user(&vcpu->arch.vfp_guest.fpexc, uaddr, id); + case KVM_REG_ARM_VFP_FPSCR: + return reg_from_user(&vcpu->arch.vfp_guest.fpscr, uaddr, id); + case KVM_REG_ARM_VFP_FPINST: + return reg_from_user(&vcpu->arch.vfp_guest.fpinst, uaddr, id); + case KVM_REG_ARM_VFP_FPINST2: + return reg_from_user(&vcpu->arch.vfp_guest.fpinst2, uaddr, id); + /* These are invariant. */ + case KVM_REG_ARM_VFP_MVFR0: + if (reg_from_user(&val, uaddr, id)) + return -EFAULT; + if (val != fmrx(MVFR0)) + return -EINVAL; + return 0; + case KVM_REG_ARM_VFP_MVFR1: + if (reg_from_user(&val, uaddr, id)) + return -EFAULT; + if (val != fmrx(MVFR1)) + return -EINVAL; + return 0; + case KVM_REG_ARM_VFP_FPSID: + if (reg_from_user(&val, uaddr, id)) + return -EFAULT; + if (val != fmrx(FPSID)) + return -EINVAL; + return 0; + default: + return -ENOENT; + } +} +#else /* !CONFIG_VFPv3 */ +static unsigned int num_vfp_regs(void) +{ + return 0; +} + +static int copy_vfp_regids(u64 __user *uindices) +{ + return 0; +} + +static int vfp_get_reg(const struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) +{ + return -ENOENT; +} + +static int vfp_set_reg(struct kvm_vcpu *vcpu, u64 id, const void __user *uaddr) +{ + return -ENOENT; +} +#endif /* !CONFIG_VFPv3 */ + int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { const struct coproc_reg *r; @@ -660,6 +826,9 @@ int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) return demux_c15_get(reg->id, uaddr); + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_VFP) + return vfp_get_reg(vcpu, reg->id, uaddr); + r = index_to_coproc_reg(vcpu, reg->id); if (!r) return get_invariant_cp15(reg->id, uaddr); @@ -676,6 +845,9 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) return demux_c15_set(reg->id, uaddr); + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_VFP) + return vfp_set_reg(vcpu, reg->id, uaddr); + r = index_to_coproc_reg(vcpu, reg->id); if (!r) return set_invariant_cp15(reg->id, uaddr); @@ -787,6 +959,7 @@ unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu) { return ARRAY_SIZE(invariant_cp15) + num_demux_regs() + + num_vfp_regs() + walk_cp15(vcpu, (u64 __user *)NULL); } @@ -807,6 +980,11 @@ int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) return err; uindices += err; + err = copy_vfp_regids(uindices); + if (err < 0) + return err; + uindices += err; + return write_demux_regids(uindices); }