aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRusty Russell <rusty.russell@linaro.org>2013-01-20 18:28:11 -0500
committerChristoffer Dall <c.dall@virtualopensystems.com>2013-01-23 13:29:15 -0500
commit4fe21e4c6def3c6a8f609893b4d5c72bc186d0d5 (patch)
treeb470777c1726f41c4d3dd657962ae0c178f9b935 /arch
parentc27581ed32275897651a84043b04ea3ccdd644e0 (diff)
KVM: ARM: VFP userspace interface
We use space #18 for floating point regs. Reviewed-by: Will Deacon <will.deacon@arm.com> Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/include/uapi/asm/kvm.h12
-rw-r--r--arch/arm/kvm/coproc.c178
2 files changed, 190 insertions, 0 deletions
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 71ae27ec0599..bbb6b2328004 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -112,6 +112,18 @@ struct kvm_arch_memory_slot {
112#define KVM_REG_ARM_DEMUX_VAL_MASK 0x00000000000000FF 112#define KVM_REG_ARM_DEMUX_VAL_MASK 0x00000000000000FF
113#define KVM_REG_ARM_DEMUX_VAL_SHIFT 0 113#define KVM_REG_ARM_DEMUX_VAL_SHIFT 0
114 114
115/* VFP registers: we could overload CP10 like ARM does, but that's ugly. */
116#define KVM_REG_ARM_VFP (0x0012 << KVM_REG_ARM_COPROC_SHIFT)
117#define KVM_REG_ARM_VFP_MASK 0x000000000000FFFF
118#define KVM_REG_ARM_VFP_BASE_REG 0x0
119#define KVM_REG_ARM_VFP_FPSID 0x1000
120#define KVM_REG_ARM_VFP_FPSCR 0x1001
121#define KVM_REG_ARM_VFP_MVFR1 0x1006
122#define KVM_REG_ARM_VFP_MVFR0 0x1007
123#define KVM_REG_ARM_VFP_FPEXC 0x1008
124#define KVM_REG_ARM_VFP_FPINST 0x1009
125#define KVM_REG_ARM_VFP_FPINST2 0x100A
126
115 127
116/* KVM_IRQ_LINE irq field index values */ 128/* KVM_IRQ_LINE irq field index values */
117#define KVM_ARM_IRQ_TYPE_SHIFT 24 129#define KVM_ARM_IRQ_TYPE_SHIFT 24
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 1827b643af15..d782638c7ec0 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -26,6 +26,8 @@
26#include <asm/cacheflush.h> 26#include <asm/cacheflush.h>
27#include <asm/cputype.h> 27#include <asm/cputype.h>
28#include <trace/events/kvm.h> 28#include <trace/events/kvm.h>
29#include <asm/vfp.h>
30#include "../vfp/vfpinstr.h"
29 31
30#include "trace.h" 32#include "trace.h"
31#include "coproc.h" 33#include "coproc.h"
@@ -653,6 +655,170 @@ static int demux_c15_set(u64 id, void __user *uaddr)
653 } 655 }
654} 656}
655 657
658#ifdef CONFIG_VFPv3
659static const int vfp_sysregs[] = { KVM_REG_ARM_VFP_FPEXC,
660 KVM_REG_ARM_VFP_FPSCR,
661 KVM_REG_ARM_VFP_FPINST,
662 KVM_REG_ARM_VFP_FPINST2,
663 KVM_REG_ARM_VFP_MVFR0,
664 KVM_REG_ARM_VFP_MVFR1,
665 KVM_REG_ARM_VFP_FPSID };
666
667static unsigned int num_fp_regs(void)
668{
669 if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK) >> MVFR0_A_SIMD_BIT) == 2)
670 return 32;
671 else
672 return 16;
673}
674
675static unsigned int num_vfp_regs(void)
676{
677 /* Normal FP regs + control regs. */
678 return num_fp_regs() + ARRAY_SIZE(vfp_sysregs);
679}
680
681static int copy_vfp_regids(u64 __user *uindices)
682{
683 unsigned int i;
684 const u64 u32reg = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP;
685 const u64 u64reg = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
686
687 for (i = 0; i < num_fp_regs(); i++) {
688 if (put_user((u64reg | KVM_REG_ARM_VFP_BASE_REG) + i,
689 uindices))
690 return -EFAULT;
691 uindices++;
692 }
693
694 for (i = 0; i < ARRAY_SIZE(vfp_sysregs); i++) {
695 if (put_user(u32reg | vfp_sysregs[i], uindices))
696 return -EFAULT;
697 uindices++;
698 }
699
700 return num_vfp_regs();
701}
702
703static int vfp_get_reg(const struct kvm_vcpu *vcpu, u64 id, void __user *uaddr)
704{
705 u32 vfpid = (id & KVM_REG_ARM_VFP_MASK);
706 u32 val;
707
708 /* Fail if we have unknown bits set. */
709 if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK
710 | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1)))
711 return -ENOENT;
712
713 if (vfpid < num_fp_regs()) {
714 if (KVM_REG_SIZE(id) != 8)
715 return -ENOENT;
716 return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpregs[vfpid],
717 id);
718 }
719
720 /* FP control registers are all 32 bit. */
721 if (KVM_REG_SIZE(id) != 4)
722 return -ENOENT;
723
724 switch (vfpid) {
725 case KVM_REG_ARM_VFP_FPEXC:
726 return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpexc, id);
727 case KVM_REG_ARM_VFP_FPSCR:
728 return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpscr, id);
729 case KVM_REG_ARM_VFP_FPINST:
730 return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpinst, id);
731 case KVM_REG_ARM_VFP_FPINST2:
732 return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpinst2, id);
733 case KVM_REG_ARM_VFP_MVFR0:
734 val = fmrx(MVFR0);
735 return reg_to_user(uaddr, &val, id);
736 case KVM_REG_ARM_VFP_MVFR1:
737 val = fmrx(MVFR1);
738 return reg_to_user(uaddr, &val, id);
739 case KVM_REG_ARM_VFP_FPSID:
740 val = fmrx(FPSID);
741 return reg_to_user(uaddr, &val, id);
742 default:
743 return -ENOENT;
744 }
745}
746
747static int vfp_set_reg(struct kvm_vcpu *vcpu, u64 id, const void __user *uaddr)
748{
749 u32 vfpid = (id & KVM_REG_ARM_VFP_MASK);
750 u32 val;
751
752 /* Fail if we have unknown bits set. */
753 if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK
754 | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1)))
755 return -ENOENT;
756
757 if (vfpid < num_fp_regs()) {
758 if (KVM_REG_SIZE(id) != 8)
759 return -ENOENT;
760 return reg_from_user(&vcpu->arch.vfp_guest.fpregs[vfpid],
761 uaddr, id);
762 }
763
764 /* FP control registers are all 32 bit. */
765 if (KVM_REG_SIZE(id) != 4)
766 return -ENOENT;
767
768 switch (vfpid) {
769 case KVM_REG_ARM_VFP_FPEXC:
770 return reg_from_user(&vcpu->arch.vfp_guest.fpexc, uaddr, id);
771 case KVM_REG_ARM_VFP_FPSCR:
772 return reg_from_user(&vcpu->arch.vfp_guest.fpscr, uaddr, id);
773 case KVM_REG_ARM_VFP_FPINST:
774 return reg_from_user(&vcpu->arch.vfp_guest.fpinst, uaddr, id);
775 case KVM_REG_ARM_VFP_FPINST2:
776 return reg_from_user(&vcpu->arch.vfp_guest.fpinst2, uaddr, id);
777 /* These are invariant. */
778 case KVM_REG_ARM_VFP_MVFR0:
779 if (reg_from_user(&val, uaddr, id))
780 return -EFAULT;
781 if (val != fmrx(MVFR0))
782 return -EINVAL;
783 return 0;
784 case KVM_REG_ARM_VFP_MVFR1:
785 if (reg_from_user(&val, uaddr, id))
786 return -EFAULT;
787 if (val != fmrx(MVFR1))
788 return -EINVAL;
789 return 0;
790 case KVM_REG_ARM_VFP_FPSID:
791 if (reg_from_user(&val, uaddr, id))
792 return -EFAULT;
793 if (val != fmrx(FPSID))
794 return -EINVAL;
795 return 0;
796 default:
797 return -ENOENT;
798 }
799}
800#else /* !CONFIG_VFPv3 */
801static unsigned int num_vfp_regs(void)
802{
803 return 0;
804}
805
806static int copy_vfp_regids(u64 __user *uindices)
807{
808 return 0;
809}
810
811static int vfp_get_reg(const struct kvm_vcpu *vcpu, u64 id, void __user *uaddr)
812{
813 return -ENOENT;
814}
815
816static int vfp_set_reg(struct kvm_vcpu *vcpu, u64 id, const void __user *uaddr)
817{
818 return -ENOENT;
819}
820#endif /* !CONFIG_VFPv3 */
821
656int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 822int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
657{ 823{
658 const struct coproc_reg *r; 824 const struct coproc_reg *r;
@@ -661,6 +827,9 @@ int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
661 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) 827 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
662 return demux_c15_get(reg->id, uaddr); 828 return demux_c15_get(reg->id, uaddr);
663 829
830 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_VFP)
831 return vfp_get_reg(vcpu, reg->id, uaddr);
832
664 r = index_to_coproc_reg(vcpu, reg->id); 833 r = index_to_coproc_reg(vcpu, reg->id);
665 if (!r) 834 if (!r)
666 return get_invariant_cp15(reg->id, uaddr); 835 return get_invariant_cp15(reg->id, uaddr);
@@ -677,6 +846,9 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
677 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) 846 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
678 return demux_c15_set(reg->id, uaddr); 847 return demux_c15_set(reg->id, uaddr);
679 848
849 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_VFP)
850 return vfp_set_reg(vcpu, reg->id, uaddr);
851
680 r = index_to_coproc_reg(vcpu, reg->id); 852 r = index_to_coproc_reg(vcpu, reg->id);
681 if (!r) 853 if (!r)
682 return set_invariant_cp15(reg->id, uaddr); 854 return set_invariant_cp15(reg->id, uaddr);
@@ -788,6 +960,7 @@ unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu)
788{ 960{
789 return ARRAY_SIZE(invariant_cp15) 961 return ARRAY_SIZE(invariant_cp15)
790 + num_demux_regs() 962 + num_demux_regs()
963 + num_vfp_regs()
791 + walk_cp15(vcpu, (u64 __user *)NULL); 964 + walk_cp15(vcpu, (u64 __user *)NULL);
792} 965}
793 966
@@ -808,6 +981,11 @@ int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
808 return err; 981 return err;
809 uindices += err; 982 uindices += err;
810 983
984 err = copy_vfp_regids(uindices);
985 if (err < 0)
986 return err;
987 uindices += err;
988
811 return write_demux_regids(uindices); 989 return write_demux_regids(uindices);
812} 990}
813 991