Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Prerelease] - Unreleased

### Fixed
* Fix restore on WHP not rewinding the guest TSC on hosts with `TSC_ADJUST` support.

## [v0.19.0] - 2026-11-04

### Added
Expand Down
10 changes: 3 additions & 7 deletions docs/msr.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,9 @@ MTRRs cannot be read.

### TSC

Hyper-V stores `TSC` and `TSC_ADJUST` independently. While time runs, it
preserves `TSC - TSC_ADJUST`: writing `TSC` also changes `TSC_ADJUST`, while
writing `TSC_ADJUST` changes the internal TSC offset.

Restore writes `TSC` before `TSC_ADJUST`. The two writes remove the guest's
delta without freezing partition time. KVM also restores `TSC` so all backends
use the same guest-time semantics.
Restore sets the guest TSC back to its snapshot value. MSHV and WHP partitions
disable `TscAdjustSupport`. That feature makes a write to `TSC` or `TSC_ADJUST`
move the other by the same amount, so restoring both would undo the rewind.

## Retained-state inventory

Expand Down
1 change: 0 additions & 1 deletion src/hyperlight_host/src/hypervisor/regs/x86_64/msrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,6 @@ const NON_MTRR_RESETTABLE_MSRS: &[u32] = &[
// MSHV maps XSS through its U_XSS alias.
MSR_XSS,
MSR_TSC,
// Hyper-V stores TSC_ADJUST independently from TSC.
MSR_TSC_ADJUST,
// Host probing omits TSC_AUX when RDTSCP is unavailable.
MSR_TSC_AUX,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ impl WhpVm {
)
.map_err(|e| CreateVmError::SetPartitionProperty(e.into()))?;

Self::disable_tsc_adjust(p)?;

#[cfg(feature = "hw-interrupts")]
Self::enable_lapic_emulation(p)?;

Expand Down Expand Up @@ -320,6 +322,39 @@ impl WhpVm {
})
}

/// `TscAdjustSupport` makes a write to `TSC` or `TSC_ADJUST` move the other
/// by the same amount, so restoring both would undo the TSC rewind.
fn disable_tsc_adjust(partition: WHV_PARTITION_HANDLE) -> Result<(), CreateVmError> {
// Bit 18 of `WHV_PROCESSOR_FEATURES1`, the second bank.
const TSC_ADJUST_SUPPORT: u64 = 1 << 18;
Comment thread
jsturtevant marked this conversation as resolved.
Resolved

let mut banks = WHV_PROCESSOR_FEATURES_BANKS {
BanksCount: 2,
..Default::default()
};
let size = std::mem::size_of_val(&banks) as u32;
// SAFETY: `banks` is a buffer of `size` bytes, and every view of its
// union is plain `u64` data.
unsafe {
WHvGetPartitionProperty(
partition,
WHvPartitionPropertyCodeProcessorFeaturesBanks,
&mut banks as *mut _ as *mut c_void,
size,
None,
)
.map_err(|e| CreateVmError::GetPartitionProperty(e.into()))?;
banks.Anonymous.AsUINT64[1] &= !TSC_ADJUST_SUPPORT;
WHvSetPartitionProperty(
partition,
WHvPartitionPropertyCodeProcessorFeaturesBanks,
&banks as *const _ as *const c_void,
size,
)
.map_err(|e| CreateVmError::SetPartitionProperty(e.into()))
}
}

fn get_registers(
&self,
names: &[WHV_REGISTER_NAME],
Expand Down
4 changes: 1 addition & 3 deletions src/hyperlight_host/src/sandbox/initialized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4832,10 +4832,8 @@ mod tests {

/// KVM ignores a host TSC write within one second of the value it
/// expects, so restores closer together than that exercise the KVM path.
/// The 500 ms gaps tolerate host stalls shorter than that. WHP is
/// excluded because it keeps elapsed time on hosts with `TSC_ADJUST`.
/// The 500 ms gaps tolerate host stalls shorter than that.
#[test]
#[cfg(any(kvm, mshv3))]
fn restore_rewinds_tsc() {
let mut sbox = SandboxBuilder::from_file(simple_guest_as_pathbuf())
.build()
Expand Down
Loading