]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
arch: hyperv: Get/set SynIC synth.registers via paravisor
authorRoman Kisel <romank@linux.microsoft.com>
Wed, 8 Oct 2025 23:34:06 +0000 (16:34 -0700)
committerWei Liu <wei.liu@kernel.org>
Sat, 15 Nov 2025 06:18:14 +0000 (06:18 +0000)
The existing Hyper-V wrappers for getting and setting MSRs are
hv_get/set_msr(). Via hv_get/set_non_nested_msr(), they detect
when running in a CoCo VM with a paravisor, and use the TDX or
SNP guest-host communication protocol to bypass the paravisor
and go directly to the host hypervisor for SynIC MSRs. The "set"
function also implements the required special handling for the
SINT MSRs.

Provide functions that allow manipulating the SynIC registers
through the paravisor. Move vmbus_signal_eom() to a more
appropriate location (which also avoids breaking KVM).

Signed-off-by: Roman Kisel <romank@linux.microsoft.com>
Reviewed-by: Alok Tiwari <alok.a.tiwari@oracle.com>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>
arch/x86/kernel/cpu/mshyperv.c
drivers/hv/hv_common.c
drivers/hv/hyperv_vmbus.h
include/asm-generic/mshyperv.h

index 1369fae7d8a93922768fdb800787d63fc6449a83..eb9f1d7eec61b5bb7238ff1fd1a9d984ce7a48ed 100644 (file)
@@ -86,6 +86,26 @@ void hv_set_non_nested_msr(unsigned int reg, u64 value)
 }
 EXPORT_SYMBOL_GPL(hv_set_non_nested_msr);
 
+/*
+ * Get the SynIC register value from the paravisor.
+ */
+u64 hv_para_get_synic_register(unsigned int reg)
+{
+       if (WARN_ON(!ms_hyperv.paravisor_present || !hv_is_synic_msr(reg)))
+               return ~0ULL;
+       return native_read_msr(reg);
+}
+
+/*
+ * Set the SynIC register value with the paravisor.
+ */
+void hv_para_set_synic_register(unsigned int reg, u64 val)
+{
+       if (WARN_ON(!ms_hyperv.paravisor_present || !hv_is_synic_msr(reg)))
+               return;
+       native_write_msr(reg, val);
+}
+
 u64 hv_get_msr(unsigned int reg)
 {
        if (hv_nested)
index 3e41f686daa5ec32f3b50df6333cf31e51e350ce..c39472ae8345a78a193fd28c35f9a2f46e9b521c 100644 (file)
@@ -721,6 +721,17 @@ void __weak hv_enable_coco_interrupt(unsigned int cpu, unsigned int vector, bool
 }
 EXPORT_SYMBOL_GPL(hv_enable_coco_interrupt);
 
+u64 __weak hv_para_get_synic_register(unsigned int reg)
+{
+       return ~0ULL;
+}
+EXPORT_SYMBOL_GPL(hv_para_get_synic_register);
+
+void __weak hv_para_set_synic_register(unsigned int reg, u64 val)
+{
+}
+EXPORT_SYMBOL_GPL(hv_para_set_synic_register);
+
 void hv_identify_partition_type(void)
 {
        /* Assume guest role */
index 4a01797d485139839657976db726dc615d088834..9ac6f55202875280ec6cbbe7685c67f8bfb1a4f7 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/bitops.h>
 #include <asm/sync_bitops.h>
+#include <asm/mshyperv.h>
 #include <linux/atomic.h>
 #include <linux/hyperv.h>
 #include <linux/interrupt.h>
@@ -335,6 +336,49 @@ extern const struct vmbus_channel_message_table_entry
 
 bool vmbus_is_confidential(void);
 
+#if IS_ENABLED(CONFIG_HYPERV_VMBUS)
+/* Free the message slot and signal end-of-message if required */
+static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
+{
+       /*
+        * On crash we're reading some other CPU's message page and we need
+        * to be careful: this other CPU may already had cleared the header
+        * and the host may already had delivered some other message there.
+        * In case we blindly write msg->header.message_type we're going
+        * to lose it. We can still lose a message of the same type but
+        * we count on the fact that there can only be one
+        * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages
+        * on crash.
+        */
+       if (cmpxchg(&msg->header.message_type, old_msg_type,
+                   HVMSG_NONE) != old_msg_type)
+               return;
+
+       /*
+        * The cmxchg() above does an implicit memory barrier to
+        * ensure the write to MessageType (ie set to
+        * HVMSG_NONE) happens before we read the
+        * MessagePending and EOMing. Otherwise, the EOMing
+        * will not deliver any more messages since there is
+        * no empty slot
+        */
+       if (msg->header.message_flags.msg_pending) {
+               /*
+                * This will cause message queue rescan to
+                * possibly deliver another msg from the
+                * hypervisor
+                */
+               if (vmbus_is_confidential())
+                       hv_para_set_synic_register(HV_MSR_EOM, 0);
+               else
+                       hv_set_msr(HV_MSR_EOM, 0);
+       }
+}
+
+extern int vmbus_interrupt;
+extern int vmbus_irq;
+#endif /* CONFIG_HYPERV_VMBUS */
+
 struct hv_device *vmbus_device_create(const guid_t *type,
                                      const guid_t *instance,
                                      struct vmbus_channel *channel);
index 8da1893365f0064050bb85b36fa5456235b59087..c328265de62446c91ecd5a7005ad508aa286574a 100644 (file)
@@ -176,46 +176,6 @@ static inline u64 hv_generate_guest_id(u64 kernel_version)
        return guest_id;
 }
 
-#if IS_ENABLED(CONFIG_HYPERV_VMBUS)
-/* Free the message slot and signal end-of-message if required */
-static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
-{
-       /*
-        * On crash we're reading some other CPU's message page and we need
-        * to be careful: this other CPU may already had cleared the header
-        * and the host may already had delivered some other message there.
-        * In case we blindly write msg->header.message_type we're going
-        * to lose it. We can still lose a message of the same type but
-        * we count on the fact that there can only be one
-        * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages
-        * on crash.
-        */
-       if (cmpxchg(&msg->header.message_type, old_msg_type,
-                   HVMSG_NONE) != old_msg_type)
-               return;
-
-       /*
-        * The cmxchg() above does an implicit memory barrier to
-        * ensure the write to MessageType (ie set to
-        * HVMSG_NONE) happens before we read the
-        * MessagePending and EOMing. Otherwise, the EOMing
-        * will not deliver any more messages since there is
-        * no empty slot
-        */
-       if (msg->header.message_flags.msg_pending) {
-               /*
-                * This will cause message queue rescan to
-                * possibly deliver another msg from the
-                * hypervisor
-                */
-               hv_set_msr(HV_MSR_EOM, 0);
-       }
-}
-
-extern int vmbus_interrupt;
-extern int vmbus_irq;
-#endif /* CONFIG_HYPERV_VMBUS */
-
 int hv_get_hypervisor_version(union hv_hypervisor_version_info *info);
 
 void hv_setup_vmbus_handler(void (*handler)(void));
@@ -350,6 +310,8 @@ bool hv_isolation_type_snp(void);
 u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size);
 u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2);
 void hv_enable_coco_interrupt(unsigned int cpu, unsigned int vector, bool set);
+u64 hv_para_get_synic_register(unsigned int reg);
+void hv_para_set_synic_register(unsigned int reg, u64 val);
 void hyperv_cleanup(void);
 bool hv_query_ext_cap(u64 cap_query);
 void hv_setup_dma_ops(struct device *dev, bool coherent);