Commit 1e54622e authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Martin Schwidefsky

[S390] cleanup lowcore access from program checks

Read all required fields for program checks from the lowcore in the
first level interrupt handler in entry[64].S. If the context that
caused the fault was enabled for interrupts we can now re-enable the
irqs in entry[64].S.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 84afdcee
......@@ -84,6 +84,7 @@ int main(void)
DEFINE(__LC_SVC_INT_CODE, offsetof(struct _lowcore, svc_code));
DEFINE(__LC_PGM_ILC, offsetof(struct _lowcore, pgm_ilc));
DEFINE(__LC_PGM_INT_CODE, offsetof(struct _lowcore, pgm_code));
DEFINE(__LC_TRANS_EXC_CODE, offsetof(struct _lowcore, trans_exc_code));
DEFINE(__LC_PER_ATMID, offsetof(struct _lowcore, per_perc_atmid));
DEFINE(__LC_PER_ADDRESS, offsetof(struct _lowcore, per_address));
DEFINE(__LC_PER_ACCESS_ID, offsetof(struct _lowcore, per_access_id));
......
......@@ -72,25 +72,9 @@ STACK_SIZE = 1 << STACK_SHIFT
l %r1,BASED(.Ltrace_irq_off_caller)
basr %r14,%r1
.endm
.macro TRACE_IRQS_CHECK_ON
tm SP_PSW(%r15),0x03 # irqs enabled?
bz BASED(0f)
TRACE_IRQS_ON
0:
.endm
.macro TRACE_IRQS_CHECK_OFF
tm SP_PSW(%r15),0x03 # irqs enabled?
bz BASED(0f)
TRACE_IRQS_OFF
0:
.endm
#else
#define TRACE_IRQS_ON
#define TRACE_IRQS_OFF
#define TRACE_IRQS_CHECK_ON
#define TRACE_IRQS_CHECK_OFF
#endif
#ifdef CONFIG_LOCKDEP
......@@ -198,6 +182,12 @@ STACK_SIZE = 1 << STACK_SHIFT
lpsw \psworg # back to caller
.endm
.macro REENABLE_IRQS
mvc __SF_EMPTY(1,%r15),SP_PSW(%r15)
ni __SF_EMPTY(%r15),0xbf
ssm __SF_EMPTY(%r15)
.endm
/*
* Scheduler resume function, called by switch_to
* gpr2 = (task_struct *) prev
......@@ -440,13 +430,11 @@ kernel_execve:
br %r14
# execve succeeded.
0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts
TRACE_IRQS_OFF
l %r15,__LC_KERNEL_STACK # load ksp
s %r15,BASED(.Lc_spsize) # make room for registers & psw
l %r9,__LC_THREAD_INFO
mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
TRACE_IRQS_ON
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
l %r1,BASED(.Lexecve_tail)
basr %r14,%r1
......@@ -483,9 +471,10 @@ pgm_check_handler:
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
pgm_no_vtime:
TRACE_IRQS_CHECK_OFF
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
l %r3,__LC_PGM_ILC # load program interruption code
l %r4,__LC_TRANS_EXC_CODE
REENABLE_IRQS
la %r8,0x7f
nr %r8,%r3
pgm_do_call:
......@@ -495,7 +484,6 @@ pgm_do_call:
la %r2,SP_PTREGS(%r15) # address of register-save area
basr %r14,%r7 # branch to interrupt-handler
pgm_exit:
TRACE_IRQS_CHECK_ON
b BASED(sysc_return)
#
......@@ -523,7 +511,6 @@ pgm_per_std:
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
pgm_no_vtime2:
TRACE_IRQS_CHECK_OFF
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
l %r1,__TI_task(%r9)
tm SP_PSW+1(%r15),0x01 # kernel per event ?
......@@ -533,6 +520,8 @@ pgm_no_vtime2:
mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
l %r3,__LC_PGM_ILC # load program interruption code
l %r4,__LC_TRANS_EXC_CODE
REENABLE_IRQS
la %r8,0x7f
nr %r8,%r3 # clear per-event-bit and ilc
be BASED(pgm_exit2) # only per or per+check ?
......@@ -542,8 +531,6 @@ pgm_no_vtime2:
la %r2,SP_PTREGS(%r15) # address of register-save area
basr %r14,%r7 # branch to interrupt-handler
pgm_exit2:
TRACE_IRQS_ON
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
b BASED(sysc_return)
#
......@@ -557,13 +544,11 @@ pgm_svcper:
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
lh %r7,0x8a # get svc number from lowcore
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
TRACE_IRQS_OFF
l %r8,__TI_task(%r9)
mvc __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
mvc __THREAD_per+__PER_address(4,%r8),__LC_PER_ADDRESS
mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
TRACE_IRQS_ON
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
lm %r2,%r6,SP_R2(%r15) # load svc arguments
b BASED(sysc_do_svc)
......
......@@ -5,7 +5,7 @@
#include <linux/signal.h>
#include <asm/ptrace.h>
typedef void pgm_check_handler_t(struct pt_regs *, long);
typedef void pgm_check_handler_t(struct pt_regs *, long, unsigned long);
extern pgm_check_handler_t *pgm_check_table[128];
pgm_check_handler_t do_protection_exception;
pgm_check_handler_t do_dat_exception;
......
......@@ -79,25 +79,9 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
basr %r2,%r0
brasl %r14,trace_hardirqs_off_caller
.endm
.macro TRACE_IRQS_CHECK_ON
tm SP_PSW(%r15),0x03 # irqs enabled?
jz 0f
TRACE_IRQS_ON
0:
.endm
.macro TRACE_IRQS_CHECK_OFF
tm SP_PSW(%r15),0x03 # irqs enabled?
jz 0f
TRACE_IRQS_OFF
0:
.endm
#else
#define TRACE_IRQS_ON
#define TRACE_IRQS_OFF
#define TRACE_IRQS_CHECK_ON
#define TRACE_IRQS_CHECK_OFF
#endif
#ifdef CONFIG_LOCKDEP
......@@ -207,6 +191,12 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
0:
.endm
.macro REENABLE_IRQS
mvc __SF_EMPTY(1,%r15),SP_PSW(%r15)
ni __SF_EMPTY(%r15),0xbf
ssm __SF_EMPTY(%r15)
.endm
/*
* Scheduler resume function, called by switch_to
* gpr2 = (task_struct *) prev
......@@ -443,14 +433,12 @@ kernel_execve:
br %r14
# execve succeeded.
0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts
# TRACE_IRQS_OFF
lg %r15,__LC_KERNEL_STACK # load ksp
aghi %r15,-SP_SIZE # make room for registers & psw
lg %r13,__LC_SVC_NEW_PSW+8
mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs
lg %r12,__LC_THREAD_INFO
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
# TRACE_IRQS_ON
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
brasl %r14,execve_tail
j sysc_return
......@@ -490,19 +478,18 @@ pgm_check_handler:
LAST_BREAK
pgm_no_vtime:
HANDLE_SIE_INTERCEPT
TRACE_IRQS_CHECK_OFF
stg %r11,SP_ARGS(%r15)
lgf %r3,__LC_PGM_ILC # load program interruption code
lg %r4,__LC_TRANS_EXC_CODE
REENABLE_IRQS
lghi %r8,0x7f
ngr %r8,%r3
pgm_do_call:
sll %r8,3
larl %r1,pgm_check_table
lg %r1,0(%r8,%r1) # load address of handler routine
la %r2,SP_PTREGS(%r15) # address of register-save area
basr %r14,%r1 # branch to interrupt-handler
pgm_exit:
TRACE_IRQS_CHECK_ON
j sysc_return
#
......@@ -533,7 +520,6 @@ pgm_per_std:
LAST_BREAK
pgm_no_vtime2:
HANDLE_SIE_INTERCEPT
TRACE_IRQS_CHECK_OFF
lg %r1,__TI_task(%r12)
tm SP_PSW+1(%r15),0x01 # kernel per event ?
jz kernel_per
......@@ -542,6 +528,8 @@ pgm_no_vtime2:
mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
oi __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
lgf %r3,__LC_PGM_ILC # load program interruption code
lg %r4,__LC_TRANS_EXC_CODE
REENABLE_IRQS
lghi %r8,0x7f
ngr %r8,%r3 # clear per-event-bit and ilc
je pgm_exit2
......@@ -551,8 +539,6 @@ pgm_no_vtime2:
la %r2,SP_PTREGS(%r15) # address of register-save area
basr %r14,%r1 # branch to interrupt-handler
pgm_exit2:
TRACE_IRQS_ON
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
j sysc_return
#
......@@ -568,13 +554,11 @@ pgm_svcper:
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
LAST_BREAK
TRACE_IRQS_OFF
lg %r8,__TI_task(%r12)
mvc __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
mvc __THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS
mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
oi __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
TRACE_IRQS_ON
stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
lmg %r2,%r6,SP_R2(%r15) # load svc arguments
j sysc_do_svc
......
......@@ -329,27 +329,19 @@ int is_valid_bugaddr(unsigned long addr)
return 1;
}
static void __kprobes inline do_trap(long interruption_code, int signr,
char *str, struct pt_regs *regs,
siginfo_t *info)
static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str,
struct pt_regs *regs, siginfo_t *info)
{
/*
* We got all needed information from the lowcore and can
* now safely switch on interrupts.
*/
if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable();
if (notify_die(DIE_TRAP, str, regs, interruption_code,
interruption_code, signr) == NOTIFY_STOP)
if (notify_die(DIE_TRAP, str, regs, pgm_int_code,
pgm_int_code, signr) == NOTIFY_STOP)
return;
if (regs->psw.mask & PSW_MASK_PSTATE) {
struct task_struct *tsk = current;
tsk->thread.trap_no = interruption_code & 0xffff;
tsk->thread.trap_no = pgm_int_code & 0xffff;
force_sig_info(signr, info, tsk);
report_user_fault(regs, interruption_code, signr);
report_user_fault(regs, pgm_int_code, signr);
} else {
const struct exception_table_entry *fixup;
fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
......@@ -361,14 +353,16 @@ static void __kprobes inline do_trap(long interruption_code, int signr,
btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
if (btt == BUG_TRAP_TYPE_WARN)
return;
die(str, regs, interruption_code);
die(str, regs, pgm_int_code);
}
}
}
static inline void __user *get_check_address(struct pt_regs *regs)
static inline void __user *get_psw_address(struct pt_regs *regs,
long pgm_int_code)
{
return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
return (void __user *)
((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN);
}
void __kprobes do_single_step(struct pt_regs *regs)
......@@ -381,57 +375,57 @@ void __kprobes do_single_step(struct pt_regs *regs)
force_sig(SIGTRAP, current);
}
static void default_trap_handler(struct pt_regs * regs, long interruption_code)
static void default_trap_handler(struct pt_regs *regs, long pgm_int_code,
unsigned long trans_exc_code)
{
if (regs->psw.mask & PSW_MASK_PSTATE) {
local_irq_enable();
report_user_fault(regs, interruption_code, SIGSEGV);
report_user_fault(regs, pgm_int_code, SIGSEGV);
do_exit(SIGSEGV);
} else
die("Unknown program exception", regs, interruption_code);
die("Unknown program exception", regs, pgm_int_code);
}
#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
static void name(struct pt_regs * regs, long interruption_code) \
#define DO_ERROR_INFO(name, signr, sicode, str) \
static void name(struct pt_regs *regs, long pgm_int_code, \
unsigned long trans_exc_code) \
{ \
siginfo_t info; \
info.si_signo = signr; \
info.si_errno = 0; \
info.si_code = sicode; \
info.si_addr = siaddr; \
do_trap(interruption_code, signr, str, regs, &info); \
info.si_addr = get_psw_address(regs, pgm_int_code); \
do_trap(pgm_int_code, signr, str, regs, &info); \
}
DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception,
ILL_ILLADR, get_check_address(regs))
DO_ERROR_INFO(SIGILL, "execute exception", execute_exception,
ILL_ILLOPN, get_check_address(regs))
DO_ERROR_INFO(SIGFPE, "fixpoint divide exception", divide_exception,
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,
ILL_ILLOPN, get_check_address(regs))
DO_ERROR_INFO(SIGILL, "privileged operation", privileged_op,
ILL_PRVOPC, get_check_address(regs))
DO_ERROR_INFO(SIGILL, "special operation exception", special_op_exception,
ILL_ILLOPN, get_check_address(regs))
DO_ERROR_INFO(SIGILL, "translation exception", translation_exception,
ILL_ILLOPN, get_check_address(regs))
static inline void
do_fp_trap(struct pt_regs *regs, void __user *location,
int fpc, long interruption_code)
DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
"addressing exception")
DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN,
"execute exception")
DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV,
"fixpoint divide exception")
DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF,
"fixpoint overflow exception")
DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF,
"HFP overflow exception")
DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND,
"HFP underflow exception")
DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES,
"HFP significance exception")
DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV,
"HFP divide exception")
DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV,
"HFP square root exception")
DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN,
"operand exception")
DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC,
"privileged operation")
DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
"special operation exception")
DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN,
"translation exception")
static inline void do_fp_trap(struct pt_regs *regs, void __user *location,
int fpc, long pgm_int_code)
{
siginfo_t si;
......@@ -454,25 +448,19 @@ do_fp_trap(struct pt_regs *regs, void __user *location,
si.si_code = FPE_FLTRES;
}
current->thread.ieee_instruction_pointer = (addr_t) location;
do_trap(interruption_code, SIGFPE,
do_trap(pgm_int_code, SIGFPE,
"floating point exception", regs, &si);
}
static void illegal_op(struct pt_regs * regs, long interruption_code)
static void illegal_op(struct pt_regs *regs, long pgm_int_code,
unsigned long trans_exc_code)
{
siginfo_t info;
__u8 opcode[6];
__u16 __user *location;
int signal = 0;
location = get_check_address(regs);
/*
* We got all needed information from the lowcore and can
* now safely switch on interrupts.
*/
if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable();
location = get_psw_address(regs, pgm_int_code);
if (regs->psw.mask & PSW_MASK_PSTATE) {
if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
......@@ -512,7 +500,7 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
* If we get an illegal op in kernel mode, send it through the
* kprobes notifier. If kprobes doesn't pick it up, SIGILL
*/
if (notify_die(DIE_BPT, "bpt", regs, interruption_code,
if (notify_die(DIE_BPT, "bpt", regs, pgm_int_code,
3, SIGTRAP) != NOTIFY_STOP)
signal = SIGILL;
}
......@@ -520,13 +508,13 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
#ifdef CONFIG_MATHEMU
if (signal == SIGFPE)
do_fp_trap(regs, location,
current->thread.fp_regs.fpc, interruption_code);
current->thread.fp_regs.fpc, pgm_int_code);
else if (signal == SIGSEGV) {
info.si_signo = signal;
info.si_errno = 0;
info.si_code = SEGV_MAPERR;
info.si_addr = (void __user *) location;
do_trap(interruption_code, signal,
do_trap(pgm_int_code, signal,
"user address fault", regs, &info);
} else
#endif
......@@ -535,28 +523,22 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
info.si_errno = 0;
info.si_code = ILL_ILLOPC;
info.si_addr = (void __user *) location;
do_trap(interruption_code, signal,
do_trap(pgm_int_code, signal,
"illegal operation", regs, &info);
}
}
#ifdef CONFIG_MATHEMU
asmlinkage void
specification_exception(struct pt_regs * regs, long interruption_code)
asmlinkage void specification_exception(struct pt_regs *regs,
long pgm_int_code,
unsigned long trans_exc_code)
{
__u8 opcode[6];
__u16 __user *location = NULL;
int signal = 0;
location = (__u16 __user *) get_check_address(regs);
/*
* We got all needed information from the lowcore and can
* now safely switch on interrupts.
*/
if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable();
location = (__u16 __user *) get_psw_address(regs, pgm_int_code);
if (regs->psw.mask & PSW_MASK_PSTATE) {
get_user(*((__u16 *) opcode), location);
......@@ -592,35 +574,29 @@ specification_exception(struct pt_regs * regs, long interruption_code)
if (signal == SIGFPE)
do_fp_trap(regs, location,
current->thread.fp_regs.fpc, interruption_code);
current->thread.fp_regs.fpc, pgm_int_code);
else if (signal) {
siginfo_t info;
info.si_signo = signal;
info.si_errno = 0;
info.si_code = ILL_ILLOPN;
info.si_addr = location;
do_trap(interruption_code, signal,
do_trap(pgm_int_code, signal,
"specification exception", regs, &info);
}
}
#else
DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
ILL_ILLOPN, get_check_address(regs));
DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
"specification exception");
#endif
static void data_exception(struct pt_regs * regs, long interruption_code)
static void data_exception(struct pt_regs *regs, long pgm_int_code,
unsigned long trans_exc_code)
{
__u16 __user *location;
int signal = 0;
location = get_check_address(regs);
/*
* We got all needed information from the lowcore and can
* now safely switch on interrupts.
*/
if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable();
location = get_psw_address(regs, pgm_int_code);
if (MACHINE_HAS_IEEE)
asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
......@@ -686,19 +662,19 @@ static void data_exception(struct pt_regs * regs, long interruption_code)
signal = SIGILL;
if (signal == SIGFPE)
do_fp_trap(regs, location,
current->thread.fp_regs.fpc, interruption_code);
current->thread.fp_regs.fpc, pgm_int_code);
else if (signal) {
siginfo_t info;
info.si_signo = signal;
info.si_errno = 0;
info.si_code = ILL_ILLOPN;
info.si_addr = location;
do_trap(interruption_code, signal,
"data exception", regs, &info);
do_trap(pgm_int_code, signal, "data exception", regs, &info);
}
}
static void space_switch_exception(struct pt_regs * regs, long int_code)
static void space_switch_exception(struct pt_regs *regs, long pgm_int_code,
unsigned long trans_exc_code)
{
siginfo_t info;
......@@ -709,8 +685,8 @@ static void space_switch_exception(struct pt_regs * regs, long int_code)
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_PRVOPC;
info.si_addr = get_check_address(regs);
do_trap(int_code, SIGILL, "space switch event", regs, &info);
info.si_addr = get_psw_address(regs, pgm_int_code);
do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info);
}
asmlinkage void kernel_stack_overflow(struct pt_regs * regs)
......
......@@ -333,12 +333,6 @@ static inline int do_exception(struct pt_regs *regs, int access,
goto out;
address = trans_exc_code & __FAIL_ADDR_MASK;
/*
* When we get here, the fault happened in the current
* task's user address space, so we can switch on the
* interrupts again and then search the VMAs
*/
local_irq_enable();
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
down_read(&mm->mmap_sem);
......@@ -397,20 +391,20 @@ static inline int do_exception(struct pt_regs *regs, int access,
return fault;
}
void __kprobes do_protection_exception(struct pt_regs *regs, long int_code)
void __kprobes do_protection_exception(struct pt_regs *regs, long pgm_int_code,
unsigned long trans_exc_code)
{
unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
int fault;
/* Protection exception is supressing, decrement psw address. */
regs->psw.addr -= (int_code >> 16);
regs->psw.addr -= (pgm_int_code >> 16);
/*
* Check for low-address protection. This needs to be treated
* as a special case because the translation exception code
* field is not guaranteed to contain valid data in this case.
*/
if (unlikely(!(trans_exc_code & 4))) {
do_low_address(regs, int_code, trans_exc_code);
do_low_address(regs, pgm_int_code, trans_exc_code);
return;
}
fault = do_exception(regs, VM_WRITE, trans_exc_code);
......@@ -418,9 +412,9 @@ void __kprobes do_protection_exception(struct pt_regs *regs, long int_code)
do_fault_error(regs, 4, trans_exc_code, fault);
}
void __kprobes do_dat_exception(struct pt_regs *regs, long int_code)
void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code,
unsigned long trans_exc_code)
{
unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
int access, fault;
access = VM_READ | VM_EXEC | VM_WRITE;
......@@ -431,21 +425,19 @@ void __kprobes do_dat_exception(struct pt_regs *regs, long int_code)
#endif
fault = do_exception(regs, access, trans_exc_code);
if (unlikely(fault))
do_fault_error(regs, int_code & 255, trans_exc_code, fault);
do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault);
}
#ifdef CONFIG_64BIT
void __kprobes do_asce_exception(struct pt_regs *regs, long int_code)
void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code,
unsigned long trans_exc_code)
{
unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
goto no_context;
local_irq_enable();
down_read(&mm->mmap_sem);
vma = find_vma(mm, trans_exc_code & __FAIL_ADDR_MASK);
up_read(&mm->mmap_sem);
......@@ -457,16 +449,16 @@ void __kprobes do_asce_exception(struct pt_regs *regs, long int_code)
/* User mode accesses just cause a SIGSEGV */
if (regs->psw.mask & PSW_MASK_PSTATE) {
do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
do_sigsegv(regs, pgm_int_code, SEGV_MAPERR, trans_exc_code);
return;
}
no_context:
do_no_context(regs, int_code, trans_exc_code);
do_no_context(regs, pgm_int_code, trans_exc_code);
}
#endif
int __handle_fault(unsigned long uaddr, unsigned long int_code, int write_user)
int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
{
struct pt_regs regs;
int access, fault;
......@@ -477,14 +469,14 @@ int __handle_fault(unsigned long uaddr, unsigned long int_code, int write_user)
regs.psw.addr = (unsigned long) __builtin_return_address(0);
regs.psw.addr |= PSW_ADDR_AMODE;
uaddr &= PAGE_MASK;
access = write_user ? VM_WRITE : VM_READ;
access = write ? VM_WRITE : VM_READ;
fault = do_exception(&regs, access, uaddr | 2);
if (unlikely(fault)) {
if (fault & VM_FAULT_OOM) {
pagefault_out_of_memory();
fault = 0;
} else if (fault & VM_FAULT_SIGBUS)
do_sigbus(&regs, int_code, uaddr);
do_sigbus(&regs, pgm_int_code, uaddr);
}
return fault ? -EFAULT : 0;
}
......
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