]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/commitdiff
KVM: s390: implement CPU model only facilities
authorChristian Borntraeger <borntraeger@de.ibm.com>
Fri, 9 Feb 2018 16:26:29 +0000 (16:26 +0000)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Fri, 9 Mar 2018 09:44:17 +0000 (09:44 +0000)
Some facilities should only be provided to the guest, if they are
enabled by a CPU model. This allows us to avoid capabilities and
to simply fall back to the cpumodel for deciding about a facility
without enabling it for older QEMUs or QEMUs without a CPU
model.

Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/tools/gen_facilities.c

index 339ac0964590a1337935ea55ee0cbc7d7c2e441e..56061cf82f01dd17c6d3c8817742290b66265bdd 100644 (file)
@@ -152,13 +152,33 @@ static int nested;
 module_param(nested, int, S_IRUGO);
 MODULE_PARM_DESC(nested, "Nested virtualization support");
 
-/* upper facilities limit for kvm */
-unsigned long kvm_s390_fac_list_mask[16] = { FACILITIES_KVM };
 
-unsigned long kvm_s390_fac_list_mask_size(void)
+/*
+ * 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
+
+/*
+ * 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 };
+/*
+ * 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(ARRAY_SIZE(kvm_s390_fac_list_mask) > S390_ARCH_FAC_MASK_SIZE_U64);
-       return ARRAY_SIZE(kvm_s390_fac_list_mask);
+       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(S390_lowcore.stfle_fac_list));
+
+       return SIZE_INTERNAL;
 }
 
 /* available cpu features supported by kvm */
@@ -1967,20 +1987,15 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
        if (!kvm->arch.sie_page2)
                goto out_err;
 
-       /* Populate the facility mask initially. */
-       memcpy(kvm->arch.model.fac_mask, S390_lowcore.stfle_fac_list,
-              sizeof(S390_lowcore.stfle_fac_list));
-       for (i = 0; i < S390_ARCH_FAC_LIST_SIZE_U64; i++) {
-               if (i < kvm_s390_fac_list_mask_size())
-                       kvm->arch.model.fac_mask[i] &= kvm_s390_fac_list_mask[i];
-               else
-                       kvm->arch.model.fac_mask[i] = 0UL;
-       }
-
-       /* Populate the facility list initially. */
        kvm->arch.model.fac_list = kvm->arch.sie_page2->fac_list;
-       memcpy(kvm->arch.model.fac_list, kvm->arch.model.fac_mask,
-              S390_ARCH_FAC_LIST_SIZE_BYTE);
+
+       for (i = 0; i < kvm_s390_fac_size(); i++) {
+               kvm->arch.model.fac_mask[i] = S390_lowcore.stfle_fac_list[i] &
+                                             (kvm_s390_fac_base[i] |
+                                              kvm_s390_fac_ext[i]);
+               kvm->arch.model.fac_list[i] = S390_lowcore.stfle_fac_list[i] &
+                                             kvm_s390_fac_base[i];
+       }
 
        /* we are always in czam mode - even on pre z14 machines */
        set_kvm_facility(kvm->arch.model.fac_mask, 138);
@@ -4044,7 +4059,7 @@ static int __init kvm_s390_init(void)
        }
 
        for (i = 0; i < 16; i++)
-               kvm_s390_fac_list_mask[i] |=
+               kvm_s390_fac_base[i] |=
                        S390_lowcore.stfle_fac_list[i] & nonhyp_mask(i);
 
        return kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
index f55ac0ef99ea70bf3fb1d8f7eb7e303eb405b2b4..1b5621f4fe5bfd5bd353b96e30bf82440430a1b2 100644 (file)
@@ -294,8 +294,6 @@ void exit_sie(struct kvm_vcpu *vcpu);
 void kvm_s390_sync_request(int req, struct kvm_vcpu *vcpu);
 int kvm_s390_vcpu_setup_cmma(struct kvm_vcpu *vcpu);
 void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu);
-unsigned long kvm_s390_fac_list_mask_size(void);
-extern unsigned long kvm_s390_fac_list_mask[];
 void kvm_s390_set_cpu_timer(struct kvm_vcpu *vcpu, __u64 cputm);
 __u64 kvm_s390_get_cpu_timer(struct kvm_vcpu *vcpu);
 
index 424a1ba4f874ad3f85f73322d5432d774fdf0498..90a8c9e84ca60e6891ca0b545bf543ec8eb1bfc7 100644 (file)
@@ -62,6 +62,13 @@ static struct facility_def facility_defs[] = {
                }
        },
        {
+               /*
+                * FACILITIES_KVM contains the list of facilities that are part
+                * of the default facility mask and list that are passed to the
+                * initial CPU model. If no CPU model is used, this, together
+                * with the non-hypervisor managed bits, is the maximum list of
+                * guest facilities supported by KVM.
+                */
                .name = "FACILITIES_KVM",
                .bits = (int[]){
                        0,  /* N3 instructions */
@@ -89,6 +96,19 @@ static struct facility_def facility_defs[] = {
                        -1  /* END */
                }
        },
+       {
+               /*
+                * FACILITIES_KVM_CPUMODEL contains the list of facilities
+                * that can be enabled by CPU model code if the host supports
+                * it. These facilities are not passed to the guest without
+                * CPU model support.
+                */
+
+               .name = "FACILITIES_KVM_CPUMODEL",
+               .bits = (int[]){
+                       -1  /* END */
+               }
+       },
 };
 
 static void print_facility_list(struct facility_def *def)