xref: /openbmc/linux/arch/riscv/kernel/traps.c (revision d32fd6bb9f2bc8178cdd65ebec1ad670a8bfa241)
150acfb2bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
276d2a049SPalmer Dabbelt /*
376d2a049SPalmer Dabbelt  * Copyright (C) 2012 Regents of the University of California
476d2a049SPalmer Dabbelt  */
576d2a049SPalmer Dabbelt 
65ed881bcSPaul Walmsley #include <linux/cpu.h>
776d2a049SPalmer Dabbelt #include <linux/kernel.h>
876d2a049SPalmer Dabbelt #include <linux/init.h>
976d2a049SPalmer Dabbelt #include <linux/sched.h>
1076d2a049SPalmer Dabbelt #include <linux/sched/debug.h>
1176d2a049SPalmer Dabbelt #include <linux/sched/signal.h>
1276d2a049SPalmer Dabbelt #include <linux/signal.h>
1376d2a049SPalmer Dabbelt #include <linux/kdebug.h>
1476d2a049SPalmer Dabbelt #include <linux/uaccess.h>
15c22b0bcbSGuo Ren #include <linux/kprobes.h>
169f564b92SBjörn Töpel #include <linux/uprobes.h>
179f564b92SBjörn Töpel #include <asm/uprobes.h>
1876d2a049SPalmer Dabbelt #include <linux/mm.h>
1976d2a049SPalmer Dabbelt #include <linux/module.h>
2076d2a049SPalmer Dabbelt #include <linux/irq.h>
213f190111SXianting Tian #include <linux/kexec.h>
22f0bddf50SGuo Ren #include <linux/entry-common.h>
2376d2a049SPalmer Dabbelt 
24030f1dfaSNanyong Sun #include <asm/asm-prototypes.h>
25091b9450SKefeng Wang #include <asm/bug.h>
26af0ead42SSami Tolvanen #include <asm/cfi.h>
27d951b20bSConor Dooley #include <asm/csr.h>
2876d2a049SPalmer Dabbelt #include <asm/processor.h>
2976d2a049SPalmer Dabbelt #include <asm/ptrace.h>
30f0bddf50SGuo Ren #include <asm/syscall.h>
31d951b20bSConor Dooley #include <asm/thread_info.h>
32cd054837SAndy Chiu #include <asm/vector.h>
33163e76ccSGuo Ren #include <asm/irq_stack.h>
3476d2a049SPalmer Dabbelt 
3576d2a049SPalmer Dabbelt int show_unhandled_signals = 1;
3676d2a049SPalmer Dabbelt 
37*f48f060aSNam Cao static DEFINE_RAW_SPINLOCK(die_lock);
3876d2a049SPalmer Dabbelt 
dump_kernel_instr(const char * loglvl,struct pt_regs * regs)39eb165bfaSBjörn Töpel static void dump_kernel_instr(const char *loglvl, struct pt_regs *regs)
40eb165bfaSBjörn Töpel {
41eb165bfaSBjörn Töpel 	char str[sizeof("0000 ") * 12 + 2 + 1], *p = str;
42eb165bfaSBjörn Töpel 	const u16 *insns = (u16 *)instruction_pointer(regs);
43eb165bfaSBjörn Töpel 	long bad;
44eb165bfaSBjörn Töpel 	u16 val;
45eb165bfaSBjörn Töpel 	int i;
46eb165bfaSBjörn Töpel 
47eb165bfaSBjörn Töpel 	for (i = -10; i < 2; i++) {
48eb165bfaSBjörn Töpel 		bad = get_kernel_nofault(val, &insns[i]);
49eb165bfaSBjörn Töpel 		if (!bad) {
50eb165bfaSBjörn Töpel 			p += sprintf(p, i == 0 ? "(%04hx) " : "%04hx ", val);
51eb165bfaSBjörn Töpel 		} else {
52eb165bfaSBjörn Töpel 			printk("%sCode: Unable to access instruction at 0x%px.\n",
53eb165bfaSBjörn Töpel 			       loglvl, &insns[i]);
54eb165bfaSBjörn Töpel 			return;
55eb165bfaSBjörn Töpel 		}
56eb165bfaSBjörn Töpel 	}
57eb165bfaSBjörn Töpel 	printk("%sCode: %s\n", loglvl, str);
58eb165bfaSBjörn Töpel }
59eb165bfaSBjörn Töpel 
die(struct pt_regs * regs,const char * str)6076d2a049SPalmer Dabbelt void die(struct pt_regs *regs, const char *str)
6176d2a049SPalmer Dabbelt {
6276d2a049SPalmer Dabbelt 	static int die_counter;
6376d2a049SPalmer Dabbelt 	int ret;
64f2913d00SPalmer Dabbelt 	long cause;
65130aee3fSMattias Nissler 	unsigned long flags;
6676d2a049SPalmer Dabbelt 
6776d2a049SPalmer Dabbelt 	oops_enter();
6876d2a049SPalmer Dabbelt 
69*f48f060aSNam Cao 	raw_spin_lock_irqsave(&die_lock, flags);
7076d2a049SPalmer Dabbelt 	console_verbose();
7176d2a049SPalmer Dabbelt 	bust_spinlocks(1);
7276d2a049SPalmer Dabbelt 
7376d2a049SPalmer Dabbelt 	pr_emerg("%s [#%d]\n", str, ++die_counter);
7476d2a049SPalmer Dabbelt 	print_modules();
75eb165bfaSBjörn Töpel 	if (regs) {
7676d2a049SPalmer Dabbelt 		show_regs(regs);
77eb165bfaSBjörn Töpel 		dump_kernel_instr(KERN_EMERG, regs);
78eb165bfaSBjörn Töpel 	}
7976d2a049SPalmer Dabbelt 
80f2913d00SPalmer Dabbelt 	cause = regs ? regs->cause : -1;
81f2913d00SPalmer Dabbelt 	ret = notify_die(DIE_OOPS, str, regs, 0, cause, SIGSEGV);
8276d2a049SPalmer Dabbelt 
83f2913d00SPalmer Dabbelt 	if (kexec_should_crash(current))
843f190111SXianting Tian 		crash_kexec(regs);
853f190111SXianting Tian 
8676d2a049SPalmer Dabbelt 	bust_spinlocks(0);
8776d2a049SPalmer Dabbelt 	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
88*f48f060aSNam Cao 	raw_spin_unlock_irqrestore(&die_lock, flags);
8976d2a049SPalmer Dabbelt 	oops_exit();
9076d2a049SPalmer Dabbelt 
9176d2a049SPalmer Dabbelt 	if (in_interrupt())
9276d2a049SPalmer Dabbelt 		panic("Fatal exception in interrupt");
9376d2a049SPalmer Dabbelt 	if (panic_on_oops)
9476d2a049SPalmer Dabbelt 		panic("Fatal exception");
9576d2a049SPalmer Dabbelt 	if (ret != NOTIFY_STOP)
960e25498fSEric W. Biederman 		make_task_dead(SIGSEGV);
9776d2a049SPalmer Dabbelt }
9876d2a049SPalmer Dabbelt 
do_trap(struct pt_regs * regs,int signo,int code,unsigned long addr)996f25a967SEric W. Biederman void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr)
10076d2a049SPalmer Dabbelt {
1016f25a967SEric W. Biederman 	struct task_struct *tsk = current;
1026f25a967SEric W. Biederman 
10376d2a049SPalmer Dabbelt 	if (show_unhandled_signals && unhandled_signal(tsk, signo)
10476d2a049SPalmer Dabbelt 	    && printk_ratelimit()) {
10576d2a049SPalmer Dabbelt 		pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x" REG_FMT,
10676d2a049SPalmer Dabbelt 			tsk->comm, task_pid_nr(tsk), signo, code, addr);
1076ab77af4SChristoph Hellwig 		print_vma_addr(KERN_CONT " in ", instruction_pointer(regs));
10876d2a049SPalmer Dabbelt 		pr_cont("\n");
109091b9450SKefeng Wang 		__show_regs(regs);
11076d2a049SPalmer Dabbelt 	}
11176d2a049SPalmer Dabbelt 
1122e1661d2SEric W. Biederman 	force_sig_fault(signo, code, (void __user *)addr);
11376d2a049SPalmer Dabbelt }
11476d2a049SPalmer Dabbelt 
do_trap_error(struct pt_regs * regs,int signo,int code,unsigned long addr,const char * str)11576d2a049SPalmer Dabbelt static void do_trap_error(struct pt_regs *regs, int signo, int code,
11676d2a049SPalmer Dabbelt 	unsigned long addr, const char *str)
11776d2a049SPalmer Dabbelt {
11874784081SGuo Ren 	current->thread.bad_cause = regs->cause;
11974784081SGuo Ren 
12076d2a049SPalmer Dabbelt 	if (user_mode(regs)) {
1216f25a967SEric W. Biederman 		do_trap(regs, signo, code, addr);
12276d2a049SPalmer Dabbelt 	} else {
12376d2a049SPalmer Dabbelt 		if (!fixup_exception(regs))
12476d2a049SPalmer Dabbelt 			die(regs, str);
12576d2a049SPalmer Dabbelt 	}
12676d2a049SPalmer Dabbelt }
12776d2a049SPalmer Dabbelt 
128e64f737aSHeiko Stuebner #if defined(CONFIG_XIP_KERNEL) && defined(CONFIG_RISCV_ALTERNATIVE)
129d0db02c6SGuo Ren #define __trap_section __noinstr_section(".xip.traps")
1305e63215cSVitaly Wool #else
131d0db02c6SGuo Ren #define __trap_section noinstr
1325e63215cSVitaly Wool #endif
13376d2a049SPalmer Dabbelt #define DO_ERROR_INFO(name, signo, code, str)					\
1345e63215cSVitaly Wool asmlinkage __visible __trap_section void name(struct pt_regs *regs)		\
13576d2a049SPalmer Dabbelt {										\
136f0bddf50SGuo Ren 	if (user_mode(regs)) {							\
137f0bddf50SGuo Ren 		irqentry_enter_from_user_mode(regs);				\
138a4c3733dSChristoph Hellwig 		do_trap_error(regs, signo, code, regs->epc, "Oops - " str);	\
139f0bddf50SGuo Ren 		irqentry_exit_to_user_mode(regs);				\
140f0bddf50SGuo Ren 	} else {								\
141f0bddf50SGuo Ren 		irqentry_state_t state = irqentry_nmi_enter(regs);		\
142f0bddf50SGuo Ren 		do_trap_error(regs, signo, code, regs->epc, "Oops - " str);	\
143f0bddf50SGuo Ren 		irqentry_nmi_exit(regs, state);					\
144f0bddf50SGuo Ren 	}									\
14576d2a049SPalmer Dabbelt }
14676d2a049SPalmer Dabbelt 
14776d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_unknown,
14876d2a049SPalmer Dabbelt 	SIGILL, ILL_ILLTRP, "unknown exception");
14976d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_insn_misaligned,
15076d2a049SPalmer Dabbelt 	SIGBUS, BUS_ADRALN, "instruction address misaligned");
15176d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_insn_fault,
15276d2a049SPalmer Dabbelt 	SIGSEGV, SEGV_ACCERR, "instruction access fault");
153cd054837SAndy Chiu 
do_trap_insn_illegal(struct pt_regs * regs)154cd054837SAndy Chiu asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *regs)
155cd054837SAndy Chiu {
15626c38cd8SAndy Chiu 	bool handled;
15726c38cd8SAndy Chiu 
158cd054837SAndy Chiu 	if (user_mode(regs)) {
159cd054837SAndy Chiu 		irqentry_enter_from_user_mode(regs);
160cd054837SAndy Chiu 
161cd054837SAndy Chiu 		local_irq_enable();
162cd054837SAndy Chiu 
16326c38cd8SAndy Chiu 		handled = riscv_v_first_use_handler(regs);
16426c38cd8SAndy Chiu 
16526c38cd8SAndy Chiu 		local_irq_disable();
16626c38cd8SAndy Chiu 
16726c38cd8SAndy Chiu 		if (!handled)
168cd054837SAndy Chiu 			do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->epc,
169cd054837SAndy Chiu 				      "Oops - illegal instruction");
170cd054837SAndy Chiu 
171cd054837SAndy Chiu 		irqentry_exit_to_user_mode(regs);
172cd054837SAndy Chiu 	} else {
173cd054837SAndy Chiu 		irqentry_state_t state = irqentry_nmi_enter(regs);
174cd054837SAndy Chiu 
175cd054837SAndy Chiu 		do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->epc,
176cd054837SAndy Chiu 			      "Oops - illegal instruction");
177cd054837SAndy Chiu 
178cd054837SAndy Chiu 		irqentry_nmi_exit(regs, state);
179cd054837SAndy Chiu 	}
180cd054837SAndy Chiu }
181cd054837SAndy Chiu 
18276d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_load_fault,
18376d2a049SPalmer Dabbelt 	SIGSEGV, SEGV_ACCERR, "load access fault");
184956d705dSDamien Le Moal #ifndef CONFIG_RISCV_M_MODE
185956d705dSDamien Le Moal DO_ERROR_INFO(do_trap_load_misaligned,
186956d705dSDamien Le Moal 	SIGBUS, BUS_ADRALN, "Oops - load address misaligned");
18776d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_store_misaligned,
188956d705dSDamien Le Moal 	SIGBUS, BUS_ADRALN, "Oops - store (or AMO) address misaligned");
189956d705dSDamien Le Moal #else
190956d705dSDamien Le Moal int handle_misaligned_load(struct pt_regs *regs);
191956d705dSDamien Le Moal int handle_misaligned_store(struct pt_regs *regs);
192956d705dSDamien Le Moal 
do_trap_load_misaligned(struct pt_regs * regs)193f0bddf50SGuo Ren asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs)
194956d705dSDamien Le Moal {
195f0bddf50SGuo Ren 	if (user_mode(regs)) {
196f0bddf50SGuo Ren 		irqentry_enter_from_user_mode(regs);
197f0bddf50SGuo Ren 
198f0bddf50SGuo Ren 		if (handle_misaligned_load(regs))
199956d705dSDamien Le Moal 			do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
200956d705dSDamien Le Moal 			      "Oops - load address misaligned");
201f0bddf50SGuo Ren 
202f0bddf50SGuo Ren 		irqentry_exit_to_user_mode(regs);
203f0bddf50SGuo Ren 	} else {
204f0bddf50SGuo Ren 		irqentry_state_t state = irqentry_nmi_enter(regs);
205f0bddf50SGuo Ren 
206f0bddf50SGuo Ren 		if (handle_misaligned_load(regs))
207f0bddf50SGuo Ren 			do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
208f0bddf50SGuo Ren 			      "Oops - load address misaligned");
209f0bddf50SGuo Ren 
210f0bddf50SGuo Ren 		irqentry_nmi_exit(regs, state);
211f0bddf50SGuo Ren 	}
212956d705dSDamien Le Moal }
213956d705dSDamien Le Moal 
do_trap_store_misaligned(struct pt_regs * regs)214f0bddf50SGuo Ren asmlinkage __visible __trap_section void do_trap_store_misaligned(struct pt_regs *regs)
215956d705dSDamien Le Moal {
216f0bddf50SGuo Ren 	if (user_mode(regs)) {
217f0bddf50SGuo Ren 		irqentry_enter_from_user_mode(regs);
218f0bddf50SGuo Ren 
219f0bddf50SGuo Ren 		if (handle_misaligned_store(regs))
220956d705dSDamien Le Moal 			do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
221956d705dSDamien Le Moal 				"Oops - store (or AMO) address misaligned");
222f0bddf50SGuo Ren 
223f0bddf50SGuo Ren 		irqentry_exit_to_user_mode(regs);
224f0bddf50SGuo Ren 	} else {
225f0bddf50SGuo Ren 		irqentry_state_t state = irqentry_nmi_enter(regs);
226f0bddf50SGuo Ren 
227f0bddf50SGuo Ren 		if (handle_misaligned_store(regs))
228f0bddf50SGuo Ren 			do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
229f0bddf50SGuo Ren 				"Oops - store (or AMO) address misaligned");
230f0bddf50SGuo Ren 
231f0bddf50SGuo Ren 		irqentry_nmi_exit(regs, state);
232f0bddf50SGuo Ren 	}
233956d705dSDamien Le Moal }
234956d705dSDamien Le Moal #endif
23576d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_store_fault,
23676d2a049SPalmer Dabbelt 	SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault");
23776d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_ecall_s,
23876d2a049SPalmer Dabbelt 	SIGILL, ILL_ILLTRP, "environment call from S-mode");
23976d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_ecall_m,
24076d2a049SPalmer Dabbelt 	SIGILL, ILL_ILLTRP, "environment call from M-mode");
24176d2a049SPalmer Dabbelt 
get_break_insn_length(unsigned long pc)242ee72e0e7SVincent Chen static inline unsigned long get_break_insn_length(unsigned long pc)
243ee72e0e7SVincent Chen {
244ee72e0e7SVincent Chen 	bug_insn_t insn;
245ee72e0e7SVincent Chen 
24625f12ae4SChristoph Hellwig 	if (get_kernel_nofault(insn, (bug_insn_t *)pc))
247ee72e0e7SVincent Chen 		return 0;
248b42d763aSZong Li 
249b42d763aSZong Li 	return GET_INSN_LENGTH(insn);
250ee72e0e7SVincent Chen }
251ee72e0e7SVincent Chen 
probe_single_step_handler(struct pt_regs * regs)2529f564b92SBjörn Töpel static bool probe_single_step_handler(struct pt_regs *regs)
2539f564b92SBjörn Töpel {
2549f564b92SBjörn Töpel 	bool user = user_mode(regs);
2559f564b92SBjörn Töpel 
2569f564b92SBjörn Töpel 	return user ? uprobe_single_step_handler(regs) : kprobe_single_step_handler(regs);
2579f564b92SBjörn Töpel }
2589f564b92SBjörn Töpel 
probe_breakpoint_handler(struct pt_regs * regs)2599f564b92SBjörn Töpel static bool probe_breakpoint_handler(struct pt_regs *regs)
2609f564b92SBjörn Töpel {
2619f564b92SBjörn Töpel 	bool user = user_mode(regs);
2629f564b92SBjörn Töpel 
2639f564b92SBjörn Töpel 	return user ? uprobe_breakpoint_handler(regs) : kprobe_breakpoint_handler(regs);
2649f564b92SBjörn Töpel }
2659f564b92SBjörn Töpel 
handle_break(struct pt_regs * regs)266f0bddf50SGuo Ren void handle_break(struct pt_regs *regs)
26776d2a049SPalmer Dabbelt {
2689f564b92SBjörn Töpel 	if (probe_single_step_handler(regs))
269c22b0bcbSGuo Ren 		return;
270c22b0bcbSGuo Ren 
2719f564b92SBjörn Töpel 	if (probe_breakpoint_handler(regs))
27274784081SGuo Ren 		return;
27374784081SGuo Ren 
27474784081SGuo Ren 	current->thread.bad_cause = regs->cause;
275c22b0bcbSGuo Ren 
276e8f44c50SChristoph Hellwig 	if (user_mode(regs))
277a4c3733dSChristoph Hellwig 		force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->epc);
278fe89bd2bSVincent Chen #ifdef CONFIG_KGDB
279fe89bd2bSVincent Chen 	else if (notify_die(DIE_TRAP, "EBREAK", regs, 0, regs->cause, SIGTRAP)
280fe89bd2bSVincent Chen 								== NOTIFY_STOP)
281fe89bd2bSVincent Chen 		return;
282fe89bd2bSVincent Chen #endif
283af0ead42SSami Tolvanen 	else if (report_bug(regs->epc, regs) == BUG_TRAP_TYPE_WARN ||
284af0ead42SSami Tolvanen 		 handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN)
285a4c3733dSChristoph Hellwig 		regs->epc += get_break_insn_length(regs->epc);
286e8f44c50SChristoph Hellwig 	else
28776d2a049SPalmer Dabbelt 		die(regs, "Kernel BUG");
28876d2a049SPalmer Dabbelt }
289f0bddf50SGuo Ren 
do_trap_break(struct pt_regs * regs)290f0bddf50SGuo Ren asmlinkage __visible __trap_section void do_trap_break(struct pt_regs *regs)
291f0bddf50SGuo Ren {
292f0bddf50SGuo Ren 	if (user_mode(regs)) {
293f0bddf50SGuo Ren 		irqentry_enter_from_user_mode(regs);
294f0bddf50SGuo Ren 
295f0bddf50SGuo Ren 		handle_break(regs);
296f0bddf50SGuo Ren 
297f0bddf50SGuo Ren 		irqentry_exit_to_user_mode(regs);
298f0bddf50SGuo Ren 	} else {
299f0bddf50SGuo Ren 		irqentry_state_t state = irqentry_nmi_enter(regs);
300f0bddf50SGuo Ren 
301f0bddf50SGuo Ren 		handle_break(regs);
302f0bddf50SGuo Ren 
303f0bddf50SGuo Ren 		irqentry_nmi_exit(regs, state);
304f0bddf50SGuo Ren 	}
305f0bddf50SGuo Ren }
306f0bddf50SGuo Ren 
do_trap_ecall_u(struct pt_regs * regs)307f0bddf50SGuo Ren asmlinkage __visible __trap_section void do_trap_ecall_u(struct pt_regs *regs)
308f0bddf50SGuo Ren {
309f0bddf50SGuo Ren 	if (user_mode(regs)) {
31052449c17SCeleste Liu 		long syscall = regs->a7;
311f0bddf50SGuo Ren 
312f0bddf50SGuo Ren 		regs->epc += 4;
313f0bddf50SGuo Ren 		regs->orig_a0 = regs->a0;
31484557cd6SCeleste Liu 		regs->a0 = -ENOSYS;
315f0bddf50SGuo Ren 
3169657e9b7SBjörn Töpel 		riscv_v_vstate_discard(regs);
3179657e9b7SBjörn Töpel 
3189c2598d4SBjörn Töpel 		syscall = syscall_enter_from_user_mode(regs, syscall);
3199c2598d4SBjörn Töpel 
32052449c17SCeleste Liu 		if (syscall >= 0 && syscall < NR_syscalls)
321f0bddf50SGuo Ren 			syscall_handler(regs, syscall);
322f0bddf50SGuo Ren 
323f0bddf50SGuo Ren 		syscall_exit_to_user_mode(regs);
324f0bddf50SGuo Ren 	} else {
325f0bddf50SGuo Ren 		irqentry_state_t state = irqentry_nmi_enter(regs);
326f0bddf50SGuo Ren 
327f0bddf50SGuo Ren 		do_trap_error(regs, SIGILL, ILL_ILLTRP, regs->epc,
328f0bddf50SGuo Ren 			"Oops - environment call from U-mode");
329f0bddf50SGuo Ren 
330f0bddf50SGuo Ren 		irqentry_nmi_exit(regs, state);
331f0bddf50SGuo Ren 	}
332f0bddf50SGuo Ren 
333f0bddf50SGuo Ren }
334f0bddf50SGuo Ren 
335f0bddf50SGuo Ren #ifdef CONFIG_MMU
do_page_fault(struct pt_regs * regs)336f0bddf50SGuo Ren asmlinkage __visible noinstr void do_page_fault(struct pt_regs *regs)
337f0bddf50SGuo Ren {
338f0bddf50SGuo Ren 	irqentry_state_t state = irqentry_enter(regs);
339f0bddf50SGuo Ren 
340f0bddf50SGuo Ren 	handle_page_fault(regs);
341f0bddf50SGuo Ren 
342f0bddf50SGuo Ren 	local_irq_disable();
343f0bddf50SGuo Ren 
344f0bddf50SGuo Ren 	irqentry_exit(regs, state);
345f0bddf50SGuo Ren }
346f0bddf50SGuo Ren #endif
347f0bddf50SGuo Ren 
handle_riscv_irq(struct pt_regs * regs)348163e76ccSGuo Ren static void noinstr handle_riscv_irq(struct pt_regs *regs)
349f0bddf50SGuo Ren {
350f0bddf50SGuo Ren 	struct pt_regs *old_regs;
351f0bddf50SGuo Ren 
352f0bddf50SGuo Ren 	irq_enter_rcu();
353f0bddf50SGuo Ren 	old_regs = set_irq_regs(regs);
354f0bddf50SGuo Ren 	handle_arch_irq(regs);
355f0bddf50SGuo Ren 	set_irq_regs(old_regs);
356f0bddf50SGuo Ren 	irq_exit_rcu();
357163e76ccSGuo Ren }
358163e76ccSGuo Ren 
do_irq(struct pt_regs * regs)359163e76ccSGuo Ren asmlinkage void noinstr do_irq(struct pt_regs *regs)
360163e76ccSGuo Ren {
361163e76ccSGuo Ren 	irqentry_state_t state = irqentry_enter(regs);
362163e76ccSGuo Ren #ifdef CONFIG_IRQ_STACKS
363163e76ccSGuo Ren 	if (on_thread_stack()) {
364163e76ccSGuo Ren 		ulong *sp = per_cpu(irq_stack_ptr, smp_processor_id())
365163e76ccSGuo Ren 					+ IRQ_STACK_SIZE/sizeof(ulong);
366163e76ccSGuo Ren 		__asm__ __volatile(
367163e76ccSGuo Ren 		"addi	sp, sp, -"RISCV_SZPTR  "\n"
368163e76ccSGuo Ren 		REG_S"  ra, (sp)		\n"
369163e76ccSGuo Ren 		"addi	sp, sp, -"RISCV_SZPTR  "\n"
370163e76ccSGuo Ren 		REG_S"  s0, (sp)		\n"
371163e76ccSGuo Ren 		"addi	s0, sp, 2*"RISCV_SZPTR "\n"
372163e76ccSGuo Ren 		"move	sp, %[sp]		\n"
373163e76ccSGuo Ren 		"move	a0, %[regs]		\n"
374163e76ccSGuo Ren 		"call	handle_riscv_irq	\n"
375163e76ccSGuo Ren 		"addi	sp, s0, -2*"RISCV_SZPTR"\n"
376163e76ccSGuo Ren 		REG_L"  s0, (sp)		\n"
377163e76ccSGuo Ren 		"addi	sp, sp, "RISCV_SZPTR   "\n"
378163e76ccSGuo Ren 		REG_L"  ra, (sp)		\n"
379163e76ccSGuo Ren 		"addi	sp, sp, "RISCV_SZPTR   "\n"
380163e76ccSGuo Ren 		:
381163e76ccSGuo Ren 		: [sp] "r" (sp), [regs] "r" (regs)
382163e76ccSGuo Ren 		: "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
383163e76ccSGuo Ren 		  "t0", "t1", "t2", "t3", "t4", "t5", "t6",
3848d0be641SGuo Ren #ifndef CONFIG_FRAME_POINTER
3858d0be641SGuo Ren 		  "s0",
3868d0be641SGuo Ren #endif
387163e76ccSGuo Ren 		  "memory");
388163e76ccSGuo Ren 	} else
389163e76ccSGuo Ren #endif
390163e76ccSGuo Ren 		handle_riscv_irq(regs);
391f0bddf50SGuo Ren 
392f0bddf50SGuo Ren 	irqentry_exit(regs, state);
393f0bddf50SGuo Ren }
39476d2a049SPalmer Dabbelt 
39576d2a049SPalmer Dabbelt #ifdef CONFIG_GENERIC_BUG
is_valid_bugaddr(unsigned long pc)39676d2a049SPalmer Dabbelt int is_valid_bugaddr(unsigned long pc)
39776d2a049SPalmer Dabbelt {
39876d2a049SPalmer Dabbelt 	bug_insn_t insn;
39976d2a049SPalmer Dabbelt 
4009a6e7af0SVincent Chen 	if (pc < VMALLOC_START)
40176d2a049SPalmer Dabbelt 		return 0;
40225f12ae4SChristoph Hellwig 	if (get_kernel_nofault(insn, (bug_insn_t *)pc))
40376d2a049SPalmer Dabbelt 		return 0;
404ee72e0e7SVincent Chen 	if ((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32)
405ee72e0e7SVincent Chen 		return (insn == __BUG_INSN_32);
406ee72e0e7SVincent Chen 	else
407ee72e0e7SVincent Chen 		return ((insn & __COMPRESSED_INSN_MASK) == __BUG_INSN_16);
40876d2a049SPalmer Dabbelt }
40976d2a049SPalmer Dabbelt #endif /* CONFIG_GENERIC_BUG */
41076d2a049SPalmer Dabbelt 
41131da94c2STong Tiangen #ifdef CONFIG_VMAP_STACK
412eff53aeaSDeepak Gupta DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)],
41331da94c2STong Tiangen 		overflow_stack)__aligned(16);
41431da94c2STong Tiangen 
handle_bad_stack(struct pt_regs * regs)41531da94c2STong Tiangen asmlinkage void handle_bad_stack(struct pt_regs *regs)
41631da94c2STong Tiangen {
41731da94c2STong Tiangen 	unsigned long tsk_stk = (unsigned long)current->stack;
41831da94c2STong Tiangen 	unsigned long ovf_stk = (unsigned long)this_cpu_ptr(overflow_stack);
41931da94c2STong Tiangen 
42031da94c2STong Tiangen 	console_verbose();
42131da94c2STong Tiangen 
42231da94c2STong Tiangen 	pr_emerg("Insufficient stack space to handle exception!\n");
42331da94c2STong Tiangen 	pr_emerg("Task stack:     [0x%016lx..0x%016lx]\n",
42431da94c2STong Tiangen 			tsk_stk, tsk_stk + THREAD_SIZE);
42531da94c2STong Tiangen 	pr_emerg("Overflow stack: [0x%016lx..0x%016lx]\n",
42631da94c2STong Tiangen 			ovf_stk, ovf_stk + OVERFLOW_STACK_SIZE);
42731da94c2STong Tiangen 
42831da94c2STong Tiangen 	__show_regs(regs);
42931da94c2STong Tiangen 	panic("Kernel stack overflow");
43031da94c2STong Tiangen 
43131da94c2STong Tiangen 	for (;;)
43231da94c2STong Tiangen 		wait_for_interrupt();
43331da94c2STong Tiangen }
43431da94c2STong Tiangen #endif
435