--- vrfc
+++ v4
@@ -1,88 +1,62 @@
From: Tianyu Lan <Tianyu.Lan@microsoft.com>
-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.
-
-Signed-off-by: Sunil Muthuswamy <sunilmut@microsoft.com>
-Co-Developed-by: Sunil Muthuswamy <sunilmut@microsoft.com>
+Add new hvcall guest address host visibility support to mark
+memory visible to host. Call it inside set_memory_decrypted
+/encrypted().
+
Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
---
- arch/x86/include/asm/hyperv-tlfs.h | 13 ++++++++
- arch/x86/include/asm/mshyperv.h | 4 +--
- arch/x86/kernel/cpu/mshyperv.c | 46 ++++++++++++++++++++++++++
- drivers/hv/channel.c | 53 ++++++++++++++++++++++++++++--
- drivers/net/hyperv/hyperv_net.h | 1 +
- drivers/net/hyperv/netvsc.c | 9 +++--
- drivers/uio/uio_hv_generic.c | 6 ++--
- include/asm-generic/hyperv-tlfs.h | 1 +
- include/linux/hyperv.h | 3 +-
- 9 files changed, 126 insertions(+), 10 deletions(-)
-
-diff --git a/arch/x86/include/asm/hyperv-tlfs.h b/arch/x86/include/asm/hyperv-tlfs.h
-index fb1893a4c32b..d22b1c3f425a 100644
---- a/arch/x86/include/asm/hyperv-tlfs.h
-+++ b/arch/x86/include/asm/hyperv-tlfs.h
-@@ -573,4 +573,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 - 2 * sizeof(u64)) / (sizeof(u64)))
-+
-+/* HvCallModifySparseGpaPageHostVisibility hypercall */
-+struct hv_input_modify_sparse_gpa_page_host_visibility {
-+ u64 partition_id;
-+ u32 host_visibility:2;
-+ u32 reserved0:30;
-+ u32 reserved1;
-+ u64 gpa_page_list[HV_MAX_MODIFY_GPA_REP_COUNT];
-+} __packed;
-+
- #endif
-diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
-index ccf60a809a17..1e8275d35c1f 100644
---- a/arch/x86/include/asm/mshyperv.h
-+++ b/arch/x86/include/asm/mshyperv.h
-@@ -262,13 +262,13 @@ static inline void hv_set_msi_entry_from_desc(union hv_msi_entry *msi_entry,
- msi_entry->address.as_uint32 = msi_desc->msg.address_lo;
- msi_entry->data.as_uint32 = msi_desc->msg.data;
- }
--
- 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(void *kbuffer, u32 size, u32 visibility);
-+int hv_mark_gpa_visibility(u16 count, const u64 pfn[], u32 visibility);
- #else /* CONFIG_HYPERV */
- static inline void hyperv_init(void) {}
- static inline void hyperv_setup_mmu_ops(void) {}
-diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
-index e88bc296afca..347c32eac8fd 100644
---- a/arch/x86/kernel/cpu/mshyperv.c
-+++ b/arch/x86/kernel/cpu/mshyperv.c
-@@ -37,6 +37,8 @@
- bool hv_root_partition;
- EXPORT_SYMBOL_GPL(hv_root_partition);
-
-+#define HV_PARTITION_ID_SELF ((u64)-1)
-+
- struct ms_hyperv_info ms_hyperv;
- EXPORT_SYMBOL_GPL(ms_hyperv);
-
-@@ -477,3 +479,47 @@ const __initconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
- .init.msi_ext_dest_id = ms_hyperv_msi_ext_dest_id,
- .init.init_platform = ms_hyperv_init_platform,
- };
-+
+ arch/x86/hyperv/Makefile | 2 +-
+ arch/x86/hyperv/ivm.c | 112 +++++++++++++++++++++++++++++
+ arch/x86/include/asm/hyperv-tlfs.h | 18 +++++
+ arch/x86/include/asm/mshyperv.h | 3 +-
+ arch/x86/mm/pat/set_memory.c | 6 +-
+ include/asm-generic/hyperv-tlfs.h | 1 +
+ 6 files changed, 139 insertions(+), 3 deletions(-)
+ create mode 100644 arch/x86/hyperv/ivm.c
+
+diff --git a/arch/x86/hyperv/Makefile b/arch/x86/hyperv/Makefile
+index 48e2c51464e8..5d2de10809ae 100644
+--- a/arch/x86/hyperv/Makefile
++++ b/arch/x86/hyperv/Makefile
+@@ -1,5 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+-obj-y := hv_init.o mmu.o nested.o irqdomain.o
++obj-y := hv_init.o mmu.o nested.o irqdomain.o ivm.o
+ obj-$(CONFIG_X86_64) += hv_apic.o hv_proc.o
+
+ ifdef CONFIG_X86_64
+diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c
+new file mode 100644
+index 000000000000..24a58795abd8
+--- /dev/null
++++ b/arch/x86/hyperv/ivm.c
+@@ -0,0 +1,112 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Hyper-V Isolation VM interface with paravisor and hypervisor
++ *
++ * Author:
++ * Tianyu Lan <Tianyu.Lan@microsoft.com>
++ */
++
++#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 encripted from host and guest
++ * needs to set memory visible to host via hvcall before sharing memory
++ * with host.
++ */
+int hv_mark_gpa_visibility(u16 count, const u64 pfn[], u32 visibility)
+{
-+ struct hv_input_modify_sparse_gpa_page_host_visibility **input_pcpu;
-+ struct hv_input_modify_sparse_gpa_page_host_visibility *input;
++ struct hv_gpa_range_for_visibility **input_pcpu, *input;
+ u16 pages_processed;
+ u64 hv_status;
+ unsigned long flags;
@@ -98,12 +72,12 @@
+ }
+
+ local_irq_save(flags);
-+ input_pcpu = (struct hv_input_modify_sparse_gpa_page_host_visibility **)
++ input_pcpu = (struct hv_gpa_range_for_visibility **)
+ this_cpu_ptr(hyperv_pcpu_input_arg);
+ input = *input_pcpu;
+ if (unlikely(!input)) {
+ local_irq_restore(flags);
-+ return -1;
++ return -EINVAL;
+ }
+
+ input->partition_id = HV_PARTITION_ID_SELF;
@@ -119,31 +93,29 @@
+ if (!(hv_status & HV_HYPERCALL_RESULT_MASK))
+ return 0;
+
-+ return -EFAULT;
++ return hv_status & HV_HYPERCALL_RESULT_MASK;
+}
+EXPORT_SYMBOL(hv_mark_gpa_visibility);
-diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
-index daa21cc72beb..204e6f3598a5 100644
---- a/drivers/hv/channel.c
-+++ b/drivers/hv/channel.c
-@@ -237,6 +237,38 @@ int vmbus_send_modifychannel(u32 child_relid, u32 target_vp)
- }
- EXPORT_SYMBOL_GPL(vmbus_send_modifychannel);
-
++
+/*
-+ * hv_set_mem_host_visibility - Set host visibility for specified memory.
++ * hv_set_mem_host_visibility - Set specified memory visible to host.
++ *
++ * In Isolation VM, all guest memory is encrypted from host and guest
++ * needs to set memory visible to host via hvcall before sharing memory
++ * with host. This function works as wrap of hv_mark_gpa_visibility()
++ * with memory base and size.
+ */
-+int hv_set_mem_host_visibility(void *kbuffer, u32 size, u32 visibility)
++static int hv_set_mem_host_visibility(void *kbuffer, size_t size, u32 visibility)
+{
-+ int i, pfn;
+ int pagecount = size >> HV_HYP_PAGE_SHIFT;
+ u64 *pfn_array;
+ int ret = 0;
-+
-+ if (!hv_isolation_type_snp())
++ int i, pfn;
++
++ if (!hv_is_isolation_supported() || !ms_hyperv.ghcb_base)
+ return 0;
+
-+ pfn_array = vzalloc(HV_HYP_PAGE_SIZE);
++ pfn_array = kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL);
+ if (!pfn_array)
+ return -ENOMEM;
+
@@ -154,143 +126,98 @@
+ if (pfn == HV_MAX_MODIFY_GPA_REP_COUNT || i == pagecount - 1) {
+ ret |= hv_mark_gpa_visibility(pfn, pfn_array, visibility);
+ pfn = 0;
++
++ if (ret)
++ goto err_free_pfn_array;
+ }
+ }
+
-+ vfree(pfn_array);
++ err_free_pfn_array:
++ kfree(pfn_array);
+ return ret;
+}
-+EXPORT_SYMBOL_GPL(hv_set_mem_host_visibility);
++
++int hv_set_mem_enc(unsigned long addr, int numpages, bool enc)
++{
++ return hv_set_mem_host_visibility((void *)addr,
++ numpages * HV_HYP_PAGE_SIZE,
++ enc ? VMBUS_PAGE_NOT_VISIBLE
++ : VMBUS_PAGE_VISIBLE_READ_WRITE);
++}
+diff --git a/arch/x86/include/asm/hyperv-tlfs.h b/arch/x86/include/asm/hyperv-tlfs.h
+index 606f5cc579b2..68826fbf92ca 100644
+--- a/arch/x86/include/asm/hyperv-tlfs.h
++++ b/arch/x86/include/asm/hyperv-tlfs.h
+@@ -262,6 +262,11 @@ 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 GPA map flags */
++#define VMBUS_PAGE_NOT_VISIBLE 0
++#define VMBUS_PAGE_VISIBLE_READ_ONLY 1
++#define VMBUS_PAGE_VISIBLE_READ_WRITE 3
+
/*
- * create_gpadl_header - Creates a gpadl for the specified buffer
+ * Declare the MSR used to setup pages used to communicate with the hypervisor.
*/
-@@ -410,6 +442,12 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel,
- if (ret)
- return ret;
-
-+ ret = hv_set_mem_host_visibility(kbuffer, size, visibility);
-+ if (ret) {
-+ pr_warn("Failed to set host visibility.\n");
-+ return ret;
-+ }
-+
- init_completion(&msginfo->waitevent);
- msginfo->waiting_channel = channel;
-
-@@ -693,7 +731,9 @@ static int __vmbus_open(struct vmbus_channel *newchannel,
- error_free_info:
- kfree(open_info);
- error_free_gpadl:
-- vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle);
-+ vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle,
-+ page_address(newchannel->ringbuffer_page),
-+ newchannel->ringbuffer_pagecount << PAGE_SHIFT);
- newchannel->ringbuffer_gpadlhandle = 0;
- error_clean_ring:
- hv_ringbuffer_cleanup(&newchannel->outbound);
-@@ -740,7 +780,8 @@ EXPORT_SYMBOL_GPL(vmbus_open);
- /*
- * vmbus_teardown_gpadl -Teardown the specified GPADL handle
- */
--int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
-+int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle,
-+ void *kbuffer, u32 size)
- {
- struct vmbus_channel_gpadl_teardown *msg;
- struct vmbus_channel_msginfo *info;
-@@ -793,6 +834,10 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
- spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
-
- kfree(info);
-+
-+ if (hv_set_mem_host_visibility(kbuffer, size, VMBUS_PAGE_NOT_VISIBLE))
-+ pr_warn("Fail to set mem host visibility.\n");
-+
- return ret;
- }
- EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl);
-@@ -869,7 +914,9 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
- /* Tear down the gpadl for the channel's ring buffer */
- else if (channel->ringbuffer_gpadlhandle) {
- ret = vmbus_teardown_gpadl(channel,
-- channel->ringbuffer_gpadlhandle);
-+ channel->ringbuffer_gpadlhandle,
-+ page_address(channel->ringbuffer_page),
-+ channel->ringbuffer_pagecount << PAGE_SHIFT);
- if (ret) {
- pr_err("Close failed: teardown gpadl return %d\n", ret);
- /*
-diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
-index 2a87cfa27ac0..b3a43c4ec8ab 100644
---- a/drivers/net/hyperv/hyperv_net.h
-+++ b/drivers/net/hyperv/hyperv_net.h
-@@ -1034,6 +1034,7 @@ struct netvsc_device {
-
- /* Send buffer allocated by us */
- void *send_buf;
-+ u32 send_buf_size;
- u32 send_buf_gpadl_handle;
- u32 send_section_cnt;
- u32 send_section_size;
-diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
-index bb72c7578330..08d73401bb28 100644
---- a/drivers/net/hyperv/netvsc.c
-+++ b/drivers/net/hyperv/netvsc.c
-@@ -245,7 +245,9 @@ static void netvsc_teardown_recv_gpadl(struct hv_device *device,
-
- if (net_device->recv_buf_gpadl_handle) {
- ret = vmbus_teardown_gpadl(device->channel,
-- net_device->recv_buf_gpadl_handle);
-+ net_device->recv_buf_gpadl_handle,
-+ net_device->recv_buf,
-+ net_device->recv_buf_size);
-
- /* If we failed here, we might as well return and have a leak
- * rather than continue and a bugchk
-@@ -267,7 +269,9 @@ static void netvsc_teardown_send_gpadl(struct hv_device *device,
-
- if (net_device->send_buf_gpadl_handle) {
- ret = vmbus_teardown_gpadl(device->channel,
-- net_device->send_buf_gpadl_handle);
-+ net_device->send_buf_gpadl_handle,
-+ net_device->send_buf,
-+ net_device->send_buf_size);
-
- /* If we failed here, we might as well return and have a leak
- * rather than continue and a bugchk
-@@ -419,6 +423,7 @@ static int netvsc_init_buf(struct hv_device *device,
- ret = -ENOMEM;
- goto cleanup;
- }
-+ net_device->send_buf_size = buf_size;
-
- /* Establish the gpadl handle for this buffer on this
- * channel. Note: This call uses the vmbus connection rather
-diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
-index 813a7bee5139..c8d4704fc90c 100644
---- a/drivers/uio/uio_hv_generic.c
-+++ b/drivers/uio/uio_hv_generic.c
-@@ -181,13 +181,15 @@ static void
- hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata)
- {
- if (pdata->send_gpadl) {
-- vmbus_teardown_gpadl(dev->channel, pdata->send_gpadl);
-+ vmbus_teardown_gpadl(dev->channel, pdata->send_gpadl,
-+ pdata->send_buf, SEND_BUFFER_SIZE);
- pdata->send_gpadl = 0;
- vfree(pdata->send_buf);
- }
-
- if (pdata->recv_gpadl) {
-- vmbus_teardown_gpadl(dev->channel, pdata->recv_gpadl);
-+ vmbus_teardown_gpadl(dev->channel, pdata->recv_gpadl,
-+ pdata->recv_buf, RECV_BUFFER_SIZE);
- pdata->recv_gpadl = 0;
- vfree(pdata->recv_buf);
- }
+@@ -561,4 +566,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 */
++struct hv_gpa_range_for_visibility {
++ u64 partition_id;
++ u32 host_visibility:2;
++ u32 reserved0:30;
++ u32 reserved1;
++ u64 gpa_page_list[HV_MAX_MODIFY_GPA_REP_COUNT];
++} __packed;
++
+ #endif
+diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
+index aeacca7c4da8..2172493dc881 100644
+--- a/arch/x86/include/asm/mshyperv.h
++++ b/arch/x86/include/asm/mshyperv.h
+@@ -194,7 +194,8 @@ 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_mark_gpa_visibility(u16 count, const u64 pfn[], u32 visibility);
++int hv_set_mem_enc(unsigned long addr, int numpages, bool enc);
+ #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 156cd235659f..6cc83c57383d 100644
+--- a/arch/x86/mm/pat/set_memory.c
++++ b/arch/x86/mm/pat/set_memory.c
+@@ -29,6 +29,8 @@
+ #include <asm/proto.h>
+ #include <asm/memtype.h>
+ #include <asm/set_memory.h>
++#include <asm/hyperv-tlfs.h>
++#include <asm/mshyperv.h>
+
+ #include "../mm_internal.h"
+
+@@ -1986,7 +1988,9 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
+ int ret;
+
+ /* Nothing to do if memory encryption is not active */
+- if (!mem_encrypt_active())
++ if (hv_is_isolation_supported())
++ return hv_set_mem_enc(addr, numpages, enc);
++ else if (!mem_encrypt_active())
+ return 0;
+
+ /* Should not be working on unaligned addresses */
diff --git a/include/asm-generic/hyperv-tlfs.h b/include/asm-generic/hyperv-tlfs.h
-index 83448e837ded..ad19f4199f90 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 {
@@ -299,22 +226,8 @@
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0
+#define HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY 0x00db
- #define HV_FLUSH_ALL_PROCESSORS BIT(0)
- #define HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES BIT(1)
-diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
-index 016fdca20d6e..41cbaa2db567 100644
---- a/include/linux/hyperv.h
-+++ b/include/linux/hyperv.h
-@@ -1183,7 +1183,8 @@ extern int vmbus_establish_gpadl(struct vmbus_channel *channel,
- u32 visibility);
-
- extern int vmbus_teardown_gpadl(struct vmbus_channel *channel,
-- u32 gpadl_handle);
-+ u32 gpadl_handle,
-+ void *kbuffer, u32 size);
-
- void vmbus_reset_channel_cb(struct vmbus_channel *channel);
-
+ /* Extended hypercalls */
+ #define HV_EXT_CALL_QUERY_CAPABILITIES 0x8001
--
2.25.1