@@ -14,4 +14,6 @@ void cgs_mh_cleanup(void);
int cgs_mh_save_encrypted_page(QEMUFile *f, ram_addr_t src_gpa, uint32_t size,
uint64_t *bytes_sent);
+int cgs_mh_load_encrypted_page(QEMUFile *f, ram_addr_t dest_gpa);
+
#endif
@@ -182,3 +182,40 @@ int cgs_mh_save_encrypted_page(QEMUFile *f, ram_addr_t src_gpa, uint32_t size,
return ret;
}
+
+int cgs_mh_load_encrypted_page(QEMUFile *f, ram_addr_t dest_gpa)
+{
+ int ret = 1;
+ uint32_t page_hdr_len, enc_page_len;
+
+ init_cgs_mig_helper_if_needed();
+
+ assert((dest_gpa & TARGET_PAGE_MASK) == dest_gpa);
+
+ /* Read page header */
+ page_hdr_len = qemu_get_be32(f);
+ if (page_hdr_len > 1024) {
+ error_report("confidential-ram: page header is too large (%d bytes) "
+ "when loading gpa %" PRIu64, page_hdr_len, dest_gpa);
+ return -EINVAL;
+ }
+ cmhs.io_page_hdr->len = page_hdr_len;
+ qemu_get_buffer(f, cmhs.io_page_hdr->data, page_hdr_len);
+
+ /* Read encrypted page */
+ enc_page_len = qemu_get_be32(f);
+ if (enc_page_len != TARGET_PAGE_SIZE) {
+ error_report("confidential-ram: encrypted page is too large (%d bytes) "
+ "when loading gpa %" PRIu64, enc_page_len, dest_gpa);
+ return -EINVAL;
+ }
+ qemu_get_buffer(f, cmhs.io_page, enc_page_len);
+
+ trace_encrypted_ram_load_page(page_hdr_len, enc_page_len, dest_gpa);
+ ret = send_command_to_cgs_mig_helper(CGS_MIG_HELPER_CMD_DECRYPT, dest_gpa);
+ if (ret) {
+ error_report("confidential-ram: failed loading page at dest_gpa "
+ "%" PRIu64 ": ret=%d", dest_gpa, ret);
+ }
+ return ret;
+}
@@ -345,4 +345,5 @@ migration_pagecache_init(int64_t max_num_items) "Setting cache buckets to %" PRI
migration_pagecache_insert(void) "Error allocating page"
# confidential-ram.c
+encrypted_ram_load_page(uint32_t hdr_len, uint32_t trans_len, uint64_t gpa) "hdr_len: %u, trans_len: %u, gpa: 0x%" PRIx64
encrypted_ram_save_page(uint32_t size, uint64_t gpa) "size: %u, gpa: 0x%" PRIx64
QEMU cannot write directly to the memory of memory-encrypted guests; this breaks normal RAM-load in the migration target. Instead, QEMU asks a migration helper running on an auxiliary vcpu in the guest to restore encrypted pages as they were received from the source to a specific GPA. The migration helper running inside the guest can safely decrypt the pages arrived from the source and load them into their proper location in the guest's memory. Loading pages uses the same shared (unencrypted) pages which both QEMU and the guest can read from and write to. Signed-off-by: Dov Murik <dovmurik@linux.vnet.ibm.com> --- migration/confidential-ram.h | 2 ++ migration/confidential-ram.c | 37 ++++++++++++++++++++++++++++++++++++ migration/trace-events | 1 + 3 files changed, 40 insertions(+)