Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

arch: hyperv: Get/set SynIC synth.registers via paravisor

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>

authored by

Roman Kisel and committed by
Wei Liu
e6eeb3c7 7c8b6c32

+77 -40
+20
arch/x86/kernel/cpu/mshyperv.c
··· 86 86 } 87 87 EXPORT_SYMBOL_GPL(hv_set_non_nested_msr); 88 88 89 + /* 90 + * Get the SynIC register value from the paravisor. 91 + */ 92 + u64 hv_para_get_synic_register(unsigned int reg) 93 + { 94 + if (WARN_ON(!ms_hyperv.paravisor_present || !hv_is_synic_msr(reg))) 95 + return ~0ULL; 96 + return native_read_msr(reg); 97 + } 98 + 99 + /* 100 + * Set the SynIC register value with the paravisor. 101 + */ 102 + void hv_para_set_synic_register(unsigned int reg, u64 val) 103 + { 104 + if (WARN_ON(!ms_hyperv.paravisor_present || !hv_is_synic_msr(reg))) 105 + return; 106 + native_write_msr(reg, val); 107 + } 108 + 89 109 u64 hv_get_msr(unsigned int reg) 90 110 { 91 111 if (hv_nested)
+11
drivers/hv/hv_common.c
··· 721 721 } 722 722 EXPORT_SYMBOL_GPL(hv_enable_coco_interrupt); 723 723 724 + u64 __weak hv_para_get_synic_register(unsigned int reg) 725 + { 726 + return ~0ULL; 727 + } 728 + EXPORT_SYMBOL_GPL(hv_para_get_synic_register); 729 + 730 + void __weak hv_para_set_synic_register(unsigned int reg, u64 val) 731 + { 732 + } 733 + EXPORT_SYMBOL_GPL(hv_para_set_synic_register); 734 + 724 735 void hv_identify_partition_type(void) 725 736 { 726 737 /* Assume guest role */
+44
drivers/hv/hyperv_vmbus.h
··· 15 15 #include <linux/list.h> 16 16 #include <linux/bitops.h> 17 17 #include <asm/sync_bitops.h> 18 + #include <asm/mshyperv.h> 18 19 #include <linux/atomic.h> 19 20 #include <linux/hyperv.h> 20 21 #include <linux/interrupt.h> ··· 335 334 /* General vmbus interface */ 336 335 337 336 bool vmbus_is_confidential(void); 337 + 338 + #if IS_ENABLED(CONFIG_HYPERV_VMBUS) 339 + /* Free the message slot and signal end-of-message if required */ 340 + static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) 341 + { 342 + /* 343 + * On crash we're reading some other CPU's message page and we need 344 + * to be careful: this other CPU may already had cleared the header 345 + * and the host may already had delivered some other message there. 346 + * In case we blindly write msg->header.message_type we're going 347 + * to lose it. We can still lose a message of the same type but 348 + * we count on the fact that there can only be one 349 + * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages 350 + * on crash. 351 + */ 352 + if (cmpxchg(&msg->header.message_type, old_msg_type, 353 + HVMSG_NONE) != old_msg_type) 354 + return; 355 + 356 + /* 357 + * The cmxchg() above does an implicit memory barrier to 358 + * ensure the write to MessageType (ie set to 359 + * HVMSG_NONE) happens before we read the 360 + * MessagePending and EOMing. Otherwise, the EOMing 361 + * will not deliver any more messages since there is 362 + * no empty slot 363 + */ 364 + if (msg->header.message_flags.msg_pending) { 365 + /* 366 + * This will cause message queue rescan to 367 + * possibly deliver another msg from the 368 + * hypervisor 369 + */ 370 + if (vmbus_is_confidential()) 371 + hv_para_set_synic_register(HV_MSR_EOM, 0); 372 + else 373 + hv_set_msr(HV_MSR_EOM, 0); 374 + } 375 + } 376 + 377 + extern int vmbus_interrupt; 378 + extern int vmbus_irq; 379 + #endif /* CONFIG_HYPERV_VMBUS */ 338 380 339 381 struct hv_device *vmbus_device_create(const guid_t *type, 340 382 const guid_t *instance,
+2 -40
include/asm-generic/mshyperv.h
··· 176 176 return guest_id; 177 177 } 178 178 179 - #if IS_ENABLED(CONFIG_HYPERV_VMBUS) 180 - /* Free the message slot and signal end-of-message if required */ 181 - static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) 182 - { 183 - /* 184 - * On crash we're reading some other CPU's message page and we need 185 - * to be careful: this other CPU may already had cleared the header 186 - * and the host may already had delivered some other message there. 187 - * In case we blindly write msg->header.message_type we're going 188 - * to lose it. We can still lose a message of the same type but 189 - * we count on the fact that there can only be one 190 - * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages 191 - * on crash. 192 - */ 193 - if (cmpxchg(&msg->header.message_type, old_msg_type, 194 - HVMSG_NONE) != old_msg_type) 195 - return; 196 - 197 - /* 198 - * The cmxchg() above does an implicit memory barrier to 199 - * ensure the write to MessageType (ie set to 200 - * HVMSG_NONE) happens before we read the 201 - * MessagePending and EOMing. Otherwise, the EOMing 202 - * will not deliver any more messages since there is 203 - * no empty slot 204 - */ 205 - if (msg->header.message_flags.msg_pending) { 206 - /* 207 - * This will cause message queue rescan to 208 - * possibly deliver another msg from the 209 - * hypervisor 210 - */ 211 - hv_set_msr(HV_MSR_EOM, 0); 212 - } 213 - } 214 - 215 - extern int vmbus_interrupt; 216 - extern int vmbus_irq; 217 - #endif /* CONFIG_HYPERV_VMBUS */ 218 - 219 179 int hv_get_hypervisor_version(union hv_hypervisor_version_info *info); 220 180 221 181 void hv_setup_vmbus_handler(void (*handler)(void)); ··· 310 350 u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size); 311 351 u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2); 312 352 void hv_enable_coco_interrupt(unsigned int cpu, unsigned int vector, bool set); 353 + u64 hv_para_get_synic_register(unsigned int reg); 354 + void hv_para_set_synic_register(unsigned int reg, u64 val); 313 355 void hyperv_cleanup(void); 314 356 bool hv_query_ext_cap(u64 cap_query); 315 357 void hv_setup_dma_ops(struct device *dev, bool coherent);