]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
KVM: s390: enable Transactional Execution
authorMichael Mueller <mimu@linux.vnet.ibm.com>
Fri, 28 Jun 2013 11:30:24 +0000 (13:30 +0200)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Fri, 17 Jan 2014 12:12:01 +0000 (13:12 +0100)
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>
arch/s390/include/asm/kvm_host.h
arch/s390/kvm/intercept.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h

index d5bc3750616ebae0c2fedac6be4587238577b3ca..eef3dd3fd9a9f76d105b2c92d266dc5079c7833f 100644 (file)
@@ -106,9 +106,22 @@ struct kvm_s390_sie_block {
        __u64   gbea;                   /* 0x0180 */
        __u8    reserved188[24];        /* 0x0188 */
        __u32   fac;                    /* 0x01a0 */
-       __u8    reserved1a4[92];        /* 0x01a4 */
+       __u8    reserved1a4[68];        /* 0x01a4 */
+       __u64   itdba;                  /* 0x01e8 */
+       __u8    reserved1f0[16];        /* 0x01f0 */
 } __attribute__((packed));
 
+struct kvm_s390_itdb {
+       __u8    data[256];
+} __packed;
+
+struct sie_page {
+       struct kvm_s390_sie_block sie_block;
+       __u8 reserved200[1024];         /* 0x0200 */
+       struct kvm_s390_itdb itdb;      /* 0x0600 */
+       __u8 reserved700[2304];         /* 0x0700 */
+} __packed;
+
 struct kvm_vcpu_stat {
        u32 exit_userspace;
        u32 exit_null;
index 5ddbbde6f65c32fde299b9b34adbddfb02c5886d..eeb1ac7d8fa48798a79c18a5015aae5aa372c455 100644 (file)
@@ -112,6 +112,17 @@ static int handle_instruction(struct kvm_vcpu *vcpu)
 static int handle_prog(struct kvm_vcpu *vcpu)
 {
        vcpu->stat.exit_program_interruption++;
+
+       /* Restore ITDB to Program-Interruption TDB in guest memory */
+       if (IS_TE_ENABLED(vcpu) &&
+           !(current->thread.per_flags & PER_FLAG_NO_TE) &&
+           IS_ITDB_VALID(vcpu)) {
+               copy_to_guest(vcpu, TDB_ADDR, vcpu->arch.sie_block->itdba,
+                             sizeof(struct kvm_s390_itdb));
+               memset((void *) vcpu->arch.sie_block->itdba, 0,
+                      sizeof(struct kvm_s390_itdb));
+       }
+
        trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc);
        return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc);
 }
index 1bb1ddaf93c0d76554aa86bb6e45332edecce1fd..0084c2c272e38ce42e7d8d10dded6d88ec6da9f9 100644 (file)
@@ -395,6 +395,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
                                                    CPUSTAT_STOPPED |
                                                    CPUSTAT_GED);
        vcpu->arch.sie_block->ecb   = 6;
+       if (test_vfacility(50) && test_vfacility(73))
+               vcpu->arch.sie_block->ecb |= 0x10;
+
        vcpu->arch.sie_block->ecb2  = 8;
        vcpu->arch.sie_block->eca   = 0xC1002001U;
        vcpu->arch.sie_block->fac   = (int) (long) vfacilities;
@@ -411,6 +414,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
                                      unsigned int id)
 {
        struct kvm_vcpu *vcpu;
+       struct sie_page *sie_page;
        int rc = -EINVAL;
 
        if (id >= KVM_MAX_VCPUS)
@@ -422,12 +426,13 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
        if (!vcpu)
                goto out;
 
-       vcpu->arch.sie_block = (struct kvm_s390_sie_block *)
-                                       get_zeroed_page(GFP_KERNEL);
-
-       if (!vcpu->arch.sie_block)
+       sie_page = (struct sie_page *) get_zeroed_page(GFP_KERNEL);
+       if (!sie_page)
                goto out_free_cpu;
 
+       vcpu->arch.sie_block = &sie_page->sie_block;
+       vcpu->arch.sie_block->itdba = (unsigned long) &sie_page->itdb;
+
        vcpu->arch.sie_block->icpua = id;
        if (!kvm_is_ucontrol(kvm)) {
                if (!kvm->arch.sca) {
@@ -1178,8 +1183,8 @@ static int __init kvm_s390_init(void)
                return -ENOMEM;
        }
        memcpy(vfacilities, S390_lowcore.stfle_fac_list, 16);
-       vfacilities[0] &= 0xff82fff3f47c0000UL;
-       vfacilities[1] &= 0x001c000000000000UL;
+       vfacilities[0] &= 0xff82fff3f47c2000UL;
+       vfacilities[1] &= 0x005c000000000000UL;
        return 0;
 }
 
index 095cf51b16ec5965feb06c08aba33becafa7fae2..f9559b0bd620962d095851fc5c884a759b49996c 100644 (file)
@@ -26,6 +26,12 @@ extern unsigned long *vfacilities;
 
 int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
 
+/* Transactional Memory Execution related macros */
+#define IS_TE_ENABLED(vcpu)    ((vcpu->arch.sie_block->ecb & 0x10))
+#define TDB_ADDR               0x1800UL
+#define TDB_FORMAT1            1
+#define IS_ITDB_VALID(vcpu)    ((*(char *)vcpu->arch.sie_block->itdba == TDB_FORMAT1))
+
 #define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\
 do { \
        debug_sprintf_event(d_kvm->arch.dbf, d_loglevel, d_string "\n", \