aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Hildenbrand <david@redhat.com>2018-02-07 06:46:43 -0500
committerChristian Borntraeger <borntraeger@de.ibm.com>2018-02-20 15:51:28 -0500
commit0e7def5fb0dc53ddbb9f62a497d15f1e11ccdc36 (patch)
tree0f79bbd4a0fc3e2c2cfc12fa494ce110e404bac0
parent1575767ef3cf5326701d2ae3075b7732cbc855e4 (diff)
KVM: s390: provide only a single function for setting the tod (fix SCK)
Right now, SET CLOCK called in the guest does not properly take care of the epoch index, as the call goes via the old kvm_s390_set_tod_clock() interface. So the epoch index is neither reset to 0, if required, nor properly set to e.g. 0xff on negative values. Fix this by providing a single kvm_s390_set_tod_clock() function. Move Multiple-epoch facility handling into it. Signed-off-by: David Hildenbrand <david@redhat.com> Message-Id: <20180207114647.6220-3-david@redhat.com> Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com> Fixes: 8fa1696ea781 ("KVM: s390: Multiple Epoch Facility support") Cc: stable@vger.kernel.org Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r--arch/s390/kvm/kvm-s390.c46
-rw-r--r--arch/s390/kvm/kvm-s390.h5
-rw-r--r--arch/s390/kvm/priv.c9
3 files changed, 22 insertions, 38 deletions
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index b07aa16dcf06..77d7818130db 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -928,12 +928,9 @@ static int kvm_s390_set_tod_ext(struct kvm *kvm, struct kvm_device_attr *attr)
928 if (copy_from_user(&gtod, (void __user *)attr->addr, sizeof(gtod))) 928 if (copy_from_user(&gtod, (void __user *)attr->addr, sizeof(gtod)))
929 return -EFAULT; 929 return -EFAULT;
930 930
931 if (test_kvm_facility(kvm, 139)) 931 if (!test_kvm_facility(kvm, 139) && gtod.epoch_idx)
932 kvm_s390_set_tod_clock_ext(kvm, &gtod);
933 else if (gtod.epoch_idx == 0)
934 kvm_s390_set_tod_clock(kvm, gtod.tod);
935 else
936 return -EINVAL; 932 return -EINVAL;
933 kvm_s390_set_tod_clock(kvm, &gtod);
937 934
938 VM_EVENT(kvm, 3, "SET: TOD extension: 0x%x, TOD base: 0x%llx", 935 VM_EVENT(kvm, 3, "SET: TOD extension: 0x%x, TOD base: 0x%llx",
939 gtod.epoch_idx, gtod.tod); 936 gtod.epoch_idx, gtod.tod);
@@ -958,13 +955,14 @@ static int kvm_s390_set_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
958 955
959static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr) 956static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
960{ 957{
961 u64 gtod; 958 struct kvm_s390_vm_tod_clock gtod = { 0 };
962 959
963 if (copy_from_user(&gtod, (void __user *)attr->addr, sizeof(gtod))) 960 if (copy_from_user(&gtod.tod, (void __user *)attr->addr,
961 sizeof(gtod.tod)))
964 return -EFAULT; 962 return -EFAULT;
965 963
966 kvm_s390_set_tod_clock(kvm, gtod); 964 kvm_s390_set_tod_clock(kvm, &gtod);
967 VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx", gtod); 965 VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx", gtod.tod);
968 return 0; 966 return 0;
969} 967}
970 968
@@ -3048,8 +3046,8 @@ retry:
3048 return 0; 3046 return 0;
3049} 3047}
3050 3048
3051void kvm_s390_set_tod_clock_ext(struct kvm *kvm, 3049void kvm_s390_set_tod_clock(struct kvm *kvm,
3052 const struct kvm_s390_vm_tod_clock *gtod) 3050 const struct kvm_s390_vm_tod_clock *gtod)
3053{ 3051{
3054 struct kvm_vcpu *vcpu; 3052 struct kvm_vcpu *vcpu;
3055 struct kvm_s390_tod_clock_ext htod; 3053 struct kvm_s390_tod_clock_ext htod;
@@ -3061,10 +3059,12 @@ void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
3061 get_tod_clock_ext((char *)&htod); 3059 get_tod_clock_ext((char *)&htod);
3062 3060
3063 kvm->arch.epoch = gtod->tod - htod.tod; 3061 kvm->arch.epoch = gtod->tod - htod.tod;
3064 kvm->arch.epdx = gtod->epoch_idx - htod.epoch_idx; 3062 kvm->arch.epdx = 0;
3065 3063 if (test_kvm_facility(kvm, 139)) {
3066 if (kvm->arch.epoch > gtod->tod) 3064 kvm->arch.epdx = gtod->epoch_idx - htod.epoch_idx;
3067 kvm->arch.epdx -= 1; 3065 if (kvm->arch.epoch > gtod->tod)
3066 kvm->arch.epdx -= 1;
3067 }
3068 3068
3069 kvm_s390_vcpu_block_all(kvm); 3069 kvm_s390_vcpu_block_all(kvm);
3070 kvm_for_each_vcpu(i, vcpu, kvm) { 3070 kvm_for_each_vcpu(i, vcpu, kvm) {
@@ -3077,22 +3077,6 @@ void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
3077 mutex_unlock(&kvm->lock); 3077 mutex_unlock(&kvm->lock);
3078} 3078}
3079 3079
3080void kvm_s390_set_tod_clock(struct kvm *kvm, u64 tod)
3081{
3082 struct kvm_vcpu *vcpu;
3083 int i;
3084
3085 mutex_lock(&kvm->lock);
3086 preempt_disable();
3087 kvm->arch.epoch = tod - get_tod_clock();
3088 kvm_s390_vcpu_block_all(kvm);
3089 kvm_for_each_vcpu(i, vcpu, kvm)
3090 vcpu->arch.sie_block->epoch = kvm->arch.epoch;
3091 kvm_s390_vcpu_unblock_all(kvm);
3092 preempt_enable();
3093 mutex_unlock(&kvm->lock);
3094}
3095
3096/** 3080/**
3097 * kvm_arch_fault_in_page - fault-in guest page if necessary 3081 * kvm_arch_fault_in_page - fault-in guest page if necessary
3098 * @vcpu: The corresponding virtual cpu 3082 * @vcpu: The corresponding virtual cpu
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 3c0a975c2477..f55ac0ef99ea 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -281,9 +281,8 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
281int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu); 281int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
282 282
283/* implemented in kvm-s390.c */ 283/* implemented in kvm-s390.c */
284void kvm_s390_set_tod_clock_ext(struct kvm *kvm, 284void kvm_s390_set_tod_clock(struct kvm *kvm,
285 const struct kvm_s390_vm_tod_clock *gtod); 285 const struct kvm_s390_vm_tod_clock *gtod);
286void kvm_s390_set_tod_clock(struct kvm *kvm, u64 tod);
287long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable); 286long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable);
288int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr); 287int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr);
289int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr); 288int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr);
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index a74578cdd3f3..f0b4185158af 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -85,9 +85,10 @@ int kvm_s390_handle_e3(struct kvm_vcpu *vcpu)
85/* Handle SCK (SET CLOCK) interception */ 85/* Handle SCK (SET CLOCK) interception */
86static int handle_set_clock(struct kvm_vcpu *vcpu) 86static int handle_set_clock(struct kvm_vcpu *vcpu)
87{ 87{
88 struct kvm_s390_vm_tod_clock gtod = { 0 };
88 int rc; 89 int rc;
89 u8 ar; 90 u8 ar;
90 u64 op2, val; 91 u64 op2;
91 92
92 vcpu->stat.instruction_sck++; 93 vcpu->stat.instruction_sck++;
93 94
@@ -97,12 +98,12 @@ static int handle_set_clock(struct kvm_vcpu *vcpu)
97 op2 = kvm_s390_get_base_disp_s(vcpu, &ar); 98 op2 = kvm_s390_get_base_disp_s(vcpu, &ar);
98 if (op2 & 7) /* Operand must be on a doubleword boundary */ 99 if (op2 & 7) /* Operand must be on a doubleword boundary */
99 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 100 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
100 rc = read_guest(vcpu, op2, ar, &val, sizeof(val)); 101 rc = read_guest(vcpu, op2, ar, &gtod.tod, sizeof(gtod.tod));
101 if (rc) 102 if (rc)
102 return kvm_s390_inject_prog_cond(vcpu, rc); 103 return kvm_s390_inject_prog_cond(vcpu, rc);
103 104
104 VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", val); 105 VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", gtod.tod);
105 kvm_s390_set_tod_clock(vcpu->kvm, val); 106 kvm_s390_set_tod_clock(vcpu->kvm, &gtod);
106 107
107 kvm_s390_set_psw_cc(vcpu, 0); 108 kvm_s390_set_psw_cc(vcpu, 0);
108 return 0; 109 return 0;