s390/alternative: use a copy of the facility bit mask
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 27 Apr 2018 05:36:44 +0000 (07:36 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 29 Apr 2018 09:31:59 +0000 (11:31 +0200)
[ Upstream commit cf1489984641369611556bf00c48f945c77bcf02 ]

To be able to switch off specific CPU alternatives with kernel parameters
make a copy of the facility bit mask provided by STFLE and use the copy
for the decision to apply an alternative.

Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/s390/include/asm/facility.h
arch/s390/include/asm/lowcore.h
arch/s390/kernel/alternative.c
arch/s390/kernel/early.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c

index 09b406db7529a34b62671b659c44ed895e7b9d19..7a8a1457dbb8553d3cf17dae7f105d808ad90d9a 100644 (file)
 
 #define MAX_FACILITY_BIT (256*8)       /* stfle_fac_list has 256 bytes */
 
+static inline void __set_facility(unsigned long nr, void *facilities)
+{
+       unsigned char *ptr = (unsigned char *) facilities;
+
+       if (nr >= MAX_FACILITY_BIT)
+               return;
+       ptr[nr >> 3] |= 0x80 >> (nr & 7);
+}
+
+static inline void __clear_facility(unsigned long nr, void *facilities)
+{
+       unsigned char *ptr = (unsigned char *) facilities;
+
+       if (nr >= MAX_FACILITY_BIT)
+               return;
+       ptr[nr >> 3] &= ~(0x80 >> (nr & 7));
+}
+
 static inline int __test_facility(unsigned long nr, void *facilities)
 {
        unsigned char *ptr;
index 7b93b78f423c667315f7d963178217937858936a..d52e7efea7d64384e09d1020f53afd7d07bfb591 100644 (file)
@@ -150,7 +150,8 @@ struct lowcore {
        __u8    pad_0x0e20[0x0f00-0x0e20];      /* 0x0e20 */
 
        /* Extended facility list */
-       __u64   stfle_fac_list[32];             /* 0x0f00 */
+       __u64   stfle_fac_list[16];             /* 0x0f00 */
+       __u64   alt_stfle_fac_list[16];         /* 0x0f80 */
        __u8    pad_0x1000[0x11b0-0x1000];      /* 0x1000 */
 
        /* Pointer to vector register save area */
index 315986a06cf57f2c768b4c1a549a794af7952b46..f5060af6117681583fc266ac2fb5d55bb82f667b 100644 (file)
@@ -74,7 +74,8 @@ static void __init_or_module __apply_alternatives(struct alt_instr *start,
                instr = (u8 *)&a->instr_offset + a->instr_offset;
                replacement = (u8 *)&a->repl_offset + a->repl_offset;
 
-               if (!test_facility(a->facility))
+               if (!__test_facility(a->facility,
+                                    S390_lowcore.alt_stfle_fac_list))
                        continue;
 
                if (unlikely(a->instrlen % 2 || a->replacementlen % 2)) {
index 62578989c74d3c8ef0067a84a31c901e8e0e90a5..171aaa221e4b7fd16db6cbee9559f83324f57c56 100644 (file)
@@ -299,6 +299,9 @@ static noinline __init void setup_facility_list(void)
 {
        stfle(S390_lowcore.stfle_fac_list,
              ARRAY_SIZE(S390_lowcore.stfle_fac_list));
+       memcpy(S390_lowcore.alt_stfle_fac_list,
+              S390_lowcore.stfle_fac_list,
+              sizeof(S390_lowcore.alt_stfle_fac_list));
 }
 
 static __init void detect_diag9c(void)
index c3bdb3e80380efd5f69ebf8553ada96dbfa15f43..433b380896b941b4957948cf5461c7e34dfb1c85 100644 (file)
@@ -336,7 +336,9 @@ static void __init setup_lowcore(void)
        lc->machine_flags = S390_lowcore.machine_flags;
        lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
        memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
-              MAX_FACILITY_BIT/8);
+              sizeof(lc->stfle_fac_list));
+       memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list,
+              sizeof(lc->alt_stfle_fac_list));
        if (MACHINE_HAS_VX)
                lc->vector_save_area_addr =
                        (unsigned long) &lc->vector_save_area;
index 35531fe1c5ea91c05b5d43a71e5de03894024287..63c8a840d56befdda6298cc1958796c2f0038109 100644 (file)
@@ -253,7 +253,9 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
        __ctl_store(lc->cregs_save_area, 0, 15);
        save_access_regs((unsigned int *) lc->access_regs_save_area);
        memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
-              MAX_FACILITY_BIT/8);
+              sizeof(lc->stfle_fac_list));
+       memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list,
+              sizeof(lc->alt_stfle_fac_list));
 }
 
 static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)