Skip to content

Commit f9c9987

Browse files
committed
x86/smp: Use dedicated cache-line for mwait_play_dead()
Monitoring idletask::thread_info::flags in mwait_play_dead() has been an obvious choice as all what is needed is a cache line which is not written by other CPUs. But there is a use case where a "dead" CPU needs to be brought out of MWAIT: kexec(). This is required as kexec() can overwrite text, pagetables, stacks and the monitored cacheline of the original kernel. The latter causes MWAIT to resume execution which obviously causes havoc on the kexec kernel which results usually in triple faults. Use a dedicated per CPU storage to prepare for that. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Ashok Raj <ashok.raj@intel.com> Reviewed-by: Borislav Petkov (AMD) <bp@alien8.de> Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230615193330.434553750@linutronix.de
1 parent 2affa6d commit f9c9987

File tree

1 file changed

+14
-10
lines changed

1 file changed

+14
-10
lines changed

arch/x86/kernel/smpboot.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,17 @@ EXPORT_PER_CPU_SYMBOL(cpu_die_map);
101101
DEFINE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
102102
EXPORT_PER_CPU_SYMBOL(cpu_info);
103103

104+
struct mwait_cpu_dead {
105+
unsigned int control;
106+
unsigned int status;
107+
};
108+
109+
/*
110+
* Cache line aligned data for mwait_play_dead(). Separate on purpose so
111+
* that it's unlikely to be touched by other CPUs.
112+
*/
113+
static DEFINE_PER_CPU_ALIGNED(struct mwait_cpu_dead, mwait_cpu_dead);
114+
104115
/* Logical package management. We might want to allocate that dynamically */
105116
unsigned int __max_logical_packages __read_mostly;
106117
EXPORT_SYMBOL(__max_logical_packages);
@@ -1758,10 +1769,10 @@ EXPORT_SYMBOL_GPL(cond_wakeup_cpu0);
17581769
*/
17591770
static inline void mwait_play_dead(void)
17601771
{
1772+
struct mwait_cpu_dead *md = this_cpu_ptr(&mwait_cpu_dead);
17611773
unsigned int eax, ebx, ecx, edx;
17621774
unsigned int highest_cstate = 0;
17631775
unsigned int highest_subcstate = 0;
1764-
void *mwait_ptr;
17651776
int i;
17661777

17671778
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
@@ -1796,13 +1807,6 @@ static inline void mwait_play_dead(void)
17961807
(highest_subcstate - 1);
17971808
}
17981809

1799-
/*
1800-
* This should be a memory location in a cache line which is
1801-
* unlikely to be touched by other processors. The actual
1802-
* content is immaterial as it is not actually modified in any way.
1803-
*/
1804-
mwait_ptr = &current_thread_info()->flags;
1805-
18061810
wbinvd();
18071811

18081812
while (1) {
@@ -1814,9 +1818,9 @@ static inline void mwait_play_dead(void)
18141818
* case where we return around the loop.
18151819
*/
18161820
mb();
1817-
clflush(mwait_ptr);
1821+
clflush(md);
18181822
mb();
1819-
__monitor(mwait_ptr, 0, 0);
1823+
__monitor(md, 0, 0);
18201824
mb();
18211825
__mwait(eax, 0);
18221826

0 commit comments

Comments
 (0)