Repository navigation
[DO NOT REVIEW] cpu_profile: pin amd.genoa.v2 for Genoa hosts without the TSA immunities - #4769
Merged
Pedro Henrique Penna (ppenna) merged 2 commits intoOct 27, 2026
Conversation
amd.genoa.v1 pins what Azure presents to the KVM of a GitHub-hosted
runner with an EPYC 9V74, CPUID 0x80000021 included: LFENCE
serialization and NoSmmCtlMsr in EAX (0x204), and the TSA immunities,
TSA_SQ_NO and TSA_L1_NO, in ECX (0x6). Not every Genoa host's hypervisor
presents them. On an Azure VM with the same CPU (family 25 model 17
stepping 1) whose root runs Linux with MSHV (Microsoft Hv
10.0.26100.9444), the host partition offers neither TSA immunity
(ProcessorFeatures1 0x50e00001ed), the root's 0x80000021 reads zero, and
its kernel reports TSA as "Vulnerable: Clear CPU buffers attempted, no
microcode". Every cold boot with --cpu-profile auto there fails before
the guest runs:
[E_PROFILE_UNSUPPORTED] the hypervisor's processor features cannot
present CPU profile amd.genoa.v1: they lack tsa_l1_no_support,
tsa_sq_no_support
and --cpu-fingerprint also finds CPUID 0x0 EAX at 0x1c, above the
supported 0xd, and 0x80000021 EAX bits 2 and 9 unsupported. As the time
ABI design anticipates for such a host, a later revision intersects the
fingerprints.
amd.genoa.v2 derives from two fingerprints: the runner's KVM fingerprint
that amd.genoa.v1 derives from (surface digest
sha256:68c11e9ed42a2e64267876eca0d21ba1083d24f36d5b4f9d891a53523646c2aa),
and that MSHV host's (surface digest
sha256:0d4f63812ed2feae52196f88a16733f54b3822389ef062c8a0c31cdb31083585),
whose CPUID and processor features test_support::GENOA_MSHV_CPUID and
GENOA_MSHV_HOST record:
cargo run -p cpu_profile --example derive_profile -- genoa 2 <kvm> <mshv>
That gives amd.genoa.v2, digest
sha256:8ee00e9ee8fd5defe3eebdc343733195d477f5f3449defa403f616d530a84839,
which is amd.genoa.v1 but for two differences:
- 0x80000021 reads zero: no LFENCE serialization, NoSmmCtlMsr, or TSA
immunities, as under amd.milan.v1. Linux guests still serialize
LFENCE through DE_CFG, whose LFENCE bit reads set under every AMD
profile, and report TSA as vulnerable.
- The maximum basic leaf is 0xd, that MSHV's, instead of 0x1c. The
leaves 0xe to 0x1c, which amd.genoa.v1 lists as zero, are out of
range.
Everything else is identical: XCR0 0x7, the features, the cache and TLB
descriptors, the address widths, and no pinned MSR.
Deriving it needed one fix to the registers' classes. The two hosts
disagree on CPUID 0x80000008 EDX, KVM 0 and MSHV 0x10000, and the policy
took that register to be descriptive, so the backends' single votes tied
("no majority for CPUID 0x80000008 EDX among the backends"). It holds
AMD's INVLPGB page count (bits 15:0) and RDPRU's largest register index
(bits 25:16), Intel reserves it, and both are limits: the class is now
Limits, so derivation takes their minimum, and a support check requires a
profile's to be within the host's. Every profile clears the register, so
neither a derivation that succeeded before nor a support check changes:
every pinned profile rederives identically, and the policy stays
openvmm-cpu-profile-policy/v1.
auto selects a generation's latest revision, so it now selects
amd.genoa.v2 on every Genoa host, GitHub's runners included. amd.genoa.v1
stays pinned: --cpu-profile amd.genoa.v1 still selects it, and its
snapshots still restore where it is supported.
pinned_data.rs, regenerated with generate_pinned from the eight files in
catalog order, gains amd.genoa.v2's block after amd.genoa.v1's and changes
nothing else but the array's length.
Tests:
- derive: amd.genoa.v2 is the policy's derivation of the recorded KVM
and MSHV hosts, both of which support it, and the MSHV host's surface
fails amd.genoa.v1 with exactly the three violations above. Rederiving a
pinned profile uses its own revision.
- hv_banks: the MSHV host's processor features cannot present
amd.genoa.v1, lacking tsa_l1_no_support and tsa_sq_no_support, and
present amd.genoa.v2.
- catalog: auto selects amd.genoa.v2 on Genoa hosts, and amd.genoa.v1
stays selectable by its ID.
- virt_whp: the time ABI tests' sample of the pinned profiles gains
amd.genoa.v2.
Validation:
- cargo test with Rust 1.95.0 on Windows: cpu_profile 115, virt 65,
virt_whp 36, openvmm_core 98, and openvmm_helpers 99 passed. clippy for
cpu_profile and virt_whp and rustdoc for cpu_profile are clean with
warnings denied, and xtask fmt passes.
- On the MSHV host above, with a musl release build of this change on
top of the streamed block snapshot stack (2b38c40), built through
NVX's platform build:
- --cpu-fingerprint passes on amd.genoa.v2, which auto selects
(NVX-CPU-PROFILE: status=pass), checking the entries outside the
profile on a partition configured from it.
- The --x-time-abi-verify preflight passes on auto with 1 and 4 VPs, and
still fails --cpu-profile amd.genoa.v1 on the TSA immunities.
- A 2-VP microVM boots on auto: its time ABI boot checks pass, its clock
synchronizes, and its guest reports TSA as "Vulnerable: No microcode".
- 15 guest-triggered snapshot captures and restores through NVX's broker
pass on auto, without a --cpu-profile argument: clone and continuation
snapshots, local, portable, and Blob-storage transfers, and two runs
that drain running commands first.
- Not run on GitHub-hosted runners: amd.genoa.v2 takes nothing from
amd.genoa.v1 that their KVM lacks, and the recorded runner's surface
supports it.
Part of microsoft/nvx#409.
Ported onto feature/microvm/dev (57d0a18) for microsoft/nvx#928: the
Guide conflict keeps this commit's sentences on Genoa's revisions and the
base's on auto's fallback to a host profile, and pinned_data.rs
regenerates identically.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
(cherry picked from commit d946e7a)
An Azure Standard_D8ads_v5 VM with an AMD EPYC 9V74 (family 25 model 17 stepping 1), whose WHP is Microsoft Hv 10.0.26100.32522 on Windows Server 2025, cannot cold-boot on amd.genoa.v1 (microsoft/nvx#928): [E_PROFILE_UNSUPPORTED] the hypervisor's processor features cannot present CPU profile amd.genoa.v1: they lack tsa_l1_no_support, tsa_sq_no_support and its --cpu-fingerprint (surface digest sha256:16be9bd6dcff0e889003df7c287ae9acf34d3a801edc2e4b31d6f8b2a3ebfd23) fails amd.genoa.v1 on the maximum basic leaf and 0x80000021, as the MSHV host that amd.genoa.v2 derives from does. test_support::GENOA_WHP_CPUID and GENOA_WHP_HOST record its CPUID and processor features. They are the Milan WHP host's but for the CPU's identity and its cache and TLB descriptors. amd.genoa.v2 serves that host as pinned: - hv_banks: its processor features cannot present amd.genoa.v1, lacking both TSA immunities, and present amd.genoa.v2. - check: its fingerprint fails amd.genoa.v1 with the violations that the host reported, and passes amd.genoa.v2, which auto selects, once a partition configured from the profile reads zero at CET's XSAVE components, as on the Milan WHP host. - derive: deriving revision 2 from the KVM, MSHV, and WHP hosts gives amd.genoa.v2's CPUID, XSAVE state, and MSRs, so the WHP host constrains nothing that the others do not, and amd.genoa.v2 keeps its digest and its provenance. Not run on that host: a cold boot, the time ABI preflight, and NVX's doctor and test-microvm. Part of microsoft/nvx#928 and microsoft/nvx#409. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
force-pushed
the
copilot/cpu-profile-genoa-v2
branch
from
October 27, 2026 21:52
b61b4b3 to
d2338ea
Compare
Pedro Henrique Penna (ppenna)
added a commit
to microsoft/nvx
that referenced
this pull request
Oct 27, 2026
Pin microsoft/openvmm#4769 at d2338ea22c36135b468e7f3ae168066b6c9efde9, two commits on 57d0a18b3, the previous pin, which is the head of feature/microvm/dev. amd.genoa.v1 pins what the KVM of the GitHub-hosted runner that it derives from presents on an EPYC 9V74: the basic leaves up to 0x1C, and LFENCE serialization, NoSmmCtlMsr, and the TSA immunities in CPUID 0x80000021. The Microsoft hypervisor of the Azure Genoa VMs fingerprinted so far presents none of them, under nested MSHV (#409) and nested WHP (#928) alike, so every cold boot with --cpu-profile auto there fails before the guest runs: [E_PROFILE_UNSUPPORTED] the hypervisor's processor features cannot present CPU profile amd.genoa.v1: they lack tsa_l1_no_support, tsa_sq_no_support The first commit pins amd.genoa.v2, amd.genoa.v1 without them, which auto now selects on every Genoa host; amd.genoa.v1 stays pinned, so --cpu-profile amd.genoa.v1 still selects it and its snapshots still restore. The second records the WHP host of #928 and tests that amd.genoa.v2 serves it as pinned. NVX's two copies of the catalog assumed one profile per generation. nvx-rs/src/host/cli/cpu_generations.json, which copies the identity of every pinned profile, gains amd.genoa.v2, and nvx-rs run's guidance lists each generation that the built-in profiles cover once. scripts/nvx_tools/time_abi.py's copy records the latest revision of each generation's profile, which doctor reports without OpenVMM, and its test compares every revision with the pinned profiles. doc/usage.md and doc/ci.md name amd.genoa.v2 as Genoa's profile. Fixes #928 Part of #409 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
to microsoft/nvx
that referenced
this pull request
Oct 27, 2026
Record the two commits that the previous commit pins as positions 348 and 349 of the microVM chain, and move the NVX pin to d2338ea22. Position 348 pins amd.genoa.v2, a second revision of the Genoa CPU profile that position 282 pins, and makes CPUID 0x80000008 EDX a limit of the derivation policy of positions 159-269. Position 349 records the nested-WHP Genoa host that amd.genoa.v2 serves as a test fixture. They add to the CPU profile work that no PR maps yet rather than fix mapped work, so they join positions 158-333, 341-343, 346, and 347 as unassigned. Add them to the chain and to the table of the commits after the mapped tip, and extend the scope. The pin is now 192 commits past the mapped tip. Positions 346 and 347 are no longer only a proposal: microsoft/openvmm#4767 merged them, so position 347, 57d0a18b3, is the head of feature/microvm/dev. Say so in the scope, and name microsoft/openvmm#4769 as the proposal of positions 348 and 349. Part of #928 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
merged commit Oct 27, 2026
d2338ea
into
feature/microvm/dev
106 of 108 checks passed
Pedro Henrique Penna (ppenna)
added a commit
to microsoft/nvx
that referenced
this pull request
Oct 28, 2026
Record the three commits that the previous commit pins as positions 350-352 of the microVM chain, and move the NVX pin to b92daa350. Positions 350-352 bound HttpBlob's requests in time, retry the ones that fail transiently on a new connection, and show them in inspect. They change only disk_blob, which upstream main and the fork base have alike and no other commit of the chain changes, so they can go upstream on their own; say so in the table's remarks. The pin is now 195 commits past the mapped tip. Positions 348 and 349 are no longer only a proposal: microsoft/openvmm#4769 merged them, so position 349, d2338ea22, is the head of feature/microvm/dev. Say so in the scope, and name microsoft/openvmm#4773 as the proposal of positions 350-352. Refs #170 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
to microsoft/nvx
that referenced
this pull request
Oct 28, 2026
Record the two commits that the previous commit pins as positions 350 and 351 of the microVM chain, and move the NVX pin to d7892ffa8. Position 350 tests that the virtio-fs device takes the state of a dormant filesystem slot into the device of an aggregate. Position 351 lets a platform restore bind an aggregate to the slot that the snapshot left dormant, with its children, policy paths, and owner, validated as at a cold boot. They add behavior rather than fix a mapped commit, and position 351 changes the dormant-slot restore of PR18's position 113, which position 293 limited to one --mount when it added aggregates, so they stay unassigned, like positions 346-349. Note in the table's remarks that assigning them means revisiting that work. The pin is now 194 commits past the mapped tip. Positions 348 and 349 are no longer only a proposal: microsoft/openvmm#4769 merged them, so position 349, d2338ea22, is the head of feature/microvm/dev. Say so in the scope, and name microsoft/openvmm#4775 as the proposal of positions 350 and 351. Part of #540 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
added a commit
to microsoft/nvx
that referenced
this pull request
Oct 28, 2026
Record the two commits that the previous commit pins as positions 350 and 351 of the microVM chain, and move the NVX pin to d7892ffa8. Position 350 tests that the virtio-fs device takes the state of a dormant filesystem slot into the device of an aggregate. Position 351 lets a platform restore bind an aggregate to the slot that the snapshot left dormant, with its children, policy paths, and owner, validated as at a cold boot. They add behavior rather than fix a mapped commit, and position 351 changes the dormant-slot restore of PR18's position 113, which position 293 limited to one --mount when it added aggregates, so they stay unassigned, like positions 346-349. Note in the table's remarks that assigning them means revisiting that work. The pin is now 194 commits past the mapped tip. Positions 348 and 349 are no longer only a proposal: microsoft/openvmm#4769 merged them, so position 349, d2338ea22, is the head of feature/microvm/dev. Say so in the scope, and name microsoft/openvmm#4775 as the proposal of positions 350 and 351. Part of #540 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pins
amd.genoa.v2, a second revision of the Genoa CPU profile, for the Genoa hosts whose hypervisor presents nothing in0x80000021and no basic leaf above0xd: the nested-MSHV host of microsoft/nvx#409 and the nested-WHP host of microsoft/nvx#928, both Azure VMs with an AMD EPYC 9V74. On both, every cold boot with--cpu-profile autofails before the guest runs:Based on
feature/microvm/dev. This branch is two commits directly on57d0a18b3, the head offeature/microvm/devsince #4767 landed, and the revision that NVX'sdevpins. It was rebased there frome68871cc6after #4767 landed:git range-diffshows identical patches, and only the first commit's port note changed, to name the new base.Cause
amd.genoa.v1pins what one GitHub-hosted runner's KVM offers on an Azure VM with an EPYC 9V74: the maximum basic leaf0x1c,LFENCEserialization and NoSmmCtlMsr in0x80000021EAX (0x204), and the TSA immunities, TSA_SQ_NO and TSA_L1_NO, in0x80000021ECX (0x6). The Microsoft hypervisor presents none of them to the partitions of these hosts, under nested MSHV (Microsoft Hv 10.0.26100.9444,Standard_D64als_v6) and nested WHP (10.0.26100.32522,Standard_D8ads_v5) alike, so both hosts' fingerprints failamd.genoa.v1on all three, and their processor features lack both TSA immunities.amd.genoa.v2(689577604)Enrique Saurez's commit
d946e7a8from nanvix/openvmm, cherry-picked with its authorship; its message describes it in full.amd.genoa.v2(sha256:8ee00e9ee8fd5defe3eebdc343733195d477f5f3449defa403f616d530a84839) derives from the runner's KVM fingerprint and the MSHV host's under the unchanged policy,openvmm-cpu-profile-policy/v1, and isamd.genoa.v1but for two differences:0x80000021reads zero, as underamd.milan.v1. Linux guests still serializeLFENCEthrough DE_CFG, whoseLFENCEbit reads set under every AMD profile, and report TSA as vulnerable.0xd. The leaves0xeto0x1c, whichamd.genoa.v1lists as zero, are out of range.Deriving it needed one fix to the registers' classes:
0x80000008EDX, AMD's INVLPGB page count and RDPRU's largest register index, is now a limit, whose derivation takes the minimum, instead of a descriptive register, on which the two hosts' single votes tied. Every pinned profile clears that register, so every pinned profile rederives identically.autoselects a generation's latest revision, so it selectsamd.genoa.v2on every Genoa host, GitHub's runners included.amd.genoa.v1stays pinned:--cpu-profile amd.genoa.v1still selects it, and its snapshots still restore where it is supported.The cherry-pick conflicted only in the snapshot guide, whose paragraph on the pinned profiles this branch's base has reworded since. The resolution keeps the commit's sentences on Genoa's revisions and the base's on
auto's fallback to a host profile.pinned_data.rsregenerates byte-identically withgenerate_pinned.The WHP host (
d2338ea22)Records the nested-WHP host of microsoft/nvx#928 as
test_support::GENOA_WHP_CPUIDandGENOA_WHP_HOST, from its--cpu-fingerprint(surface digestsha256:16be9bd6dcff0e889003df7c287ae9acf34d3a801edc2e4b31d6f8b2a3ebfd23). That WHP offers exactly the processor features of the Milan WHP host thatamd.milan.v1derives from, and its CPUID is that host's but for the CPU's identity and its cache and TLB descriptors.hv_banks::tests::the_genoa_mshv_and_whp_hosts_present_the_second_genoa_profile, which extends the MSHV host's test: neither host's processor features can presentamd.genoa.v1, both lackingtsa_l1_no_supportandtsa_sq_no_support, and both presentamd.genoa.v2.check::tests::the_genoa_whp_host_supports_the_second_genoa_profile: the fingerprint failsamd.genoa.v1with exactly the violations that the host reported, and passesamd.genoa.v2, whichautoselects, once a partition configured from the profile reads zero at CET's XSAVE components,0xd.11and0xd.12, as on the Milan WHP host.derive::tests::the_whp_host_adds_nothing_to_the_second_genoa_profile: deriving revision 2 from the KVM, MSHV, and WHP hosts givesamd.genoa.v2's CPUID, XSAVE state, and MSRs, so the WHP host constrains nothing that the others do not, andamd.genoa.v2keeps its digest and its provenance.Validation
d2338ea22:cargo clippy --all-targets -p cpu_profile -p virt_whp -- -D warnings,cargo doc --no-deps -p cpu_profile -p virt_whpwith-D warnings,cargo nextest run --profile agent -p cpu_profile -p virt_whp(162 passed, 17 skipped), andcargo xtask fmt --fix(clean). Before the rebase, the same checks passed atb61b4b363and, with 160 tests, at8bd425136.d946e7a8's author validated it, on an earlier base, on the MSHV host of Qualify the AMD CPU profiles on MSHV, WHP, and bare-metal hosts, and pin profiles for AMD client CPUs nvx#409, all onauto: the fingerprint check, the time ABI preflight with 1 and 4 VPs, a 2-VP boot, and 15 snapshot captures and restores.d2338ea22, with the coordinated changes to NVX's copies of the catalog, and runs NVX's CI matrix with it.Part of microsoft/nvx#409 and microsoft/nvx#928.