diff options
| -rw-r--r-- | Documentation/virtual/kvm/api.txt | 6 | ||||
| -rw-r--r-- | arch/arm/include/uapi/asm/kvm.h | 12 | ||||
| -rw-r--r-- | arch/arm/kvm/coproc.c | 178 |
3 files changed, 196 insertions, 0 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 94f17a30edd3..38066a7a74e1 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt | |||
| @@ -1808,6 +1808,12 @@ ARM 64-bit CP15 registers have the following id bit patterns: | |||
| 1808 | ARM CCSIDR registers are demultiplexed by CSSELR value: | 1808 | ARM CCSIDR registers are demultiplexed by CSSELR value: |
| 1809 | 0x4002 0000 0011 00 <csselr:8> | 1809 | 0x4002 0000 0011 00 <csselr:8> |
| 1810 | 1810 | ||
| 1811 | ARM 32-bit VFP control registers have the following id bit patterns: | ||
| 1812 | 0x4002 0000 0012 1 <regno:12> | ||
| 1813 | |||
| 1814 | ARM 64-bit FP registers have the following id bit patterns: | ||
| 1815 | 0x4002 0000 0012 0 <regno:12> | ||
| 1816 | |||
| 1811 | 4.69 KVM_GET_ONE_REG | 1817 | 4.69 KVM_GET_ONE_REG |
| 1812 | 1818 | ||
| 1813 | Capability: KVM_CAP_ONE_REG | 1819 | Capability: KVM_CAP_ONE_REG |
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 | ||
