From: Nina Schoetterl-Glausch Directly use the size of the arrays instead of going through the indirection of kvm_s390_fac_size(). Don't use magic number for the number of entries in the non hypervisor managed facility bit mask list. Make the constraint of that number on kvm_s390_fac_base obvious. Get rid of implicit double anding of stfle_fac_list. Reviewed-by: Claudio Imbrenda Signed-off-by: Nina Schoetterl-Glausch Signed-off-by: Christoph Schlameuss --- arch/s390/kvm/kvm-s390.c | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 56a50524b3eee4e17b5b8a5833c2a560d120c443..797d77174fe692c1e63cacc38f251dd3bc98a23b 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -231,33 +231,25 @@ static int async_destroy = 1; module_param(async_destroy, int, 0444); MODULE_PARM_DESC(async_destroy, "Asynchronous destroy for protected guests"); -/* - * For now we handle at most 16 double words as this is what the s390 base - * kernel handles and stores in the prefix page. If we ever need to go beyond - * this, this requires changes to code, but the external uapi can stay. - */ -#define SIZE_INTERNAL 16 - +#define HMFAI_DWORDS 16 /* * Base feature mask that defines default mask for facilities. Consists of the * defines in FACILITIES_KVM and the non-hypervisor managed bits. */ -static unsigned long kvm_s390_fac_base[SIZE_INTERNAL] = { FACILITIES_KVM }; +static unsigned long kvm_s390_fac_base[HMFAI_DWORDS] = { FACILITIES_KVM }; +static_assert(ARRAY_SIZE(((long[]){ FACILITIES_KVM })) <= HMFAI_DWORDS); +static_assert(ARRAY_SIZE(kvm_s390_fac_base) <= S390_ARCH_FAC_MASK_SIZE_U64); +static_assert(ARRAY_SIZE(kvm_s390_fac_base) <= S390_ARCH_FAC_LIST_SIZE_U64); +static_assert(ARRAY_SIZE(kvm_s390_fac_base) <= ARRAY_SIZE(stfle_fac_list)); + /* * Extended feature mask. Consists of the defines in FACILITIES_KVM_CPUMODEL * and defines the facilities that can be enabled via a cpu model. */ -static unsigned long kvm_s390_fac_ext[SIZE_INTERNAL] = { FACILITIES_KVM_CPUMODEL }; - -static unsigned long kvm_s390_fac_size(void) -{ - BUILD_BUG_ON(SIZE_INTERNAL > S390_ARCH_FAC_MASK_SIZE_U64); - BUILD_BUG_ON(SIZE_INTERNAL > S390_ARCH_FAC_LIST_SIZE_U64); - BUILD_BUG_ON(SIZE_INTERNAL * sizeof(unsigned long) > - sizeof(stfle_fac_list)); - - return SIZE_INTERNAL; -} +static const unsigned long kvm_s390_fac_ext[] = { FACILITIES_KVM_CPUMODEL }; +static_assert(ARRAY_SIZE(kvm_s390_fac_ext) <= S390_ARCH_FAC_MASK_SIZE_U64); +static_assert(ARRAY_SIZE(kvm_s390_fac_ext) <= S390_ARCH_FAC_LIST_SIZE_U64); +static_assert(ARRAY_SIZE(kvm_s390_fac_ext) <= ARRAY_SIZE(stfle_fac_list)); /* available cpu features supported by kvm */ static DECLARE_BITMAP(kvm_s390_available_cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS); @@ -3371,13 +3363,16 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) kvm->arch.sie_page2->kvm = kvm; kvm->arch.model.fac_list = kvm->arch.sie_page2->fac_list; - for (i = 0; i < kvm_s390_fac_size(); i++) { + for (i = 0; i < ARRAY_SIZE(kvm_s390_fac_base); i++) { kvm->arch.model.fac_mask[i] = stfle_fac_list[i] & - (kvm_s390_fac_base[i] | - kvm_s390_fac_ext[i]); + kvm_s390_fac_base[i]; kvm->arch.model.fac_list[i] = stfle_fac_list[i] & kvm_s390_fac_base[i]; } + for (i = 0; i < ARRAY_SIZE(kvm_s390_fac_ext); i++) { + kvm->arch.model.fac_mask[i] |= stfle_fac_list[i] & + kvm_s390_fac_ext[i]; + } kvm->arch.model.subfuncs = kvm_s390_available_subfunc; /* we are always in czam mode - even on pre z14 machines */ @@ -6040,9 +6035,8 @@ static int __init kvm_s390_init(void) return -EINVAL; } - for (i = 0; i < 16; i++) - kvm_s390_fac_base[i] |= - stfle_fac_list[i] & nonhyp_mask(i); + for (i = 0; i < HMFAI_DWORDS; i++) + kvm_s390_fac_base[i] |= nonhyp_mask(i); r = __kvm_s390_init(); if (r) -- 2.53.0 From: Nina Schoetterl-Glausch Detect alternate STFLE interpretive execution facility 2. Signed-off-by: Nina Schoetterl-Glausch Signed-off-by: Christoph Schlameuss --- arch/s390/include/asm/sclp.h | 1 + drivers/s390/char/sclp_early.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 0f184dbdbe5e0748fcecbca38b9e55a56968dc79..0f21501d3e866338895caeed385aa4f586384d69 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -104,6 +104,7 @@ struct sclp_info { unsigned char has_aisii : 1; unsigned char has_aeni : 1; unsigned char has_aisi : 1; + unsigned char has_astfleie2 : 1; unsigned int ibc; unsigned int mtid; unsigned int mtid_cp; diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index 6bf501ad8ff0ea6d3df0a721f29fd24506409493..22dd797e62291fef087d46ac1c7f805486e3935b 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -61,8 +61,10 @@ static void __init sclp_early_facilities_detect(void) sclp.has_sipl = !!(sccb->cbl & 0x4000); sclp.has_sipl_eckd = !!(sccb->cbl & 0x2000); } - if (sccb->cpuoff > 139) + if (sccb->cpuoff > 139) { sclp.has_diag324 = !!(sccb->byte_139 & 0x80); + sclp.has_astfleie2 = !!(sccb->byte_139 & 0x40); + } sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; sclp.rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; sclp.rzm <<= 20; -- 2.53.0 From: Nina Schoetterl-Glausch Use switch case in anticipation of handling format-1 and format-2 facility list designations in the future. As the alternate STFLE facilities are not enabled, only case 0 is possible. No functional change intended. Signed-off-by: Nina Schoetterl-Glausch Signed-off-by: Christoph Schlameuss --- arch/s390/include/uapi/asm/kvm.h | 1 + arch/s390/kvm/vsie.c | 53 ++++++++++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index 60345dd2cba2d611b76f8b5c70eab8f0abab4b9b..4192769b5ce069ba28d00d7cf1c4f1b34037d633 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h @@ -444,6 +444,7 @@ struct kvm_s390_vm_cpu_machine { #define KVM_S390_VM_CPU_FEAT_PFMFI 11 #define KVM_S390_VM_CPU_FEAT_SIGPIF 12 #define KVM_S390_VM_CPU_FEAT_KSS 13 +#define KVM_S390_VM_CPU_FEAT_ASTFLEIE2 14 struct kvm_s390_vm_cpu_feat { __u64 feat[16]; }; diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index b526621d2a1b0a00cd63afd7a96b5c8da81984a7..3a90d4011bf06c35416ca2ea81eab1f0f71e8be4 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -6,12 +6,15 @@ * * Author(s): David Hildenbrand */ +#include #include #include #include +#include #include #include #include +#include #include #include @@ -1008,6 +1011,23 @@ static void retry_vsie_icpt(struct vsie_page *vsie_page) clear_vsie_icpt(vsie_page); } +static int handle_stfle_0(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, + u32 fac_list_origin) +{ + struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; + + /* + * format-0 -> size of nested guest's facility list == guest's size + * guest's size == host's size, since STFLE is interpretatively executed + * using a format-0 for the guest, too. + */ + if (read_guest_real(vcpu, fac_list_origin, &vsie_page->fac, + stfle_size() * sizeof(u64))) + return set_validity_icpt(scb_s, 0x1090U); + scb_s->fac = (u32)virt_to_phys(&vsie_page->fac); + return 0; +} + /* * Try to shadow + enable the guest 2 provided facility list. * Retry instruction execution if enabled for and provided by guest 2. @@ -1017,29 +1037,30 @@ static void retry_vsie_icpt(struct vsie_page *vsie_page) */ static int handle_stfle(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) { - struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; - __u32 fac = READ_ONCE(vsie_page->scb_o->fac); + u32 fac = READ_ONCE(vsie_page->scb_o->fac); + int fac_list_format_mask, fac_list_format; + u32 fac_list_origin; + bool has_astfleie2; - /* - * Alternate-STFLE-Interpretive-Execution facilities are not supported - * -> format-0 flcb - */ + BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct vsie_page, fac), 8)); if (fac && test_kvm_facility(vcpu->kvm, 7)) { retry_vsie_icpt(vsie_page); /* * The facility list origin (FLO) is in bits 1 - 28 of the FLD * so we need to mask here before reading. */ - fac = fac & 0x7ffffff8U; - /* - * format-0 -> size of nested guest's facility list == guest's size - * guest's size == host's size, since STFLE is interpretatively executed - * using a format-0 for the guest, too. - */ - if (read_guest_real(vcpu, fac, &vsie_page->fac, - stfle_size() * sizeof(u64))) - return set_validity_icpt(scb_s, 0x1090U); - scb_s->fac = (u32)virt_to_phys(&vsie_page->fac); + fac_list_origin = fac & 0x7ffffff8U; + has_astfleie2 = test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_ASTFLEIE2); + fac_list_format_mask = has_astfleie2 ? 3 : 0; + fac_list_format = fac & fac_list_format_mask; + switch (fac_list_format) { + case 0: + return handle_stfle_0(vcpu, vsie_page, fac_list_origin); + case 1: + case 2: + case 3: + unreachable(); + } } return 0; } -- 2.53.0 From: Nina Schoetterl-Glausch Implement shadowing of format-2 facility list when running in VSIE. ASTFLEIE2 is available since IBM z16. To function G1 has to run this KVM code and G1 and G2 have to run QEMU with ASTFLEIE2 support. Signed-off-by: Nina Schoetterl-Glausch Co-developed-by: Christoph Schlameuss Signed-off-by: Christoph Schlameuss --- arch/s390/kvm/kvm-s390.c | 2 ++ arch/s390/kvm/vsie.c | 33 +++++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 797d77174fe692c1e63cacc38f251dd3bc98a23b..3f922b96356aa3c5ed653758fbd05509ba5b337f 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -464,6 +464,8 @@ static void __init kvm_s390_cpu_feat_init(void) allow_cpu_feat(KVM_S390_VM_CPU_FEAT_IBS); if (sclp.has_kss) allow_cpu_feat(KVM_S390_VM_CPU_FEAT_KSS); + if (sclp.has_astfleie2) + allow_cpu_feat(KVM_S390_VM_CPU_FEAT_ASTFLEIE2); /* * KVM_S390_VM_CPU_FEAT_SKEY: Wrong shadow of PTE.I bits will make * all skey handling functions read/set the skey from the PGSTE diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 3a90d4011bf06c35416ca2ea81eab1f0f71e8be4..4396abeb58ed577c49fa9b98de1c630d6759e9a2 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -65,9 +65,9 @@ struct vsie_page { * looked up by other CPUs. */ unsigned long flags; /* 0x0260 */ - __u8 reserved[0x0700 - 0x0268]; /* 0x0268 */ - struct kvm_s390_crypto_cb crycb; /* 0x0700 */ - __u8 fac[S390_ARCH_FAC_LIST_SIZE_BYTE]; /* 0x0800 */ + __u8 reserved[0x06f8 - 0x0268]; /* 0x0268 */ + struct kvm_s390_crypto_cb crycb; /* 0x06f8 */ + __u8 fac[8 + S390_ARCH_FAC_LIST_SIZE_BYTE];/* 0x0800 */ }; /** @@ -1028,6 +1028,29 @@ static int handle_stfle_0(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, return 0; } +static int handle_stfle_2(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, + u32 fac_list_origin) +{ + struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; + u8 *shadow_fac = &vsie_page->fac[0]; + u64 len; + + if (read_guest_real(vcpu, fac_list_origin, &len, sizeof(len))) + return set_validity_icpt(scb_s, 0x1090U); + fac_list_origin += sizeof(len); + len = (len & 0xff); + memcpy(shadow_fac, &len, sizeof(len)); /* discard reserved bits */ + shadow_fac += sizeof(len); + len += 1; + /* assert no overflow with maximum len */ + BUILD_BUG_ON(sizeof(vsie_page->fac) < 257 * sizeof(u64)); + if (read_guest_real(vcpu, fac_list_origin, shadow_fac, len * sizeof(u64))) + return set_validity_icpt(scb_s, 0x1090U); + BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct vsie_page, fac), 8)); + scb_s->fac = (u32)virt_to_phys(&vsie_page->fac) | 2; + return 0; +} + /* * Try to shadow + enable the guest 2 provided facility list. * Retry instruction execution if enabled for and provided by guest 2. @@ -1057,9 +1080,11 @@ static int handle_stfle(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) case 0: return handle_stfle_0(vcpu, vsie_page, fac_list_origin); case 1: + return set_validity_icpt(&vsie_page->scb_s, 0x1330U); case 2: + return handle_stfle_2(vcpu, vsie_page, fac_list_origin); case 3: - unreachable(); + return set_validity_icpt(&vsie_page->scb_s, 0x1330U); } } return 0; -- 2.53.0