s390/mcck: always enter C handler with DAT enabled
authorAlexander Gordeev <agordeev@linux.ibm.com>
Fri, 18 Jun 2021 06:17:15 +0000 (08:17 +0200)
committerVasily Gorbik <gor@linux.ibm.com>
Mon, 5 Jul 2021 10:44:23 +0000 (12:44 +0200)
The machine check handler must be entered with DAT disabled
in case control registers are corrupted or a storage error
happened and we can not tell if such error corresponds to a
page table.

Both of described conditions end up in stopping all CPUs and
entering the disabled wait in C half of the handler. However,
the storage errors are still checked after the DAT is enabled
and C code is entered. In case a page table is damaged such
flow is not expected to work.

This update paves the way for moving the storage error checks
from C to assembler half. All fatal errors that can only be
handled with DAT disabled are handled in assembler half also.
As result, the C half is only entered if the DAT is secured.

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/kernel/entry.S
arch/s390/kernel/nmi.c

index ff715cc2b77ba9cf3f61b28eb51f09997ce63121..6bc8ed80045895aaa0b40ad124e28881d771dc92 100644 (file)
@@ -570,7 +570,6 @@ ENTRY(mcck_int_handler)
        BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
 .Lmcck_stack:
        lg      %r15,__LC_MCCK_STACK
-.Lmcck_skip:
        la      %r11,STACK_FRAME_OVERHEAD(%r15)
        stctg   %c1,%c1,__PT_CR1(%r11)
        lctlg   %c1,%c1,__LC_KERNEL_ASCE
@@ -612,8 +611,33 @@ ENTRY(mcck_int_handler)
        b       __LC_RETURN_MCCK_LPSWE
 
 .Lmcck_panic:
-       lg      %r15,__LC_NODAT_STACK
-       j       .Lmcck_skip
+       /*
+        * Iterate over all possible CPU addresses in the range 0..0xffff
+        * and stop each CPU using signal processor. Use compare and swap
+        * to allow just one CPU-stopper and prevent concurrent CPUs from
+        * stopping each other while leaving the others running.
+        */
+       lhi     %r5,0
+       lhi     %r6,1
+       larl    %r7,.Lstop_lock
+       cs      %r5,%r6,0(%r7)          # single CPU-stopper only
+       jnz     4f
+       larl    %r7,.Lthis_cpu
+       stap    0(%r7)                  # this CPU address
+       lh      %r4,0(%r7)
+       nilh    %r4,0
+       lhi     %r0,1
+       sll     %r0,16                  # CPU counter
+       lhi     %r3,0                   # next CPU address
+0:     cr      %r3,%r4
+       je      2f
+1:     sigp    %r1,%r3,SIGP_STOP       # stop next CPU
+       brc     SIGP_CC_BUSY,1b
+2:     ahi     %r3,1
+       brct    %r0,0b
+3:     sigp    %r1,%r4,SIGP_STOP       # stop this CPU
+       brc     SIGP_CC_BUSY,3b
+4:     j       4b
 ENDPROC(mcck_int_handler)
 
 #
@@ -664,6 +688,11 @@ ENTRY(stack_overflow)
 ENDPROC(stack_overflow)
 #endif
 
+       .section .data, "aw"
+               .align  4
+.Lstop_lock:   .long   0
+.Lthis_cpu:    .short  0
+
        .section .rodata, "a"
 #define SYSCALL(esame,emu)     .quad __s390x_ ## esame
        .globl  sys_call_table
index 11f8c296f60d3c7b0e0507495108937868c68d20..a424f6e69b953c499cb1cfaae2e841be0313fc1f 100644 (file)
@@ -205,14 +205,6 @@ static int notrace s390_check_registers(union mci mci, int umode)
                        s390_handle_damage();
                kill_task = 1;
        }
-       /* Check control registers */
-       if (!mci.cr) {
-               /*
-                * Control registers have unknown contents.
-                * Can't recover and therefore stopping machine.
-                */
-               s390_handle_damage();
-       }
        if (!mci.fp) {
                /*
                 * Floating point registers can't be restored. If the
@@ -273,22 +265,6 @@ static int notrace s390_check_registers(union mci mci, int umode)
                        kill_task = 1;
                }
        }
-       /* Check if old PSW is valid */
-       if (!mci.wp) {
-               /*
-                * Can't tell if we come from user or kernel mode
-                * -> stopping machine.
-                */
-               s390_handle_damage();
-       }
-       /* Check for invalid kernel instruction address */
-       if (!mci.ia && !umode) {
-               /*
-                * The instruction address got lost while running
-                * in the kernel -> stopping machine.
-                */
-               s390_handle_damage();
-       }
 
        if (!mci.ms || !mci.pm || !mci.ia)
                kill_task = 1;
@@ -353,11 +329,6 @@ int notrace s390_do_machine_check(struct pt_regs *regs)
        mci.val = S390_lowcore.mcck_interruption_code;
        mcck = this_cpu_ptr(&cpu_mcck);
 
-       if (mci.sd) {
-               /* System damage -> stopping machine */
-               s390_handle_damage();
-       }
-
        /*
         * Reinject the instruction processing damages' machine checks
         * including Delayed Access Exception into the guest