Commit 1a914247 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: signals & exceptions

From: Martin Schwidefsky <schwidefsky@de.ibm.com>
From: Ulrich Weigand <uweigand@de.ibm.com>

s390 core changes:
 - Add signo between signal frame and the signal return instruction on the
   user stack for backtrace over signal handlers.
 - Add hfp floating point exceptions.
 - Use a single function for region, segment and page translation exceptions.
 - Discard SIGTRAP for single stepped instructions if the trapping instruction
   is repeated (normal memory faults) or if another signal is delivered anyway.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d9ca90fb
...@@ -40,6 +40,7 @@ typedef struct ...@@ -40,6 +40,7 @@ typedef struct
__u8 callee_used_stack[__SIGNAL_FRAMESIZE32]; __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
struct sigcontext32 sc; struct sigcontext32 sc;
_sigregs32 sregs; _sigregs32 sregs;
int signo;
__u8 retcode[S390_SYSCALL_SIZE]; __u8 retcode[S390_SYSCALL_SIZE];
} sigframe32; } sigframe32;
...@@ -497,6 +498,10 @@ static void setup_frame32(int sig, struct k_sigaction *ka, ...@@ -497,6 +498,10 @@ static void setup_frame32(int sig, struct k_sigaction *ka,
To avoid breaking binary compatibility, they are passed as args. */ To avoid breaking binary compatibility, they are passed as args. */
regs->gprs[4] = current->thread.trap_no; regs->gprs[4] = current->thread.trap_no;
regs->gprs[5] = current->thread.prot_addr; regs->gprs[5] = current->thread.prot_addr;
/* Place signal number on stack to allow backtrace from handler. */
if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
goto give_sigsegv;
return; return;
give_sigsegv: give_sigsegv:
......
...@@ -70,7 +70,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) ...@@ -70,7 +70,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
.macro CLEANUP_SAVE_ALL_BASE psworg,savearea,sync .macro CLEANUP_SAVE_ALL_BASE psworg,savearea,sync
l %r1,SP_PSW+4(%r15) l %r1,SP_PSW+4(%r15)
cli 1(%r1),0xcf cli 1(%r1),0xcf
jne 0f bne BASED(0f)
mvc \savearea(16),SP_R12(%r15) mvc \savearea(16),SP_R12(%r15)
0: st %r13,SP_R13(%r15) 0: st %r13,SP_R13(%r15)
.endm .endm
...@@ -140,9 +140,9 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) ...@@ -140,9 +140,9 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
.macro CLEANUP_RESTORE_ALL .macro CLEANUP_RESTORE_ALL
l %r1,SP_PSW+4(%r15) l %r1,SP_PSW+4(%r15)
cli 0(%r1),0x82 cli 0(%r1),0x82
jne 0f bne BASED(0f)
mvc SP_PSW(8,%r15),__LC_RETURN_PSW mvc SP_PSW(8,%r15),__LC_RETURN_PSW
j 1f b BASED(1f)
0: l %r1,SP_R15(%r15) 0: l %r1,SP_R15(%r15)
mvc SP_PSW(8,%r15),SP_PSW(%r1) mvc SP_PSW(8,%r15),SP_PSW(%r1)
mvc SP_R0(64,%r15),SP_R0(%r1) mvc SP_R0(64,%r15),SP_R0(%r1)
...@@ -157,9 +157,9 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) ...@@ -157,9 +157,9 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
tm SP_PSW+1(%r15),0x01 # test problem state bit tm SP_PSW+1(%r15),0x01 # test problem state bit
bnz BASED(0f) # from user -> not critical bnz BASED(0f) # from user -> not critical
clc SP_PSW+4(4,%r15),BASED(.Lcritical_end) clc SP_PSW+4(4,%r15),BASED(.Lcritical_end)
jnl 0f bnl BASED(0f)
clc SP_PSW+4(4,%r15),BASED(.Lcritical_start) clc SP_PSW+4(4,%r15),BASED(.Lcritical_start)
jl 0f bl BASED(0f)
l %r1,BASED(.Lcleanup_critical) l %r1,BASED(.Lcleanup_critical)
basr %r14,%r1 basr %r14,%r1
0: 0:
...@@ -291,6 +291,7 @@ sysc_reschedule: ...@@ -291,6 +291,7 @@ sysc_reschedule:
# _TIF_SIGPENDING is set, call do_signal # _TIF_SIGPENDING is set, call do_signal
# #
sysc_sigpending: sysc_sigpending:
ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
la %r2,SP_PTREGS(%r15) # load pt_regs la %r2,SP_PTREGS(%r15) # load pt_regs
sr %r3,%r3 # clear *oldset sr %r3,%r3 # clear *oldset
l %r1,BASED(.Ldo_signal) l %r1,BASED(.Ldo_signal)
...@@ -311,7 +312,7 @@ sysc_restart: ...@@ -311,7 +312,7 @@ sysc_restart:
b BASED(sysc_do_restart) # restart svc b BASED(sysc_do_restart) # restart svc
# #
# _TIF_SINGLE_STEP is set, call do_debugger_trap # _TIF_SINGLE_STEP is set, call do_single_step
# #
sysc_singlestep: sysc_singlestep:
ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
...@@ -319,7 +320,7 @@ sysc_singlestep: ...@@ -319,7 +320,7 @@ sysc_singlestep:
la %r2,SP_PTREGS(%r15) # address of register-save area la %r2,SP_PTREGS(%r15) # address of register-save area
l %r1,BASED(.Lhandle_per) # load adr. of per handler l %r1,BASED(.Lhandle_per) # load adr. of per handler
la %r14,BASED(sysc_return) # load adr. of system return la %r14,BASED(sysc_return) # load adr. of system return
br %r1 # branch to do_debugger_trap br %r1 # branch to do_single_step
__critical_end: __critical_end:
...@@ -460,8 +461,9 @@ pgm_check_handler: ...@@ -460,8 +461,9 @@ pgm_check_handler:
SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
l %r3,__LC_PGM_ILC # load program interruption code l %r3,__LC_PGM_ILC # load program interruption code
la %r8,0x7f la %r8,0x7f
l %r7,BASED(.Ljump_table)
nr %r8,%r3 nr %r8,%r3
pgm_do_call:
l %r7,BASED(.Ljump_table)
sll %r8,2 sll %r8,2
GET_THREAD_INFO GET_THREAD_INFO
l %r7,0(%r8,%r7) # load address of handler routine l %r7,0(%r8,%r7) # load address of handler routine
...@@ -492,20 +494,12 @@ pgm_per_std: ...@@ -492,20 +494,12 @@ pgm_per_std:
mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS
mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
la %r4,0x7f oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
l %r3,__LC_PGM_ILC # load program interruption code l %r3,__LC_PGM_ILC # load program interruption code
nr %r4,%r3 # clear per-event-bit and ilc la %r8,0x7f
be BASED(pgm_per_only) # only per or per+check ? nr %r8,%r3 # clear per-event-bit and ilc
l %r1,BASED(.Ljump_table) be BASED(sysc_return) # only per or per+check ?
sll %r4,2 b BASED(pgm_do_call)
l %r1,0(%r4,%r1) # load address of handler routine
la %r2,SP_PTREGS(%r15) # address of register-save area
basr %r14,%r1 # branch to interrupt-handler
pgm_per_only:
la %r2,SP_PTREGS(15) # address of register-save area
l %r1,BASED(.Lhandle_per) # load adr. of per handler
la %r14,BASED(sysc_return) # load adr. of system return
br %r1 # branch to do_debugger_trap
# #
# it was a single stepped SVC that is causing all the trouble # it was a single stepped SVC that is causing all the trouble
...@@ -745,7 +739,7 @@ cleanup_sysc_leave: ...@@ -745,7 +739,7 @@ cleanup_sysc_leave:
.Ldo_extint: .long do_extint .Ldo_extint: .long do_extint
.Ldo_signal: .long do_signal .Ldo_signal: .long do_signal
.Ldo_softirq: .long do_softirq .Ldo_softirq: .long do_softirq
.Lhandle_per: .long do_debugger_trap .Lhandle_per: .long do_single_step
.Ljump_table: .long pgm_check_table .Ljump_table: .long pgm_check_table
.Lschedule: .long schedule .Lschedule: .long schedule
.Lclone: .long sys_clone .Lclone: .long sys_clone
......
...@@ -282,6 +282,7 @@ sysc_reschedule: ...@@ -282,6 +282,7 @@ sysc_reschedule:
# _TIF_SIGPENDING is set, call do_signal # _TIF_SIGPENDING is set, call do_signal
# #
sysc_sigpending: sysc_sigpending:
ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
la %r2,SP_PTREGS(%r15) # load pt_regs la %r2,SP_PTREGS(%r15) # load pt_regs
sgr %r3,%r3 # clear *oldset sgr %r3,%r3 # clear *oldset
brasl %r14,do_signal # call do_signal brasl %r14,do_signal # call do_signal
...@@ -301,7 +302,7 @@ sysc_restart: ...@@ -301,7 +302,7 @@ sysc_restart:
j sysc_do_restart # restart svc j sysc_do_restart # restart svc
# #
# _TIF_SINGLE_STEP is set, call do_debugger_trap # _TIF_SINGLE_STEP is set, call do_single_step
# #
sysc_singlestep: sysc_singlestep:
ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
...@@ -309,7 +310,7 @@ sysc_singlestep: ...@@ -309,7 +310,7 @@ sysc_singlestep:
sth %r0,SP_TRAP(%r15) # set trap indication to pgm check sth %r0,SP_TRAP(%r15) # set trap indication to pgm check
la %r2,SP_PTREGS(%r15) # address of register-save area la %r2,SP_PTREGS(%r15) # address of register-save area
larl %r14,sysc_return # load adr. of system return larl %r14,sysc_return # load adr. of system return
jg do_debugger_trap # branch to do_debugger_trap jg do_single_step # branch to do_sigtrap
__critical_end: __critical_end:
...@@ -497,6 +498,7 @@ pgm_check_handler: ...@@ -497,6 +498,7 @@ pgm_check_handler:
lgf %r3,__LC_PGM_ILC # load program interruption code lgf %r3,__LC_PGM_ILC # load program interruption code
lghi %r8,0x7f lghi %r8,0x7f
ngr %r8,%r3 ngr %r8,%r3
pgm_do_call:
sll %r8,3 sll %r8,3
GET_THREAD_INFO GET_THREAD_INFO
larl %r1,pgm_check_table larl %r1,pgm_check_table
...@@ -527,19 +529,12 @@ pgm_per_std: ...@@ -527,19 +529,12 @@ pgm_per_std:
mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS
mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
lghi %r4,0x7f oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
lgf %r3,__LC_PGM_ILC # load program interruption code lgf %r3,__LC_PGM_ILC # load program interruption code
nr %r4,%r3 # clear per-event-bit and ilc lghi %r8,0x7f
je pgm_per_only # only per of per+check ? ngr %r8,%r3 # clear per-event-bit and ilc
sll %r4,3 je sysc_return
larl %r1,pgm_check_table j pgm_do_call
lg %r1,0(%r4,%r1) # load address of handler routine
la %r2,SP_PTREGS(%r15) # address of register-save area
basr %r14,%r1 # branch to interrupt-handler
pgm_per_only:
la %r2,SP_PTREGS(15) # address of register-save area
larl %r14,sysc_return # load adr. of system return
jg do_debugger_trap
# #
# it was a single stepped SVC that is causing all the trouble # it was a single stepped SVC that is causing all the trouble
......
...@@ -39,6 +39,7 @@ typedef struct ...@@ -39,6 +39,7 @@ typedef struct
__u8 callee_used_stack[__SIGNAL_FRAMESIZE]; __u8 callee_used_stack[__SIGNAL_FRAMESIZE];
struct sigcontext sc; struct sigcontext sc;
_sigregs sregs; _sigregs sregs;
int signo;
__u8 retcode[S390_SYSCALL_SIZE]; __u8 retcode[S390_SYSCALL_SIZE];
} sigframe; } sigframe;
...@@ -350,6 +351,10 @@ static void setup_frame(int sig, struct k_sigaction *ka, ...@@ -350,6 +351,10 @@ static void setup_frame(int sig, struct k_sigaction *ka,
To avoid breaking binary compatibility, they are passed as args. */ To avoid breaking binary compatibility, they are passed as args. */
regs->gprs[4] = current->thread.trap_no; regs->gprs[4] = current->thread.trap_no;
regs->gprs[5] = current->thread.prot_addr; regs->gprs[5] = current->thread.prot_addr;
/* Place signal number on stack to allow backtrace from handler. */
if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
goto give_sigsegv;
return; return;
give_sigsegv: give_sigsegv:
......
...@@ -54,9 +54,7 @@ int sysctl_userprocess_debug = 0; ...@@ -54,9 +54,7 @@ int sysctl_userprocess_debug = 0;
#endif #endif
extern pgm_check_handler_t do_protection_exception; extern pgm_check_handler_t do_protection_exception;
extern pgm_check_handler_t do_segment_exception; extern pgm_check_handler_t do_dat_exception;
extern pgm_check_handler_t do_region_exception;
extern pgm_check_handler_t do_page_exception;
extern pgm_check_handler_t do_pseudo_page_fault; extern pgm_check_handler_t do_pseudo_page_fault;
#ifdef CONFIG_PFAULT #ifdef CONFIG_PFAULT
extern int pfault_init(void); extern int pfault_init(void);
...@@ -300,14 +298,10 @@ static inline void *get_check_address(struct pt_regs *regs) ...@@ -300,14 +298,10 @@ static inline void *get_check_address(struct pt_regs *regs)
return (void *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN); return (void *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
} }
int do_debugger_trap(struct pt_regs *regs) void do_single_step(struct pt_regs *regs)
{ {
if ((regs->psw.mask & PSW_MASK_PSTATE) && if ((current->ptrace & PT_PTRACED) != 0)
(current->ptrace & PT_PTRACED)) { force_sig(SIGTRAP, current);
force_sig(SIGTRAP,current);
return 0;
}
return 1;
} }
#define DO_ERROR(signr, str, name) \ #define DO_ERROR(signr, str, name) \
...@@ -329,12 +323,24 @@ asmlinkage void name(struct pt_regs * regs, long interruption_code) \ ...@@ -329,12 +323,24 @@ asmlinkage void name(struct pt_regs * regs, long interruption_code) \
DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler) DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler)
DO_ERROR_INFO(SIGBUS, "addressing exception", addressing_exception, DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception,
BUS_ADRERR, get_check_address(regs)) ILL_ILLADR, get_check_address(regs))
DO_ERROR_INFO(SIGILL, "execute exception", execute_exception, DO_ERROR_INFO(SIGILL, "execute exception", execute_exception,
ILL_ILLOPN, get_check_address(regs)) ILL_ILLOPN, get_check_address(regs))
DO_ERROR_INFO(SIGFPE, "fixpoint divide exception", divide_exception, DO_ERROR_INFO(SIGFPE, "fixpoint divide exception", divide_exception,
FPE_INTDIV, get_check_address(regs)) FPE_INTDIV, get_check_address(regs))
DO_ERROR_INFO(SIGFPE, "fixpoint overflow exception", overflow_exception,
FPE_INTOVF, get_check_address(regs))
DO_ERROR_INFO(SIGFPE, "HFP overflow exception", hfp_overflow_exception,
FPE_FLTOVF, get_check_address(regs))
DO_ERROR_INFO(SIGFPE, "HFP underflow exception", hfp_underflow_exception,
FPE_FLTUND, get_check_address(regs))
DO_ERROR_INFO(SIGFPE, "HFP significance exception", hfp_significance_exception,
FPE_FLTRES, get_check_address(regs))
DO_ERROR_INFO(SIGFPE, "HFP divide exception", hfp_divide_exception,
FPE_FLTDIV, get_check_address(regs))
DO_ERROR_INFO(SIGFPE, "HFP square root exception", hfp_sqrt_exception,
FPE_FLTINV, get_check_address(regs))
DO_ERROR_INFO(SIGILL, "operand exception", operand_exception, DO_ERROR_INFO(SIGILL, "operand exception", operand_exception,
ILL_ILLOPN, get_check_address(regs)) ILL_ILLOPN, get_check_address(regs))
DO_ERROR_INFO(SIGILL, "privileged operation", privileged_op, DO_ERROR_INFO(SIGILL, "privileged operation", privileged_op,
...@@ -388,19 +394,15 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) ...@@ -388,19 +394,15 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
if (regs->psw.mask & PSW_MASK_PSTATE) if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable(); local_irq_enable();
if (regs->psw.mask & PSW_MASK_PSTATE) if (regs->psw.mask & PSW_MASK_PSTATE) {
get_user(*((__u16 *) opcode), (__u16 __user *)location); get_user(*((__u16 *) opcode), (__u16 __user *) location);
if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) {
if (current->ptrace & PT_PTRACED)
force_sig(SIGTRAP, current);
else else
*((__u16 *)opcode)=*((__u16 *)location);
if (*((__u16 *)opcode)==S390_BREAKPOINT_U16)
{
if(do_debugger_trap(regs))
signal = SIGILL; signal = SIGILL;
}
#ifdef CONFIG_MATHEMU #ifdef CONFIG_MATHEMU
else if (regs->psw.mask & PSW_MASK_PSTATE) } else if (opcode[0] == 0xb3) {
{
if (opcode[0] == 0xb3) {
get_user(*((__u16 *) (opcode+2)), location+1); get_user(*((__u16 *) (opcode+2)), location+1);
signal = math_emu_b3(opcode, regs); signal = math_emu_b3(opcode, regs);
} else if (opcode[0] == 0xed) { } else if (opcode[0] == 0xed) {
...@@ -416,12 +418,12 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) ...@@ -416,12 +418,12 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
} else if (*((__u16 *) opcode) == 0xb29d) { } else if (*((__u16 *) opcode) == 0xb29d) {
get_user(*((__u16 *) (opcode+2)), location+1); get_user(*((__u16 *) (opcode+2)), location+1);
signal = math_emu_lfpc(opcode, regs); signal = math_emu_lfpc(opcode, regs);
#endif
} else } else
signal = SIGILL; signal = SIGILL;
} } else
#endif
else
signal = SIGILL; signal = SIGILL;
if (signal == SIGFPE) if (signal == SIGFPE)
do_fp_trap(regs, location, do_fp_trap(regs, location,
current->thread.fp_regs.fpc, interruption_code); current->thread.fp_regs.fpc, interruption_code);
...@@ -479,6 +481,7 @@ specification_exception(struct pt_regs * regs, long interruption_code) ...@@ -479,6 +481,7 @@ specification_exception(struct pt_regs * regs, long interruption_code)
} }
} else } else
signal = SIGILL; signal = SIGILL;
if (signal == SIGFPE) if (signal == SIGFPE)
do_fp_trap(regs, location, do_fp_trap(regs, location,
current->thread.fp_regs.fpc, interruption_code); current->thread.fp_regs.fpc, interruption_code);
...@@ -605,19 +608,29 @@ void __init trap_init(void) ...@@ -605,19 +608,29 @@ void __init trap_init(void)
pgm_check_table[5] = &addressing_exception; pgm_check_table[5] = &addressing_exception;
pgm_check_table[6] = &specification_exception; pgm_check_table[6] = &specification_exception;
pgm_check_table[7] = &data_exception; pgm_check_table[7] = &data_exception;
pgm_check_table[8] = &overflow_exception;
pgm_check_table[9] = &divide_exception; pgm_check_table[9] = &divide_exception;
pgm_check_table[0x10] = &do_segment_exception; pgm_check_table[0x0A] = &overflow_exception;
pgm_check_table[0x11] = &do_page_exception; pgm_check_table[0x0B] = &divide_exception;
pgm_check_table[0x0C] = &hfp_overflow_exception;
pgm_check_table[0x0D] = &hfp_underflow_exception;
pgm_check_table[0x0E] = &hfp_significance_exception;
pgm_check_table[0x0F] = &hfp_divide_exception;
pgm_check_table[0x10] = &do_dat_exception;
pgm_check_table[0x11] = &do_dat_exception;
pgm_check_table[0x12] = &translation_exception; pgm_check_table[0x12] = &translation_exception;
pgm_check_table[0x13] = &special_op_exception; pgm_check_table[0x13] = &special_op_exception;
#ifndef CONFIG_ARCH_S390X #ifndef CONFIG_ARCH_S390X
pgm_check_table[0x14] = &do_pseudo_page_fault; pgm_check_table[0x14] = &do_pseudo_page_fault;
#else /* CONFIG_ARCH_S390X */ #else /* CONFIG_ARCH_S390X */
pgm_check_table[0x38] = &addressing_exception; pgm_check_table[0x38] = &do_dat_exception;
pgm_check_table[0x3B] = &do_region_exception; pgm_check_table[0x39] = &do_dat_exception;
pgm_check_table[0x3A] = &do_dat_exception;
pgm_check_table[0x3B] = &do_dat_exception;
#endif /* CONFIG_ARCH_S390X */ #endif /* CONFIG_ARCH_S390X */
pgm_check_table[0x15] = &operand_exception; pgm_check_table[0x15] = &operand_exception;
pgm_check_table[0x1C] = &privileged_op; pgm_check_table[0x1C] = &privileged_op;
pgm_check_table[0x1D] = &hfp_sqrt_exception;
pgm_check_table[0x40] = &do_monitor_call; pgm_check_table[0x40] = &do_monitor_call;
if (MACHINE_IS_VM) { if (MACHINE_IS_VM) {
......
...@@ -159,7 +159,8 @@ static void force_sigsegv(struct pt_regs *regs, unsigned long error_code, ...@@ -159,7 +159,8 @@ static void force_sigsegv(struct pt_regs *regs, unsigned long error_code,
* 11 Page translation -> Not present (nullification) * 11 Page translation -> Not present (nullification)
* 3b Region third trans. -> Not present (nullification) * 3b Region third trans. -> Not present (nullification)
*/ */
extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) extern inline void
do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
{ {
struct task_struct *tsk; struct task_struct *tsk;
struct mm_struct *mm; struct mm_struct *mm;
...@@ -177,7 +178,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) ...@@ -177,7 +178,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
* as a special case because the translation exception code * as a special case because the translation exception code
* field is not guaranteed to contain valid data in this case. * field is not guaranteed to contain valid data in this case.
*/ */
if (error_code == 4 && !(S390_lowcore.trans_exc_code & 4)) { if (is_protection && !(S390_lowcore.trans_exc_code & 4)) {
/* Low-address protection hit in kernel mode means /* Low-address protection hit in kernel mode means
NULL pointer write access in kernel mode. */ NULL pointer write access in kernel mode. */
...@@ -232,7 +233,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) ...@@ -232,7 +233,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
*/ */
good_area: good_area:
si_code = SEGV_ACCERR; si_code = SEGV_ACCERR;
if (error_code != 4) { if (!is_protection) {
/* page not present, check vm flags */ /* page not present, check vm flags */
if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
goto bad_area; goto bad_area;
...@@ -247,7 +248,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) ...@@ -247,7 +248,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
* make sure we exit gracefully rather than endlessly redo * make sure we exit gracefully rather than endlessly redo
* the fault. * the fault.
*/ */
switch (handle_mm_fault(mm, vma, address, error_code == 4)) { switch (handle_mm_fault(mm, vma, address, is_protection)) {
case VM_FAULT_MINOR: case VM_FAULT_MINOR:
tsk->min_flt++; tsk->min_flt++;
break; break;
...@@ -263,6 +264,11 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) ...@@ -263,6 +264,11 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
} }
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
/*
* The instruction that caused the program check will
* be repeated. Don't signal single step via SIGTRAP.
*/
clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
return; return;
/* /*
...@@ -337,28 +343,15 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) ...@@ -337,28 +343,15 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
void do_protection_exception(struct pt_regs *regs, unsigned long error_code) void do_protection_exception(struct pt_regs *regs, unsigned long error_code)
{ {
regs->psw.addr -= (error_code >> 16); regs->psw.addr -= (error_code >> 16);
do_exception(regs, 4); do_exception(regs, 4, 1);
} }
void do_segment_exception(struct pt_regs *regs, unsigned long error_code) void do_dat_exception(struct pt_regs *regs, unsigned long error_code)
{ {
do_exception(regs, 0x10); do_exception(regs, error_code & 0xff, 0);
} }
void do_page_exception(struct pt_regs *regs, unsigned long error_code) #ifndef CONFIG_ARCH_S390X
{
do_exception(regs, 0x11);
}
#ifdef CONFIG_ARCH_S390X
void
do_region_exception(struct pt_regs *regs, unsigned long error_code)
{
do_exception(regs, 0x3b);
}
#else /* CONFIG_ARCH_S390X */
typedef struct _pseudo_wait_t { typedef struct _pseudo_wait_t {
struct _pseudo_wait_t *next; struct _pseudo_wait_t *next;
...@@ -456,6 +449,11 @@ do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -456,6 +449,11 @@ do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code)
wait_struct.next = pseudo_lock_queue; wait_struct.next = pseudo_lock_queue;
pseudo_lock_queue = &wait_struct; pseudo_lock_queue = &wait_struct;
spin_unlock(&pseudo_wait_spinlock); spin_unlock(&pseudo_wait_spinlock);
/*
* The instruction that caused the program check will
* be repeated. Don't signal single step via SIGTRAP.
*/
clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
/* go to sleep */ /* go to sleep */
wait_event(wait_struct.queue, wait_struct.resolved); wait_event(wait_struct.queue, wait_struct.resolved);
} }
......
...@@ -85,7 +85,7 @@ static inline struct thread_info *current_thread_info(void) ...@@ -85,7 +85,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_RESTART_SVC 4 /* restart svc with new svc number */ #define TIF_RESTART_SVC 4 /* restart svc with new svc number */
#define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */ #define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */
#define TIF_SINGLE_STEP 6 /* single stepped svc */ #define TIF_SINGLE_STEP 6 /* deliver sigtrap on return to user */
#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */
#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling
TIF_NEED_RESCHED */ TIF_NEED_RESCHED */
......
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