From patchwork Tue Sep 18 07:14:49 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Mackerras X-Patchwork-Id: 1471031 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 0788BDF24C for ; Tue, 18 Sep 2012 07:14:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757283Ab2IRHOd (ORCPT ); Tue, 18 Sep 2012 03:14:33 -0400 Received: from ozlabs.org ([203.10.76.45]:41908 "EHLO ozlabs.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756886Ab2IRHOb (ORCPT ); Tue, 18 Sep 2012 03:14:31 -0400 Received: by ozlabs.org (Postfix, from userid 1003) id 4BEBD2C018B; Tue, 18 Sep 2012 17:14:30 +1000 (EST) Date: Tue, 18 Sep 2012 17:14:49 +1000 From: Paul Mackerras To: Alexander Graf Cc: kvm-ppc@vger.kernel.org, kvm@vger.kernel.org Subject: [PATCH v2 2/2] KVM: PPC: Book3S HV: Get/set guest FP regs using the GET/SET_ONE_REG interface Message-ID: <20120918071449.GC12437@bloggs.ozlabs.ibm.com> References: <20120918071301.GA12437@bloggs.ozlabs.ibm.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20120918071301.GA12437@bloggs.ozlabs.ibm.com> User-Agent: Mutt/1.5.21 (2010-09-15) Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org This enables userspace to get and set all the guest floating-point state using the KVM_[GS]ET_ONE_REG ioctls. The floating-point state includes all of the traditional floating-point registers and the FPSCR (floating point status/control register), all the VMX/Altivec vector registers and the VSCR (vector status/control register), and on POWER7, the vector-scalar registers (note that each FP register is the high-order half of the corresponding VSR). Signed-off-by: Paul Mackerras --- Documentation/virtual/kvm/api.txt | 11 ++++ arch/powerpc/include/asm/kvm.h | 20 +++++++ arch/powerpc/kvm/book3s_hv.c | 112 +++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 407556f..a02f0de 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1759,6 +1759,17 @@ registers, find a list below: PPC | KVM_REG_PPC_PMC6 | 32 PPC | KVM_REG_PPC_PMC7 | 32 PPC | KVM_REG_PPC_PMC8 | 32 + PPC | KVM_REG_PPC_FPR0 | 64 + ... + PPC | KVM_REG_PPC_FPR31 | 64 + PPC | KVM_REG_PPC_VR0 | 128 + ... + PPC | KVM_REG_PPC_VR31 | 128 + PPC | KVM_REG_PPC_VSR0 | 128 + ... + PPC | KVM_REG_PPC_VSR31 | 128 + PPC | KVM_REG_PPC_FPSCR | 64 + PPC | KVM_REG_PPC_VSCR | 32 4.69 KVM_GET_ONE_REG diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h index 9557576..1466975 100644 --- a/arch/powerpc/include/asm/kvm.h +++ b/arch/powerpc/include/asm/kvm.h @@ -360,4 +360,24 @@ struct kvm_book3e_206_tlb_params { #define KVM_REG_PPC_PMC7 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1e) #define KVM_REG_PPC_PMC8 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1f) +/* 32 floating-point registers */ +#define KVM_REG_PPC_FPR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x20) +#define KVM_REG_PPC_FPR(n) (KVM_REG_PPC_FPR0 + (n)) +#define KVM_REG_PPC_FPR31 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3f) + +/* 32 VMX/Altivec vector registers */ +#define KVM_REG_PPC_VR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x40) +#define KVM_REG_PPC_VR(n) (KVM_REG_PPC_VR0 + (n)) +#define KVM_REG_PPC_VR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x5f) + +/* 32 double-width FP registers for VSX */ +/* High-order halves overlap with FP regs */ +#define KVM_REG_PPC_VSR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x60) +#define KVM_REG_PPC_VSR(n) (KVM_REG_PPC_VSR0 + (n)) +#define KVM_REG_PPC_VSR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x7f) + +/* FP and vector status/control registers */ +#define KVM_REG_PPC_FPSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x80) +#define KVM_REG_PPC_VSCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x81) + #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index c4b5636..32defa0 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -585,6 +585,54 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) i = reg->id - KVM_REG_PPC_PMC1; r = put_user(vcpu->arch.pmc[i], (u32 __user *)reg->addr); break; + + case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31: + i = reg->id - KVM_REG_PPC_FPR0; +#ifdef CONFIG_VSX + if (cpu_has_feature(CPU_FTR_VSX)) { + /* VSX => FP reg i is stored in arch.vsr[2*i] */ + r = put_user(vcpu->arch.vsr[2 * i], + (u64 __user *)reg->addr); + break; + } +#endif + r = put_user(vcpu->arch.fpr[i], (u64 __user *)reg->addr); + break; + case KVM_REG_PPC_FPSCR: + r = put_user(vcpu->arch.fpscr, (u64 __user *)reg->addr); + break; + +#ifdef CONFIG_ALTIVEC + case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31: + r = -ENXIO; + if (!cpu_has_feature(CPU_FTR_ALTIVEC)) + break; + i = reg->id - KVM_REG_PPC_VR0; + r = -EFAULT; + if (!copy_to_user((char __user *)reg->addr, + &vcpu->arch.vr[i], sizeof(vector128))) + r = 0; + break; + case KVM_REG_PPC_VSCR: + r = -ENXIO; + if (!cpu_has_feature(CPU_FTR_ALTIVEC)) + break; + r = put_user(vcpu->arch.vscr.u[3], (u32 __user *)reg->addr); + break; +#endif + +#ifdef CONFIG_VSX + case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: + r = -ENXIO; + if (!cpu_has_feature(CPU_FTR_VSX)) + break; + i = (reg->id - KVM_REG_PPC_VR0) * 2; + r = -EFAULT; + if (!copy_to_user((char __user *)reg->addr, + &vcpu->arch.vsr[i], 2 * sizeof(u64))) + r = 0; + break; +#endif default: break; } @@ -661,6 +709,70 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) if (!r) vcpu->arch.pmc[i] = wval; break; + + case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31: + i = reg->id - KVM_REG_PPC_FPR0; + r = get_user(val, (u64 __user *)reg->addr); + if (r) + break; +#ifdef CONFIG_VSX + if (cpu_has_feature(CPU_FTR_VSX)) { + /* VSX => FP reg i is stored in arch.vsr[2*i] */ + vcpu->arch.vsr[2 * i] = val; + break; + } +#endif + vcpu->arch.fpr[i] = r; + break; + case KVM_REG_PPC_FPSCR: + r = get_user(val, (u64 __user *)reg->addr); + if (!r) + vcpu->arch.fpscr = val; + break; + +#ifdef CONFIG_ALTIVEC + case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31: { + vector128 tmp; + + r = -ENXIO; + if (!cpu_has_feature(CPU_FTR_ALTIVEC)) + break; + i = reg->id - KVM_REG_PPC_VR0; + r = -EFAULT; + if (copy_from_user(&tmp, (char __user *)reg->addr, + sizeof(vector128))) + break; + r = 0; + vcpu->arch.vr[i] = tmp; + break; + } + case KVM_REG_PPC_VSCR: + r = -ENXIO; + if (!cpu_has_feature(CPU_FTR_ALTIVEC)) + break; + r = get_user(wval, (u32 __user *)reg->addr); + if (!r) + vcpu->arch.vscr.u[3] = wval; + break; +#endif +#ifdef CONFIG_VSX + case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: { + u64 tmp[2]; + + r = -ENXIO; + if (!cpu_has_feature(CPU_FTR_VSX)) + break; + i = (reg->id - KVM_REG_PPC_VSR0) * 2; + r = -EFAULT; + if (copy_from_user(tmp, (char __user *)reg->addr, + 2 * sizeof(u64))) + break; + r = 0; + vcpu->arch.vsr[i] = tmp[0]; + vcpu->arch.vsr[i + 1] = tmp[1]; + break; + } +#endif default: break; }