Skip to content

Commit 0e7def5

Browse files
davidhildenbrandborntraeger
authored andcommitted
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 <[email protected]> Message-Id: <[email protected]> Reviewed-by: Christian Borntraeger <[email protected]> Fixes: 8fa1696 ("KVM: s390: Multiple Epoch Facility support") Cc: [email protected] Signed-off-by: Christian Borntraeger <[email protected]>
1 parent 1575767 commit 0e7def5

File tree

3 files changed

+22
-38
lines changed

3 files changed

+22
-38
lines changed

arch/s390/kvm/kvm-s390.c

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -928,12 +928,9 @@ static int kvm_s390_set_tod_ext(struct kvm *kvm, struct kvm_device_attr *attr)
928928
if (copy_from_user(&gtod, (void __user *)attr->addr, sizeof(gtod)))
929929
return -EFAULT;
930930

931-
if (test_kvm_facility(kvm, 139))
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
931+
if (!test_kvm_facility(kvm, 139) && gtod.epoch_idx)
936932
return -EINVAL;
933+
kvm_s390_set_tod_clock(kvm, &gtod);
937934

938935
VM_EVENT(kvm, 3, "SET: TOD extension: 0x%x, TOD base: 0x%llx",
939936
gtod.epoch_idx, gtod.tod);
@@ -958,13 +955,14 @@ static int kvm_s390_set_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
958955

959956
static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
960957
{
961-
u64 gtod;
958+
struct kvm_s390_vm_tod_clock gtod = { 0 };
962959

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)))
964962
return -EFAULT;
965963

966-
kvm_s390_set_tod_clock(kvm, gtod);
967-
VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx", gtod);
964+
kvm_s390_set_tod_clock(kvm, &gtod);
965+
VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx", gtod.tod);
968966
return 0;
969967
}
970968

@@ -3048,8 +3046,8 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
30483046
return 0;
30493047
}
30503048

3051-
void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
3052-
const struct kvm_s390_vm_tod_clock *gtod)
3049+
void kvm_s390_set_tod_clock(struct kvm *kvm,
3050+
const struct kvm_s390_vm_tod_clock *gtod)
30533051
{
30543052
struct kvm_vcpu *vcpu;
30553053
struct kvm_s390_tod_clock_ext htod;
@@ -3061,10 +3059,12 @@ void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
30613059
get_tod_clock_ext((char *)&htod);
30623060

30633061
kvm->arch.epoch = gtod->tod - htod.tod;
3064-
kvm->arch.epdx = gtod->epoch_idx - htod.epoch_idx;
3065-
3066-
if (kvm->arch.epoch > gtod->tod)
3067-
kvm->arch.epdx -= 1;
3062+
kvm->arch.epdx = 0;
3063+
if (test_kvm_facility(kvm, 139)) {
3064+
kvm->arch.epdx = gtod->epoch_idx - htod.epoch_idx;
3065+
if (kvm->arch.epoch > gtod->tod)
3066+
kvm->arch.epdx -= 1;
3067+
}
30683068

30693069
kvm_s390_vcpu_block_all(kvm);
30703070
kvm_for_each_vcpu(i, vcpu, kvm) {
@@ -3077,22 +3077,6 @@ void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
30773077
mutex_unlock(&kvm->lock);
30783078
}
30793079

3080-
void 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-
30963080
/**
30973081
* kvm_arch_fault_in_page - fault-in guest page if necessary
30983082
* @vcpu: The corresponding virtual cpu

arch/s390/kvm/kvm-s390.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,8 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
281281
int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
282282

283283
/* implemented in kvm-s390.c */
284-
void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
285-
const struct kvm_s390_vm_tod_clock *gtod);
286-
void kvm_s390_set_tod_clock(struct kvm *kvm, u64 tod);
284+
void kvm_s390_set_tod_clock(struct kvm *kvm,
285+
const struct kvm_s390_vm_tod_clock *gtod);
287286
long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable);
288287
int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr);
289288
int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr);

arch/s390/kvm/priv.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,10 @@ int kvm_s390_handle_e3(struct kvm_vcpu *vcpu)
8585
/* Handle SCK (SET CLOCK) interception */
8686
static int handle_set_clock(struct kvm_vcpu *vcpu)
8787
{
88+
struct kvm_s390_vm_tod_clock gtod = { 0 };
8889
int rc;
8990
u8 ar;
90-
u64 op2, val;
91+
u64 op2;
9192

9293
vcpu->stat.instruction_sck++;
9394

@@ -97,12 +98,12 @@ static int handle_set_clock(struct kvm_vcpu *vcpu)
9798
op2 = kvm_s390_get_base_disp_s(vcpu, &ar);
9899
if (op2 & 7) /* Operand must be on a doubleword boundary */
99100
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));
101102
if (rc)
102103
return kvm_s390_inject_prog_cond(vcpu, rc);
103104

104-
VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", val);
105-
kvm_s390_set_tod_clock(vcpu->kvm, val);
105+
VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", gtod.tod);
106+
kvm_s390_set_tod_clock(vcpu->kvm, &gtod);
106107

107108
kvm_s390_set_psw_cc(vcpu, 0);
108109
return 0;

0 commit comments

Comments
 (0)