diff options
author | Rusty Russell <rusty.russell@linaro.org> | 2013-01-20 18:28:11 -0500 |
---|---|---|
committer | Christoffer Dall <c.dall@virtualopensystems.com> | 2013-01-23 13:29:15 -0500 |
commit | 4fe21e4c6def3c6a8f609893b4d5c72bc186d0d5 (patch) | |
tree | b470777c1726f41c4d3dd657962ae0c178f9b935 /arch | |
parent | c27581ed32275897651a84043b04ea3ccdd644e0 (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.h | 12 | ||||
-rw-r--r-- | arch/arm/kvm/coproc.c | 178 |
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 | ||
659 | static 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 | |||
667 | static 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 | |||
675 | static unsigned int num_vfp_regs(void) | ||
676 | { | ||
677 | /* Normal FP regs + control regs. */ | ||
678 | return num_fp_regs() + ARRAY_SIZE(vfp_sysregs); | ||
679 | } | ||
680 | |||
681 | static 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 | |||
703 | static 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 | |||
747 | static 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 */ | ||
801 | static unsigned int num_vfp_regs(void) | ||
802 | { | ||
803 | return 0; | ||
804 | } | ||
805 | |||
806 | static int copy_vfp_regids(u64 __user *uindices) | ||
807 | { | ||
808 | return 0; | ||
809 | } | ||
810 | |||
811 | static int vfp_get_reg(const struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) | ||
812 | { | ||
813 | return -ENOENT; | ||
814 | } | ||
815 | |||
816 | static int vfp_set_reg(struct kvm_vcpu *vcpu, u64 id, const void __user *uaddr) | ||
817 | { | ||
818 | return -ENOENT; | ||
819 | } | ||
820 | #endif /* !CONFIG_VFPv3 */ | ||
821 | |||
656 | int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) | 822 | int 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 | ||