Repository navigation
time ABI: publish the host's clock correction with each time sample - #1018
Pedro Henrique Penna (ppenna) wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The checker can accept stale clock corrections, and the restore-limit phase can pass without exercising Linux’s frequency limit, leaving both scenarios insufficiently validated.
2 open issues
What changed in this PR
Moves NVX to time ABI 2 so guests apply the host’s published clock correction rather than estimating it. This coordinates guest boot and restore behavior with the OpenVMM pin and addresses the host-clock qualification problems described in #1009 and #1008.
Changes:
- Updates time samples, restore packets, guest frequency control, and reported clock state.
- Changes doctor H4 to check TSC stability and synchronized host correction without gating on correction size.
- Adds a host-correction microVM scenario, regression coverage, and updated architecture documentation.
| File | Description |
|---|---|
scripts/test_time_abi.py |
Updates ABI diagnostics and host-clock qualification tests. |
scripts/test_nvx_tools.py |
Updates comments describing qualification and time ABI behavior. |
scripts/test_microvm_tests.py |
Adds host-correction scenario and report-checker tests. |
scripts/nvx_tools/time_abi.py |
Updates harness descriptions and errors to ABI v2. |
scripts/nvx_tools/microvm_tests.py |
Adds host-correction boot and restore validation. |
scripts/nvx_tools/microvm_test_scripts/time-host-correction.sh.in |
Reports guest state and paired time samples. |
scripts/nvx_tools/microvm_test_scripts/snapshot-core.sh |
Removes an outdated packet-version comment. |
scripts/nvx_tools/microvm_shards.json |
Adds the scenario and rebalances test shards. |
scripts/nvx_tools/doctor.py |
Reads host clock corrections and revises H4 qualification. |
nvx-rs/tests/guest_tools.rs |
Updates packet, sample, and command-output tests. |
nvx-rs/tests/fixtures/template/README.md |
Documents regenerated ABI v2 fixture manifests. |
nvx-rs/src/host/template/test_support.rs |
Uses the current time ABI in manifest fixtures. |
nvx-rs/src/host/template/manifest/tests.rs |
Tests rejection of incompatible time ABI versions. |
nvx-rs/src/host/launch.rs |
Removes version-specific wording from a comment. |
nvx-rs/src/guest/time/test_mode.rs |
Updates decoder and clock-arithmetic test hooks. |
nvx-rs/src/guest/time/system.rs |
Pairs samples with guest clocks and applies host corrections. |
nvx-rs/src/guest/time/state.rs |
Records host status, correction, bounds, and disruptions. |
nvx-rs/src/guest/time/mod.rs |
Identifies the guest implementation as ABI v2. |
nvx-rs/src/guest/time/daemon.rs |
Holds published frequency corrections and handles disruptions. |
nvx-rs/src/guest/time/cpu_mask.rs |
Removes version-specific wording from a comment. |
nvx-rs/src/guest/time/commands.rs |
Expands nvx-time sample output and pairing validation. |
nvx-rs/src/guest/time/checks.rs |
Checks the ABI v2 CPUID identity. |
nvx-rs/src/guest/time/api.rs |
Applies sampled host corrections during boot and restore. |
nvx-rs/src/guest/sys/mod.rs |
Exposes the frequency-hold type internally. |
nvx-rs/src/guest/sys/discipline.rs |
Holds frequency while allowing kernel phase correction. |
nvx-rs/src/contract.rs |
Sets time ABI 2 and restore packet 5. |
nvx-rs/README.md |
Updates guest API and tool descriptions to ABI v2. |
guest/common/nvx-snapshot |
Updates comments for packet v5 and sampled restore time. |
doc/usage.md |
Describes the host-correction scenario. |
doc/openvmm-upstream-roadmap.md |
Records the new pin and its six commits. |
doc/design/5.5-restore-protocol.md |
Specifies packet v5 and sample-based clock repair. |
doc/design/3.2-clock-and-time.md |
Specifies ABI v2 samples, corrections, and discipline. |
doc/design/3.1-platform-control-device.md |
Describes host-paired time samples. |
doc/design/1.2-non-goals.md |
Clarifies the distinction from paravirtual clocks. |
doc/ci.md |
Documents revised H4 checks and scenario expectations. |
doc/build.md |
Updates guest-tool and boot-time behavior descriptions. |
.github/actions/validate-runner/action.yml |
Updates comments describing host qualification. |
Review effort: Balanced
ea808fa to
013c960
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Fixed boot and restore offsets can push host corrections beyond Linux’s ±500 ppm limit, causing the non-limit checks to reject guests that correctly clamp their corrections.
1 open issue
2 resolved since last review
Review effort: Balanced
013c960 to
0327747
Compare
0327747 to
d17c209
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
The coordinated guest time-ABI and snapshot-format changes require maintainer confirmation of exact-pin compatibility, artifact deployment, and pending cross-platform validation across KVM, MSHV, and WHP.
1 open issue
1 resolved since last review
Review effort: Balanced
d17c209 to
a91e5e5
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
The breaking time-ABI and restore-protocol migration needs maintainer review and exact-pin KVM/MSHV/WHP validation, with the coupled OpenVMM PR still open and its full CI unfinished.
No open issues 🎉
1 resolved since last review
Review effort: Balanced
a91e5e5 to
990e4b4
Compare
There was a problem hiding this comment.
🟡 Changes recommended
H4 still rejects stable, synchronized hosts when H3 supplies native_tsc_hz and correction-derived rate deviation exceeds 250 ppm, preserving the qualification failure the change intends to remove.
1 open issue
2 resolved since last review
Review effort: Max
Pin microsoft/openvmm#4809 at 090fbab88f2cc2e069147c8dca122e343c9363ed, six commits on bcfc47cff6606afadffef97551e538962895b598, the previous pin and the head of feature/microvm/dev. Under time ABI 1 the guest paired host UTC with its own clock: nvx-time read CLOCK_REALTIME around the port write that latches a time sample and accepted the pairing only within 1 ms at boot and restore, or 50 us for its discipline, so a port write that a loaded host served late cost a sample, and three cost a boot or a restore. It then estimated how fast host UTC runs against its TSC by steering the kernel's PLL over minutes, although the host's time service already knows that rate. Time ABI 2 has OpenVMM pair each sample's host UTC with the guest TSC on the host and publish with it the host's clock correction, which the host OS reports (adjtimex on Linux, GetSystemTimeAdjustmentPrecise on Windows), the bound of the correction's error, the status and maximum error of host UTC, and a disruption counter, which changes on a host suspension, a step of host UTC, or a change of the guest TSC's offset. The version-2 sample is 48 bytes. CPUID leaf 0x40000002 reports time ABI 2.0 (EBX 0x00020000). Restore packet 5 drops host UTC, so its header shrinks to 24 bytes, and the guest's repair takes a time sample instead. The guest moves with the pin, since a guest of one time ABI fails the other's conformance check: - nvx::contract: TIME_ABI_VERSION 2 and RESTORE_PACKET_VERSION 5. - Pairing: the guest reads its TSC before and after the selector write, and CLOCK_REALTIME between those reads, and accepts a sample only if its TSC lies within that bracket, widened by the published pairing bound and 1 us of skew. It compares host UTC with CLOCK_REALTIME at the sample's TSC, moving its CLOCK_REALTIME read there at the rate at which Linux counts it; the offset's uncertainty is the pairing bound, half the bracket, and 2,000 ppm of that move. - Rate: from the host's correction and the TSC rate, which the guest reads once from the Hyper-V TSC frequency MSR (0x40000022) and keeps in its time state, the guest computes the adjtimex frequency that makes CLOCK_REALTIME, which Linux counts at its kHz rounding of the TSC rate, run at host UTC's rate. It clamps that frequency to Linux's 500 ppm limit and reports whether it did. - Discipline: boot steps the clock to host UTC and holds that frequency with STA_FREQHOLD, so that the kernel's PLL corrects only the phase. Every poll holds the latest correction and slews the measured offset, or steps it from 128 ms on. A changed disruption counter returns the daemon to its fast cadence. Boot, restore, and polls take up to three samples within 100 us; a boot that gets none fails its check, and a restore fails its repair. The maximum and estimated errors that the guest sets include host UTC's maximum error only when the host reports a synchronized clock; the guest never marks its clock unsynchronized on the host's behalf. - Restore: the repair reads packet 5 and takes its time sample in the same port transaction, then steps the clock and holds the frequency. - State: the time state records the host's status, correction, and correction bound, host UTC's maximum error, the disruption counter, and whether the frequency was limited. nvx-time sample prints a sample's fields and the guest's pairing, and the test hooks packet, sample, pair, frequency, and correction take the new fields. Templates record time ABI version 2, so the manifest reader refuses a template of time ABI 1, which must be recaptured. The fixtures' manifests, which OpenVMM's generator regenerated at the pin, differ from the previous ones only in that version. The template-key vectors keep the contract versions that their test fixes. Comments, the nvx-rs README, and nvx-snapshot name the new versions. OpenVMM's protocol vectors and CPU profiles are unchanged at the pin. Part of #1009 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The architecture guide described time ABI 1: a 16-byte time sample that the guest pairs with its own clock within 1 ms, or 50 us for its discipline, a guest that estimates host UTC's rate itself, and restore packet 4, which carries host UTC latched at its first selection. Describe time ABI 2, which the previous commit pins. 3.2, Clock and time: - Table 3.5: CPUID leaf 0x40000002 reports time ABI 2.0 in EBX. - 3.2.4: the host clock correction of every time sample includes a restore's rate deviation, so that the guest compensates it from its repair on. - 3.2.6, Backend obligations: every backend knows the guest TSC's offset from the host TSC before any processor runs, at cold boot and at every restore, so that the VMM pairs each sample's host UTC with the guest TSC. - 3.2.9, Time samples, rewritten: Figure 3.1 lays out the 48-byte version-2 sample field by field; the text gives the guest's pairing, the bracket check and the uncertainty of the offset, how it computes the adjtimex frequency that makes CLOCK_REALTIME run at host UTC's rate from the correction and the TSC rate, and the 500 ppm limit that it reports. Table 3.10 bounds every use, boot, restore, and the discipline, at 100 us and three attempts. The samples are no paravirtual clock: they feed only the wall-clock discipline, and the TSC stays the guest's clocksource. - 3.2.10, Guest obligations: the time state's new fields, a boot that takes a sample within the bound before readiness, steps to host UTC, and holds the frequency that the host's correction gives, and a discipline that holds that frequency at every accepted sample, so that the kernel's PLL only slews the phase, and returns to its fast cadence when the disruption counter changes. 5.5, Restore protocol: Figure 5.7 lays out restore packet 5, whose header is 24 bytes and carries no UTC, 88 bytes without memory ranges, and flag 3 also covers the host clock rate's test hook. The guest's repair steps take a time sample in the packet's port transaction and set the clock and its rate from it. 3.1, Platform control device, says that time samples pair host UTC with the guest TSC and carry the host's correction, and that the guest checks the pairing against TSC reads around the port write. 1.2, Non-goals, names kvmclock, Hyper-V's reference TSC page, and VMClock among the excluded paravirtual clocks, and says what the time samples feed instead. The build guide's description of nvx-time names restore packet 5 and the version-2 sample parsers and the correction that the discipline applies. Part of #1009 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Since this branch split from dev, H4's rate qualification gained the 250 ppm budget that time ABI 2 leaves for the host's clock correction, a retry when chronyd's skew straddles that limit, a warning above the old 100 ppm bound, the kernel PLL's estimate when chronyd is absent, and the average correction since boot as evidence (#1008). Keep all of those checks and their evidence. Time ABI 2 also changes what H4 must learn directly from the host. Every time sample publishes the host's clock correction, which the guest holds, so a qualified host must have a time service maintaining that correction. H4 now additionally: - Fails unless the host publishes a synchronized correction, read as OpenVMM reads it: on Linux, adjtimex reports neither STA_UNSYNC nor STA_CLOCKERR; on Windows, GetSystemTimeAdjustmentPrecise reports an applied adjustment. - Reports the status, correction, and host UTC's maximum error in its detail and as host_clock_status and host_correction_ppm summary facts. The direct correction is evidence; the independent 250 ppm rate gate continues to protect the guest's correction budget. - Keeps the chronyd estimate and its skew, conclusive re-reads, the kernel PLL fallback, the warning, and the average since boot, instead of replacing them with the instantaneous correction. The Linux reader shares the typed struct timex reader with the PLL and H7. The Windows reader uses the precise API's direction: the performance counter ticks increment times per second, and host UTC counts a second for every adjustment ticks, so a larger adjustment slows UTC. The H4 tests cover synchronized, free-running, unreliable, and unknown host clocks; Linux frequency, tick, and maximum-error mapping; Windows' correction direction; the summary facts; and the interaction with the rate budget, warnings, chronyd re-reads, PLL fallback, and boot average. The CI guide, validate-runner, and its test describe the combined gate. Part of #1009 Refs #1008 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
990e4b4 to
7603877
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The hook-rate calculation adds rates instead of composing them multiplicatively, allowing saturating phases and rejecting valid ones, with the same error reflected in the tests.
1 open issue
1 resolved since last review
Review effort: Max
Time ABI 2 publishes the host's clock correction with every sample, and the guest holds it as its frequency correction. Add the `time-host-correction` microVM scenario to check that behavior when host UTC runs at a deliberately different rate from the guest TSC. An unhooked cold boot first reads the host's own correction. OpenVMM's `host-rate-offset-ppm` hook then drives: - a hooked cold boot whose published correction stays below Linux's 500 ppm frequency limit; - a restore at another correction below the limit; and - a restore in the host correction's direction that exceeds the limit, where the guest must hold +/-500 ppm and report frequency_limited=1. The ordinary hooks solve OpenVMM's multiplicative composition of the host and hook rates for targets of 200 and 150 ppm against the host correction's sign. They are clamped to OpenVMM's accepted +/-10,000 ppm hook range; at its edge they use the closest composed correction below Linux's limit, and a host correction that cannot be brought below that limit fails before OpenVMM starts with a diagnostic naming both bounds. The limit hook is 900 ppm in the host correction's direction. Each phase requires the test-hook flag and checks that the boot step or restore repair did not retain a stale correction. Two samples pair host UTC and the guest's realtime clock with the guest TSC, so the checker verifies that both clocks run at the published correction, within their pairing uncertainty and the allowance for host slews. The limit phase requires the saturated frequency and flag explicitly. Linux counts the declared TSC rate rounded down to the kHz. The checker derives the permitted difference between the host and kernel frequency corrections from each report's tsc_hz and the worst 999 Hz loss, instead of assuming a rate of at least 1 GHz. The regression at 500,000,999 Hz accepts the valid 1,998 ppb difference; the hook tests cover both +/-10,000 ppm boundaries and reject corrections that cannot be offset. The shard plan runs the scenario on KVM, MSHV, and WHP. Unit tests cover the successful phases, stale and ignored corrections, the clock-rate checks, host slews and changing corrections, saturation, missing or unhooked samples, the full 500 MHz ABI range, OpenVMM's hook range, and the probe, boot, and restore command sequence. Part of #1009 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Record the six commits that the first commit of this series pins as positions 368-373 of the microVM chain, and move the NVX pin to 090fbab88. Positions 368-373 move NVX's time ABI to version 2: the shared host TSC bracket, the host OS's discipline of host UTC, the publication of host UTC paired with the guest TSC and its correction, the guest TSC's offset on every backend, the version-2 time sample and restore packet 5, and the Guide's description. They change the time-ABI backends, portb device, restore packet, and VM worker that positions 159-269 added. Position 372 also adapts petri's microVM configuration from PR15 and the ttrpc microVM test from PR25. The six commits are directly on bcfc47cff, position 367 and the current head of feature/microvm/dev after microsoft/openvmm#4818 merged positions 366-367. Update the scope, physical DAG, after-tip count and table, and remarks. The pin is 216 commits past the mapped tip. Part of #1009 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
7603877 to
4aeff73
Compare


Fixes #1009. Pins microsoft/openvmm#4809 at
090fbab88f2cc2e069147c8dca122e343c9363ed, which moves every microVM to time ABI 2: OpenVMM pairs each time sample's host UTC with the guest TSC on the host and publishes with it the host's clock correction, which the guest now applies instead of estimating it over minutes. The guest,nvx.py doctor's H4, the architecture guide, and a new microVM scenario move with the pin.Based on
devat78c626dac. microsoft/openvmm#4809 is six commits directly onbcfc47cff, the head offeature/microvm/devsince microsoft/openvmm#4818 merged, and the pin is that pull request's rebased head commit itself.Change
edcce2828openvmmopenvmm,nvx-rs/,guest/common/nvx-snapshot, wording inscripts/bcfc47cff->090fbab88, and the guest of time ABI 2 and restore packet 5, which must move with it: the version-2 sample's decoder, the pairing against the guest's own TSC bracket, the frequency correction from the host's correction, the discipline that holds it, the restore repair's sample, the time state's new fields,nvx-time sample, and the template fixtures' manifests, regenerated at the pind0491ef80docdoc/design/{1.2,3.1,3.2,5.5},doc/build.md7a8d13b75doctorscripts/nvx_tools/doctor.py,scripts/test_time_abi.py,doc/ci.md,validate-runner2e3f894dctest-microvmscripts/nvx_tools/microvm_tests.py, its guest script and tests,microvm_shards.json,doc/ci.md,doc/usage.mdtime-host-correctionscenario4aeff73a8docdoc/openvmm-upstream-roadmap.mdOpenVMM's control-session protocol vectors and built-in CPU profiles are unchanged at the pin.
Time ABI 2
OpenVMM (microsoft/openvmm#4809). Writing
0xa7to the portb status port latches a 48-byte version-2 sample: host UTC and the guest TSC at the same instant, paired on the host through the guest TSC's offset, which every backend measures before any VP runs (KVM'sKVM_VCPU_TSC_OFFSET; VP 0's TSC between two host TSC reads on MSHV and WHP), with the pairing's bound; the status of host UTC; a disruption counter, which changes on a host suspension, a step of host UTC, or a change of the offset; and the host's correction, how fast host UTC runs against the guest TSC counted at the declared rate, with the bounds of its error and of host UTC's. OpenVMM reads the correction from the host OS, whatever time service runs there:adjtimexon Linux, and on WindowsGetSystemTimeAdjustmentPrecise, whose increment is the performance counter's frequency and whose adjustment is the counter's ticks in each second of UTC, so that UTC runs at the increment over the adjustment of the counter's rate. After a restore the correction includes the restore's rate deviation. Restore packet 5 drops host UTC; CPUID leaf0x40000002reports time ABI 2.0, and snapshots record time ABI version 2.Guest (
nvx-rs).nvx-timereads its TSC around the selector write and its realtime clock between two more TSC reads, accepts a sample only if its TSC lies in that bracket, widened by the pairing bound and the 1 µs skew bound, and takes the offset from host UTC at the sample's TSC. It sets the kernel's frequency correction so that its realtime clock, which Linux counts at the TSC rate rounded down to the kHz, runs at host UTC's published rate, within Linux's ±500 ppm, and reportsfrequency_limitedbeyond it. Boot steps to host UTC and holds that frequency withSTA_FREQHOLD, so that the kernel's PLL corrects only the phase; every poll holds the latest correction, and a changed disruption counter returns the discipline to its fast cadence. Boot, restore, and polls take up to three samples within 100 µs, where time ABI 1 accepted 1 ms at boot and restore. A restore's repair takes its sample in the packet's port transaction, so a clone runs at the destination host's correction from its repair on. The time state reports the host's status, correction and its bound, host UTC's maximum error, and the disruption counter.The issue's next steps
dev's 250 ppm guest-budget gate, chronyd re-reads, warning, kernel-PLL fallback, and average-since-boot evidence, and additionally requires the host to publish a synchronized correction. The directly read status, correction, and maximum error are evidence; the independent rate gate still protects the guest's correction budget.time-host-correctionreads the host's own correction from an unhooked cold boot. OpenVMM'shost-rate-offset-ppmhook then selects ordinary corrections below Linux's limit and a 900 ppm limit phase. The ordinary hooks solve OpenVMM's multiplicative rate composition and stay within its +/-10,000 ppm parser range and fail explicitly if no accepted hook can avoid saturation; the frequency allowance is derived from the reported TSC rate down to the ABI's 500 MHz minimum. It runs on KVM, MSHV, and WHP.The open questions:
0xa7sample, 48 bytes, rather than a page that the guest maps.E_MANIFEST_TIME); snapshots and templates must be recaptured.Compatibility
nvx-rsmove together with the pin.Validate runnerstep reports its runner's.Validation
This branch was rebuilt on
devfour times whiledevmoved, each time carrying the same patches:565d1ebe5, on67f395e54, pinning OpenVMMb27be7e6a.cf7453276, onf8469b80a, pinning93b2c4d91.013c960c8, ond89d37090, pinninga417f946a.4aeff73a8, on78c626dac, pinning090fbab88. This rebuild preservesdev's newer H4 budget, chronyd, PLL, warning, and average-correction work; folds in the current review fixes; and carries the Windows correction fix below.The Windows correction's sign. CI's run of
032774707failed the second WHP shard onazure-windows-3, intime-host-correction's hooked cold boot. There, host UTC ran at +151.4 ppm against the guest TSC while OpenVMM published +248.7 ppm. Without the hook, OpenVMM published +48.7 ppm as the host's own correction while host UTC ran at -48.6 ppm.GetSystemTimeAdjustmentPreciseas the legacyGetSystemTimeAdjustment, which adds its adjustment once per increment. The precise API instead reports frequencies: the increment is the performance counter's, and Windows counts a second of UTC for every adjustment's worth of the counter's ticks. A larger adjustment therefore slows UTC.QueryPerformanceCountershowed this on both Windows hosts measured:azure-windows-3, whose time service moved its adjustment from 10,000,501 to 10,000,588 for an increment of 10,000,000, UTC ran 53.1 ppm slow.The validation:
090fbab88: formatting; package-scoped check, clippy with-D warnings, rustdoc, and unit tests for every changed crate on Windows and Linux; 18 WHP, 12 KVM, and 13 MSHV ignored hardware tests; and the two affected KVM VMM tests all pass.utc_offset_ms, and a VMM test showed the ttrpc microVM test's guest reading restore packet 4. The pin fixes both, and both microVM VMM tests passed on Linux/KVM.4aeff73a8:nvx.py verify; the time ABI (75), microVM (305), andnvx_tools(566) suites; ruff, Linux and Windows pyright, Markdown links; and the OpenVMM vectors and CPU profiles (3 and 1).990e4b425, before the final base-only refresh: shell formatting and linting; the nvx-rs feature matrix, rustdoc, MSRV, and runtime-adapter protocol, host, and Linux-musl guest clippy checks.d17c209d5, before a review corrected design doc 3.2's pairing equations:nvx.py verify; the time ABI, scenario, shard, and Markdown tests (185) andtest_nvx_tools.py(566); ruff, pyright, andscripts/check_markdown_links.py; and theopenvmm_vectorsandopenvmm_cpu_profilescomparisons, ignored tests included (3 and 1).cf7453276:nvx-rsand runtime adapter fmt and clippy, for the host and forx86_64-unknown-linux-musl.990e4b425: the fullvalidate-nvxsuite (1,503 tests), adversarial (84), host-connect (4), Specula (25), and Markdown links; everycheck-nvx-rsstep, including guest binaries and the runtime adapter's protocol, host, and guest configurations.990e4b425with OpenVMM090fbab88and freshly built guest artifacts:time-host-correctionanddoctor --checks H3 H4 --ci-schedulepass on Linux/KVM and Linux/MSHV.032774707with the scenario's probe: the fullvalidate-nvxPython suite (1,467 tests), plus the adversarial (84) and host-connect (4) tests.032774707: the runtime adapter's VM scenarios (154), includingdev's new clone and template scenarios.cf7453276, every step ofcheck-nvx-rs:75765b660remain byte-identical at090fbab88; the exact-pin tests pass.nvx-rsbuilt from the branch:d17c209d5on Windows/WHP, with OpenVMM75765b660:time-host-correctionran twice. Its published corrections matched host UTC's measured rate against the guest TSC within 0.04 to 0.12 ppm; the old reading left gaps of 0.24 to 0.93 ppm, twice the host's correction.nvx.py doctor --checks H3 H4 --ci-schedulepassed. H4 read -0.600 ppm for an adjustment of 10,000,006, and host UTC measured -0.612 ppm against the counter.032774707with the scenario's probe:time-host-correctionpassed 3 times on each backend.frequency_limited=1.565d1ebe5:nvx.py doctor --checks H1 H2 H3 H4 H6on the qualification schedule passed on Linux/KVM, Linux/MSHV, and Windows/WHP.cf7453276andea808fa91on Linux/MSHV:time-host-correction,time-abi-conformance,snapshot-core,restore-downtime,smp-snapshot, andcpu-profile-fallbackpassed.nvx.py doctor --checks H1 H2 H3 H4 --ci-schedulepassed.adjtimexto 0.03 ppm.STA_UNSYNCnorSTA_CLOCKERR, the Windows ones an applied time adjustment, and their corrections range from -76 to +6.9 ppm.ea808fa91, before the review's fixes, passed.032774707failed only where it found the Windows sign above.a91e5e5f6(40963908778) passed:azure-windows-3,time-host-correctionread the host's own correction as -52.8 ppm and published corrections that host UTC followed.vm_clone::a_clone_refuses_a_scratch_image_whose_upper_an_earlier_clone_usedon KVM. That test fails intermittently ondevas well (runtime-adapter: a_clone_refuses_a_scratch_image_whose_upper_an_earlier_clone_used fails intermittently #1020);dev's own push run at4d9e76d90failed it the same hour. A rerun passed.090fbab88passed on attempt 10: https://github.com/microsoft/openvmm/actions/runs/41015566000.4aeff73a8is https://github.com/microsoft/nvx/actions/runs/41077274125; its WHP jobs are waiting for offline runners.Merge microsoft/openvmm#4809 into
feature/microvm/dev, by fast-forwarding that branch to090fbab88, before merging this pull request.