Commit f2fb4e4f authored by Stuart Menefy's avatar Stuart Menefy Committed by Paul Mundt

sh: Conditionally re-enable IRQs in fault path.

The current kernel behaviour is to reenable interrupts unconditionally
when taking a page fault. This patch changes this to only enable them
if interrupts were previously enabled.

It also fixes a problem seen with this fix in place: the kernel previously
flushed the vsyscall page when handling a signal, which is not only
unncessary, but caused a possible sleep with interrupts disabled.
Signed-off-by: default avatarStuart Menefy <stuart.menefy@st.com>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 068f5914
...@@ -373,6 +373,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, ...@@ -373,6 +373,7 @@ static int setup_frame(int sig, struct k_sigaction *ka,
err |= __put_user(OR_R0_R0, &frame->retcode[6]); err |= __put_user(OR_R0_R0, &frame->retcode[6]);
err |= __put_user((__NR_sigreturn), &frame->retcode[7]); err |= __put_user((__NR_sigreturn), &frame->retcode[7]);
regs->pr = (unsigned long) frame->retcode; regs->pr = (unsigned long) frame->retcode;
flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode));
} }
if (err) if (err)
...@@ -398,8 +399,6 @@ static int setup_frame(int sig, struct k_sigaction *ka, ...@@ -398,8 +399,6 @@ static int setup_frame(int sig, struct k_sigaction *ka,
pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
current->comm, task_pid_nr(current), frame, regs->pc, regs->pr); current->comm, task_pid_nr(current), frame, regs->pc, regs->pr);
flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode));
return 0; return 0;
give_sigsegv: give_sigsegv:
......
...@@ -37,16 +37,12 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, ...@@ -37,16 +37,12 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
int fault; int fault;
siginfo_t info; siginfo_t info;
trace_hardirqs_on();
local_irq_enable();
#ifdef CONFIG_SH_KGDB #ifdef CONFIG_SH_KGDB
if (kgdb_nofault && kgdb_bus_err_hook) if (kgdb_nofault && kgdb_bus_err_hook)
kgdb_bus_err_hook(); kgdb_bus_err_hook();
#endif #endif
tsk = current; tsk = current;
mm = tsk->mm;
si_code = SEGV_MAPERR; si_code = SEGV_MAPERR;
if (unlikely(address >= TASK_SIZE)) { if (unlikely(address >= TASK_SIZE)) {
...@@ -88,6 +84,14 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, ...@@ -88,6 +84,14 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
return; return;
} }
/* Only enable interrupts if they were on before the fault */
if ((regs->sr & SR_IMASK) != SR_IMASK) {
trace_hardirqs_on();
local_irq_enable();
}
mm = tsk->mm;
/* /*
* If we're in an interrupt or have no user * If we're in an interrupt or have no user
* context, we must not take the fault.. * context, we must not take the fault..
......
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