|
@@ -380,19 +380,24 @@ void stop_this_cpu(void *dummy)
|
|
disable_local_APIC();
|
|
disable_local_APIC();
|
|
mcheck_cpu_clear(this_cpu_ptr(&cpu_info));
|
|
mcheck_cpu_clear(this_cpu_ptr(&cpu_info));
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Use wbinvd on processors that support SME. This provides support
|
|
|
|
+ * for performing a successful kexec when going from SME inactive
|
|
|
|
+ * to SME active (or vice-versa). The cache must be cleared so that
|
|
|
|
+ * if there are entries with the same physical address, both with and
|
|
|
|
+ * without the encryption bit, they don't race each other when flushed
|
|
|
|
+ * and potentially end up with the wrong entry being committed to
|
|
|
|
+ * memory.
|
|
|
|
+ */
|
|
|
|
+ if (boot_cpu_has(X86_FEATURE_SME))
|
|
|
|
+ native_wbinvd();
|
|
for (;;) {
|
|
for (;;) {
|
|
/*
|
|
/*
|
|
- * Use wbinvd followed by hlt to stop the processor. This
|
|
|
|
- * provides support for kexec on a processor that supports
|
|
|
|
- * SME. With kexec, going from SME inactive to SME active
|
|
|
|
- * requires clearing cache entries so that addresses without
|
|
|
|
- * the encryption bit set don't corrupt the same physical
|
|
|
|
- * address that has the encryption bit set when caches are
|
|
|
|
- * flushed. To achieve this a wbinvd is performed followed by
|
|
|
|
- * a hlt. Even if the processor is not in the kexec/SME
|
|
|
|
- * scenario this only adds a wbinvd to a halting processor.
|
|
|
|
|
|
+ * Use native_halt() so that memory contents don't change
|
|
|
|
+ * (stack usage and variables) after possibly issuing the
|
|
|
|
+ * native_wbinvd() above.
|
|
*/
|
|
*/
|
|
- asm volatile("wbinvd; hlt" : : : "memory");
|
|
|
|
|
|
+ native_halt();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|