Skip to content

Commit bc29b71

Browse files
mrutland-armctmarinas
authored andcommitted
arm64: entry: clarify entry/exit helpers
When entering an exception, we must perform irq/context state management before we can use instrumentable C code. Similarly, when exiting an exception we cannot use instrumentable C code after we perform irq/context state management. Originally, we'd intended that the enter_from_*() and exit_to_*() helpers would enforce this by virtue of being the first and last functions called, respectively, in an exception handler. However, as they now call instrumentable code themselves, this is not as clearly true. To make this more robust, this patch splits the irq/context state management into separate helpers, with all the helpers commented to make their intended purpose more obvious. In exit_to_kernel_mode() we'll now check TFSR_EL1 before we assert that IRQs are disabled, but this ordering is not important, and other than this there should be no functional change as a result of this patch. Signed-off-by: Mark Rutland <[email protected]> Cc: James Morse <[email protected]> Cc: Joey Gouly <[email protected]> Cc: Marc Zyngier <[email protected]> Cc: Will Deacon <[email protected]> Reviewed-by: Joey Gouly <[email protected]> Link: https://lore.kernel.org/r/[email protected] [[email protected]: comment typos fix-up] Signed-off-by: Catalin Marinas <[email protected]>
1 parent 46a2b02 commit bc29b71

File tree

1 file changed

+63
-7
lines changed

1 file changed

+63
-7
lines changed

arch/arm64/kernel/entry-common.c

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@
2626
#include <asm/system_misc.h>
2727

2828
/*
29+
* Handle IRQ/context state management when entering from kernel mode.
30+
* Before this function is called it is not safe to call regular kernel code,
31+
* intrumentable code, or any code which may trigger an exception.
32+
*
2933
* This is intended to match the logic in irqentry_enter(), handling the kernel
3034
* mode transitions only.
3135
*/
32-
static void noinstr enter_from_kernel_mode(struct pt_regs *regs)
36+
static __always_inline void __enter_from_kernel_mode(struct pt_regs *regs)
3337
{
3438
regs->exit_rcu = false;
3539

@@ -45,20 +49,26 @@ static void noinstr enter_from_kernel_mode(struct pt_regs *regs)
4549
lockdep_hardirqs_off(CALLER_ADDR0);
4650
rcu_irq_enter_check_tick();
4751
trace_hardirqs_off_finish();
52+
}
4853

54+
static void noinstr enter_from_kernel_mode(struct pt_regs *regs)
55+
{
56+
__enter_from_kernel_mode(regs);
4957
mte_check_tfsr_entry();
5058
}
5159

5260
/*
61+
* Handle IRQ/context state management when exiting to kernel mode.
62+
* After this function returns it is not safe to call regular kernel code,
63+
* intrumentable code, or any code which may trigger an exception.
64+
*
5365
* This is intended to match the logic in irqentry_exit(), handling the kernel
5466
* mode transitions only, and with preemption handled elsewhere.
5567
*/
56-
static void noinstr exit_to_kernel_mode(struct pt_regs *regs)
68+
static __always_inline void __exit_to_kernel_mode(struct pt_regs *regs)
5769
{
5870
lockdep_assert_irqs_disabled();
5971

60-
mte_check_tfsr_exit();
61-
6272
if (interrupts_enabled(regs)) {
6373
if (regs->exit_rcu) {
6474
trace_hardirqs_on_prepare();
@@ -75,24 +85,55 @@ static void noinstr exit_to_kernel_mode(struct pt_regs *regs)
7585
}
7686
}
7787

78-
asmlinkage void noinstr enter_from_user_mode(void)
88+
static void noinstr exit_to_kernel_mode(struct pt_regs *regs)
89+
{
90+
mte_check_tfsr_exit();
91+
__exit_to_kernel_mode(regs);
92+
}
93+
94+
/*
95+
* Handle IRQ/context state management when entering from user mode.
96+
* Before this function is called it is not safe to call regular kernel code,
97+
* intrumentable code, or any code which may trigger an exception.
98+
*/
99+
static __always_inline void __enter_from_user_mode(void)
79100
{
80101
lockdep_hardirqs_off(CALLER_ADDR0);
81102
CT_WARN_ON(ct_state() != CONTEXT_USER);
82103
user_exit_irqoff();
83104
trace_hardirqs_off_finish();
84105
}
85106

86-
asmlinkage void noinstr exit_to_user_mode(void)
107+
asmlinkage void noinstr enter_from_user_mode(void)
108+
{
109+
__enter_from_user_mode();
110+
}
111+
112+
/*
113+
* Handle IRQ/context state management when exiting to user mode.
114+
* After this function returns it is not safe to call regular kernel code,
115+
* intrumentable code, or any code which may trigger an exception.
116+
*/
117+
static __always_inline void __exit_to_user_mode(void)
87118
{
88-
mte_check_tfsr_exit();
89119

90120
trace_hardirqs_on_prepare();
91121
lockdep_hardirqs_on_prepare(CALLER_ADDR0);
92122
user_enter_irqoff();
93123
lockdep_hardirqs_on(CALLER_ADDR0);
94124
}
95125

126+
asmlinkage void noinstr exit_to_user_mode(void)
127+
{
128+
mte_check_tfsr_exit();
129+
__exit_to_user_mode();
130+
}
131+
132+
/*
133+
* Handle IRQ/context state management when entering an NMI from user/kernel
134+
* mode. Before this function is called it is not safe to call regular kernel
135+
* code, intrumentable code, or any code which may trigger an exception.
136+
*/
96137
static void noinstr arm64_enter_nmi(struct pt_regs *regs)
97138
{
98139
regs->lockdep_hardirqs = lockdep_hardirqs_enabled();
@@ -106,6 +147,11 @@ static void noinstr arm64_enter_nmi(struct pt_regs *regs)
106147
ftrace_nmi_enter();
107148
}
108149

150+
/*
151+
* Handle IRQ/context state management when exiting an NMI from user/kernel
152+
* mode. After this function returns it is not safe to call regular kernel
153+
* code, intrumentable code, or any code which may trigger an exception.
154+
*/
109155
static void noinstr arm64_exit_nmi(struct pt_regs *regs)
110156
{
111157
bool restore = regs->lockdep_hardirqs;
@@ -123,6 +169,11 @@ static void noinstr arm64_exit_nmi(struct pt_regs *regs)
123169
__nmi_exit();
124170
}
125171

172+
/*
173+
* Handle IRQ/context state management when entering a debug exception from
174+
* kernel mode. Before this function is called it is not safe to call regular
175+
* kernel code, intrumentable code, or any code which may trigger an exception.
176+
*/
126177
static void noinstr arm64_enter_el1_dbg(struct pt_regs *regs)
127178
{
128179
regs->lockdep_hardirqs = lockdep_hardirqs_enabled();
@@ -133,6 +184,11 @@ static void noinstr arm64_enter_el1_dbg(struct pt_regs *regs)
133184
trace_hardirqs_off_finish();
134185
}
135186

187+
/*
188+
* Handle IRQ/context state management when exiting a debug exception from
189+
* kernel mode. After this function returns it is not safe to call regular
190+
* kernel code, intrumentable code, or any code which may trigger an exception.
191+
*/
136192
static void noinstr arm64_exit_el1_dbg(struct pt_regs *regs)
137193
{
138194
bool restore = regs->lockdep_hardirqs;

0 commit comments

Comments
 (0)