summaryrefslogtreecommitdiff
path: root/arch/mips/kernel/process.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-04-06 13:16:34 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-04-06 13:16:34 -0700
commit977674c06b189dd54729a91331c05761688ad064 (patch)
treeb632e03a73e8824684ba836a43eaf75b6be27afa /arch/mips/kernel/process.c
parent4691f4a6d4aadb67eab06c6659136bc2b00db851 (diff)
parentdb8466c581cca1a08b505f1319c3ecd246f16fa8 (diff)
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS fixes from Ralf Baechle: "Lantiq: - Fix adding xbar resoures causing a panic Loongson3: - Some Loongson 3A don't identify themselves as having an FTLB so hardwire that knowledge into CPU probing. - Handle Loongson 3 TLB peculiarities in the fast path of the RDHWR emulation. - Fix invalid FTLB entries with huge page on VTLB+FTLB platforms - Add missing calculation of S-cache and V-cache cache-way size Ralink: - Fix typos in rt3883 pinctrl data Generic: - Force o32 fp64 support on 32bit MIPS64r6 kernels - Yet another build fix after the linux/sched.h changes - Wire up statx system call - Fix stack unwinding after introduction of IRQ stack - Fix spinlock code to build even for microMIPS with recent binutils SMP-CPS: - Fix retrieval of VPE mask on big endian CPUs" * 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: MIPS: IRQ Stack: Unwind IRQ stack onto task stack MIPS: c-r4k: Fix Loongson-3's vcache/scache waysize calculation MIPS: Flush wrong invalid FTLB entry for huge page MIPS: Check TLB before handle_ri_rdhwr() for Loongson-3 MIPS: Add MIPS_CPU_FTLB for Loongson-3A R2 MIPS: Lantiq: fix missing xbar kernel panic MIPS: smp-cps: Fix retrieval of VPE mask on big endian CPUs MIPS: Wire up statx system call MIPS: Include asm/ptrace.h now linux/sched.h doesn't MIPS: ralink: Fix typos in rt3883 pinctrl MIPS: End spinlocks with .insn MIPS: Force o32 fp64 support on 32bit MIPS64r6 kernels
Diffstat (limited to 'arch/mips/kernel/process.c')
-rw-r--r--arch/mips/kernel/process.c56
1 files changed, 38 insertions, 18 deletions
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index fb6b6b650719..b68e10fc453d 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -488,31 +488,52 @@ unsigned long notrace unwind_stack_by_address(unsigned long stack_page,
unsigned long pc,
unsigned long *ra)
{
+ unsigned long low, high, irq_stack_high;
struct mips_frame_info info;
unsigned long size, ofs;
+ struct pt_regs *regs;
int leaf;
- extern void ret_from_irq(void);
- extern void ret_from_exception(void);
if (!stack_page)
return 0;
/*
- * If we reached the bottom of interrupt context,
- * return saved pc in pt_regs.
+ * IRQ stacks start at IRQ_STACK_START
+ * task stacks at THREAD_SIZE - 32
*/
- if (pc == (unsigned long)ret_from_irq ||
- pc == (unsigned long)ret_from_exception) {
- struct pt_regs *regs;
- if (*sp >= stack_page &&
- *sp + sizeof(*regs) <= stack_page + THREAD_SIZE - 32) {
- regs = (struct pt_regs *)*sp;
- pc = regs->cp0_epc;
- if (!user_mode(regs) && __kernel_text_address(pc)) {
- *sp = regs->regs[29];
- *ra = regs->regs[31];
- return pc;
- }
+ low = stack_page;
+ if (!preemptible() && on_irq_stack(raw_smp_processor_id(), *sp)) {
+ high = stack_page + IRQ_STACK_START;
+ irq_stack_high = high;
+ } else {
+ high = stack_page + THREAD_SIZE - 32;
+ irq_stack_high = 0;
+ }
+
+ /*
+ * If we reached the top of the interrupt stack, start unwinding
+ * the interrupted task stack.
+ */
+ if (unlikely(*sp == irq_stack_high)) {
+ unsigned long task_sp = *(unsigned long *)*sp;
+
+ /*
+ * Check that the pointer saved in the IRQ stack head points to
+ * something within the stack of the current task
+ */
+ if (!object_is_on_stack((void *)task_sp))
+ return 0;
+
+ /*
+ * Follow pointer to tasks kernel stack frame where interrupted
+ * state was saved.
+ */
+ regs = (struct pt_regs *)task_sp;
+ pc = regs->cp0_epc;
+ if (!user_mode(regs) && __kernel_text_address(pc)) {
+ *sp = regs->regs[29];
+ *ra = regs->regs[31];
+ return pc;
}
return 0;
}
@@ -533,8 +554,7 @@ unsigned long notrace unwind_stack_by_address(unsigned long stack_page,
if (leaf < 0)
return 0;
- if (*sp < stack_page ||
- *sp + info.frame_size > stack_page + THREAD_SIZE - 32)
+ if (*sp < low || *sp + info.frame_size > high)
return 0;
if (leaf)