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: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Hendrik Brueckner 2015-10-01 17:02:48 +02:00 committed by Martin Schwidefsky
parent 0ac277790e
commit 83abeffbd5
3 changed files with 98 additions and 64 deletions

View File

@ -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 */

View File

@ -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)

View File

@ -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