What used to be a simple few instructions has turned into a giant mess
(for x86_64). Not only does it use static_branch wrong, it mixes it
with dynamic branches for no apparent reason.
Notably it uses static_branch through an out-of-line function call,
which completely defeats the purpose, since instead of a simple
JMP/NOP site, you get a CALL+RET+TEST+Jcc sequence in return, which is
absolutely idiotic.
Add to that a dynamic test of hyperv_paravisor_present, something
which is set once and never changed.
Replace all this idiocy with a single direct function call to the
right hypercall variant.
Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
---
arch/x86/hyperv/hv_init.c | 21 ++++++
arch/x86/hyperv/ivm.c | 14 ++++
arch/x86/include/asm/mshyperv.h | 137 +++++++++++-----------------------------
arch/x86/kernel/cpu/mshyperv.c | 18 +++--
4 files changed, 88 insertions(+), 102 deletions(-)
--- a/arch/x86/hyperv/hv_init.c
+++ b/arch/x86/hyperv/hv_init.c
@@ -35,7 +35,28 @@
#include <linux/highmem.h>
void *hv_hypercall_pg;
+
+#ifdef CONFIG_X86_64
+u64 hv_pg_hypercall(u64 control, u64 param1, u64 param2)
+{
+ u64 hv_status;
+
+ if (!hv_hypercall_pg)
+ return U64_MAX;
+
+ register u64 __r8 asm("r8") = param2;
+ asm volatile (CALL_NOSPEC
+ : "=a" (hv_status), ASM_CALL_CONSTRAINT,
+ "+c" (control), "+d" (param1)
+ : "r" (__r8),
+ : "cc", "memory", "r9", "r10", "r11");
+
+ return hv_status;
+}
+#else
EXPORT_SYMBOL_GPL(hv_hypercall_pg);
+#endif
union hv_ghcb * __percpu *hv_ghcb_pg;
--- a/arch/x86/hyperv/ivm.c
+++ b/arch/x86/hyperv/ivm.c
@@ -376,6 +376,20 @@ int hv_snp_boot_ap(u32 cpu, unsigned lon
return ret;
}
+u64 hv_snp_hypercall(u64 control, u64 param1, u64 param2)
+{
+ u64 hv_status;
+
+ register u64 __r8 asm("r8") = param2;
+ asm volatile("vmmcall"
+ : "=a" (hv_status), ASM_CALL_CONSTRAINT,
+ "+c" (control), "+d" (param1)
+ : "r" (__r8)
+ : "cc", "memory", "r9", "r10", "r11");
+
+ return hv_status;
+}