aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorJason J. Herne <jjherne@linux.vnet.ibm.com>2014-09-23 09:23:01 -0400
committerChristian Borntraeger <borntraeger@de.ibm.com>2015-03-17 11:33:06 -0400
commit30ee2a984f07b00895e0e01d78859b3aff9307c7 (patch)
treeee5c8b449a7030653bccb4829df374f969840328 /arch/s390
parente44fc8c9dab215ac0e398622a05574cffd5f5184 (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.c123
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
733static 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;
777out:
778 kvfree(keys);
779 return r;
780}
781
782static 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 }
830out:
831 kvfree(keys);
832 return r;
833}
834
732long kvm_arch_vm_ioctl(struct file *filp, 835long 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 }