aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Mueller <mimu@linux.vnet.ibm.com>2013-06-28 07:30:24 -0400
committerChristian Borntraeger <borntraeger@de.ibm.com>2014-01-17 07:12:01 -0500
commit7feb6bb8e6dbd129c11fc93bf206daa156bf1c0f (patch)
tree383c77a8523822b940c68a42a323d4da949697d2
parent26a865f4aa8e66a6d94958de7656f7f1b03c6c56 (diff)
KVM: s390: enable Transactional Execution
This patch enables transactional execution for KVM guests on s390 systems zec12 or later. We rework the allocation of the page containing the sie_block to also back the Interception Transaction Diagnostic Block. If available the TE facilities will be enabled. Setting bit 73 and 50 in vfacilities bitmask reveals the HW facilities Transactional Memory and Constraint Transactional Memory respectively to the KVM guest. Furthermore, the patch restores the Program-Interruption TDB from the Interception TDB in case a program interception has occurred and the ITDB has a valid format. Signed-off-by: Michael Mueller <mimu@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r--arch/s390/include/asm/kvm_host.h15
-rw-r--r--arch/s390/kvm/intercept.c11
-rw-r--r--arch/s390/kvm/kvm-s390.c17
-rw-r--r--arch/s390/kvm/kvm-s390.h6
4 files changed, 42 insertions, 7 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index d5bc3750616e..eef3dd3fd9a9 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -106,9 +106,22 @@ struct kvm_s390_sie_block {
106 __u64 gbea; /* 0x0180 */ 106 __u64 gbea; /* 0x0180 */
107 __u8 reserved188[24]; /* 0x0188 */ 107 __u8 reserved188[24]; /* 0x0188 */
108 __u32 fac; /* 0x01a0 */ 108 __u32 fac; /* 0x01a0 */
109 __u8 reserved1a4[92]; /* 0x01a4 */ 109 __u8 reserved1a4[68]; /* 0x01a4 */
110 __u64 itdba; /* 0x01e8 */
111 __u8 reserved1f0[16]; /* 0x01f0 */
110} __attribute__((packed)); 112} __attribute__((packed));
111 113
114struct kvm_s390_itdb {
115 __u8 data[256];
116} __packed;
117
118struct sie_page {
119 struct kvm_s390_sie_block sie_block;
120 __u8 reserved200[1024]; /* 0x0200 */
121 struct kvm_s390_itdb itdb; /* 0x0600 */
122 __u8 reserved700[2304]; /* 0x0700 */
123} __packed;
124
112struct kvm_vcpu_stat { 125struct kvm_vcpu_stat {
113 u32 exit_userspace; 126 u32 exit_userspace;
114 u32 exit_null; 127 u32 exit_null;
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 5ddbbde6f65c..eeb1ac7d8fa4 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -112,6 +112,17 @@ static int handle_instruction(struct kvm_vcpu *vcpu)
112static int handle_prog(struct kvm_vcpu *vcpu) 112static int handle_prog(struct kvm_vcpu *vcpu)
113{ 113{
114 vcpu->stat.exit_program_interruption++; 114 vcpu->stat.exit_program_interruption++;
115
116 /* Restore ITDB to Program-Interruption TDB in guest memory */
117 if (IS_TE_ENABLED(vcpu) &&
118 !(current->thread.per_flags & PER_FLAG_NO_TE) &&
119 IS_ITDB_VALID(vcpu)) {
120 copy_to_guest(vcpu, TDB_ADDR, vcpu->arch.sie_block->itdba,
121 sizeof(struct kvm_s390_itdb));
122 memset((void *) vcpu->arch.sie_block->itdba, 0,
123 sizeof(struct kvm_s390_itdb));
124 }
125
115 trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc); 126 trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc);
116 return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc); 127 return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc);
117} 128}
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 1bb1ddaf93c0..0084c2c272e3 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -395,6 +395,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
395 CPUSTAT_STOPPED | 395 CPUSTAT_STOPPED |
396 CPUSTAT_GED); 396 CPUSTAT_GED);
397 vcpu->arch.sie_block->ecb = 6; 397 vcpu->arch.sie_block->ecb = 6;
398 if (test_vfacility(50) && test_vfacility(73))
399 vcpu->arch.sie_block->ecb |= 0x10;
400
398 vcpu->arch.sie_block->ecb2 = 8; 401 vcpu->arch.sie_block->ecb2 = 8;
399 vcpu->arch.sie_block->eca = 0xC1002001U; 402 vcpu->arch.sie_block->eca = 0xC1002001U;
400 vcpu->arch.sie_block->fac = (int) (long) vfacilities; 403 vcpu->arch.sie_block->fac = (int) (long) vfacilities;
@@ -411,6 +414,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
411 unsigned int id) 414 unsigned int id)
412{ 415{
413 struct kvm_vcpu *vcpu; 416 struct kvm_vcpu *vcpu;
417 struct sie_page *sie_page;
414 int rc = -EINVAL; 418 int rc = -EINVAL;
415 419
416 if (id >= KVM_MAX_VCPUS) 420 if (id >= KVM_MAX_VCPUS)
@@ -422,12 +426,13 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
422 if (!vcpu) 426 if (!vcpu)
423 goto out; 427 goto out;
424 428
425 vcpu->arch.sie_block = (struct kvm_s390_sie_block *) 429 sie_page = (struct sie_page *) get_zeroed_page(GFP_KERNEL);
426 get_zeroed_page(GFP_KERNEL); 430 if (!sie_page)
427
428 if (!vcpu->arch.sie_block)
429 goto out_free_cpu; 431 goto out_free_cpu;
430 432
433 vcpu->arch.sie_block = &sie_page->sie_block;
434 vcpu->arch.sie_block->itdba = (unsigned long) &sie_page->itdb;
435
431 vcpu->arch.sie_block->icpua = id; 436 vcpu->arch.sie_block->icpua = id;
432 if (!kvm_is_ucontrol(kvm)) { 437 if (!kvm_is_ucontrol(kvm)) {
433 if (!kvm->arch.sca) { 438 if (!kvm->arch.sca) {
@@ -1178,8 +1183,8 @@ static int __init kvm_s390_init(void)
1178 return -ENOMEM; 1183 return -ENOMEM;
1179 } 1184 }
1180 memcpy(vfacilities, S390_lowcore.stfle_fac_list, 16); 1185 memcpy(vfacilities, S390_lowcore.stfle_fac_list, 16);
1181 vfacilities[0] &= 0xff82fff3f47c0000UL; 1186 vfacilities[0] &= 0xff82fff3f47c2000UL;
1182 vfacilities[1] &= 0x001c000000000000UL; 1187 vfacilities[1] &= 0x005c000000000000UL;
1183 return 0; 1188 return 0;
1184} 1189}
1185 1190
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 095cf51b16ec..f9559b0bd620 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -26,6 +26,12 @@ extern unsigned long *vfacilities;
26 26
27int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu); 27int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
28 28
29/* Transactional Memory Execution related macros */
30#define IS_TE_ENABLED(vcpu) ((vcpu->arch.sie_block->ecb & 0x10))
31#define TDB_ADDR 0x1800UL
32#define TDB_FORMAT1 1
33#define IS_ITDB_VALID(vcpu) ((*(char *)vcpu->arch.sie_block->itdba == TDB_FORMAT1))
34
29#define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\ 35#define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\
30do { \ 36do { \
31 debug_sprintf_event(d_kvm->arch.dbf, d_loglevel, d_string "\n", \ 37 debug_sprintf_event(d_kvm->arch.dbf, d_loglevel, d_string "\n", \