Re: [Qemu-devel] [PATCH v3 10/14] target/i386: sev: add support to load incoming encrypted page
* Singh, Brijesh (brijesh.si...@amd.com) wrote: > The sev_load_incoming_page() provide the implementation to read the > incoming guest private pages from the socket and load it into the guest > memory. The routines uses the RECEIVE_START command to create the > incoming encryption context on the first call then uses the > RECEIEVE_UPDATE_DATA command to load the encrypted pages into the guest > memory. After migration is completed, we issue the RECEIVE_FINISH command > to transition the SEV guest to the runnable state so that it can be > executed. > > Signed-off-by: Brijesh Singh OK, some comments about the return values of the functions would help, but other than that. Reviewed-by: Dr. David Alan Gilbert > --- > accel/kvm/kvm-all.c | 6 ++ > accel/kvm/sev-stub.c | 5 ++ > include/sysemu/sev.h | 1 + > target/i386/sev.c| 137 ++- > target/i386/trace-events | 3 + > 5 files changed, 151 insertions(+), 1 deletion(-) > > diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c > index a5b0ae9363..ba0e7fa2be 100644 > --- a/accel/kvm/kvm-all.c > +++ b/accel/kvm/kvm-all.c > @@ -180,9 +180,15 @@ static int kvm_memcrypt_save_outgoing_page(QEMUFile *f, > uint8_t *ptr, >bytes_sent); > } > > +static int kvm_memcrypt_load_incoming_page(QEMUFile *f, uint8_t *ptr) > +{ > +return sev_load_incoming_page(kvm_state->memcrypt_handle, f, ptr); > +} > + > static struct MachineMemoryEncryptionOps sev_memory_encryption_ops = { > .save_setup = kvm_memcrypt_save_setup, > .save_outgoing_page = kvm_memcrypt_save_outgoing_page, > +.load_incoming_page = kvm_memcrypt_load_incoming_page, > }; > > int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len) > diff --git a/accel/kvm/sev-stub.c b/accel/kvm/sev-stub.c > index 51b17b8141..1b6773ef72 100644 > --- a/accel/kvm/sev-stub.c > +++ b/accel/kvm/sev-stub.c > @@ -36,3 +36,8 @@ int sev_save_outgoing_page(void *handle, QEMUFile *f, > uint8_t *ptr, > { > return 1; > } > + > +int sev_load_incoming_page(void *handle, QEMUFile *f, uint8_t *ptr) > +{ > +return 1; > +} > diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h > index f06fd203cd..e9371bd2dd 100644 > --- a/include/sysemu/sev.h > +++ b/include/sysemu/sev.h > @@ -22,4 +22,5 @@ int sev_save_setup(void *handle, const char *pdh, const > char *plat_cert, > const char *amd_cert); > 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); > #endif > diff --git a/target/i386/sev.c b/target/i386/sev.c > index 1820c62a71..a689011991 100644 > --- a/target/i386/sev.c > +++ b/target/i386/sev.c > @@ -721,13 +721,34 @@ sev_launch_finish(SEVState *s) > } > } > > +static int > +sev_receive_finish(SEVState *s) > +{ > +int error, ret = 1; > + > +trace_kvm_sev_receive_finish(); > +ret = sev_ioctl(s->sev_fd, KVM_SEV_RECEIVE_FINISH, 0, &error); > +if (ret) { > +error_report("%s: RECEIVE_FINISH ret=%d fw_error=%d '%s'", > +__func__, ret, error, fw_error_to_str(error)); > +goto err; > +} > + > +sev_set_guest_state(SEV_STATE_RUNNING); > +err: > +return ret; > +} > + > + > static void > sev_vm_state_change(void *opaque, int running, RunState state) > { > SEVState *s = opaque; > > if (running) { > -if (!sev_check_state(SEV_STATE_RUNNING)) { > +if (sev_check_state(SEV_STATE_RECEIVE_UPDATE)) { > +sev_receive_finish(s); > +} else if (!sev_check_state(SEV_STATE_RUNNING)) { > sev_launch_finish(s); > } > } > @@ -1097,6 +1118,120 @@ int sev_save_outgoing_page(void *handle, QEMUFile *f, > uint8_t *ptr, > return sev_send_update_data(s, f, ptr, sz, bytes_sent); > } > > +static int > +sev_receive_start(QSevGuestInfo *sev, QEMUFile *f) > +{ > +int ret = 1; > +int fw_error; > +struct kvm_sev_receive_start start = { }; > +gchar *session = NULL, *pdh_cert = NULL; > + > +/* get SEV guest handle */ > +start.handle = object_property_get_int(OBJECT(sev), "handle", > + &error_abort); > + > +/* get the source policy */ > +start.policy = qemu_get_be32(f); > + > +/* get source PDH key */ > +start.pdh_len = qemu_get_be32(f); > +if (!check_blob_length(start.pdh_len)) { > +return 1; > +} > + > +pdh_cert = g_new(gchar, start.pdh_len); > +qemu_get_buffer(f, (uint8_t *)pdh_cert, start.pdh_len); > +start.pdh_uaddr = (uintptr_t)pdh_cert; > + > +/* get source session data */ > +start.session_len = qemu_get_be32(f); > +if (!check_blob_length(start.session_len)) { > +return 1; > +} > +session = g_new(gchar, start.session_len); > +qemu_get_buffer(f, (uint8_t *)session, start.session_len
[Qemu-devel] [PATCH v3 10/14] target/i386: sev: add support to load incoming encrypted page
The sev_load_incoming_page() provide the implementation to read the incoming guest private pages from the socket and load it into the guest memory. The routines uses the RECEIVE_START command to create the incoming encryption context on the first call then uses the RECEIEVE_UPDATE_DATA command to load the encrypted pages into the guest memory. After migration is completed, we issue the RECEIVE_FINISH command to transition the SEV guest to the runnable state so that it can be executed. Signed-off-by: Brijesh Singh --- accel/kvm/kvm-all.c | 6 ++ accel/kvm/sev-stub.c | 5 ++ include/sysemu/sev.h | 1 + target/i386/sev.c| 137 ++- target/i386/trace-events | 3 + 5 files changed, 151 insertions(+), 1 deletion(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index a5b0ae9363..ba0e7fa2be 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -180,9 +180,15 @@ static int kvm_memcrypt_save_outgoing_page(QEMUFile *f, uint8_t *ptr, bytes_sent); } +static int kvm_memcrypt_load_incoming_page(QEMUFile *f, uint8_t *ptr) +{ +return sev_load_incoming_page(kvm_state->memcrypt_handle, f, ptr); +} + static struct MachineMemoryEncryptionOps sev_memory_encryption_ops = { .save_setup = kvm_memcrypt_save_setup, .save_outgoing_page = kvm_memcrypt_save_outgoing_page, +.load_incoming_page = kvm_memcrypt_load_incoming_page, }; int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len) diff --git a/accel/kvm/sev-stub.c b/accel/kvm/sev-stub.c index 51b17b8141..1b6773ef72 100644 --- a/accel/kvm/sev-stub.c +++ b/accel/kvm/sev-stub.c @@ -36,3 +36,8 @@ int sev_save_outgoing_page(void *handle, QEMUFile *f, uint8_t *ptr, { return 1; } + +int sev_load_incoming_page(void *handle, QEMUFile *f, uint8_t *ptr) +{ +return 1; +} diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h index f06fd203cd..e9371bd2dd 100644 --- a/include/sysemu/sev.h +++ b/include/sysemu/sev.h @@ -22,4 +22,5 @@ int sev_save_setup(void *handle, const char *pdh, const char *plat_cert, const char *amd_cert); 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); #endif diff --git a/target/i386/sev.c b/target/i386/sev.c index 1820c62a71..a689011991 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -721,13 +721,34 @@ sev_launch_finish(SEVState *s) } } +static int +sev_receive_finish(SEVState *s) +{ +int error, ret = 1; + +trace_kvm_sev_receive_finish(); +ret = sev_ioctl(s->sev_fd, KVM_SEV_RECEIVE_FINISH, 0, &error); +if (ret) { +error_report("%s: RECEIVE_FINISH ret=%d fw_error=%d '%s'", +__func__, ret, error, fw_error_to_str(error)); +goto err; +} + +sev_set_guest_state(SEV_STATE_RUNNING); +err: +return ret; +} + + static void sev_vm_state_change(void *opaque, int running, RunState state) { SEVState *s = opaque; if (running) { -if (!sev_check_state(SEV_STATE_RUNNING)) { +if (sev_check_state(SEV_STATE_RECEIVE_UPDATE)) { +sev_receive_finish(s); +} else if (!sev_check_state(SEV_STATE_RUNNING)) { sev_launch_finish(s); } } @@ -1097,6 +1118,120 @@ int sev_save_outgoing_page(void *handle, QEMUFile *f, uint8_t *ptr, return sev_send_update_data(s, f, ptr, sz, bytes_sent); } +static int +sev_receive_start(QSevGuestInfo *sev, QEMUFile *f) +{ +int ret = 1; +int fw_error; +struct kvm_sev_receive_start start = { }; +gchar *session = NULL, *pdh_cert = NULL; + +/* get SEV guest handle */ +start.handle = object_property_get_int(OBJECT(sev), "handle", + &error_abort); + +/* get the source policy */ +start.policy = qemu_get_be32(f); + +/* get source PDH key */ +start.pdh_len = qemu_get_be32(f); +if (!check_blob_length(start.pdh_len)) { +return 1; +} + +pdh_cert = g_new(gchar, start.pdh_len); +qemu_get_buffer(f, (uint8_t *)pdh_cert, start.pdh_len); +start.pdh_uaddr = (uintptr_t)pdh_cert; + +/* get source session data */ +start.session_len = qemu_get_be32(f); +if (!check_blob_length(start.session_len)) { +return 1; +} +session = g_new(gchar, start.session_len); +qemu_get_buffer(f, (uint8_t *)session, start.session_len); +start.session_uaddr = (uintptr_t)session; + +trace_kvm_sev_receive_start(start.policy, session, pdh_cert); + +ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_RECEIVE_START, +&start, &fw_error); +if (ret < 0) { +error_report("Error RECEIVE_START ret=%d fw_error=%d '%s'", +ret, fw_error, fw_error_to_str(fw_error)); +goto err; +} + +object_property_set_int(OBJECT(sev), start.handle, "hand