Skip to content

Commit 8fa1696

Browse files
Collin L. Wallingborntraeger
authored andcommitted
KVM: s390: Multiple Epoch Facility support
Allow for the enablement of MEF and the support for the extended epoch in SIE and VSIE for the extended guest TOD-Clock. A new interface is used for getting/setting a guest's extended TOD-Clock that uses a single ioctl invocation, KVM_S390_VM_TOD_EXT. Since the host time is a moving target that might see an epoch switch or STP sync checks we need an atomic ioctl and cannot use the exisiting two interfaces. The old method of getting and setting the guest TOD-Clock is still retained and is used when the old ioctls are called. Signed-off-by: Collin L. Walling <[email protected]> Reviewed-by: Janosch Frank <[email protected]> Reviewed-by: Claudio Imbrenda <[email protected]> Reviewed-by: Jason J. Herne <[email protected]> Reviewed-by: Cornelia Huck <[email protected]> Signed-off-by: Christian Borntraeger <[email protected]>
1 parent b697e43 commit 8fa1696

File tree

7 files changed

+138
-2
lines changed

7 files changed

+138
-2
lines changed

Documentation/virtual/kvm/devices/vm.txt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ Architectures: s390
176176

177177
3.1. ATTRIBUTE: KVM_S390_VM_TOD_HIGH
178178

179-
Allows user space to set/get the TOD clock extension (u8).
179+
Allows user space to set/get the TOD clock extension (u8) (superseded by
180+
KVM_S390_VM_TOD_EXT).
180181

181182
Parameters: address of a buffer in user space to store the data (u8) to
182183
Returns: -EFAULT if the given address is not accessible from kernel space
@@ -190,6 +191,17 @@ the POP (u64).
190191
Parameters: address of a buffer in user space to store the data (u64) to
191192
Returns: -EFAULT if the given address is not accessible from kernel space
192193

194+
3.3. ATTRIBUTE: KVM_S390_VM_TOD_EXT
195+
Allows user space to set/get bits 0-63 of the TOD clock register as defined in
196+
the POP (u64). If the guest CPU model supports the TOD clock extension (u8), it
197+
also allows user space to get/set it. If the guest CPU model does not support
198+
it, it is stored as 0 and not allowed to be set to a value != 0.
199+
200+
Parameters: address of a buffer in user space to store the data
201+
(kvm_s390_vm_tod_clock) to
202+
Returns: -EFAULT if the given address is not accessible from kernel space
203+
-EINVAL if setting the TOD clock extension to != 0 is not supported
204+
193205
4. GROUP: KVM_S390_VM_CRYPTO
194206
Architectures: s390
195207

arch/s390/include/asm/kvm_host.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,9 @@ struct kvm_s390_sie_block {
226226
#define ECB3_RI 0x01
227227
__u8 ecb3; /* 0x0063 */
228228
__u32 scaol; /* 0x0064 */
229-
__u8 reserved68[4]; /* 0x0068 */
229+
__u8 reserved68; /* 0x0068 */
230+
__u8 epdx; /* 0x0069 */
231+
__u8 reserved6a[2]; /* 0x006a */
230232
__u32 todpr; /* 0x006c */
231233
__u8 reserved70[16]; /* 0x0070 */
232234
__u64 mso; /* 0x0080 */
@@ -265,6 +267,7 @@ struct kvm_s390_sie_block {
265267
__u64 cbrlo; /* 0x01b8 */
266268
__u8 reserved1c0[8]; /* 0x01c0 */
267269
#define ECD_HOSTREGMGMT 0x20000000
270+
#define ECD_MEF 0x08000000
268271
__u32 ecd; /* 0x01c8 */
269272
__u8 reserved1cc[18]; /* 0x01cc */
270273
__u64 pp; /* 0x01de */
@@ -739,6 +742,7 @@ struct kvm_arch{
739742
struct kvm_s390_cpu_model model;
740743
struct kvm_s390_crypto crypto;
741744
struct kvm_s390_vsie vsie;
745+
u8 epdx;
742746
u64 epoch;
743747
struct kvm_s390_migration_state *migration_state;
744748
/* subset of available cpu features enabled by user space */

arch/s390/include/uapi/asm/kvm.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ struct kvm_s390_io_adapter_req {
8888
/* kvm attributes for KVM_S390_VM_TOD */
8989
#define KVM_S390_VM_TOD_LOW 0
9090
#define KVM_S390_VM_TOD_HIGH 1
91+
#define KVM_S390_VM_TOD_EXT 2
92+
93+
struct kvm_s390_vm_tod_clock {
94+
__u8 epoch_idx;
95+
__u64 tod;
96+
};
9197

9298
/* kvm attributes for KVM_S390_VM_CPU_MODEL */
9399
/* processor related attributes are r/w */

arch/s390/kvm/kvm-s390.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,12 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
130130
{ NULL }
131131
};
132132

133+
struct kvm_s390_tod_clock_ext {
134+
__u8 epoch_idx;
135+
__u64 tod;
136+
__u8 reserved[7];
137+
} __packed;
138+
133139
/* allow nested virtualization in KVM (if enabled by user space) */
134140
static int nested;
135141
module_param(nested, int, S_IRUGO);
@@ -874,6 +880,26 @@ static int kvm_s390_vm_get_migration(struct kvm *kvm,
874880
return 0;
875881
}
876882

883+
static int kvm_s390_set_tod_ext(struct kvm *kvm, struct kvm_device_attr *attr)
884+
{
885+
struct kvm_s390_vm_tod_clock gtod;
886+
887+
if (copy_from_user(&gtod, (void __user *)attr->addr, sizeof(gtod)))
888+
return -EFAULT;
889+
890+
if (test_kvm_facility(kvm, 139))
891+
kvm_s390_set_tod_clock_ext(kvm, &gtod);
892+
else if (gtod.epoch_idx == 0)
893+
kvm_s390_set_tod_clock(kvm, gtod.tod);
894+
else
895+
return -EINVAL;
896+
897+
VM_EVENT(kvm, 3, "SET: TOD extension: 0x%x, TOD base: 0x%llx",
898+
gtod.epoch_idx, gtod.tod);
899+
900+
return 0;
901+
}
902+
877903
static int kvm_s390_set_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
878904
{
879905
u8 gtod_high;
@@ -909,6 +935,9 @@ static int kvm_s390_set_tod(struct kvm *kvm, struct kvm_device_attr *attr)
909935
return -EINVAL;
910936

911937
switch (attr->attr) {
938+
case KVM_S390_VM_TOD_EXT:
939+
ret = kvm_s390_set_tod_ext(kvm, attr);
940+
break;
912941
case KVM_S390_VM_TOD_HIGH:
913942
ret = kvm_s390_set_tod_high(kvm, attr);
914943
break;
@@ -922,6 +951,43 @@ static int kvm_s390_set_tod(struct kvm *kvm, struct kvm_device_attr *attr)
922951
return ret;
923952
}
924953

954+
static void kvm_s390_get_tod_clock_ext(struct kvm *kvm,
955+
struct kvm_s390_vm_tod_clock *gtod)
956+
{
957+
struct kvm_s390_tod_clock_ext htod;
958+
959+
preempt_disable();
960+
961+
get_tod_clock_ext((char *)&htod);
962+
963+
gtod->tod = htod.tod + kvm->arch.epoch;
964+
gtod->epoch_idx = htod.epoch_idx + kvm->arch.epdx;
965+
966+
if (gtod->tod < htod.tod)
967+
gtod->epoch_idx += 1;
968+
969+
preempt_enable();
970+
}
971+
972+
static int kvm_s390_get_tod_ext(struct kvm *kvm, struct kvm_device_attr *attr)
973+
{
974+
struct kvm_s390_vm_tod_clock gtod;
975+
976+
memset(&gtod, 0, sizeof(gtod));
977+
978+
if (test_kvm_facility(kvm, 139))
979+
kvm_s390_get_tod_clock_ext(kvm, &gtod);
980+
else
981+
gtod.tod = kvm_s390_get_tod_clock_fast(kvm);
982+
983+
if (copy_to_user((void __user *)attr->addr, &gtod, sizeof(gtod)))
984+
return -EFAULT;
985+
986+
VM_EVENT(kvm, 3, "QUERY: TOD extension: 0x%x, TOD base: 0x%llx",
987+
gtod.epoch_idx, gtod.tod);
988+
return 0;
989+
}
990+
925991
static int kvm_s390_get_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
926992
{
927993
u8 gtod_high = 0;
@@ -954,6 +1020,9 @@ static int kvm_s390_get_tod(struct kvm *kvm, struct kvm_device_attr *attr)
9541020
return -EINVAL;
9551021

9561022
switch (attr->attr) {
1023+
case KVM_S390_VM_TOD_EXT:
1024+
ret = kvm_s390_get_tod_ext(kvm, attr);
1025+
break;
9571026
case KVM_S390_VM_TOD_HIGH:
9581027
ret = kvm_s390_get_tod_high(kvm, attr);
9591028
break;
@@ -2369,6 +2438,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
23692438
vcpu->arch.sie_block->eca |= ECA_VX;
23702439
vcpu->arch.sie_block->ecd |= ECD_HOSTREGMGMT;
23712440
}
2441+
if (test_kvm_facility(vcpu->kvm, 139))
2442+
vcpu->arch.sie_block->ecd |= ECD_MEF;
2443+
23722444
vcpu->arch.sie_block->sdnxo = ((unsigned long) &vcpu->run->s.regs.sdnx)
23732445
| SDNXC;
23742446
vcpu->arch.sie_block->riccbd = (unsigned long) &vcpu->run->s.regs.riccb;
@@ -2855,6 +2927,35 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
28552927
return 0;
28562928
}
28572929

2930+
void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
2931+
const struct kvm_s390_vm_tod_clock *gtod)
2932+
{
2933+
struct kvm_vcpu *vcpu;
2934+
struct kvm_s390_tod_clock_ext htod;
2935+
int i;
2936+
2937+
mutex_lock(&kvm->lock);
2938+
preempt_disable();
2939+
2940+
get_tod_clock_ext((char *)&htod);
2941+
2942+
kvm->arch.epoch = gtod->tod - htod.tod;
2943+
kvm->arch.epdx = gtod->epoch_idx - htod.epoch_idx;
2944+
2945+
if (kvm->arch.epoch > gtod->tod)
2946+
kvm->arch.epdx -= 1;
2947+
2948+
kvm_s390_vcpu_block_all(kvm);
2949+
kvm_for_each_vcpu(i, vcpu, kvm) {
2950+
vcpu->arch.sie_block->epoch = kvm->arch.epoch;
2951+
vcpu->arch.sie_block->epdx = kvm->arch.epdx;
2952+
}
2953+
2954+
kvm_s390_vcpu_unblock_all(kvm);
2955+
preempt_enable();
2956+
mutex_unlock(&kvm->lock);
2957+
}
2958+
28582959
void kvm_s390_set_tod_clock(struct kvm *kvm, u64 tod)
28592960
{
28602961
struct kvm_vcpu *vcpu;

arch/s390/kvm/kvm-s390.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
272272
int handle_sthyi(struct kvm_vcpu *vcpu);
273273

274274
/* implemented in kvm-s390.c */
275+
void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
276+
const struct kvm_s390_vm_tod_clock *gtod);
275277
void kvm_s390_set_tod_clock(struct kvm *kvm, u64 tod);
276278
long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable);
277279
int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr);

arch/s390/kvm/vsie.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,9 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
349349
scb_s->eca |= scb_o->eca & ECA_IB;
350350
if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_CEI))
351351
scb_s->eca |= scb_o->eca & ECA_CEI;
352+
/* Epoch Extension */
353+
if (test_kvm_facility(vcpu->kvm, 139))
354+
scb_s->ecd |= scb_o->ecd & ECD_MEF;
352355

353356
prepare_ibc(vcpu, vsie_page);
354357
rc = shadow_crycb(vcpu, vsie_page);
@@ -919,6 +922,13 @@ static void register_shadow_scb(struct kvm_vcpu *vcpu,
919922
*/
920923
preempt_disable();
921924
scb_s->epoch += vcpu->kvm->arch.epoch;
925+
926+
if (scb_s->ecd & ECD_MEF) {
927+
scb_s->epdx += vcpu->kvm->arch.epdx;
928+
if (scb_s->epoch < vcpu->kvm->arch.epoch)
929+
scb_s->epdx += 1;
930+
}
931+
922932
preempt_enable();
923933
}
924934

arch/s390/tools/gen_facilities.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ static struct facility_def facility_defs[] = {
8181
130, /* instruction-execution-protection */
8282
131, /* enhanced-SOP 2 and side-effect */
8383
138, /* configuration z/architecture mode (czam) */
84+
139, /* multiple epoch facility */
8485
146, /* msa extension 8 */
8586
-1 /* END */
8687
}

0 commit comments

Comments
 (0)