From 3434042340ca031b6d355cc79dd00e166bd2e2fd Mon Sep 17 00:00:00 2001 From: jiangxin Date: Fri, 17 Jun 2022 09:45:45 +0800 Subject: [PATCH] target/i386: csv: Add support to migrate the incoming page for CSV3 guest The csv3_receive_encrypt_data() provides the method to read incoming guest private pages from socket and load them into guest memory. The routine is similar to CSV2's. Usually, it starts with a RECEIVE START command to create the migration context. Then RECEIVE ENCRYPT DATA command is performed to let the firmware load incoming pages into guest memory. After migration is completed, a RECEIVE FINISH command is performed to the firmware. Signed-off-by: Jiang Xin Signed-off-by: hanliyang --- target/i386/csv.c | 87 ++++++++++++++++++++++++++++++++++++++++ target/i386/csv.h | 2 + target/i386/sev.c | 8 ++++ target/i386/sev.h | 1 + target/i386/trace-events | 1 + 5 files changed, 99 insertions(+) diff --git a/target/i386/csv.c b/target/i386/csv.c index 22e709a95c..ac080b3766 100644 --- a/target/i386/csv.c +++ b/target/i386/csv.c @@ -38,11 +38,14 @@ bool csv_kvm_cpu_reset_inhibit; struct ConfidentialGuestMemoryEncryptionOps csv3_memory_encryption_ops = { .save_setup = sev_save_setup, .save_outgoing_page = NULL, + .load_incoming_page = csv3_load_incoming_page, .is_gfn_in_unshared_region = NULL, .save_outgoing_shared_regions_list = sev_save_outgoing_shared_regions_list, .load_incoming_shared_regions_list = sev_load_incoming_shared_regions_list, .queue_outgoing_page = csv3_queue_outgoing_page, .save_queued_outgoing_pages = csv3_save_queued_outgoing_pages, + .queue_incoming_page = NULL, + .load_queued_incoming_pages = NULL, }; #define CSV3_OUTGOING_PAGE_NUM \ @@ -89,6 +92,7 @@ csv3_init(uint32_t policy, int fd, void *state, struct sev_ops *ops) QTAILQ_INIT(&csv3_guest.dma_map_regions_list); qemu_mutex_init(&csv3_guest.dma_map_regions_list_mutex); csv3_guest.sev_send_start = ops->sev_send_start; + csv3_guest.sev_receive_start = ops->sev_receive_start; } return 0; } @@ -483,3 +487,86 @@ csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent) return csv3_send_encrypt_data(s, f, NULL, 0, bytes_sent); } + +static int +csv3_receive_start(QEMUFile *f) +{ + if (csv3_guest.sev_receive_start) + return csv3_guest.sev_receive_start(f); + else + return -1; +} + +static int csv3_receive_encrypt_data(QEMUFile *f, uint8_t *ptr) +{ + int ret = 1, fw_error = 0; + uint32_t i, guest_addr_entry_num; + gchar *hdr = NULL, *trans = NULL; + struct guest_addr_entry *guest_addr_data; + struct kvm_csv3_receive_encrypt_data update = {}; + void *hva = NULL; + MemoryRegion *mr = NULL; + + /* get packet header */ + update.hdr_len = qemu_get_be32(f); + + hdr = g_new(gchar, update.hdr_len); + qemu_get_buffer(f, (uint8_t *)hdr, update.hdr_len); + update.hdr_uaddr = (uintptr_t)hdr; + + /* get guest addr data */ + update.guest_addr_len = qemu_get_be32(f); + + guest_addr_data = (struct guest_addr_entry *)g_new(gchar, update.guest_addr_len); + qemu_get_buffer(f, (uint8_t *)guest_addr_data, update.guest_addr_len); + update.guest_addr_data = (uintptr_t)guest_addr_data; + + /* get transport buffer */ + update.trans_len = qemu_get_be32(f); + + trans = g_new(gchar, update.trans_len); + update.trans_uaddr = (uintptr_t)trans; + qemu_get_buffer(f, (uint8_t *)update.trans_uaddr, update.trans_len); + + /* update share memory. */ + guest_addr_entry_num = update.guest_addr_len / sizeof(struct guest_addr_entry); + for (i = 0; i < guest_addr_entry_num; i++) { + if (guest_addr_data[i].share) { + hva = gpa2hva(&mr, + ((uint64_t)guest_addr_data[i].gfn << TARGET_PAGE_BITS), + TARGET_PAGE_SIZE, + NULL); + if (hva) + memcpy(hva, trans + i * TARGET_PAGE_SIZE, TARGET_PAGE_SIZE); + } + } + + trace_kvm_csv3_receive_encrypt_data(trans, update.trans_len, hdr, update.hdr_len); + + ret = csv3_ioctl(KVM_CSV3_RECEIVE_ENCRYPT_DATA, &update, &fw_error); + if (ret) { + error_report("Error RECEIVE_ENCRYPT_DATA ret=%d fw_error=%d '%s'", + ret, fw_error, fw_error_to_str(fw_error)); + goto err; + } + +err: + g_free(trans); + g_free(guest_addr_data); + g_free(hdr); + return ret; +} + +int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr) +{ + /* + * If this is first buffer and SEV is not in recieiving state then + * use RECEIVE_START command to create a encryption context. + */ + if (!csv3_check_state(SEV_STATE_RECEIVE_UPDATE) && + csv3_receive_start(f)) { + return 1; + } + + return csv3_receive_encrypt_data(f, ptr); +} diff --git a/target/i386/csv.h b/target/i386/csv.h index 12c1b22659..afcd59180c 100644 --- a/target/i386/csv.h +++ b/target/i386/csv.h @@ -108,6 +108,7 @@ struct Csv3GuestState { size_t guest_addr_len; int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); + int (*sev_receive_start)(QEMUFile *f); }; typedef struct Csv3GuestState Csv3GuestState; @@ -121,6 +122,7 @@ int csv3_load_data(uint64_t gpa, uint8_t *ptr, uint64_t len, Error **errp); int csv3_shared_region_dma_map(uint64_t start, uint64_t end); void csv3_shared_region_dma_unmap(uint64_t start, uint64_t end); +int csv3_load_incoming_page(QEMUFile *f, uint8_t *ptr); int csv3_queue_outgoing_page(uint8_t *ptr, uint32_t sz, uint64_t addr); int csv3_save_queued_outgoing_pages(QEMUFile *f, uint64_t *bytes_sent); diff --git a/target/i386/sev.c b/target/i386/sev.c index 5a96b0b452..5124bf3dee 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -2665,10 +2665,18 @@ static int _sev_send_start(QEMUFile *f, uint64_t *bytes_sent) return sev_send_start(s, f, bytes_sent); } +static int _sev_receive_start(QEMUFile *f) +{ + SevGuestState *s = sev_guest; + + return sev_receive_start(s, f); +} + struct sev_ops sev_ops = { .sev_ioctl = sev_ioctl, .fw_error_to_str = fw_error_to_str, .sev_send_start = _sev_send_start, + .sev_receive_start = _sev_receive_start, }; static void diff --git a/target/i386/sev.h b/target/i386/sev.h index 8ccef22a95..647b426b16 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -84,6 +84,7 @@ struct sev_ops { int (*sev_ioctl)(int fd, int cmd, void *data, int *error); const char *(*fw_error_to_str)(int code); int (*sev_send_start)(QEMUFile *f, uint64_t *bytes_sent); + int (*sev_receive_start)(QEMUFile *f); }; extern struct sev_ops sev_ops; diff --git a/target/i386/trace-events b/target/i386/trace-events index a4a58b12a1..b3cb9aaf71 100644 --- a/target/i386/trace-events +++ b/target/i386/trace-events @@ -23,3 +23,4 @@ kvm_sev_receive_update_vmsa(uint32_t cpu_id, uint32_t cpu_index, void *src, int # csv.c kvm_csv3_launch_encrypt_data(uint64_t gpa, void *addr, uint64_t len) "gpa 0x%" PRIx64 "addr %p len 0x%" PRIx64 kvm_csv3_send_encrypt_data(void *dst, int len) "trans %p len %d" +kvm_csv3_receive_encrypt_data(void *dst, int len, void *hdr, int hdr_len) "trans %p len %d hdr %p hdr_len %d" -- 2.41.0.windows.1