hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/arch/arm64/kernel/sdei.c
....@@ -2,13 +2,16 @@
22 // Copyright (C) 2017 Arm Ltd.
33 #define pr_fmt(fmt) "sdei: " fmt
44
5
+#include <linux/arm-smccc.h>
56 #include <linux/arm_sdei.h>
67 #include <linux/hardirq.h>
78 #include <linux/irqflags.h>
89 #include <linux/sched/task_stack.h>
10
+#include <linux/scs.h>
911 #include <linux/uaccess.h>
1012
1113 #include <asm/alternative.h>
14
+#include <asm/exception.h>
1215 #include <asm/kprobes.h>
1316 #include <asm/mmu.h>
1417 #include <asm/ptrace.h>
....@@ -36,6 +39,17 @@
3639 DEFINE_PER_CPU(unsigned long *, sdei_stack_critical_ptr);
3740 #endif
3841
42
+DEFINE_PER_CPU(struct sdei_registered_event *, sdei_active_normal_event);
43
+DEFINE_PER_CPU(struct sdei_registered_event *, sdei_active_critical_event);
44
+
45
+DECLARE_PER_CPU(unsigned long *, sdei_shadow_call_stack_normal_ptr);
46
+DECLARE_PER_CPU(unsigned long *, sdei_shadow_call_stack_critical_ptr);
47
+
48
+#ifdef CONFIG_SHADOW_CALL_STACK
49
+DEFINE_PER_CPU(unsigned long *, sdei_shadow_call_stack_normal_ptr);
50
+DEFINE_PER_CPU(unsigned long *, sdei_shadow_call_stack_critical_ptr);
51
+#endif
52
+
3953 static void _free_sdei_stack(unsigned long * __percpu *ptr, int cpu)
4054 {
4155 unsigned long *p;
....@@ -50,6 +64,9 @@
5064 static void free_sdei_stacks(void)
5165 {
5266 int cpu;
67
+
68
+ if (!IS_ENABLED(CONFIG_VMAP_STACK))
69
+ return;
5370
5471 for_each_possible_cpu(cpu) {
5572 _free_sdei_stack(&sdei_stack_normal_ptr, cpu);
....@@ -74,6 +91,9 @@
7491 int cpu;
7592 int err = 0;
7693
94
+ if (!IS_ENABLED(CONFIG_VMAP_STACK))
95
+ return 0;
96
+
7797 for_each_possible_cpu(cpu) {
7898 err = _init_sdei_stack(&sdei_stack_normal_ptr, cpu);
7999 if (err)
....@@ -89,24 +109,68 @@
89109 return err;
90110 }
91111
112
+static void _free_sdei_scs(unsigned long * __percpu *ptr, int cpu)
113
+{
114
+ void *s;
115
+
116
+ s = per_cpu(*ptr, cpu);
117
+ if (s) {
118
+ per_cpu(*ptr, cpu) = NULL;
119
+ scs_free(s);
120
+ }
121
+}
122
+
123
+static void free_sdei_scs(void)
124
+{
125
+ int cpu;
126
+
127
+ for_each_possible_cpu(cpu) {
128
+ _free_sdei_scs(&sdei_shadow_call_stack_normal_ptr, cpu);
129
+ _free_sdei_scs(&sdei_shadow_call_stack_critical_ptr, cpu);
130
+ }
131
+}
132
+
133
+static int _init_sdei_scs(unsigned long * __percpu *ptr, int cpu)
134
+{
135
+ void *s;
136
+
137
+ s = scs_alloc(cpu_to_node(cpu));
138
+ if (!s)
139
+ return -ENOMEM;
140
+ per_cpu(*ptr, cpu) = s;
141
+
142
+ return 0;
143
+}
144
+
145
+static int init_sdei_scs(void)
146
+{
147
+ int cpu;
148
+ int err = 0;
149
+
150
+ if (!IS_ENABLED(CONFIG_SHADOW_CALL_STACK))
151
+ return 0;
152
+
153
+ for_each_possible_cpu(cpu) {
154
+ err = _init_sdei_scs(&sdei_shadow_call_stack_normal_ptr, cpu);
155
+ if (err)
156
+ break;
157
+ err = _init_sdei_scs(&sdei_shadow_call_stack_critical_ptr, cpu);
158
+ if (err)
159
+ break;
160
+ }
161
+
162
+ if (err)
163
+ free_sdei_scs();
164
+
165
+ return err;
166
+}
167
+
92168 static bool on_sdei_normal_stack(unsigned long sp, struct stack_info *info)
93169 {
94170 unsigned long low = (unsigned long)raw_cpu_read(sdei_stack_normal_ptr);
95171 unsigned long high = low + SDEI_STACK_SIZE;
96172
97
- if (!low)
98
- return false;
99
-
100
- if (sp < low || sp >= high)
101
- return false;
102
-
103
- if (info) {
104
- info->low = low;
105
- info->high = high;
106
- info->type = STACK_TYPE_SDEI_NORMAL;
107
- }
108
-
109
- return true;
173
+ return on_stack(sp, low, high, STACK_TYPE_SDEI_NORMAL, info);
110174 }
111175
112176 static bool on_sdei_critical_stack(unsigned long sp, struct stack_info *info)
....@@ -114,19 +178,7 @@
114178 unsigned long low = (unsigned long)raw_cpu_read(sdei_stack_critical_ptr);
115179 unsigned long high = low + SDEI_STACK_SIZE;
116180
117
- if (!low)
118
- return false;
119
-
120
- if (sp < low || sp >= high)
121
- return false;
122
-
123
- if (info) {
124
- info->low = low;
125
- info->high = high;
126
- info->type = STACK_TYPE_SDEI_CRITICAL;
127
- }
128
-
129
- return true;
181
+ return on_stack(sp, low, high, STACK_TYPE_SDEI_CRITICAL, info);
130182 }
131183
132184 bool _on_sdei_stack(unsigned long sp, struct stack_info *info)
....@@ -153,15 +205,16 @@
153205 */
154206 if (is_hyp_mode_available() && !is_kernel_in_hyp_mode()) {
155207 pr_err("Not supported on this hardware/boot configuration\n");
156
- return 0;
208
+ goto out_err;
157209 }
158210
159
- if (IS_ENABLED(CONFIG_VMAP_STACK)) {
160
- if (init_sdei_stacks())
161
- return 0;
162
- }
211
+ if (init_sdei_stacks())
212
+ goto out_err;
163213
164
- sdei_exit_mode = (conduit == CONDUIT_HVC) ? SDEI_EXIT_HVC : SDEI_EXIT_SMC;
214
+ if (init_sdei_scs())
215
+ goto out_err_free_stacks;
216
+
217
+ sdei_exit_mode = (conduit == SMCCC_CONDUIT_HVC) ? SDEI_EXIT_HVC : SDEI_EXIT_SMC;
165218
166219 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
167220 if (arm64_kernel_unmapped_at_el0()) {
....@@ -174,6 +227,10 @@
174227 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
175228 return (unsigned long)__sdei_asm_handler;
176229
230
+out_err_free_stacks:
231
+ free_sdei_stacks();
232
+out_err:
233
+ return 0;
177234 }
178235
179236 /*
....@@ -203,7 +260,7 @@
203260
204261 /*
205262 * We didn't take an exception to get here, set PAN. UAO will be cleared
206
- * by sdei_event_handler()s set_fs(USER_DS) call.
263
+ * by sdei_event_handler()s force_uaccess_begin() call.
207264 */
208265 __uaccess_enable_hw_pan();
209266
....@@ -246,26 +303,16 @@
246303 }
247304
248305
249
-asmlinkage __kprobes notrace unsigned long
306
+asmlinkage noinstr unsigned long
250307 __sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
251308 {
252309 unsigned long ret;
253
- bool do_nmi_exit = false;
254310
255
- /*
256
- * nmi_enter() deals with printk() re-entrance and use of RCU when
257
- * RCU believed this CPU was idle. Because critical events can
258
- * interrupt normal events, we may already be in_nmi().
259
- */
260
- if (!in_nmi()) {
261
- nmi_enter();
262
- do_nmi_exit = true;
263
- }
311
+ arm64_enter_nmi(regs);
264312
265313 ret = _sdei_handler(regs, arg);
266314
267
- if (do_nmi_exit)
268
- nmi_exit();
315
+ arm64_exit_nmi(regs);
269316
270317 return ret;
271318 }