As a part of the confidential guest reset process, the existing encrypted guest state must be made mutable since it would be discarded after reset. A new encrypted and locked guest state must be established after the reset. To this end, a new callback per confidential guest support class (eg, tdx or sev-snp) is added that will indicate whether its possible to rebuild guest state:
bool (*can_rebuild_guest_state)(ConfidentialGuestSupport *cgs) This api returns true if rebuilding guest state is possible, false otherwise. A KVM based confidential guest reset is only possible when the existing state is locked but its possible to rebuild guest state. Otherwise, the guest is not resettable. Signed-off-by: Ani Sinha <[email protected]> --- include/system/confidential-guest-support.h | 27 +++++++++++++++++++++ system/runstate.c | 11 +++++++-- target/i386/kvm/tdx.c | 6 +++++ target/i386/sev.c | 9 +++++++ 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/include/system/confidential-guest-support.h b/include/system/confidential-guest-support.h index 0cc8b26e64..3c37227263 100644 --- a/include/system/confidential-guest-support.h +++ b/include/system/confidential-guest-support.h @@ -152,6 +152,11 @@ typedef struct ConfidentialGuestSupportClass { */ int (*get_mem_map_entry)(int index, ConfidentialGuestMemoryMapEntry *entry, Error **errp); + + /* + * is it possible to rebuild the guest state? + */ + bool (*can_rebuild_guest_state)(ConfidentialGuestSupport *cgs); } ConfidentialGuestSupportClass; static inline int confidential_guest_kvm_init(ConfidentialGuestSupport *cgs, @@ -167,6 +172,28 @@ static inline int confidential_guest_kvm_init(ConfidentialGuestSupport *cgs, return 0; } +static inline bool +confidential_guest_can_rebuild_state(ConfidentialGuestSupport *cgs) +{ + ConfidentialGuestSupportClass *klass; + + if (!cgs) { + /* non-confidential guests */ + return true; + } + + klass = CONFIDENTIAL_GUEST_SUPPORT_GET_CLASS(cgs); + if (klass->can_rebuild_guest_state) { + return klass->can_rebuild_guest_state(cgs); + } + + /* + * by default, we should not be able to unprotect the + * confidential guest state + */ + return false; +} + static inline int confidential_guest_kvm_reset(ConfidentialGuestSupport *cgs, Error **errp) { diff --git a/system/runstate.c b/system/runstate.c index f5e57fd1f7..fb878c2992 100644 --- a/system/runstate.c +++ b/system/runstate.c @@ -58,6 +58,7 @@ #include "system/reset.h" #include "system/runstate.h" #include "system/runstate-action.h" +#include "system/confidential-guest-support.h" #include "system/system.h" #include "system/tpm.h" #include "trace.h" @@ -564,7 +565,12 @@ void qemu_system_reset(ShutdownCause reason) if (cpus_are_resettable()) { cpu_synchronize_all_post_reset(); } else { - assert(runstate_check(RUN_STATE_PRELAUNCH)); + /* + * for confidential guests, cpus are not resettable but their + * state can be rebuilt under some conditions. + */ + assert(runstate_check(RUN_STATE_PRELAUNCH) || + (current_machine->cgs && runstate_is_running())); } vm_set_suspended(false); @@ -713,7 +719,8 @@ void qemu_system_reset_request(ShutdownCause reason) if (reboot_action == REBOOT_ACTION_SHUTDOWN && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) { shutdown_requested = reason; - } else if (!cpus_are_resettable()) { + } else if (!cpus_are_resettable() && + !confidential_guest_can_rebuild_state(current_machine->cgs)) { error_report("cpus are not resettable, terminating"); shutdown_requested = reason; } else { diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index b6fac162bd..20f9d63eff 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -1594,6 +1594,11 @@ static ResettableState *tdx_reset_state(Object *obj) return &tdx->reset_state; } +static bool tdx_can_rebuild_guest_state(ConfidentialGuestSupport *cgs) +{ + return true; +} + static void tdx_guest_class_init(ObjectClass *oc, const void *data) { ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc); @@ -1601,6 +1606,7 @@ static void tdx_guest_class_init(ObjectClass *oc, const void *data) ResettableClass *rc = RESETTABLE_CLASS(oc); klass->kvm_init = tdx_kvm_init; + klass->can_rebuild_guest_state = tdx_can_rebuild_guest_state; x86_klass->kvm_type = tdx_kvm_type; x86_klass->cpu_instance_init = tdx_cpu_instance_init; x86_klass->adjust_cpuid_features = tdx_adjust_cpuid_features; diff --git a/target/i386/sev.c b/target/i386/sev.c index 246a58c752..4eea58d160 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -2659,6 +2659,14 @@ static int cgs_set_guest_state(hwaddr gpa, uint8_t *ptr, uint64_t len, return -1; } +static bool sev_can_rebuild_guest_state(ConfidentialGuestSupport *cgs) +{ + if (!sev_snp_enabled() && !sev_es_enabled()) { + return false; + } + return true; +} + static int cgs_get_mem_map_entry(int index, ConfidentialGuestMemoryMapEntry *entry, Error **errp) @@ -2833,6 +2841,7 @@ sev_common_instance_init(Object *obj) cgs->set_guest_state = cgs_set_guest_state; cgs->get_mem_map_entry = cgs_get_mem_map_entry; cgs->set_guest_policy = cgs_set_guest_policy; + cgs->can_rebuild_guest_state = sev_can_rebuild_guest_state; qemu_register_resettable(OBJECT(sev_common)); -- 2.42.0
