Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 83abeffb authored by Hendrik Brueckner's avatar Hendrik Brueckner Committed by Martin Schwidefsky
Browse files

s390/entry: add assembler macro to conveniently tests under mask



Various functions in entry.S perform test-under-mask instructions
to test for particular bits in memory.  Because test-under-mask uses
a mask value of one byte, the mask value and the offset into the
memory must be calculated manually.  This easily introduces errors
and is hard to review and read.

Introduce the TSTMSK assembler macro to specify a mask constant and
let the macro calculate the offset and the byte mask to generate a
test-under-mask instruction.  The benefit is that existing symbolic
constants can now be used for tests.  Also the macro checks for
zero mask values and mask values that consist of multiple bytes.

Signed-off-by: default avatarHendrik Brueckner <brueckner@linux.vnet.ibm.com>
Reviewed-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 0ac27779
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -11,8 +11,16 @@
#ifndef _ASM_S390_NMI_H
#define _ASM_S390_NMI_H

#include <linux/const.h>
#include <linux/types.h>

#define MCCK_CODE_SYSTEM_DAMAGE		_BITUL(63)
#define MCCK_CODE_CPU_TIMER_VALID	_BITUL(63 - 46)
#define MCCK_CODE_PSW_MWP_VALID		_BITUL(63 - 20)
#define MCCK_CODE_PSW_IA_VALID		_BITUL(63 - 23)

#ifndef __ASSEMBLY__

struct mci {
	__u32 sd :  1; /* 00 system damage */
	__u32 pd :  1; /* 01 instruction-processing damage */
@@ -63,4 +71,5 @@ struct pt_regs;
extern void s390_handle_mcck(void);
extern void s390_do_machine_check(struct pt_regs *regs);

#endif /* __ASSEMBLY__ */
#endif /* _ASM_S390_NMI_H */
+24 −23
Original line number Diff line number Diff line
@@ -5,11 +5,35 @@
#ifndef _ASM_S390_SETUP_H
#define _ASM_S390_SETUP_H

#include <linux/const.h>
#include <uapi/asm/setup.h>


#define PARMAREA		0x10400

/*
 * Machine features detected in head.S
 */

#define MACHINE_FLAG_VM		_BITUL(0)
#define MACHINE_FLAG_IEEE	_BITUL(1)
#define MACHINE_FLAG_CSP	_BITUL(2)
#define MACHINE_FLAG_MVPG	_BITUL(3)
#define MACHINE_FLAG_DIAG44	_BITUL(4)
#define MACHINE_FLAG_IDTE	_BITUL(5)
#define MACHINE_FLAG_DIAG9C	_BITUL(6)
#define MACHINE_FLAG_KVM	_BITUL(8)
#define MACHINE_FLAG_ESOP	_BITUL(9)
#define MACHINE_FLAG_EDAT1	_BITUL(10)
#define MACHINE_FLAG_EDAT2	_BITUL(11)
#define MACHINE_FLAG_LPAR	_BITUL(12)
#define MACHINE_FLAG_LPP	_BITUL(13)
#define MACHINE_FLAG_TOPOLOGY	_BITUL(14)
#define MACHINE_FLAG_TE		_BITUL(15)
#define MACHINE_FLAG_TLB_LC	_BITUL(17)
#define MACHINE_FLAG_VX		_BITUL(18)
#define MACHINE_FLAG_CAD	_BITUL(19)

#ifndef __ASSEMBLY__

#include <asm/lowcore.h>
@@ -28,29 +52,6 @@ extern unsigned long max_physmem_end;

extern void detect_memory_memblock(void);

/*
 * Machine features detected in head.S
 */

#define MACHINE_FLAG_VM		(1UL << 0)
#define MACHINE_FLAG_IEEE	(1UL << 1)
#define MACHINE_FLAG_CSP	(1UL << 2)
#define MACHINE_FLAG_MVPG	(1UL << 3)
#define MACHINE_FLAG_DIAG44	(1UL << 4)
#define MACHINE_FLAG_IDTE	(1UL << 5)
#define MACHINE_FLAG_DIAG9C	(1UL << 6)
#define MACHINE_FLAG_KVM	(1UL << 8)
#define MACHINE_FLAG_ESOP	(1UL << 9)
#define MACHINE_FLAG_EDAT1	(1UL << 10)
#define MACHINE_FLAG_EDAT2	(1UL << 11)
#define MACHINE_FLAG_LPAR	(1UL << 12)
#define MACHINE_FLAG_LPP	(1UL << 13)
#define MACHINE_FLAG_TOPOLOGY	(1UL << 14)
#define MACHINE_FLAG_TE		(1UL << 15)
#define MACHINE_FLAG_TLB_LC	(1UL << 17)
#define MACHINE_FLAG_VX		(1UL << 18)
#define MACHINE_FLAG_CAD	(1UL << 19)

#define MACHINE_IS_VM		(S390_lowcore.machine_flags & MACHINE_FLAG_VM)
#define MACHINE_IS_KVM		(S390_lowcore.machine_flags & MACHINE_FLAG_KVM)
#define MACHINE_IS_LPAR		(S390_lowcore.machine_flags & MACHINE_FLAG_LPAR)
+65 −41
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@
#include <asm/sigp.h>
#include <asm/irq.h>
#include <asm/vx-insn.h>
#include <asm/setup.h>
#include <asm/nmi.h>

__PT_R0      =	__PT_GPRS
__PT_R1      =	__PT_GPRS + 8
@@ -138,6 +140,28 @@ _PIF_WORK = (_PIF_PER_TRAP)
#endif
	.endm

	/*
	 * The TSTMSK macro generates a test-under-mask instruction by
	 * calculating the memory offset for the specified mask value.
	 * Mask value can be any constant.  The macro shifts the mask
	 * value to calculate the memory offset for the test-under-mask
	 * instruction.
	 */
	.macro TSTMSK addr, mask, size=8, bytepos=0
		.if (\bytepos < \size) && (\mask >> 8)
			.if (\mask & 0xff)
				.error "Mask exceeds byte boundary"
			.endif
			TSTMSK \addr, "(\mask >> 8)", \size, "(\bytepos + 1)"
			.exitm
		.endif
		.ifeq \mask
			.error "Mask must not be zero"
		.endif
		off = \size - \bytepos - 1
		tm	off+\addr, \mask
	.endm

	.section .kprobes.text, "ax"

/*
@@ -180,7 +204,7 @@ ENTRY(sie64a)
	stg	%r2,__SF_EMPTY(%r15)		# save control block pointer
	stg	%r3,__SF_EMPTY+8(%r15)		# save guest register save area
	xc	__SF_EMPTY+16(16,%r15),__SF_EMPTY+16(%r15) # host id & reason
	tm	__LC_CPU_FLAGS+7,_CIF_FPU	# load guest fp/vx registers ?
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU		# load guest fp/vx registers ?
	jno	.Lsie_load_guest_gprs
	brasl	%r14,load_fpu_regs		# load guest fp/vx regs
.Lsie_load_guest_gprs:
@@ -194,14 +218,14 @@ ENTRY(sie64a)
	oi	__SIE_PROG0C+3(%r14),1		# we are going into SIE now
	tm	__SIE_PROG20+3(%r14),3		# last exit...
	jnz	.Lsie_skip
	tm	__LC_CPU_FLAGS+7,_CIF_FPU
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
	jo	.Lsie_skip			# exit if fp/vx regs changed
	tm	__LC_MACHINE_FLAGS+6,0x20	# MACHINE_FLAG_LPP
	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_LPP
	jz	.Lsie_enter
	.insn	s,0xb2800000,__LC_CURRENT_PID	# set guest id to pid
.Lsie_enter:
	sie	0(%r14)
	tm	__LC_MACHINE_FLAGS+6,0x20	# MACHINE_FLAG_LPP
	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_LPP
	jz	.Lsie_skip
	.insn	s,0xb2800000,__SF_EMPTY+16(%r15)# set host id
.Lsie_skip:
@@ -270,7 +294,7 @@ ENTRY(system_call)
	stg	%r2,__PT_ORIG_GPR2(%r11)
	stg	%r7,STACK_FRAME_OVERHEAD(%r15)
	lgf	%r9,0(%r8,%r10)			# get system call add.
	tm	__TI_flags+7(%r12),_TIF_TRACE
	TSTMSK	__TI_flags(%r12),_TIF_TRACE
	jnz	.Lsysc_tracesys
	basr	%r14,%r9			# call sys_xxxx
	stg	%r2,__PT_R2(%r11)		# store return value
@@ -278,11 +302,11 @@ ENTRY(system_call)
.Lsysc_return:
	LOCKDEP_SYS_EXIT
.Lsysc_tif:
	tm	__PT_FLAGS+7(%r11),_PIF_WORK
	TSTMSK	__PT_FLAGS(%r11),_PIF_WORK
	jnz	.Lsysc_work
	tm	__TI_flags+7(%r12),_TIF_WORK
	TSTMSK	__TI_flags(%r12),_TIF_WORK
	jnz	.Lsysc_work			# check for work
	tm	__LC_CPU_FLAGS+7,_CIF_WORK
	TSTMSK	__LC_CPU_FLAGS,_CIF_WORK
	jnz	.Lsysc_work
.Lsysc_restore:
	lg	%r14,__LC_VDSO_PER_CPU
@@ -298,23 +322,23 @@ ENTRY(system_call)
# One of the work bits is on. Find out which one.
#
.Lsysc_work:
	tm	__LC_CPU_FLAGS+7,_CIF_MCCK_PENDING
	TSTMSK	__LC_CPU_FLAGS,_CIF_MCCK_PENDING
	jo	.Lsysc_mcck_pending
	tm	__TI_flags+7(%r12),_TIF_NEED_RESCHED
	TSTMSK	__TI_flags(%r12),_TIF_NEED_RESCHED
	jo	.Lsysc_reschedule
#ifdef CONFIG_UPROBES
	tm	__TI_flags+7(%r12),_TIF_UPROBE
	TSTMSK	__TI_flags(%r12),_TIF_UPROBE
	jo	.Lsysc_uprobe_notify
#endif
	tm	__PT_FLAGS+7(%r11),_PIF_PER_TRAP
	TSTMSK	__PT_FLAGS(%r11),_PIF_PER_TRAP
	jo	.Lsysc_singlestep
	tm	__TI_flags+7(%r12),_TIF_SIGPENDING
	TSTMSK	__TI_flags(%r12),_TIF_SIGPENDING
	jo	.Lsysc_sigpending
	tm	__TI_flags+7(%r12),_TIF_NOTIFY_RESUME
	TSTMSK	__TI_flags(%r12),_TIF_NOTIFY_RESUME
	jo	.Lsysc_notify_resume
	tm	__LC_CPU_FLAGS+7,_CIF_FPU
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
	jo	.Lsysc_vxrs
	tm	__LC_CPU_FLAGS+7,_CIF_ASCE
	TSTMSK	__LC_CPU_FLAGS,_CIF_ASCE
	jo	.Lsysc_uaccess
	j	.Lsysc_return		# beware of critical section cleanup

@@ -353,7 +377,7 @@ ENTRY(system_call)
.Lsysc_sigpending:
	lgr	%r2,%r11		# pass pointer to pt_regs
	brasl	%r14,do_signal
	tm	__PT_FLAGS+7(%r11),_PIF_SYSCALL
	TSTMSK	__PT_FLAGS(%r11),_PIF_SYSCALL
	jno	.Lsysc_return
	lmg	%r2,%r7,__PT_R2(%r11)	# load svc arguments
	lg	%r10,__TI_sysc_table(%r12)	# address of system call table
@@ -413,7 +437,7 @@ ENTRY(system_call)
	basr	%r14,%r9		# call sys_xxx
	stg	%r2,__PT_R2(%r11)	# store return value
.Lsysc_tracenogo:
	tm	__TI_flags+7(%r12),_TIF_TRACE
	TSTMSK	__TI_flags(%r12),_TIF_TRACE
	jz	.Lsysc_return
	lgr	%r2,%r11		# pass pointer to pt_regs
	larl	%r14,.Lsysc_return
@@ -553,7 +577,7 @@ ENTRY(io_int_handler)
	lghi	%r3,THIN_INTERRUPT
.Lio_call:
	brasl	%r14,do_IRQ
	tm	__LC_MACHINE_FLAGS+6,0x10	# MACHINE_FLAG_LPAR
	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_LPAR
	jz	.Lio_return
	tpi	0
	jz	.Lio_return
@@ -563,9 +587,9 @@ ENTRY(io_int_handler)
	LOCKDEP_SYS_EXIT
	TRACE_IRQS_ON
.Lio_tif:
	tm	__TI_flags+7(%r12),_TIF_WORK
	TSTMSK	__TI_flags(%r12),_TIF_WORK
	jnz	.Lio_work		# there is work to do (signals etc.)
	tm	__LC_CPU_FLAGS+7,_CIF_WORK
	TSTMSK	__LC_CPU_FLAGS,_CIF_WORK
	jnz	.Lio_work
.Lio_restore:
	lg	%r14,__LC_VDSO_PER_CPU
@@ -593,7 +617,7 @@ ENTRY(io_int_handler)
	# check for preemptive scheduling
	icm	%r0,15,__TI_precount(%r12)
	jnz	.Lio_restore		# preemption is disabled
	tm	__TI_flags+7(%r12),_TIF_NEED_RESCHED
	TSTMSK	__TI_flags(%r12),_TIF_NEED_RESCHED
	jno	.Lio_restore
	# switch to kernel stack
	lg	%r1,__PT_R15(%r11)
@@ -625,17 +649,17 @@ ENTRY(io_int_handler)
# One of the work bits is on. Find out which one.
#
.Lio_work_tif:
	tm	__LC_CPU_FLAGS+7,_CIF_MCCK_PENDING
	TSTMSK	__LC_CPU_FLAGS,_CIF_MCCK_PENDING
	jo	.Lio_mcck_pending
	tm	__TI_flags+7(%r12),_TIF_NEED_RESCHED
	TSTMSK	__TI_flags(%r12),_TIF_NEED_RESCHED
	jo	.Lio_reschedule
	tm	__TI_flags+7(%r12),_TIF_SIGPENDING
	TSTMSK	__TI_flags(%r12),_TIF_SIGPENDING
	jo	.Lio_sigpending
	tm	__TI_flags+7(%r12),_TIF_NOTIFY_RESUME
	TSTMSK	__TI_flags(%r12),_TIF_NOTIFY_RESUME
	jo	.Lio_notify_resume
	tm	__LC_CPU_FLAGS+7,_CIF_FPU
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
	jo	.Lio_vxrs
	tm	__LC_CPU_FLAGS+7,_CIF_ASCE
	TSTMSK	__LC_CPU_FLAGS,_CIF_ASCE
	jo	.Lio_uaccess
	j	.Lio_return		# beware of critical section cleanup

@@ -757,12 +781,12 @@ ENTRY(psw_idle)
ENTRY(save_fpu_regs)
	lg	%r2,__LC_CURRENT
	aghi	%r2,__TASK_thread
	tm	__LC_CPU_FLAGS+7,_CIF_FPU
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
	bor	%r14
	stfpc	__THREAD_FPU_fpc(%r2)
.Lsave_fpu_regs_fpc_end:
	lg	%r3,__THREAD_FPU_regs(%r2)
	tm	__LC_MACHINE_FLAGS+5,4	  # MACHINE_HAS_VX
	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_VX
	jz	.Lsave_fpu_regs_fp	  # no -> store FP regs
.Lsave_fpu_regs_vx_low:
	VSTM	%v0,%v15,0,%r3		  # vstm 0,15,0(3)
@@ -804,10 +828,10 @@ ENTRY(save_fpu_regs)
load_fpu_regs:
	lg	%r4,__LC_CURRENT
	aghi	%r4,__TASK_thread
	tm	__LC_CPU_FLAGS+7,_CIF_FPU
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
	bnor	%r14
	lfpc	__THREAD_FPU_fpc(%r4)
	tm	__LC_MACHINE_FLAGS+5,4		# MACHINE_HAS_VX
	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_VX
	lg	%r4,__THREAD_FPU_regs(%r4)	# %r4 <- reg save area
	jz	.Lload_fpu_regs_fp		# -> no VX, load FP regs
.Lload_fpu_regs_vx:
@@ -851,11 +875,11 @@ ENTRY(mcck_int_handler)
	lg	%r12,__LC_THREAD_INFO
	larl	%r13,cleanup_critical
	lmg	%r8,%r9,__LC_MCK_OLD_PSW
	tm	__LC_MCCK_CODE,0x80	# system damage?
	TSTMSK	__LC_MCCK_CODE,MCCK_CODE_SYSTEM_DAMAGE
	jo	.Lmcck_panic		# yes -> rest of mcck code invalid
	lghi	%r14,__LC_CPU_TIMER_SAVE_AREA
	mvc	__LC_MCCK_ENTER_TIMER(8),0(%r14)
	tm	__LC_MCCK_CODE+5,0x02	# stored cpu timer value valid?
	TSTMSK	__LC_MCCK_CODE,MCCK_CODE_CPU_TIMER_VALID
	jo	3f
	la	%r14,__LC_SYNC_ENTER_TIMER
	clc	0(8,%r14),__LC_ASYNC_ENTER_TIMER
@@ -869,7 +893,7 @@ ENTRY(mcck_int_handler)
	la	%r14,__LC_LAST_UPDATE_TIMER
2:	spt	0(%r14)
	mvc	__LC_MCCK_ENTER_TIMER(8),0(%r14)
3:	tm	__LC_MCCK_CODE+2,0x09	# mwp + ia of old psw valid?
3:	TSTMSK	__LC_MCCK_CODE,(MCCK_CODE_PSW_MWP_VALID|MCCK_CODE_PSW_IA_VALID)
	jno	.Lmcck_panic		# no -> skip cleanup critical
	SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+64,__LC_MCCK_ENTER_TIMER
.Lmcck_skip:
@@ -889,7 +913,7 @@ ENTRY(mcck_int_handler)
	la	%r11,STACK_FRAME_OVERHEAD(%r1)
	lgr	%r15,%r1
	ssm	__LC_PGM_NEW_PSW	# turn dat on, keep irqs off
	tm	__LC_CPU_FLAGS+7,_CIF_MCCK_PENDING
	TSTMSK	__LC_CPU_FLAGS,_CIF_MCCK_PENDING
	jno	.Lmcck_return
	TRACE_IRQS_OFF
	brasl	%r14,s390_handle_mcck
@@ -1018,7 +1042,7 @@ cleanup_critical:

.Lcleanup_sie:
	lg	%r9,__SF_EMPTY(%r15)		# get control block pointer
	tm	__LC_MACHINE_FLAGS+6,0x20	# MACHINE_FLAG_LPP
	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_LPP
	jz	0f
	.insn	s,0xb2800000,__SF_EMPTY+16(%r15)# set host id
0:	ni	__SIE_PROG0C+3(%r9),0xfe	# no longer in SIE
@@ -1173,7 +1197,7 @@ cleanup_critical:
	.quad	.Lpsw_idle_lpsw

.Lcleanup_save_fpu_regs:
	tm	__LC_CPU_FLAGS+7,_CIF_FPU
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
	bor	%r14
	clg	%r9,BASED(.Lcleanup_save_fpu_regs_done)
	jhe	5f
@@ -1191,7 +1215,7 @@ cleanup_critical:
	stfpc	__THREAD_FPU_fpc(%r2)
1:	# Load register save area and check if VX is active
	lg	%r3,__THREAD_FPU_regs(%r2)
	tm	__LC_MACHINE_FLAGS+5,4	  # MACHINE_HAS_VX
	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_VX
	jz	4f			  # no VX -> store FP regs
2:	# Store vector registers (V0-V15)
	VSTM	%v0,%v15,0,%r3		  # vstm 0,15,0(3)
@@ -1231,7 +1255,7 @@ cleanup_critical:
	.quad	.Lsave_fpu_regs_done

.Lcleanup_load_fpu_regs:
	tm	__LC_CPU_FLAGS+7,_CIF_FPU
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
	bnor	%r14
	clg	%r9,BASED(.Lcleanup_load_fpu_regs_done)
	jhe	1f
@@ -1244,7 +1268,7 @@ cleanup_critical:
	lg	%r4,__LC_CURRENT
	aghi	%r4,__TASK_thread
	lfpc	__THREAD_FPU_fpc(%r4)
	tm	__LC_MACHINE_FLAGS+5,4		# MACHINE_HAS_VX
	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_VX
	lg	%r4,__THREAD_FPU_regs(%r4)	# %r4 <- reg save area
	jz	2f				# -> no VX, load FP regs
4:	# Load V0 ..V15 registers