162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (C) 1991, 1992  Linus Torvalds
462306a36Sopenharmony_ci *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include <linux/sched/debug.h>
762306a36Sopenharmony_ci#include <linux/kallsyms.h>
862306a36Sopenharmony_ci#include <linux/kprobes.h>
962306a36Sopenharmony_ci#include <linux/uaccess.h>
1062306a36Sopenharmony_ci#include <linux/hardirq.h>
1162306a36Sopenharmony_ci#include <linux/kdebug.h>
1262306a36Sopenharmony_ci#include <linux/export.h>
1362306a36Sopenharmony_ci#include <linux/ptrace.h>
1462306a36Sopenharmony_ci#include <linux/kexec.h>
1562306a36Sopenharmony_ci#include <linux/sysfs.h>
1662306a36Sopenharmony_ci#include <linux/bug.h>
1762306a36Sopenharmony_ci#include <linux/nmi.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <asm/cpu_entry_area.h>
2062306a36Sopenharmony_ci#include <asm/stacktrace.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic const char * const exception_stack_names[] = {
2362306a36Sopenharmony_ci		[ ESTACK_DF	]	= "#DF",
2462306a36Sopenharmony_ci		[ ESTACK_NMI	]	= "NMI",
2562306a36Sopenharmony_ci		[ ESTACK_DB	]	= "#DB",
2662306a36Sopenharmony_ci		[ ESTACK_MCE	]	= "#MC",
2762306a36Sopenharmony_ci		[ ESTACK_VC	]	= "#VC",
2862306a36Sopenharmony_ci		[ ESTACK_VC2	]	= "#VC2",
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciconst char *stack_type_name(enum stack_type type)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	BUILD_BUG_ON(N_EXCEPTION_STACKS != 6);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	if (type == STACK_TYPE_TASK)
3662306a36Sopenharmony_ci		return "TASK";
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (type == STACK_TYPE_IRQ)
3962306a36Sopenharmony_ci		return "IRQ";
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	if (type == STACK_TYPE_SOFTIRQ)
4262306a36Sopenharmony_ci		return "SOFTIRQ";
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (type == STACK_TYPE_ENTRY) {
4562306a36Sopenharmony_ci		/*
4662306a36Sopenharmony_ci		 * On 64-bit, we have a generic entry stack that we
4762306a36Sopenharmony_ci		 * use for all the kernel entry points, including
4862306a36Sopenharmony_ci		 * SYSENTER.
4962306a36Sopenharmony_ci		 */
5062306a36Sopenharmony_ci		return "ENTRY_TRAMPOLINE";
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (type >= STACK_TYPE_EXCEPTION && type <= STACK_TYPE_EXCEPTION_LAST)
5462306a36Sopenharmony_ci		return exception_stack_names[type - STACK_TYPE_EXCEPTION];
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	return NULL;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/**
6062306a36Sopenharmony_ci * struct estack_pages - Page descriptor for exception stacks
6162306a36Sopenharmony_ci * @offs:	Offset from the start of the exception stack area
6262306a36Sopenharmony_ci * @size:	Size of the exception stack
6362306a36Sopenharmony_ci * @type:	Type to store in the stack_info struct
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_cistruct estack_pages {
6662306a36Sopenharmony_ci	u32	offs;
6762306a36Sopenharmony_ci	u16	size;
6862306a36Sopenharmony_ci	u16	type;
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define EPAGERANGE(st)							\
7262306a36Sopenharmony_ci	[PFN_DOWN(CEA_ESTACK_OFFS(st)) ...				\
7362306a36Sopenharmony_ci	 PFN_DOWN(CEA_ESTACK_OFFS(st) + CEA_ESTACK_SIZE(st) - 1)] = {	\
7462306a36Sopenharmony_ci		.offs	= CEA_ESTACK_OFFS(st),				\
7562306a36Sopenharmony_ci		.size	= CEA_ESTACK_SIZE(st),				\
7662306a36Sopenharmony_ci		.type	= STACK_TYPE_EXCEPTION + ESTACK_ ##st, }
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/*
7962306a36Sopenharmony_ci * Array of exception stack page descriptors. If the stack is larger than
8062306a36Sopenharmony_ci * PAGE_SIZE, all pages covering a particular stack will have the same
8162306a36Sopenharmony_ci * info. The guard pages including the not mapped DB2 stack are zeroed
8262306a36Sopenharmony_ci * out.
8362306a36Sopenharmony_ci */
8462306a36Sopenharmony_cistatic const
8562306a36Sopenharmony_cistruct estack_pages estack_pages[CEA_ESTACK_PAGES] ____cacheline_aligned = {
8662306a36Sopenharmony_ci	EPAGERANGE(DF),
8762306a36Sopenharmony_ci	EPAGERANGE(NMI),
8862306a36Sopenharmony_ci	EPAGERANGE(DB),
8962306a36Sopenharmony_ci	EPAGERANGE(MCE),
9062306a36Sopenharmony_ci	EPAGERANGE(VC),
9162306a36Sopenharmony_ci	EPAGERANGE(VC2),
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic __always_inline bool in_exception_stack(unsigned long *stack, struct stack_info *info)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	unsigned long begin, end, stk = (unsigned long)stack;
9762306a36Sopenharmony_ci	const struct estack_pages *ep;
9862306a36Sopenharmony_ci	struct pt_regs *regs;
9962306a36Sopenharmony_ci	unsigned int k;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	BUILD_BUG_ON(N_EXCEPTION_STACKS != 6);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	begin = (unsigned long)__this_cpu_read(cea_exception_stacks);
10462306a36Sopenharmony_ci	/*
10562306a36Sopenharmony_ci	 * Handle the case where stack trace is collected _before_
10662306a36Sopenharmony_ci	 * cea_exception_stacks had been initialized.
10762306a36Sopenharmony_ci	 */
10862306a36Sopenharmony_ci	if (!begin)
10962306a36Sopenharmony_ci		return false;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	end = begin + sizeof(struct cea_exception_stacks);
11262306a36Sopenharmony_ci	/* Bail if @stack is outside the exception stack area. */
11362306a36Sopenharmony_ci	if (stk < begin || stk >= end)
11462306a36Sopenharmony_ci		return false;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* Calc page offset from start of exception stacks */
11762306a36Sopenharmony_ci	k = (stk - begin) >> PAGE_SHIFT;
11862306a36Sopenharmony_ci	/* Lookup the page descriptor */
11962306a36Sopenharmony_ci	ep = &estack_pages[k];
12062306a36Sopenharmony_ci	/* Guard page? */
12162306a36Sopenharmony_ci	if (!ep->size)
12262306a36Sopenharmony_ci		return false;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	begin += (unsigned long)ep->offs;
12562306a36Sopenharmony_ci	end = begin + (unsigned long)ep->size;
12662306a36Sopenharmony_ci	regs = (struct pt_regs *)end - 1;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	info->type	= ep->type;
12962306a36Sopenharmony_ci	info->begin	= (unsigned long *)begin;
13062306a36Sopenharmony_ci	info->end	= (unsigned long *)end;
13162306a36Sopenharmony_ci	info->next_sp	= (unsigned long *)regs->sp;
13262306a36Sopenharmony_ci	return true;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic __always_inline bool in_irq_stack(unsigned long *stack, struct stack_info *info)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	unsigned long *end = (unsigned long *)this_cpu_read(pcpu_hot.hardirq_stack_ptr);
13862306a36Sopenharmony_ci	unsigned long *begin;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/*
14162306a36Sopenharmony_ci	 * @end points directly to the top most stack entry to avoid a -8
14262306a36Sopenharmony_ci	 * adjustment in the stack switch hotpath. Adjust it back before
14362306a36Sopenharmony_ci	 * calculating @begin.
14462306a36Sopenharmony_ci	 */
14562306a36Sopenharmony_ci	end++;
14662306a36Sopenharmony_ci	begin = end - (IRQ_STACK_SIZE / sizeof(long));
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/*
14962306a36Sopenharmony_ci	 * Due to the switching logic RSP can never be == @end because the
15062306a36Sopenharmony_ci	 * final operation is 'popq %rsp' which means after that RSP points
15162306a36Sopenharmony_ci	 * to the original stack and not to @end.
15262306a36Sopenharmony_ci	 */
15362306a36Sopenharmony_ci	if (stack < begin || stack >= end)
15462306a36Sopenharmony_ci		return false;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	info->type	= STACK_TYPE_IRQ;
15762306a36Sopenharmony_ci	info->begin	= begin;
15862306a36Sopenharmony_ci	info->end	= end;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/*
16162306a36Sopenharmony_ci	 * The next stack pointer is stored at the top of the irq stack
16262306a36Sopenharmony_ci	 * before switching to the irq stack. Actual stack entries are all
16362306a36Sopenharmony_ci	 * below that.
16462306a36Sopenharmony_ci	 */
16562306a36Sopenharmony_ci	info->next_sp = (unsigned long *)*(end - 1);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return true;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cibool noinstr get_stack_info_noinstr(unsigned long *stack, struct task_struct *task,
17162306a36Sopenharmony_ci				    struct stack_info *info)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	if (in_task_stack(stack, task, info))
17462306a36Sopenharmony_ci		return true;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (task != current)
17762306a36Sopenharmony_ci		return false;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (in_exception_stack(stack, info))
18062306a36Sopenharmony_ci		return true;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	if (in_irq_stack(stack, info))
18362306a36Sopenharmony_ci		return true;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (in_entry_stack(stack, info))
18662306a36Sopenharmony_ci		return true;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	return false;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ciint get_stack_info(unsigned long *stack, struct task_struct *task,
19262306a36Sopenharmony_ci		   struct stack_info *info, unsigned long *visit_mask)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	task = task ? : current;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (!stack)
19762306a36Sopenharmony_ci		goto unknown;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (!get_stack_info_noinstr(stack, task, info))
20062306a36Sopenharmony_ci		goto unknown;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	/*
20362306a36Sopenharmony_ci	 * Make sure we don't iterate through any given stack more than once.
20462306a36Sopenharmony_ci	 * If it comes up a second time then there's something wrong going on:
20562306a36Sopenharmony_ci	 * just break out and report an unknown stack type.
20662306a36Sopenharmony_ci	 */
20762306a36Sopenharmony_ci	if (visit_mask) {
20862306a36Sopenharmony_ci		if (*visit_mask & (1UL << info->type)) {
20962306a36Sopenharmony_ci			if (task == current)
21062306a36Sopenharmony_ci				printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
21162306a36Sopenharmony_ci			goto unknown;
21262306a36Sopenharmony_ci		}
21362306a36Sopenharmony_ci		*visit_mask |= 1UL << info->type;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	return 0;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ciunknown:
21962306a36Sopenharmony_ci	info->type = STACK_TYPE_UNKNOWN;
22062306a36Sopenharmony_ci	return -EINVAL;
22162306a36Sopenharmony_ci}
222