From 5be76a4759e45f16302e82e50d85d53e687e558c Mon Sep 17 00:00:00 2001 From: John Davis Date: Mon, 16 Feb 2026 18:03:23 -0600 Subject: [PATCH] bootloader: Implement TSC calibration via Hyper-V MSR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Jérôme Duval Haiku-Format: Haiku-format Bot --- src/system/boot/arch/x86/arch_cpu.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/system/boot/arch/x86/arch_cpu.cpp b/src/system/boot/arch/x86/arch_cpu.cpp index 1d20e05ed4..a130843372 100644 --- a/src/system/boot/arch/x86/arch_cpu.cpp +++ b/src/system/boot/arch/x86/arch_cpu.cpp @@ -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);