[PATCH v2] x86: Skip WBINVD instruction for VM guest

From: Kuppuswamy Sathyanarayanan
Date: Thu Nov 18 2021 - 23:03:51 EST


ACPI mandates that CPU caches be flushed before entering any sleep
state. This ensures that the CPU and its caches can be powered down
without losing data.

ACPI-based VMs have maintained this sleep-state-entry behavior.
However, cache flushing for VM sleep state entry is useless. Unlike on
bare metal, guest sleep states are not correlated with potential data
loss of any kind; the host is responsible for data preservation. In
fact, some KVM configurations simply skip the cache flushing
instruction (see need_emulate_wbinvd()).

Further, on TDX systems, the WBINVD instruction causes an
unconditional #VE exception. If this cache flushing remained, it would
need extra code in the form of a #VE handler.

All use of ACPI_FLUSH_CPU_CACHE() appears to be in sleep-state-related
code.

This means that the ACPI use of WBINVD is at *best* superfluous.

Disable ACPI CPU cache flushing on all X86_FEATURE_HYPERVISOR systems,
which includes TDX.

Cc: Rafael J. Wysocki <rjw@xxxxxxxxxxxxx>
Cc: linux-acpi@xxxxxxxxxxxxxxx
Reviewed-by: Dan Williams <dan.j.williams@xxxxxxxxx>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx>
---

Changes since v1:
* Used cpu_feature_enabled() instead of boot_cpu_has().

arch/x86/include/asm/acenv.h | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/acenv.h b/arch/x86/include/asm/acenv.h
index 9aff97f0de7f..dba05c74bd7e 100644
--- a/arch/x86/include/asm/acenv.h
+++ b/arch/x86/include/asm/acenv.h
@@ -10,10 +10,15 @@
#define _ASM_X86_ACENV_H

#include <asm/special_insns.h>
+#include <asm/cpu.h>

/* Asm macros */

-#define ACPI_FLUSH_CPU_CACHE() wbinvd()
+#define ACPI_FLUSH_CPU_CACHE() \
+do { \
+ if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) \
+ wbinvd(); \
+} while (0)

int __acpi_acquire_global_lock(unsigned int *lock);
int __acpi_release_global_lock(unsigned int *lock);
--
2.25.1