bootloader: Implement TSC calibration via Hyper-V MSR

Hyper-V does not use the standard hypervisor CPUID leaf for TSC
frequency reporting, causing time drift on Gen1 VMs as the PIT is
considered unreliable. Gen2 VMs do not emulate a PIT and require
the use of this MSR.

Change-Id: I38cbdb9f8de7259b5cb4bc195d0e6585d76782c2
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10339
Reviewed-by: waddlesplash <[email protected]>
Reviewed-by: Jérôme Duval <[email protected]>
Haiku-Format: Haiku-format Bot <[email protected]>
This commit is contained in:
John Davis
2026-02-19 20:16:41 +00:00
committed by Jérôme Duval
parent 79b809944b
commit 5be76a4759
+24
View File
@@ -327,6 +327,7 @@ determine_cpu_conversion_factor(uint8 channel)
&& (info.regs.ecx & IA32_FEATURE_EXT_HYPERVISOR) != 0) {
get_current_cpuid(&info, 0x40000000, 0);
const uint32 maxVMM = info.regs.eax;
if (maxVMM >= 0x40000010) {
get_current_cpuid(&info, 0x40000010, 0);
@@ -339,6 +340,29 @@ determine_cpu_conversion_factor(uint8 channel)
dprintf("TSC frequency read from hypervisor CPUID leaf\n");
return;
}
if (maxVMM >= 0x40000003) {
// Hyper-V does not implement the standard hypervisor timing interface
// "Hv#1" here indicates Hyper-V
get_current_cpuid(&info, 0x40000001, 0);
if (info.regs.eax == 0x31237648) {
// Check for HV_X64_MSR_TSC_FREQUENCY presence
// TSC frequency is represented in Hz
get_current_cpuid(&info, 0x40000003, 0);
if ((info.regs.eax & (1 << 11)) != 0) {
uint64 clockSpeed = x86_read_msr(0x40000022);
if (clockSpeed > 0) {
gTimeConversionFactor = (uint64(1000000) << 32) / clockSpeed;
gKernelArgs.arch_args.system_time_cv_factor = gTimeConversionFactor;
gKernelArgs.arch_args.cpu_clock_speed = clockSpeed;
dprintf("TSC frequency read from Hyper-V MSR\n");
return;
}
}
}
}
}
calculate_cpu_conversion_factor(channel);