Inter-revision diff: patch 3

Comparing v5 (message) to v3 (message)

--- v5
+++ v3
@@ -1,41 +1,21 @@
 From: Tianyu Lan <Tianyu.Lan@microsoft.com>
 
-Add new hvcall guest address host visibility support to mark
-memory visible to host. Call it inside set_memory_decrypted
-/encrypted(). Add HYPERVISOR feature check in the
-hv_is_isolation_supported() to optimize in non-virtualization
-environment.
+Add new hvcall guest address host visibility support. Mark vmbus
+ring buffer visible to host when create gpadl buffer and mark back
+to not visible when tear down gpadl buffer.
 
-Acked-by: Dave Hansen <dave.hansen@intel.com>
+Co-developed-by: Sunil Muthuswamy <sunilmut@microsoft.com>
 Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
 ---
-Change since v4:
-        * Fix typo in the comment
-	* Make hv_mark_gpa_visibility() to be a static function
-	* Merge __hv_set_mem_host_visibility() and hv_set_mem_host_visibility()
-
-Change since v3:
-	* Fix error code handle in the __hv_set_mem_host_visibility().
-	* Move HvCallModifySparseGpaPageHostVisibility near to enum
-	  hv_mem_host_visibility.
-
-Change since v2:
-       * Rework __set_memory_enc_dec() and call Hyper-V and AMD function
-         according to platform check.
-
-Change since v1:
-       * Use new staic call x86_set_memory_enc to avoid add Hyper-V
-         specific check in the set_memory code.
----
  arch/x86/hyperv/Makefile           |   2 +-
- arch/x86/hyperv/hv_init.c          |   6 ++
- arch/x86/hyperv/ivm.c              | 105 +++++++++++++++++++++++++++++
- arch/x86/include/asm/hyperv-tlfs.h |  17 +++++
- arch/x86/include/asm/mshyperv.h    |   2 +-
- arch/x86/mm/pat/set_memory.c       |  19 ++++--
+ arch/x86/hyperv/ivm.c              | 106 +++++++++++++++++++++++++++++
+ arch/x86/include/asm/hyperv-tlfs.h |  24 +++++++
+ arch/x86/include/asm/mshyperv.h    |   4 +-
+ arch/x86/mm/pat/set_memory.c       |  10 ++-
+ drivers/hv/channel.c               |  38 ++++++++++-
  include/asm-generic/hyperv-tlfs.h  |   1 +
- include/asm-generic/mshyperv.h     |   1 +
- 8 files changed, 146 insertions(+), 7 deletions(-)
+ include/linux/hyperv.h             |  10 +++
+ 8 files changed, 190 insertions(+), 5 deletions(-)
  create mode 100644 arch/x86/hyperv/ivm.c
 
 diff --git a/arch/x86/hyperv/Makefile b/arch/x86/hyperv/Makefile
@@ -49,29 +29,12 @@
  obj-$(CONFIG_X86_64)	+= hv_apic.o hv_proc.o
  
  ifdef CONFIG_X86_64
-diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
-index a7e922755ad1..d57df6825527 100644
---- a/arch/x86/hyperv/hv_init.c
-+++ b/arch/x86/hyperv/hv_init.c
-@@ -603,6 +603,12 @@ EXPORT_SYMBOL_GPL(hv_get_isolation_type);
- 
- bool hv_is_isolation_supported(void)
- {
-+	if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
-+		return false;
-+
-+	if (!hypervisor_is_type(X86_HYPER_MS_HYPERV))
-+		return false;
-+
- 	return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE;
- }
- 
 diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c
 new file mode 100644
-index 000000000000..79e7fb83472a
+index 000000000000..fad1d3024056
 --- /dev/null
 +++ b/arch/x86/hyperv/ivm.c
-@@ -0,0 +1,105 @@
+@@ -0,0 +1,106 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Hyper-V Isolation VM interface with paravisor and hypervisor
@@ -83,19 +46,17 @@
 +#include <linux/hyperv.h>
 +#include <linux/types.h>
 +#include <linux/bitfield.h>
-+#include <linux/slab.h>
 +#include <asm/io.h>
 +#include <asm/mshyperv.h>
 +
 +/*
 + * hv_mark_gpa_visibility - Set pages visible to host via hvcall.
 + *
-+ * In Isolation VM, all guest memory is encrypted from host and guest
++ * In Isolation VM, all guest memory is encripted from host and guest
 + * needs to set memory visible to host via hvcall before sharing memory
 + * with host.
 + */
-+static int hv_mark_gpa_visibility(u16 count, const u64 pfn[],
-+			   enum hv_mem_host_visibility visibility)
++int hv_mark_gpa_visibility(u16 count, const u64 pfn[], u32 visibility)
 +{
 +	struct hv_gpa_range_for_visibility **input_pcpu, *input;
 +	u16 pages_processed;
@@ -131,11 +92,12 @@
 +			0, input, &pages_processed);
 +	local_irq_restore(flags);
 +
-+	if (hv_result_success(hv_status))
++	if (!(hv_status & HV_HYPERCALL_RESULT_MASK))
 +		return 0;
-+	else
-+		return -EFAULT;
++
++	return hv_status & HV_HYPERCALL_RESULT_MASK;
 +}
++EXPORT_SYMBOL(hv_mark_gpa_visibility);
 +
 +/*
 + * hv_set_mem_host_visibility - Set specified memory visible to host.
@@ -145,55 +107,71 @@
 + * with host. This function works as wrap of hv_mark_gpa_visibility()
 + * with memory base and size.
 + */
-+int hv_set_mem_host_visibility(unsigned long kbuffer, int pagecount, bool visible)
++int hv_set_mem_host_visibility(void *kbuffer, size_t size,
++			       enum vmbus_page_visibility visibility)
 +{
-+	enum hv_mem_host_visibility visibility = visible ?
-+			VMBUS_PAGE_VISIBLE_READ_WRITE : VMBUS_PAGE_NOT_VISIBLE;
++	int pagecount = size >> HV_HYP_PAGE_SHIFT;
 +	u64 *pfn_array;
 +	int ret = 0;
 +	int i, pfn;
 +
-+	if (!hv_is_isolation_supported() || !hv_hypercall_pg)
++	if (!hv_is_isolation_supported())
 +		return 0;
 +
-+	pfn_array = kmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL);
++	pfn_array = vzalloc(HV_HYP_PAGE_SIZE);
 +	if (!pfn_array)
 +		return -ENOMEM;
 +
 +	for (i = 0, pfn = 0; i < pagecount; i++) {
-+		pfn_array[pfn] = virt_to_hvpfn((void *)kbuffer + i * HV_HYP_PAGE_SIZE);
++		pfn_array[pfn] = virt_to_hvpfn(kbuffer + i * HV_HYP_PAGE_SIZE);
 +		pfn++;
 +
 +		if (pfn == HV_MAX_MODIFY_GPA_REP_COUNT || i == pagecount - 1) {
-+			ret = hv_mark_gpa_visibility(pfn, pfn_array,
-+						     visibility);
++			ret |= hv_mark_gpa_visibility(pfn, pfn_array, visibility);
++			pfn = 0;
++
 +			if (ret)
 +				goto err_free_pfn_array;
-+			pfn = 0;
 +		}
 +	}
 +
 + err_free_pfn_array:
-+	kfree(pfn_array);
++	vfree(pfn_array);
 +	return ret;
 +}
++EXPORT_SYMBOL_GPL(hv_set_mem_host_visibility);
++
 diff --git a/arch/x86/include/asm/hyperv-tlfs.h b/arch/x86/include/asm/hyperv-tlfs.h
-index 2322d6bd5883..381e88122a5f 100644
+index 606f5cc579b2..632281b91b44 100644
 --- a/arch/x86/include/asm/hyperv-tlfs.h
 +++ b/arch/x86/include/asm/hyperv-tlfs.h
-@@ -276,6 +276,23 @@ enum hv_isolation_type {
+@@ -262,6 +262,17 @@ enum hv_isolation_type {
  #define HV_X64_MSR_TIME_REF_COUNT	HV_REGISTER_TIME_REF_COUNT
  #define HV_X64_MSR_REFERENCE_TSC	HV_REGISTER_REFERENCE_TSC
  
-+/* Hyper-V memory host visibility */
-+enum hv_mem_host_visibility {
-+	VMBUS_PAGE_NOT_VISIBLE		= 0,
-+	VMBUS_PAGE_VISIBLE_READ_ONLY	= 1,
-+	VMBUS_PAGE_VISIBLE_READ_WRITE	= 3
++/* Hyper-V GPA map flags */
++#define HV_MAP_GPA_PERMISSIONS_NONE            0x0
++#define HV_MAP_GPA_READABLE                    0x1
++#define HV_MAP_GPA_WRITABLE                    0x2
++
++enum vmbus_page_visibility {
++	VMBUS_PAGE_NOT_VISIBLE = 0,
++	VMBUS_PAGE_VISIBLE_READ_ONLY = 1,
++	VMBUS_PAGE_VISIBLE_READ_WRITE = 3
 +};
 +
+ /*
+  * Declare the MSR used to setup pages used to communicate with the hypervisor.
+  */
+@@ -561,4 +572,17 @@ enum hv_interrupt_type {
+ 
+ #include <asm-generic/hyperv-tlfs.h>
+ 
++/* All input parameters should be in single page. */
++#define HV_MAX_MODIFY_GPA_REP_COUNT		\
++	((PAGE_SIZE / sizeof(u64)) - 2)
++
 +/* HvCallModifySparseGpaPageHostVisibility hypercall */
-+#define HV_MAX_MODIFY_GPA_REP_COUNT	((PAGE_SIZE / sizeof(u64)) - 2)
 +struct hv_gpa_range_for_visibility {
 +	u64 partition_id;
 +	u32 host_visibility:2;
@@ -202,24 +180,24 @@
 +	u64 gpa_page_list[HV_MAX_MODIFY_GPA_REP_COUNT];
 +} __packed;
 +
- /*
-  * Declare the MSR used to setup pages used to communicate with the hypervisor.
-  */
+ #endif
 diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
-index 37739a277ac6..ede440f9a1e2 100644
+index aeacca7c4da8..6af9d55ffe3b 100644
 --- a/arch/x86/include/asm/mshyperv.h
 +++ b/arch/x86/include/asm/mshyperv.h
-@@ -192,7 +192,7 @@ struct irq_domain *hv_create_pci_msi_domain(void);
+@@ -194,7 +194,9 @@ struct irq_domain *hv_create_pci_msi_domain(void);
  int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector,
  		struct hv_interrupt_entry *entry);
  int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry);
 -
-+int hv_set_mem_host_visibility(unsigned long addr, int numpages, bool visible);
++int hv_mark_gpa_visibility(u16 count, const u64 pfn[], u32 visibility);
++int hv_set_mem_host_visibility(void *kbuffer, size_t size,
++			       enum vmbus_page_visibility visibility);
  #else /* CONFIG_HYPERV */
  static inline void hyperv_init(void) {}
  static inline void hyperv_setup_mmu_ops(void) {}
 diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
-index ad8a5c586a35..1e4a0882820a 100644
+index 156cd235659f..a82975600107 100644
 --- a/arch/x86/mm/pat/set_memory.c
 +++ b/arch/x86/mm/pat/set_memory.c
 @@ -29,6 +29,8 @@
@@ -231,43 +209,115 @@
  
  #include "../mm_internal.h"
  
-@@ -1980,15 +1982,11 @@ int set_memory_global(unsigned long addr, int numpages)
- 				    __pgprot(_PAGE_GLOBAL), 0);
- }
- 
--static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
-+static int __set_memory_enc_pgtable(unsigned long addr, int numpages, bool enc)
- {
- 	struct cpa_data cpa;
+@@ -1986,8 +1988,14 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
  	int ret;
  
--	/* Nothing to do if memory encryption is not active */
+ 	/* Nothing to do if memory encryption is not active */
 -	if (!mem_encrypt_active())
--		return 0;
--
++	if (hv_is_isolation_supported()) {
++		return hv_set_mem_host_visibility((void *)addr,
++				numpages * HV_HYP_PAGE_SIZE,
++				enc ? VMBUS_PAGE_NOT_VISIBLE
++				: VMBUS_PAGE_VISIBLE_READ_WRITE);
++	} else if (!mem_encrypt_active()) {
+ 		return 0;
++	}
+ 
  	/* Should not be working on unaligned addresses */
  	if (WARN_ONCE(addr & ~PAGE_MASK, "misaligned address: %#lx\n", addr))
- 		addr &= PAGE_MASK;
-@@ -2023,6 +2021,17 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
+diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
+index f3761c73b074..01048bb07082 100644
+--- a/drivers/hv/channel.c
++++ b/drivers/hv/channel.c
+@@ -17,6 +17,7 @@
+ #include <linux/hyperv.h>
+ #include <linux/uio.h>
+ #include <linux/interrupt.h>
++#include <linux/set_memory.h>
+ #include <asm/page.h>
+ #include <asm/mshyperv.h>
+ 
+@@ -465,7 +466,7 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel,
+ 	struct list_head *curr;
+ 	u32 next_gpadl_handle;
+ 	unsigned long flags;
+-	int ret = 0;
++	int ret = 0, index;
+ 
+ 	next_gpadl_handle =
+ 		(atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1);
+@@ -474,6 +475,13 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel,
+ 	if (ret)
+ 		return ret;
+ 
++	ret = set_memory_decrypted((unsigned long)kbuffer,
++				   HVPFN_UP(size));
++	if (ret) {
++		pr_warn("Failed to set host visibility.\n");
++		return ret;
++	}
++
+ 	init_completion(&msginfo->waitevent);
+ 	msginfo->waiting_channel = channel;
+ 
+@@ -539,6 +547,15 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel,
+ 	/* At this point, we received the gpadl created msg */
+ 	*gpadl_handle = gpadlmsg->gpadl;
+ 
++	if (type == HV_GPADL_BUFFER)
++		index = 0;
++	else
++		index = channel->gpadl_range[1].gpadlhandle ? 2 : 1;
++
++	channel->gpadl_range[index].size = size;
++	channel->gpadl_range[index].buffer = kbuffer;
++	channel->gpadl_range[index].gpadlhandle = *gpadl_handle;
++
+ cleanup:
+ 	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+ 	list_del(&msginfo->msglistentry);
+@@ -549,6 +566,11 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel,
+ 	}
+ 
+ 	kfree(msginfo);
++
++	if (ret)
++		set_memory_encrypted((unsigned long)kbuffer,
++				     HVPFN_UP(size));
++
  	return ret;
  }
  
-+static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
-+{
-+	if (hv_is_isolation_supported())
-+		return hv_set_mem_host_visibility(addr, numpages, !enc);
-+
-+	if (mem_encrypt_active())
-+		return __set_memory_enc_pgtable(addr, numpages, enc);
-+
-+	return 0;
-+}
-+
- int set_memory_encrypted(unsigned long addr, int numpages)
- {
- 	return __set_memory_enc_dec(addr, numpages, true);
+@@ -811,7 +833,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
+ 	struct vmbus_channel_gpadl_teardown *msg;
+ 	struct vmbus_channel_msginfo *info;
+ 	unsigned long flags;
+-	int ret;
++	int ret, i;
+ 
+ 	info = kzalloc(sizeof(*info) +
+ 		       sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
+@@ -859,6 +881,18 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
+ 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+ 
+ 	kfree(info);
++
++	/* Find gpadl buffer virtual address and size. */
++	for (i = 0; i < VMBUS_GPADL_RANGE_COUNT; i++)
++		if (channel->gpadl_range[i].gpadlhandle == gpadl_handle)
++			break;
++
++	if (set_memory_encrypted((unsigned long)channel->gpadl_range[i].buffer,
++			HVPFN_UP(channel->gpadl_range[i].size)))
++		pr_warn("Fail to set mem host visibility.\n");
++
++	channel->gpadl_range[i].gpadlhandle = 0;
++
+ 	return ret;
+ }
+ EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl);
 diff --git a/include/asm-generic/hyperv-tlfs.h b/include/asm-generic/hyperv-tlfs.h
-index 56348a541c50..8ed6733d5146 100644
+index 515c3fb06ab3..8a0219255545 100644
 --- a/include/asm-generic/hyperv-tlfs.h
 +++ b/include/asm-generic/hyperv-tlfs.h
 @@ -158,6 +158,7 @@ struct ms_hyperv_tsc_page {
@@ -278,18 +328,34 @@
  
  /* Extended hypercalls */
  #define HV_EXT_CALL_QUERY_CAPABILITIES		0x8001
-diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h
-index e04efb87fee5..cb529c85c0ad 100644
---- a/include/asm-generic/mshyperv.h
-+++ b/include/asm-generic/mshyperv.h
-@@ -254,6 +254,7 @@ bool hv_query_ext_cap(u64 cap_query);
- static inline bool hv_is_hyperv_initialized(void) { return false; }
- static inline bool hv_is_hibernation_supported(void) { return false; }
- static inline void hyperv_cleanup(void) {}
-+static inline bool hv_is_isolation_supported(void) { return false; }
- #endif /* CONFIG_HYPERV */
- 
- #endif
+diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
+index 2e859d2f9609..06eccaba10c5 100644
+--- a/include/linux/hyperv.h
++++ b/include/linux/hyperv.h
+@@ -809,6 +809,14 @@ struct vmbus_device {
+ 
+ #define VMBUS_DEFAULT_MAX_PKT_SIZE 4096
+ 
++struct vmbus_gpadl_range {
++	u32 gpadlhandle;
++	u32 size;
++	void *buffer;
++};
++
++#define VMBUS_GPADL_RANGE_COUNT		3
++
+ struct vmbus_channel {
+ 	struct list_head listentry;
+ 
+@@ -829,6 +837,8 @@ struct vmbus_channel {
+ 	struct completion rescind_event;
+ 
+ 	u32 ringbuffer_gpadlhandle;
++	/* GPADL_RING and Send/Receive GPADL_BUFFER. */
++	struct vmbus_gpadl_range gpadl_range[VMBUS_GPADL_RANGE_COUNT];
+ 
+ 	/* Allocated memory for ring buffer */
+ 	struct page *ringbuffer_page;
 -- 
 2.25.1
 
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help