xref: /linux/arch/x86/include/asm/irq_stack.h (revision 3503d56cc7233ced602e38a4c13caa64f00ab2aa)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_X86_IRQ_STACK_H
3 #define _ASM_X86_IRQ_STACK_H
4 
5 #include <linux/ptrace.h>
6 
7 #include <asm/processor.h>
8 
9 #ifdef CONFIG_X86_64
10 static __always_inline bool irqstack_active(void)
11 {
12 	return __this_cpu_read(irq_count) != -1;
13 }
14 
15 void asm_call_on_stack(void *sp, void *func, void *arg);
16 
17 static __always_inline void __run_on_irqstack(void *func, void *arg)
18 {
19 	void *tos = __this_cpu_read(hardirq_stack_ptr);
20 
21 	__this_cpu_add(irq_count, 1);
22 	asm_call_on_stack(tos - 8, func, arg);
23 	__this_cpu_sub(irq_count, 1);
24 }
25 
26 #else /* CONFIG_X86_64 */
27 static inline bool irqstack_active(void) { return false; }
28 static inline void __run_on_irqstack(void *func, void *arg) { }
29 #endif /* !CONFIG_X86_64 */
30 
31 static __always_inline bool irq_needs_irq_stack(struct pt_regs *regs)
32 {
33 	if (IS_ENABLED(CONFIG_X86_32))
34 		return false;
35 	if (!regs)
36 		return !irqstack_active();
37 	return !user_mode(regs) && !irqstack_active();
38 }
39 
40 static __always_inline void run_on_irqstack_cond(void *func, void *arg,
41 						 struct pt_regs *regs)
42 {
43 	void (*__func)(void *arg) = func;
44 
45 	lockdep_assert_irqs_disabled();
46 
47 	if (irq_needs_irq_stack(regs))
48 		__run_on_irqstack(__func, arg);
49 	else
50 		__func(arg);
51 }
52 
53 #endif
54