When memory encryption is enabled in VM, the guest pages will be
encrypted with the guest-specific key, to protect the confidentiality
of data in transit. To support the live migration we need to use
platform specific hooks to access the guest memory.
The kvm_memcrypt_save_outgoing_page() can be used by the sender to write
the encrypted pages and metadata associated with it on the socket.
The kvm_memcrypt_load_incoming_page() can be used by receiver to read the
incoming encrypted pages from the socket and load into the guest memory.
Signed-off-by: Brijesh Singh <<brijesh.singh@amd.com>>
---
accel/kvm/kvm-all.c | 27 +++++++++++++++++++++++++++
accel/kvm/sev-stub.c | 11 +++++++++++
accel/stubs/kvm-stub.c | 12 ++++++++++++
include/sysemu/kvm.h | 12 ++++++++++++
include/sysemu/sev.h | 3 +++
5 files changed, 65 insertions(+)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 3d86ae5052..162a2d5085 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -110,6 +110,10 @@ struct KVMState
/* memory encryption */
void *memcrypt_handle;
int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
+ int (*memcrypt_save_outgoing_page)(void *ehandle, QEMUFile *f,
+ uint8_t *ptr, uint32_t sz, uint64_t *bytes_sent);
+ int (*memcrypt_load_incoming_page)(void *ehandle, QEMUFile *f,
+ uint8_t *ptr);
};
KVMState *kvm_state;
@@ -165,6 +169,29 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
return 1;
}
+int kvm_memcrypt_save_outgoing_page(QEMUFile *f, uint8_t *ptr,
+ uint32_t size, uint64_t *bytes_sent)
+{
+ if (kvm_state->memcrypt_handle &&
+ kvm_state->memcrypt_save_outgoing_page) {
+ return kvm_state->memcrypt_save_outgoing_page(kvm_state->memcrypt_handle,
+ f, ptr, size, bytes_sent);
+ }
+
+ return 1;
+}
+
+int kvm_memcrypt_load_incoming_page(QEMUFile *f, uint8_t *ptr)
+{
+ if (kvm_state->memcrypt_handle &&
+ kvm_state->memcrypt_load_incoming_page) {
+ return kvm_state->memcrypt_load_incoming_page(kvm_state->memcrypt_handle,
+ f, ptr);
+ }
+
+ return 1;
+}
+
static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
{
KVMState *s = kvm_state;
diff --git a/accel/kvm/sev-stub.c b/accel/kvm/sev-stub.c
index 4f97452585..c12a8e005e 100644
--- a/accel/kvm/sev-stub.c
+++ b/accel/kvm/sev-stub.c
@@ -24,3 +24,14 @@ void *sev_guest_init(const char *id)
{
return NULL;
}
+
+int sev_save_outgoing_page(void *handle, QEMUFile *f, uint8_t *ptr,
+ uint32_t size, uint64_t *bytes_sent)
+{
+ return 1;
+}
+
+int sev_load_incoming_page(void *handle, QEMUFile *f, uint8_t *ptr)
+{
+ return 1;
+}
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index 6feb66ed80..e14b879531 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -114,6 +114,18 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
return 1;
}
+int kvm_memcrypt_save_outgoing_page(QEMUFile *f, uint8_t *ptr,
+ uint32_t size, uint64_t *bytes_sent)
+{
+ return 1;
+}
+
+int kvm_memcrypt_load_incoming_page(QEMUFile *f, uint8_t *ptr)
+{
+ return 1;
+}
+
+
#ifndef CONFIG_USER_ONLY
int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
{
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index acd90aebb6..bb6bcc143c 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -247,6 +247,18 @@ bool kvm_memcrypt_enabled(void);
*/
int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len);
+/**
+ * kvm_memcrypt_save_outgoing_buffer - encrypt the outgoing buffer
+ * and write to the wire.
+ */
+int kvm_memcrypt_save_outgoing_page(QEMUFile *f, uint8_t *ptr, uint32_t size,
+ uint64_t *bytes_sent);
+
+/**
+ * kvm_memcrypt_load_incoming_buffer - read the encrypt incoming buffer and copy
+ * the buffer into the guest memory space.
+ */
+int kvm_memcrypt_load_incoming_page(QEMUFile *f, uint8_t *ptr);
#ifdef NEED_CPU_H
#include "cpu.h"
diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h
index 98c1ec8d38..752a71b1c0 100644
--- a/include/sysemu/sev.h
+++ b/include/sysemu/sev.h
@@ -18,4 +18,7 @@
void *sev_guest_init(const char *id);
int sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len);
+int sev_save_outgoing_page(void *handle, QEMUFile *f, uint8_t *ptr,
+ uint32_t size, uint64_t *bytes_sent);
+int sev_load_incoming_page(void *handle, QEMUFile *f, uint8_t *ptr);
#endif
--
2.17.1
* Singh, Brijesh (brijesh.singh@amd.com) wrote:
> When memory encryption is enabled in VM, the guest pages will be
> encrypted with the guest-specific key, to protect the confidentiality
> of data in transit. To support the live migration we need to use
> platform specific hooks to access the guest memory.
>
> The kvm_memcrypt_save_outgoing_page() can be used by the sender to write
> the encrypted pages and metadata associated with it on the socket.
>
> The kvm_memcrypt_load_incoming_page() can be used by receiver to read the
> incoming encrypted pages from the socket and load into the guest memory.
>
> Signed-off-by: Brijesh Singh <<brijesh.singh@amd.com>>
> ---
> accel/kvm/kvm-all.c | 27 +++++++++++++++++++++++++++
> accel/kvm/sev-stub.c | 11 +++++++++++
> accel/stubs/kvm-stub.c | 12 ++++++++++++
> include/sysemu/kvm.h | 12 ++++++++++++
> include/sysemu/sev.h | 3 +++
> 5 files changed, 65 insertions(+)
>
> diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
> index 3d86ae5052..162a2d5085 100644
> --- a/accel/kvm/kvm-all.c
> +++ b/accel/kvm/kvm-all.c
> @@ -110,6 +110,10 @@ struct KVMState
> /* memory encryption */
> void *memcrypt_handle;
> int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
> + int (*memcrypt_save_outgoing_page)(void *ehandle, QEMUFile *f,
> + uint8_t *ptr, uint32_t sz, uint64_t *bytes_sent);
> + int (*memcrypt_load_incoming_page)(void *ehandle, QEMUFile *f,
> + uint8_t *ptr);
> };
>
> KVMState *kvm_state;
> @@ -165,6 +169,29 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
> return 1;
> }
>
> +int kvm_memcrypt_save_outgoing_page(QEMUFile *f, uint8_t *ptr,
> + uint32_t size, uint64_t *bytes_sent)
> +{
> + if (kvm_state->memcrypt_handle &&
> + kvm_state->memcrypt_save_outgoing_page) {
> + return kvm_state->memcrypt_save_outgoing_page(kvm_state->memcrypt_handle,
> + f, ptr, size, bytes_sent);
> + }
> +
> + return 1;
This needs to be commented saying what the return values mean.
I'm not sure what '1' means for the case when this didn't have
encryption support.
> +}
> +
> +int kvm_memcrypt_load_incoming_page(QEMUFile *f, uint8_t *ptr)
> +{
> + if (kvm_state->memcrypt_handle &&
> + kvm_state->memcrypt_load_incoming_page) {
> + return kvm_state->memcrypt_load_incoming_page(kvm_state->memcrypt_handle,
> + f, ptr);
> + }
> +
> + return 1;
> +}
> +
> static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
> {
> KVMState *s = kvm_state;
> diff --git a/accel/kvm/sev-stub.c b/accel/kvm/sev-stub.c
> index 4f97452585..c12a8e005e 100644
> --- a/accel/kvm/sev-stub.c
> +++ b/accel/kvm/sev-stub.c
> @@ -24,3 +24,14 @@ void *sev_guest_init(const char *id)
> {
> return NULL;
> }
> +
> +int sev_save_outgoing_page(void *handle, QEMUFile *f, uint8_t *ptr,
> + uint32_t size, uint64_t *bytes_sent)
> +{
> + return 1;
> +}
> +
> +int sev_load_incoming_page(void *handle, QEMUFile *f, uint8_t *ptr)
> +{
> + return 1;
> +}
> diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
> index 6feb66ed80..e14b879531 100644
> --- a/accel/stubs/kvm-stub.c
> +++ b/accel/stubs/kvm-stub.c
> @@ -114,6 +114,18 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
> return 1;
> }
>
> +int kvm_memcrypt_save_outgoing_page(QEMUFile *f, uint8_t *ptr,
> + uint32_t size, uint64_t *bytes_sent)
> +{
> + return 1;
> +}
> +
> +int kvm_memcrypt_load_incoming_page(QEMUFile *f, uint8_t *ptr)
> +{
> + return 1;
> +}
> +
> +
> #ifndef CONFIG_USER_ONLY
> int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
> {
> diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
> index acd90aebb6..bb6bcc143c 100644
> --- a/include/sysemu/kvm.h
> +++ b/include/sysemu/kvm.h
> @@ -247,6 +247,18 @@ bool kvm_memcrypt_enabled(void);
> */
> int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len);
>
> +/**
> + * kvm_memcrypt_save_outgoing_buffer - encrypt the outgoing buffer
> + * and write to the wire.
> + */
> +int kvm_memcrypt_save_outgoing_page(QEMUFile *f, uint8_t *ptr, uint32_t size,
> + uint64_t *bytes_sent);
> +
> +/**
> + * kvm_memcrypt_load_incoming_buffer - read the encrypt incoming buffer and copy
> + * the buffer into the guest memory space.
> + */
> +int kvm_memcrypt_load_incoming_page(QEMUFile *f, uint8_t *ptr);
>
> #ifdef NEED_CPU_H
> #include "cpu.h"
> diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h
> index 98c1ec8d38..752a71b1c0 100644
> --- a/include/sysemu/sev.h
> +++ b/include/sysemu/sev.h
> @@ -18,4 +18,7 @@
>
> void *sev_guest_init(const char *id);
> int sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len);
> +int sev_save_outgoing_page(void *handle, QEMUFile *f, uint8_t *ptr,
> + uint32_t size, uint64_t *bytes_sent);
> +int sev_load_incoming_page(void *handle, QEMUFile *f, uint8_t *ptr);
> #endif
> --
> 2.17.1
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
On 7/11/19 12:47 PM, Dr. David Alan Gilbert wrote:
> * Singh, Brijesh (brijesh.singh@amd.com) wrote:
>> When memory encryption is enabled in VM, the guest pages will be
>> encrypted with the guest-specific key, to protect the confidentiality
>> of data in transit. To support the live migration we need to use
>> platform specific hooks to access the guest memory.
>>
>> The kvm_memcrypt_save_outgoing_page() can be used by the sender to write
>> the encrypted pages and metadata associated with it on the socket.
>>
>> The kvm_memcrypt_load_incoming_page() can be used by receiver to read the
>> incoming encrypted pages from the socket and load into the guest memory.
>>
>> Signed-off-by: Brijesh Singh <<brijesh.singh@amd.com>>
>> ---
>> accel/kvm/kvm-all.c | 27 +++++++++++++++++++++++++++
>> accel/kvm/sev-stub.c | 11 +++++++++++
>> accel/stubs/kvm-stub.c | 12 ++++++++++++
>> include/sysemu/kvm.h | 12 ++++++++++++
>> include/sysemu/sev.h | 3 +++
>> 5 files changed, 65 insertions(+)
>>
>> diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
>> index 3d86ae5052..162a2d5085 100644
>> --- a/accel/kvm/kvm-all.c
>> +++ b/accel/kvm/kvm-all.c
>> @@ -110,6 +110,10 @@ struct KVMState
>> /* memory encryption */
>> void *memcrypt_handle;
>> int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
>> + int (*memcrypt_save_outgoing_page)(void *ehandle, QEMUFile *f,
>> + uint8_t *ptr, uint32_t sz, uint64_t *bytes_sent);
>> + int (*memcrypt_load_incoming_page)(void *ehandle, QEMUFile *f,
>> + uint8_t *ptr);
>> };
>>
>> KVMState *kvm_state;
>> @@ -165,6 +169,29 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
>> return 1;
>> }
>>
>> +int kvm_memcrypt_save_outgoing_page(QEMUFile *f, uint8_t *ptr,
>> + uint32_t size, uint64_t *bytes_sent)
>> +{
>> + if (kvm_state->memcrypt_handle &&
>> + kvm_state->memcrypt_save_outgoing_page) {
>> + return kvm_state->memcrypt_save_outgoing_page(kvm_state->memcrypt_handle,
>> + f, ptr, size, bytes_sent);
>> + }
>> +
>> + return 1;
>
> This needs to be commented saying what the return values mean.
> I'm not sure what '1' means for the case when this didn't have
> encryption support.
>
Agreed, I will add comment in API header about this. The value of zero
means success and anything else is failure.
>> +}
>> +
>> +int kvm_memcrypt_load_incoming_page(QEMUFile *f, uint8_t *ptr)
>> +{
>> + if (kvm_state->memcrypt_handle &&
>> + kvm_state->memcrypt_load_incoming_page) {
>> + return kvm_state->memcrypt_load_incoming_page(kvm_state->memcrypt_handle,
>> + f, ptr);
>> + }
>> +
>> + return 1;
>> +}
>> +
>> static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
>> {
>> KVMState *s = kvm_state;
>> diff --git a/accel/kvm/sev-stub.c b/accel/kvm/sev-stub.c
>> index 4f97452585..c12a8e005e 100644
>> --- a/accel/kvm/sev-stub.c
>> +++ b/accel/kvm/sev-stub.c
>> @@ -24,3 +24,14 @@ void *sev_guest_init(const char *id)
>> {
>> return NULL;
>> }
>> +
>> +int sev_save_outgoing_page(void *handle, QEMUFile *f, uint8_t *ptr,
>> + uint32_t size, uint64_t *bytes_sent)
>> +{
>> + return 1;
>> +}
>> +
>> +int sev_load_incoming_page(void *handle, QEMUFile *f, uint8_t *ptr)
>> +{
>> + return 1;
>> +}
>> diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
>> index 6feb66ed80..e14b879531 100644
>> --- a/accel/stubs/kvm-stub.c
>> +++ b/accel/stubs/kvm-stub.c
>> @@ -114,6 +114,18 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
>> return 1;
>> }
>>
>> +int kvm_memcrypt_save_outgoing_page(QEMUFile *f, uint8_t *ptr,
>> + uint32_t size, uint64_t *bytes_sent)
>> +{
>> + return 1;
>> +}
>> +
>> +int kvm_memcrypt_load_incoming_page(QEMUFile *f, uint8_t *ptr)
>> +{
>> + return 1;
>> +}
>> +
>> +
>> #ifndef CONFIG_USER_ONLY
>> int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
>> {
>> diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
>> index acd90aebb6..bb6bcc143c 100644
>> --- a/include/sysemu/kvm.h
>> +++ b/include/sysemu/kvm.h
>> @@ -247,6 +247,18 @@ bool kvm_memcrypt_enabled(void);
>> */
>> int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len);
>>
>> +/**
>> + * kvm_memcrypt_save_outgoing_buffer - encrypt the outgoing buffer
>> + * and write to the wire.
>> + */
>> +int kvm_memcrypt_save_outgoing_page(QEMUFile *f, uint8_t *ptr, uint32_t size,
>> + uint64_t *bytes_sent);
>> +
>> +/**
>> + * kvm_memcrypt_load_incoming_buffer - read the encrypt incoming buffer and copy
>> + * the buffer into the guest memory space.
>> + */
>> +int kvm_memcrypt_load_incoming_page(QEMUFile *f, uint8_t *ptr);
>>
>> #ifdef NEED_CPU_H
>> #include "cpu.h"
>> diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h
>> index 98c1ec8d38..752a71b1c0 100644
>> --- a/include/sysemu/sev.h
>> +++ b/include/sysemu/sev.h
>> @@ -18,4 +18,7 @@
>>
>> void *sev_guest_init(const char *id);
>> int sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len);
>> +int sev_save_outgoing_page(void *handle, QEMUFile *f, uint8_t *ptr,
>> + uint32_t size, uint64_t *bytes_sent);
>> +int sev_load_incoming_page(void *handle, QEMUFile *f, uint8_t *ptr);
>> #endif
>> --
>> 2.17.1
>>
> --
> Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
>
© 2016 - 2026 Red Hat, Inc.