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

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
Loading
Loading
Loading
Loading
+32 −3
Original line number Diff line number Diff line
@@ -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
+0 −29
Original line number Diff line number Diff line
@@ -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