hypervisor: aarch64: advance the guest counter on restore and migration

Currently, Cloud Hypervisor round-trips CNTVCT_EL0 through
KVM_GET_REG_LIST/SET_ONE_REG, which leaves a cold-restored or migrated
guest behind real UTC by the downtime. Same-host pause/resume
self-corrects (the physical counter keeps running across the pause), so
only restore and migration cases required the clock to catch up to wall
clock time.

Since ARM has no kernel helper, compute the difference in wall clock
time and compute the ticks so that it can advance the CNTVCT correctly.
It is set via vcpu0 only as it affects a single VM wide value after
Linux 6.4. For older kernels, it was a truly vcpu value which needs to
be invoked for every vcpu.

Gated on all(target_arch = "aarch64", feature = "kvm"); x86 is
unchanged.

Basic manual test case (aarch64 + KVM) verified both in intra host and
inter host snapshot save/restore:

1. Boot a Linux guest; in the guest, `date -u` tracks the host's UTC.
2. Pause and snapshot the VM (ch-remote pause; ch-remote snapshot
   file:///<dir>).
3. Leave it down for several minutes (the off-host interval).
4. Restore and resume into a fresh VMM (ch-remote restore
   source_url=file:///<dir>,resume=true).
5. In the guest, run `date -u` again and compare to the host: the guest
   now tracks current UTC, having advanced by ~the time it spent down.

Before this change the restored guest reads behind real UTC by the
downtime; after it, the guest clock is back in sync (to within the
snapshot-to-restore sampling slop).

Signed-off-by: Atish Patra <atishp@meta.com>
This commit is contained in:
Atish Patra
2026-06-11 15:30:49 -07:00
committed by Rob Bradford
parent 69637dde69
commit 25271c9d0c
7 changed files with 178 additions and 35 deletions

View File

@@ -249,6 +249,17 @@ pub struct TimerState {
pub cntfrq: u64,
}
/// How the guest clock is re-established when the vCPUs resume: a same-host
/// pause/resume left it running, whereas a snapshot restore / migration-receive
/// means the guest was off-host and the clock must catch up to wall time.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ClockRestoreMode {
/// Same-host pause -> resume; the clock kept running, nothing to advance.
SameHostResume,
/// Restored from a snapshot or migrated in; advance to current wall time.
SnapshotRestore,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct HypervisorVmConfig {
#[cfg(feature = "tdx")]