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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user