@@ -53,10 +53,13 @@
#include "block.h"
#include "sysemu/sysemu.h"
#include "sysemu/cpu-throttle.h"
+#include "sysemu/kvm.h"
#include "savevm.h"
#include "qemu/iov.h"
#include "multifd.h"
#include "sysemu/runstate.h"
+#include "hw/boards.h"
+#include "confidential-ram.h"
#if defined(__linux__)
#include "qemu/userfaultfd.h"
@@ -81,6 +84,7 @@
#define RAM_SAVE_FLAG_XBZRLE 0x40
/* 0x80 is reserved in migration.h start with 0x100 next */
#define RAM_SAVE_FLAG_COMPRESS_PAGE 0x100
+#define RAM_SAVE_FLAG_GUEST_ENCRYPTED_PAGE 0x200
static inline bool memcrypt_enabled(void)
{
@@ -94,6 +98,13 @@ static inline bool is_zero_range(uint8_t *p, uint64_t size)
return buffer_is_zero(p, size);
}
+static inline bool confidential_guest(void)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+
+ return ms->cgs;
+}
+
XBZRLECacheStats xbzrle_counters;
/* struct contains XBZRLE cache and a static page
@@ -660,6 +671,23 @@ static void mig_throttle_guest_down(uint64_t bytes_dirty_period,
}
}
+/**
+ * is_page_encrypted: check if the page is encrypted
+ *
+ * Returns a bool indicating whether the page is encrypted.
+ */
+static bool is_page_encrypted(RAMState *rs, RAMBlock *block, unsigned long page)
+{
+ /* ROM devices contain unencrypted data */
+ if (memory_region_is_romd(block->mr) ||
+ memory_region_is_rom(block->mr) ||
+ !memory_region_is_ram(block->mr)) {
+ return false;
+ }
+
+ return test_bit(page, block->encbmap);
+}
+
/**
* xbzrle_cache_zero_page: insert a zero page in the XBZRLE cache
*
@@ -1928,6 +1956,45 @@ static bool save_compress_page(RAMState *rs, RAMBlock *block, ram_addr_t offset)
return false;
}
+/**
+ * ram_save_encrypted_page - send the given encrypted page to the stream
+ *
+ * Return the number of pages written (=1).
+ */
+static int ram_save_encrypted_page(RAMState *rs, PageSearchStatus *pss,
+ bool last_stage)
+{
+ int ret;
+ uint8_t *p;
+ RAMBlock *block = pss->block;
+ ram_addr_t offset = pss->page << TARGET_PAGE_BITS;
+ ram_addr_t gpa;
+ uint64_t bytes_sent;
+
+ p = block->host + offset;
+
+ /* Find the GPA of the page */
+ if (!kvm_physical_memory_addr_from_host(kvm_state, p, &gpa)) {
+ error_report("%s failed to get gpa for offset %" PRIu64 " block %s",
+ __func__, offset, memory_region_name(block->mr));
+ return -1;
+ }
+
+ ram_counters.transferred +=
+ save_page_header(rs, rs->f, block,
+ offset | RAM_SAVE_FLAG_GUEST_ENCRYPTED_PAGE);
+
+ ret = cgs_mh_save_encrypted_page(rs->f, gpa, TARGET_PAGE_SIZE, &bytes_sent);
+ if (ret) {
+ return -1;
+ }
+
+ ram_counters.transferred += bytes_sent;
+ ram_counters.normal++;
+
+ return 1;
+}
+
/**
* ram_save_target_page: save one target page
*
@@ -1948,6 +2015,26 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss,
return res;
}
+ /*
+ * If memory encryption is enabled then skip saving the data pages used by
+ * the migration handler.
+ */
+ if (confidential_guest() &&
+ gpa_inside_migration_helper_shared_area(offset)) {
+ return 0;
+ }
+
+ /*
+ * If memory encryption is enabled then use memory encryption APIs
+ * to write the outgoing buffer to the wire. The encryption APIs
+ * will take care of accessing the guest memory and re-encrypt it
+ * for the transport purposes.
+ */
+ if (confidential_guest() &&
+ is_page_encrypted(rs, pss->block, pss->page)) {
+ return ram_save_encrypted_page(rs, pss, last_stage);
+ }
+
if (save_compress_page(rs, block, offset)) {
return 1;
}
@@ -2776,6 +2863,10 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
return -1;
}
+ if (confidential_guest()) {
+ cgs_mh_init();
+ }
+
/* migration has already setup the bitmap, reuse it. */
if (!migration_in_colo_state()) {
if (ram_init_all(rsp) != 0) {
When saving RAM pages of a confidential guest, check whether a page is encrypted. If it is, ask the in-guest migration helper to encrypt the page for transmission. This relies on ability to track the encryption status of each page according to guest's reports, and thus requires the relevant patches in the guest OS and OVMF and the host KVM and QEMU. This is all encapsulated in is_page_encrypted; the implementation can be modified according to the underlying implementation of page encryption status tracking (bitmap / KVM shared regions list / user-side list) Signed-off-by: Dov Murik <dovmurik@linux.vnet.ibm.com> --- migration/ram.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+)