[RFC PATCH part-7 09/12] pkvm: x86: Implement do_share() helper for sharing memory

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Shaoqin Huang <shaoqin.huang@xxxxxxxxx>

One component sharing a memory region with another can be achieved using
a "share" operation, which results in the page state of sharer become
from PAGE_OWNED to PAGE_SHARED_OWNED, and the page state of being
shared become from NOPAGE to PAGE_SHARED_BORROWED. The two components now
can access the page both.

Introduce a do_share() helper for safely sharing a memory region from
one component to another. Currently, only host_to_guest sharing is
implemented, but the code is easily extended to handle other
combinations and the permission checks for each component are reusable.

Signed-off-by: Shaoqin Huang <shaoqin.huang@xxxxxxxxx>
---
 arch/x86/kvm/vmx/pkvm/hyp/mem_protect.c | 155 ++++++++++++++++++++++++
 arch/x86/kvm/vmx/pkvm/hyp/mem_protect.h |  18 +++
 2 files changed, 173 insertions(+)

diff --git a/arch/x86/kvm/vmx/pkvm/hyp/mem_protect.c b/arch/x86/kvm/vmx/pkvm/hyp/mem_protect.c
index fad81f91794c..987fe172f6a6 100644
--- a/arch/x86/kvm/vmx/pkvm/hyp/mem_protect.c
+++ b/arch/x86/kvm/vmx/pkvm/hyp/mem_protect.c
@@ -17,6 +17,7 @@ struct check_walk_data {
 enum pkvm_component_id {
 	PKVM_ID_HYP,
 	PKVM_ID_HOST,
+	PKVM_ID_GUEST,
 };
 
 struct pkvm_mem_trans_desc {
@@ -29,6 +30,12 @@ struct pkvm_mem_trans_desc {
 		struct {
 			u64	addr;
 		} hyp;
+
+		struct {
+			struct pkvm_pgtable	*pgt;
+			u64			addr;
+			u64			phys;
+		} guest;
 	};
 	u64			prot;
 };
@@ -118,6 +125,13 @@ static pkvm_id completer_owner_id(const struct pkvm_mem_transition *tx)
 	return __pkvm_owner_id(&tx->completer);
 }
 
+static int __guest_check_page_state_range(struct pkvm_pgtable *pgt,
+					  u64 addr, u64 size,
+					  enum pkvm_page_state state)
+{
+	return check_page_state_range(pgt, addr, size, state);
+}
+
 static int host_request_donation(const struct pkvm_mem_transition *tx)
 {
 	u64 addr = tx->initiator.host.addr;
@@ -298,3 +312,144 @@ int __pkvm_hyp_donate_host(u64 hpa, u64 size)
 
 	return ret;
 }
+
+static int host_request_share(const struct pkvm_mem_transition *tx)
+{
+	u64 addr = tx->initiator.host.addr;
+	u64 size = tx->size;
+
+	return __host_check_page_state_range(addr, size, PKVM_PAGE_OWNED);
+}
+
+static int guest_ack_share(const struct pkvm_mem_transition *tx)
+{
+	u64 addr = tx->completer.guest.addr;
+	u64 size = tx->size;
+
+	return __guest_check_page_state_range(tx->completer.guest.pgt, addr,
+					      size, PKVM_NOPAGE);
+}
+
+static int check_share(const struct pkvm_mem_transition *tx)
+{
+	int ret;
+
+	switch (tx->initiator.id) {
+	case PKVM_ID_HOST:
+		ret = host_request_share(tx);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret)
+		return ret;
+
+	switch (tx->completer.id) {
+	case PKVM_ID_GUEST:
+		ret = guest_ack_share(tx);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int host_initiate_share(const struct pkvm_mem_transition *tx)
+{
+	u64 addr = tx->initiator.host.addr;
+	u64 size = tx->size;
+	u64 prot = pkvm_mkstate(tx->initiator.prot, PKVM_PAGE_SHARED_OWNED);
+
+	return host_ept_create_idmap_locked(addr, size, 0, prot);
+}
+
+static int guest_complete_share(const struct pkvm_mem_transition *tx)
+{
+	struct pkvm_pgtable *pgt = tx->completer.guest.pgt;
+	u64 addr = tx->completer.guest.addr;
+	u64 size = tx->size;
+	u64 phys = tx->completer.guest.phys;
+	u64 prot = tx->completer.prot;
+
+	prot = pkvm_mkstate(prot, PKVM_PAGE_SHARED_BORROWED);
+	return pkvm_pgtable_map(pgt, addr, phys, size, 0, prot);
+}
+
+static int __do_share(const struct pkvm_mem_transition *tx)
+{
+	int ret;
+
+	switch (tx->initiator.id) {
+	case PKVM_ID_HOST:
+		ret = host_initiate_share(tx);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret)
+		return ret;
+
+	switch (tx->completer.id) {
+	case PKVM_ID_GUEST:
+		ret = guest_complete_share(tx);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/*
+ * do_share() - The page owner grants access to another component with a given
+ * set of permissions.
+ *
+ * Initiator: OWNED	=> SHARED_OWNED
+ * Completer: NOPAGE	=> SHARED_BORROWED
+ */
+static int do_share(const struct pkvm_mem_transition *share)
+{
+	int ret;
+
+	ret = check_share(share);
+	if (ret)
+		return ret;
+
+	return WARN_ON(__do_share(share));
+}
+
+int __pkvm_host_share_guest(u64 hpa, struct pkvm_pgtable *guest_pgt,
+			    u64 gpa, u64 size, u64 prot)
+{
+	int ret;
+	struct pkvm_mem_transition share = {
+		.size		= size,
+		.initiator	= {
+			.id	= PKVM_ID_HOST,
+			.host	= {
+				.addr	= hpa,
+			},
+			.prot	= HOST_EPT_DEF_MEM_PROT,
+		},
+		.completer	= {
+			.id	= PKVM_ID_GUEST,
+			.guest	= {
+				.pgt	= guest_pgt,
+				.addr	= gpa,
+				.phys	= hpa,
+			},
+			.prot	= prot,
+		},
+	};
+
+	host_ept_lock();
+
+	ret = do_share(&share);
+
+	host_ept_unlock();
+
+	return ret;
+}
diff --git a/arch/x86/kvm/vmx/pkvm/hyp/mem_protect.h b/arch/x86/kvm/vmx/pkvm/hyp/mem_protect.h
index efb3b3895f58..549cc5246620 100644
--- a/arch/x86/kvm/vmx/pkvm/hyp/mem_protect.h
+++ b/arch/x86/kvm/vmx/pkvm/hyp/mem_protect.h
@@ -82,4 +82,22 @@ int __pkvm_host_donate_hyp(u64 hpa, u64 size);
  */
 int __pkvm_hyp_donate_host(u64 hpa, u64 size);
 
+/*
+ * __pkvm_host_share_guest() - Share pages between host and guest. Host still
+ * ownes the page and guest will have temporary access to these pages.
+ *
+ * @hpa:	Start hpa of being shared pages, must be continuous.
+ * @guest_pgt:	The guest ept pagetable.
+ * @gpa:	Start gpa that will be used for mapping into the guest ept.
+ * @size:	The size of pages to be shared.
+ * @prot:	The prot that will be used for creating mapping for guest ept.
+ *
+ * A range of pages [hpa, hpa + size) in host ept that their page state
+ * will be modified from PAGE_OWNED to PAGE_SHARED_OWNED. There will be
+ * mapping from gfn to pfn to be created in guest ept. The @prot
+ * and PAGE_SHARED_BORROWED will be used to create such mapping.
+ */
+int __pkvm_host_share_guest(u64 hpa, struct pkvm_pgtable *guest_pgt,
+			    u64 gpa, u64 size, u64 prot);
+
 #endif
-- 
2.25.1




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux