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>
This commit is contained in:
parent
26a865f4aa
commit
7feb6bb8e6
|
@ -106,9 +106,22 @@ struct kvm_s390_sie_block {
|
||||||
__u64 gbea; /* 0x0180 */
|
__u64 gbea; /* 0x0180 */
|
||||||
__u8 reserved188[24]; /* 0x0188 */
|
__u8 reserved188[24]; /* 0x0188 */
|
||||||
__u32 fac; /* 0x01a0 */
|
__u32 fac; /* 0x01a0 */
|
||||||
__u8 reserved1a4[92]; /* 0x01a4 */
|
__u8 reserved1a4[68]; /* 0x01a4 */
|
||||||
|
__u64 itdba; /* 0x01e8 */
|
||||||
|
__u8 reserved1f0[16]; /* 0x01f0 */
|
||||||
} __attribute__((packed));
|
} __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 {
|
struct kvm_vcpu_stat {
|
||||||
u32 exit_userspace;
|
u32 exit_userspace;
|
||||||
u32 exit_null;
|
u32 exit_null;
|
||||||
|
|
|
@ -112,6 +112,17 @@ static int handle_instruction(struct kvm_vcpu *vcpu)
|
||||||
static int handle_prog(struct kvm_vcpu *vcpu)
|
static int handle_prog(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
vcpu->stat.exit_program_interruption++;
|
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);
|
trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc);
|
||||||
return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc);
|
return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -395,6 +395,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
|
||||||
CPUSTAT_STOPPED |
|
CPUSTAT_STOPPED |
|
||||||
CPUSTAT_GED);
|
CPUSTAT_GED);
|
||||||
vcpu->arch.sie_block->ecb = 6;
|
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->ecb2 = 8;
|
||||||
vcpu->arch.sie_block->eca = 0xC1002001U;
|
vcpu->arch.sie_block->eca = 0xC1002001U;
|
||||||
vcpu->arch.sie_block->fac = (int) (long) vfacilities;
|
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)
|
unsigned int id)
|
||||||
{
|
{
|
||||||
struct kvm_vcpu *vcpu;
|
struct kvm_vcpu *vcpu;
|
||||||
|
struct sie_page *sie_page;
|
||||||
int rc = -EINVAL;
|
int rc = -EINVAL;
|
||||||
|
|
||||||
if (id >= KVM_MAX_VCPUS)
|
if (id >= KVM_MAX_VCPUS)
|
||||||
|
@ -422,12 +426,13 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
|
||||||
if (!vcpu)
|
if (!vcpu)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
vcpu->arch.sie_block = (struct kvm_s390_sie_block *)
|
sie_page = (struct sie_page *) get_zeroed_page(GFP_KERNEL);
|
||||||
get_zeroed_page(GFP_KERNEL);
|
if (!sie_page)
|
||||||
|
|
||||||
if (!vcpu->arch.sie_block)
|
|
||||||
goto out_free_cpu;
|
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;
|
vcpu->arch.sie_block->icpua = id;
|
||||||
if (!kvm_is_ucontrol(kvm)) {
|
if (!kvm_is_ucontrol(kvm)) {
|
||||||
if (!kvm->arch.sca) {
|
if (!kvm->arch.sca) {
|
||||||
|
@ -1178,8 +1183,8 @@ static int __init kvm_s390_init(void)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
memcpy(vfacilities, S390_lowcore.stfle_fac_list, 16);
|
memcpy(vfacilities, S390_lowcore.stfle_fac_list, 16);
|
||||||
vfacilities[0] &= 0xff82fff3f47c0000UL;
|
vfacilities[0] &= 0xff82fff3f47c2000UL;
|
||||||
vfacilities[1] &= 0x001c000000000000UL;
|
vfacilities[1] &= 0x005c000000000000UL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,12 @@ extern unsigned long *vfacilities;
|
||||||
|
|
||||||
int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
|
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...)\
|
#define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\
|
||||||
do { \
|
do { \
|
||||||
debug_sprintf_event(d_kvm->arch.dbf, d_loglevel, d_string "\n", \
|
debug_sprintf_event(d_kvm->arch.dbf, d_loglevel, d_string "\n", \
|
||||||
|
|
Loading…
Reference in New Issue