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#include <linux/objtool.h>
7
8#include <asm/processor.h>
9
10#ifdef CONFIG_X86_64
11
12/*
13 * Macro to inline switching to an interrupt stack and invoking function
14 * calls from there. The following rules apply:
15 *
16 * - Ordering:
17 *
18 *   1. Write the stack pointer into the top most place of the irq
19 *	stack. This ensures that the various unwinders can link back to the
20 *	original stack.
21 *
22 *   2. Switch the stack pointer to the top of the irq stack.
23 *
24 *   3. Invoke whatever needs to be done (@asm_call argument)
25 *
26 *   4. Pop the original stack pointer from the top of the irq stack
27 *	which brings it back to the original stack where it left off.
28 *
29 * - Function invocation:
30 *
31 *   To allow flexible usage of the macro, the actual function code including
32 *   the store of the arguments in the call ABI registers is handed in via
33 *   the @asm_call argument.
34 *
35 * - Local variables:
36 *
37 *   @tos:
38 *	The @tos variable holds a pointer to the top of the irq stack and
39 *	_must_ be allocated in a non-callee saved register as this is a
40 *	restriction coming from objtool.
41 *
42 *	Note, that (tos) is both in input and output constraints to ensure
43 *	that the compiler does not assume that R11 is left untouched in
44 *	case this macro is used in some place where the per cpu interrupt
45 *	stack pointer is used again afterwards
46 *
47 * - Function arguments:
48 *	The function argument(s), if any, have to be defined in register
49 *	variables at the place where this is invoked. Storing the
50 *	argument(s) in the proper register(s) is part of the @asm_call
51 *
52 * - Constraints:
53 *
54 *   The constraints have to be done very carefully because the compiler
55 *   does not know about the assembly call.
56 *
57 *   output:
58 *     As documented already above the @tos variable is required to be in
59 *     the output constraints to make the compiler aware that R11 cannot be
60 *     reused after the asm() statement.
61 *
62 *     For builds with CONFIG_UNWINDER_FRAME_POINTER, ASM_CALL_CONSTRAINT is
63 *     required as well as this prevents certain creative GCC variants from
64 *     misplacing the ASM code.
65 *
66 *  input:
67 *    - func:
68 *	  Immediate, which tells the compiler that the function is referenced.
69 *
70 *    - tos:
71 *	  Register. The actual register is defined by the variable declaration.
72 *
73 *    - function arguments:
74 *	  The constraints are handed in via the 'argconstr' argument list. They
75 *	  describe the register arguments which are used in @asm_call.
76 *
77 *  clobbers:
78 *     Function calls can clobber anything except the callee-saved
79 *     registers. Tell the compiler.
80 */
81#define call_on_stack(stack, func, asm_call, argconstr...)		\
82{									\
83	register void *tos asm("r11");					\
84									\
85	tos = ((void *)(stack));					\
86									\
87	asm_inline volatile(						\
88	"movq	%%rsp, (%[tos])				\n"		\
89	"movq	%[tos], %%rsp				\n"		\
90									\
91	asm_call							\
92									\
93	"popq	%%rsp					\n"		\
94									\
95	: "+r" (tos), ASM_CALL_CONSTRAINT				\
96	: [__func] "i" (func), [tos] "r" (tos) argconstr		\
97	: "cc", "rax", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10",	\
98	  "memory"							\
99	);								\
100}
101
102#define ASM_CALL_ARG0							\
103	"call %P[__func]				\n"		\
104	ASM_REACHABLE
105
106#define ASM_CALL_ARG1							\
107	"movq	%[arg1], %%rdi				\n"		\
108	ASM_CALL_ARG0
109
110#define ASM_CALL_ARG2							\
111	"movq	%[arg2], %%rsi				\n"		\
112	ASM_CALL_ARG1
113
114#define ASM_CALL_ARG3							\
115	"movq	%[arg3], %%rdx				\n"		\
116	ASM_CALL_ARG2
117
118#define call_on_irqstack(func, asm_call, argconstr...)			\
119	call_on_stack(__this_cpu_read(pcpu_hot.hardirq_stack_ptr),	\
120		      func, asm_call, argconstr)
121
122/* Macros to assert type correctness for run_*_on_irqstack macros */
123#define assert_function_type(func, proto)				\
124	static_assert(__builtin_types_compatible_p(typeof(&func), proto))
125
126#define assert_arg_type(arg, proto)					\
127	static_assert(__builtin_types_compatible_p(typeof(arg), proto))
128
129/*
130 * Macro to invoke system vector and device interrupt C handlers.
131 */
132#define call_on_irqstack_cond(func, regs, asm_call, constr, c_args...)	\
133{									\
134	/*								\
135	 * User mode entry and interrupt on the irq stack do not	\
136	 * switch stacks. If from user mode the task stack is empty.	\
137	 */								\
138	if (user_mode(regs) || __this_cpu_read(pcpu_hot.hardirq_stack_inuse)) { \
139		irq_enter_rcu();					\
140		func(c_args);						\
141		irq_exit_rcu();						\
142	} else {							\
143		/*							\
144		 * Mark the irq stack inuse _before_ and unmark _after_	\
145		 * switching stacks. Interrupts are disabled in both	\
146		 * places. Invoke the stack switch macro with the call	\
147		 * sequence which matches the above direct invocation.	\
148		 */							\
149		__this_cpu_write(pcpu_hot.hardirq_stack_inuse, true);	\
150		call_on_irqstack(func, asm_call, constr);		\
151		__this_cpu_write(pcpu_hot.hardirq_stack_inuse, false);	\
152	}								\
153}
154
155/*
156 * Function call sequence for __call_on_irqstack() for system vectors.
157 *
158 * Note that irq_enter_rcu() and irq_exit_rcu() do not use the input
159 * mechanism because these functions are global and cannot be optimized out
160 * when compiling a particular source file which uses one of these macros.
161 *
162 * The argument (regs) does not need to be pushed or stashed in a callee
163 * saved register to be safe vs. the irq_enter_rcu() call because the
164 * clobbers already prevent the compiler from storing it in a callee
165 * clobbered register. As the compiler has to preserve @regs for the final
166 * call to idtentry_exit() anyway, it's likely that it does not cause extra
167 * effort for this asm magic.
168 */
169#define ASM_CALL_SYSVEC							\
170	"call irq_enter_rcu				\n"		\
171	ASM_CALL_ARG1							\
172	"call irq_exit_rcu				\n"
173
174#define SYSVEC_CONSTRAINTS	, [arg1] "r" (regs)
175
176#define run_sysvec_on_irqstack_cond(func, regs)				\
177{									\
178	assert_function_type(func, void (*)(struct pt_regs *));		\
179	assert_arg_type(regs, struct pt_regs *);			\
180									\
181	call_on_irqstack_cond(func, regs, ASM_CALL_SYSVEC,		\
182			      SYSVEC_CONSTRAINTS, regs);		\
183}
184
185/*
186 * As in ASM_CALL_SYSVEC above the clobbers force the compiler to store
187 * @regs and @vector in callee saved registers.
188 */
189#define ASM_CALL_IRQ							\
190	"call irq_enter_rcu				\n"		\
191	ASM_CALL_ARG2							\
192	"call irq_exit_rcu				\n"
193
194#define IRQ_CONSTRAINTS	, [arg1] "r" (regs), [arg2] "r" ((unsigned long)vector)
195
196#define run_irq_on_irqstack_cond(func, regs, vector)			\
197{									\
198	assert_function_type(func, void (*)(struct pt_regs *, u32));	\
199	assert_arg_type(regs, struct pt_regs *);			\
200	assert_arg_type(vector, u32);					\
201									\
202	call_on_irqstack_cond(func, regs, ASM_CALL_IRQ,			\
203			      IRQ_CONSTRAINTS, regs, vector);		\
204}
205
206#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
207/*
208 * Macro to invoke __do_softirq on the irq stack. This is only called from
209 * task context when bottom halves are about to be reenabled and soft
210 * interrupts are pending to be processed. The interrupt stack cannot be in
211 * use here.
212 */
213#define do_softirq_own_stack()						\
214{									\
215	__this_cpu_write(pcpu_hot.hardirq_stack_inuse, true);		\
216	call_on_irqstack(__do_softirq, ASM_CALL_ARG0);			\
217	__this_cpu_write(pcpu_hot.hardirq_stack_inuse, false);		\
218}
219
220#endif
221
222#else /* CONFIG_X86_64 */
223/* System vector handlers always run on the stack they interrupted. */
224#define run_sysvec_on_irqstack_cond(func, regs)				\
225{									\
226	irq_enter_rcu();						\
227	func(regs);							\
228	irq_exit_rcu();							\
229}
230
231/* Switches to the irq stack within func() */
232#define run_irq_on_irqstack_cond(func, regs, vector)			\
233{									\
234	irq_enter_rcu();						\
235	func(regs, vector);						\
236	irq_exit_rcu();							\
237}
238
239#endif /* !CONFIG_X86_64 */
240
241#endif
242