Skip to content

Commit b1ab4bb

Browse files
hikejsclaude
andcommitted
feat(windows): merge Windows WHPX backend and virtio device implementations
Merge branch 'chore/windows-ci-smoke-validation' into main Includes: - WHPX hypervisor backend (vstate.rs, whpx_vcpu.rs) - virtio Windows backends: balloon, console, rng, vsock, blk, net, snd, fs - TSI (Transparent Socket Impersonation) for vsock: TCP/UDP/Named Pipes (Phases 1-5) - virtiofs Windows passthrough (4 phases, production-ready) - credit-based flow control and DGRAM support for vsock - WHPX smoke tests (13 tests) and CI workflow - Windows eventfd, stdin reader, serial output wiring - vm-memory vendored with Windows mmap support Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2 parents 48a3ea6 + 68de7f3 commit b1ab4bb

130 files changed

Lines changed: 27369 additions & 482 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/windows_ci.yml

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
name: Windows CI
2+
on:
3+
pull_request:
4+
workflow_dispatch:
5+
inputs:
6+
run_whpx_smoke:
7+
description: Run WHPX smoke tests on self-hosted runner
8+
required: false
9+
type: boolean
10+
default: false
11+
whpx_test_filter:
12+
description: Optional cargo test filter for WHPX smoke
13+
required: false
14+
type: string
15+
default: test_whpx_
16+
rootfs_dir:
17+
description: Optional rootfs dir path on self-hosted runner
18+
required: false
19+
type: string
20+
default: ''
21+
cleanup_rootfs:
22+
description: Remove rootfs directory after smoke run
23+
required: false
24+
type: boolean
25+
default: false
26+
max_rootfs_age_hours:
27+
description: Rebuild rootfs if marker age exceeds this value
28+
required: false
29+
type: string
30+
default: '168'
31+
dry_run_rootfs_decision:
32+
description: Only evaluate rootfs reuse/rebuild decision and exit
33+
required: false
34+
type: boolean
35+
default: false
36+
fail_if_rootfs_rebuild:
37+
description: Fail run if rootfs decision is rebuild
38+
required: false
39+
type: boolean
40+
default: false
41+
rootfs_marker_format:
42+
description: Rootfs marker format/version used for reuse checks
43+
required: false
44+
type: string
45+
default: libkrun-windows-smoke-rootfs-v1
46+
compatible_rootfs_marker_formats:
47+
description: Additional compatible marker formats (comma-separated)
48+
required: false
49+
type: string
50+
default: ''
51+
promote_compatible_marker:
52+
description: Rewrite compatible marker to primary marker format
53+
required: false
54+
type: boolean
55+
default: true
56+
57+
jobs:
58+
windows-build-and-tests:
59+
name: Windows build and tests
60+
runs-on: windows-latest
61+
continue-on-error: true
62+
steps:
63+
- uses: actions/checkout@v4
64+
65+
- name: Setup Rust toolchain
66+
uses: dtolnay/rust-toolchain@stable
67+
with:
68+
targets: x86_64-pc-windows-msvc
69+
70+
- name: Create a fake init
71+
shell: pwsh
72+
run: |
73+
New-Item -ItemType File -Path "init/init" -Force | Out-Null
74+
75+
- name: Build check (Windows target)
76+
run: cargo check -p utils -p polly -p devices -p vmm -p libkrun --target x86_64-pc-windows-msvc
77+
continue-on-error: true
78+
79+
- name: Utils tests (Windows)
80+
run: cargo test -p utils --target x86_64-pc-windows-msvc --lib
81+
continue-on-error: true
82+
83+
- name: Polly tests
84+
run: cargo test -p polly --target x86_64-pc-windows-msvc --lib
85+
continue-on-error: true
86+
87+
- name: VMM tests (Windows)
88+
run: cargo test -p vmm --target x86_64-pc-windows-msvc --lib
89+
continue-on-error: true
90+
91+
windows-whpx-smoke:
92+
name: Windows WHPX smoke (manual)
93+
if: github.event_name == 'workflow_dispatch' && inputs.run_whpx_smoke
94+
runs-on: [self-hosted, windows, hyperv]
95+
steps:
96+
- uses: actions/checkout@v4
97+
98+
- name: Setup Rust toolchain
99+
uses: dtolnay/rust-toolchain@stable
100+
with:
101+
targets: x86_64-pc-windows-msvc
102+
103+
- name: Create a fake init
104+
shell: pwsh
105+
run: |
106+
New-Item -ItemType File -Path "init/init" -Force | Out-Null
107+
108+
- name: WHPX smoke suite
109+
shell: pwsh
110+
run: |
111+
$rootfsArgs = @()
112+
$cleanupArgs = @()
113+
$dryRunArgs = @()
114+
$failIfRebuildArgs = @()
115+
$promoteArgs = @()
116+
if ("${{ inputs.rootfs_dir }}") {
117+
$rootfsArgs = @("-RootfsDir", "${{ inputs.rootfs_dir }}")
118+
}
119+
if ("${{ inputs.cleanup_rootfs }}" -eq "true") {
120+
$cleanupArgs = @("-CleanupRootfs")
121+
}
122+
if ("${{ inputs.dry_run_rootfs_decision }}" -eq "true") {
123+
$dryRunArgs = @("-DryRunRootfsDecision")
124+
}
125+
if ("${{ inputs.fail_if_rootfs_rebuild }}" -eq "true") {
126+
$failIfRebuildArgs = @("-FailIfRootfsRebuild")
127+
}
128+
if ("${{ inputs.promote_compatible_marker }}" -eq "true") {
129+
$promoteArgs = @("-PromoteCompatibleMarker")
130+
}
131+
./tests/windows/run_whpx_smoke.ps1 -Target x86_64-pc-windows-msvc -TestFilter "${{ inputs.whpx_test_filter }}" -LogDir "$env:RUNNER_TEMP/libkrun-whpx-smoke" -RootfsMarkerFormat "${{ inputs.rootfs_marker_format }}" -CompatibleRootfsMarkerFormats "${{ inputs.compatible_rootfs_marker_formats }}" -MaxRootfsAgeHours "${{ inputs.max_rootfs_age_hours }}" @rootfsArgs @cleanupArgs @dryRunArgs @failIfRebuildArgs @promoteArgs
132+
133+
- name: Publish WHPX smoke summary
134+
if: always()
135+
shell: pwsh
136+
run: |
137+
$summaryFile = "$env:RUNNER_TEMP/libkrun-whpx-smoke/summary.txt"
138+
$summaryJsonFile = "$env:RUNNER_TEMP/libkrun-whpx-smoke/summary.json"
139+
$phaseFile = "$env:RUNNER_TEMP/libkrun-whpx-smoke/phases.log"
140+
141+
if ((-not (Test-Path $summaryFile)) -and (-not (Test-Path $summaryJsonFile))) {
142+
"## Windows WHPX smoke`n`nFAIL: summary artifact not found." >> $env:GITHUB_STEP_SUMMARY
143+
exit 0
144+
}
145+
146+
$summary = @{}
147+
if (Test-Path $summaryJsonFile) {
148+
$json = Get-Content $summaryJsonFile -Raw | ConvertFrom-Json
149+
foreach ($prop in $json.PSObject.Properties) {
150+
$summary[$prop.Name] = [string]$prop.Value
151+
}
152+
}
153+
else {
154+
Get-Content $summaryFile | ForEach-Object {
155+
if ($_ -match "^([^=]+)=(.*)$") {
156+
$summary[$matches[1]] = $matches[2]
157+
}
158+
}
159+
}
160+
161+
$status = $summary["status"]
162+
if (-not $status) { $status = "unknown" }
163+
$icon = if ($status -eq "passed") { "OK" } else { "FAIL" }
164+
165+
"## Windows WHPX smoke" >> $env:GITHUB_STEP_SUMMARY
166+
"" >> $env:GITHUB_STEP_SUMMARY
167+
"$icon status: **$status**" >> $env:GITHUB_STEP_SUMMARY
168+
"- git_sha: $($summary['git_sha'])" >> $env:GITHUB_STEP_SUMMARY
169+
"- runner_name: $($summary['runner_name'])" >> $env:GITHUB_STEP_SUMMARY
170+
"- runner_os: $($summary['runner_os'])" >> $env:GITHUB_STEP_SUMMARY
171+
"- target: $($summary['target'])" >> $env:GITHUB_STEP_SUMMARY
172+
"- filter: $($summary['test_filter'])" >> $env:GITHUB_STEP_SUMMARY
173+
"- cleanup_rootfs: $($summary['cleanup_rootfs'])" >> $env:GITHUB_STEP_SUMMARY
174+
"- dry_run_rootfs_decision: $($summary['dry_run_rootfs_decision'])" >> $env:GITHUB_STEP_SUMMARY
175+
"- fail_if_rootfs_rebuild: $($summary['fail_if_rootfs_rebuild'])" >> $env:GITHUB_STEP_SUMMARY
176+
"- rootfs_marker_format: $($summary['rootfs_marker_format'])" >> $env:GITHUB_STEP_SUMMARY
177+
"- compatible_rootfs_marker_formats: $($summary['compatible_rootfs_marker_formats'])" >> $env:GITHUB_STEP_SUMMARY
178+
"- promote_compatible_marker: $($summary['promote_compatible_marker'])" >> $env:GITHUB_STEP_SUMMARY
179+
"- max_rootfs_age_hours: $($summary['max_rootfs_age_hours'])" >> $env:GITHUB_STEP_SUMMARY
180+
"- rootfs_reused: $($summary['rootfs_reused'])" >> $env:GITHUB_STEP_SUMMARY
181+
"- rootfs_action: $($summary['rootfs_action'])" >> $env:GITHUB_STEP_SUMMARY
182+
"- rootfs_reuse_reason: $($summary['rootfs_reuse_reason'])" >> $env:GITHUB_STEP_SUMMARY
183+
"- marker_promoted: $($summary['marker_promoted'])" >> $env:GITHUB_STEP_SUMMARY
184+
"- log: $($summary['log_path'])" >> $env:GITHUB_STEP_SUMMARY
185+
"" >> $env:GITHUB_STEP_SUMMARY
186+
187+
if (Test-Path $phaseFile) {
188+
"<details><summary>Phase timeline</summary>" >> $env:GITHUB_STEP_SUMMARY
189+
"" >> $env:GITHUB_STEP_SUMMARY
190+
"```text" >> $env:GITHUB_STEP_SUMMARY
191+
Get-Content $phaseFile | ForEach-Object { $_ >> $env:GITHUB_STEP_SUMMARY }
192+
"```" >> $env:GITHUB_STEP_SUMMARY
193+
"</details>" >> $env:GITHUB_STEP_SUMMARY
194+
}
195+
196+
- name: Upload WHPX smoke logs
197+
if: always()
198+
uses: actions/upload-artifact@v4
199+
with:
200+
name: windows-whpx-smoke-logs
201+
path: ${{ runner.temp }}/libkrun-whpx-smoke
202+
if-no-files-found: ignore

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ examples/consoles
1818
examples/rootfs_fedora
1919
test-prefix
2020
/linux-sysroot
21+
22+
.claude/settings.local.json

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ Teoh Han Hui <teohhanhui@gmail.com>
2828
Tyler Fanelli <tfanelli@redhat.com>
2929
Wainer dos Santos Moschetta <wainersm@redhat.com>
3030
Zalan Blenessy <zalan.blenessy@gmail.com>
31+
Roy Lin <linzhixiao1996@gmail.com>

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ resolver = "2"
99
[profile.release]
1010
#panic = "abort"
1111
lto = true
12+
13+
[patch.crates-io]
14+
vm-memory = { path = "third_party/vm-memory" }

README.md

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
# libkrun
88

9-
```libkrun``` is a dynamic library that allows programs to easily acquire the ability to run processes in a partially isolated environment using [KVM](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt) Virtualization on Linux and [HVF](https://developer.apple.com/documentation/hypervisor) on macOS/ARM64.
9+
```libkrun``` is a dynamic library that allows programs to easily acquire the ability to run processes in a partially isolated environment using [KVM](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt) Virtualization on Linux, [HVF](https://developer.apple.com/documentation/hypervisor) on macOS/ARM64, and [WHPX](https://learn.microsoft.com/en-us/virtualization/api/) on Windows x86_64.
1010

1111
It integrates a VMM (Virtual Machine Monitor, the userspace side of an Hypervisor) with the minimum amount of emulated devices required to its purpose, abstracting most of the complexity that comes from Virtual Machine management, offering users a simple C API.
1212

@@ -44,7 +44,7 @@ Each variant generates a dynamic library with a different name (and ```soname```
4444

4545
## Virtio device support
4646

47-
### All variants
47+
### Linux and macOS
4848

4949
* virtio-console
5050
* virtio-block
@@ -56,6 +56,15 @@ Each variant generates a dynamic library with a different name (and ```soname```
5656
* virtio-rng
5757
* virtio-snd
5858

59+
### Windows (x86_64)
60+
61+
* virtio-console
62+
* virtio-block
63+
* virtio-net (via TcpStream backend)
64+
* virtio-vsock (via Named Pipe backend; no TSI; DGRAM support)
65+
* virtio-balloon (free-page reporting)
66+
* virtio-rng
67+
5968
## Networking
6069

6170
In ```libkrun```, networking is provided by two different, mutually exclusive techniques: **virtio-vsock + TSI** and **virtio-net + passt/gvproxy**.
@@ -225,25 +234,46 @@ A suitable sysroot is automatically generated by the Makefile from Debian reposi
225234
sudo make [FEATURE_OPTIONS] install
226235
```
227236

228-
### Windows (Experimental)
229-
- Windows 10 2004+ or Windows 11
230-
- Hyper-V enabled
231-
- WinHvPlatform API support
232-
- Architectures: x86_64, aarch64
237+
### Windows (x86_64, Experimental)
233238

234-
### Building for Windows
239+
> **Status**: Early development. Linux kernels boot through early console output. Full
240+
> userspace boot is not yet supported (interrupt injection is not yet implemented).
235241
236-
Cross-compile from Linux/macOS:
237-
```bash
238-
cargo build --target x86_64-pc-windows-msvc --release
239-
cargo build --target aarch64-pc-windows-msvc --release
242+
#### Requirements
243+
244+
* Windows 10 version 2004 or later, or Windows 11
245+
* **Windows Hypervisor Platform** enabled (Settings → Optional Features, or `DISM /Online /Enable-Feature /FeatureName:HypervisorPlatform`)
246+
* A working [Rust](https://www.rust-lang.org/) toolchain with the `x86_64-pc-windows-msvc` target (`rustup target add x86_64-pc-windows-msvc`)
247+
* MSVC build tools (Visual Studio Build Tools 2019 or later)
248+
249+
#### Compiling
250+
251+
```powershell
252+
cargo build -p libkrun --target x86_64-pc-windows-msvc --release
240253
```
241254

242-
Native build on Windows:
255+
#### Running smoke tests
256+
243257
```powershell
244-
cargo build --release
258+
# Requires Windows Hypervisor Platform; must use --test-threads=1
259+
cargo test -p vmm --target x86_64-pc-windows-msvc --lib -- test_whpx_ --ignored --test-threads=1
245260
```
246261

262+
#### API differences from Linux/macOS
263+
264+
| API | Windows equivalent |
265+
|-----|--------------------|
266+
| `krun_add_net_unixstream` | `krun_add_net` (TcpStream address) |
267+
| `krun_add_vsock_port` | `krun_add_vsock_port_windows` (Named Pipe name) |
268+
| `krun_add_disk` | same |
269+
270+
#### Known limitations
271+
272+
* x86_64 only (no ARM64/WHPX support on Windows)
273+
* virtio-fs, virtio-gpu, and virtio-snd are not supported
274+
* TSI (Transparent Socket Impersonation) is not supported; vsock uses Windows Named Pipes
275+
* No interrupt injection yet — guest kernel stalls after early boot output
276+
247277
## Using the library
248278

249279
Despite being written in Rust, this library provides a simple C API defined in [include/libkrun.h](include/libkrun.h)

0 commit comments

Comments
 (0)