@@ -1786,6 +1786,10 @@ static int kvm_init(MachineState *ms)
kvm_state->memcrypt_sync_page_enc_bitmap = sev_sync_page_enc_bitmap;
kvm_state->memcrypt_save_outgoing_page = sev_save_outgoing_page;
kvm_state->memcrypt_load_incoming_page = sev_load_incoming_page;
+ kvm_state->memcrypt_load_incoming_page_enc_bitmap =
+ sev_load_incoming_page_enc_bitmap;
+ kvm_state->memcrypt_save_outgoing_page_enc_bitmap =
+ sev_save_outgoing_page_enc_bitmap;
}
ret = kvm_arch_init(ms, s);
@@ -78,6 +78,7 @@
/* 0x80 is reserved in migration.h start with 0x100 next */
#define RAM_SAVE_FLAG_COMPRESS_PAGE 0x100
#define RAM_SAVE_FLAG_ENCRYPTED_PAGE 0x200
+#define RAM_SAVE_FLAG_PAGE_ENCRYPTED_BITMAP 0x400
static inline bool is_zero_range(uint8_t *p, uint64_t size)
{
@@ -3551,6 +3552,35 @@ out:
return done;
}
+/**
+ * migration_save_page_enc_bitmap: function to send the page enc bitmap
+ *
+ * Returns zero to indicate success or negative on error
+ */
+static int migration_save_page_enc_bitmap(QEMUFile *f, RAMState *rs)
+{
+ int r;
+ RAMBlock *block;
+
+ RAMBLOCK_FOREACH_MIGRATABLE(block) {
+ /* ROM region does not encrypted data, skip sending the bitmap */
+ if (memory_region_is_rom(block->mr)) {
+ continue;
+ }
+
+ qemu_put_be64(f, RAM_SAVE_FLAG_PAGE_ENCRYPTED_BITMAP);
+ qemu_put_byte(f, strlen(block->idstr));
+ qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr));
+ r = kvm_memcrypt_save_outgoing_page_enc_bitmap(f, block->host,
+ block->max_length, block->encbmap);
+ if (r) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
/**
* ram_save_complete: function called to send the remaining amount of ram
*
@@ -3595,6 +3625,10 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
flush_compressed_data(rs);
ram_control_after_iterate(f, RAM_CONTROL_FINISH);
+ if (kvm_memcrypt_enabled()) {
+ ret = migration_save_page_enc_bitmap(f, rs);
+ }
+
rcu_read_unlock();
multifd_send_sync_main();
@@ -4343,7 +4377,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
if (flags & (RAM_SAVE_FLAG_ZERO | RAM_SAVE_FLAG_PAGE |
RAM_SAVE_FLAG_COMPRESS_PAGE | RAM_SAVE_FLAG_XBZRLE |
- RAM_SAVE_FLAG_ENCRYPTED_PAGE)) {
+ RAM_SAVE_FLAG_ENCRYPTED_PAGE |
+ RAM_SAVE_FLAG_PAGE_ENCRYPTED_BITMAP)) {
RAMBlock *block = ram_block_from_stream(f, flags);
/*
@@ -4469,6 +4504,12 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
ret = -EINVAL;
}
break;
+ case RAM_SAVE_FLAG_PAGE_ENCRYPTED_BITMAP:
+ if (kvm_memcrypt_load_incoming_page_enc_bitmap(f)) {
+ error_report("Failed to load page enc bitmap");
+ ret = -EINVAL;
+ }
+ break;
case RAM_SAVE_FLAG_EOS:
/* normal exit */
multifd_recv_sync_main();
@@ -896,6 +896,8 @@ int sev_sync_page_enc_bitmap(void *handle, uint8_t *host, uint64_t size,
return 1;
}
+ trace_kvm_sev_sync_page_enc_bitmap(base_gpa, size);
+
e.enc_bitmap = bitmap;
e.start = base_gpa >> TARGET_PAGE_BITS;
e.num_pages = pages;
@@ -1216,6 +1218,60 @@ int sev_load_incoming_page(void *handle, QEMUFile *f, uint8_t *ptr)
return sev_receive_update_data(f, ptr);
}
+int sev_load_incoming_page_enc_bitmap(void *handle, QEMUFile *f)
+{
+ void *bmap;
+ unsigned long pages, length;
+ unsigned long bmap_size, base_gpa;
+ struct kvm_page_enc_bitmap e = {};
+
+ base_gpa = qemu_get_be64(f);
+ length = qemu_get_be64(f);
+ pages = length >> TARGET_PAGE_BITS;
+
+ bmap_size = BITS_TO_LONGS(pages) * sizeof(unsigned long);
+ bmap = g_malloc0(bmap_size);
+ qemu_get_buffer(f, (uint8_t *)bmap, bmap_size);
+
+ trace_kvm_sev_load_page_enc_bitmap(base_gpa, length);
+
+ e.start = base_gpa >> TARGET_PAGE_BITS;
+ e.num_pages = pages;
+ e.enc_bitmap = bmap;
+ if (kvm_vm_ioctl(kvm_state, KVM_SET_PAGE_ENC_BITMAP, &e) == -1) {
+ error_report("KVM_SET_PAGE_ENC_BITMAP ioctl failed %d", errno);
+ g_free(bmap);
+ return 1;
+ }
+
+ g_free(bmap);
+
+ return 0;
+}
+
+int sev_save_outgoing_page_enc_bitmap(void *handle, QEMUFile *f,
+ uint8_t *host, uint64_t length,
+ unsigned long *bmap)
+{
+ int r;
+ unsigned long base_gpa;
+ unsigned long pages = length >> TARGET_PAGE_BITS;
+ unsigned long bmap_sz = BITS_TO_LONGS(pages) * sizeof(unsigned long);
+
+ r = kvm_physical_memory_addr_from_host(kvm_state, host, &base_gpa);
+ if (!r) {
+ return 1;
+ }
+
+ trace_kvm_sev_save_page_enc_bitmap(base_gpa, length);
+
+ qemu_put_be64(f, base_gpa);
+ qemu_put_be64(f, length);
+ qemu_put_buffer(f, (uint8_t *)bmap, bmap_sz);
+
+ return 0;
+}
+
static void
sev_register_types(void)
{
@@ -21,3 +21,6 @@ kvm_sev_send_finish(void) ""
kvm_sev_receive_start(int policy, void *session, void *pdh) "policy 0x%x session %p pdh %p"
kvm_sev_receive_update_data(void *src, void *dst, int len, void *hdr, int hdr_len) "guest %p trans %p len %d hdr %p hdr_len %d"
kvm_sev_receive_finish(void) ""
+kvm_sev_sync_page_enc_bitmap(uint64_t start, uint64_t len) "start 0x%" PRIx64 " len 0x%" PRIx64
+kvm_sev_save_page_enc_bitmap(uint64_t start, uint64_t len) "start 0x%" PRIx64 " len 0x%" PRIx64
+kvm_sev_load_page_enc_bitmap(uint64_t start, uint64_t len) "start 0x%" PRIx64 " len 0x%" PRIx64
When memory encryption is enabled, the hypervisor maintains a page encryption bitmap which is referred by hypervisor during migratoin to check if page is private or shared. The bitmap is built during the VM bootup and must be migrated to the target host so that hypervisor on target host can use it for future migration. Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> --- accel/kvm/kvm-all.c | 4 +++ migration/ram.c | 43 +++++++++++++++++++++++++++++- target/i386/sev.c | 56 ++++++++++++++++++++++++++++++++++++++++ target/i386/trace-events | 3 +++ 4 files changed, 105 insertions(+), 1 deletion(-)