Project

General

Profile

Actions

Bug #14668

open

bhyve could better emulate pmtimer rollover

Added by Patrick Mooney 26 days ago. Updated 26 days ago.

Status:
New
Priority:
Normal
Assignee:
-
Category:
bhyve
Start date:
Due date:
% Done:

0%

Estimated time:
Difficulty:
Medium
Tags:
Gerrit CR:

Description

In the PIIX4 specification, the PM timer is stated to have certain behavior when its value rolls over:

When bit 23 of the timer transitions from high-to-low or low-to-high, the TMROF_STS bit is set. If the TMROF_EN bit is set an SCI interrupt is also generated.

The vpmtmr emulation in bhyve lacks any of that, acting simply as a 24-bit wide read-only timer. It would probably be useful to provide some sort of interface so the host software could properly emulate that roll-over behavior (in c-bhyve and/or propolis).

Actions #1

Updated by Greg Colombo 26 days ago

One result of this is that when you run a Windows guest that decides to use the PM timer, its performance counter APIs like Win32's QueryPerformanceCounter will go backwards every few seconds. This isn't generally fatal to the system (in that it doesn't immediately BSOD), but user programs that rely on QPC increasing over time will be unhappy; notably, DWM (the desktop compositor) has a timing thread that will fastfail if it sees QPC moving backwards, so RDP/graphical console sessions will be unstable and difficult to use. Switching Windows to use a different time source like the HPET stabilizes these users.

Here's a small Rust program that exhibits this. In Cargo.toml add a dependency on the windows crate:


[dependencies.windows]
version = "0.36.1" 
features = ["Win32_System_Performance", "Win32_Foundation"]

Then, in main.rs:

use windows::{
    Win32::System::Performance::QueryPerformanceCounter,
    Win32::System::Performance::QueryPerformanceFrequency,
};

fn main() {
    let mut qpc: i64 = 0;
    let mut qpc_freq: i64 = 0;

    unsafe {
        QueryPerformanceFrequency(&mut qpc_freq).unwrap();
    }

    println!("QPC frequency: {} / 0x{:x}", qpc_freq, qpc_freq);

    let mut sample: usize = 1;
    loop {
        unsafe {
            QueryPerformanceCounter(&mut qpc).unwrap();
        }
        println!("Sample {:>16} | {:#016x}", sample, qpc);
        sample += 1;
        std::thread::sleep(std::time::Duration::from_secs(1));
    }
}

Building this against the x86_64-pc-windows-msvc target and running it in a Windows guest will show that bits 0-23 frequently roll over, but that bits 24 and up don't increase at the frequency you would expect, as in this sample output:


QPC frequency: 3579545 / 0x369e99
Sample                1 | 0x0000000e4fc53f
Sample                2 | 0x0000000d8758a6
Sample                3 | 0x0000000dbed1fa
Sample                4 | 0x0000000df64c58
Sample                5 | 0x0000000e2dc547
Sample                6 | 0x0000000e6539f4
Sample                7 | 0x0000000d9d921c
Sample                8 | 0x0000000dd50f1c
Sample                9 | 0x0000000e0c8990
Sample               10 | 0x0000000e43fff6
Sample               11 | 0x0000000e7b7a93
Sample               12 | 0x0000000db3cb6a <-- rollover
Sample               13 | 0x0000000deb41c1
Sample               14 | 0x0000000e22bad4
Sample               15 | 0x0000000e5a3579
Sample               16 | 0x0000001d8356db <- rollover, but incremented at bit 28
Sample               17 | 0x0000001dbda283
Sample               18 | 0x0000001df519d9
Sample               19 | 0x0000001e2c9731
Sample               20 | 0x0000001e640eb7
Sample               21 | 0x0000001d9c6776 <- rollover, etc.
Sample               22 | 0x0000001dd3df8a
Sample               23 | 0x0000001e144438
Sample               24 | 0x0000001e4b58f0
Sample               25 | 0x0000001d83a975
Sample               26 | 0x0000001dc15afb
Sample               27 | 0x0000001df89434
Sample               28 | 0x0000001e300df4
Sample               29 | 0x0000001e678891
Sample               30 | 0x0000001d9fe245
Sample               31 | 0x0000001dd75767
Sample               32 | 0x0000001e0ed20b
Sample               33 | 0x0000001e464877
Sample               34 | 0x0000001e7dc48a
Actions

Also available in: Atom PDF