x86/process: Move the buffer clearing before MONITOR

Commit 8e786a85c0a3c0fffae6244733fb576eeabd9dec upstream.

Move the VERW clearing before the MONITOR so that VERW doesn't disarm it
and the machine never enters C1.

Original idea by Kim Phillips <kim.phillips@amd.com>.

Suggested-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Borislav Petkov (AMD)
2025-04-14 15:33:19 +02:00
committed by Greg Kroah-Hartman
parent 6fb766d53f
commit 8c19449058
2 changed files with 27 additions and 14 deletions

View File

@@ -44,8 +44,6 @@ static __always_inline void __monitorx(const void *eax, unsigned long ecx,
static __always_inline void __mwait(unsigned long eax, unsigned long ecx) static __always_inline void __mwait(unsigned long eax, unsigned long ecx)
{ {
x86_idle_clear_cpu_buffers();
/* "mwait %eax, %ecx;" */ /* "mwait %eax, %ecx;" */
asm volatile(".byte 0x0f, 0x01, 0xc9;" asm volatile(".byte 0x0f, 0x01, 0xc9;"
:: "a" (eax), "c" (ecx)); :: "a" (eax), "c" (ecx));
@@ -89,7 +87,6 @@ static __always_inline void __mwaitx(unsigned long eax, unsigned long ebx,
static __always_inline void __sti_mwait(unsigned long eax, unsigned long ecx) static __always_inline void __sti_mwait(unsigned long eax, unsigned long ecx)
{ {
x86_idle_clear_cpu_buffers();
/* "mwait %eax, %ecx;" */ /* "mwait %eax, %ecx;" */
asm volatile("sti; .byte 0x0f, 0x01, 0xc9;" asm volatile("sti; .byte 0x0f, 0x01, 0xc9;"
@@ -108,13 +105,20 @@ static __always_inline void __sti_mwait(unsigned long eax, unsigned long ecx)
*/ */
static __always_inline void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) static __always_inline void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
{ {
if (need_resched())
return;
x86_idle_clear_cpu_buffers();
if (static_cpu_has_bug(X86_BUG_MONITOR) || !current_set_polling_and_test()) { if (static_cpu_has_bug(X86_BUG_MONITOR) || !current_set_polling_and_test()) {
const void *addr = &current_thread_info()->flags; const void *addr = &current_thread_info()->flags;
alternative_input("", "clflush (%[addr])", X86_BUG_CLFLUSH_MONITOR, [addr] "a" (addr)); alternative_input("", "clflush (%[addr])", X86_BUG_CLFLUSH_MONITOR, [addr] "a" (addr));
__monitor(addr, 0, 0); __monitor(addr, 0, 0);
if (!need_resched()) { if (need_resched())
goto out;
if (ecx & 1) { if (ecx & 1) {
__mwait(eax, ecx); __mwait(eax, ecx);
} else { } else {
@@ -122,7 +126,8 @@ static __always_inline void mwait_idle_with_hints(unsigned long eax, unsigned lo
raw_local_irq_disable(); raw_local_irq_disable();
} }
} }
}
out:
current_clr_polling(); current_clr_polling();
} }

View File

@@ -928,16 +928,24 @@ static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
*/ */
static __cpuidle void mwait_idle(void) static __cpuidle void mwait_idle(void)
{ {
if (need_resched())
return;
x86_idle_clear_cpu_buffers();
if (!current_set_polling_and_test()) { if (!current_set_polling_and_test()) {
const void *addr = &current_thread_info()->flags; const void *addr = &current_thread_info()->flags;
alternative_input("", "clflush (%[addr])", X86_BUG_CLFLUSH_MONITOR, [addr] "a" (addr)); alternative_input("", "clflush (%[addr])", X86_BUG_CLFLUSH_MONITOR, [addr] "a" (addr));
__monitor(addr, 0, 0); __monitor(addr, 0, 0);
if (!need_resched()) { if (need_resched())
goto out;
__sti_mwait(0, 0); __sti_mwait(0, 0);
raw_local_irq_disable(); raw_local_irq_disable();
} }
}
out:
__current_clr_polling(); __current_clr_polling();
} }