diff options
author | Jason J. Herne <jjherne@linux.vnet.ibm.com> | 2014-09-23 09:23:01 -0400 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2015-03-17 11:33:06 -0400 |
commit | 30ee2a984f07b00895e0e01d78859b3aff9307c7 (patch) | |
tree | ee5c8b449a7030653bccb4829df374f969840328 /arch/s390 | |
parent | e44fc8c9dab215ac0e398622a05574cffd5f5184 (diff) |
KVM: s390: Create ioctl for Getting/Setting guest storage keys
Provide the KVM_S390_GET_SKEYS and KVM_S390_SET_SKEYS ioctl which can be used
to get/set guest storage keys. This functionality is needed for live migration
of s390 guests that use storage keys.
Signed-off-by: Jason J. Herne <jjherne@linux.vnet.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index fdfa10662700..0dc22baa0a57 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -179,6 +179,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) | |||
179 | case KVM_CAP_MP_STATE: | 179 | case KVM_CAP_MP_STATE: |
180 | case KVM_CAP_S390_USER_SIGP: | 180 | case KVM_CAP_S390_USER_SIGP: |
181 | case KVM_CAP_S390_USER_STSI: | 181 | case KVM_CAP_S390_USER_STSI: |
182 | case KVM_CAP_S390_SKEYS: | ||
182 | r = 1; | 183 | r = 1; |
183 | break; | 184 | break; |
184 | case KVM_CAP_S390_MEM_OP: | 185 | case KVM_CAP_S390_MEM_OP: |
@@ -729,6 +730,108 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) | |||
729 | return ret; | 730 | return ret; |
730 | } | 731 | } |
731 | 732 | ||
733 | static long kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args) | ||
734 | { | ||
735 | uint8_t *keys; | ||
736 | uint64_t hva; | ||
737 | unsigned long curkey; | ||
738 | int i, r = 0; | ||
739 | |||
740 | if (args->flags != 0) | ||
741 | return -EINVAL; | ||
742 | |||
743 | /* Is this guest using storage keys? */ | ||
744 | if (!mm_use_skey(current->mm)) | ||
745 | return KVM_S390_GET_SKEYS_NONE; | ||
746 | |||
747 | /* Enforce sane limit on memory allocation */ | ||
748 | if (args->count < 1 || args->count > KVM_S390_SKEYS_MAX) | ||
749 | return -EINVAL; | ||
750 | |||
751 | keys = kmalloc_array(args->count, sizeof(uint8_t), | ||
752 | GFP_KERNEL | __GFP_NOWARN); | ||
753 | if (!keys) | ||
754 | keys = vmalloc(sizeof(uint8_t) * args->count); | ||
755 | if (!keys) | ||
756 | return -ENOMEM; | ||
757 | |||
758 | for (i = 0; i < args->count; i++) { | ||
759 | hva = gfn_to_hva(kvm, args->start_gfn + i); | ||
760 | if (kvm_is_error_hva(hva)) { | ||
761 | r = -EFAULT; | ||
762 | goto out; | ||
763 | } | ||
764 | |||
765 | curkey = get_guest_storage_key(current->mm, hva); | ||
766 | if (IS_ERR_VALUE(curkey)) { | ||
767 | r = curkey; | ||
768 | goto out; | ||
769 | } | ||
770 | keys[i] = curkey; | ||
771 | } | ||
772 | |||
773 | r = copy_to_user((uint8_t __user *)args->skeydata_addr, keys, | ||
774 | sizeof(uint8_t) * args->count); | ||
775 | if (r) | ||
776 | r = -EFAULT; | ||
777 | out: | ||
778 | kvfree(keys); | ||
779 | return r; | ||
780 | } | ||
781 | |||
782 | static long kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args) | ||
783 | { | ||
784 | uint8_t *keys; | ||
785 | uint64_t hva; | ||
786 | int i, r = 0; | ||
787 | |||
788 | if (args->flags != 0) | ||
789 | return -EINVAL; | ||
790 | |||
791 | /* Enforce sane limit on memory allocation */ | ||
792 | if (args->count < 1 || args->count > KVM_S390_SKEYS_MAX) | ||
793 | return -EINVAL; | ||
794 | |||
795 | keys = kmalloc_array(args->count, sizeof(uint8_t), | ||
796 | GFP_KERNEL | __GFP_NOWARN); | ||
797 | if (!keys) | ||
798 | keys = vmalloc(sizeof(uint8_t) * args->count); | ||
799 | if (!keys) | ||
800 | return -ENOMEM; | ||
801 | |||
802 | r = copy_from_user(keys, (uint8_t __user *)args->skeydata_addr, | ||
803 | sizeof(uint8_t) * args->count); | ||
804 | if (r) { | ||
805 | r = -EFAULT; | ||
806 | goto out; | ||
807 | } | ||
808 | |||
809 | /* Enable storage key handling for the guest */ | ||
810 | s390_enable_skey(); | ||
811 | |||
812 | for (i = 0; i < args->count; i++) { | ||
813 | hva = gfn_to_hva(kvm, args->start_gfn + i); | ||
814 | if (kvm_is_error_hva(hva)) { | ||
815 | r = -EFAULT; | ||
816 | goto out; | ||
817 | } | ||
818 | |||
819 | /* Lowest order bit is reserved */ | ||
820 | if (keys[i] & 0x01) { | ||
821 | r = -EINVAL; | ||
822 | goto out; | ||
823 | } | ||
824 | |||
825 | r = set_guest_storage_key(current->mm, hva, | ||
826 | (unsigned long)keys[i], 0); | ||
827 | if (r) | ||
828 | goto out; | ||
829 | } | ||
830 | out: | ||
831 | kvfree(keys); | ||
832 | return r; | ||
833 | } | ||
834 | |||
732 | long kvm_arch_vm_ioctl(struct file *filp, | 835 | long kvm_arch_vm_ioctl(struct file *filp, |
733 | unsigned int ioctl, unsigned long arg) | 836 | unsigned int ioctl, unsigned long arg) |
734 | { | 837 | { |
@@ -788,6 +891,26 @@ long kvm_arch_vm_ioctl(struct file *filp, | |||
788 | r = kvm_s390_vm_has_attr(kvm, &attr); | 891 | r = kvm_s390_vm_has_attr(kvm, &attr); |
789 | break; | 892 | break; |
790 | } | 893 | } |
894 | case KVM_S390_GET_SKEYS: { | ||
895 | struct kvm_s390_skeys args; | ||
896 | |||
897 | r = -EFAULT; | ||
898 | if (copy_from_user(&args, argp, | ||
899 | sizeof(struct kvm_s390_skeys))) | ||
900 | break; | ||
901 | r = kvm_s390_get_skeys(kvm, &args); | ||
902 | break; | ||
903 | } | ||
904 | case KVM_S390_SET_SKEYS: { | ||
905 | struct kvm_s390_skeys args; | ||
906 | |||
907 | r = -EFAULT; | ||
908 | if (copy_from_user(&args, argp, | ||
909 | sizeof(struct kvm_s390_skeys))) | ||
910 | break; | ||
911 | r = kvm_s390_set_skeys(kvm, &args); | ||
912 | break; | ||
913 | } | ||
791 | default: | 914 | default: |
792 | r = -ENOTTY; | 915 | r = -ENOTTY; |
793 | } | 916 | } |