Skip to content

feat(runtime): support nested virtualization on Windows x86_64 hosts - #10

Draft
olebhansen wants to merge 2 commits into
main-digdirfrom
feat/windows-nested-virt
Draft

olebhansen wants to merge 2 commits into
main-digdirfrom
feat/windows-nested-virt

Conversation

@olebhansen

@olebhansen olebhansen commented Oct 25, 2026 •

Copy link
Copy Markdown

Status

This is a draft for local use, not intended to be merged. As agreed in digdir/digdir-agents#173, Windows support should come from upstream. Upstream's open pull request for nested virtualization covers Windows x86_64 on msb_krun 0.1.42. It goes further than this PR, with complete Windows timer state in snapshots, nested snapshots, and a Hyper-V-enabled Windows firmware bundle. Until that work reaches a fork sync, this branch lets Windows users patch digdir-agents locally to get nestedSandboxes. Close it when the fork syncs to an upstream release that contains that work.

The branch is rebased onto 0.7.11-digdir.1 (9e43b128). Builds pinned to the earlier commit 50eb730e should move to the new head.

Changes

Nested virtualization (nested_virt) is refused on Windows on main-digdir, because crates/runtime/lib/nested_virt.rs only accepts Linux x86_64 and Apple silicon hosts.

  1. chore(deps): bump libkrun to 0.1.42. msb_krun 0.1.42 sets WHvPartitionPropertyCodeNestedVirtualization on WHP partitions when nesting is enabled. 0.1.41 only left VMX/SVM in the guest CPUID. The bump also changes Windows x86_64 full snapshots (see Compatibility).
  2. feat(runtime): support nested virtualization on Windows x86_64 hosts.
    • host_support() on Windows x86_64 creates a one-vCPU WHP partition with nesting and xAPIC emulation, sets it up and deletes it. That is the configuration libkrun uses, and WHP refuses nesting at setup without the local APIC emulation. WinHvPlatform.dll is loaded at run time, as Hypervisor.framework is on macOS.
    • A new launch capability, nested_virt_windows. Older Windows runtimes advertise nested_virt but refuse nesting only once the VM starts, so on Windows x86_64 the SDK requires nested_virt_windows before replacing, changing or starting a nested sandbox.
    • Docs, COMPATIBILITY.md, and a step in the Windows CI job that runs the host-check tests.

The guest kernel needs no change. The released libkrunfw-windows-x86_64.dll is built from the Linux x86_64 config and already has kvm_intel and kvm_amd built in.

Compatibility

  • Nesting: with an older Windows runtime, the SDK refuses with upgrade-required before it touches the sandbox; verified against the released v0.7.8-digdir.2 msb.exe. Other hosts ignore the new capability.
  • Windows full snapshots: WHP execution state now records the emulated PIT (backend ABI 2). This runtime refuses full snapshots, forks and branches captured by earlier Windows runtimes, and earlier runtimes refuse the new ABI. Recovery is to restart from the snapshot's disks and capture again. digdir-agents uses no snapshots.

Evidence

On Windows 11 Enterprise 26200, Intel Core Ultra 7 155H, VBS/HVCI on:

  • After the rebase onto 0.7.11-digdir.1:
    • MSB_TEST_EXPECT_NESTED_VIRT=1 cargo test -p microsandbox-runtime --lib nested_virt passes, as do the SDK's nested_virt lib tests and cargo clippy -p microsandbox-cli -p microsandbox-runtime -p microsandbox -- -D warnings.
    • Both tests in sdk/rust/tests/nested_virt.rs pass against the msb.exe built from this branch, with the libkrunfw-windows-x86_64.dll from v0.7.11-digdir.1 and MSB_TEST_EXPECT_NESTED_VIRT=1. Run the test binary directly, not through cargo test (see Known gaps).
  • Before the rebase:
    • Inside a nested Debian sandbox, the Linux msb from v0.7.8-digdir.2 ran msb run alpine in about 3 s. The inner guest logs Hypervisor detected: KVM.
    • An Agent with nestedSandboxes: required, started by a host agentd built against this branch, ran T3 Code. T3 Code created nested worker Agents through agentctl inside it (L1 Linux microsandbox on the guest's /dev/kvm), and the first was Ready in about a minute, including the runtime download and image pull. T3 Code then connected to a worker over SSH.

Known gaps:

  • On Windows, cargo test runs tests inside a kill-on-close job object that does not allow breakaway. The SDK spawns detached runtimes with CREATE_BREAKAWAY_FROM_JOB, so under cargo test, create_detached() and modify().restart() fail with PermissionDenied (os error 5). That made nested_virt_can_be_modified_on_an_existing_sandbox look broken in the first version of this description; it passes when the test binary runs directly. This is unrelated to nesting and exists on main-digdir too. A fallback without breakaway would be a separate change.
  • AMD Windows was not tested here. Upstream's qualification covers it.
  • Hosted CI runners probably lack nesting, so CI only exercises the probe.

馃 Generated with Claude Code

Ole Hansen and others added 2 commits October 26, 2026 09:57
msb_krun 0.1.42 can enable nested virtualization in WHP partitions, which
Windows hosts need before a sandbox can opt in to it.

It also changes Windows x86_64 full snapshots: WHP execution state now carries
the emulated PIT and uses backend state ABI 2. This runtime refuses earlier
Windows full snapshots with libkrun's missing-PIT error, and earlier runtimes
refuse the new ABI; disk-only snapshots and other hosts are unchanged. Windows
guests also boot with tsc_early_khz from the WHP processor clock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Windows host check now accepts Windows x86_64 when the Windows Hypervisor
Platform sets up a one-vCPU partition with nesting and xAPIC emulation enabled,
the configuration libkrun uses. WHP refuses nesting at setup without the local
APIC emulation. WinHvPlatform.dll is loaded at run time, as Hypervisor.framework
is on macOS, so processes that link the runtime still start on hosts without the
optional feature.

Older Windows runtimes advertise the nested_virt capability but refuse nesting
once the VM starts, after replace or a modify restart has already changed the
sandbox. Runtimes now also advertise nested_virt_windows, and on Windows x86_64
the SDK requires it before replacing, changing or starting a nested sandbox.
The launch key and record field are unchanged.

The Windows CI job runs the host check tests, which accept either result on
hosted runners. MSB_TEST_EXPECT_NESTED_VIRT now also makes the unit test fail
when a host expected to nest is refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@olebhansen
olebhansen force-pushed the feat/windows-nested-virt branch from 50eb730 to ba6de0e Compare October 26, 2026 10:10
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.

1 participant