]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: s390: vsie: Implement ASTFLEIE facility 2
authorNina Schoetterl-Glausch <nsg@linux.ibm.com>
Fri, 12 Jun 2026 12:23:04 +0000 (14:23 +0200)
committerClaudio Imbrenda <imbrenda@linux.ibm.com>
Fri, 12 Jun 2026 13:13:30 +0000 (15:13 +0200)
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 <nsg@linux.ibm.com>
Co-developed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
[imbrenda@linux.ibm.com: Fix typo in comment]
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260612-vsie-alter-stfle-fac-v4-4-74f0e1559929@linux.ibm.com>

arch/s390/include/asm/kvm_host.h
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/vsie.c

index 8a4f4a39f7a2b7e3a4525b41a416ae6ccb209a3c..aa4c4685f95c3a9fff0c0c3ce2e8e9d14101b325 100644 (file)
@@ -504,6 +504,18 @@ struct kvm_s390_cpu_model {
        struct kvm_s390_vm_cpu_uv_feat uv_feat_guest;
 };
 
+#define S390_ARCH_FAC_FORMAT_2 2
+struct kvm_s390_flcb2 {
+       union {
+               struct {
+                       u8 reserved0[7];
+                       u8 length;
+               };
+               u64 header_val;
+       };
+       u64 facilities[S390_ARCH_FAC_LIST_SIZE_U64];
+};
+
 typedef int (*crypto_hook)(struct kvm_vcpu *vcpu);
 
 struct kvm_s390_crypto {
index 7334c160d0199162dced54b427e9cc168bc74b16..de28ee1f7882ab02a857bc1f6ba76312a1e81f84 100644 (file)
@@ -465,6 +465,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
index c7dcdd460dd1d2639902e1b67232ea8ec57b6416..eea24562e7db2b8acbc78828ba53d8dbd0b4310f 100644 (file)
@@ -65,9 +65,9 @@ struct vsie_page {
        gpa_t scb_gpa;                          /* 0x0258 */
        /* the shadow gmap in use by the vsie_page */
        struct gmap_cache gmap_cache;           /* 0x0260 */
-       __u8 reserved[0x0700 - 0x0278];         /* 0x0278 */
-       struct kvm_s390_crypto_cb crycb;        /* 0x0700 */
-       __u8 fac[S390_ARCH_FAC_LIST_SIZE_BYTE]; /* 0x0800 */
+       __u8 reserved[0x06f8 - 0x0278];         /* 0x0278 */
+       struct kvm_s390_crypto_cb crycb;        /* 0x06f8 */
+       __u8 fac[8 + S390_ARCH_FAC_LIST_SIZE_BYTE];/* 0x07f8 */
 };
 
 static_assert(sizeof(struct vsie_page) == PAGE_SIZE);
@@ -1020,6 +1020,28 @@ 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_flcb2 *flcb_s = (struct kvm_s390_flcb2 *)vsie_page->fac;
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+       u64 len;
+
+       if (read_guest_real(vcpu, fac_list_origin, &len, sizeof(len)))
+               return set_validity_icpt(scb_s, 0x1090U);
+
+       /* discard reserved bits */
+       len = (len & U8_MAX);
+       flcb_s->header_val = len;
+       len += 1;
+
+       if (read_guest_real(vcpu, fac_list_origin + offsetof(struct kvm_s390_flcb2, facilities),
+                           &flcb_s->facilities, len * sizeof(u64)))
+               return set_validity_icpt(scb_s, 0x1090U);
+
+       scb_s->fac = (u32)virt_to_phys(&vsie_page->fac) | S390_ARCH_FAC_FORMAT_2;
+       return 0;
+}
+
 /*
  * Try to shadow + enable the guest 2 provided facility list.
  * Retry instruction execution if enabled for and provided by guest 2.
@@ -1034,6 +1056,8 @@ static int handle_stfle(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
        int format_mask, format;
        u32 origin;
 
+       /* assert no overflow with maximum len */
+       BUILD_BUG_ON(sizeof(vsie_page->fac) < ((S390_ARCH_FAC_LIST_SIZE_U64 + 1) * sizeof(u64)));
        BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct vsie_page, fac), 8));
 
        if (fac && test_kvm_facility(vcpu->kvm, 7)) {
@@ -1049,9 +1073,11 @@ static int handle_stfle(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
                case 0:
                        return handle_stfle_0(vcpu, vsie_page, origin);
                case 1:
+                       return set_validity_icpt(&vsie_page->scb_s, 0x1330U);
                case 2:
+                       return handle_stfle_2(vcpu, vsie_page, origin);
                case 3:
-                       unreachable();
+                       return set_validity_icpt(&vsie_page->scb_s, 0x1330U);
                }
        }
        return 0;