kvm/clock: add support for confidential guest reset
Confidential guests change the KVM VM file descriptor upon reset and also create new VCPU file descriptors against the new KVM VM file descriptor. We need to save the clock state from kvm before KVM VM file descriptor changes and restore it after. Also after VCPU file descriptors changed, we must call KVM_KVMCLOCK_CTRL on the VCPU file descriptor to inform KVM that the VCPU is in paused state. Signed-off-by: Ani Sinha <anisinha@redhat.com> Link: https://lore.kernel.org/r/20260225035000.385950-32-anisinha@redhat.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Ani Sinha committed
Feb 25, 2026 at 09:19 UTC
18d55d0f66e2ff2881064a6c30bf8a02589b68b3
1 file changed
+59
hw/i386/kvm/clock.c
+59
@@ -50,6 +50,9 @@ struct KVMClockState {
50
/* whether the 'clock' value was obtained in a host with
51
* reliable KVM_GET_CLOCK */
52
bool clock_is_reliable;
53
+
54
+ NotifierWithReturn kvmclock_vcpufd_change_notifier;
55
+ NotifierWithReturn kvmclock_vmfd_change_notifier;
56
};
57
58
struct pvclock_vcpu_time_info {
@@ -63,6 +66,9 @@ struct pvclock_vcpu_time_info {
66
uint8_t pad[2];
67
} __attribute__((__packed__)); /* 32 bytes */
68
69
+static int kvmclock_set_clock(NotifierWithReturn *notifier,
70
+ void *data, Error** errp);
71
+
72
static uint64_t kvmclock_current_nsec(KVMClockState *s)
73
{
74
CPUState *cpu = first_cpu;
@@ -219,6 +225,54 @@ static void kvmclock_vm_state_change(void *opaque, bool running,
225
}
226
}
227
228
+static int kvmclock_save_clock(NotifierWithReturn *notifier,
229
+ void *data, Error** errp)
230
+{
231
+ if (!((VmfdChangeNotifier *)data)->pre) {
232
+ return 0;
233
+ }
234
+ KVMClockState *s = container_of(notifier, KVMClockState,
235
+ kvmclock_vmfd_change_notifier);
236
+ kvm_update_clock(s);
237
+ return 0;
238
+}
239
+
240
+static int kvmclock_set_clock(NotifierWithReturn *notifier,
241
+ void *data, Error** errp)
242
+{
243
+ struct kvm_clock_data clock_data = {};
244
+ CPUState *cpu;
245
+ int ret;
246
+ KVMClockState *s = container_of(notifier, KVMClockState,
247
+ kvmclock_vcpufd_change_notifier);
248
+ int cap_clock_ctrl = kvm_check_extension(kvm_state, KVM_CAP_KVMCLOCK_CTRL);
249
+
250
+ if (!s->clock_is_reliable) {
251
+ uint64_t pvclock_via_mem = kvmclock_current_nsec(s);
252
+ /* saved clock value before vmfd change is not reliable */
253
+ if (pvclock_via_mem) {
254
+ s->clock = pvclock_via_mem;
255
+ }
256
+ }
257
+
258
+ clock_data.clock = s->clock;
259
+ ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &clock_data);
260
+ if (ret < 0) {
261
+ fprintf(stderr, "KVM_SET_CLOCK failed: %s\n", strerror(-ret));
262
+ abort();
263
+ }
264
+
265
+ if (!cap_clock_ctrl) {
266
+ return 0;
267
+ }
268
+ CPU_FOREACH(cpu) {
269
+ run_on_cpu(cpu, do_kvmclock_ctrl, RUN_ON_CPU_NULL);
270
+ }
271
+
272
+ return 0;
273
+}
274
+
275
+
276
static void kvmclock_realize(DeviceState *dev, Error **errp)
277
{
278
KVMClockState *s = KVM_CLOCK(dev);
@@ -230,7 +284,12 @@ static void kvmclock_realize(DeviceState *dev, Error **errp)
284
285
kvm_update_clock(s);
286
287
+ s->kvmclock_vcpufd_change_notifier.notify = kvmclock_set_clock;
288
+ s->kvmclock_vmfd_change_notifier.notify = kvmclock_save_clock;
289
+
290
qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
291
+ kvm_vcpufd_add_change_notifier(&s->kvmclock_vcpufd_change_notifier);
292
+ kvm_vmfd_add_change_notifier(&s->kvmclock_vmfd_change_notifier);
293
}
294
295
static bool kvmclock_clock_is_reliable_needed(void *opaque)