Skip to content

Qualify the AMD CPU profiles on MSHV, WHP, and bare-metal hosts, and pin profiles for AMD client CPUs #409

Description

Summary

#396 added AMD support to the time ABI's CPU profiles. #404 pinned amd.milan.v1 from one nested-WHP fingerprint. #412 pinned amd.genoa.v1 and amd.turin.v1 from KVM fingerprints of GitHub-hosted Actions runners, and qualified all three profiles on KVM on those runners. What remains needs AMD hosts that neither the configured development hosts nor the CI runners provide:

Gap Effect
No AMD host has run MSHV The AMD paths of the MSHV backend are unit-tested only: the per-VP 0x8000001E results and the HWCR and DE_CFG intercepts
Each AMD profile derives from one backend of one Azure VM type: Milan from WHP, and Genoa and Turin from KVM A host whose hypervisor lacks one of a profile's features fails with E_PROFILE_UNSUPPORTED, which names --cpu-profile host, until a later revision intersects its fingerprint. Genoa and Turin are unverified on MSHV and WHP, and Milan on MSHV
No bare-metal AMD host Azure offers its VMs no IBRS, STIBP, or SSBD, so no AMD profile has them, and their Linux guests mitigate Spectre v2 with retpolines. On Genoa, Azure presents the TSA immunities of 0x80000021 ECX. amd.genoa.v1 pins them, so it fails on a bare-metal Genoa host whose KVM, under a host kernel that applies the VERW mitigation, does not report them
No profile for AMD client CPUs or other server models A cold boot with auto fails with E_PROFILE_HOST_UNKNOWN, and --cpu-profile host serves them. Client CPUs: the Ryzen models of Zen 3, Zen 4, and Zen 5. Other server models: Bergamo, Siena, and Turin Dense

Plan

  • Fingerprint Milan, Genoa, and Turin on MSHV and WHP, and on bare-metal hosts where available. For MSHV, use Azure Linux with nested MSHV on Dasv5, Dasv6, and Dasv7 VMs. Qualify those hosts with nvx.py doctor and nvx.py test-microvm, and derive v2 revisions that intersect the fingerprints of every backend.
    • Fingerprint Genoa under nested MSHV on an Azure Dalsv6 VM. It fails amd.genoa.v1 on the TSA immunities, the maximum basic leaf, and 0x80000021 EAX (Qualify the AMD CPU profiles on MSHV, WHP, and bare-metal hosts, and pin profiles for AMD client CPUs #409 (comment)).
    • Pin amd.genoa.v2, which intersects that fingerprint with the runner's KVM fingerprint (nanvix/openvmm branch esaurez/cpu-profile-genoa-v2-20261007), and promote it into NVX with the catalog copy in scripts/nvx_tools/time_abi.py, its test, and the docs that name amd.genoa.v1.
    • Qualify that host on amd.genoa.v2 with nvx.py doctor and nvx.py test-microvm --backend mshv.
    • Fingerprint Turin under MSHV and WHP: amd.turin.v1 pins the same maximum basic leaf and 0x80000021 values as amd.genoa.v1.
  • Qualify the MSHV backend's per-VP 0x8000001E results and its HWCR and DE_CFG intercepts on an AMD MSHV host.
  • Collect WHP fingerprints of Ryzen hosts from developers, and pin one profile per client microarchitecture. openvmm --hypervisor whp --cpu-fingerprint fingerprint.json writes the fingerprint before it fails with E_PROFILE_HOST_UNKNOWN.

Until then, run --cpu-profile host boots the hosts that no built-in profile serves.

Activity

  1. ppenna commented on Oct 8, 2026

    @ppenna
    ContributorAuthor

    amd.genoa.v1 fails on Genoa under nested MSHV on Azure

    An Azure Dalsv6 VM (Standard_D64als_v6, EPYC 9V74, 25/17 stepping 1), whose Azure Linux 3.0 root partition (6.6.148-200.mshv-b1f02da.azl3) runs on a nested Microsoft hypervisor (10.0.26100.9444), cannot cold-boot a microVM with --cpu-profile auto. With v0.1.0-dev.f813dc76cd23, whose OpenVMM is the revision that dev pins (3e1f5bd4), every cold boot 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
    

    Cause

    amd.genoa.v1 pins what one GitHub-hosted runner's KVM offers on an Azure VM with the same CPU. The nested hypervisor's partitions, the root included, see less:

    CPUID amd.genoa.v1 (the runner's KVM) This host's MSHV
    0x0 EAX, the maximum basic leaf 0x1c 0xd
    0x80000021 EAX: LFENCE serialization (bit 2) and NoSmmCtlMsr (bit 9) 0x204 0
    0x80000021 ECX: TSA_SQ_NO (bit 1) and TSA_L1_NO (bit 2) 0x6 0

    The TSA immunities are only the first check to fail. The host partition's processor features (ProcessorFeatures1 0x50e00001ed) offer none of the bits that control 0x80000021, so a cold boot stops there, but the support check that follows would also fail on the other two rows: a hypervisor that added only the TSA immunities would still fail amd.genoa.v1. --cpu-fingerprint reports all three (surface digest sha256:0d4f63812ed2feae52196f88a16733f54b3822389ef062c8a0c31cdb31083585). The root's kernel reports TSA as Vulnerable: Clear CPU buffers attempted, no microcode.

    amd.milan.v1, derived from nested WHP on Azure, has the same shape: maximum basic leaf 0xd and nothing in 0x80000021. The gap is therefore likely in what the Microsoft hypervisor presents to partitions on AMD CPUs, not in this VM. amd.turin.v1 pins the same maximum basic leaf and 0x80000021 values as amd.genoa.v1, so Turin hosts on MSHV or WHP likely fail the same way; that is unverified.

    --cpu-profile host boots on this host (amd.host.v1), but doctor never qualifies a host profile.

    Fix in progress

    The nanvix/openvmm branch esaurez/cpu-profile-genoa-v2-20261007 (d946e7a8, no pull request yet) pins amd.genoa.v2, derived from the runner's KVM fingerprint and this host's MSHV fingerprint, which its test_support::GENOA_MSHV_CPUID and GENOA_MSHV_HOST record. It is amd.genoa.v1 with nothing in 0x80000021 and the maximum basic leaf 0xd, so its Linux guests report TSA as vulnerable, as under amd.milan.v1. auto selects it on every Genoa host. amd.genoa.v1 stays selectable by ID, so its snapshots still restore where it is supported.

    • Its author validated a build of it on this host, all on auto: the fingerprint check passes, the time ABI preflight passes with 1 and 4 VPs, a 2-VP guest boots, and snapshot captures and restores pass. The host's surface digest has not changed since.
    • The commit applies cleanly to OpenVMM's main (3e1f5bd4), where cargo test -p cpu_profile (115 tests) and virt_whp's time ABI tests (24, with 8 that need hardware ignored) pass on Windows.

    Promoting it into NVX takes more than the gitlink. With amd.genoa.v2 pinned, test_the_catalog_copy_matches_openvmm_pinned_profiles fails, as it should on a second revision: NVX's copy of the catalog (CPU_GENERATIONS in scripts/nvx_tools/time_abi.py) names one profile per generation, always v1 (CpuGeneration.profile_id), which doctor --no-openvmm reports. doc/usage.md, doc/design/time-abi.md, and doc/ci.md also name amd.genoa.v1 as Genoa's profile.

    This host can also serve the plan's qualification of the MSHV backend's AMD paths (per-VP 0x8000001E, HWCR, and DE_CFG).

    Reproduction

    $REL is the extracted nvx-0.1.0-linux-mshv package of v0.1.0-dev.f813dc76cd23.

    $ $REL/bin/openvmm --machine microvm --hypervisor mshv --processors 1 --memory 256M \
        --kernel $REL/guest/vmlinux --initrd $REL/guest/initramfs.cpio.gz --x-time-abi-verify
    NVX-TIME-ABI-VERIFY: v=1 status=fail backend=mshv code=E_PROFILE_UNSUPPORTED detail="failed to launch vm worker: ... [E_PROFILE_UNSUPPORTED] the hypervisor's processor features cannot present CPU profile amd.genoa.v1: they lack tsa_l1_no_support, tsa_sq_no_suppo..."
    
    $ $REL/bin/openvmm --hypervisor mshv --cpu-fingerprint fingerprint.json
    NVX-CPU-PROFILE: status=fail backend=mshv generation=genoa profile=amd.genoa.v1 profile_digest=sha256:894ac647... surface_digest=sha256:0d4f6381... host_invariant_tsc=no code=E_PROFILE_UNSUPPORTED detail="the backend does not support CPU profile amd.genoa.v1: CPUID 0x0 EAX[31:0] is 0x1c, above the supported 0xd; CPUID 0x80000021 EAX bits 2, 9 are not supported; CPUID 0x80000021 ECX bits 1, 2 are not supported; ..."
    
    $ $REL/bin/openvmm --machine microvm --hypervisor mshv --processors 1 --memory 256M \
        --kernel $REL/guest/vmlinux --initrd $REL/guest/initramfs.cpio.gz --x-time-abi-verify \
        --cpu-profile host
    NVX-TIME-ABI-VERIFY: v=1 status=ok backend=mshv cpu_profile=amd.host.v1 tsc_hz=2596150073 native_tsc_hz=2596150073 lapic_hz=200000000 msr_route=ExitToVmm sync=FrozenWrite

    The fingerprint check's elided entries, which lie outside the profile, come from the fingerprint's probe partition, which enables every feature: the check reads them there because amd.genoa.v1 already failed. On amd.genoa.v2, it reads them on a partition configured from the profile, and passes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions