s390/entry: add assembler macro to conveniently tests under mask
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>
Thu, 1 Oct 2015 15:02:48 +0000 (17:02 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 14 Oct 2015 12:32:09 +0000 (14:32 +0200)
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>
arch/s390/include/asm/nmi.h
arch/s390/include/asm/setup.h
arch/s390/kernel/entry.S

index 3027a5a..4c1cd41 100644 (file)
 #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 */
index b8ffc1b..ab015a7 100644 (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)
index 3f23185..2444ea7 100644 (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