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. Encrypted VMs have concept of private and shared memory. The private memory is encrypted with the guest-specific key, while shared memory may be encrypted with hyperivosr key. The KVM_{SET,GET}_PAGE_ENC_BITMAP ioctl can be used to get/set the bitmap from/to the hypervisor. The kvm_memcrypt_sync_page_enc_bitmap() can be used by the sender to get the page encryption bitmap. The bitmap is used to determine the page state (private or shared). The kvm_memcrypt_send_outgoing_page_enc_bitmap() can be used by the sender to write the page encryption bitmap on the socket. The kvm_memcrypt_load_incoming_page_enc_bitmap() can be used by the receiver to read the page encryption bitmap from the socket. Signed-off-by: Brijesh Singh <<brijesh.singh@xxxxxxx>> --- accel/kvm/kvm-all.c | 68 ++++++++++++++++++++++++++++++++++++++++++ accel/kvm/sev-stub.c | 28 +++++++++++++++++ accel/stubs/kvm-stub.c | 30 +++++++++++++++++++ include/sysemu/kvm.h | 33 ++++++++++++++++++++ include/sysemu/sev.h | 9 ++++++ 5 files changed, 168 insertions(+) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index b0c4bed6e3..4d5ff8b9f5 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -109,6 +109,15 @@ 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); + int (*memcrypt_load_incoming_page_enc_bitmap)(void *ehandle, QEMUFile *f); + int (*memcrypt_save_outgoing_page_enc_bitmap)(void *ehandle, QEMUFile *f, + uint8_t *host, uint64_t length, unsigned long *bmap); + int (*memcrypt_sync_page_enc_bitmap)(void *ehandle, uint8_t *host, + uint64_t length, unsigned long *bmap); }; KVMState *kvm_state; @@ -164,6 +173,65 @@ 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; +} + +int kvm_memcrypt_load_incoming_page_enc_bitmap(QEMUFile *f) +{ + if (kvm_state->memcrypt_handle && + kvm_state->memcrypt_load_incoming_page_enc_bitmap) { + return kvm_state->memcrypt_load_incoming_page_enc_bitmap( + kvm_state->memcrypt_handle, f); + } + + return 1; +} + +int kvm_memcrypt_save_outgoing_page_enc_bitmap(QEMUFile *f, uint8_t *host, + uint64_t length, + unsigned long *bmap) +{ + if (kvm_state->memcrypt_handle && + kvm_state->memcrypt_save_outgoing_page_enc_bitmap) { + return kvm_state->memcrypt_save_outgoing_page_enc_bitmap( + kvm_state->memcrypt_handle, f, host, length, bmap); + } + + return 1; +} + +int kvm_memcrypt_sync_page_enc_bitmap(uint8_t *host, uint64_t length, + unsigned long *bmap) +{ + if (kvm_state->memcrypt_handle && + kvm_state->memcrypt_sync_page_enc_bitmap) { + return kvm_state->memcrypt_sync_page_enc_bitmap( + kvm_state->memcrypt_handle, host, length, bmap); + } + + 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..5d8c3f2ecd 100644 --- a/accel/kvm/sev-stub.c +++ b/accel/kvm/sev-stub.c @@ -24,3 +24,31 @@ 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; +} + +int sev_load_incoming_page_enc_bitmap(void *handle, QEMUFile *f) +{ + return 1; +} + +int sev_save_outgoing_page_enc_bitmap(void *handle, QEMUFile *f, + unsigned long *bmap) +{ + return 1; +} + +int sev_sync_page_enc_bitmap(void *handle, uint8_t *host, uint64_t size, + unsigned long *bitmap) +{ + return 1; +} diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c index 6feb66ed80..bef7376985 100644 --- a/accel/stubs/kvm-stub.c +++ b/accel/stubs/kvm-stub.c @@ -114,6 +114,36 @@ 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; +} + +int kvm_memcrypt_load_incoming_page_enc_bitmap(QEMUFile *f) +{ + return 1; +} + +int kvm_memcrypt_save_outgoing_page_enc_bitmap(QEMUFile *f, uint8_t *host, + uint64_t length, + unsigned long *bmap) +{ + return 1; +} + +int kvm_memcrypt_sync_page_enc_bitmap(uint8_t *host, uint64_t size, + unsigned long *bitmap) +{ + 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 a6d1cd190f..f85a60e411 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -246,6 +246,39 @@ 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); + +/** + * kvm_memcrypt_load_incoming_page_enc_bitmap: read the page encryption bitmap + * from the socket and pass it to the hypervisor. + */ +int kvm_memcrypt_load_incoming_page_enc_bitmap(QEMUFile *f); + +/** + * kvm_memcrypt_sync_page_enc_bitmap: sync the page encryption bitmap + * The caller is responsible to allocate/free the bitmap. + */ +int kvm_memcrypt_sync_page_enc_bitmap(uint8_t *host, uint64_t size, + unsigned long *bitmap); + +/** + * kvm_memcrypt_save_outgoing_page_enc_bitmap: write the page encryption bitmap + * on socket. + */ +int kvm_memcrypt_save_outgoing_page_enc_bitmap(QEMUFile *f, uint8_t *host, + uint64_t length, + unsigned long *bmap); #ifdef NEED_CPU_H #include "cpu.h" diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h index 98c1ec8d38..009be45230 100644 --- a/include/sysemu/sev.h +++ b/include/sysemu/sev.h @@ -18,4 +18,13 @@ 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); +int sev_load_incoming_page_enc_bitmap(void *handle, QEMUFile *f); +int sev_save_outgoing_page_enc_bitmap(void *handle, QEMUFile *f, + uint8_t *host, uint64_t length, + unsigned long *bmap); +int sev_sync_page_enc_bitmap(void *handle, uint8_t *host, uint64_t size, + unsigned long *bitmap); #endif -- 2.17.1