Skip to content

igvmfilegen: Add Linux direct boot support with native VP context#3103

Open
jinankjain wants to merge 4 commits intomicrosoft:mainfrom
jinankjain:igvm_direct_boot
Open

igvmfilegen: Add Linux direct boot support with native VP context#3103
jinankjain wants to merge 4 commits intomicrosoft:mainfrom
jinankjain:igvm_direct_boot

Conversation

@jinankjain
Copy link
Copy Markdown

This series adds the ability to generate IGVM files that boot a Linux kernel
directly at VTL0 without a paravisor, using the hypervisor-agnostic
IgvmPlatformType::NATIVE platform type and IgvmNativeVpContextX64 VP
context format.

Motivation

Today, igvmfilegen can produce IGVM files for guests running under Hyper-V's
VBS isolation, using IgvmPlatformType::VSM_ISOLATION and VBS-specific VP
context headers. This works well for Hyper-V but ties the generated files to
a single hypervisor's isolation model.

For scenarios like Linux direct boot on non-Hyper-V hypervisors (e.g., KVM),
we need a hypervisor-agnostic representation. The IGVM specification defines
IgvmPlatformType::NATIVE and IgvmNativeVpContextX64 for exactly this
purpose — they describe initial VP state as a flat set of architectural
registers without assuming any particular hypervisor interface.

Approach

The changes are structured as four incremental commits:

  1. Add Linux direct boot loading logic — Implements the core boot protocol
    setup: GDT, identity-mapped page tables, Linux zero page (boot_params),
    setup_header fixups, and IGVM parameter areas for the command line, memory
    map, and SLIT/MADT/SRAT ACPI tables. This commit uses the existing VBS VP
    context path and works end-to-end on Hyper-V.
  2. Add native VP context builder — Introduces NativeVpContext, a new
    VpContextBuilder implementation that maps x86 registers into the
    IgvmNativeVpContextX64 flat struct. Registers not representable in the
    native format (MTRRs, PAT) are silently skipped. This is purely additive —
    no existing behavior changes.
  3. Support NATIVE platform type in IgvmLoader — Extends IgvmLoader to
    emit an IgvmPlatformType::NATIVE platform header and select IGVM revision
    V2 (required for native VP context) when native mode is active. Again purely
    additive.
  4. Activate native VP context for Linux direct boot — Wires everything
    together: when generating an IGVM file for a Linux image with no isolation
    (isolation_type: "none"), the loader now automatically uses the native VP
    context builder and NATIVE platform type instead of VBS. No manifest file
    changes are needed — the existing Image::Linux + isolation_type: "none"
    combination is sufficient to trigger the new path.

Trade-offs

IgvmNativeVpContextX64 has a fixed register layout that does not include
MTRRs or PAT. This means the generated IGVM files rely on the hypervisor's
default MTRR/PAT configuration. For KVM and other mainstream hypervisors this
is fine — they set up reasonable defaults. The VBS path remains available for
Hyper-V scenarios that need full register control.

Testing done

I used the following manifest.json and resource.json to generate the igvm file and use that to boot a guest on CloudHypervisor with KVM as the hypervisor:

 {
      "guest_arch": "x64",
      "guest_configs": [
          {
              "guest_svn": 1,
              "max_vtl": 0,
              "isolation_type": "none",
              "image": {
                  "linux": {
                      "use_initrd": false,
                      "command_line": "console=ttyS0",
                      "memory_size": 536870912
                  }
              }
          }
      ]
 }

{
     "resources": {
         "linux_kernel": "/home/jinankjain/dev/linux/vmlinux"
     }
}
./target/debug/igvmfilegen manifest --manifest manifest.json --resources resource.json -o output.bin
2026-03-23T13:50:20.795829Z  INFO igvmfilegen: Building igvm file with given config and resources config=Config { guest_arch: X64, guest_configs: [GuestConfig { guest_svn: 1, max_vtl: 0, isolation_type: None, image: Linux(LinuxImage { use_initrd: false, command_line: "console=ttyS0" }) }] } resources=Resources { resources: {LinuxKernel: "/home/jinankjain/dev/linux/vmlinux"} }
2026-03-23T13:50:20.845634Z  INFO igvmfilegen::file_loader: IGVM file isolation isolation=None
2026-03-23T13:50:20.845679Z  INFO igvmfilegen::file_loader: IGVM file layout:
2026-03-23T13:50:20.845692Z  INFO igvmfilegen::file_loader: 0x1000 - 0x2000 tag="linux-zeropage" size_bytes=4096
2026-03-23T13:50:20.845706Z  INFO igvmfilegen::file_loader: 0x2000 - 0x3000 tag="default-gdt" size_bytes=4096
2026-03-23T13:50:20.845718Z  INFO igvmfilegen::file_loader: 0x3000 - 0x9000 tag="linux-pagetables" size_bytes=24576
2026-03-23T13:50:20.845729Z  INFO igvmfilegen::file_loader: 0xa000 - 0xb000 tag="linux-cmdline" size_bytes=4096
2026-03-23T13:50:20.845740Z  INFO igvmfilegen::file_loader: 0xb000 - 0xf000 tag="linux-memory-map" size_bytes=16384
2026-03-23T13:50:20.845750Z  INFO igvmfilegen::file_loader: 0xf000 - 0x10000 tag="linux-madt" size_bytes=4096
2026-03-23T13:50:20.845762Z  INFO igvmfilegen::file_loader: 0x10000 - 0x12000 tag="linux-srat" size_bytes=8192
2026-03-23T13:50:20.845773Z  INFO igvmfilegen::file_loader: 0x12000 - 0x13000 tag="linux-slit" size_bytes=4096
2026-03-23T13:50:20.845784Z  INFO igvmfilegen::file_loader: 0x13000 - 0x14000 tag="linux-pptt" size_bytes=4096
2026-03-23T13:50:20.845794Z  INFO igvmfilegen::file_loader: 0x1000000 - 0x2b76000 tag="linux-kernel" size_bytes=28794880
2026-03-23T13:50:20.845805Z  INFO igvmfilegen::file_loader: 0x2c00000 - 0x387d000 tag="linux-kernel" size_bytes=13094912
2026-03-23T13:50:22.169612Z  INFO igvmfilegen: Debug validation of serialized IGVM file.
2026-03-23T13:50:23.191894Z  INFO igvmfilegen: Writing output IGVM file path=output.bin
2026-03-23T13:50:23.242650Z  INFO igvmfilegen: Writing output map file path=output.bin.map

@jinankjain jinankjain requested a review from a team as a code owner March 23, 2026 13:50
@jstarks
Copy link
Copy Markdown
Member

jstarks commented Mar 23, 2026

What about ARM64?

@chris-oo
Copy link
Copy Markdown
Member

I'm not sure we've yet defined the native type for ARM64 in igvm upstream...

Copy link
Copy Markdown
Member

@chris-oo chris-oo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd probably want us to add support for this in openvmm so we can confirm this keeps working as well. I don't think that this is that hard to do, could you do that in a follow up?


fn import_vp_register(&mut self, register: X86Register) {
if !Self::is_supported(&register) {
tracing::debug!(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems like it could be a pretty big "gotcha" in the future. I don't know the best way to fix this, other than warn or fail the load (but that would require loader changes).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you say, should we fail hard on this?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes we should hard fail. but does this mean that the existing loaders don't work?

hex = { workspace = true, features = ["serde"] }
igvm.workspace = true
igvm_defs.workspace = true
igvm_defs = { workspace = true, features = ["unstable"] }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fascinating, i though we did this already.

@jinankjain
Copy link
Copy Markdown
Author

I'm not sure we've yet defined the native type for ARM64 in igvm upstream...

Agreed ARM64 is not yet supported on upstream.

Jinank Jain added 4 commits March 25, 2026 03:50
Add the ability to generate IGVM files that boot a Linux kernel directly
at VTL0 without a paravisor. Previously, the `Image::Linux` config
variant only loaded the kernel and initrd into memory but did not set up
the boot environment, so it only worked as a VTL0 payload under OpenHCL.

The new `load_linux_direct_boot_config` trait method (with x86_64 and
aarch64 implementations) sets up everything the kernel needs to boot:

x86_64:
- GDT and 4GB identity-mapped page tables
- Linux boot_params zero page (setup header, command line pointer,
  initrd location)
- IGVM parameter areas for VMM-provided data (command line, memory map,
  MADT, SRAT, SLIT, PPTT)
- VP registers for 64-bit long mode entry (CR0, CR3, CR4, EFER, RIP,
  RSI, PAT, MTRRs)

aarch64:
- Delegates to the existing set_direct_boot_registers_arm64 helper

Signed-off-by: Jinank Jain <jinankjain@meta.com>
Add a NativeVpContext builder that emits IgvmDirectiveHeader::X64NativeVpContext
instead of the Hyper-V specific X64VbsVpContext. This uses the fixed-layout
IgvmNativeVpContextX64 struct which is hypervisor-agnostic, making it suitable
for non-isolated guests on platforms like KVM.

The builder silently skips registers that have no corresponding field in
IgvmNativeVpContextX64 (PAT, MTRRs), and deduplicates data segment registers
(DS/ES/FS/GS/SS) since they all map to a single set of fields in the native
context.

The plumbing to select the native builder is added via a new
use_native_vp_context parameter on IgvmLoader::new() and a
create_native_vp_context() method on the IgvmLoaderRegister trait, but no
caller enables it yet — this is purely additive with no behavioral change.

Signed-off-by: Jinank Jain <jinankjain@meta.com>
When native VP context is enabled, emit IgvmPlatformType::NATIVE
instead of VSM_ISOLATION in the IGVM platform header, and use IGVM
V2 file format which is required by the spec for native VP context
support.

No behavioral change yet as no caller enables native VP context.

Signed-off-by: Jinank Jain <jinankjain@meta.com>
Activate the native VP context builder when generating IGVM files for
Linux direct boot without isolation. This produces IGVM files with
IgvmPlatformType::NATIVE and X64NativeVpContext instead of the
Hyper-V specific VSM_ISOLATION and X64VbsVpContext, making the
generated files hypervisor-agnostic.

Signed-off-by: Jinank Jain <jinankjain@meta.com>
@jinankjain
Copy link
Copy Markdown
Author

I'd probably want us to add support for this in openvmm so we can confirm this keeps working as well. I don't think that this is that hard to do, could you do that in a follow up?

I think I have the openvmm changes ready let me post them as well as part of this series.

@chris-oo
Copy link
Copy Markdown
Member

The description is a bit wordy, can we tighten it up a bit? Could you elaborate a bit more on the broader reason for "why" for this change too?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants