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 <anisinha@redhat.com>
---
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