]> git.baikalelectronics.ru Git - kernel.git/commitdiff
s390/mcck: move register validation to C code
authorAlexander Gordeev <agordeev@linux.ibm.com>
Fri, 18 Jun 2021 06:17:18 +0000 (08:17 +0200)
committerVasily Gorbik <gor@linux.ibm.com>
Mon, 5 Jul 2021 10:44:23 +0000 (12:44 +0200)
This update partially reverts commit 2a31ee8fd079 ("s390/nmi:
do register validation as early as possible").

Storage error checks and control registers validation are left
in the assembler code, since correct ASCEs and page tables are
required to enable DAT - which is done before the C handler is
entered.

System damage, kernel instruction address and PSW MWP checks
are left in the assembler code as well, since there is no way
to proceed if one of these checks is failed.

The getcpu vdso syscall reads CPU number from the programmable
field of the TOD clock. Disregard the TOD programmable register
validity bit and load the CPU number into the TOD programmable
field unconditionally.

Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/include/asm/ctl_reg.h
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/entry.S
arch/s390/kernel/nmi.c

index ed5efbb531c40c73e36aa41813e76d6ee0ff63d9..adc0179fa34e98e91ae3216737949c7a63e4ad0b 100644 (file)
@@ -21,8 +21,6 @@
 #define CR0_INTERRUPT_KEY_SUBMASK      BIT(63 - 57)
 #define CR0_MEASUREMENT_ALERT_SUBMASK  BIT(63 - 58)
 
-#define CR2_GUARDED_STORAGE            BIT(63 - 59)
-
 #define CR14_UNUSED_32                 BIT(63 - 32)
 #define CR14_UNUSED_33                 BIT(63 - 33)
 #define CR14_CHANNEL_REPORT_SUBMASK    BIT(63 - 35)
index f53605a3dfcdcb5335effc63dcff68c7bdfe13cc..77ff2130cb04529f40683e2d7ebe3584574e14fd 100644 (file)
@@ -14,8 +14,6 @@
 #include <linux/pgtable.h>
 #include <asm/idle.h>
 #include <asm/gmap.h>
-#include <asm/nmi.h>
-#include <asm/setup.h>
 #include <asm/stacktrace.h>
 
 int main(void)
@@ -108,7 +106,6 @@ int main(void)
        OFFSET(__LC_LAST_UPDATE_CLOCK, lowcore, last_update_clock);
        OFFSET(__LC_INT_CLOCK, lowcore, int_clock);
        OFFSET(__LC_MCCK_CLOCK, lowcore, mcck_clock);
-       OFFSET(__LC_CLOCK_COMPARATOR, lowcore, clock_comparator);
        OFFSET(__LC_BOOT_CLOCK, lowcore, boot_clock);
        OFFSET(__LC_CURRENT, lowcore, current_task);
        OFFSET(__LC_KERNEL_STACK, lowcore, kernel_stack);
@@ -145,9 +142,6 @@ int main(void)
        OFFSET(__LC_CREGS_SAVE_AREA, lowcore, cregs_save_area);
        OFFSET(__LC_PGM_TDB, lowcore, pgm_tdb);
        BLANK();
-       /* extended machine check save area */
-       OFFSET(__MCESA_GS_SAVE_AREA, mcesa, guarded_storage_save_area);
-       BLANK();
        /* gmap/sie offsets */
        OFFSET(__GMAP_ASCE, gmap, asce);
        OFFSET(__SIE_PROG0C, kvm_s390_sie_block, prog0c);
index 8f72a8f9bc333a131b1f1e5e78ec47cb2e579aed..5a2f70cbd3a9da8e34f458212e1198ba62d3cb50 100644 (file)
@@ -14,7 +14,6 @@
 #include <asm/alternative-asm.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
-#include <asm/ctl_reg.h>
 #include <asm/dwarf.h>
 #include <asm/errno.h>
 #include <asm/ptrace.h>
@@ -506,8 +505,6 @@ ENTRY(mcck_int_handler)
        BPOFF
        la      %r1,4095                # validate r1
        spt     __LC_CPU_TIMER_SAVE_AREA-4095(%r1)      # validate cpu timer
-       sckc    __LC_CLOCK_COMPARATOR                   # validate comparator
-       lam     %a0,%a15,__LC_AREGS_SAVE_AREA-4095(%r1) # validate acrs
        lmg     %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# validate gprs
        lg      %r12,__LC_CURRENT
        lmg     %r8,%r9,__LC_MCK_OLD_PSW
@@ -518,41 +515,7 @@ ENTRY(mcck_int_handler)
        la      %r14,4095
        lctlg   %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r14) # validate ctl regs
        ptlb
-       lg      %r11,__LC_MCESAD-4095(%r14) # extended machine check save area
-       nill    %r11,0xfc00             # MCESA_ORIGIN_MASK
-       TSTMSK  __LC_CREGS_SAVE_AREA+16-4095(%r14),CR2_GUARDED_STORAGE
-       jno     0f
-       TSTMSK  __LC_MCCK_CODE,MCCK_CODE_GS_VALID
-       jno     0f
-       .insn    rxy,0xe3000000004d,0,__MCESA_GS_SAVE_AREA(%r11) # LGSC
-0:     l       %r14,__LC_FP_CREG_SAVE_AREA-4095(%r14)
-       TSTMSK  __LC_MCCK_CODE,MCCK_CODE_FC_VALID
-       jo      0f
-       sr      %r14,%r14
-0:     sfpc    %r14
-       TSTMSK  __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
-       jo      0f
-       lghi    %r14,__LC_FPREGS_SAVE_AREA
-       ld      %f0,0(%r14)
-       ld      %f1,8(%r14)
-       ld      %f2,16(%r14)
-       ld      %f3,24(%r14)
-       ld      %f4,32(%r14)
-       ld      %f5,40(%r14)
-       ld      %f6,48(%r14)
-       ld      %f7,56(%r14)
-       ld      %f8,64(%r14)
-       ld      %f9,72(%r14)
-       ld      %f10,80(%r14)
-       ld      %f11,88(%r14)
-       ld      %f12,96(%r14)
-       ld      %f13,104(%r14)
-       ld      %f14,112(%r14)
-       ld      %f15,120(%r14)
-       j       1f
-0:     VLM     %v0,%v15,0,%r11
-       VLM     %v16,%v31,256,%r11
-1:     lghi    %r14,__LC_CPU_TIMER_SAVE_AREA
+       lghi    %r14,__LC_CPU_TIMER_SAVE_AREA
        mvc     __LC_MCCK_ENTER_TIMER(8),0(%r14)
        TSTMSK  __LC_MCCK_CODE,MCCK_CODE_CPU_TIMER_VALID
        jo      3f
index fdb5d23ac995711e7922901f2a7952e3301a9d02..20f8e1868853fde3e4f4ed592f042038ba53916f 100644 (file)
@@ -189,12 +189,16 @@ void noinstr s390_handle_mcck(void)
  * returns 0 if all required registers are available
  * returns 1 otherwise
  */
-static int notrace s390_check_registers(union mci mci, int umode)
+static int notrace s390_validate_registers(union mci mci, int umode)
 {
+       struct mcesa *mcesa;
+       void *fpt_save_area;
        union ctlreg2 cr2;
        int kill_task;
+       u64 zero;
 
        kill_task = 0;
+       zero = 0;
 
        if (!mci.gr) {
                /*
@@ -217,35 +221,89 @@ static int notrace s390_check_registers(union mci mci, int umode)
                if (!test_cpu_flag(CIF_FPU))
                        kill_task = 1;
        }
+       fpt_save_area = &S390_lowcore.floating_pt_save_area;
        if (!mci.fc) {
                /*
                 * Floating point control register can't be restored.
                 * If the kernel currently uses the floating pointer
                 * registers and needs the FPC register the system is
                 * stopped. If the process has its floating pointer
-                * registers loaded it is terminated.
+                * registers loaded it is terminated. Otherwise the
+                * FPC is just validated.
                 */
                if (S390_lowcore.fpu_flags & KERNEL_FPC)
                        s390_handle_damage();
+               asm volatile(
+                       "       lfpc    %0\n"
+                       :
+                       : "Q" (zero));
                if (!test_cpu_flag(CIF_FPU))
                        kill_task = 1;
+       } else {
+               asm volatile(
+                       "       lfpc    %0\n"
+                       :
+                       : "Q" (S390_lowcore.fpt_creg_save_area));
        }
 
-       if (MACHINE_HAS_VX) {
+       mcesa = (struct mcesa *)(S390_lowcore.mcesad & MCESA_ORIGIN_MASK);
+       if (!MACHINE_HAS_VX) {
+               /* Validate floating point registers */
+               asm volatile(
+                       "       ld      0,0(%0)\n"
+                       "       ld      1,8(%0)\n"
+                       "       ld      2,16(%0)\n"
+                       "       ld      3,24(%0)\n"
+                       "       ld      4,32(%0)\n"
+                       "       ld      5,40(%0)\n"
+                       "       ld      6,48(%0)\n"
+                       "       ld      7,56(%0)\n"
+                       "       ld      8,64(%0)\n"
+                       "       ld      9,72(%0)\n"
+                       "       ld      10,80(%0)\n"
+                       "       ld      11,88(%0)\n"
+                       "       ld      12,96(%0)\n"
+                       "       ld      13,104(%0)\n"
+                       "       ld      14,112(%0)\n"
+                       "       ld      15,120(%0)\n"
+                       :
+                       : "a" (fpt_save_area)
+                       : "memory");
+       } else {
+               /* Validate vector registers */
+               union ctlreg0 cr0;
+
                if (!mci.vr) {
                        /*
                         * Vector registers can't be restored. If the kernel
                         * currently uses vector registers the system is
                         * stopped. If the process has its vector registers
-                        * loaded it is terminated.
+                        * loaded it is terminated. Otherwise just validate
+                        * the registers.
                         */
                        if (S390_lowcore.fpu_flags & KERNEL_VXR)
                                s390_handle_damage();
                        if (!test_cpu_flag(CIF_FPU))
                                kill_task = 1;
                }
+               cr0.val = S390_lowcore.cregs_save_area[0];
+               cr0.afp = cr0.vx = 1;
+               __ctl_load(cr0.val, 0, 0);
+               asm volatile(
+                       "       la      1,%0\n"
+                       "       .word   0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */
+                       "       .word   0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */
+                       :
+                       : "Q" (*(struct vx_array *)mcesa->vector_save_area)
+                       : "1");
+               __ctl_load(S390_lowcore.cregs_save_area[0], 0, 0);
        }
-       /* Check if access registers are valid */
+       /* Validate access registers */
+       asm volatile(
+               "       lam     0,15,0(%0)\n"
+               :
+               : "a" (&S390_lowcore.access_regs_save_area)
+               : "memory");
        if (!mci.ar) {
                /*
                 * Access registers have unknown contents.
@@ -253,7 +311,7 @@ static int notrace s390_check_registers(union mci mci, int umode)
                 */
                kill_task = 1;
        }
-       /* Check guarded storage registers */
+       /* Validate guarded storage registers */
        cr2.val = S390_lowcore.cregs_save_area[2];
        if (cr2.gse) {
                if (!mci.gs) {
@@ -263,15 +321,26 @@ static int notrace s390_check_registers(union mci mci, int umode)
                         * It has to be terminated.
                         */
                        kill_task = 1;
+               } else {
+                       load_gs_cb((struct gs_cb *)mcesa->guarded_storage_save_area);
                }
        }
+       /*
+        * The getcpu vdso syscall reads CPU number from the programmable
+        * field of the TOD clock. Disregard the TOD programmable register
+        * validity bit and load the CPU number into the TOD programmable
+        * field unconditionally.
+        */
+       set_tod_programmable_field(raw_smp_processor_id());
+       /* Validate clock comparator register */
+       set_clock_comparator(S390_lowcore.clock_comparator);
 
        if (!mci.ms || !mci.pm || !mci.ia)
                kill_task = 1;
 
        return kill_task;
 }
-NOKPROBE_SYMBOL(s390_check_registers);
+NOKPROBE_SYMBOL(s390_validate_registers);
 
 /*
  * Backup the guest's machine check info to its description block
@@ -369,7 +438,7 @@ int notrace s390_do_machine_check(struct pt_regs *regs)
                        s390_handle_damage();
                }
        }
-       if (s390_check_registers(mci, user_mode(regs))) {
+       if (s390_validate_registers(mci, user_mode(regs))) {
                /*
                 * Couldn't restore all register contents for the
                 * user space process -> mark task for termination.