hc
2024-02-20 e636c8d336489bf3eed5878299e6cc045bbad077
kernel/drivers/firmware/arm_sdei.c
....@@ -2,6 +2,7 @@
22 // Copyright (C) 2017 Arm Ltd.
33 #define pr_fmt(fmt) "sdei: " fmt
44
5
+#include <acpi/ghes.h>
56 #include <linux/acpi.h>
67 #include <linux/arm_sdei.h>
78 #include <linux/arm-smccc.h>
....@@ -77,11 +78,26 @@
7778 int first_error;
7879 };
7980
80
-#define CROSSCALL_INIT(arg, event) (arg.event = event, \
81
- arg.first_error = 0, \
82
- atomic_set(&arg.errors, 0))
81
+#define CROSSCALL_INIT(arg, event) \
82
+ do { \
83
+ arg.event = event; \
84
+ arg.first_error = 0; \
85
+ atomic_set(&arg.errors, 0); \
86
+ } while (0)
8387
84
-static inline int sdei_do_cross_call(void *fn, struct sdei_event * event)
88
+static inline int sdei_do_local_call(smp_call_func_t fn,
89
+ struct sdei_event *event)
90
+{
91
+ struct sdei_crosscall_args arg;
92
+
93
+ CROSSCALL_INIT(arg, event);
94
+ fn(&arg);
95
+
96
+ return arg.first_error;
97
+}
98
+
99
+static inline int sdei_do_cross_call(smp_call_func_t fn,
100
+ struct sdei_event *event)
85101 {
86102 struct sdei_crosscall_args arg;
87103
....@@ -113,26 +129,7 @@
113129 return -ENOMEM;
114130 }
115131
116
- /* Not an error value ... */
117
- return sdei_err;
118
-}
119
-
120
-/*
121
- * If x0 is any of these values, then the call failed, use sdei_to_linux_errno()
122
- * to translate.
123
- */
124
-static int sdei_is_err(struct arm_smccc_res *res)
125
-{
126
- switch (res->a0) {
127
- case SDEI_NOT_SUPPORTED:
128
- case SDEI_INVALID_PARAMETERS:
129
- case SDEI_DENIED:
130
- case SDEI_PENDING:
131
- case SDEI_OUT_OF_RESOURCE:
132
- return true;
133
- }
134
-
135
- return false;
132
+ return 0;
136133 }
137134
138135 static int invoke_sdei_fn(unsigned long function_id, unsigned long arg0,
....@@ -140,14 +137,13 @@
140137 unsigned long arg3, unsigned long arg4,
141138 u64 *result)
142139 {
143
- int err = 0;
140
+ int err;
144141 struct arm_smccc_res res;
145142
146143 if (sdei_firmware_call) {
147144 sdei_firmware_call(function_id, arg0, arg1, arg2, arg3, arg4,
148145 &res);
149
- if (sdei_is_err(&res))
150
- err = sdei_to_linux_errno(res.a0);
146
+ err = sdei_to_linux_errno(res.a0);
151147 } else {
152148 /*
153149 * !sdei_firmware_call means we failed to probe or called
....@@ -164,6 +160,7 @@
164160
165161 return err;
166162 }
163
+NOKPROBE_SYMBOL(invoke_sdei_fn);
167164
168165 static struct sdei_event *sdei_event_find(u32 event_num)
169166 {
....@@ -208,36 +205,34 @@
208205 lockdep_assert_held(&sdei_events_lock);
209206
210207 event = kzalloc(sizeof(*event), GFP_KERNEL);
211
- if (!event)
212
- return ERR_PTR(-ENOMEM);
208
+ if (!event) {
209
+ err = -ENOMEM;
210
+ goto fail;
211
+ }
213212
214213 INIT_LIST_HEAD(&event->list);
215214 event->event_num = event_num;
216215
217216 err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY,
218217 &result);
219
- if (err) {
220
- kfree(event);
221
- return ERR_PTR(err);
222
- }
218
+ if (err)
219
+ goto fail;
223220 event->priority = result;
224221
225222 err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_TYPE,
226223 &result);
227
- if (err) {
228
- kfree(event);
229
- return ERR_PTR(err);
230
- }
224
+ if (err)
225
+ goto fail;
231226 event->type = result;
232227
233228 if (event->type == SDEI_EVENT_TYPE_SHARED) {
234229 reg = kzalloc(sizeof(*reg), GFP_KERNEL);
235230 if (!reg) {
236
- kfree(event);
237
- return ERR_PTR(-ENOMEM);
231
+ err = -ENOMEM;
232
+ goto fail;
238233 }
239234
240
- reg->event_num = event_num;
235
+ reg->event_num = event->event_num;
241236 reg->priority = event->priority;
242237
243238 reg->callback = cb;
....@@ -249,8 +244,8 @@
249244
250245 regs = alloc_percpu(struct sdei_registered_event);
251246 if (!regs) {
252
- kfree(event);
253
- return ERR_PTR(-ENOMEM);
247
+ err = -ENOMEM;
248
+ goto fail;
254249 }
255250
256251 for_each_possible_cpu(cpu) {
....@@ -265,26 +260,23 @@
265260 event->private_registered = regs;
266261 }
267262
268
- if (sdei_event_find(event_num)) {
269
- kfree(event->registered);
270
- kfree(event);
271
- event = ERR_PTR(-EBUSY);
272
- } else {
273
- spin_lock(&sdei_list_lock);
274
- list_add(&event->list, &sdei_list);
275
- spin_unlock(&sdei_list_lock);
276
- }
263
+ spin_lock(&sdei_list_lock);
264
+ list_add(&event->list, &sdei_list);
265
+ spin_unlock(&sdei_list_lock);
277266
278267 return event;
268
+
269
+fail:
270
+ kfree(event);
271
+ return ERR_PTR(err);
279272 }
280273
281
-static void sdei_event_destroy(struct sdei_event *event)
274
+static void sdei_event_destroy_llocked(struct sdei_event *event)
282275 {
283276 lockdep_assert_held(&sdei_events_lock);
277
+ lockdep_assert_held(&sdei_list_lock);
284278
285
- spin_lock(&sdei_list_lock);
286279 list_del(&event->list);
287
- spin_unlock(&sdei_list_lock);
288280
289281 if (event->type == SDEI_EVENT_TYPE_SHARED)
290282 kfree(event->registered);
....@@ -292,6 +284,13 @@
292284 free_percpu(event->private_registered);
293285
294286 kfree(event);
287
+}
288
+
289
+static void sdei_event_destroy(struct sdei_event *event)
290
+{
291
+ spin_lock(&sdei_list_lock);
292
+ sdei_event_destroy_llocked(event);
293
+ spin_unlock(&sdei_list_lock);
295294 }
296295
297296 static int sdei_api_get_version(u64 *version)
....@@ -427,7 +426,6 @@
427426
428427 return err;
429428 }
430
-EXPORT_SYMBOL(sdei_event_enable);
431429
432430 static int sdei_api_event_disable(u32 event_num)
433431 {
....@@ -469,7 +467,6 @@
469467
470468 return err;
471469 }
472
-EXPORT_SYMBOL(sdei_event_disable);
473470
474471 static int sdei_api_event_unregister(u32 event_num)
475472 {
....@@ -490,16 +487,6 @@
490487 sdei_cross_call_return(arg, err);
491488 }
492489
493
-static int _sdei_event_unregister(struct sdei_event *event)
494
-{
495
- lockdep_assert_held(&sdei_events_lock);
496
-
497
- if (event->type == SDEI_EVENT_TYPE_SHARED)
498
- return sdei_api_event_unregister(event->event_num);
499
-
500
- return sdei_do_cross_call(_local_event_unregister, event);
501
-}
502
-
503490 int sdei_event_unregister(u32 event_num)
504491 {
505492 int err;
....@@ -509,29 +496,31 @@
509496
510497 mutex_lock(&sdei_events_lock);
511498 event = sdei_event_find(event_num);
512
- do {
513
- if (!event) {
514
- pr_warn("Event %u not registered\n", event_num);
515
- err = -ENOENT;
516
- break;
517
- }
499
+ if (!event) {
500
+ pr_warn("Event %u not registered\n", event_num);
501
+ err = -ENOENT;
502
+ goto unlock;
503
+ }
518504
519
- spin_lock(&sdei_list_lock);
520
- event->reregister = false;
521
- event->reenable = false;
522
- spin_unlock(&sdei_list_lock);
505
+ spin_lock(&sdei_list_lock);
506
+ event->reregister = false;
507
+ event->reenable = false;
508
+ spin_unlock(&sdei_list_lock);
523509
524
- err = _sdei_event_unregister(event);
525
- if (err)
526
- break;
510
+ if (event->type == SDEI_EVENT_TYPE_SHARED)
511
+ err = sdei_api_event_unregister(event->event_num);
512
+ else
513
+ err = sdei_do_cross_call(_local_event_unregister, event);
527514
528
- sdei_event_destroy(event);
529
- } while (0);
515
+ if (err)
516
+ goto unlock;
517
+
518
+ sdei_event_destroy(event);
519
+unlock:
530520 mutex_unlock(&sdei_events_lock);
531521
532522 return err;
533523 }
534
-EXPORT_SYMBOL(sdei_event_unregister);
535524
536525 /*
537526 * unregister events, but don't destroy them as they are re-registered by
....@@ -548,7 +537,7 @@
548537 if (event->type != SDEI_EVENT_TYPE_SHARED)
549538 continue;
550539
551
- err = _sdei_event_unregister(event);
540
+ err = sdei_api_event_unregister(event->event_num);
552541 if (err)
553542 break;
554543 }
....@@ -582,25 +571,6 @@
582571 sdei_cross_call_return(arg, err);
583572 }
584573
585
-static int _sdei_event_register(struct sdei_event *event)
586
-{
587
- int err;
588
-
589
- lockdep_assert_held(&sdei_events_lock);
590
-
591
- if (event->type == SDEI_EVENT_TYPE_SHARED)
592
- return sdei_api_event_register(event->event_num,
593
- sdei_entry_point,
594
- event->registered,
595
- SDEI_EVENT_REGISTER_RM_ANY, 0);
596
-
597
- err = sdei_do_cross_call(_local_event_register, event);
598
- if (err)
599
- sdei_do_cross_call(_local_event_unregister, event);
600
-
601
- return err;
602
-}
603
-
604574 int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
605575 {
606576 int err;
....@@ -609,63 +579,44 @@
609579 WARN_ON(in_nmi());
610580
611581 mutex_lock(&sdei_events_lock);
612
- do {
613
- if (sdei_event_find(event_num)) {
614
- pr_warn("Event %u already registered\n", event_num);
615
- err = -EBUSY;
616
- break;
617
- }
582
+ if (sdei_event_find(event_num)) {
583
+ pr_warn("Event %u already registered\n", event_num);
584
+ err = -EBUSY;
585
+ goto unlock;
586
+ }
618587
619
- event = sdei_event_create(event_num, cb, arg);
620
- if (IS_ERR(event)) {
621
- err = PTR_ERR(event);
622
- pr_warn("Failed to create event %u: %d\n", event_num,
623
- err);
624
- break;
625
- }
588
+ event = sdei_event_create(event_num, cb, arg);
589
+ if (IS_ERR(event)) {
590
+ err = PTR_ERR(event);
591
+ pr_warn("Failed to create event %u: %d\n", event_num, err);
592
+ goto unlock;
593
+ }
626594
627
- cpus_read_lock();
628
- err = _sdei_event_register(event);
629
- if (err) {
630
- sdei_event_destroy(event);
631
- pr_warn("Failed to register event %u: %d\n", event_num,
632
- err);
633
- } else {
634
- spin_lock(&sdei_list_lock);
635
- event->reregister = true;
636
- spin_unlock(&sdei_list_lock);
637
- }
638
- cpus_read_unlock();
639
- } while (0);
640
- mutex_unlock(&sdei_events_lock);
595
+ cpus_read_lock();
596
+ if (event->type == SDEI_EVENT_TYPE_SHARED) {
597
+ err = sdei_api_event_register(event->event_num,
598
+ sdei_entry_point,
599
+ event->registered,
600
+ SDEI_EVENT_REGISTER_RM_ANY, 0);
601
+ } else {
602
+ err = sdei_do_cross_call(_local_event_register, event);
603
+ if (err)
604
+ sdei_do_cross_call(_local_event_unregister, event);
605
+ }
641606
642
- return err;
643
-}
644
-EXPORT_SYMBOL(sdei_event_register);
645
-
646
-static int sdei_reregister_event(struct sdei_event *event)
647
-{
648
- int err;
649
-
650
- lockdep_assert_held(&sdei_events_lock);
651
-
652
- err = _sdei_event_register(event);
653607 if (err) {
654
- pr_err("Failed to re-register event %u\n", event->event_num);
655608 sdei_event_destroy(event);
656
- return err;
609
+ pr_warn("Failed to register event %u: %d\n", event_num, err);
610
+ goto cpu_unlock;
657611 }
658612
659
- if (event->reenable) {
660
- if (event->type == SDEI_EVENT_TYPE_SHARED)
661
- err = sdei_api_event_enable(event->event_num);
662
- else
663
- err = sdei_do_cross_call(_local_event_enable, event);
664
- }
665
-
666
- if (err)
667
- pr_err("Failed to re-enable event %u\n", event->event_num);
668
-
613
+ spin_lock(&sdei_list_lock);
614
+ event->reregister = true;
615
+ spin_unlock(&sdei_list_lock);
616
+cpu_unlock:
617
+ cpus_read_unlock();
618
+unlock:
619
+ mutex_unlock(&sdei_events_lock);
669620 return err;
670621 }
671622
....@@ -681,9 +632,24 @@
681632 continue;
682633
683634 if (event->reregister) {
684
- err = sdei_reregister_event(event);
685
- if (err)
635
+ err = sdei_api_event_register(event->event_num,
636
+ sdei_entry_point, event->registered,
637
+ SDEI_EVENT_REGISTER_RM_ANY, 0);
638
+ if (err) {
639
+ pr_err("Failed to re-register event %u\n",
640
+ event->event_num);
641
+ sdei_event_destroy_llocked(event);
686642 break;
643
+ }
644
+ }
645
+
646
+ if (event->reenable) {
647
+ err = sdei_api_event_enable(event->event_num);
648
+ if (err) {
649
+ pr_err("Failed to re-enable event %u\n",
650
+ event->event_num);
651
+ break;
652
+ }
687653 }
688654 }
689655 spin_unlock(&sdei_list_lock);
....@@ -695,7 +661,7 @@
695661 static int sdei_cpuhp_down(unsigned int cpu)
696662 {
697663 struct sdei_event *event;
698
- struct sdei_crosscall_args arg;
664
+ int err;
699665
700666 /* un-register private events */
701667 spin_lock(&sdei_list_lock);
....@@ -703,12 +669,11 @@
703669 if (event->type == SDEI_EVENT_TYPE_SHARED)
704670 continue;
705671
706
- CROSSCALL_INIT(arg, event);
707
- /* call the cross-call function locally... */
708
- _local_event_unregister(&arg);
709
- if (arg.first_error)
672
+ err = sdei_do_local_call(_local_event_unregister, event);
673
+ if (err) {
710674 pr_err("Failed to unregister event %u: %d\n",
711
- event->event_num, arg.first_error);
675
+ event->event_num, err);
676
+ }
712677 }
713678 spin_unlock(&sdei_list_lock);
714679
....@@ -718,7 +683,7 @@
718683 static int sdei_cpuhp_up(unsigned int cpu)
719684 {
720685 struct sdei_event *event;
721
- struct sdei_crosscall_args arg;
686
+ int err;
722687
723688 /* re-register/enable private events */
724689 spin_lock(&sdei_list_lock);
....@@ -727,20 +692,19 @@
727692 continue;
728693
729694 if (event->reregister) {
730
- CROSSCALL_INIT(arg, event);
731
- /* call the cross-call function locally... */
732
- _local_event_register(&arg);
733
- if (arg.first_error)
695
+ err = sdei_do_local_call(_local_event_register, event);
696
+ if (err) {
734697 pr_err("Failed to re-register event %u: %d\n",
735
- event->event_num, arg.first_error);
698
+ event->event_num, err);
699
+ }
736700 }
737701
738702 if (event->reenable) {
739
- CROSSCALL_INIT(arg, event);
740
- _local_event_enable(&arg);
741
- if (arg.first_error)
703
+ err = sdei_do_local_call(_local_event_enable, event);
704
+ if (err) {
742705 pr_err("Failed to re-enable event %u: %d\n",
743
- event->event_num, arg.first_error);
706
+ event->event_num, err);
707
+ }
744708 }
745709 }
746710 spin_unlock(&sdei_list_lock);
....@@ -878,6 +842,7 @@
878842 {
879843 arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res);
880844 }
845
+NOKPROBE_SYMBOL(sdei_smccc_smc);
881846
882847 static void sdei_smccc_hvc(unsigned long function_id,
883848 unsigned long arg0, unsigned long arg1,
....@@ -885,6 +850,74 @@
885850 unsigned long arg4, struct arm_smccc_res *res)
886851 {
887852 arm_smccc_hvc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res);
853
+}
854
+NOKPROBE_SYMBOL(sdei_smccc_hvc);
855
+
856
+int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
857
+ sdei_event_callback *critical_cb)
858
+{
859
+ int err;
860
+ u64 result;
861
+ u32 event_num;
862
+ sdei_event_callback *cb;
863
+
864
+ if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
865
+ return -EOPNOTSUPP;
866
+
867
+ event_num = ghes->generic->notify.vector;
868
+ if (event_num == 0) {
869
+ /*
870
+ * Event 0 is reserved by the specification for
871
+ * SDEI_EVENT_SIGNAL.
872
+ */
873
+ return -EINVAL;
874
+ }
875
+
876
+ err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY,
877
+ &result);
878
+ if (err)
879
+ return err;
880
+
881
+ if (result == SDEI_EVENT_PRIORITY_CRITICAL)
882
+ cb = critical_cb;
883
+ else
884
+ cb = normal_cb;
885
+
886
+ err = sdei_event_register(event_num, cb, ghes);
887
+ if (!err)
888
+ err = sdei_event_enable(event_num);
889
+
890
+ return err;
891
+}
892
+
893
+int sdei_unregister_ghes(struct ghes *ghes)
894
+{
895
+ int i;
896
+ int err;
897
+ u32 event_num = ghes->generic->notify.vector;
898
+
899
+ might_sleep();
900
+
901
+ if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
902
+ return -EOPNOTSUPP;
903
+
904
+ /*
905
+ * The event may be running on another CPU. Disable it
906
+ * to stop new events, then try to unregister a few times.
907
+ */
908
+ err = sdei_event_disable(event_num);
909
+ if (err)
910
+ return err;
911
+
912
+ for (i = 0; i < 3; i++) {
913
+ err = sdei_event_unregister(event_num);
914
+ if (err != -EINPROGRESS)
915
+ break;
916
+
917
+ schedule();
918
+ }
919
+
920
+ return err;
888921 }
889922
890923 #ifdef CONFIG_FIQ_DEBUGGER_TRUST_ZONE
....@@ -976,29 +1009,29 @@
9761009 if (np) {
9771010 if (of_property_read_string(np, "method", &method)) {
9781011 pr_warn("missing \"method\" property\n");
979
- return CONDUIT_INVALID;
1012
+ return SMCCC_CONDUIT_NONE;
9801013 }
9811014
9821015 if (!strcmp("hvc", method)) {
9831016 sdei_firmware_call = &sdei_smccc_hvc;
984
- return CONDUIT_HVC;
1017
+ return SMCCC_CONDUIT_HVC;
9851018 } else if (!strcmp("smc", method)) {
9861019 sdei_firmware_call = &sdei_smccc_smc;
987
- return CONDUIT_SMC;
1020
+ return SMCCC_CONDUIT_SMC;
9881021 }
9891022
9901023 pr_warn("invalid \"method\" property: %s\n", method);
991
- } else if (IS_ENABLED(CONFIG_ACPI) && !acpi_disabled) {
1024
+ } else if (!acpi_disabled) {
9921025 if (acpi_psci_use_hvc()) {
9931026 sdei_firmware_call = &sdei_smccc_hvc;
994
- return CONDUIT_HVC;
1027
+ return SMCCC_CONDUIT_HVC;
9951028 } else {
9961029 sdei_firmware_call = &sdei_smccc_smc;
997
- return CONDUIT_SMC;
1030
+ return SMCCC_CONDUIT_SMC;
9981031 }
9991032 }
10001033
1001
- return CONDUIT_INVALID;
1034
+ return SMCCC_CONDUIT_NONE;
10021035 }
10031036
10041037 static int sdei_probe(struct platform_device *pdev)
....@@ -1012,8 +1045,6 @@
10121045 return 0;
10131046
10141047 err = sdei_api_get_version(&ver);
1015
- if (err == -EOPNOTSUPP)
1016
- pr_err("advertised but not implemented in platform firmware\n");
10171048 if (err) {
10181049 pr_err("Failed to get SDEI version: %d\n", err);
10191050 sdei_mark_interface_broken();
....@@ -1087,26 +1118,9 @@
10871118 .probe = sdei_probe,
10881119 };
10891120
1090
-static bool __init sdei_present_dt(void)
1091
-{
1092
- struct device_node *np, *fw_np;
1093
-
1094
- fw_np = of_find_node_by_name(NULL, "firmware");
1095
- if (!fw_np)
1096
- return false;
1097
-
1098
- np = of_find_matching_node(fw_np, sdei_of_match);
1099
- if (!np)
1100
- return false;
1101
- of_node_put(np);
1102
-
1103
- return true;
1104
-}
1105
-
11061121 static bool __init sdei_present_acpi(void)
11071122 {
11081123 acpi_status status;
1109
- struct platform_device *pdev;
11101124 struct acpi_table_header *sdei_table_header;
11111125
11121126 if (acpi_disabled)
....@@ -1121,28 +1135,29 @@
11211135 if (ACPI_FAILURE(status))
11221136 return false;
11231137
1124
- pdev = platform_device_register_simple(sdei_driver.driver.name, 0, NULL,
1125
- 0);
1126
- if (IS_ERR(pdev))
1127
- return false;
1138
+ acpi_put_table(sdei_table_header);
11281139
11291140 return true;
11301141 }
11311142
1132
-static int __init sdei_init(void)
1143
+void __init sdei_init(void)
11331144 {
1134
- if (sdei_present_dt() || sdei_present_acpi())
1135
- platform_driver_register(&sdei_driver);
1145
+ struct platform_device *pdev;
1146
+ int ret;
11361147
1137
- return 0;
1148
+ ret = platform_driver_register(&sdei_driver);
1149
+ if (ret || !sdei_present_acpi())
1150
+ return;
1151
+
1152
+ pdev = platform_device_register_simple(sdei_driver.driver.name,
1153
+ 0, NULL, 0);
1154
+ if (IS_ERR(pdev)) {
1155
+ ret = PTR_ERR(pdev);
1156
+ platform_driver_unregister(&sdei_driver);
1157
+ pr_info("Failed to register ACPI:SDEI platform device %d\n",
1158
+ ret);
1159
+ }
11381160 }
1139
-
1140
-/*
1141
- * On an ACPI system SDEI needs to be ready before HEST:GHES tries to register
1142
- * its events. ACPI is initialised from a subsys_initcall(), GHES is initialised
1143
- * by device_initcall(). We want to be called in the middle.
1144
- */
1145
-subsys_initcall_sync(sdei_init);
11461161
11471162 int sdei_event_handler(struct pt_regs *regs,
11481163 struct sdei_registered_event *arg)
....@@ -1151,16 +1166,42 @@
11511166 mm_segment_t orig_addr_limit;
11521167 u32 event_num = arg->event_num;
11531168
1154
- orig_addr_limit = get_fs();
1155
- set_fs(USER_DS);
1169
+ /*
1170
+ * Save restore 'fs'.
1171
+ * The architecture's entry code save/restores 'fs' when taking an
1172
+ * exception from the kernel. This ensures addr_limit isn't inherited
1173
+ * if you interrupted something that allowed the uaccess routines to
1174
+ * access kernel memory.
1175
+ * Do the same here because this doesn't come via the same entry code.
1176
+ */
1177
+ orig_addr_limit = force_uaccess_begin();
11561178
11571179 err = arg->callback(event_num, regs, arg->callback_arg);
11581180 if (err)
11591181 pr_err_ratelimited("event %u on CPU %u failed with error: %d\n",
11601182 event_num, smp_processor_id(), err);
11611183
1162
- set_fs(orig_addr_limit);
1184
+ force_uaccess_end(orig_addr_limit);
11631185
11641186 return err;
11651187 }
11661188 NOKPROBE_SYMBOL(sdei_event_handler);
1189
+
1190
+void sdei_handler_abort(void)
1191
+{
1192
+ /*
1193
+ * If the crash happened in an SDEI event handler then we need to
1194
+ * finish the handler with the firmware so that we can have working
1195
+ * interrupts in the crash kernel.
1196
+ */
1197
+ if (__this_cpu_read(sdei_active_critical_event)) {
1198
+ pr_warn("still in SDEI critical event context, attempting to finish handler.\n");
1199
+ __sdei_handler_abort();
1200
+ __this_cpu_write(sdei_active_critical_event, NULL);
1201
+ }
1202
+ if (__this_cpu_read(sdei_active_normal_event)) {
1203
+ pr_warn("still in SDEI normal event context, attempting to finish handler.\n");
1204
+ __sdei_handler_abort();
1205
+ __this_cpu_write(sdei_active_normal_event, NULL);
1206
+ }
1207
+}