Commit 7f6dc8d4 authored by Alexander Gordeev's avatar Alexander Gordeev Committed by Vasily Gorbik

s390/mcck: always enter C handler with DAT enabled

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: default avatarAlexander Gordeev <agordeev@linux.ibm.com>
Reviewed-by: default avatarHeiko Carstens <hca@linux.ibm.com>
Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent e2c13d64
...@@ -570,7 +570,6 @@ ENTRY(mcck_int_handler) ...@@ -570,7 +570,6 @@ ENTRY(mcck_int_handler)
BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
.Lmcck_stack: .Lmcck_stack:
lg %r15,__LC_MCCK_STACK lg %r15,__LC_MCCK_STACK
.Lmcck_skip:
la %r11,STACK_FRAME_OVERHEAD(%r15) la %r11,STACK_FRAME_OVERHEAD(%r15)
stctg %c1,%c1,__PT_CR1(%r11) stctg %c1,%c1,__PT_CR1(%r11)
lctlg %c1,%c1,__LC_KERNEL_ASCE lctlg %c1,%c1,__LC_KERNEL_ASCE
...@@ -612,8 +611,33 @@ ENTRY(mcck_int_handler) ...@@ -612,8 +611,33 @@ ENTRY(mcck_int_handler)
b __LC_RETURN_MCCK_LPSWE b __LC_RETURN_MCCK_LPSWE
.Lmcck_panic: .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) ENDPROC(mcck_int_handler)
# #
...@@ -664,6 +688,11 @@ ENTRY(stack_overflow) ...@@ -664,6 +688,11 @@ ENTRY(stack_overflow)
ENDPROC(stack_overflow) ENDPROC(stack_overflow)
#endif #endif
.section .data, "aw"
.align 4
.Lstop_lock: .long 0
.Lthis_cpu: .short 0
.section .rodata, "a" .section .rodata, "a"
#define SYSCALL(esame,emu) .quad __s390x_ ## esame #define SYSCALL(esame,emu) .quad __s390x_ ## esame
.globl sys_call_table .globl sys_call_table
......
...@@ -205,14 +205,6 @@ static int notrace s390_check_registers(union mci mci, int umode) ...@@ -205,14 +205,6 @@ static int notrace s390_check_registers(union mci mci, int umode)
s390_handle_damage(); s390_handle_damage();
kill_task = 1; 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) { if (!mci.fp) {
/* /*
* Floating point registers can't be restored. If the * Floating point registers can't be restored. If the
...@@ -273,22 +265,6 @@ static int notrace s390_check_registers(union mci mci, int umode) ...@@ -273,22 +265,6 @@ static int notrace s390_check_registers(union mci mci, int umode)
kill_task = 1; 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) if (!mci.ms || !mci.pm || !mci.ia)
kill_task = 1; kill_task = 1;
...@@ -353,11 +329,6 @@ int notrace s390_do_machine_check(struct pt_regs *regs) ...@@ -353,11 +329,6 @@ int notrace s390_do_machine_check(struct pt_regs *regs)
mci.val = S390_lowcore.mcck_interruption_code; mci.val = S390_lowcore.mcck_interruption_code;
mcck = this_cpu_ptr(&cpu_mcck); mcck = this_cpu_ptr(&cpu_mcck);
if (mci.sd) {
/* System damage -> stopping machine */
s390_handle_damage();
}
/* /*
* Reinject the instruction processing damages' machine checks * Reinject the instruction processing damages' machine checks
* including Delayed Access Exception into the guest * including Delayed Access Exception into the guest
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment