hc
2024-11-01 2f529f9b558ca1c1bd74be7437a84e4711743404
kernel/arch/x86/mm/tlb.c
....@@ -5,6 +5,7 @@
55 #include <linux/spinlock.h>
66 #include <linux/smp.h>
77 #include <linux/interrupt.h>
8
+#include <linux/irq_pipeline.h>
89 #include <linux/export.h>
910 #include <linux/cpu.h>
1011 #include <linux/debugfs.h>
....@@ -309,10 +310,12 @@
309310 void switch_mm(struct mm_struct *prev, struct mm_struct *next,
310311 struct task_struct *tsk)
311312 {
312
- unsigned long flags;
313
+ unsigned long flags, _flags;
313314
314315 local_irq_save(flags);
316
+ protect_inband_mm(_flags);
315317 switch_mm_irqs_off(prev, next, tsk);
318
+ unprotect_inband_mm(_flags);
316319 local_irq_restore(flags);
317320 }
318321
....@@ -440,7 +443,9 @@
440443 */
441444
442445 /* We don't want flush_tlb_func_* to run concurrently with us. */
443
- if (IS_ENABLED(CONFIG_PROVE_LOCKING))
446
+ if (IS_ENABLED(CONFIG_DOVETAIL))
447
+ WARN_ON_ONCE(!hard_irqs_disabled());
448
+ else if (IS_ENABLED(CONFIG_PROVE_LOCKING))
444449 WARN_ON_ONCE(!irqs_disabled());
445450
446451 /*
....@@ -666,15 +671,24 @@
666671 * wants us to catch up to.
667672 */
668673 struct mm_struct *loaded_mm = this_cpu_read(cpu_tlbstate.loaded_mm);
669
- u32 loaded_mm_asid = this_cpu_read(cpu_tlbstate.loaded_mm_asid);
670
- u64 mm_tlb_gen = atomic64_read(&loaded_mm->context.tlb_gen);
671
- u64 local_tlb_gen = this_cpu_read(cpu_tlbstate.ctxs[loaded_mm_asid].tlb_gen);
674
+ u32 loaded_mm_asid;
675
+ u64 mm_tlb_gen;
676
+ u64 local_tlb_gen;
677
+ unsigned long flags;
672678
673679 /* This code cannot presently handle being reentered. */
674680 VM_WARN_ON(!irqs_disabled());
675681
676
- if (unlikely(loaded_mm == &init_mm))
682
+ protect_inband_mm(flags);
683
+
684
+ loaded_mm_asid = this_cpu_read(cpu_tlbstate.loaded_mm_asid);
685
+ mm_tlb_gen = atomic64_read(&loaded_mm->context.tlb_gen);
686
+ local_tlb_gen = this_cpu_read(cpu_tlbstate.ctxs[loaded_mm_asid].tlb_gen);
687
+
688
+ if (unlikely(loaded_mm == &init_mm)) {
689
+ unprotect_inband_mm(flags);
677690 return;
691
+ }
678692
679693 VM_WARN_ON(this_cpu_read(cpu_tlbstate.ctxs[loaded_mm_asid].ctx_id) !=
680694 loaded_mm->context.ctx_id);
....@@ -690,6 +704,7 @@
690704 * IPIs to lazy TLB mode CPUs.
691705 */
692706 switch_mm_irqs_off(NULL, &init_mm, NULL);
707
+ unprotect_inband_mm(flags);
693708 return;
694709 }
695710
....@@ -700,12 +715,15 @@
700715 * be handled can catch us all the way up, leaving no work for
701716 * the second flush.
702717 */
718
+ unprotect_inband_mm(flags);
703719 trace_tlb_flush(reason, 0);
704720 return;
705721 }
706722
707723 WARN_ON_ONCE(local_tlb_gen > mm_tlb_gen);
708724 WARN_ON_ONCE(f->new_tlb_gen > mm_tlb_gen);
725
+
726
+ unprotect_inband_mm(flags);
709727
710728 /*
711729 * If we get to this point, we know that our TLB is out of date.
....@@ -1063,7 +1081,7 @@
10631081 * from interrupts. (Use the raw variant because this code can
10641082 * be called from deep inside debugging code.)
10651083 */
1066
- raw_local_irq_save(flags);
1084
+ flags = hard_local_irq_save();
10671085
10681086 cr4 = this_cpu_read(cpu_tlbstate.cr4);
10691087 /* toggle PGE */
....@@ -1071,7 +1089,7 @@
10711089 /* write old PGE again and flush TLBs */
10721090 native_write_cr4(cr4);
10731091
1074
- raw_local_irq_restore(flags);
1092
+ hard_local_irq_restore(flags);
10751093 }
10761094
10771095 /*
....@@ -1079,6 +1097,8 @@
10791097 */
10801098 STATIC_NOPV void native_flush_tlb_local(void)
10811099 {
1100
+ unsigned long flags;
1101
+
10821102 /*
10831103 * Preemption or interrupts must be disabled to protect the access
10841104 * to the per CPU variable and to prevent being preempted between
....@@ -1086,10 +1106,14 @@
10861106 */
10871107 WARN_ON_ONCE(preemptible());
10881108
1109
+ flags = hard_cond_local_irq_save();
1110
+
10891111 invalidate_user_asid(this_cpu_read(cpu_tlbstate.loaded_mm_asid));
10901112
10911113 /* If current->mm == NULL then the read_cr3() "borrows" an mm */
10921114 native_write_cr3(__native_read_cr3());
1115
+
1116
+ hard_cond_local_irq_restore(flags);
10931117 }
10941118
10951119 void flush_tlb_local(void)
....@@ -1165,6 +1189,16 @@
11651189 VM_WARN_ON_ONCE(!loaded_mm);
11661190
11671191 /*
1192
+ * There would be no way for the companion core to switch an
1193
+ * out-of-band task back in-band in order to handle an access
1194
+ * fault over NMI safely. Tell the caller that uaccess from
1195
+ * NMI is NOT ok if the preempted task was running
1196
+ * out-of-band.
1197
+ */
1198
+ if (running_oob())
1199
+ return false;
1200
+
1201
+ /*
11681202 * The condition we want to check is
11691203 * current_mm->pgd == __va(read_cr3_pa()). This may be slow, though,
11701204 * if we're running in a VM with shadow paging, and nmi_uaccess_okay()