diff mbox series

[4/6] drivers/virt: pkvm: Hook up mem_encrypt API using pKVM hypercalls

Message ID 20240730151113.1497-5-will@kernel.org (mailing list archive)
State New, archived
Headers show
Series Support for running as a pKVM protected guest | expand

Commit Message

Will Deacon July 30, 2024, 3:11 p.m. UTC
If we detect the presence of pKVM's SHARE and UNSHARE hypercalls, then
register a backend implementation of the mem_encrypt API so that things
like DMA buffers can be shared appropriately with the host.

Signed-off-by: Will Deacon <will@kernel.org>
---
 Documentation/virt/kvm/arm/hypercalls.rst     | 50 +++++++++++++++++
 drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 55 +++++++++++++++++++
 include/linux/arm-smccc.h                     | 14 +++++
 3 files changed, 119 insertions(+)

Comments

Marc Zyngier Aug. 21, 2024, 4:49 p.m. UTC | #1
On Tue, 30 Jul 2024 16:11:10 +0100,
Will Deacon <will@kernel.org> wrote:
> 
> If we detect the presence of pKVM's SHARE and UNSHARE hypercalls, then
> register a backend implementation of the mem_encrypt API so that things
> like DMA buffers can be shared appropriately with the host.
> 
> Signed-off-by: Will Deacon <will@kernel.org>
> ---
>  Documentation/virt/kvm/arm/hypercalls.rst     | 50 +++++++++++++++++
>  drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 55 +++++++++++++++++++
>  include/linux/arm-smccc.h                     | 14 +++++
>  3 files changed, 119 insertions(+)
> 

[...]

> diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
> index 16b6dcc54e02..9cb7c95920b0 100644
> --- a/include/linux/arm-smccc.h
> +++ b/include/linux/arm-smccc.h
> @@ -116,6 +116,8 @@
>  #define ARM_SMCCC_KVM_FUNC_FEATURES		0
>  #define ARM_SMCCC_KVM_FUNC_PTP			1
>  #define ARM_SMCCC_KVM_FUNC_HYP_MEMINFO		2
> +#define ARM_SMCCC_KVM_FUNC_MEM_SHARE		3
> +#define ARM_SMCCC_KVM_FUNC_MEM_UNSHARE		4
>  #define ARM_SMCCC_KVM_FUNC_FEATURES_2		127
>  #define ARM_SMCCC_KVM_NUM_FUNCS			128

As you will certainly add a bunch of other calls (hopefully soon-ish),
how about reserving an actual range for those, so that we can
future-proof the ABI early?

Grab 64 right away, and we don't have to worry about new stuff for a
while.

What do you think?

	M.
Will Deacon Aug. 23, 2024, 3:41 p.m. UTC | #2
Hi Marc,

On Wed, Aug 21, 2024 at 05:49:45PM +0100, Marc Zyngier wrote:
> On Tue, 30 Jul 2024 16:11:10 +0100,
> Will Deacon <will@kernel.org> wrote:
> > 
> > If we detect the presence of pKVM's SHARE and UNSHARE hypercalls, then
> > register a backend implementation of the mem_encrypt API so that things
> > like DMA buffers can be shared appropriately with the host.
> > 
> > Signed-off-by: Will Deacon <will@kernel.org>
> > ---
> >  Documentation/virt/kvm/arm/hypercalls.rst     | 50 +++++++++++++++++
> >  drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 55 +++++++++++++++++++
> >  include/linux/arm-smccc.h                     | 14 +++++
> >  3 files changed, 119 insertions(+)
> > 
> 
> [...]
> 
> > diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
> > index 16b6dcc54e02..9cb7c95920b0 100644
> > --- a/include/linux/arm-smccc.h
> > +++ b/include/linux/arm-smccc.h
> > @@ -116,6 +116,8 @@
> >  #define ARM_SMCCC_KVM_FUNC_FEATURES		0
> >  #define ARM_SMCCC_KVM_FUNC_PTP			1
> >  #define ARM_SMCCC_KVM_FUNC_HYP_MEMINFO		2
> > +#define ARM_SMCCC_KVM_FUNC_MEM_SHARE		3
> > +#define ARM_SMCCC_KVM_FUNC_MEM_UNSHARE		4
> >  #define ARM_SMCCC_KVM_FUNC_FEATURES_2		127
> >  #define ARM_SMCCC_KVM_NUM_FUNCS			128
> 
> As you will certainly add a bunch of other calls (hopefully soon-ish),
> how about reserving an actual range for those, so that we can
> future-proof the ABI early?
> 
> Grab 64 right away, and we don't have to worry about new stuff for a
> while.
> 
> What do you think?

I think that's incredibly generous. Let's see whether we really need
that to start with...

/me dives into android15-6.6

So we currently allocate 3-11 there and some of those are because we
messed up v1 of a hypercall and had to introduce a new one. I don't plan
to inflict that on upstream, but avoiding conflicts would be good.

The big thing on the horizon is a hypercall-based IOMMU interface which
looks like it will need ~10 new calls. I suppose we could multiplex some
of that, but otherwise 32 would probably do us if you don't want to give
up such a big chunk of the space immediately.

Will
Marc Zyngier Aug. 23, 2024, 4:53 p.m. UTC | #3
On Fri, 23 Aug 2024 16:41:55 +0100,
Will Deacon <will@kernel.org> wrote:
> 
> Hi Marc,
> 
> On Wed, Aug 21, 2024 at 05:49:45PM +0100, Marc Zyngier wrote:
> > On Tue, 30 Jul 2024 16:11:10 +0100,
> > Will Deacon <will@kernel.org> wrote:
> > > 
> > > If we detect the presence of pKVM's SHARE and UNSHARE hypercalls, then
> > > register a backend implementation of the mem_encrypt API so that things
> > > like DMA buffers can be shared appropriately with the host.
> > > 
> > > Signed-off-by: Will Deacon <will@kernel.org>
> > > ---
> > >  Documentation/virt/kvm/arm/hypercalls.rst     | 50 +++++++++++++++++
> > >  drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 55 +++++++++++++++++++
> > >  include/linux/arm-smccc.h                     | 14 +++++
> > >  3 files changed, 119 insertions(+)
> > > 
> > 
> > [...]
> > 
> > > diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
> > > index 16b6dcc54e02..9cb7c95920b0 100644
> > > --- a/include/linux/arm-smccc.h
> > > +++ b/include/linux/arm-smccc.h
> > > @@ -116,6 +116,8 @@
> > >  #define ARM_SMCCC_KVM_FUNC_FEATURES		0
> > >  #define ARM_SMCCC_KVM_FUNC_PTP			1
> > >  #define ARM_SMCCC_KVM_FUNC_HYP_MEMINFO		2
> > > +#define ARM_SMCCC_KVM_FUNC_MEM_SHARE		3
> > > +#define ARM_SMCCC_KVM_FUNC_MEM_UNSHARE		4
> > >  #define ARM_SMCCC_KVM_FUNC_FEATURES_2		127
> > >  #define ARM_SMCCC_KVM_NUM_FUNCS			128
> > 
> > As you will certainly add a bunch of other calls (hopefully soon-ish),
> > how about reserving an actual range for those, so that we can
> > future-proof the ABI early?
> > 
> > Grab 64 right away, and we don't have to worry about new stuff for a
> > while.
> > 
> > What do you think?
> 
> I think that's incredibly generous. Let's see whether we really need
> that to start with...
> 
> /me dives into android15-6.6
> 
> So we currently allocate 3-11 there and some of those are because we
> messed up v1 of a hypercall and had to introduce a new one. I don't plan
> to inflict that on upstream, but avoiding conflicts would be good.
> 
> The big thing on the horizon is a hypercall-based IOMMU interface which
> looks like it will need ~10 new calls. I suppose we could multiplex some
> of that, but otherwise 32 would probably do us if you don't want to give
> up such a big chunk of the space immediately.

Honestly, whatever number of bits you have in mind, just double it and
run with it. We don't need to be precious about those, specially given
that bog-standard KVM is unlikely to grow any new PV hypercall (PTP
was enough of a disaster to cure me from that disease).

Thanks,

	M.
diff mbox series

Patch

diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst
index 16515eb42149..c42580e71bf8 100644
--- a/Documentation/virt/kvm/arm/hypercalls.rst
+++ b/Documentation/virt/kvm/arm/hypercalls.rst
@@ -66,3 +66,53 @@  Query the memory protection parameters for a pKVM protected virtual machine.
 | Return Values:      | (int64)  | R0 | ``INVALID_PARAMETER (-3)`` on error, else   |
 |                     |          |    | memory protection granule in bytes          |
 +---------------------+----------+----+---------------------------------------------+
+
+``ARM_SMCCC_KVM_FUNC_MEM_SHARE``
+--------------------------------
+
+Share a region of memory with the KVM host, granting it read, write and execute
+permissions. The size of the region is equal to the memory protection granule
+advertised by ``ARM_SMCCC_KVM_FUNC_HYP_MEMINFO``.
+
++---------------------+-------------------------------------------------------------+
+| Presence:           | Optional; pKVM protected guests only.                       |
++---------------------+-------------------------------------------------------------+
+| Calling convention: | HVC64                                                       |
++---------------------+----------+--------------------------------------------------+
+| Function ID:        | (uint32) | 0xC6000003                                       |
++---------------------+----------+----+---------------------------------------------+
+| Arguments:          | (uint64) | R1 | Base IPA of memory region to share          |
+|                     +----------+----+---------------------------------------------+
+|                     | (uint64) | R2 | Reserved / Must be zero                     |
+|                     +----------+----+---------------------------------------------+
+|                     | (uint64) | R3 | Reserved / Must be zero                     |
++---------------------+----------+----+---------------------------------------------+
+| Return Values:      | (int64)  | R0 | ``SUCCESS (0)``                             |
+|                     |          |    +---------------------------------------------+
+|                     |          |    | ``INVALID_PARAMETER (-3)``                  |
++---------------------+----------+----+---------------------------------------------+
+
+``ARM_SMCCC_KVM_FUNC_MEM_UNSHARE``
+----------------------------------
+
+Revoke access permission from the KVM host to a memory region previously shared
+with ``ARM_SMCCC_KVM_FUNC_MEM_SHARE``. The size of the region is equal to the
+memory protection granule advertised by ``ARM_SMCCC_KVM_FUNC_HYP_MEMINFO``.
+
++---------------------+-------------------------------------------------------------+
+| Presence:           | Optional; pKVM protected guests only.                       |
++---------------------+-------------------------------------------------------------+
+| Calling convention: | HVC64                                                       |
++---------------------+----------+--------------------------------------------------+
+| Function ID:        | (uint32) | 0xC6000004                                       |
++---------------------+----------+----+---------------------------------------------+
+| Arguments:          | (uint64) | R1 | Base IPA of memory region to unshare        |
+|                     +----------+----+---------------------------------------------+
+|                     | (uint64) | R2 | Reserved / Must be zero                     |
+|                     +----------+----+---------------------------------------------+
+|                     | (uint64) | R3 | Reserved / Must be zero                     |
++---------------------+----------+----+---------------------------------------------+
+| Return Values:      | (int64)  | R0 | ``SUCCESS (0)``                             |
+|                     |          |    +---------------------------------------------+
+|                     |          |    | ``INVALID_PARAMETER (-3)``                  |
++---------------------+----------+----+---------------------------------------------+
diff --git a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
index a5148701d2f1..8256cf68fd76 100644
--- a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
+++ b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
@@ -9,18 +9,72 @@ 
 
 #include <linux/arm-smccc.h>
 #include <linux/array_size.h>
+#include <linux/mem_encrypt.h>
 #include <linux/mm.h>
 
 #include <asm/hypervisor.h>
 
 static size_t pkvm_granule;
 
+static int arm_smccc_do_one_page(u32 func_id, phys_addr_t phys)
+{
+	phys_addr_t end = phys + PAGE_SIZE;
+
+	while (phys < end) {
+		struct arm_smccc_res res;
+
+		arm_smccc_1_1_invoke(func_id, phys, 0, 0, &res);
+		if (res.a0 != SMCCC_RET_SUCCESS)
+			return -EPERM;
+
+		phys += pkvm_granule;
+	}
+
+	return 0;
+}
+
+static int __set_memory_range(u32 func_id, unsigned long start, int numpages)
+{
+	void *addr = (void *)start, *end = addr + numpages * PAGE_SIZE;
+
+	while (addr < end) {
+		int err;
+
+		err = arm_smccc_do_one_page(func_id, virt_to_phys(addr));
+		if (err)
+			return err;
+
+		addr += PAGE_SIZE;
+	}
+
+	return 0;
+}
+
+static int pkvm_set_memory_encrypted(unsigned long addr, int numpages)
+{
+	return __set_memory_range(ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID,
+				  addr, numpages);
+}
+
+static int pkvm_set_memory_decrypted(unsigned long addr, int numpages)
+{
+	return __set_memory_range(ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID,
+				  addr, numpages);
+}
+
+static const struct arm64_mem_crypt_ops pkvm_crypt_ops = {
+	.encrypt	= pkvm_set_memory_encrypted,
+	.decrypt	= pkvm_set_memory_decrypted,
+};
+
 void pkvm_init_hyp_services(void)
 {
 	int i;
 	struct arm_smccc_res res;
 	const u32 funcs[] = {
 		ARM_SMCCC_KVM_FUNC_HYP_MEMINFO,
+		ARM_SMCCC_KVM_FUNC_MEM_SHARE,
+		ARM_SMCCC_KVM_FUNC_MEM_UNSHARE,
 	};
 
 	for (i = 0; i < ARRAY_SIZE(funcs); ++i) {
@@ -34,4 +88,5 @@  void pkvm_init_hyp_services(void)
 		return;
 
 	pkvm_granule = res.a0;
+	arm64_mem_crypt_ops_register(&pkvm_crypt_ops);
 }
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 16b6dcc54e02..9cb7c95920b0 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -116,6 +116,8 @@ 
 #define ARM_SMCCC_KVM_FUNC_FEATURES		0
 #define ARM_SMCCC_KVM_FUNC_PTP			1
 #define ARM_SMCCC_KVM_FUNC_HYP_MEMINFO		2
+#define ARM_SMCCC_KVM_FUNC_MEM_SHARE		3
+#define ARM_SMCCC_KVM_FUNC_MEM_UNSHARE		4
 #define ARM_SMCCC_KVM_FUNC_FEATURES_2		127
 #define ARM_SMCCC_KVM_NUM_FUNCS			128
 
@@ -144,6 +146,18 @@ 
 			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
 			   ARM_SMCCC_KVM_FUNC_HYP_MEMINFO)
 
+#define ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID			\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_64,				\
+			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
+			   ARM_SMCCC_KVM_FUNC_MEM_SHARE)
+
+#define ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID			\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_64,				\
+			   ARM_SMCCC_OWNER_VENDOR_HYP,			\
+			   ARM_SMCCC_KVM_FUNC_MEM_UNSHARE)
+
 /* ptp_kvm counter type ID */
 #define KVM_PTP_VIRT_COUNTER			0
 #define KVM_PTP_PHYS_COUNTER			1