hypervisor: aarch64: capture the guest counter for snapshot/restore

Unlike x86, ARM64 has no kvmclock support to sync guest time upon
required. However, the guest reads the architected virtual timer
(CNTVCT_EL0) directly which can be modified by the VMM to update the
time after snapshot restore. Since the CNTVCT is in ticks, we also need
to read CNTFRQ (via mrs due to lack of ONEREG interface) to compute the
ticks from wall clock difference.

Because the counter is a vCPU register, the capture must run with the
vCPUs quiesced, so the VMM now captures the clock just after
cpu_manager.pause() through the boot vCPU. This is behaviorally
identical for x86, whose clock is VM-wide. There is no restore/advance
yet, so aarch64 guests still resume behind real time until the following
commit.

Signed-off-by: Atish Patra <atishp@meta.com>
This commit is contained in:
Atish Patra
2026-06-11 15:25:08 -07:00
committed by Rob Bradford
parent ad909a3d71
commit 69637dde69
8 changed files with 144 additions and 28 deletions

View File

@@ -226,9 +226,28 @@ impl ClockData {
}
/// Guest clock state preserved across pause/resume and snapshot/restore
/// (`ClockData` on x86).
/// (`ClockData` on x86, `TimerState` on aarch64+kvm.
/// The platform where it has not guest clock, `Option<ClockState>` will be None.
#[cfg(target_arch = "x86_64")]
pub type ClockState = ClockData;
#[cfg(all(target_arch = "aarch64", feature = "kvm"))]
pub type ClockState = TimerState;
#[cfg(not(any(target_arch = "x86_64", all(target_arch = "aarch64", feature = "kvm"))))]
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
pub enum ClockState {}
/// Guest timer state captured on aarch64 for snapshot/migration: the guest
/// virtual counter (`CNTVCT_EL0`) plus the host wall clock and counter
/// frequency needed to advance it to current wall time on restore. aarch64 has
/// no `KVM_SET_CLOCK`/`KVM_CLOCK_REALTIME`, so the VMM records these and does the
/// advance itself.
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
#[cfg(all(target_arch = "aarch64", feature = "kvm"))]
pub struct TimerState {
pub cntvct: u64,
pub host_realtime_ns: u64,
pub cntfrq: u64,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct HypervisorVmConfig {