mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
252 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d412ac2182 | ||
|
|
628bb74cce | ||
|
|
5dc1668927 | ||
|
|
8d8791c95d | ||
|
|
ade49a9fd2 | ||
|
|
87d765a168 | ||
|
|
98b28d5866 | ||
|
|
c2664e6a8d | ||
|
|
88087c18b0 | ||
|
|
22867232e1 | ||
|
|
3f489286c5 | ||
|
|
13772c5a65 | ||
|
|
fde74c57ad | ||
|
|
b665aa19f4 | ||
|
|
3d3693699b | ||
|
|
1ed31abb5d | ||
|
|
1446873b28 | ||
|
|
5f04c9b6fe | ||
|
|
46d59f0bc4 | ||
|
|
9add5263f7 | ||
|
|
dfaa151dfc | ||
|
|
2cd5b0b5e0 | ||
|
|
d08365a131 | ||
|
|
496d4c204b | ||
|
|
e0b863ecfe | ||
|
|
beb353eab2 | ||
|
|
1cfe096fb1 | ||
|
|
c8c68f3f77 | ||
|
|
77634a3c05 | ||
|
|
ab18a923f1 | ||
|
|
9f316b2e50 | ||
|
|
a03f17a275 | ||
|
|
c14f9ee2f4 | ||
|
|
ec56f07316 | ||
|
|
574d86dd4d | ||
|
|
a633b009ed | ||
|
|
b475965632 | ||
|
|
11b1ab40a5 | ||
|
|
10e77ebd1e | ||
|
|
167ae5a78a | ||
|
|
8736256564 | ||
|
|
55e08edd7f | ||
|
|
54f66aaadc | ||
|
|
d656058c21 | ||
|
|
3227372fe0 | ||
|
|
ac3f51002d | ||
|
|
0d2e2cd4c3 | ||
|
|
1fc969d37a | ||
|
|
27f5016ad3 | ||
|
|
a0ddcc68d7 | ||
|
|
df5aecd144 | ||
|
|
862d267302 | ||
|
|
44d9c7fd42 | ||
|
|
12abe2dd2b | ||
|
|
39a81c596f | ||
|
|
3b0d2e796b | ||
|
|
42357c01f3 | ||
|
|
b7b5b9d7e6 | ||
|
|
a63e064004 | ||
|
|
62c1f39ea2 | ||
|
|
460ba718d4 | ||
|
|
c91a8e1324 | ||
|
|
1adfb7e9f8 | ||
|
|
8dd4d42053 | ||
|
|
3834b43878 | ||
|
|
52605cc0e4 | ||
|
|
92beda1e32 | ||
|
|
167fef382a | ||
|
|
5126e9b26e | ||
|
|
59bd682b1f | ||
|
|
8e3b351038 | ||
|
|
3f8d06b47e | ||
|
|
66460765a3 | ||
|
|
b748b8987d | ||
|
|
c9483fb080 | ||
|
|
f52cd3bb85 | ||
|
|
57cd12fabc | ||
|
|
869c649e81 | ||
|
|
a9e30c88df | ||
|
|
1666375a31 | ||
|
|
9a0be7db3a | ||
|
|
324c5deb37 | ||
|
|
09e79a5e9b | ||
|
|
af261f231c | ||
|
|
7122e2989c | ||
|
|
d0b253d15f | ||
|
|
59baa29deb | ||
|
|
19fdf8bc79 | ||
|
|
58b902d036 | ||
|
|
e3213c8a79 | ||
|
|
2e2ce47271 | ||
|
|
d3a8332282 | ||
|
|
c64004b9a9 | ||
|
|
149e424b6e | ||
|
|
b07d471d4f | ||
|
|
345e65c9c2 | ||
|
|
f93aa42319 | ||
|
|
fa4bf92feb | ||
|
|
f30d460fa3 | ||
|
|
2c94773bdc | ||
|
|
9f1d2d34e8 | ||
|
|
57508a4b1c | ||
|
|
012f2572d5 | ||
|
|
b9dbe3a2f7 | ||
|
|
6230929d51 | ||
|
|
04d034a0bc | ||
|
|
f603afc46e | ||
|
|
b68add2d0d | ||
|
|
0f44db5da4 | ||
|
|
a7dccf94cf | ||
|
|
0e6e539d9b | ||
|
|
1cb1cff882 | ||
|
|
fefbc356a2 | ||
|
|
8b37448d28 | ||
|
|
92d083f593 | ||
|
|
58d8795b53 | ||
|
|
b37e2ed378 | ||
|
|
ef8fb9bd25 | ||
|
|
cfafc85b9c | ||
|
|
683491a955 | ||
|
|
2bbb08b2a4 | ||
|
|
b77eb63688 | ||
|
|
6722c303b0 | ||
|
|
6e0bd73c90 | ||
|
|
103fe1f48b | ||
|
|
f4e1b72477 | ||
|
|
65628e8d94 | ||
|
|
851de1e0b3 | ||
|
|
a9ec0f33c0 | ||
|
|
9266ea4995 | ||
|
|
6b8070de95 | ||
|
|
a5712641d2 | ||
|
|
aad4dc3b6b | ||
|
|
f4495de143 | ||
|
|
99d9a3d299 | ||
|
|
df7c728399 | ||
|
|
1e5a4e8d77 | ||
|
|
ff3fb91ba6 | ||
|
|
86c19816c6 | ||
|
|
ad1cb130a5 | ||
|
|
0c75e7f7b2 | ||
|
|
cb171d4a23 | ||
|
|
bc310bb173 | ||
|
|
76f4641004 | ||
|
|
dcb12c05a7 | ||
|
|
078c0408b3 | ||
|
|
b99b2bc990 | ||
|
|
0cd6d96874 | ||
|
|
a5d0ff7039 | ||
|
|
da1ab77848 | ||
|
|
989d3d3960 | ||
|
|
1559b7b684 | ||
|
|
e96474a5bd | ||
|
|
2a36a18be3 | ||
|
|
0e386581e0 | ||
|
|
1f0e5eb66a | ||
|
|
157db33d65 | ||
|
|
40df6c3787 | ||
|
|
b425c5f57c | ||
|
|
b4e3942708 | ||
|
|
802f489e4d | ||
|
|
fdecd94b20 | ||
|
|
2af2cc539f | ||
|
|
7d71319210 | ||
|
|
e710e21744 | ||
|
|
9c658e21a5 | ||
|
|
38620eaea8 | ||
|
|
a388d76228 | ||
|
|
710a860e9b | ||
|
|
83f22ac779 | ||
|
|
71b4aad3f1 | ||
|
|
d7afa3c47e | ||
|
|
073374e2b0 | ||
|
|
d4f40487e3 | ||
|
|
f63cf2ebc0 | ||
|
|
46031cb211 | ||
|
|
c52ccf3992 | ||
|
|
7b31871a36 | ||
|
|
1b58c63734 | ||
|
|
d1435a44af | ||
|
|
a75d71f2c8 | ||
|
|
96209e7a16 | ||
|
|
7a68689794 | ||
|
|
6e6b519a74 | ||
|
|
958ef69295 | ||
|
|
ffc222b26e | ||
|
|
5b706422e8 | ||
|
|
84105992b7 | ||
|
|
0235ed3388 | ||
|
|
58066e2da4 | ||
|
|
62d6553714 | ||
|
|
2a45e44bda | ||
|
|
099cdd2af8 | ||
|
|
340fd6571a | ||
|
|
02f951a9c3 | ||
|
|
22be5f9d0f | ||
|
|
a9ccb20e5a | ||
|
|
2b150ac2ea | ||
|
|
204bf2e3f5 | ||
|
|
2a40fe5541 | ||
|
|
7ae4e2b8fe | ||
|
|
f17f4079b4 | ||
|
|
342851c88c | ||
|
|
37c3b0429a | ||
|
|
af14044fb8 | ||
|
|
fa39d1e9b9 | ||
|
|
00714dc54a | ||
|
|
87fb9cedc9 | ||
|
|
ce2928d842 | ||
|
|
a18b08c682 | ||
|
|
43935c3b95 | ||
|
|
c3c550c454 | ||
|
|
7da632def6 | ||
|
|
f38ef20e3b | ||
|
|
a033b1ef67 | ||
|
|
ffa7d27b5e | ||
|
|
da725daca0 | ||
|
|
0fe0eb4c97 | ||
|
|
8877211d9e | ||
|
|
f907ff5d82 | ||
|
|
89a2562c5a | ||
|
|
29cf637f3f | ||
|
|
fd9fa2a681 | ||
|
|
756aebafda | ||
|
|
d4d63502be | ||
|
|
961793ba8c | ||
|
|
cbeed02a7c | ||
|
|
10eb687687 | ||
|
|
83cc554f90 | ||
|
|
7d8d27c1b4 | ||
|
|
d692dfb8e3 | ||
|
|
7ad58457b0 | ||
|
|
62d2189ade | ||
|
|
7e7855bc8f | ||
|
|
11cc35e6b5 | ||
|
|
89677c3181 | ||
|
|
307cfeba27 | ||
|
|
43bb09df50 | ||
|
|
81d570e271 | ||
|
|
31ca22d4b6 | ||
|
|
cf995451a2 | ||
|
|
4fea40f008 | ||
|
|
2daab89987 | ||
|
|
1bc63e7848 | ||
|
|
2115a41568 | ||
|
|
4b4354a52c | ||
|
|
67751d07d6 | ||
|
|
509fd8b03e | ||
|
|
1294f052b2 | ||
|
|
01b38b9c59 | ||
|
|
db51e9e209 | ||
|
|
57dfcc06d3 |
2
.github/workflows/build.yaml
vendored
2
.github/workflows/build.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
- "1.60"
|
||||
- "1.65"
|
||||
target:
|
||||
- x86_64-unknown-linux-gnu
|
||||
- x86_64-unknown-linux-musl
|
||||
|
||||
90
.github/workflows/release.yaml
vendored
90
.github/workflows/release.yaml
vendored
@@ -1,62 +1,48 @@
|
||||
name: Cloud Hypervisor Release
|
||||
on: [create]
|
||||
on: [pull_request, create]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||
if: (github.event_name == 'create' && github.event.ref_type == 'tag') || github.event_name == 'pull_request'
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Install musl-gcc
|
||||
run: sudo apt install -y musl-tools
|
||||
run: sudo apt install -y musl-tools
|
||||
- name: Create release directory
|
||||
run: rsync -rv --exclude=.git . ../cloud-hypervisor-${{ github.event.ref }}
|
||||
- name: Install Rust toolchain (x86_64-unknown-linux-gnu)
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
target: x86_64-unknown-linux-gnu
|
||||
toolchain: "1.65"
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- name: Install Rust toolchain (x86_64-unknown-linux-musl)
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
target: x86_64-unknown-linux-musl
|
||||
toolchain: "1.65"
|
||||
target: x86_64-unknown-linux-musl
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
toolchain: "1.65"
|
||||
command: build
|
||||
args: --all --release --target=x86_64-unknown-linux-gnu
|
||||
- name: Static Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
toolchain: "1.65"
|
||||
command: build
|
||||
args: --all --release --target=x86_64-unknown-linux-musl
|
||||
- name: Strip cloud-hypervisor binaries
|
||||
run: strip target/*/release/cloud-hypervisor
|
||||
- name: Install Rust toolchain (aarch64-unknown-linux-musl)
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
target: aarch64-unknown-linux-musl
|
||||
override: true
|
||||
- name: Static Build (AArch64)
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: true
|
||||
command: build
|
||||
args: --all --release --target=aarch64-unknown-linux-musl
|
||||
- name: Vendor
|
||||
working-directory: ../cloud-hypervisor-${{ github.event.ref }}
|
||||
run: |
|
||||
mkdir ../vendor-cargo-home
|
||||
export CARGO_HOME=$(realpath ../vendor-cargo-home)
|
||||
mkdir .cargo
|
||||
cargo vendor > .cargo/config.toml
|
||||
toolchain: "1.65"
|
||||
target: aarch64-unknown-linux-musl
|
||||
override: true
|
||||
- name: Create Release
|
||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
@@ -66,20 +52,8 @@ jobs:
|
||||
release_name: ${{ github.ref }}
|
||||
draft: true
|
||||
prerelease: true
|
||||
- name: Create vendored source archive
|
||||
working-directory: ../
|
||||
run: tar cJf cloud-hypervisor-${{ github.event.ref }}.tar.xz cloud-hypervisor-${{ github.event.ref }}
|
||||
- name: Upload cloud-hypervisor vendored source archive
|
||||
id: upload-release-cloud-hypervisor-vendored-sources
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ../cloud-hypervisor-${{ github.event.ref }}.tar.xz
|
||||
asset_name: cloud-hypervisor-${{ github.event.ref }}.tar.xz
|
||||
asset_content_type: application/x-xz
|
||||
- name: Upload cloud-hypervisor
|
||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||
id: upload-release-cloud-hypervisor
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
@@ -90,6 +64,7 @@ jobs:
|
||||
asset_name: cloud-hypervisor
|
||||
asset_content_type: application/octet-stream
|
||||
- name: Upload static cloud-hypervisor
|
||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||
id: upload-release-static-cloud-hypervisor
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
@@ -100,6 +75,7 @@ jobs:
|
||||
asset_name: cloud-hypervisor-static
|
||||
asset_content_type: application/octet-stream
|
||||
- name: Upload ch-remote
|
||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||
id: upload-release-ch-remote
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
@@ -110,6 +86,7 @@ jobs:
|
||||
asset_name: ch-remote
|
||||
asset_content_type: application/octet-stream
|
||||
- name: Upload static-ch-remote
|
||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||
id: upload-release-static-ch-remote
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
@@ -119,7 +96,18 @@ jobs:
|
||||
asset_path: target/x86_64-unknown-linux-musl/release/ch-remote
|
||||
asset_name: ch-remote-static
|
||||
asset_content_type: application/octet-stream
|
||||
- name: Clean build tree ahead of cross build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clean
|
||||
- name: Static Build (AArch64)
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: true
|
||||
command: build
|
||||
args: --all --release --target=aarch64-unknown-linux-musl
|
||||
- name: Upload static AArch64 cloud-hypervisor
|
||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||
id: upload-release-static-aarch64-cloud-hypervisor
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
@@ -130,6 +118,7 @@ jobs:
|
||||
asset_name: cloud-hypervisor-static-aarch64
|
||||
asset_content_type: application/octet-stream
|
||||
- name: Upload static AArch64 ch-remote
|
||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||
id: upload-release-static-aarch64-ch-remote
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
@@ -139,3 +128,24 @@ jobs:
|
||||
asset_path: target/aarch64-unknown-linux-musl/release/ch-remote
|
||||
asset_name: ch-remote-static-aarch64
|
||||
asset_content_type: application/octet-stream
|
||||
- name: Vendor
|
||||
working-directory: ../cloud-hypervisor-${{ github.event.ref }}
|
||||
run: |
|
||||
mkdir ../vendor-cargo-home
|
||||
export CARGO_HOME=$(realpath ../vendor-cargo-home)
|
||||
mkdir .cargo
|
||||
cargo vendor > .cargo/config.toml
|
||||
- name: Create vendored source archive
|
||||
working-directory: ../
|
||||
run: tar cJf cloud-hypervisor-${{ github.event.ref }}.tar.xz cloud-hypervisor-${{ github.event.ref }}
|
||||
- name: Upload cloud-hypervisor vendored source archive
|
||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||
id: upload-release-cloud-hypervisor-vendored-sources
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ../cloud-hypervisor-${{ github.event.ref }}.tar.xz
|
||||
asset_name: cloud-hypervisor-${{ github.event.ref }}.tar.xz
|
||||
asset_content_type: application/x-xz
|
||||
|
||||
522
Cargo.lock
generated
522
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
31
Cargo.toml
31
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cloud-hypervisor"
|
||||
version = "27.0.0"
|
||||
version = "28.4.0"
|
||||
authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
default-run = "cloud-hypervisor"
|
||||
@@ -10,46 +10,53 @@ description = "Open source Virtual Machine Monitor (VMM) that runs on top of KVM
|
||||
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
||||
# Minimum buildable version:
|
||||
# Keep in sync with version in .github/workflows/build.yaml
|
||||
rust-version = "1.60"
|
||||
# Policy on MSRV (see #4318):
|
||||
# Can only be bumped by:
|
||||
# a.) A dependency requires it,
|
||||
# b.) If we want to use a new feature and that MSRV is at least 6 months old,
|
||||
# c.) There is a security issue that is addressed by the toolchain update.
|
||||
rust-version = "1.65"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
opt-level = "s"
|
||||
strip = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.65"
|
||||
anyhow = "1.0.66"
|
||||
api_client = { path = "api_client" }
|
||||
clap = { version = "3.2.22", features = ["wrap_help","cargo"] }
|
||||
clap = { version = "4.0.29", features = ["wrap_help","cargo","string"] }
|
||||
epoll = "4.3.1"
|
||||
event_monitor = { path = "event_monitor" }
|
||||
hypervisor = { path = "hypervisor" }
|
||||
libc = "0.2.133"
|
||||
libc = "0.2.138"
|
||||
log = { version = "0.4.17", features = ["std"] }
|
||||
option_parser = { path = "option_parser" }
|
||||
seccompiler = "0.3.0"
|
||||
serde_json = "1.0.85"
|
||||
serde_json = "1.0.89"
|
||||
signal-hook = "0.3.14"
|
||||
thiserror = "1.0.37"
|
||||
tpm = { path = "tpm"}
|
||||
tracer = { path = "tracer" }
|
||||
vmm = { path = "vmm" }
|
||||
vmm-sys-util = "0.10.0"
|
||||
vm-memory = "0.9.0"
|
||||
vmm-sys-util = "0.11.0"
|
||||
vm-memory = "0.10.0"
|
||||
|
||||
[build-dependencies]
|
||||
clap = { version = "3.2.22", features = ["cargo"] }
|
||||
clap = { version = "4.0.29", features = ["cargo"] }
|
||||
|
||||
# List of patched crates
|
||||
[patch.crates-io]
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx" }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" }
|
||||
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||
|
||||
[dev-dependencies]
|
||||
dirs = "4.0.0"
|
||||
net_util = { path = "net_util" }
|
||||
once_cell = "1.15.0"
|
||||
serde_json = "1.0.85"
|
||||
once_cell = "1.16.0"
|
||||
serde_json = "1.0.89"
|
||||
test_infra = { path = "test_infra" }
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
|
||||
642
Jenkinsfile
vendored
642
Jenkinsfile
vendored
@@ -1,337 +1,333 @@
|
||||
def runWorkers = true
|
||||
pipeline{
|
||||
agent none
|
||||
stages {
|
||||
stage ('Early checks') {
|
||||
agent { node { label 'built-in' } }
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage ('Check for documentation only changes') {
|
||||
when {
|
||||
expression {
|
||||
return docsFileOnly()
|
||||
}
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
runWorkers = false
|
||||
echo "Documentation only changes, no need to run the CI"
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ('Check for fuzzer files only changes') {
|
||||
when {
|
||||
expression {
|
||||
return fuzzFileOnly()
|
||||
}
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
runWorkers = false
|
||||
echo "Fuzzer cargo files only changes, no need to run the CI"
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ('Check for RFC/WIP builds') {
|
||||
when {
|
||||
changeRequest comparator: 'REGEXP', title: '.*(rfc|RFC|wip|WIP).*'
|
||||
beforeAgent true
|
||||
}
|
||||
steps {
|
||||
error("Failing as this is marked as a WIP or RFC PR.")
|
||||
}
|
||||
}
|
||||
stage ('Cancel older builds') {
|
||||
when { not { branch 'main' } }
|
||||
steps {
|
||||
cancelPreviousBuilds()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ('Build') {
|
||||
parallel {
|
||||
stage ('Worker build') {
|
||||
agent { node { label 'jammy' } }
|
||||
when {
|
||||
beforeAgent true
|
||||
expression {
|
||||
return runWorkers
|
||||
}
|
||||
}
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage ('Prepare environment') {
|
||||
steps {
|
||||
sh "scripts/prepare_vdpa.sh"
|
||||
}
|
||||
}
|
||||
stage ('Run OpenAPI tests') {
|
||||
steps {
|
||||
sh "scripts/run_openapi_tests.sh"
|
||||
}
|
||||
}
|
||||
stage ('Run unit tests') {
|
||||
steps {
|
||||
sh "scripts/dev_cli.sh tests --unit"
|
||||
}
|
||||
}
|
||||
stage ('Run integration tests') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh "sudo modprobe openvswitch"
|
||||
sh "scripts/dev_cli.sh tests --integration"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ('AArch64 worker build') {
|
||||
agent { node { label 'bionic-arm64' } }
|
||||
when {
|
||||
beforeAgent true
|
||||
expression {
|
||||
return runWorkers
|
||||
}
|
||||
}
|
||||
environment {
|
||||
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
|
||||
}
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage ('Run unit tests') {
|
||||
steps {
|
||||
sh "scripts/dev_cli.sh tests --unit --libc musl"
|
||||
}
|
||||
}
|
||||
stage ('Run integration tests') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh "sudo modprobe openvswitch"
|
||||
sh "scripts/dev_cli.sh tests --integration --libc musl"
|
||||
}
|
||||
}
|
||||
stage ('Install azure-cli') {
|
||||
steps {
|
||||
installAzureCli("bionic", "arm64")
|
||||
}
|
||||
}
|
||||
stage ('Download Windows image') {
|
||||
steps {
|
||||
sh '''#!/bin/bash -x
|
||||
IMG_BASENAME=windows-11-iot-enterprise-aarch64.raw
|
||||
IMG_PATH=$HOME/workloads/$IMG_BASENAME
|
||||
IMG_GZ_PATH=$HOME/workloads/$IMG_BASENAME.gz
|
||||
IMG_GZ_BLOB_NAME=windows-11-iot-enterprise-aarch64-9-min.raw.gz
|
||||
cp "scripts/$IMG_BASENAME.sha1" "$HOME/workloads/"
|
||||
pushd "$HOME/workloads"
|
||||
if sha1sum "$IMG_BASENAME.sha1" --check; then
|
||||
exit
|
||||
fi
|
||||
popd
|
||||
mkdir -p "$HOME/workloads"
|
||||
az storage blob download \
|
||||
--container-name private-images \
|
||||
--file "$IMG_GZ_PATH" \
|
||||
--name "$IMG_GZ_BLOB_NAME" \
|
||||
--connection-string "$AZURE_CONNECTION_STRING"
|
||||
gzip -d $IMG_GZ_PATH
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage ('Run Windows guest integration tests') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh "scripts/dev_cli.sh tests --integration-windows --libc musl"
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ('Worker build (musl)') {
|
||||
agent { node { label 'jammy' } }
|
||||
when {
|
||||
beforeAgent true
|
||||
expression {
|
||||
return runWorkers
|
||||
}
|
||||
}
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage ('Prepare environment') {
|
||||
steps {
|
||||
sh "scripts/prepare_vdpa.sh"
|
||||
}
|
||||
}
|
||||
stage ('Run unit tests for musl') {
|
||||
steps {
|
||||
sh "scripts/dev_cli.sh tests --unit --libc musl"
|
||||
}
|
||||
}
|
||||
stage ('Run integration tests for musl') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh "sudo modprobe openvswitch"
|
||||
sh "scripts/dev_cli.sh tests --integration --libc musl"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ('Worker build - Windows guest') {
|
||||
agent { node { label 'jammy' } }
|
||||
when {
|
||||
beforeAgent true
|
||||
expression {
|
||||
return runWorkers
|
||||
}
|
||||
}
|
||||
environment {
|
||||
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
|
||||
}
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage ('Install azure-cli') {
|
||||
steps {
|
||||
installAzureCli("jammy", "amd64")
|
||||
}
|
||||
}
|
||||
stage ('Download assets') {
|
||||
steps {
|
||||
sh "mkdir ${env.HOME}/workloads"
|
||||
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/windows-server-2019.raw" --name windows-server-2019.raw --connection-string "$AZURE_CONNECTION_STRING"'
|
||||
}
|
||||
}
|
||||
stage ('Run Windows guest integration tests') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh "scripts/dev_cli.sh tests --integration-windows"
|
||||
}
|
||||
}
|
||||
stage ('Run Windows guest integration tests for musl') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh "scripts/dev_cli.sh tests --integration-windows --libc musl"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ('Worker build - Live Migration') {
|
||||
agent { node { label 'jammy' } }
|
||||
when {
|
||||
beforeAgent true
|
||||
expression {
|
||||
return runWorkers
|
||||
}
|
||||
}
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage ('Run live-migration integration tests') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh "sudo modprobe openvswitch"
|
||||
sh "scripts/dev_cli.sh tests --integration-live-migration"
|
||||
}
|
||||
}
|
||||
stage ('Run live-migration integration tests for musl') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh "sudo modprobe openvswitch"
|
||||
sh "scripts/dev_cli.sh tests --integration-live-migration --libc musl"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
regression {
|
||||
script {
|
||||
if (env.BRANCH_NAME == 'main') {
|
||||
slackSend (color: '#ff0000', message: '"main" branch build is now failing', channel: '#jenkins-ci')
|
||||
}
|
||||
}
|
||||
}
|
||||
fixed {
|
||||
script {
|
||||
if (env.BRANCH_NAME == 'main') {
|
||||
slackSend (color: '#00ff00', message: '"main" branch build is now fixed', channel: '#jenkins-ci')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pipeline {
|
||||
agent none
|
||||
stages {
|
||||
stage('Early checks') {
|
||||
agent { node { label 'built-in' } }
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage('Check for documentation only changes') {
|
||||
when {
|
||||
expression {
|
||||
return docsFileOnly()
|
||||
}
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
runWorkers = false
|
||||
echo 'Documentation only changes, no need to run the CI'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Check for fuzzer files only changes') {
|
||||
when {
|
||||
expression {
|
||||
return fuzzFileOnly()
|
||||
}
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
runWorkers = false
|
||||
echo 'Fuzzer cargo files only changes, no need to run the CI'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Check for RFC/WIP builds') {
|
||||
when {
|
||||
changeRequest comparator: 'REGEXP', title: '.*(rfc|RFC|wip|WIP).*'
|
||||
beforeAgent true
|
||||
}
|
||||
steps {
|
||||
error('Failing as this is marked as a WIP or RFC PR.')
|
||||
}
|
||||
}
|
||||
stage('Cancel older builds') {
|
||||
when { not { branch 'main' } }
|
||||
steps {
|
||||
cancelPreviousBuilds()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
parallel {
|
||||
stage('Worker build') {
|
||||
agent { node { label 'jammy' } }
|
||||
when {
|
||||
beforeAgent true
|
||||
expression {
|
||||
return runWorkers
|
||||
}
|
||||
}
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage('Prepare environment') {
|
||||
steps {
|
||||
sh 'scripts/prepare_vdpa.sh'
|
||||
}
|
||||
}
|
||||
stage('Run OpenAPI tests') {
|
||||
steps {
|
||||
sh 'scripts/run_openapi_tests.sh'
|
||||
}
|
||||
}
|
||||
stage('Run unit tests') {
|
||||
steps {
|
||||
sh 'scripts/dev_cli.sh tests --unit'
|
||||
}
|
||||
}
|
||||
stage('Run integration tests') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh 'sudo modprobe openvswitch'
|
||||
sh 'scripts/dev_cli.sh tests --integration'
|
||||
}
|
||||
}
|
||||
stage('Run live-migration integration tests') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh 'sudo modprobe openvswitch'
|
||||
sh 'scripts/dev_cli.sh tests --integration-live-migration'
|
||||
}
|
||||
}
|
||||
stage('Run unit tests for musl') {
|
||||
steps {
|
||||
sh 'scripts/dev_cli.sh tests --unit --libc musl'
|
||||
}
|
||||
}
|
||||
stage('Run integration tests for musl') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh 'sudo modprobe openvswitch'
|
||||
sh 'scripts/dev_cli.sh tests --integration --libc musl'
|
||||
}
|
||||
}
|
||||
stage('Run live-migration integration tests for musl') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh 'sudo modprobe openvswitch'
|
||||
sh 'scripts/dev_cli.sh tests --integration-live-migration --libc musl'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('AArch64 worker build') {
|
||||
agent { node { label 'bionic-arm64' } }
|
||||
when {
|
||||
beforeAgent true
|
||||
expression {
|
||||
return runWorkers
|
||||
}
|
||||
}
|
||||
environment {
|
||||
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
|
||||
}
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage('Run unit tests') {
|
||||
steps {
|
||||
sh 'scripts/dev_cli.sh tests --unit --libc musl'
|
||||
}
|
||||
}
|
||||
stage('Run integration tests') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh 'sudo modprobe openvswitch'
|
||||
sh 'scripts/dev_cli.sh tests --integration --libc musl'
|
||||
}
|
||||
}
|
||||
stage('Install azure-cli') {
|
||||
steps {
|
||||
installAzureCli('bionic', 'arm64')
|
||||
}
|
||||
}
|
||||
stage('Download Windows image') {
|
||||
steps {
|
||||
sh '''#!/bin/bash -x
|
||||
IMG_BASENAME=windows-11-iot-enterprise-aarch64.raw
|
||||
IMG_PATH=$HOME/workloads/$IMG_BASENAME
|
||||
IMG_GZ_PATH=$HOME/workloads/$IMG_BASENAME.gz
|
||||
IMG_GZ_BLOB_NAME=windows-11-iot-enterprise-aarch64-9-min.raw.gz
|
||||
cp "scripts/$IMG_BASENAME.sha1" "$HOME/workloads/"
|
||||
pushd "$HOME/workloads"
|
||||
if sha1sum "$IMG_BASENAME.sha1" --check; then
|
||||
exit
|
||||
fi
|
||||
popd
|
||||
mkdir -p "$HOME/workloads"
|
||||
az storage blob download \
|
||||
--container-name private-images \
|
||||
--file "$IMG_GZ_PATH" \
|
||||
--name "$IMG_GZ_BLOB_NAME" \
|
||||
--connection-string "$AZURE_CONNECTION_STRING"
|
||||
gzip -d $IMG_GZ_PATH
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage('Run Windows guest integration tests') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh 'scripts/dev_cli.sh tests --integration-windows --libc musl'
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Worker build - Windows guest') {
|
||||
agent { node { label 'jammy' } }
|
||||
when {
|
||||
beforeAgent true
|
||||
expression {
|
||||
return runWorkers
|
||||
}
|
||||
}
|
||||
environment {
|
||||
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
|
||||
}
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage('Install azure-cli') {
|
||||
steps {
|
||||
installAzureCli('jammy', 'amd64')
|
||||
}
|
||||
}
|
||||
stage('Download assets') {
|
||||
steps {
|
||||
sh "mkdir ${env.HOME}/workloads"
|
||||
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/windows-server-2019.raw" --name windows-server-2019.raw --connection-string "$AZURE_CONNECTION_STRING"'
|
||||
}
|
||||
}
|
||||
stage('Run Windows guest integration tests') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh 'scripts/dev_cli.sh tests --integration-windows'
|
||||
}
|
||||
}
|
||||
stage('Run Windows guest integration tests for musl') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh 'scripts/dev_cli.sh tests --integration-windows --libc musl'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Worker build - Metrics') {
|
||||
agent { node { label 'jammy-metrics' } }
|
||||
when {
|
||||
branch 'main'
|
||||
beforeAgent true
|
||||
expression {
|
||||
return runWorkers
|
||||
}
|
||||
}
|
||||
environment {
|
||||
METRICS_PUBLISH_KEY = credentials('52e0945f-ce7a-43d1-87af-67d1d87cc40f')
|
||||
}
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage('Run metrics tests') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh 'scripts/dev_cli.sh tests --metrics -- -- --report-file /root/workloads/metrics.json'
|
||||
}
|
||||
}
|
||||
stage('Upload metrics report') {
|
||||
steps {
|
||||
sh 'curl -X PUT https://cloud-hypervisor-metrics.azurewebsites.net/api/publishmetrics -H "x-functions-key: $METRICS_PUBLISH_KEY" -T ~/workloads/metrics.json'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
regression {
|
||||
script {
|
||||
if (env.BRANCH_NAME == 'main') {
|
||||
slackSend(color: '#ff0000', message: '"main" branch build is now failing', channel: '#jenkins-ci')
|
||||
}
|
||||
}
|
||||
}
|
||||
fixed {
|
||||
script {
|
||||
if (env.BRANCH_NAME == 'main') {
|
||||
slackSend(color: '#00ff00', message: '"main" branch build is now fixed', channel: '#jenkins-ci')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def cancelPreviousBuilds() {
|
||||
// Check for other instances of this particular build, cancel any that are older than the current one
|
||||
def jobName = env.JOB_NAME
|
||||
def currentBuildNumber = env.BUILD_NUMBER.toInteger()
|
||||
def currentJob = Jenkins.instance.getItemByFullName(jobName)
|
||||
// Check for other instances of this particular build, cancel any that are older than the current one
|
||||
def jobName = env.JOB_NAME
|
||||
def currentBuildNumber = env.BUILD_NUMBER.toInteger()
|
||||
def currentJob = Jenkins.instance.getItemByFullName(jobName)
|
||||
|
||||
// Loop through all instances of this particular job/branch
|
||||
for (def build : currentJob.builds) {
|
||||
if (build.isBuilding() && (build.number.toInteger() < currentBuildNumber)) {
|
||||
echo "Older build still queued. Sending kill signal to build number: ${build.number}"
|
||||
build.doStop()
|
||||
}
|
||||
}
|
||||
// Loop through all instances of this particular job/branch
|
||||
for (def build : currentJob.builds) {
|
||||
if (build.isBuilding() && (build.number.toInteger() < currentBuildNumber)) {
|
||||
echo "Older build still queued. Sending kill signal to build number: ${build.number}"
|
||||
build.doStop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def installAzureCli(distro, arch) {
|
||||
sh "sudo apt install -y ca-certificates curl apt-transport-https lsb-release gnupg"
|
||||
sh "curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null"
|
||||
sh "echo \"deb [arch=${arch}] https://packages.microsoft.com/repos/azure-cli/ ${distro} main\" | sudo tee /etc/apt/sources.list.d/azure-cli.list"
|
||||
sh "sudo apt update"
|
||||
sh "sudo apt install -y azure-cli"
|
||||
sh 'sudo apt install -y ca-certificates curl apt-transport-https lsb-release gnupg'
|
||||
sh 'curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null'
|
||||
sh "echo \"deb [arch=${arch}] https://packages.microsoft.com/repos/azure-cli/ ${distro} main\" | sudo tee /etc/apt/sources.list.d/azure-cli.list"
|
||||
sh 'sudo apt update'
|
||||
sh 'sudo apt install -y azure-cli'
|
||||
}
|
||||
|
||||
def boolean docsFileOnly() {
|
||||
if (env.CHANGE_TARGET == null) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
return sh(
|
||||
@@ -342,7 +338,7 @@ def boolean docsFileOnly() {
|
||||
|
||||
def boolean fuzzFileOnly() {
|
||||
if (env.CHANGE_TARGET == null) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
return sh(
|
||||
|
||||
328
README.md
328
README.md
@@ -5,24 +5,21 @@
|
||||
- [Guest OS](#guest-os)
|
||||
- [2. Getting Started](#2-getting-started)
|
||||
- [Host OS](#host-os)
|
||||
- [Preparation](#preparation)
|
||||
- [Install prerequisites](#install-prerequisites)
|
||||
- [Clone and build](#clone-and-build)
|
||||
- [Containerized builds and tests](#containerized-builds-and-tests)
|
||||
- [Use Prebuilt Binaries](#use-prebuilt-binaries)
|
||||
- [Run](#run)
|
||||
- [Cloud image](#cloud-image)
|
||||
- [Custom kernel and disk image](#custom-kernel-and-disk-image)
|
||||
- [Building your kernel](#building-your-kernel)
|
||||
- [Use Pre-built Binaries](#use-pre-built-binaries)
|
||||
- [Packages](#packages)
|
||||
- [Building from Source](#building-from-source)
|
||||
- [Booting Linux](#booting-linux)
|
||||
- [Firmware Booting](#firmware-booting)
|
||||
- [Custom Kernel and Disk Image](#custom-kernel-and-disk-image)
|
||||
- [Building your Kernel](#building-your-kernel)
|
||||
- [Disk image](#disk-image)
|
||||
- [Booting the guest VM](#booting-the-guest-vm)
|
||||
- [3. Status](#3-status)
|
||||
- [Hot Plug](#hot-plug)
|
||||
- [Device Model](#device-model)
|
||||
- [TODO](#todo)
|
||||
- [Roadmap](#roadmap)
|
||||
- [4. `rust-vmm` project dependency](#4-rust-vmm-project-dependency)
|
||||
- [Firecracker and crosvm](#firecracker-and-crosvm)
|
||||
- [4. Relationship with _Rust VMM_ Project](#4-relationship-with-rust-vmm-project)
|
||||
- [Differences with Firecracker and crosvm](#differences-with-firecracker-and-crosvm)
|
||||
- [5. Community](#5-community)
|
||||
- [Contribute](#contribute)
|
||||
- [Slack](#slack)
|
||||
@@ -32,18 +29,18 @@
|
||||
# 1. What is Cloud Hypervisor?
|
||||
|
||||
Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on
|
||||
top of [KVM](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt)
|
||||
hypervisor and Microsoft Hypervisor (MSHV).
|
||||
top of the [KVM](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt)
|
||||
hypervisor and the Microsoft Hypervisor (MSHV).
|
||||
|
||||
The project focuses on exclusively running modern, cloud workloads, on top of
|
||||
a limited set of hardware architectures and platforms. Cloud workloads refers
|
||||
to those that are usually run by customers inside a cloud provider. For our
|
||||
purposes this means modern operating systems with most I/O handled by
|
||||
paravirtualised devices (i.e. virtio), no requirement for legacy devices, and
|
||||
The project focuses on running modern, _Cloud Workloads_, on specific, common,
|
||||
hardware architectures. In this case _Cloud Workloads_ refers to those that are
|
||||
run by customers inside a Cloud Service Provider. This means modern operating
|
||||
systems with most I/O handled by
|
||||
paravirtualised devices (e.g. _virtio_), no requirement for legacy devices, and
|
||||
64-bit CPUs.
|
||||
|
||||
Cloud Hypervisor is implemented in [Rust](https://www.rust-lang.org/) and is
|
||||
based on the [rust-vmm](https://github.com/rust-vmm) crates.
|
||||
based on the [Rust VMM](https://github.com/rust-vmm) crates.
|
||||
|
||||
## Objectives
|
||||
|
||||
@@ -63,7 +60,7 @@ based on the [rust-vmm](https://github.com/rust-vmm) crates.
|
||||
### Architectures
|
||||
|
||||
Cloud Hypervisor supports the `x86-64` and `AArch64` architectures. There are
|
||||
some small differences in functionality between the two architectures
|
||||
minor differences in functionality between the two architectures
|
||||
(see [#1125](https://github.com/cloud-hypervisor/cloud-hypervisor/issues/1125)).
|
||||
|
||||
### Guest OS
|
||||
@@ -72,157 +69,121 @@ Cloud Hypervisor supports `64-bit Linux` and Windows 10/Windows Server 2019.
|
||||
|
||||
# 2. Getting Started
|
||||
|
||||
Below sections describe how to build and run Cloud Hypervisor on the `x86_64`
|
||||
platform. For getting started on the `AArch64` platform, please refer to the
|
||||
[Arm64 documentation](docs/arm64.md).
|
||||
The following sections describe how to build and run Cloud Hypervisor on the
|
||||
`x86-64` platform. For getting started on the `AArch64` platform, please refer
|
||||
to the
|
||||
[AArch64 documentation](docs/arm64.md).
|
||||
|
||||
## Host OS
|
||||
|
||||
Based on required KVM functionality the minimum host kernel version is 4.11.
|
||||
For adequate peformance the minimum recommended host kernel vesion is 5.6. The
|
||||
For required KVM functionality the minimum host kernel version is 4.11. For
|
||||
adequate performance the minimum recommended host kernel version is 5.6. The
|
||||
majority of the CI currently tests with kernel version 5.15.
|
||||
|
||||
## Preparation
|
||||
## Use Pre-built Binaries
|
||||
|
||||
We create a folder to build and run `cloud-hypervisor` at `$HOME/cloud-hypervisor`
|
||||
The recommended approach to getting started with Cloud Hypervisor is by using a
|
||||
pre-built binary. Binaries are available for the [latest
|
||||
release](https://github.com/cloud-hypervisor/cloud-hypervisor/releases/latest).
|
||||
Use `cloud-hypervisor-static` for `x86-64` or `cloud-hypervisor-static-aarch64`
|
||||
for `AArch64` platform.
|
||||
|
||||
```shell
|
||||
$ export CLOUDH=$HOME/cloud-hypervisor
|
||||
$ mkdir $CLOUDH
|
||||
```
|
||||
## Packages
|
||||
|
||||
## Install prerequisites
|
||||
|
||||
You need to install some prerequisite packages in order to build and test Cloud
|
||||
Hypervisor. Here, all the steps are based on Ubuntu, for other Linux
|
||||
distributions please replace the package manager and package name.
|
||||
|
||||
```shell
|
||||
# Install build-essential, git, and qemu-utils
|
||||
$ sudo apt install git build-essential qemu-utils
|
||||
# Install rust tool chain
|
||||
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
# If you want to build statically linked binary please add musl target
|
||||
$ rustup target add x86_64-unknown-linux-musl
|
||||
```
|
||||
|
||||
## Clone and build
|
||||
|
||||
First you need to clone and build the cloud-hypervisor repo:
|
||||
|
||||
```shell
|
||||
$ pushd $CLOUDH
|
||||
$ git clone https://github.com/cloud-hypervisor/cloud-hypervisor.git
|
||||
$ cd cloud-hypervisor
|
||||
$ cargo build --release
|
||||
|
||||
# We need to give the cloud-hypervisor binary the NET_ADMIN capabilities for it to set TAP interfaces up on the host.
|
||||
$ sudo setcap cap_net_admin+ep ./target/release/cloud-hypervisor
|
||||
|
||||
# If you want to build statically linked binary
|
||||
$ cargo build --release --target=x86_64-unknown-linux-musl --all
|
||||
$ popd
|
||||
```
|
||||
|
||||
This will build a `cloud-hypervisor` binary under
|
||||
`$CLOUDH/cloud-hypervisor/target/release/cloud-hypervisor`.
|
||||
|
||||
### Containerized builds and tests
|
||||
|
||||
If you want to build and test Cloud Hypervisor without having to install all the
|
||||
required dependencies (The rust toolchain, cargo tools, etc), you can also use
|
||||
Cloud Hypervisor's development script: `dev_cli.sh`. Please note that upon its
|
||||
first invocation, this script will pull a fairly large container image.
|
||||
|
||||
For example, to build the Cloud Hypervisor release binary:
|
||||
|
||||
```shell
|
||||
$ pushd $CLOUDH
|
||||
$ cd cloud-hypervisor
|
||||
$ ./scripts/dev_cli.sh build --release
|
||||
```
|
||||
|
||||
With `dev_cli.sh`, one can also run the Cloud Hypervisor CI locally. This can be
|
||||
very convenient for debugging CI errors without having to fully rely on the
|
||||
Cloud Hypervisor CI infrastructure.
|
||||
|
||||
For example, to run the Cloud Hypervisor unit tests:
|
||||
|
||||
```shell
|
||||
$ ./scripts/dev_cli.sh tests --unit
|
||||
```
|
||||
|
||||
Run the `./scripts/dev_cli.sh --help` command to view all the supported
|
||||
development script commands and their related options.
|
||||
|
||||
## Use Prebuilt Binaries
|
||||
|
||||
Cloud Hypervisor packages targeting some popular Linux distributions are available
|
||||
thanks to the [Open Build Service](https://build.opensuse.org). The
|
||||
[OBS README](https://github.com/cloud-hypervisor/obs-packaging) explains how to
|
||||
For convenience, packages are also available targeting some popular Linux
|
||||
distributions. This is thanks to the [Open Build
|
||||
Service](https://build.opensuse.org). The [OBS
|
||||
README](https://github.com/cloud-hypervisor/obs-packaging) explains how to
|
||||
enable the repository in a supported Linux distribution and install Cloud Hypervisor
|
||||
and accompanying packages. Please report any packaging issues in the
|
||||
[obs-packaging](https://github.com/cloud-hypervisor/obs-packaging) repository.
|
||||
|
||||
## Run
|
||||
## Building from Source
|
||||
|
||||
You can run a guest VM by either using an existing cloud image or booting into
|
||||
your own kernel and disk image.
|
||||
Please see the [instructions for building from source](docs/building.md) if you
|
||||
do not wish to use the pre-built binaries.
|
||||
|
||||
### Cloud image
|
||||
## Booting Linux
|
||||
|
||||
Cloud Hypervisor supports booting disk images containing all needed
|
||||
components to run cloud workloads, a.k.a. cloud images. To do that we rely on
|
||||
the [Rust Hypervisor
|
||||
Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) project
|
||||
to provide an ELF formatted KVM firmware for `cloud-hypervisor` to directly
|
||||
boot into.
|
||||
The instructions below are for the `x86-64` platform. For `AArch64` please see
|
||||
the [AArch64 specific documentation](docs/arm64.md).
|
||||
|
||||
We need to get the latest `rust-hypervisor-firmware` release and also a working
|
||||
cloud image. Here we will use a Ubuntu image:
|
||||
Cloud Hypervisor supports direct kernel boot (if the kernel is built with PVH
|
||||
support) or booting via a firmware (either [Rust Hypervisor
|
||||
Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) or an
|
||||
edk2 UEFI firmware called `CLOUDHV`.)
|
||||
|
||||
Binary builds of the firmware files are available for the latest release of
|
||||
[Rust Hyperivor
|
||||
Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/latest)
|
||||
and [our edk2
|
||||
repository](https://github.com/cloud-hypervisor/edk2/releases/latest)
|
||||
|
||||
The choice of firmware depends on your guest OS choice; some experimentation
|
||||
may be required.
|
||||
|
||||
### Firmware Booting
|
||||
|
||||
Cloud Hypervisor supports booting disk images containing all needed components
|
||||
to run cloud workloads, a.k.a. cloud images.
|
||||
|
||||
The following sample commands will download an Ubuntu Cloud image, converting
|
||||
it into a format that Cloud Hypervisor can use and a firmware to boot the image
|
||||
with.
|
||||
|
||||
```shell
|
||||
$ pushd $CLOUDH
|
||||
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
|
||||
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-server-cloudimg-amd64.raw
|
||||
$ wget https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/download/0.4.1/hypervisor-fw
|
||||
$ popd
|
||||
$ wget https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/download/0.4.2/hypervisor-fw
|
||||
```
|
||||
|
||||
The Ubuntu cloud images do not ship with a default password so it necessary to
|
||||
use a `cloud-init` disk image to customise the image on the first boot. A basic
|
||||
`cloud-init` image is generated by this [script](scripts/create-cloud-init.sh).
|
||||
This seeds the image with a default username/password of `cloud/cloud123`. It
|
||||
is only necessary to add this disk image on the first boot.
|
||||
|
||||
```shell
|
||||
$ pushd $CLOUDH
|
||||
$ sudo setcap cap_net_admin+ep ./cloud-hypervisor/target/release/cloud-hypervisor
|
||||
$ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
||||
$ sudo setcap cap_net_admin+ep ./cloud-hypervisor
|
||||
$ ./create-cloud-init.sh
|
||||
$ ./cloud-hypervisor \
|
||||
--kernel ./hypervisor-fw \
|
||||
--disk path=focal-server-cloudimg-amd64.raw \
|
||||
--disk path=focal-server-cloudimg-amd64.raw path=/tmp/ubuntu-cloudinit.img \
|
||||
--cpus boot=4 \
|
||||
--memory size=1024M \
|
||||
--net "tap=,mac=,ip=,mask="
|
||||
$ popd
|
||||
```
|
||||
|
||||
Multiple arguments can be given to the `--disk` parameter.
|
||||
If access to the firmware messages or interaction with the boot loader (e.g.
|
||||
GRUB) is required then it necessary to switch to the serial console instead of
|
||||
`virtio-console`.
|
||||
|
||||
### Custom kernel and disk image
|
||||
```shell
|
||||
$ ./cloud-hypervisor \
|
||||
--kernel ./hypervisor-fw \
|
||||
--disk path=focal-server-cloudimg-amd64.raw path=/tmp/ubuntu-cloudinit.img \
|
||||
--cpus boot=4 \
|
||||
--memory size=1024M \
|
||||
--net "tap=,mac=,ip=,mask=" \
|
||||
--serial tty \
|
||||
--console off
|
||||
```
|
||||
|
||||
#### Building your kernel
|
||||
### Custom Kernel and Disk Image
|
||||
|
||||
Cloud Hypervisor also supports direct kernel boot into a `vmlinux` ELF kernel.
|
||||
In order to support virtio-watchdog we have our own development branch. You are
|
||||
of course able to use your own kernel but these instructions will continue with
|
||||
the version that we develop and test against.
|
||||
#### Building your Kernel
|
||||
|
||||
Cloud Hypervisor also supports direct kernel boot into a `vmlinux` ELF kernel (compiled with PVH support). In order to support development there is a custom branch; however provided the required options are enabled any recent kernel will suffice.
|
||||
|
||||
To build the kernel:
|
||||
|
||||
```shell
|
||||
|
||||
# Clone the Cloud Hypervisor Linux branch
|
||||
$ pushd $CLOUDH
|
||||
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-5.15.12 linux-cloud-hypervisor
|
||||
$ pushd linux-cloud-hypervisor
|
||||
|
||||
# Use the cloud-hypervisor kernel config to build your kernel
|
||||
$ cp $CLOUDH/cloud-hypervisor/resources/linux-config-x86_64 .config
|
||||
$ wget https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/main/resources/linux-config-x86_64
|
||||
$ cp linux-config-x86_64 .config
|
||||
$ KCFLAGS="-Wa,-mx86-used-note=no" make bzImage -j `nproc`
|
||||
$ popd
|
||||
```
|
||||
@@ -232,42 +193,34 @@ The `vmlinux` kernel image will then be located at
|
||||
|
||||
#### Disk image
|
||||
|
||||
For the disk image, we will use a Ubuntu cloud image that contains a root
|
||||
partition:
|
||||
For the disk image the same Ubuntu image as before can be used. This contains
|
||||
an `ext4` root filesystem.
|
||||
|
||||
```shell
|
||||
$ pushd $CLOUDH
|
||||
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
|
||||
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-server-cloudimg-amd64.raw
|
||||
$ popd
|
||||
```
|
||||
|
||||
#### Booting the guest VM
|
||||
|
||||
Now we can directly boot into our custom kernel and make it use the Ubuntu root
|
||||
partition. If we want to have 4 vCPUs and 1024 MBytes of memory:
|
||||
These sample commands boot the disk image using the custom kernel whilst also
|
||||
supplying the desired kernel command line.
|
||||
|
||||
```shell
|
||||
$ pushd $CLOUDH
|
||||
$ sudo setcap cap_net_admin+ep ./cloud-hypervisor/target/release/cloud-hypervisor
|
||||
$ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
||||
$ sudo setcap cap_net_admin+ep ./cloud-hypervisor
|
||||
$ ./create-cloud-init.sh
|
||||
$ ./cloud-hypervisor \
|
||||
--kernel ./linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin \
|
||||
--disk path=focal-server-cloudimg-amd64.raw \
|
||||
--disk path=focal-server-cloudimg-amd64.raw path=/tmp/ubuntu-cloudinit.img \
|
||||
--cmdline "console=hvc0 root=/dev/vda1 rw" \
|
||||
--cpus boot=4 \
|
||||
--memory size=1024M \
|
||||
--net "tap=,mac=,ip=,mask="
|
||||
```
|
||||
|
||||
The above example use the `virtio-console` device as the guest console, and this
|
||||
device may not be enabled soon enough by the guest kernel to get early kernel
|
||||
debug messages.
|
||||
If earlier kernel messages are required the serial console should be used instead of `virtio-console`.
|
||||
|
||||
When in need for earlier debug messages, using the legacy serial device based
|
||||
console is preferred:
|
||||
|
||||
```
|
||||
$ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
||||
```./cloud-hypervisor \
|
||||
--kernel ./linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin \
|
||||
--console off \
|
||||
--serial tty \
|
||||
@@ -280,8 +233,8 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
||||
|
||||
# 3. Status
|
||||
|
||||
Cloud Hypervisor is under active development. The following stability guarantees
|
||||
are currently made:
|
||||
Cloud Hypervisor is under active development. The following stability
|
||||
guarantees are currently made:
|
||||
|
||||
* The API (including command line options) will not be removed or changed in a
|
||||
breaking way without a minimum of 2 major releases notice. Where possible
|
||||
@@ -299,16 +252,18 @@ Currently the following items are **not** guaranteed across updates:
|
||||
* The following features are considered experimental and may change
|
||||
substantially between releases: TDX, vfio-user, vDPA.
|
||||
|
||||
As of 2022-04-05, the following cloud images are supported:
|
||||
Further details can be found in the [release documentation](docs/releases.md).
|
||||
|
||||
- [Ubuntu Bionic](https://cloud-images.ubuntu.com/bionic/current/) (cloudimg)
|
||||
- [Ubuntu Focal](https://cloud-images.ubuntu.com/focal/current/) (cloudimg)
|
||||
- [Ubuntu Jammy](https://cloud-images.ubuntu.com/jammy/current/) (cloudimg)
|
||||
As of 2022-10-13, the following cloud images are supported:
|
||||
|
||||
- [Ubuntu Bionic](https://cloud-images.ubuntu.com/bionic/current/) (bionic-server-cloudimg-amd64.img)
|
||||
- [Ubuntu Focal](https://cloud-images.ubuntu.com/focal/current/) (focal-server-cloudimg-amd64.img)
|
||||
- [Ubuntu Jammy](https://cloud-images.ubuntu.com/jammy/current/) (jammy-server-cloudimg-amd64.img )
|
||||
- [Fedora 36](https://fedora.mirrorservice.org/fedora/linux/releases/36/Cloud/x86_64/images/) (Fedora-Cloud-Base-36-1.5.x86_64.raw.xz)
|
||||
|
||||
Direct kernel boot to userspace should work with a rootfs from most
|
||||
distributions.
|
||||
|
||||
Further details can be found in the [release documentation](docs/releases.md).
|
||||
distributions although you may need to enable exotic filesystem types in the
|
||||
reference kernel configuration (e.g. XFS or btrfs.)
|
||||
|
||||
## Hot Plug
|
||||
|
||||
@@ -321,18 +276,12 @@ Cloud Hypervisor supports hotplug of CPUs, passthrough devices (VFIO),
|
||||
Details of the device model can be found in this
|
||||
[documentation](docs/device_model.md).
|
||||
|
||||
## TODO
|
||||
|
||||
We are not tracking the Cloud Hypervisor TODO list from a specific git tracked
|
||||
file but through
|
||||
[github issues](https://github.com/cloud-hypervisor/cloud-hypervisor/issues/new)
|
||||
instead.
|
||||
|
||||
## Roadmap
|
||||
|
||||
The project roadmap is tracked through a [GitHub project](https://github.com/orgs/cloud-hypervisor/projects/6).
|
||||
The project roadmap is tracked through a [GitHub
|
||||
project](https://github.com/orgs/cloud-hypervisor/projects/6).
|
||||
|
||||
# 4. `rust-vmm` project dependency
|
||||
# 4. Relationship with _Rust VMM_ Project
|
||||
|
||||
In order to satisfy the design goal of having a high-performance,
|
||||
security-focused hypervisor the decision was made to use the
|
||||
@@ -341,39 +290,26 @@ focus on memory and thread safety makes it an ideal candidate for implementing
|
||||
VMMs.
|
||||
|
||||
Instead of implementing the VMM components from scratch, Cloud Hypervisor is
|
||||
importing the [rust-vmm](https://github.com/rust-vmm) crates, and sharing code
|
||||
importing the [Rust VMM](https://github.com/rust-vmm) crates, and sharing code
|
||||
and architecture together with other VMMs like e.g. Amazon's
|
||||
[Firecracker](https://firecracker-microvm.github.io/) and Google's
|
||||
[crosvm](https://chromium.googlesource.com/chromiumos/platform/crosvm/).
|
||||
|
||||
Cloud Hypervisor embraces the rust-vmm project goals, which is to be able to
|
||||
share and re-use as many virtualization crates as possible. As such, the Cloud
|
||||
Hypervisor relationship with the rust-vmm project is twofold:
|
||||
Cloud Hypervisor embraces the _Rust VMM_ project's goals, which is to be able
|
||||
to share and re-use as many virtualization crates as possible.
|
||||
|
||||
1. It will use as much of the rust-vmm code as possible. Any new rust-vmm crate
|
||||
that's relevant to the project goals will be integrated as soon as possible.
|
||||
2. As it is likely that the rust-vmm project will lack some of the features that
|
||||
Cloud Hypervisor needs (e.g. ACPI, VFIO, vhost-user, etc), we will be using
|
||||
the Cloud Hypervisor VMM to implement and test them, and contribute them back
|
||||
to the rust-vmm project.
|
||||
|
||||
## Firecracker and crosvm
|
||||
## Differences with Firecracker and crosvm
|
||||
|
||||
A large part of the Cloud Hypervisor code is based on either the Firecracker or
|
||||
the crosvm projects implementations. Both of these are VMMs written in Rust with
|
||||
a focus on safety and security, like Cloud Hypervisor.
|
||||
the crosvm project's implementations. Both of these are VMMs written in Rust
|
||||
with a focus on safety and security, like Cloud Hypervisor.
|
||||
|
||||
However we want to emphasize that the Cloud Hypervisor project is neither a fork
|
||||
nor a reimplementation of any of those projects. The goals and use cases we're
|
||||
trying to meet are different. We're aiming at supporting cloud workloads, i.e.
|
||||
those modern, full Linux distribution images currently being run by Cloud
|
||||
Service Provider (CSP) tenants.
|
||||
The goal of the Cloud Hypervisor project differs from the aforementioned
|
||||
projects in that it aims to be a general purpose VMM for _Cloud Workloads_ and
|
||||
not limited to container/serverless or client workloads.
|
||||
|
||||
Our primary target is not to support client or serverless use cases, and as such
|
||||
our code base already diverges from the crosvm and Firecracker ones. As we add
|
||||
more features to support our use cases, we believe that the divergence will
|
||||
increase while at the same time sharing as much of the fundamental
|
||||
virtualization code through the rust-vmm project crates as possible.
|
||||
The Cloud Hypervisor community thanks the communities of both the Firecracker
|
||||
and crosvm projects for their excellent work.
|
||||
|
||||
# 5. Community
|
||||
|
||||
@@ -383,12 +319,12 @@ repository.
|
||||
|
||||
## Contribute
|
||||
|
||||
We are working on building a global, diverse and collaborative community around
|
||||
the Cloud Hypervisor project. Anyone who is interested in
|
||||
The project strongly believes in building a global, diverse and collaborative
|
||||
community around the Cloud Hypervisor project. Anyone who is interested in
|
||||
[contributing](CONTRIBUTING.md) to the project is welcome to participate.
|
||||
|
||||
We believe that contributing to a open source project like Cloud Hypervisor
|
||||
covers a lot more than just sending code. Testing, documentation, pull request
|
||||
Contributing to a open source project like Cloud Hypervisor covers a lot more
|
||||
than just sending code. Testing, documentation, pull request
|
||||
reviews, bug reports, feature requests, project improvement suggestions, etc,
|
||||
are all equal and welcome means of contribution. See the
|
||||
[CONTRIBUTING](CONTRIBUTING.md) document for more details.
|
||||
|
||||
@@ -5,4 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
vm-memory = "0.9.0"
|
||||
vm-memory = "0.10.0"
|
||||
|
||||
@@ -1083,7 +1083,7 @@ impl<'a, T> CreateField<'a, T> {
|
||||
buffer,
|
||||
offset,
|
||||
field,
|
||||
phantom: PhantomData::default(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
vmm-sys-util = "0.10.0"
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
@@ -22,16 +22,16 @@ impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use Error::*;
|
||||
match self {
|
||||
Socket(e) => write!(f, "Error writing to or reading from HTTP socket: {}", e),
|
||||
SocketSendFds(e) => write!(f, "Error writing to or reading from HTTP socket: {}", e),
|
||||
StatusCodeParsing(e) => write!(f, "Error parsing HTTP status code: {}", e),
|
||||
Socket(e) => write!(f, "Error writing to or reading from HTTP socket: {e}"),
|
||||
SocketSendFds(e) => write!(f, "Error writing to or reading from HTTP socket: {e}"),
|
||||
StatusCodeParsing(e) => write!(f, "Error parsing HTTP status code: {e}"),
|
||||
MissingProtocol => write!(f, "HTTP output is missing protocol statement"),
|
||||
ContentLengthParsing(e) => write!(f, "Error parsing HTTP Content-Length field: {}", e),
|
||||
ContentLengthParsing(e) => write!(f, "Error parsing HTTP Content-Length field: {e}"),
|
||||
ServerResponse(s, o) => {
|
||||
if let Some(o) = o {
|
||||
write!(f, "Server responded with an error: {:?}: {}", s, o)
|
||||
write!(f, "Server responded with an error: {s:?}: {o}")
|
||||
} else {
|
||||
write!(f, "Server responded with an error: {:?}", s)
|
||||
write!(f, "Server responded with an error: {s:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ impl StatusCode {
|
||||
}
|
||||
|
||||
fn get_header<'a>(res: &'a str, header: &'a str) -> Option<&'a str> {
|
||||
let header_str = format!("{}: ", header);
|
||||
let header_str = format!("{header}: ");
|
||||
res.find(&header_str)
|
||||
.map(|o| &res[o + header_str.len()..o + res[o..].find('\r').unwrap()])
|
||||
}
|
||||
@@ -153,8 +153,7 @@ pub fn simple_api_full_command_with_fds_and_response<T: Read + Write + ScmSocket
|
||||
socket
|
||||
.send_with_fds(
|
||||
&[format!(
|
||||
"{} /api/v1/{} HTTP/1.1\r\nHost: localhost\r\nAccept: */*\r\n",
|
||||
method, full_command
|
||||
"{method} /api/v1/{full_command} HTTP/1.1\r\nHost: localhost\r\nAccept: */*\r\n"
|
||||
)
|
||||
.as_bytes()],
|
||||
&request_fds,
|
||||
@@ -235,7 +234,7 @@ pub fn simple_api_command_with_fds<T: Read + Write + ScmSocket>(
|
||||
) -> Result<(), Error> {
|
||||
// Create the full VM command. For VMM commands, use
|
||||
// simple_api_full_command().
|
||||
let full_command = format!("vm.{}", c);
|
||||
let full_command = format!("vm.{c}");
|
||||
|
||||
simple_api_full_command_with_fds(socket, method, &full_command, request_body, request_fds)
|
||||
}
|
||||
|
||||
@@ -9,20 +9,20 @@ default = []
|
||||
tdx = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.65"
|
||||
anyhow = "1.0.66"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.133"
|
||||
linux-loader = { version = "0.6.0", features = ["elf", "bzimage", "pe"] }
|
||||
libc = "0.2.138"
|
||||
linux-loader = { version = "0.8.1", features = ["elf", "bzimage", "pe"] }
|
||||
log = "0.4.17"
|
||||
serde = { version = "1.0.145", features = ["rc", "derive"] }
|
||||
serde = { version = "1.0.150", features = ["rc", "derive"] }
|
||||
thiserror = "1.0.37"
|
||||
uuid = "1.1.2"
|
||||
versionize = "0.1.6"
|
||||
uuid = "1.2.2"
|
||||
versionize = "0.1.9"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-memory = { version = "0.9.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = { version = "0.10.0", features = ["with-serde"] }
|
||||
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
|
||||
|
||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||
fdt_parser = { version = "0.1.4", package = "fdt" }
|
||||
|
||||
@@ -51,8 +51,6 @@ const SIZE_CELLS: u32 = 0x2;
|
||||
// Look for "The 1st cell..."
|
||||
const GIC_FDT_IRQ_TYPE_SPI: u32 = 0;
|
||||
const GIC_FDT_IRQ_TYPE_PPI: u32 = 1;
|
||||
const GIC_FDT_IRQ_PPI_CPU_SHIFT: u32 = 8;
|
||||
const GIC_FDT_IRQ_PPI_CPU_MASK: u32 = 0xff << GIC_FDT_IRQ_PPI_CPU_SHIFT;
|
||||
|
||||
// From https://elixir.bootlin.com/linux/v4.9.62/source/include/dt-bindings/interrupt-controller/irq.h#L17
|
||||
const IRQ_TYPE_EDGE_RISING: u32 = 1;
|
||||
@@ -121,7 +119,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
|
||||
create_gic_node(&mut fdt, gic_device)?;
|
||||
create_timer_node(&mut fdt)?;
|
||||
if pmu_supported {
|
||||
create_pmu_node(&mut fdt, vcpu_mpidr.len())?;
|
||||
create_pmu_node(&mut fdt)?;
|
||||
}
|
||||
create_clock_node(&mut fdt)?;
|
||||
create_psci_node(&mut fdt)?;
|
||||
@@ -162,7 +160,7 @@ fn create_cpu_nodes(
|
||||
let num_cpus = vcpu_mpidr.len();
|
||||
|
||||
for (cpu_id, mpidr) in vcpu_mpidr.iter().enumerate().take(num_cpus) {
|
||||
let cpu_name = format!("cpu@{:x}", cpu_id);
|
||||
let cpu_name = format!("cpu@{cpu_id:x}");
|
||||
let cpu_node = fdt.begin_node(&cpu_name)?;
|
||||
fdt.property_string("device_type", "cpu")?;
|
||||
fdt.property_string("compatible", "arm,arm-v8")?;
|
||||
@@ -194,15 +192,15 @@ fn create_cpu_nodes(
|
||||
|
||||
// Create device tree nodes with regard of above mapping.
|
||||
for cluster_idx in 0..packages {
|
||||
let cluster_name = format!("cluster{:x}", cluster_idx);
|
||||
let cluster_name = format!("cluster{cluster_idx:x}");
|
||||
let cluster_node = fdt.begin_node(&cluster_name)?;
|
||||
|
||||
for core_idx in 0..cores_per_package {
|
||||
let core_name = format!("core{:x}", core_idx);
|
||||
let core_name = format!("core{core_idx:x}");
|
||||
let core_node = fdt.begin_node(&core_name)?;
|
||||
|
||||
for thread_idx in 0..threads_per_core {
|
||||
let thread_name = format!("thread{:x}", thread_idx);
|
||||
let thread_name = format!("thread{thread_idx:x}");
|
||||
let thread_node = fdt.begin_node(&thread_name)?;
|
||||
let cpu_idx = threads_per_core * cores_per_package * cluster_idx
|
||||
+ threads_per_core * core_idx
|
||||
@@ -249,7 +247,7 @@ fn create_memory_node(
|
||||
node_memory_addr = memory_region_start_addr;
|
||||
}
|
||||
}
|
||||
let memory_node_name = format!("memory@{:x}", node_memory_addr);
|
||||
let memory_node_name = format!("memory@{node_memory_addr:x}");
|
||||
let memory_node = fdt.begin_node(&memory_node_name)?;
|
||||
fdt.property_string("device_type", "memory")?;
|
||||
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
||||
@@ -541,16 +539,9 @@ fn create_devices_node<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Buil
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_pmu_node(fdt: &mut FdtWriter, cpu_nums: usize) -> FdtWriterResult<()> {
|
||||
let num_cpus = cpu_nums as u64 as u32;
|
||||
fn create_pmu_node(fdt: &mut FdtWriter) -> FdtWriterResult<()> {
|
||||
let compatible = "arm,armv8-pmuv3";
|
||||
let cpu_mask: u32 =
|
||||
(((1 << num_cpus) - 1) << GIC_FDT_IRQ_PPI_CPU_SHIFT) & GIC_FDT_IRQ_PPI_CPU_MASK;
|
||||
let irq = [
|
||||
GIC_FDT_IRQ_TYPE_PPI,
|
||||
AARCH64_PMU_IRQ,
|
||||
cpu_mask | IRQ_TYPE_LEVEL_HI,
|
||||
];
|
||||
let irq = [GIC_FDT_IRQ_TYPE_PPI, AARCH64_PMU_IRQ, IRQ_TYPE_LEVEL_HI];
|
||||
|
||||
let pmu_node = fdt.begin_node("pmu")?;
|
||||
fdt.property_string("compatible", compatible)?;
|
||||
@@ -679,7 +670,7 @@ fn create_pci_nodes(
|
||||
|
||||
// See kernel document Documentation/devicetree/bindings/virtio/iommu.txt
|
||||
// for virtio-iommu node settings.
|
||||
let virtio_iommu_node_name = format!("virtio_iommu@{:x}", virtio_iommu_bdf);
|
||||
let virtio_iommu_node_name = format!("virtio_iommu@{virtio_iommu_bdf:x}");
|
||||
let virtio_iommu_node = fdt.begin_node(&virtio_iommu_node_name)?;
|
||||
fdt.property_u32("#iommu-cells", 1)?;
|
||||
fdt.property_string("compatible", "virtio,pci-iommu")?;
|
||||
|
||||
@@ -98,6 +98,11 @@ pub const RAM_START: GuestAddress = GuestAddress(0x4000_0000);
|
||||
pub const MEM_32BIT_RESERVED_START: GuestAddress = GuestAddress(0xfc00_0000);
|
||||
pub const MEM_32BIT_RESERVED_SIZE: u64 = 0x0400_0000;
|
||||
|
||||
/// TPM Address Range
|
||||
/// This Address range is specific to CRB Interface
|
||||
pub const TPM_START: GuestAddress = GuestAddress(0xfed4_0000);
|
||||
pub const TPM_SIZE: u64 = 0x1000;
|
||||
|
||||
/// Start of 64-bit RAM.
|
||||
pub const RAM_64BIT_START: GuestAddress = GuestAddress(0x1_0000_0000);
|
||||
|
||||
|
||||
@@ -34,9 +34,7 @@ where
|
||||
if uefi_size > 0x300000 {
|
||||
return Err(Error::UefiTooBig);
|
||||
}
|
||||
uefi_image
|
||||
.seek(SeekFrom::Start(0))
|
||||
.map_err(|_| Error::SeekUefiStart)?;
|
||||
uefi_image.rewind().map_err(|_| Error::SeekUefiStart)?;
|
||||
guest_mem
|
||||
.read_exact_from(guest_addr, uefi_image, uefi_size)
|
||||
.map_err(|_| Error::ReadUefiImage)
|
||||
|
||||
@@ -145,7 +145,7 @@ pub const PAGE_SIZE: usize = 4096;
|
||||
|
||||
impl fmt::Display for DeviceType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
write!(f, "{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -107,6 +107,11 @@ pub const KVM_TSS_SIZE: u64 = (3 * 4) << 10;
|
||||
pub const KVM_IDENTITY_MAP_START: GuestAddress = GuestAddress(KVM_TSS_START.0 + KVM_TSS_SIZE);
|
||||
pub const KVM_IDENTITY_MAP_SIZE: u64 = 4 << 10;
|
||||
|
||||
/// TPM Address Range
|
||||
/// This Address range is specific to CRB Interface
|
||||
pub const TPM_START: GuestAddress = GuestAddress(0xfed4_0000);
|
||||
pub const TPM_SIZE: u64 = 0x1000;
|
||||
|
||||
// IOAPIC
|
||||
pub const IOAPIC_START: GuestAddress = GuestAddress(0xfec0_0000);
|
||||
pub const IOAPIC_SIZE: u64 = 0x20;
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::GuestMemoryMmap;
|
||||
use crate::InitramfsConfig;
|
||||
use crate::RegionType;
|
||||
use hypervisor::arch::x86::{CpuIdEntry, CPUID_FLAG_VALID_INDEX};
|
||||
use hypervisor::HypervisorError;
|
||||
use hypervisor::{HypervisorCpuError, HypervisorError};
|
||||
use linux_loader::loader::bootparam::boot_params;
|
||||
use linux_loader::loader::elf::start_info::{
|
||||
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
|
||||
@@ -36,6 +36,7 @@ pub mod tdx;
|
||||
const TSC_DEADLINE_TIMER_ECX_BIT: u8 = 24; // tsc deadline timer ecx bit.
|
||||
const HYPERVISOR_ECX_BIT: u8 = 31; // Hypervisor ecx bit.
|
||||
const MTRR_EDX_BIT: u8 = 12; // Hypervisor ecx bit.
|
||||
const INVARIANT_TSC_EDX_BIT: u8 = 8; // Invariant TSC bit on 0x8000_0007 EDX
|
||||
|
||||
// KVM feature bits
|
||||
const KVM_FEATURE_ASYNC_PF_INT_BIT: u8 = 14;
|
||||
@@ -191,6 +192,9 @@ pub enum Error {
|
||||
// Error writing EBDA address
|
||||
EbdaSetup(vm_memory::GuestMemoryError),
|
||||
|
||||
// Error getting CPU TSC frequency
|
||||
GetTscFrequency(HypervisorCpuError),
|
||||
|
||||
/// Error retrieving TDX capabilities through the hypervisor (kvm/mshv) API
|
||||
#[cfg(feature = "tdx")]
|
||||
TdxCapabilities(HypervisorError),
|
||||
@@ -631,6 +635,20 @@ pub fn generate_common_cpuid(
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copy host L2 cache details if not populated by KVM
|
||||
0x8000_0006 => {
|
||||
if entry.eax == 0 && entry.ebx == 0 && entry.ecx == 0 && entry.edx == 0 {
|
||||
// SAFETY: cpuid called with valid leaves
|
||||
if unsafe { std::arch::x86_64::__cpuid(0x8000_0000).eax } >= 0x8000_0006 {
|
||||
// SAFETY: cpuid called with valid leaves
|
||||
let leaf = unsafe { std::arch::x86_64::__cpuid(0x8000_0006) };
|
||||
entry.eax = leaf.eax;
|
||||
entry.ebx = leaf.ebx;
|
||||
entry.ecx = leaf.ecx;
|
||||
entry.edx = leaf.edx;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set CPU physical bits
|
||||
0x8000_0008 => {
|
||||
entry.eax = (entry.eax & 0xffff_ff00) | (phys_bits as u32 & 0xff);
|
||||
@@ -735,6 +753,41 @@ pub fn configure_vcpu(
|
||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
|
||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
|
||||
|
||||
// Set ApicId in cpuid for each vcpu
|
||||
// SAFETY: get host cpuid when eax=1
|
||||
let mut cpu_ebx = unsafe { core::arch::x86_64::__cpuid(1) }.ebx;
|
||||
cpu_ebx &= 0xffffff;
|
||||
cpu_ebx |= (id as u32) << 24;
|
||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
|
||||
|
||||
// The TSC frequency CPUID leaf should not be included when running with HyperV emulation
|
||||
if !kvm_hyperv {
|
||||
if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? {
|
||||
// Need to check that the TSC doesn't vary with dynamic frequency
|
||||
// SAFETY: cpuid called with valid leaves
|
||||
if unsafe { std::arch::x86_64::__cpuid(0x8000_0007) }.edx
|
||||
& (1u32 << INVARIANT_TSC_EDX_BIT)
|
||||
> 0
|
||||
{
|
||||
CpuidPatch::set_cpuid_reg(
|
||||
&mut cpuid,
|
||||
0x4000_0000,
|
||||
None,
|
||||
CpuidReg::EAX,
|
||||
0x4000_0010,
|
||||
);
|
||||
cpuid.retain(|c| c.function != 0x4000_0010);
|
||||
cpuid.push(CpuIdEntry {
|
||||
function: 0x4000_0010,
|
||||
eax: tsc_khz,
|
||||
ebx: 1000000, /* LAPIC resolution of 1ns (freq: 1GHz) is hardcoded in KVM's
|
||||
* APIC_BUS_CYCLE_NS */
|
||||
..Default::default()
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
vcpu.set_cpuid2(&cpuid)
|
||||
.map_err(|e| Error::SetSupportedCpusFailed(e.into()))?;
|
||||
|
||||
@@ -764,11 +817,11 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
|
||||
.checked_add(layout::MEM_32BIT_DEVICES_SIZE)
|
||||
.expect("32-bit reserved region is too large");
|
||||
|
||||
let requested_memory_size = GuestAddress(size as u64);
|
||||
let requested_memory_size = GuestAddress(size);
|
||||
let mut regions = Vec::new();
|
||||
|
||||
// case1: guest memory fits before the gap
|
||||
if size as u64 <= layout::MEM_32BIT_RESERVED_START.raw_value() {
|
||||
if size <= layout::MEM_32BIT_RESERVED_START.raw_value() {
|
||||
regions.push((GuestAddress(0), size as usize, RegionType::Ram));
|
||||
// case2: guest memory extends beyond the gap
|
||||
} else {
|
||||
@@ -865,7 +918,7 @@ fn configure_pvh(
|
||||
start_info.0.magic = XEN_HVM_START_MAGIC_VALUE;
|
||||
start_info.0.version = 1; // pvh has version 1
|
||||
start_info.0.nr_modules = 0;
|
||||
start_info.0.cmdline_paddr = cmdline_addr.raw_value() as u64;
|
||||
start_info.0.cmdline_paddr = cmdline_addr.raw_value();
|
||||
start_info.0.memmap_paddr = layout::MEMMAP_START.raw_value();
|
||||
|
||||
if let Some(rsdp_addr) = rsdp_addr {
|
||||
@@ -934,7 +987,7 @@ fn configure_pvh(
|
||||
add_memmap_entry(
|
||||
&mut memmap,
|
||||
sgx_epc_region.start().raw_value(),
|
||||
sgx_epc_region.size() as u64,
|
||||
sgx_epc_region.size(),
|
||||
E820_RESERVED,
|
||||
);
|
||||
}
|
||||
@@ -1126,7 +1179,7 @@ fn update_cpuid_sgx(
|
||||
for (i, epc_section) in epc_sections.iter().enumerate() {
|
||||
let subleaf_idx = i + 2;
|
||||
let start = epc_section.start().raw_value();
|
||||
let size = epc_section.size() as u64;
|
||||
let size = epc_section.size();
|
||||
let eax = (start & 0xffff_f000) as u32 | 0x1;
|
||||
let ebx = (start >> 32) as u32;
|
||||
let ecx = (size & 0xffff_f000) as u32 | (leaf.ecx & 0xf);
|
||||
@@ -1302,6 +1355,6 @@ mod tests {
|
||||
add_memmap_entry(&mut memmap, 0, 0x1000, E820_RAM);
|
||||
add_memmap_entry(&mut memmap, 0x10000, 0xa000, E820_RESERVED);
|
||||
|
||||
assert_eq!(format!("{:?}", memmap), format!("{:?}", expected_memmap));
|
||||
assert_eq!(format!("{memmap:?}"), format!("{expected_memmap:?}"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ mod tests {
|
||||
mpspec::MP_IOAPIC => mem::size_of::<MpcIoapicWrapper>(),
|
||||
mpspec::MP_INTSRC => mem::size_of::<MpcIntsrcWrapper>(),
|
||||
mpspec::MP_LINTSRC => mem::size_of::<MpcLintsrcWrapper>(),
|
||||
_ => panic!("unrecognized mpc table entry type: {}", type_),
|
||||
_ => panic!("unrecognized mpc table entry type: {type_}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ pub fn configure_segments_and_sregs(
|
||||
mem: &GuestMemoryMmap,
|
||||
sregs: &mut SpecialRegisters,
|
||||
) -> Result<()> {
|
||||
let gdt_table: [u64; BOOT_GDT_MAX as usize] = {
|
||||
let gdt_table: [u64; BOOT_GDT_MAX] = {
|
||||
// Configure GDT entries as specified by PVH boot protocol
|
||||
[
|
||||
gdt_entry(0, 0, 0), // NULL
|
||||
|
||||
@@ -48,10 +48,10 @@ impl Display for Error {
|
||||
Clear => "Failure while zeroing out the memory for the SMBIOS table".to_string(),
|
||||
WriteSmbiosEp => "Failure to write SMBIOS entrypoint structure".to_string(),
|
||||
WriteData => "Failure to write additional data to memory".to_string(),
|
||||
ParseUuid(e) => format!("Failure to parse uuid: {}", e),
|
||||
ParseUuid(e) => format!("Failure to parse uuid: {e}"),
|
||||
};
|
||||
|
||||
write!(f, "SMBIOS error: {}", description)
|
||||
write!(f, "SMBIOS error: {description}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ pub struct TdvfSection {
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub enum TdvfSectionType {
|
||||
Bfv,
|
||||
Cfv,
|
||||
@@ -55,15 +55,10 @@ pub enum TdvfSectionType {
|
||||
PermMem,
|
||||
Payload,
|
||||
PayloadParam,
|
||||
#[default]
|
||||
Reserved = 0xffffffff,
|
||||
}
|
||||
|
||||
impl Default for TdvfSectionType {
|
||||
fn default() -> Self {
|
||||
TdvfSectionType::Reserved
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfError> {
|
||||
// The 32-bit offset to the TDVF metadata is located 32 bytes from
|
||||
// the end of the file.
|
||||
@@ -120,21 +115,16 @@ pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfErro
|
||||
}
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
enum HobType {
|
||||
Handoff = 0x1,
|
||||
ResourceDescriptor = 0x3,
|
||||
GuidExtension = 0x4,
|
||||
#[default]
|
||||
Unused = 0xfffe,
|
||||
EndOfHobList = 0xffff,
|
||||
}
|
||||
|
||||
impl Default for HobType {
|
||||
fn default() -> Self {
|
||||
HobType::Unused
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
struct HobHeader {
|
||||
@@ -184,19 +174,14 @@ struct HobGuidType {
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub enum PayloadImageType {
|
||||
#[default]
|
||||
ExecutablePayload,
|
||||
BzImage,
|
||||
RawVmLinux,
|
||||
}
|
||||
|
||||
impl Default for PayloadImageType {
|
||||
fn default() -> Self {
|
||||
PayloadImageType::ExecutablePayload
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
pub struct PayloadInfo {
|
||||
@@ -447,7 +432,7 @@ mod tests {
|
||||
let mut f = std::fs::File::open("tdvf.fd").unwrap();
|
||||
let sections = parse_tdvf_sections(&mut f).unwrap();
|
||||
for section in sections {
|
||||
eprintln!("{:x?}", section)
|
||||
eprintln!("{section:x?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,17 +8,17 @@ edition = "2021"
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
io-uring = "0.5.6"
|
||||
libc = "0.2.133"
|
||||
io-uring = "0.5.9"
|
||||
libc = "0.2.138"
|
||||
log = "0.4.17"
|
||||
qcow = { path = "../qcow" }
|
||||
thiserror = "1.0.37"
|
||||
versionize = "0.1.6"
|
||||
versionize = "0.1.9"
|
||||
versionize_derive = "0.1.4"
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
|
||||
virtio-queue = "0.6.1"
|
||||
vm-memory = { version = "0.9.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
virtio-queue = "0.7.0"
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.10.0"
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
|
||||
@@ -51,23 +51,23 @@ pub const SECTOR_SIZE: u64 = 0x01 << SECTOR_SHIFT;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Guest gave us bad memory addresses.")]
|
||||
#[error("Guest gave us bad memory addresses")]
|
||||
GuestMemory(GuestMemoryError),
|
||||
#[error("Guest gave us offsets that would have overflowed a usize.")]
|
||||
#[error("Guest gave us offsets that would have overflowed a usize")]
|
||||
CheckedOffset(GuestAddress, usize),
|
||||
#[error("Guest gave us a write only descriptor that protocol says to read from.")]
|
||||
#[error("Guest gave us a write only descriptor that protocol says to read from")]
|
||||
UnexpectedWriteOnlyDescriptor,
|
||||
#[error("Guest gave us a read only descriptor that protocol says to write to.")]
|
||||
#[error("Guest gave us a read only descriptor that protocol says to write to")]
|
||||
UnexpectedReadOnlyDescriptor,
|
||||
#[error("Guest gave us too few descriptors in a descriptor chain.")]
|
||||
#[error("Guest gave us too few descriptors in a descriptor chain")]
|
||||
DescriptorChainTooShort,
|
||||
#[error("Guest gave us a descriptor that was too short to use.")]
|
||||
#[error("Guest gave us a descriptor that was too short to use")]
|
||||
DescriptorLengthTooSmall,
|
||||
#[error("Getting a block's metadata fails for any reason.")]
|
||||
#[error("Getting a block's metadata fails for any reason")]
|
||||
GetFileMetadata,
|
||||
#[error("The requested operation would cause a seek beyond disk end.")]
|
||||
#[error("The requested operation would cause a seek beyond disk end")]
|
||||
InvalidOffset,
|
||||
#[error("The requested operation does not support multiple descriptors.")]
|
||||
#[error("The requested operation does not support multiple descriptors")]
|
||||
TooManyDescriptors,
|
||||
}
|
||||
|
||||
@@ -566,15 +566,15 @@ pub fn block_io_uring_is_supported() -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check IORING_OP_READ is supported
|
||||
if !probe.is_supported(opcode::Read::CODE) {
|
||||
info!("{} IORING_OP_READ operation not supported", error_msg);
|
||||
// Check IORING_OP_READV is supported
|
||||
if !probe.is_supported(opcode::Readv::CODE) {
|
||||
info!("{} IORING_OP_READV operation not supported", error_msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check IORING_OP_WRITE is supported
|
||||
if !probe.is_supported(opcode::Write::CODE) {
|
||||
info!("{} IORING_OP_WRITE operation not supported", error_msg);
|
||||
// Check IORING_OP_WRITEV is supported
|
||||
if !probe.is_supported(opcode::Writev::CODE) {
|
||||
info!("{} IORING_OP_WRITEV operation not supported", error_msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ impl DiskFile for QcowDiskSync {
|
||||
fn size(&mut self) -> DiskFileResult<u64> {
|
||||
let mut file = self.qcow_file.lock().unwrap();
|
||||
|
||||
Ok(file.seek(SeekFrom::End(0)).map_err(DiskFileError::Size)? as u64)
|
||||
file.seek(SeekFrom::End(0)).map_err(DiskFileError::Size)
|
||||
}
|
||||
|
||||
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||
|
||||
@@ -23,10 +23,9 @@ impl RawFileDisk {
|
||||
|
||||
impl DiskFile for RawFileDisk {
|
||||
fn size(&mut self) -> DiskFileResult<u64> {
|
||||
Ok(self
|
||||
.file
|
||||
self.file
|
||||
.seek(SeekFrom::End(0))
|
||||
.map_err(DiskFileError::Size)? as u64)
|
||||
.map_err(DiskFileError::Size)
|
||||
}
|
||||
|
||||
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||
|
||||
@@ -22,10 +22,9 @@ impl RawFileDiskSync {
|
||||
|
||||
impl DiskFile for RawFileDiskSync {
|
||||
fn size(&mut self) -> DiskFileResult<u64> {
|
||||
Ok(self
|
||||
.file
|
||||
self.file
|
||||
.seek(SeekFrom::End(0))
|
||||
.map_err(DiskFileError::Size)? as u64)
|
||||
.map_err(DiskFileError::Size)
|
||||
}
|
||||
|
||||
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||
@@ -72,7 +71,7 @@ impl AsyncIo for RawFileSync {
|
||||
let result = unsafe {
|
||||
libc::preadv(
|
||||
self.fd as libc::c_int,
|
||||
iovecs.as_ptr() as *const libc::iovec,
|
||||
iovecs.as_ptr(),
|
||||
iovecs.len() as libc::c_int,
|
||||
offset,
|
||||
)
|
||||
@@ -96,7 +95,7 @@ impl AsyncIo for RawFileSync {
|
||||
let result = unsafe {
|
||||
libc::pwritev(
|
||||
self.fd as libc::c_int,
|
||||
iovecs.as_ptr() as *const libc::iovec,
|
||||
iovecs.as_ptr(),
|
||||
iovecs.len() as libc::c_int,
|
||||
offset,
|
||||
)
|
||||
@@ -118,7 +117,7 @@ impl AsyncIo for RawFileSync {
|
||||
}
|
||||
|
||||
if let Some(user_data) = user_data {
|
||||
self.completion_list.push((user_data, result as i32));
|
||||
self.completion_list.push((user_data, result));
|
||||
self.eventfd.write(1).unwrap();
|
||||
}
|
||||
|
||||
|
||||
2
build.rs
2
build.rs
@@ -23,5 +23,5 @@ fn main() {
|
||||
// variable BUILT_VERSION, so that it can be reused from the binary.
|
||||
// Particularly, this is used from src/main.rs to display the exact
|
||||
// version.
|
||||
println!("cargo:rustc-env=BUILT_VERSION={}", version);
|
||||
println!("cargo:rustc-env=BUILT_VERSION={version}");
|
||||
}
|
||||
|
||||
@@ -6,19 +6,22 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { path = "../acpi_tables" }
|
||||
anyhow = "1.0.65"
|
||||
anyhow = "1.0.66"
|
||||
arch = { path = "../arch" }
|
||||
bitflags = "1.3.2"
|
||||
bitflags = "2.4.1"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.133"
|
||||
libc = "0.2.138"
|
||||
log = "0.4.17"
|
||||
versionize = "0.1.6"
|
||||
phf = { version = "0.11.1", features = ["macros"] }
|
||||
thiserror = "1.0.37"
|
||||
tpm = { path = "../tpm" }
|
||||
versionize = "0.1.9"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = "0.9.0"
|
||||
vm-memory = "0.10.0"
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = "0.10.0"
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||
arch = { path = "../arch" }
|
||||
|
||||
@@ -114,7 +114,7 @@ impl Aml for AcpiGedDevice {
|
||||
&aml::ResourceTemplate::new(vec![&aml::AddressSpace::new_memory(
|
||||
aml::AddressSpaceCachable::NotCacheable,
|
||||
true,
|
||||
self.address.0 as u64,
|
||||
self.address.0,
|
||||
self.address.0 + GED_DEVICE_ACPI_SIZE as u64 - 1,
|
||||
)]),
|
||||
),
|
||||
|
||||
@@ -40,11 +40,11 @@ impl DebugIoPortRange {
|
||||
impl fmt::Display for DebugIoPortRange {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
DebugIoPortRange::Firmware => write!(f, "{}: Firmware", DEBUG_IOPORT_PREFIX),
|
||||
DebugIoPortRange::Bootloader => write!(f, "{}: Bootloader", DEBUG_IOPORT_PREFIX),
|
||||
DebugIoPortRange::Kernel => write!(f, "{}: Kernel", DEBUG_IOPORT_PREFIX),
|
||||
DebugIoPortRange::Userspace => write!(f, "{}: Userspace", DEBUG_IOPORT_PREFIX),
|
||||
DebugIoPortRange::Custom => write!(f, "{}: Custom", DEBUG_IOPORT_PREFIX),
|
||||
DebugIoPortRange::Firmware => write!(f, "{DEBUG_IOPORT_PREFIX}: Firmware"),
|
||||
DebugIoPortRange::Bootloader => write!(f, "{DEBUG_IOPORT_PREFIX}: Bootloader"),
|
||||
DebugIoPortRange::Kernel => write!(f, "{DEBUG_IOPORT_PREFIX}: Kernel"),
|
||||
DebugIoPortRange::Userspace => write!(f, "{DEBUG_IOPORT_PREFIX}: Userspace"),
|
||||
DebugIoPortRange::Custom => write!(f, "{DEBUG_IOPORT_PREFIX}: Custom"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,13 +51,13 @@ pub enum Error {
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::BadWriteOffset(offset) => write!(f, "Bad Write Offset: {}", offset),
|
||||
Error::BadWriteOffset(offset) => write!(f, "Bad Write Offset: {offset}"),
|
||||
Error::GpioInterruptDisabled => write!(f, "GPIO interrupt disabled by guest driver.",),
|
||||
Error::GpioInterruptFailure(ref e) => {
|
||||
write!(f, "Could not trigger GPIO interrupt: {}.", e)
|
||||
write!(f, "Could not trigger GPIO interrupt: {e}.")
|
||||
}
|
||||
Error::GpioTriggerKeyFailure(key) => {
|
||||
write!(f, "Invalid GPIO Input key triggerd: {}.", key)
|
||||
write!(f, "Invalid GPIO Input key triggerd: {key}.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ pub enum Error {
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::BadWriteOffset(offset) => write!(f, "Bad Write Offset: {}", offset),
|
||||
Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {}", e),
|
||||
Error::BadWriteOffset(offset) => write!(f, "Bad Write Offset: {offset}"),
|
||||
Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ impl Serial {
|
||||
}
|
||||
|
||||
fn handle_write(&mut self, offset: u8, v: u8) -> Result<()> {
|
||||
match offset as u8 {
|
||||
match offset {
|
||||
DLAB_LOW if self.is_dlab_set() => {
|
||||
self.baud_divisor = (self.baud_divisor & 0xff00) | u16::from(v)
|
||||
}
|
||||
|
||||
@@ -60,11 +60,11 @@ pub enum Error {
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::BadWriteOffset(offset) => write!(f, "pl011_write: Bad Write Offset: {}", offset),
|
||||
Error::BadWriteOffset(offset) => write!(f, "pl011_write: Bad Write Offset: {offset}"),
|
||||
Error::DmaNotImplemented => write!(f, "pl011: DMA not implemented."),
|
||||
Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {}", e),
|
||||
Error::WriteAllFailure(e) => write!(f, "Failed to write: {}", e),
|
||||
Error::FlushFailure(e) => write!(f, "Failed to flush: {}", e),
|
||||
Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {e}"),
|
||||
Error::WriteAllFailure(e) => write!(f, "Failed to write: {e}"),
|
||||
Error::FlushFailure(e) => write!(f, "Failed to flush: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ pub mod interrupt_controller;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub mod ioapic;
|
||||
pub mod legacy;
|
||||
pub mod tpm;
|
||||
|
||||
pub use self::acpi::{AcpiGedDevice, AcpiPmTimerDevice, AcpiShutdownDevice};
|
||||
|
||||
|
||||
467
devices/src/tpm.rs
Normal file
467
devices/src/tpm.rs
Normal file
@@ -0,0 +1,467 @@
|
||||
// Copyright © 2022, Microsoft Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use anyhow::anyhow;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use arch::aarch64::layout::{TPM_SIZE, TPM_START};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use arch::x86_64::layout::{TPM_SIZE, TPM_START};
|
||||
use phf::phf_map;
|
||||
use std::cmp;
|
||||
use std::sync::{Arc, Barrier};
|
||||
use thiserror::Error;
|
||||
use tpm::emulator::{BackendCmd, Emulator};
|
||||
use tpm::TPM_CRB_BUFFER_MAX;
|
||||
use tpm::TPM_SUCCESS;
|
||||
use vm_device::BusDevice;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Emulator doesn't implement min required capabilities: {0}")]
|
||||
CheckCaps(#[source] anyhow::Error),
|
||||
#[error("Failed to initialize tpm: {0}")]
|
||||
Init(#[source] anyhow::Error),
|
||||
#[error("Failed to deliver tpm Command: {0}")]
|
||||
DeliverRequest(#[source] anyhow::Error),
|
||||
}
|
||||
type Result<T> = anyhow::Result<T, Error>;
|
||||
|
||||
/* crb 32-bit registers */
|
||||
const CRB_LOC_STATE: u32 = 0x0;
|
||||
//Register Fields
|
||||
// Field => (start, length)
|
||||
// start: lowest bit in the bit field numbered from 0
|
||||
// length: length of the bit field
|
||||
const CRB_LOC_STATE_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
|
||||
"tpmEstablished" => [0, 1],
|
||||
"locAssigned" => [1,1],
|
||||
"activeLocality"=> [2, 3],
|
||||
"reserved" => [5, 2],
|
||||
"tpmRegValidSts" => [7, 1]
|
||||
};
|
||||
const CRB_LOC_CTRL: u32 = 0x08;
|
||||
const CRB_LOC_CTRL_REQUEST_ACCESS: u32 = 1 << 0;
|
||||
const CRB_LOC_CTRL_RELINQUISH: u32 = 1 << 1;
|
||||
const CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT: u32 = 1 << 3;
|
||||
const CRB_LOC_STS: u32 = 0x0C;
|
||||
const CRB_LOC_STS_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
|
||||
"Granted" => [0, 1],
|
||||
"beenSeized" => [1,1]
|
||||
};
|
||||
const CRB_INTF_ID: u32 = 0x30;
|
||||
const CRB_INTF_ID_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
|
||||
"InterfaceType" => [0, 4],
|
||||
"InterfaceVersion" => [4, 4],
|
||||
"CapLocality" => [8, 1],
|
||||
"CapCRBIdleBypass" => [9, 1],
|
||||
"Reserved1" => [10, 1],
|
||||
"CapDataXferSizeSupport" => [11, 2],
|
||||
"CapFIFO" => [13, 1],
|
||||
"CapCRB" => [14, 1],
|
||||
"CapIFRes" => [15, 2],
|
||||
"InterfaceSelector" => [17, 2],
|
||||
"IntfSelLock" => [19, 1],
|
||||
"Reserved2" => [20, 4],
|
||||
"RID" => [24, 8]
|
||||
};
|
||||
const CRB_INTF_ID2: u32 = 0x34;
|
||||
const CRB_INTF_ID2_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
|
||||
"VID" => [0, 16],
|
||||
"DID" => [16, 16]
|
||||
};
|
||||
const CRB_CTRL_REQ: u32 = 0x40;
|
||||
const CRB_CTRL_REQ_CMD_READY: u32 = 1 << 0;
|
||||
const CRB_CTRL_REQ_GO_IDLE: u32 = 1 << 1;
|
||||
const CRB_CTRL_STS: u32 = 0x44;
|
||||
const CRB_CTRL_STS_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
|
||||
"tpmSts" => [0, 1],
|
||||
"tpmIdle" => [1, 1]
|
||||
};
|
||||
const CRB_CTRL_CANCEL: u32 = 0x48;
|
||||
const CRB_CANCEL_INVOKE: u32 = 1 << 0;
|
||||
const CRB_CTRL_START: u32 = 0x4C;
|
||||
const CRB_START_INVOKE: u32 = 1 << 0;
|
||||
const CRB_CTRL_CMD_LADDR: u32 = 0x5C;
|
||||
const CRB_CTRL_CMD_HADDR: u32 = 0x60;
|
||||
const CRB_CTRL_RSP_SIZE: u32 = 0x64;
|
||||
const CRB_CTRL_RSP_ADDR: u32 = 0x68;
|
||||
const CRB_DATA_BUFFER: u32 = 0x80;
|
||||
|
||||
const TPM_CRB_NO_LOCALITY: u32 = 0xff;
|
||||
|
||||
const TPM_CRB_ADDR_BASE: u32 = TPM_START.0 as u32;
|
||||
const TPM_CRB_ADDR_SIZE: usize = TPM_SIZE as usize;
|
||||
|
||||
const TPM_CRB_R_MAX: u32 = CRB_DATA_BUFFER;
|
||||
|
||||
// CRB Protocol details
|
||||
const CRB_INTF_TYPE_CRB_ACTIVE: u32 = 0b1;
|
||||
const CRB_INTF_VERSION_CRB: u32 = 0b1;
|
||||
const CRB_INTF_CAP_LOCALITY_0_ONLY: u32 = 0b0;
|
||||
const CRB_INTF_CAP_IDLE_FAST: u32 = 0b0;
|
||||
const CRB_INTF_CAP_XFER_SIZE_64: u32 = 0b11;
|
||||
const CRB_INTF_CAP_FIFO_NOT_SUPPORTED: u32 = 0b0;
|
||||
const CRB_INTF_CAP_CRB_SUPPORTED: u32 = 0b1;
|
||||
const CRB_INTF_IF_SELECTOR_CRB: u32 = 0b1;
|
||||
const PCI_VENDOR_ID_IBM: u32 = 0x1014;
|
||||
const CRB_CTRL_CMD_SIZE_REG: u32 = 0x58;
|
||||
const CRB_CTRL_CMD_SIZE: usize = TPM_CRB_ADDR_SIZE - CRB_DATA_BUFFER as usize;
|
||||
|
||||
fn get_fields_map(reg: u32) -> phf::Map<&'static str, [u32; 2]> {
|
||||
match reg {
|
||||
CRB_LOC_STATE => CRB_LOC_STATE_FIELDS,
|
||||
CRB_LOC_STS => CRB_LOC_STS_FIELDS,
|
||||
CRB_INTF_ID => CRB_INTF_ID_FIELDS,
|
||||
CRB_INTF_ID2 => CRB_INTF_ID2_FIELDS,
|
||||
CRB_CTRL_STS => CRB_CTRL_STS_FIELDS,
|
||||
_ => {
|
||||
panic!("Fields in '{reg:?}' register were accessed which are Invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a particular field in a Register
|
||||
fn set_reg_field(regs: &mut [u32; TPM_CRB_R_MAX as usize], reg: u32, field: &str, value: u32) {
|
||||
let reg_fields = get_fields_map(reg);
|
||||
if reg_fields.contains_key(field) {
|
||||
let start = reg_fields.get(field).unwrap()[0];
|
||||
let len = reg_fields.get(field).unwrap()[1];
|
||||
let mask = (!(0_u32) >> (32 - len)) << start;
|
||||
regs[reg as usize] = (regs[reg as usize] & !mask) | ((value << start) & mask);
|
||||
} else {
|
||||
error!(
|
||||
"Failed to tpm Register. {:?} is not a valid field in Reg {:#X}",
|
||||
field, reg
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the value of a particular field in a Register
|
||||
fn get_reg_field(regs: &[u32; TPM_CRB_R_MAX as usize], reg: u32, field: &str) -> u32 {
|
||||
let reg_fields = get_fields_map(reg);
|
||||
if reg_fields.contains_key(field) {
|
||||
let start = reg_fields.get(field).unwrap()[0];
|
||||
let len = reg_fields.get(field).unwrap()[1];
|
||||
let mask = (!(0_u32) >> (32 - len)) << start;
|
||||
(regs[reg as usize] & mask) >> start
|
||||
} else {
|
||||
// TODO: Sensible return value if fields do not exist
|
||||
0x0
|
||||
}
|
||||
}
|
||||
|
||||
fn locality_from_addr(addr: u32) -> u8 {
|
||||
(addr >> 12) as u8
|
||||
}
|
||||
|
||||
pub struct Tpm {
|
||||
emulator: Emulator,
|
||||
cmd: Option<BackendCmd>,
|
||||
regs: [u32; TPM_CRB_R_MAX as usize],
|
||||
backend_buff_size: usize,
|
||||
data_buff: [u8; TPM_CRB_BUFFER_MAX],
|
||||
data_buff_len: usize,
|
||||
}
|
||||
|
||||
impl Tpm {
|
||||
pub fn new(path: String) -> Result<Self> {
|
||||
let emulator = Emulator::new(path)
|
||||
.map_err(|e| Error::Init(anyhow!("Failed while initializing tpm Emulator: {:?}", e)))?;
|
||||
let mut tpm = Tpm {
|
||||
emulator,
|
||||
cmd: None,
|
||||
regs: [0; TPM_CRB_R_MAX as usize],
|
||||
backend_buff_size: TPM_CRB_BUFFER_MAX,
|
||||
data_buff: [0; TPM_CRB_BUFFER_MAX],
|
||||
data_buff_len: 0,
|
||||
};
|
||||
tpm.reset()?;
|
||||
Ok(tpm)
|
||||
}
|
||||
|
||||
fn get_active_locality(&mut self) -> u32 {
|
||||
if get_reg_field(&self.regs, CRB_LOC_STATE, "locAssigned") == 0 {
|
||||
return TPM_CRB_NO_LOCALITY;
|
||||
}
|
||||
get_reg_field(&self.regs, CRB_LOC_STATE, "activeLocality")
|
||||
}
|
||||
|
||||
fn request_completed(&mut self, result: isize) {
|
||||
self.regs[CRB_CTRL_START as usize] = !CRB_START_INVOKE;
|
||||
if result != 0 {
|
||||
set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmSts", 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> Result<()> {
|
||||
let cur_buff_size = self.emulator.get_buffer_size().unwrap();
|
||||
self.regs = [0; TPM_CRB_R_MAX as usize];
|
||||
set_reg_field(&mut self.regs, CRB_LOC_STATE, "tpmRegValidSts", 1);
|
||||
set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 1);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"InterfaceType",
|
||||
CRB_INTF_TYPE_CRB_ACTIVE,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"InterfaceVersion",
|
||||
CRB_INTF_VERSION_CRB,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"CapLocality",
|
||||
CRB_INTF_CAP_LOCALITY_0_ONLY,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"CapCRBIdleBypass",
|
||||
CRB_INTF_CAP_IDLE_FAST,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"CapDataXferSizeSupport",
|
||||
CRB_INTF_CAP_XFER_SIZE_64,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"CapFIFO",
|
||||
CRB_INTF_CAP_FIFO_NOT_SUPPORTED,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"CapCRB",
|
||||
CRB_INTF_CAP_CRB_SUPPORTED,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"InterfaceSelector",
|
||||
CRB_INTF_IF_SELECTOR_CRB,
|
||||
);
|
||||
set_reg_field(&mut self.regs, CRB_INTF_ID, "RID", 0b0000);
|
||||
set_reg_field(&mut self.regs, CRB_INTF_ID2, "VID", PCI_VENDOR_ID_IBM);
|
||||
|
||||
self.regs[CRB_CTRL_CMD_SIZE_REG as usize] = CRB_CTRL_CMD_SIZE as u32;
|
||||
self.regs[CRB_CTRL_CMD_LADDR as usize] = TPM_CRB_ADDR_BASE + CRB_DATA_BUFFER;
|
||||
self.regs[CRB_CTRL_RSP_SIZE as usize] = CRB_CTRL_CMD_SIZE as u32;
|
||||
self.regs[CRB_CTRL_RSP_ADDR as usize] = TPM_CRB_ADDR_BASE + CRB_DATA_BUFFER;
|
||||
|
||||
self.backend_buff_size = cmp::min(cur_buff_size, TPM_CRB_BUFFER_MAX);
|
||||
|
||||
if let Err(e) = self.emulator.startup_tpm(self.backend_buff_size) {
|
||||
return Err(Error::Init(anyhow!(
|
||||
"Failed while running Startup TPM. Error: {:?}",
|
||||
e
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//impl BusDevice for TPM
|
||||
impl BusDevice for Tpm {
|
||||
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
||||
let mut offset: u32 = offset as u32;
|
||||
let read_len: usize = data.len();
|
||||
|
||||
if offset >= CRB_DATA_BUFFER
|
||||
&& (offset + read_len as u32) < (CRB_DATA_BUFFER + self.data_buff.len() as u32)
|
||||
{
|
||||
// Read from Data Buffer
|
||||
let start: usize = (offset as usize) - (CRB_DATA_BUFFER as usize);
|
||||
let end: usize = start + read_len;
|
||||
data[..].clone_from_slice(&self.data_buff[start..end]);
|
||||
} else {
|
||||
offset &= 0xff;
|
||||
let mut val = self.regs[offset as usize];
|
||||
|
||||
if offset == CRB_LOC_STATE && !self.emulator.get_established_flag() {
|
||||
val |= 0x1;
|
||||
}
|
||||
|
||||
if data.len() <= 4 {
|
||||
data.clone_from_slice(val.to_ne_bytes()[0..read_len].as_ref());
|
||||
} else {
|
||||
error!(
|
||||
"Invalid tpm read: offset {:#X}, data length {:?}",
|
||||
offset,
|
||||
data.len()
|
||||
);
|
||||
}
|
||||
}
|
||||
debug!(
|
||||
"MMIO Read: offset {:#X} len {:?} val = {:02X?} ",
|
||||
offset,
|
||||
data.len(),
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||
debug!(
|
||||
"MMIO Write: offset {:#X} len {:?} input data {:02X?}",
|
||||
offset,
|
||||
data.len(),
|
||||
data
|
||||
);
|
||||
let mut offset: u32 = offset as u32;
|
||||
if offset < CRB_DATA_BUFFER {
|
||||
offset &= 0xff;
|
||||
}
|
||||
let locality = locality_from_addr(offset) as u32;
|
||||
let write_len = data.len();
|
||||
|
||||
if offset >= CRB_DATA_BUFFER
|
||||
&& (offset + write_len as u32) < (CRB_DATA_BUFFER + self.data_buff.len() as u32)
|
||||
{
|
||||
let start: usize = (offset as usize) - (CRB_DATA_BUFFER as usize);
|
||||
if start == 0 {
|
||||
// If filling data_buff at index 0, reset length to 0
|
||||
self.data_buff_len = 0;
|
||||
self.data_buff.fill(0);
|
||||
}
|
||||
let end: usize = start + data.len();
|
||||
self.data_buff[start..end].clone_from_slice(data);
|
||||
self.data_buff_len += data.len();
|
||||
} else {
|
||||
// Ctrl Commands that take more than 4 bytes as input are not yet supported
|
||||
// CTRL_RSP_ADDR usually gets 8 byte write request. Last 4 bytes are zeros.
|
||||
if write_len > 4 && offset != CRB_CTRL_RSP_ADDR {
|
||||
error!(
|
||||
"Invalid tpm write: offset {:#X}, data length {}",
|
||||
offset,
|
||||
data.len()
|
||||
);
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut input: [u8; 4] = [0; 4];
|
||||
input.copy_from_slice(&data[0..4]);
|
||||
let v = u32::from_le_bytes(input);
|
||||
|
||||
match offset {
|
||||
CRB_CTRL_CMD_SIZE_REG => {
|
||||
self.regs[CRB_CTRL_CMD_SIZE_REG as usize] = v;
|
||||
}
|
||||
CRB_CTRL_CMD_LADDR => {
|
||||
self.regs[CRB_CTRL_CMD_LADDR as usize] = v;
|
||||
}
|
||||
CRB_CTRL_CMD_HADDR => {
|
||||
self.regs[CRB_CTRL_CMD_HADDR as usize] = v;
|
||||
}
|
||||
CRB_CTRL_RSP_SIZE => {
|
||||
self.regs[CRB_CTRL_RSP_SIZE as usize] = v;
|
||||
}
|
||||
CRB_CTRL_RSP_ADDR => {
|
||||
self.regs[CRB_CTRL_RSP_ADDR as usize] = v;
|
||||
}
|
||||
CRB_CTRL_REQ => match v {
|
||||
CRB_CTRL_REQ_CMD_READY => {
|
||||
set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 0);
|
||||
}
|
||||
CRB_CTRL_REQ_GO_IDLE => {
|
||||
set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 1);
|
||||
}
|
||||
_ => {
|
||||
error!("Invalid value passed to CRTL_REQ register");
|
||||
return None;
|
||||
}
|
||||
},
|
||||
CRB_CTRL_CANCEL => {
|
||||
if v == CRB_CANCEL_INVOKE
|
||||
&& (self.regs[CRB_CTRL_START as usize] & CRB_START_INVOKE != 0)
|
||||
{
|
||||
if let Err(e) = self.emulator.cancel_cmd() {
|
||||
error!("Failed to run cancel command. Error: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
CRB_CTRL_START => {
|
||||
if v == CRB_START_INVOKE
|
||||
&& ((self.regs[CRB_CTRL_START as usize] & CRB_START_INVOKE) == 0)
|
||||
&& self.get_active_locality() == locality
|
||||
{
|
||||
self.regs[CRB_CTRL_START as usize] |= CRB_START_INVOKE;
|
||||
|
||||
self.cmd = Some(BackendCmd {
|
||||
locality: locality as u8,
|
||||
input: self.data_buff[0..self.data_buff_len].to_vec(),
|
||||
input_len: cmp::min(self.data_buff_len, TPM_CRB_BUFFER_MAX),
|
||||
output: self.data_buff.to_vec(),
|
||||
output_len: TPM_CRB_BUFFER_MAX,
|
||||
selftest_done: false,
|
||||
});
|
||||
|
||||
let mut cmd = self.cmd.as_ref().unwrap().clone();
|
||||
let output = self.emulator.deliver_request(&mut cmd).map_err(|e| {
|
||||
Error::DeliverRequest(anyhow!(
|
||||
"Failed to deliver tpm request. Error :{:?}",
|
||||
e
|
||||
))
|
||||
});
|
||||
//TODO: drop the copy here
|
||||
self.data_buff.fill(0);
|
||||
self.data_buff.clone_from_slice(output.unwrap().as_slice());
|
||||
|
||||
self.request_completed(TPM_SUCCESS as isize);
|
||||
}
|
||||
}
|
||||
CRB_LOC_CTRL => {
|
||||
warn!(
|
||||
"CRB_LOC_CTRL locality to write = {:?} val = {:?}",
|
||||
locality, v
|
||||
);
|
||||
match v {
|
||||
CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT => {}
|
||||
CRB_LOC_CTRL_RELINQUISH => {
|
||||
set_reg_field(&mut self.regs, CRB_LOC_STATE, "locAssigned", 0);
|
||||
set_reg_field(&mut self.regs, CRB_LOC_STS, "Granted", 0);
|
||||
}
|
||||
CRB_LOC_CTRL_REQUEST_ACCESS => {
|
||||
set_reg_field(&mut self.regs, CRB_LOC_STS, "Granted", 1);
|
||||
set_reg_field(&mut self.regs, CRB_LOC_STS, "beenSeized", 0);
|
||||
set_reg_field(&mut self.regs, CRB_LOC_STATE, "locAssigned", 1);
|
||||
}
|
||||
_ => {
|
||||
error!("Invalid value to write in CRB_LOC_CTRL {:#X} ", v);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
error!(
|
||||
"Invalid tpm write: offset {:#X}, data length {:?}",
|
||||
offset,
|
||||
data.len()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_set_get_reg_field() {
|
||||
let mut regs: [u32; TPM_CRB_R_MAX as usize] = [0; TPM_CRB_R_MAX as usize];
|
||||
set_reg_field(&mut regs, CRB_INTF_ID, "RID", 0xAC);
|
||||
assert_eq!(
|
||||
get_reg_field(®s, CRB_INTF_ID, "RID"),
|
||||
0xAC,
|
||||
concat!("Test: ", stringify!(set_get_reg_field))
|
||||
);
|
||||
}
|
||||
}
|
||||
82
docs/building.md
Normal file
82
docs/building.md
Normal file
@@ -0,0 +1,82 @@
|
||||
- [Building Cloud Hypervisor](#building-cloud-hypervisor)
|
||||
- [Preparation](#preparation)
|
||||
- [Install prerequisites](#install-prerequisites)
|
||||
- [Clone and build](#clone-and-build)
|
||||
- [Containerized builds and tests](#containerized-builds-and-tests)
|
||||
|
||||
# Building Cloud Hypervisor
|
||||
|
||||
We recommend users use the pre-built binaries that are mentioned in the README.md file in the root of the repository. Building from source is only necessary if you wish to make modifications.
|
||||
|
||||
## Preparation
|
||||
|
||||
We create a folder to build and run `cloud-hypervisor` at `$HOME/cloud-hypervisor`
|
||||
|
||||
```shell
|
||||
$ export CLOUDH=$HOME/cloud-hypervisor
|
||||
$ mkdir $CLOUDH
|
||||
```
|
||||
|
||||
## Install prerequisites
|
||||
|
||||
You need to install some prerequisite packages in order to build and test Cloud
|
||||
Hypervisor. Here, all the steps are based on Ubuntu, for other Linux
|
||||
distributions please replace the package manager and package name.
|
||||
|
||||
```shell
|
||||
# Install build-essential, git, and qemu-utils
|
||||
$ sudo apt install git build-essential qemu-utils
|
||||
# Install rust tool chain
|
||||
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
# If you want to build statically linked binary please add musl target
|
||||
$ rustup target add x86_64-unknown-linux-musl
|
||||
```
|
||||
|
||||
## Clone and build
|
||||
|
||||
First you need to clone and build the Cloud Hypervisor repository:
|
||||
|
||||
```shell
|
||||
$ pushd $CLOUDH
|
||||
$ git clone https://github.com/cloud-hypervisor/cloud-hypervisor.git
|
||||
$ cd cloud-hypervisor
|
||||
$ cargo build --release
|
||||
|
||||
# We need to give the cloud-hypervisor binary the NET_ADMIN capabilities for it to set TAP interfaces up on the host.
|
||||
$ sudo setcap cap_net_admin+ep ./target/release/cloud-hypervisor
|
||||
|
||||
# If you want to build statically linked binary
|
||||
$ cargo build --release --target=x86_64-unknown-linux-musl --all
|
||||
$ popd
|
||||
```
|
||||
|
||||
This will build a `cloud-hypervisor` binary under
|
||||
`$CLOUDH/cloud-hypervisor/target/release/cloud-hypervisor`.
|
||||
|
||||
### Containerized builds and tests
|
||||
|
||||
If you want to build and test Cloud Hypervisor without having to install all the
|
||||
required dependencies (The rust toolchain, cargo tools, etc), you can also use
|
||||
Cloud Hypervisor's development script: `dev_cli.sh`. Please note that upon its
|
||||
first invocation, this script will pull a fairly large container image.
|
||||
|
||||
For example, to build the Cloud Hypervisor release binary:
|
||||
|
||||
```shell
|
||||
$ pushd $CLOUDH
|
||||
$ cd cloud-hypervisor
|
||||
$ ./scripts/dev_cli.sh build --release
|
||||
```
|
||||
|
||||
With `dev_cli.sh`, one can also run the Cloud Hypervisor CI locally. This can be
|
||||
very convenient for debugging CI errors without having to fully rely on the
|
||||
Cloud Hypervisor CI infrastructure.
|
||||
|
||||
For example, to run the Cloud Hypervisor unit tests:
|
||||
|
||||
```shell
|
||||
$ ./scripts/dev_cli.sh tests --unit
|
||||
```
|
||||
|
||||
Run the `./scripts/dev_cli.sh --help` command to view all the supported
|
||||
development script commands and their related options.
|
||||
@@ -20,12 +20,13 @@ struct MemoryConfig {
|
||||
hugepages: bool,
|
||||
hugepage_size: Option<u64>,
|
||||
prefault: bool,
|
||||
thp: bool
|
||||
zones: Option<Vec<MemoryZoneConfig>>,
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
--memory <memory> Memory parameters "size=<guest_memory_size>,mergeable=on|off,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,hotplug_method=acpi|virtio-mem,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>,prefault=on|off" [default: size=512M]
|
||||
--memory <memory> Memory parameters "size=<guest_memory_size>,mergeable=on|off,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,hotplug_method=acpi|virtio-mem,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>,prefault=on|off,thp=on|off" [default: size=512M,thp=on]
|
||||
```
|
||||
|
||||
### `size`
|
||||
@@ -117,6 +118,9 @@ needing access to the guest RAM content.
|
||||
By default this option is turned off, which results in performing `mmap(2)`
|
||||
with `MAP_PRIVATE` flag.
|
||||
|
||||
If `hugepages=on` then the value of this field is ignored as huge pages always
|
||||
requires `MAP_SHARED`.
|
||||
|
||||
_Example_
|
||||
|
||||
```
|
||||
@@ -140,6 +144,9 @@ behaviour, e.g. error with `ReadKernelImage` is common. If there is a strange
|
||||
error with `hugepages` enabled, just disable it or check whether there are enough
|
||||
huge pages.
|
||||
|
||||
If `hugepages=on` then the value of `shared` is ignored as huge pages always
|
||||
requires `MAP_SHARED`.
|
||||
|
||||
By default this option is turned off.
|
||||
|
||||
_Example_
|
||||
@@ -171,6 +178,25 @@ _Example_
|
||||
--memory size=1G,prefault=on
|
||||
```
|
||||
|
||||
### `thp`
|
||||
|
||||
Specifies if private anonymous memory for the guest (i.e. `shared=off` and no
|
||||
backing file) should be labelled `MADV_HUGEPAGE` with `madvise(2)` indicating
|
||||
to the kernel that this memory may be backed with huge pages transparently.
|
||||
|
||||
The use of transparent huge pages can improve the performance of the guest as
|
||||
there will fewer virtualisation related page faults. Unlike using
|
||||
`hugepages=on` a specific number of huge pages do not need to be allocated by
|
||||
the kernel.
|
||||
|
||||
By default this option is turned on.
|
||||
|
||||
_Example_
|
||||
|
||||
```
|
||||
--memory size=1G,thp=on
|
||||
```
|
||||
|
||||
## Advanced Parameters
|
||||
|
||||
`MemoryZoneConfig` or what is known as `--memory-zone` from the CLI perspective
|
||||
@@ -271,6 +297,9 @@ other processes running on the host. One can use this option when running
|
||||
vhost-user devices as part of the VM device model, as they will be driven
|
||||
by standalone daemons needing access to the guest RAM content.
|
||||
|
||||
If `hugepages=on` then the value of this field is ignored as huge pages always
|
||||
requires `MAP_SHARED`.
|
||||
|
||||
By default this option is turned off, which result in performing `mmap(2)`
|
||||
with `MAP_PRIVATE` flag.
|
||||
|
||||
@@ -298,6 +327,9 @@ behaviour, e.g. error with `ReadKernelImage` is common. If there is a strange
|
||||
error with `hugepages` enabled, just disable it or check whether there are enough
|
||||
huge pages.
|
||||
|
||||
If `hugepages=on` then the value of `shared` is ignored as huge pages always
|
||||
requires `MAP_SHARED`.
|
||||
|
||||
By default this option is turned off.
|
||||
|
||||
_Example_
|
||||
|
||||
@@ -64,5 +64,5 @@ it will log every system call issued by the process. It is important to use
|
||||
`-f` option in order to trace each and every thread belonging to the process.
|
||||
|
||||
```
|
||||
strace -f ./cloud-hypervisor ...
|
||||
strace --decode-pids=comm -f ./cloud-hypervisor ...
|
||||
```
|
||||
|
||||
122
docs/tpm.md
Normal file
122
docs/tpm.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# TPM
|
||||
Tpm in Cloud-Hypervisor is emulated using `swtpm` as the backend. [swtpm](https://github.com/stefanberger/swtpm) is the link to swtpm project.
|
||||
|
||||
Current implementation only supports TPM `2.0` version. At the moment only
|
||||
`CRB Interface` is implemented. This interface is described in
|
||||
[TCG PC Client Platform TPM Profile Specification for TPM 2.0, Revision 01.05 v4](https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p05p_r14_pub.pdf).
|
||||
|
||||
|
||||
## Usage
|
||||
`--tpm`, an optional argument, can be passed to enable tpm device.
|
||||
This argument takes an UNIX domain Socket as a `socket` value.
|
||||
|
||||
_Example_
|
||||
|
||||
An Example invocation with `--tpm` argument:
|
||||
|
||||
```
|
||||
./cloud-hypervisor/target/release/cloud-hypervisor \
|
||||
--kernel ./hypervisor-fw \
|
||||
--disk path=focal-server-cloudimg-amd64.raw \
|
||||
--cpus boot=4 \
|
||||
--memory size=1024M \
|
||||
--net "tap=,mac=,ip=,mask=" \
|
||||
--tpm socket="/var/run/swtpm.socket"
|
||||
```
|
||||
|
||||
## swtpm
|
||||
Before invoking cloud-hypervisor with `--tpm` argument, a `swtpm`
|
||||
process should be started to listen at the input socket. Below is an
|
||||
example invocation of swtpm process.
|
||||
|
||||
```
|
||||
swtpm socket --tpmstate dir=/var/run/swtpm \
|
||||
--ctrl type=unixio,path="/var/run/swtpm.socket" \
|
||||
--flags startup-clear \
|
||||
--tpm2
|
||||
```
|
||||
|
||||
## Guest
|
||||
After starting a guest with the above commands, ensure below listed modules are
|
||||
loaded in the guest:
|
||||
|
||||
```
|
||||
# lsmod | grep tpm
|
||||
tpm_crb 20480 0
|
||||
tpm 81920 1 tpm_crb
|
||||
```
|
||||
|
||||
Below is the IO Memory map configured in the guest:
|
||||
|
||||
```
|
||||
# cat /proc/iomem | grep MSFT
|
||||
fed40000-fed40fff : MSFT0101:00
|
||||
fed40000-fed40fff : MSFT0101:00
|
||||
```
|
||||
Below are the devices created in the guest:
|
||||
|
||||
```
|
||||
# ls /dev/tpm*
|
||||
/dev/tpm0 /dev/tpmrm0
|
||||
```
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
Inside the guest install `tpm2-tools` package. This package provides some
|
||||
commands to run against TPM that supports 2.0 version.
|
||||
|
||||
_Examples_
|
||||
```
|
||||
// Run Self Test
|
||||
# tpm2_selftest -f
|
||||
# echo $?
|
||||
0
|
||||
|
||||
|
||||
# echo "hello" > input.txt
|
||||
// this command generates hash of the input file using all the algos supported by TPM
|
||||
|
||||
# tpm2_pcrevent input.txt
|
||||
sha1: f572d396fae9206628714fb2ce00f72e94f2258f
|
||||
sha256: 5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03
|
||||
sha384: 1d0f284efe3edea4b9ca3bd514fa134b17eae361ccc7a1eefeff801b9bd6604e01f21f6bf249ef030599f0c
|
||||
218f2ba8c
|
||||
sha512: e7c22b994c59d9cf2b48e549b1e24666636045930d3da7c1acb299d1c3b7f931f94aae41edda2c2b207a36e
|
||||
10f8bcb8d45223e54878f5b316e7ce3b6bc019629
|
||||
|
||||
// verify one of the hashes
|
||||
# sha256sum input.txt
|
||||
5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03 input.txt
|
||||
```
|
||||
|
||||
### Bundled Functional Test
|
||||
|
||||
Build time dependencies for `tpm2-tss` are captured in [INSTALL](https://github.com/tpm2-software/tpm2-tss/blob/master/INSTALL.md).
|
||||
|
||||
```
|
||||
# git clone https://github.com/tpm2-software/tpm2-tss.git
|
||||
# cd tpm2-tss
|
||||
# ./configure --enable-integration --with-devicetests="mandatory,optional" --with-device=/dev/tpm0
|
||||
# sudo make check-device
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
============================================================================
|
||||
Testsuite summary for tpm2-tss 3.2.0-74-ge03617d9
|
||||
============================================================================
|
||||
# TOTAL: 154
|
||||
# PASS: 88
|
||||
# SKIP: 7
|
||||
# XFAIL: 0
|
||||
# FAIL: 59
|
||||
# XPASS: 0
|
||||
# ERROR: 0
|
||||
============================================================================
|
||||
See ./test-suite.log
|
||||
Please report to https://github.com/tpm2-software/tpm2-tss/issues
|
||||
============================================================================
|
||||
```
|
||||
The same set of failures are noticed while running these tests on `Qemu` with
|
||||
its TPM implementation.
|
||||
@@ -131,7 +131,7 @@ See also the [links](#Links) section for a more extended SAC documentation.
|
||||
|
||||
## Network
|
||||
|
||||
This section illustrates the Windows specific corner points for the VM network configuration. For the extended networking guide, including bridging for multiple VMs, follow [networking.md](networking.md).
|
||||
This section illustrates the Windows specific aspects of the VM network configuration.
|
||||
|
||||
### Basic Networking
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.133"
|
||||
serde = { version = "1.0.145", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.85"
|
||||
libc = "0.2.138"
|
||||
once_cell = "1.16.0"
|
||||
serde = { version = "1.0.150", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.89"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use once_cell::sync::OnceCell;
|
||||
use serde::Serialize;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
@@ -11,12 +12,13 @@ use std::io::Write;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
static mut MONITOR: Option<(File, Instant)> = None;
|
||||
static MONITOR: OnceCell<(File, Instant)> = OnceCell::new();
|
||||
|
||||
/// This function must only be called once from the main process before any threads
|
||||
/// are created to avoid race conditions
|
||||
pub fn set_monitor(file: File) -> Result<(), std::io::Error> {
|
||||
assert!(unsafe { MONITOR.is_none() });
|
||||
// There is only one caller of this function, so MONITOR is written to only once
|
||||
assert!(MONITOR.get().is_none());
|
||||
let fd = file.as_raw_fd();
|
||||
let ret = unsafe {
|
||||
let mut flags = libc::fcntl(fd, libc::F_GETFL);
|
||||
@@ -26,9 +28,9 @@ pub fn set_monitor(file: File) -> Result<(), std::io::Error> {
|
||||
if ret < 0 {
|
||||
return Err(std::io::Error::last_os_error());
|
||||
}
|
||||
unsafe {
|
||||
MONITOR = Some((file, Instant::now()));
|
||||
};
|
||||
|
||||
MONITOR.get_or_init(|| (file, Instant::now()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -41,7 +43,7 @@ struct Event<'a> {
|
||||
}
|
||||
|
||||
pub fn event_log(source: &str, event: &str, properties: Option<&HashMap<Cow<str>, Cow<str>>>) {
|
||||
if let Some((file, start)) = unsafe { MONITOR.as_ref() } {
|
||||
if let Some((file, start)) = MONITOR.get().as_ref() {
|
||||
let e = Event {
|
||||
timestamp: start.elapsed(),
|
||||
source,
|
||||
|
||||
376
fuzz/Cargo.lock
generated
376
fuzz/Cargo.lock
generated
@@ -11,9 +11,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.65"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
|
||||
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
|
||||
|
||||
[[package]]
|
||||
name = "api_client"
|
||||
@@ -24,9 +24,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.1.6"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f44124848854b941eafdb34f05b3bcf59472f643c7e151eba7c2b69daa469ed5"
|
||||
checksum = "29d47fbf90d5149a107494b15a7dc8d69b351be2db3bb9691740e88ec17fd880"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
@@ -56,23 +56,6 @@ dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
@@ -88,6 +71,12 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "block_util"
|
||||
version = "0.1.0"
|
||||
@@ -115,9 +104,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.73"
|
||||
version = "1.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
]
|
||||
@@ -130,33 +119,31 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.22"
|
||||
version = "4.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750"
|
||||
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"clap_lex",
|
||||
"indexmap",
|
||||
"is-terminal",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"terminal_size",
|
||||
"textwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.4"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloud-hypervisor"
|
||||
version = "26.0.0"
|
||||
version = "28.3.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"api_client",
|
||||
@@ -171,6 +158,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"signal-hook",
|
||||
"thiserror",
|
||||
"tpm",
|
||||
"tracer",
|
||||
"vm-memory",
|
||||
"vmm",
|
||||
@@ -218,9 +206,9 @@ checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.14.1"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02"
|
||||
checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
@@ -228,9 +216,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.14.1"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f"
|
||||
checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
@@ -242,9 +230,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.14.1"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5"
|
||||
checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
@@ -258,11 +246,14 @@ dependencies = [
|
||||
"acpi_tables",
|
||||
"anyhow",
|
||||
"arch",
|
||||
"bitflags",
|
||||
"bitflags 2.4.1",
|
||||
"byteorder",
|
||||
"hypervisor",
|
||||
"libc",
|
||||
"log",
|
||||
"phf",
|
||||
"thiserror",
|
||||
"tpm",
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"vm-device",
|
||||
@@ -277,7 +268,7 @@ version = "4.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20df693c700404f7e19d4d6fae6b15215d2913c27955d2b9d6f2c0f537511cd0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -307,6 +298,7 @@ name = "event_monitor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
@@ -325,26 +317,20 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.7"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.20"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7a30908dbce072eca83216eab939d2290080e00ca71611b96a09e5cdce5f3fa"
|
||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -385,36 +371,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ea37f355c05dde75b84bba2d767906ad522e97cd9e2eef2be7a4ab7fb442c06"
|
||||
|
||||
[[package]]
|
||||
name = "io-uring"
|
||||
version = "0.5.6"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a645fd8e7048c2f54050f7d0d4de8f624ada437e043bc7d72609bd08d70120b"
|
||||
checksum = "7ba34abb5175052fc1a2227a10d2275b7386c9990167de9786c0b88d8b062330"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.3"
|
||||
name = "is-terminal"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
|
||||
checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"io-lifetimes",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
@@ -427,8 +419,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kvm-bindings"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.5.0-tdx#52e56d0e8ef0f6ea32fc0492e6a175b73617a49f"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.6.0-tdx#7d9ffb47e5b9b1989577258800a0f57c93f1445f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
@@ -437,8 +429,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kvm-ioctls"
|
||||
version = "0.11.0"
|
||||
source = "git+https://github.com/rust-vmm/kvm-ioctls?branch=main#1e03e29cdfbb0cb108a98de7a78045a5a517f18e"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8f8dc9c1896e5f144ec5d07169bc29f39a047686d29585a91f30489abfaeb6b"
|
||||
dependencies = [
|
||||
"kvm-bindings",
|
||||
"libc",
|
||||
@@ -453,15 +446,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.133"
|
||||
version = "0.2.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
|
||||
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae185684fe19814afd066da15a7cc41e126886c21282934225d9fc847582da58"
|
||||
checksum = "c8fff891139ee62800da71b7fd5b508d570b9ad95e614a53c6f453ca08366038"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"cc",
|
||||
@@ -470,18 +463,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-loader"
|
||||
version = "0.6.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62a2f912deca034ec34b0a43a390059ea98daac40e440ebe8bea88f3315fe168"
|
||||
checksum = "b9259ddbfbb52cc918f6bbc60390004ddd0228cf1d85f402009ff2b3d95de83f"
|
||||
dependencies = [
|
||||
"vm-memory",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.0.46"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d"
|
||||
checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
@@ -495,7 +488,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "micro_http"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#863b0370ba7e57f7df5b908ada9e5b44809ccae9"
|
||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#4b18a043e997da5b5f679e3defc279fec908753e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"vmm-sys-util",
|
||||
@@ -531,9 +524,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.15.0"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
|
||||
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
||||
|
||||
[[package]]
|
||||
name = "option_parser"
|
||||
@@ -541,9 +534,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.3.0"
|
||||
version = "6.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
|
||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
||||
|
||||
[[package]]
|
||||
name = "pci"
|
||||
@@ -569,10 +562,52 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.45"
|
||||
name = "phf"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3edcd08cf4fea98d1ae6c9ddd3b8ccb1acac7c3693d62625969a7daa04a2ae36"
|
||||
checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c"
|
||||
dependencies = [
|
||||
"phf_macros",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -597,6 +632,21 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "rate_limiter"
|
||||
version = "0.1.0"
|
||||
@@ -608,9 +658,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "remain"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06df529c0d271b27ac4a2c260f5ce2914b60bd44702cecec7b9f271adbdde23b"
|
||||
checksum = "1a81bc6a3aaeb180f767bd2bda8c03bac5b93b3b69a783c66f35d16a4df276cf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -628,11 +678,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.35.11"
|
||||
version = "0.36.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbb2fda4666def1433b1b05431ab402e42a1084285477222b72d6c564c417cef"
|
||||
checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
@@ -663,18 +713,18 @@ checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.145"
|
||||
version = "1.0.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
|
||||
checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.145"
|
||||
version = "1.0.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
|
||||
checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -683,9 +733,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.85"
|
||||
version = "1.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
|
||||
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -694,9 +744,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "2.0.1"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368f2d60d049ea019a84dcd6687b0d1e0030fe663ae105039bdf967ed5e6a9a7"
|
||||
checksum = "25bf4a5a814902cd1014dbccfa4d4560fb8432c779471e96e035602519f82eef"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_with_macros",
|
||||
@@ -704,9 +754,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with_macros"
|
||||
version = "2.0.1"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ccadfacf6cf10faad22bbadf55986bdd0856edfb5d9210aa1dcf1f516e84e93"
|
||||
checksum = "e3452b4c0f6c1e357f73fdb87cd1efabaa12acf328c7a528e252893baeb3f4aa"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
@@ -737,6 +787,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
@@ -751,9 +807,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.101"
|
||||
version = "1.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
|
||||
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -771,23 +827,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.2.1"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8440c860cf79def6164e4a0a983bcc2305d82419177a0e0c71930d049e3ac5a1"
|
||||
checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16"
|
||||
dependencies = [
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.37"
|
||||
@@ -808,6 +855,18 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tpm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"byteorder",
|
||||
"libc",
|
||||
"log",
|
||||
"thiserror",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracer"
|
||||
version = "0.1.0"
|
||||
@@ -821,24 +880,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.4"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
|
||||
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.1.2"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
|
||||
checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "versionize"
|
||||
version = "0.1.6"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7429cf68de8f091b667d27323ed323afd39584a56d533995b12ddd748e5e6ca9"
|
||||
checksum = "d6e2495726cf917e7ba7ec8bf0f0fceab543dd38d0a4195ed6bef331e38a290f"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"crc64",
|
||||
@@ -863,17 +922,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vfio-bindings"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43449b404c488f70507dca193debd4bea361fe8089869b947adc19720e464bce"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#43439e056ddfa84a4f7906ee7f2f58be70505c08"
|
||||
dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vfio-ioctls"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#bf7c9b997b4ad0ca1ab4bfe96dc1b10d4bc5be24"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#43439e056ddfa84a4f7906ee7f2f58be70505c08"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"kvm-bindings",
|
||||
@@ -916,11 +974,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vhost"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79243657c76e5c90dcbf60187c842614f6dfc7123972c55bb3bcc446792aca93"
|
||||
checksum = "c9b791c5b0717a0558888a4cf7240cea836f39a99cb342e12ce633dcaa078072"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
@@ -969,9 +1027,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "virtio-queue"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e2b7bea73248006630c9611a61ac3b8e44eece09342801fe1faec583b7a9f02"
|
||||
checksum = "19e927d93d54c365034fd7f31a5f458a1f540de4a37c52e892670dad9692173c"
|
||||
dependencies = [
|
||||
"log",
|
||||
"virtio-bindings",
|
||||
@@ -1003,14 +1061,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vm-fdt"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#720e48e435b791ec6cbe8d2b229448b71dcb1ab9"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#c5a99ab71b130435927d19b50c85fcd5ce904a8c"
|
||||
|
||||
[[package]]
|
||||
name = "vm-memory"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "583f213899e8a5eea23d9c507252d4bed5bc88f0ecbe0783262f80034630744b"
|
||||
checksum = "688a70366615b45575a424d9c665561c1b5ab2224d494f706b6a6812911a827c"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"libc",
|
||||
@@ -1047,7 +1105,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
"arch",
|
||||
"bitflags",
|
||||
"bitflags 2.4.1",
|
||||
"block_util",
|
||||
"clap",
|
||||
"devices",
|
||||
@@ -1088,11 +1146,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vmm-sys-util"
|
||||
version = "0.10.0"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08604d7be03eb26e33b3cee3ed4aef2bf550b305d1cca60e84da5d28d3790b62"
|
||||
checksum = "cc06a16ee8ebf0d9269aed304030b0d20a866b8b3dd3d4ce532596ac567a0d24"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
@@ -1137,43 +1195,57 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.36.1"
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
||||
|
||||
@@ -12,18 +12,18 @@ cargo-fuzz = true
|
||||
block_util = { path = "../block_util" }
|
||||
devices = { path = "../devices" }
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.133"
|
||||
libfuzzer-sys = "0.4.4"
|
||||
libc = "0.2.135"
|
||||
libfuzzer-sys = "0.4.5"
|
||||
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
|
||||
once_cell = "1.15.0"
|
||||
once_cell = "1.16.0"
|
||||
qcow = { path = "../qcow" }
|
||||
seccompiler = "0.3.0"
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-devices = { path = "../virtio-devices" }
|
||||
virtio-queue = "0.6.1"
|
||||
virtio-queue = "0.7.0"
|
||||
vmm = { path = "../vmm" }
|
||||
vmm-sys-util = "0.10.0"
|
||||
vm-memory = "0.9.0"
|
||||
vmm-sys-util = "0.11.0"
|
||||
vm-memory = "0.10.0"
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
|
||||
@@ -31,8 +31,7 @@ vm-virtio = { path = "../vm-virtio" }
|
||||
path = ".."
|
||||
|
||||
[patch.crates-io]
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx" }
|
||||
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||
|
||||
# Prevent this from interfering with workspaces
|
||||
@@ -57,12 +56,30 @@ path = "fuzz_targets/cmos.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "console"
|
||||
path = "fuzz_targets/console.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "http_api"
|
||||
path = "fuzz_targets/http_api.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "iommu"
|
||||
path = "fuzz_targets/iommu.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "mem"
|
||||
path = "fuzz_targets/mem.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "pmem"
|
||||
path = "fuzz_targets/pmem.rs"
|
||||
|
||||
@@ -16,12 +16,12 @@ use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
|
||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
||||
|
||||
const QUEUE_DATA_SIZE: usize = 4;
|
||||
const MEM_SIZE: usize = 1 * 1024 * 1024;
|
||||
const MEM_SIZE: usize = 512 * 1024;
|
||||
const BALLOON_SIZE: u64 = 512 * 1024;
|
||||
// Number of queues
|
||||
const QUEUE_NUM: usize = 3;
|
||||
// Max entries in the queue.
|
||||
const QUEUE_SIZE: u16 = 256;
|
||||
const QUEUE_SIZE: u16 = 64;
|
||||
// Descriptor table alignment
|
||||
const DESC_TABLE_ALIGN_SIZE: u64 = 16;
|
||||
// Avalable ring alignment
|
||||
@@ -49,6 +49,7 @@ fuzz_target!(|bytes| {
|
||||
true,
|
||||
SeccompAction::Allow,
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ fuzz_target!(|bytes| {
|
||||
SeccompAction::Allow,
|
||||
None,
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
194
fuzz/fuzz_targets/console.rs
Normal file
194
fuzz/fuzz_targets/console.rs
Normal file
@@ -0,0 +1,194 @@
|
||||
// Copyright © 2022 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use seccompiler::SeccompAction;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::sync::Arc;
|
||||
use virtio_devices::{VirtioDevice, VirtioInterrupt, VirtioInterruptType};
|
||||
use virtio_queue::{Queue, QueueT};
|
||||
use vm_memory::{bitmap::AtomicBitmap, Bytes, GuestAddress, GuestMemoryAtomic};
|
||||
use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
|
||||
|
||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
||||
|
||||
macro_rules! align {
|
||||
($n:expr, $align:expr) => {{
|
||||
(($n + $align - 1) / $align) * $align
|
||||
}};
|
||||
}
|
||||
|
||||
const CONSOLE_INPUT_SIZE: usize = 128;
|
||||
const QUEUE_DATA_SIZE: usize = 4;
|
||||
const MEM_SIZE: usize = 32 * 1024 * 1024;
|
||||
// Guest memory gap
|
||||
const GUEST_MEM_GAP: u64 = 1 * 1024 * 1024;
|
||||
// Guest physical address for the first virt queue
|
||||
const BASE_VIRT_QUEUE_ADDR: u64 = MEM_SIZE as u64 + GUEST_MEM_GAP;
|
||||
// Number of queues
|
||||
const QUEUE_NUM: usize = 2;
|
||||
// Max entries in the queue.
|
||||
const QUEUE_SIZE: u16 = 256;
|
||||
// Descriptor table alignment
|
||||
const DESC_TABLE_ALIGN_SIZE: u64 = 16;
|
||||
// Used ring alignment
|
||||
const USED_RING_ALIGN_SIZE: u64 = 4;
|
||||
// Descriptor table size
|
||||
const DESC_TABLE_SIZE: u64 = 16_u64 * QUEUE_SIZE as u64;
|
||||
// Available ring size
|
||||
const AVAIL_RING_SIZE: u64 = 6_u64 + 2 * QUEUE_SIZE as u64;
|
||||
// Padding size before used ring
|
||||
const PADDING_SIZE: u64 = align!(AVAIL_RING_SIZE, USED_RING_ALIGN_SIZE) - AVAIL_RING_SIZE;
|
||||
// Used ring size
|
||||
const USED_RING_SIZE: u64 = 6_u64 + 8 * QUEUE_SIZE as u64;
|
||||
// Virtio-queue size in bytes
|
||||
const QUEUE_BYTES_SIZE: usize = align!(
|
||||
DESC_TABLE_SIZE + AVAIL_RING_SIZE + PADDING_SIZE + USED_RING_SIZE,
|
||||
DESC_TABLE_ALIGN_SIZE
|
||||
) as usize;
|
||||
|
||||
fuzz_target!(|bytes| {
|
||||
if bytes.len() < (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE) * QUEUE_NUM + CONSOLE_INPUT_SIZE
|
||||
|| bytes.len()
|
||||
> (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE) * QUEUE_NUM + CONSOLE_INPUT_SIZE + MEM_SIZE
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let (pipe_rx, mut pipe_tx) = create_pipe().unwrap();
|
||||
let output = unsafe {
|
||||
File::from_raw_fd(
|
||||
memfd_create(&std::ffi::CString::new("fuzz_console_output").unwrap()).unwrap(),
|
||||
)
|
||||
};
|
||||
let endpoint = virtio_devices::Endpoint::FilePair(output, pipe_rx);
|
||||
|
||||
let (mut console, _) = virtio_devices::Console::new(
|
||||
"fuzzer_console".to_owned(),
|
||||
endpoint,
|
||||
None, // resize_pipe
|
||||
false, // iommu
|
||||
SeccompAction::Allow,
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let console_input_bytes = &bytes[..CONSOLE_INPUT_SIZE];
|
||||
let queue_data = &bytes[CONSOLE_INPUT_SIZE..CONSOLE_INPUT_SIZE + QUEUE_DATA_SIZE * QUEUE_NUM];
|
||||
let queue_bytes = &bytes[CONSOLE_INPUT_SIZE + QUEUE_DATA_SIZE * QUEUE_NUM
|
||||
..CONSOLE_INPUT_SIZE + (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE) * QUEUE_NUM];
|
||||
let mem_bytes = &bytes[CONSOLE_INPUT_SIZE + (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE) * QUEUE_NUM..];
|
||||
|
||||
// Setup the virt queues with the input bytes
|
||||
let mut queues = setup_virt_queues(
|
||||
&[
|
||||
&queue_data[..QUEUE_DATA_SIZE].try_into().unwrap(),
|
||||
&queue_data[QUEUE_DATA_SIZE..QUEUE_DATA_SIZE * 2]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
],
|
||||
BASE_VIRT_QUEUE_ADDR,
|
||||
);
|
||||
|
||||
// Setup the guest memory with the input bytes
|
||||
let mem = GuestMemoryMmap::from_ranges(&[
|
||||
(GuestAddress(0), MEM_SIZE),
|
||||
(GuestAddress(BASE_VIRT_QUEUE_ADDR), queue_bytes.len()),
|
||||
])
|
||||
.unwrap();
|
||||
if mem
|
||||
.write_slice(queue_bytes, GuestAddress(BASE_VIRT_QUEUE_ADDR))
|
||||
.is_err()
|
||||
{
|
||||
return;
|
||||
}
|
||||
if mem.write_slice(mem_bytes, GuestAddress(0 as u64)).is_err() {
|
||||
return;
|
||||
}
|
||||
let guest_memory = GuestMemoryAtomic::new(mem);
|
||||
|
||||
let input_queue = queues.remove(0);
|
||||
let input_evt = EventFd::new(0).unwrap();
|
||||
let input_queue_evt = unsafe { EventFd::from_raw_fd(libc::dup(input_evt.as_raw_fd())) };
|
||||
let output_queue = queues.remove(0);
|
||||
let output_evt = EventFd::new(0).unwrap();
|
||||
let output_queue_evt = unsafe { EventFd::from_raw_fd(libc::dup(output_evt.as_raw_fd())) };
|
||||
|
||||
// Kick the 'queue' events and endpoint event before activate the console device
|
||||
input_queue_evt.write(1).unwrap();
|
||||
output_queue_evt.write(1).unwrap();
|
||||
pipe_tx.write_all(console_input_bytes).unwrap(); // To use fuzzed data;
|
||||
|
||||
console
|
||||
.activate(
|
||||
guest_memory,
|
||||
Arc::new(NoopVirtioInterrupt {}),
|
||||
vec![(0, input_queue, input_evt), (1, output_queue, output_evt)],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Wait for the events to finish and console device worker thread to return
|
||||
console.wait_for_epoll_threads();
|
||||
});
|
||||
|
||||
pub struct NoopVirtioInterrupt {}
|
||||
|
||||
impl VirtioInterrupt for NoopVirtioInterrupt {
|
||||
fn trigger(&self, _int_type: VirtioInterruptType) -> std::result::Result<(), std::io::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_virt_queues(bytes: &[&[u8; QUEUE_DATA_SIZE]], base_addr: u64) -> Vec<Queue> {
|
||||
let mut queues = Vec::new();
|
||||
for (i, b) in bytes.iter().enumerate() {
|
||||
let mut q = Queue::new(QUEUE_SIZE).unwrap();
|
||||
|
||||
let desc_table_addr = base_addr + (QUEUE_BYTES_SIZE * i) as u64;
|
||||
let avail_ring_addr = desc_table_addr + DESC_TABLE_SIZE;
|
||||
let used_ring_addr = avail_ring_addr + PADDING_SIZE + AVAIL_RING_SIZE;
|
||||
q.try_set_desc_table_address(GuestAddress(desc_table_addr))
|
||||
.unwrap();
|
||||
q.try_set_avail_ring_address(GuestAddress(avail_ring_addr))
|
||||
.unwrap();
|
||||
q.try_set_used_ring_address(GuestAddress(used_ring_addr))
|
||||
.unwrap();
|
||||
|
||||
q.set_next_avail(b[0] as u16); // 'u8' is enough given the 'QUEUE_SIZE' is small
|
||||
q.set_next_used(b[1] as u16);
|
||||
q.set_event_idx(b[2] % 2 != 0);
|
||||
q.set_size(b[3] as u16 % QUEUE_SIZE);
|
||||
|
||||
q.set_ready(true);
|
||||
queues.push(q);
|
||||
}
|
||||
|
||||
queues
|
||||
}
|
||||
|
||||
fn memfd_create(name: &std::ffi::CStr) -> Result<RawFd, std::io::Error> {
|
||||
let res = unsafe { libc::syscall(libc::SYS_memfd_create, name.as_ptr(), 0) };
|
||||
|
||||
if res < 0 {
|
||||
Err(std::io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(res as RawFd)
|
||||
}
|
||||
}
|
||||
|
||||
fn create_pipe() -> Result<(File, File), std::io::Error> {
|
||||
let mut pipe = [-1; 2];
|
||||
if unsafe { libc::pipe2(pipe.as_mut_ptr(), libc::O_CLOEXEC) } == -1 {
|
||||
return Err(std::io::Error::last_os_error());
|
||||
}
|
||||
let rx = unsafe { File::from_raw_fd(pipe[0]) };
|
||||
let tx = unsafe { File::from_raw_fd(pipe[1]) };
|
||||
|
||||
Ok((rx, tx))
|
||||
}
|
||||
145
fuzz/fuzz_targets/iommu.rs
Normal file
145
fuzz/fuzz_targets/iommu.rs
Normal file
@@ -0,0 +1,145 @@
|
||||
// Copyright © 2022 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use seccompiler::SeccompAction;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||
use std::sync::Arc;
|
||||
use virtio_devices::{VirtioDevice, VirtioInterrupt, VirtioInterruptType};
|
||||
use virtio_queue::{Queue, QueueT};
|
||||
use vm_memory::{bitmap::AtomicBitmap, Bytes, GuestAddress, GuestMemoryAtomic};
|
||||
use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
|
||||
|
||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
||||
|
||||
macro_rules! align {
|
||||
($n:expr, $align:expr) => {{
|
||||
(($n + $align - 1) / $align) * $align
|
||||
}};
|
||||
}
|
||||
|
||||
const QUEUE_DATA_SIZE: usize = 4;
|
||||
const MEM_SIZE: usize = 32 * 1024 * 1024;
|
||||
// Reuse what's being done from DeviceManager::get_msi_iova_space()
|
||||
const IOVA_SPACE_SIZE: usize = (0xfeef_ffff - 0xfee0_0000) + 1;
|
||||
|
||||
// Max entries in the queue.
|
||||
const QUEUE_SIZE: u16 = 256;
|
||||
// Descriptor table alignment
|
||||
const DESC_TABLE_ALIGN_SIZE: u64 = 16;
|
||||
// Avalable ring alignment
|
||||
const AVAIL_RING_ALIGN_SIZE: u64 = 2;
|
||||
// Used ring alignment
|
||||
const USED_RING_ALIGN_SIZE: u64 = 4;
|
||||
// Descriptor table size
|
||||
const DESC_TABLE_SIZE: u64 = 16_u64 * QUEUE_SIZE as u64;
|
||||
// Available ring size
|
||||
const AVAIL_RING_SIZE: u64 = 6_u64 + 2 * QUEUE_SIZE as u64;
|
||||
// Used ring size
|
||||
const USED_RING_SIZE: u64 = 6_u64 + 8 * QUEUE_SIZE as u64;
|
||||
|
||||
// Guest memory gap
|
||||
const GUEST_MEM_GAP: u64 = 1 * 1024 * 1024;
|
||||
// Guest physical address for descriptor table.
|
||||
const DESC_TABLE_ADDR: u64 = align!(MEM_SIZE as u64 + GUEST_MEM_GAP, DESC_TABLE_ALIGN_SIZE);
|
||||
// Guest physical address for available ring
|
||||
const AVAIL_RING_ADDR: u64 = align!(DESC_TABLE_ADDR + DESC_TABLE_SIZE, AVAIL_RING_ALIGN_SIZE);
|
||||
// Guest physical address for used ring
|
||||
const USED_RING_ADDR: u64 = align!(AVAIL_RING_ADDR + AVAIL_RING_SIZE, USED_RING_ALIGN_SIZE);
|
||||
// Virtio-queue size in bytes
|
||||
const QUEUE_BYTES_SIZE: usize = (USED_RING_ADDR + USED_RING_SIZE - DESC_TABLE_ADDR) as usize;
|
||||
|
||||
fuzz_target!(|bytes| {
|
||||
if bytes.len() < (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE)
|
||||
|| bytes.len() > (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE + MEM_SIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let (mut iommu, _) = virtio_devices::Iommu::new(
|
||||
"fuzzer_iommu".to_owned(),
|
||||
SeccompAction::Allow,
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
((MEM_SIZE - IOVA_SPACE_SIZE) as u64, (MEM_SIZE - 1) as u64),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let queue_data = &bytes[..QUEUE_DATA_SIZE];
|
||||
let queue_bytes = &bytes[QUEUE_DATA_SIZE..QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE];
|
||||
let mem_bytes = &bytes[QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE..];
|
||||
|
||||
// Setup the request queue with the input bytes
|
||||
let request_queue = setup_virt_queue(queue_data.try_into().unwrap());
|
||||
// Given the "event queue" events are not handled from the current
|
||||
// implementation of virtio-iommu, we simply setup the 'event_queue'
|
||||
// with exactly the same content as the 'request_queue'.
|
||||
let _event_queue = setup_virt_queue(queue_data.try_into().unwrap());
|
||||
|
||||
// Setup the guest memory with the input bytes
|
||||
let mem = GuestMemoryMmap::from_ranges(&[
|
||||
(GuestAddress(0), MEM_SIZE),
|
||||
(GuestAddress(DESC_TABLE_ADDR), QUEUE_BYTES_SIZE),
|
||||
])
|
||||
.unwrap();
|
||||
if mem
|
||||
.write_slice(queue_bytes, GuestAddress(DESC_TABLE_ADDR))
|
||||
.is_err()
|
||||
{
|
||||
return;
|
||||
}
|
||||
if mem.write_slice(mem_bytes, GuestAddress(0 as u64)).is_err() {
|
||||
return;
|
||||
}
|
||||
let guest_memory = GuestMemoryAtomic::new(mem);
|
||||
|
||||
let request_evt = EventFd::new(0).unwrap();
|
||||
let request_queue_evt = unsafe { EventFd::from_raw_fd(libc::dup(request_evt.as_raw_fd())) };
|
||||
let _event_evt = EventFd::new(0).unwrap();
|
||||
|
||||
// Kick the 'queue' event before activate the vIOMMU device
|
||||
request_queue_evt.write(1).unwrap();
|
||||
|
||||
iommu
|
||||
.activate(
|
||||
guest_memory,
|
||||
Arc::new(NoopVirtioInterrupt {}),
|
||||
vec![
|
||||
(0, request_queue, request_evt),
|
||||
(0, _event_queue, _event_evt),
|
||||
],
|
||||
)
|
||||
.ok();
|
||||
|
||||
// Wait for the events to finish and vIOMMU device worker thread to return
|
||||
iommu.wait_for_epoll_threads();
|
||||
});
|
||||
|
||||
pub struct NoopVirtioInterrupt {}
|
||||
|
||||
impl VirtioInterrupt for NoopVirtioInterrupt {
|
||||
fn trigger(&self, _int_type: VirtioInterruptType) -> std::result::Result<(), std::io::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_virt_queue(bytes: &[u8; QUEUE_DATA_SIZE]) -> Queue {
|
||||
let mut q = Queue::new(QUEUE_SIZE).unwrap();
|
||||
q.set_next_avail(bytes[0] as u16); // 'u8' is enough given the 'QUEUE_SIZE' is small
|
||||
q.set_next_used(bytes[1] as u16);
|
||||
q.set_event_idx(bytes[2] % 2 != 0);
|
||||
q.set_size(bytes[3] as u16 % QUEUE_SIZE);
|
||||
|
||||
q.try_set_desc_table_address(GuestAddress(DESC_TABLE_ADDR))
|
||||
.unwrap();
|
||||
q.try_set_avail_ring_address(GuestAddress(AVAIL_RING_ADDR))
|
||||
.unwrap();
|
||||
q.try_set_used_ring_address(GuestAddress(USED_RING_ADDR))
|
||||
.unwrap();
|
||||
q.set_ready(true);
|
||||
|
||||
q
|
||||
}
|
||||
179
fuzz/fuzz_targets/mem.rs
Normal file
179
fuzz/fuzz_targets/mem.rs
Normal file
@@ -0,0 +1,179 @@
|
||||
// Copyright © 2022 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use seccompiler::SeccompAction;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use virtio_devices::{BlocksState, Mem, VirtioDevice, VirtioInterrupt, VirtioInterruptType};
|
||||
use virtio_queue::{Queue, QueueT};
|
||||
use vm_memory::{bitmap::AtomicBitmap, Bytes, GuestAddress, GuestMemoryAtomic};
|
||||
use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
|
||||
|
||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
||||
type GuestRegionMmap = vm_memory::GuestRegionMmap<AtomicBitmap>;
|
||||
|
||||
macro_rules! align {
|
||||
($n:expr, $align:expr) => {{
|
||||
(($n + $align - 1) / $align) * $align
|
||||
}};
|
||||
}
|
||||
|
||||
const VIRTIO_MEM_DATA_SIZE: usize = 1;
|
||||
const QUEUE_DATA_SIZE: usize = 4;
|
||||
// The size of the guest memory for the virtio-mem region
|
||||
const MEM_SIZE: usize = 128 * 1024 * 1024;
|
||||
// The start address of the virtio-mem region in the guest memory
|
||||
const VIRTIO_MEM_REGION_ADDRESS: u64 = 0;
|
||||
|
||||
// Max entries in the queue.
|
||||
const QUEUE_SIZE: u16 = 64;
|
||||
// Descriptor table alignment
|
||||
const DESC_TABLE_ALIGN_SIZE: u64 = 16;
|
||||
// Avalable ring alignment
|
||||
const AVAIL_RING_ALIGN_SIZE: u64 = 2;
|
||||
// Used ring alignment
|
||||
const USED_RING_ALIGN_SIZE: u64 = 4;
|
||||
// Descriptor table size
|
||||
const DESC_TABLE_SIZE: u64 = 16_u64 * QUEUE_SIZE as u64;
|
||||
// Available ring size
|
||||
const AVAIL_RING_SIZE: u64 = 6_u64 + 2 * QUEUE_SIZE as u64;
|
||||
// Used ring size
|
||||
const USED_RING_SIZE: u64 = 6_u64 + 8 * QUEUE_SIZE as u64;
|
||||
|
||||
// Guest memory gap
|
||||
const GUEST_MEM_GAP: u64 = 1 * 1024 * 1024;
|
||||
// Guest physical address for descriptor table.
|
||||
const DESC_TABLE_ADDR: u64 = align!(MEM_SIZE as u64 + GUEST_MEM_GAP, DESC_TABLE_ALIGN_SIZE);
|
||||
// Guest physical address for available ring
|
||||
const AVAIL_RING_ADDR: u64 = align!(DESC_TABLE_ADDR + DESC_TABLE_SIZE, AVAIL_RING_ALIGN_SIZE);
|
||||
// Guest physical address for used ring
|
||||
const USED_RING_ADDR: u64 = align!(AVAIL_RING_ADDR + AVAIL_RING_SIZE, USED_RING_ALIGN_SIZE);
|
||||
// Virtio-queue size in bytes
|
||||
const QUEUE_BYTES_SIZE: usize = (USED_RING_ADDR + USED_RING_SIZE - DESC_TABLE_ADDR) as usize;
|
||||
|
||||
fuzz_target!(|bytes| {
|
||||
if bytes.len() < VIRTIO_MEM_DATA_SIZE + QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE
|
||||
|| bytes.len() > (VIRTIO_MEM_DATA_SIZE + QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE + MEM_SIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let virtio_mem_data = &bytes[..VIRTIO_MEM_DATA_SIZE];
|
||||
let queue_data = &bytes[VIRTIO_MEM_DATA_SIZE..VIRTIO_MEM_DATA_SIZE + QUEUE_DATA_SIZE];
|
||||
let queue_bytes = &bytes[VIRTIO_MEM_DATA_SIZE + QUEUE_DATA_SIZE
|
||||
..VIRTIO_MEM_DATA_SIZE + QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE];
|
||||
let mem_bytes = &bytes[VIRTIO_MEM_DATA_SIZE + QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE..];
|
||||
|
||||
// Create a virtio-mem device based on the input bytes;
|
||||
let (mut virtio_mem, virtio_mem_region) =
|
||||
create_dummy_virtio_mem(virtio_mem_data.try_into().unwrap());
|
||||
|
||||
// Setup the virt queue with the input bytes
|
||||
let q = setup_virt_queue(queue_data.try_into().unwrap());
|
||||
|
||||
// Setup the guest memory with the input bytes
|
||||
let mem = GuestMemoryMmap::from_ranges(&[
|
||||
(GuestAddress(DESC_TABLE_ADDR), QUEUE_BYTES_SIZE), // guest region for the virt queue
|
||||
])
|
||||
.unwrap();
|
||||
if mem
|
||||
.write_slice(queue_bytes, GuestAddress(DESC_TABLE_ADDR))
|
||||
.is_err()
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Add the memory region for the virtio-mem device
|
||||
let mem = mem.insert_region(virtio_mem_region).unwrap();
|
||||
if mem
|
||||
.write_slice(mem_bytes, GuestAddress(VIRTIO_MEM_REGION_ADDRESS))
|
||||
.is_err()
|
||||
{
|
||||
return;
|
||||
}
|
||||
let guest_memory = GuestMemoryAtomic::new(mem);
|
||||
|
||||
let evt = EventFd::new(0).unwrap();
|
||||
let queue_evt = unsafe { EventFd::from_raw_fd(libc::dup(evt.as_raw_fd())) };
|
||||
|
||||
// Kick the 'queue' event before activate the virtio-mem device
|
||||
queue_evt.write(1).unwrap();
|
||||
|
||||
virtio_mem
|
||||
.activate(
|
||||
guest_memory,
|
||||
Arc::new(NoopVirtioInterrupt {}),
|
||||
vec![(0, q, evt)],
|
||||
)
|
||||
.ok();
|
||||
|
||||
// Wait for the events to finish and virtio-mem device worker thread to return
|
||||
virtio_mem.wait_for_epoll_threads();
|
||||
});
|
||||
|
||||
pub struct NoopVirtioInterrupt {}
|
||||
|
||||
impl VirtioInterrupt for NoopVirtioInterrupt {
|
||||
fn trigger(&self, _int_type: VirtioInterruptType) -> std::result::Result<(), std::io::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Create a dummy virtio-mem device for fuzzing purpose only
|
||||
fn create_dummy_virtio_mem(bytes: &[u8; VIRTIO_MEM_DATA_SIZE]) -> (Mem, Arc<GuestRegionMmap>) {
|
||||
let numa_id = if bytes[0] % 2 != 0 { Some(0) } else { None };
|
||||
|
||||
let region = vmm::memory_manager::MemoryManager::create_ram_region(
|
||||
&None,
|
||||
0,
|
||||
GuestAddress(VIRTIO_MEM_REGION_ADDRESS),
|
||||
MEM_SIZE,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
numa_id,
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let blocks_state = Arc::new(Mutex::new(BlocksState::new(region.size() as u64)));
|
||||
|
||||
(
|
||||
Mem::new(
|
||||
"fuzzer_mem".to_owned(),
|
||||
®ion,
|
||||
SeccompAction::Allow,
|
||||
numa_id.map(|i| i as u16),
|
||||
0,
|
||||
false,
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
blocks_state.clone(),
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
region,
|
||||
)
|
||||
}
|
||||
|
||||
fn setup_virt_queue(bytes: &[u8; QUEUE_DATA_SIZE]) -> Queue {
|
||||
let mut q = Queue::new(QUEUE_SIZE).unwrap();
|
||||
q.set_next_avail(bytes[0] as u16); // 'u8' is enough given the 'QUEUE_SIZE' is small
|
||||
q.set_next_used(bytes[1] as u16);
|
||||
q.set_event_idx(bytes[2] % 2 != 0);
|
||||
q.set_size(bytes[3] as u16 % QUEUE_SIZE);
|
||||
|
||||
q.try_set_desc_table_address(GuestAddress(DESC_TABLE_ADDR))
|
||||
.unwrap();
|
||||
q.try_set_avail_ring_address(GuestAddress(AVAIL_RING_ADDR))
|
||||
.unwrap();
|
||||
q.try_set_used_ring_address(GuestAddress(USED_RING_ADDR))
|
||||
.unwrap();
|
||||
q.set_ready(true);
|
||||
|
||||
q
|
||||
}
|
||||
@@ -127,6 +127,7 @@ fn create_dummy_pmem() -> Pmem {
|
||||
false,
|
||||
SeccompAction::Allow,
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ fuzz_target!(|bytes| {
|
||||
false,
|
||||
SeccompAction::Allow,
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ fuzz_target!(|bytes| {
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
SeccompAction::Allow,
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -11,20 +11,20 @@ mshv = ["mshv-ioctls", "mshv-bindings"]
|
||||
tdx = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.65"
|
||||
anyhow = "1.0.66"
|
||||
byteorder = "1.4.3"
|
||||
thiserror = "1.0.37"
|
||||
libc = "0.2.133"
|
||||
libc = "0.2.138"
|
||||
log = "0.4.17"
|
||||
kvm-ioctls = { version = "0.11.0", optional = true }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
kvm-ioctls = { version = "0.13.0", optional = true }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
||||
serde = { version = "1.0.145", features = ["rc", "derive"] }
|
||||
serde_with = { version = "2.0.1", default-features = false, features = ["macros"] }
|
||||
serde = { version = "1.0.150", features = ["rc", "derive"] }
|
||||
serde_with = { version = "2.1.0", default-features = false, features = ["macros"] }
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||
vm-memory = { version = "0.9.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = { version = "0.10.0", features = ["with-serde"] }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
||||
version = "1.17.0"
|
||||
@@ -32,4 +32,4 @@ default-features = false
|
||||
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.9.1"
|
||||
env_logger = "0.10.0"
|
||||
|
||||
@@ -24,10 +24,10 @@ impl<T: Debug> Display for Exception<T> {
|
||||
self.vector,
|
||||
self.ip,
|
||||
self.error
|
||||
.map(|e| format!(": error {:x}", e))
|
||||
.map(|e| format!(": error {e:x}"))
|
||||
.unwrap_or_else(|| "".to_owned()),
|
||||
self.payload
|
||||
.map(|payload| format!(": payload {:x}", payload))
|
||||
.map(|payload| format!(": payload {payload:x}"))
|
||||
.unwrap_or_else(|| "".to_owned())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ fn get_op<T: CpuStateManager>(
|
||||
insn: &Instruction,
|
||||
op_index: u32,
|
||||
op_size: usize,
|
||||
state: &mut T,
|
||||
platform: &mut dyn PlatformEmulator<CpuState = T>,
|
||||
state: &T,
|
||||
platform: &dyn PlatformEmulator<CpuState = T>,
|
||||
) -> Result<u64, PlatformError> {
|
||||
if insn.op_count() < op_index + 1 {
|
||||
return Err(PlatformError::InvalidOperand(anyhow!(
|
||||
@@ -56,7 +56,7 @@ fn get_op<T: CpuStateManager>(
|
||||
OpKind::Immediate16 => insn.immediate16() as u64,
|
||||
OpKind::Immediate32 => insn.immediate32() as u64,
|
||||
OpKind::Immediate32to64 => insn.immediate32to64() as u64,
|
||||
OpKind::Immediate64 => insn.immediate64() as u64,
|
||||
OpKind::Immediate64 => insn.immediate64(),
|
||||
k => return Err(PlatformError::InvalidOperand(anyhow!("{:?}", k))),
|
||||
};
|
||||
|
||||
|
||||
@@ -48,12 +48,12 @@ pub enum HypervisorCpuError {
|
||||
///
|
||||
/// Setting floating point registers error
|
||||
///
|
||||
#[error("Failed to set special register: {0}")]
|
||||
#[error("Failed to set floating point registers: {0}")]
|
||||
SetFloatingPointRegs(#[source] anyhow::Error),
|
||||
///
|
||||
/// Getting floating point register error
|
||||
///
|
||||
#[error("Failed to get special register: {0}")]
|
||||
#[error("Failed to get floating points registers: {0}")]
|
||||
GetFloatingPointRegs(#[source] anyhow::Error),
|
||||
///
|
||||
/// Setting Cpuid error
|
||||
@@ -237,6 +237,12 @@ pub enum HypervisorCpuError {
|
||||
///
|
||||
#[error("Failed to initialize PMU")]
|
||||
InitializePmu,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Error getting TSC frequency
|
||||
///
|
||||
#[error("Failed to get TSC frequency: {0}")]
|
||||
GetTscKhz(#[source] anyhow::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -432,4 +438,11 @@ pub trait Vcpu: Send + Sync {
|
||||
/// Return the list of initial MSR entries for a VCPU
|
||||
///
|
||||
fn boot_msr_entries(&self) -> Vec<MsrEntry>;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Get the frequency of the TSC if available
|
||||
///
|
||||
fn tsc_khz(&self) -> Result<Option<u32>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,8 +97,7 @@ pub fn is_system_register(regid: u64) -> bool {
|
||||
|
||||
assert!(
|
||||
!(size != KVM_REG_SIZE_U32 && size != KVM_REG_SIZE_U64),
|
||||
"Unexpected register size for system register {}",
|
||||
size
|
||||
"Unexpected register size for system register {size}"
|
||||
);
|
||||
|
||||
true
|
||||
|
||||
@@ -330,7 +330,7 @@ impl KvmVm {
|
||||
Ok(VfioDeviceFd::new_from_kvm(device_fd))
|
||||
}
|
||||
/// Checks if a particular `Cap` is available.
|
||||
fn check_extension(&self, c: Cap) -> bool {
|
||||
pub fn check_extension(&self, c: Cap) -> bool {
|
||||
self.fd.check_extension(c)
|
||||
}
|
||||
}
|
||||
@@ -2152,6 +2152,23 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.set_device_attr(&cpu_attr)
|
||||
.map_err(|_| cpu::HypervisorCpuError::InitializePmu)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Get the frequency of the TSC if available
|
||||
///
|
||||
fn tsc_khz(&self) -> cpu::Result<Option<u32>> {
|
||||
match self.fd.get_tsc_khz() {
|
||||
Err(e) => {
|
||||
if e.errno() == libc::EIO {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(cpu::HypervisorCpuError::GetTscKhz(e.into()))
|
||||
}
|
||||
}
|
||||
Ok(v) => Ok(Some(v)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KvmVcpu {
|
||||
|
||||
@@ -50,6 +50,9 @@ pub fn check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()> {
|
||||
if !kvm.check_extension(Cap::ImmediateExit) {
|
||||
return Err(KvmError::CapabilityMissing(Cap::ImmediateExit));
|
||||
}
|
||||
if !kvm.check_extension(Cap::GetTscKhz) {
|
||||
return Err(KvmError::CapabilityMissing(Cap::GetTscKhz));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
|
||||
@@ -61,7 +61,7 @@ pub use vm::{
|
||||
Vm, VmOps,
|
||||
};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum HypervisorType {
|
||||
Kvm,
|
||||
Mshv,
|
||||
|
||||
@@ -38,9 +38,7 @@ use std::fs::File;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::x86::{
|
||||
CpuIdEntry, FpuState, LapicState, MsrEntry, SpecialRegisters, StandardRegisters,
|
||||
};
|
||||
use crate::arch::x86::{CpuIdEntry, FpuState, MsrEntry};
|
||||
|
||||
const DIRTY_BITMAP_CLEAR_DIRTY: u64 = 0x4;
|
||||
const DIRTY_BITMAP_SET_DIRTY: u64 = 0x8;
|
||||
@@ -299,7 +297,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
///
|
||||
/// Returns the vCPU general purpose registers.
|
||||
///
|
||||
fn get_regs(&self) -> cpu::Result<StandardRegisters> {
|
||||
fn get_regs(&self) -> cpu::Result<crate::arch::x86::StandardRegisters> {
|
||||
Ok(self
|
||||
.fd
|
||||
.get_regs()
|
||||
@@ -310,7 +308,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
///
|
||||
/// Sets the vCPU general purpose registers.
|
||||
///
|
||||
fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> {
|
||||
fn set_regs(&self, regs: &crate::arch::x86::StandardRegisters) -> cpu::Result<()> {
|
||||
let regs = (*regs).into();
|
||||
self.fd
|
||||
.set_regs(®s)
|
||||
@@ -320,7 +318,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
///
|
||||
/// Returns the vCPU special registers.
|
||||
///
|
||||
fn get_sregs(&self) -> cpu::Result<SpecialRegisters> {
|
||||
fn get_sregs(&self) -> cpu::Result<crate::arch::x86::SpecialRegisters> {
|
||||
Ok(self
|
||||
.fd
|
||||
.get_sregs()
|
||||
@@ -331,7 +329,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
///
|
||||
/// Sets the vCPU special registers.
|
||||
///
|
||||
fn set_sregs(&self, sregs: &SpecialRegisters) -> cpu::Result<()> {
|
||||
fn set_sregs(&self, sregs: &crate::arch::x86::SpecialRegisters) -> cpu::Result<()> {
|
||||
let sregs = (*sregs).into();
|
||||
self.fd
|
||||
.set_sregs(&sregs)
|
||||
@@ -581,7 +579,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
///
|
||||
/// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
|
||||
///
|
||||
fn get_lapic(&self) -> cpu::Result<LapicState> {
|
||||
fn get_lapic(&self) -> cpu::Result<crate::arch::x86::LapicState> {
|
||||
Ok(self
|
||||
.fd
|
||||
.get_lapic()
|
||||
@@ -592,7 +590,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
///
|
||||
/// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
|
||||
///
|
||||
fn set_lapic(&self, lapic: &LapicState) -> cpu::Result<()> {
|
||||
fn set_lapic(&self, lapic: &crate::arch::x86::LapicState) -> cpu::Result<()> {
|
||||
let lapic: mshv_bindings::LapicState = (*lapic).clone().into();
|
||||
self.fd
|
||||
.set_lapic(&lapic)
|
||||
@@ -703,7 +701,6 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
msr!(msr_index::MSR_LSTAR),
|
||||
msr!(msr_index::MSR_KERNEL_GS_BASE),
|
||||
msr!(msr_index::MSR_SYSCALL_MASK),
|
||||
msr!(msr_index::MSR_IA32_TSC),
|
||||
msr_data!(msr_index::MSR_MTRRdefType, MTRR_ENABLE | MTRR_MEM_TYPE_WB),
|
||||
]
|
||||
.to_vec()
|
||||
@@ -1093,7 +1090,7 @@ impl vm::Vm for MshvVm {
|
||||
flags,
|
||||
guest_pfn: guest_phys_addr >> PAGE_SHIFT,
|
||||
size: memory_size,
|
||||
userspace_addr: userspace_addr as u64,
|
||||
userspace_addr,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@ authors = ["The Chromium OS Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
vmm-sys-util = "0.10.0"
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
@@ -28,10 +28,12 @@ pub mod inn;
|
||||
// generated with bindgen /usr/include/linux/sockios.h --no-unstable-rust
|
||||
// --constified-enum '*' --with-derive-default
|
||||
pub mod sockios;
|
||||
pub use if_tun::*;
|
||||
pub use iff::*;
|
||||
pub use inn::*;
|
||||
pub use sockios::*;
|
||||
pub use if_tun::{
|
||||
sock_fprog, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_TAP, IFF_VNET_HDR, TUN_F_CSUM, TUN_F_TSO4,
|
||||
TUN_F_TSO6, TUN_F_TSO_ECN, TUN_F_UFO,
|
||||
};
|
||||
pub use iff::{ifreq, net_device_flags_IFF_UP, setsockopt, sockaddr, AF_INET};
|
||||
pub use inn::sockaddr_in;
|
||||
|
||||
pub const TUNTAP: ::std::os::raw::c_uint = 84;
|
||||
|
||||
|
||||
@@ -6,23 +6,23 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
epoll = "4.3.1"
|
||||
getrandom = "0.2.7"
|
||||
libc = "0.2.133"
|
||||
getrandom = "0.2.8"
|
||||
libc = "0.2.138"
|
||||
log = "0.4.17"
|
||||
net_gen = { path = "../net_gen" }
|
||||
rate_limiter = { path = "../rate_limiter" }
|
||||
serde = "1.0.145"
|
||||
serde = "1.0.150"
|
||||
thiserror = "1.0.37"
|
||||
versionize = "0.1.6"
|
||||
versionize = "0.1.9"
|
||||
versionize_derive = "0.1.4"
|
||||
virtio-bindings = "0.1.0"
|
||||
virtio-queue = "0.6.1"
|
||||
vm-memory = { version = "0.9.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
virtio-queue = "0.7.0"
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.10.0"
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
[dev-dependencies]
|
||||
once_cell = "1.15.0"
|
||||
pnet = "0.31.0"
|
||||
pnet_datalink = "0.31.0"
|
||||
serde_json = "1.0.85"
|
||||
once_cell = "1.16.0"
|
||||
pnet = "0.34.0"
|
||||
pnet_datalink = "0.34.0"
|
||||
serde_json = "1.0.89"
|
||||
|
||||
@@ -125,7 +125,7 @@ impl<'de> Deserialize<'de> for MacAddr {
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
MacAddr::parse_str(&s)
|
||||
.map_err(|e| D::Error::custom(format!("The provided MAC address is invalid: {}", e)))
|
||||
.map_err(|e| D::Error::custom(format!("The provided MAC address is invalid: {e}")))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ mod tests {
|
||||
|
||||
let mac = MacAddr::parse_str("12:34:56:78:9a:BC").unwrap();
|
||||
|
||||
println!("parsed MAC address: {}", mac);
|
||||
println!("parsed MAC address: {mac}");
|
||||
|
||||
let bytes = mac.get_bytes();
|
||||
assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]);
|
||||
|
||||
@@ -12,9 +12,9 @@ use thiserror::Error;
|
||||
pub enum Error {
|
||||
#[error("Failed to convert an hexadecimal string into an integer: {0}")]
|
||||
ConvertHexStringToInt(std::num::ParseIntError),
|
||||
#[error("Error related to the multiqueue support (no support TAP side).")]
|
||||
#[error("Error related to the multiqueue support (no support TAP side)")]
|
||||
MultiQueueNoTapSupport,
|
||||
#[error("Error related to the multiqueue support (no support device side).")]
|
||||
#[error("Error related to the multiqueue support (no support device side)")]
|
||||
MultiQueueNoDeviceSupport,
|
||||
#[error("Failed to read the TAP flags from sysfs: {0}")]
|
||||
ReadSysfsTunFlags(io::Error),
|
||||
@@ -41,7 +41,7 @@ type Result<T> = std::result::Result<T, Error>;
|
||||
fn check_mq_support(if_name: &Option<&str>, queue_pairs: usize) -> Result<()> {
|
||||
if let Some(tap_name) = if_name {
|
||||
let mq = queue_pairs > 1;
|
||||
let path = format!("/sys/class/net/{}/tun_flags", tap_name);
|
||||
let path = format!("/sys/class/net/{tap_name}/tun_flags");
|
||||
// interface does not exist, check is not required
|
||||
if !Path::new(&path).exists() {
|
||||
return Ok(());
|
||||
|
||||
@@ -86,7 +86,7 @@ impl TxVirtio {
|
||||
let result = unsafe {
|
||||
libc::writev(
|
||||
tap.as_raw_fd() as libc::c_int,
|
||||
iovecs.as_ptr() as *const libc::iovec,
|
||||
iovecs.as_ptr(),
|
||||
iovecs.len() as libc::c_int,
|
||||
)
|
||||
};
|
||||
@@ -104,6 +104,10 @@ impl TxVirtio {
|
||||
return Err(NetQueuePairError::WriteTap(e));
|
||||
}
|
||||
|
||||
if (result as usize) < vnet_hdr_len() {
|
||||
return Err(NetQueuePairError::InvalidVirtioNetHeader);
|
||||
}
|
||||
|
||||
self.counter_bytes += Wrapping(result as u64 - vnet_hdr_len() as u64);
|
||||
self.counter_frames += Wrapping(1);
|
||||
|
||||
@@ -185,7 +189,7 @@ impl RxVirtio {
|
||||
.translate_gva(access_platform, desc.len() as usize),
|
||||
10,
|
||||
)
|
||||
.unwrap();
|
||||
.ok_or(NetQueuePairError::DescriptorInvalidHeader)?;
|
||||
let mut next_desc = Some(desc);
|
||||
|
||||
let mut iovecs = Vec::new();
|
||||
@@ -220,7 +224,7 @@ impl RxVirtio {
|
||||
let result = unsafe {
|
||||
libc::readv(
|
||||
tap.as_raw_fd() as libc::c_int,
|
||||
iovecs.as_ptr() as *const libc::iovec,
|
||||
iovecs.as_ptr(),
|
||||
iovecs.len() as libc::c_int,
|
||||
)
|
||||
};
|
||||
@@ -238,6 +242,10 @@ impl RxVirtio {
|
||||
return Err(NetQueuePairError::ReadTap(e));
|
||||
}
|
||||
|
||||
if (result as usize) < vnet_hdr_len() {
|
||||
return Err(NetQueuePairError::InvalidVirtioNetHeader);
|
||||
}
|
||||
|
||||
// Write num_buffers to guest memory. We simply write 1 as we
|
||||
// never spread the frame over more than one descriptor chain.
|
||||
desc_chain
|
||||
@@ -288,7 +296,7 @@ pub struct NetCounters {
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum NetQueuePairError {
|
||||
#[error("No memory configured.")]
|
||||
#[error("No memory configured")]
|
||||
NoMemoryConfigured,
|
||||
#[error("Error registering listener: {0}")]
|
||||
RegisterListener(io::Error),
|
||||
@@ -302,9 +310,9 @@ pub enum NetQueuePairError {
|
||||
GuestMemory(vm_memory::GuestMemoryError),
|
||||
#[error("Returned an error while iterating through the queue: {0}")]
|
||||
QueueIteratorFailed(virtio_queue::Error),
|
||||
#[error("Descriptor chain is too short.")]
|
||||
#[error("Descriptor chain is too short")]
|
||||
DescriptorChainTooShort,
|
||||
#[error("Descriptor chain does not contain valid descriptors.")]
|
||||
#[error("Descriptor chain does not contain valid descriptors")]
|
||||
DescriptorChainInvalid,
|
||||
#[error("Failed to determine if queue needed notification: {0}")]
|
||||
QueueNeedsNotification(virtio_queue::Error),
|
||||
@@ -312,6 +320,10 @@ pub enum NetQueuePairError {
|
||||
QueueEnableNotification(virtio_queue::Error),
|
||||
#[error("Failed to add used index to the queue: {0}")]
|
||||
QueueAddUsed(virtio_queue::Error),
|
||||
#[error("Descriptor with invalid virtio-net header")]
|
||||
DescriptorInvalidHeader,
|
||||
#[error("Invalid virtio-net header")]
|
||||
InvalidVirtioNetHeader,
|
||||
}
|
||||
|
||||
pub struct NetQueuePair {
|
||||
|
||||
@@ -26,13 +26,13 @@ pub enum Error {
|
||||
ConfigureTap(IoError),
|
||||
#[error("Unable to retrieve features: {0}")]
|
||||
GetFeatures(IoError),
|
||||
#[error("Missing multiqueue support in the kernel.")]
|
||||
#[error("Missing multiqueue support in the kernel")]
|
||||
MultiQueueKernelSupport,
|
||||
#[error("ioctl failed: {0}")]
|
||||
IoctlError(IoError),
|
||||
#[error("Failed to create a socket: {0}")]
|
||||
NetUtil(NetUtilError),
|
||||
#[error("Invalid interface name.")]
|
||||
#[error("Invalid interface name")]
|
||||
InvalidIfname,
|
||||
#[error("Error parsing MAC data: {0}")]
|
||||
MacParsing(IoError),
|
||||
@@ -586,7 +586,7 @@ mod tests {
|
||||
let _tap_ip_guard = TAP_IP_LOCK.lock().unwrap();
|
||||
|
||||
let t = Tap::new(1).unwrap();
|
||||
println!("created tap: {:?}", t);
|
||||
println!("created tap: {t:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -28,10 +28,10 @@ pub enum OptionParserError {
|
||||
impl fmt::Display for OptionParserError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
OptionParserError::UnknownOption(s) => write!(f, "unknown option: {}", s),
|
||||
OptionParserError::InvalidSyntax(s) => write!(f, "invalid syntax:{}", s),
|
||||
OptionParserError::UnknownOption(s) => write!(f, "unknown option: {s}"),
|
||||
OptionParserError::InvalidSyntax(s) => write!(f, "invalid syntax:{s}"),
|
||||
OptionParserError::Conversion(field, value) => {
|
||||
write!(f, "unable to convert {} for {}", value, field)
|
||||
write!(f, "unable to convert {value} for {field}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,23 +10,20 @@ kvm = ["vfio-ioctls/kvm"]
|
||||
mshv = ["vfio-ioctls/mshv"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.65"
|
||||
anyhow = "1.0.66"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main", features = ["fam-wrappers"] }
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||
vfio_user = { path = "../vfio_user" }
|
||||
vmm-sys-util = "0.10.0"
|
||||
libc = "0.2.133"
|
||||
vmm-sys-util = "0.11.0"
|
||||
libc = "0.2.138"
|
||||
log = "0.4.17"
|
||||
serde = { version = "1.0.145", features = ["derive"] }
|
||||
serde = { version = "1.0.150", features = ["derive"] }
|
||||
thiserror = "1.0.37"
|
||||
versionize = "0.1.6"
|
||||
versionize = "0.1.9"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = "0.9.0"
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
|
||||
[dependencies.vfio-bindings]
|
||||
version = "0.3.1"
|
||||
features = ["fam-wrappers"]
|
||||
vm-memory = "0.10.0"
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
@@ -514,9 +514,9 @@ impl Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::Error::*;
|
||||
match self {
|
||||
BarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s),
|
||||
BarInUse(b) => write!(f, "bar {} already used", b),
|
||||
BarInUse64(b) => write!(f, "64bit bar {} already used(requires two regs)", b),
|
||||
BarAddressInvalid(a, s) => write!(f, "address {a} size {s} too big"),
|
||||
BarInUse(b) => write!(f, "bar {b} already used"),
|
||||
BarInUse64(b) => write!(f, "64bit bar {b} already used(requires two regs)"),
|
||||
BarInvalid(b) => write!(f, "bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
|
||||
BarInvalid64(b) => write!(
|
||||
f,
|
||||
@@ -524,18 +524,18 @@ impl Display for Error {
|
||||
b,
|
||||
NUM_BAR_REGS - 1
|
||||
),
|
||||
BarSizeInvalid(s) => write!(f, "bar address {} not a power of two", s),
|
||||
BarSizeInvalid(s) => write!(f, "bar address {s} not a power of two"),
|
||||
CapabilityEmpty => write!(f, "empty capabilities are invalid"),
|
||||
CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {}", l),
|
||||
CapabilitySpaceFull(s) => write!(f, "capability of size {} doesn't fit", s),
|
||||
CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {l}"),
|
||||
CapabilitySpaceFull(s) => write!(f, "capability of size {s} doesn't fit"),
|
||||
Decode32BarSize => write!(f, "failed to decode 32 bits BAR size"),
|
||||
Decode64BarSize => write!(f, "failed to decode 64 bits BAR size"),
|
||||
Encode32BarSize => write!(f, "failed to encode 32 bits BAR size"),
|
||||
Encode64BarSize => write!(f, "failed to encode 64 bits BAR size"),
|
||||
RomBarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s),
|
||||
RomBarInUse(b) => write!(f, "rom bar {} already used", b),
|
||||
RomBarAddressInvalid(a, s) => write!(f, "address {a} size {s} too big"),
|
||||
RomBarInUse(b) => write!(f, "rom bar {b} already used"),
|
||||
RomBarInvalid(b) => write!(f, "rom bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
|
||||
RomBarSizeInvalid(s) => write!(f, "rom bar address {} not a power of two", s),
|
||||
RomBarSizeInvalid(s) => write!(f, "rom bar address {s} not a power of two"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ pub enum Error {
|
||||
IoRegistrationFailed(u64, configuration::Error),
|
||||
/// Expected resource not found.
|
||||
MissingResource,
|
||||
/// Invalid resource.
|
||||
InvalidResource(Resource),
|
||||
}
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
@@ -29,14 +31,15 @@ impl Display for Error {
|
||||
use self::Error::*;
|
||||
|
||||
match self {
|
||||
CapabilitiesSetup(e) => write!(f, "failed to add capability {}", e),
|
||||
CapabilitiesSetup(e) => write!(f, "failed to add capability {e}"),
|
||||
IoAllocationFailed(size) => {
|
||||
write!(f, "failed to allocate space for an IO BAR, size={}", size)
|
||||
write!(f, "failed to allocate space for an IO BAR, size={size}")
|
||||
}
|
||||
IoRegistrationFailed(addr, e) => {
|
||||
write!(f, "failed to register an IO BAR, addr={} err={}", addr, e)
|
||||
write!(f, "failed to register an IO BAR, addr={addr} err={e}")
|
||||
}
|
||||
MissingResource => write!(f, "failed to find expected resource"),
|
||||
InvalidResource(r) => write!(f, "invalid resource {r:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ enum Error {
|
||||
UpdateInterruptRoute(io::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Versionize)]
|
||||
#[derive(Debug, Clone, Versionize, Eq, PartialEq)]
|
||||
pub struct MsixTableEntry {
|
||||
pub msg_addr_lo: u32,
|
||||
pub msg_addr_hi: u32,
|
||||
@@ -258,7 +258,7 @@ impl MsixConfig {
|
||||
let modulo_offset = offset % MSIX_TABLE_ENTRIES_MODULO;
|
||||
|
||||
// Store the value of the entry before modification
|
||||
let mut old_entry: Option<MsixTableEntry> = None;
|
||||
let old_entry = self.table_entries[index].clone();
|
||||
|
||||
match data.len() {
|
||||
4 => {
|
||||
@@ -268,7 +268,6 @@ impl MsixConfig {
|
||||
0x4 => self.table_entries[index].msg_addr_hi = value,
|
||||
0x8 => self.table_entries[index].msg_data = value,
|
||||
0xc => {
|
||||
old_entry = Some(self.table_entries[index].clone());
|
||||
self.table_entries[index].vector_ctl = value;
|
||||
}
|
||||
_ => error!("invalid offset"),
|
||||
@@ -284,7 +283,6 @@ impl MsixConfig {
|
||||
self.table_entries[index].msg_addr_hi = (value >> 32) as u32;
|
||||
}
|
||||
0x8 => {
|
||||
old_entry = Some(self.table_entries[index].clone());
|
||||
self.table_entries[index].msg_data = (value & 0xffff_ffffu64) as u32;
|
||||
self.table_entries[index].vector_ctl = (value >> 32) as u32;
|
||||
}
|
||||
@@ -296,10 +294,18 @@ impl MsixConfig {
|
||||
_ => error!("invalid data length"),
|
||||
};
|
||||
|
||||
// Update interrupt routes
|
||||
if self.enabled && !self.masked {
|
||||
let table_entry = &self.table_entries[index];
|
||||
let table_entry = &self.table_entries[index];
|
||||
|
||||
// Optimisation to avoid excessive updates
|
||||
if &old_entry == table_entry {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update interrupt routes
|
||||
// Optimisation: only update routes if the entry is not masked;
|
||||
// this is safe because if the entry is masked (starts masked as per spec)
|
||||
// in the table then it won't be triggered. (See: #4273)
|
||||
if self.enabled && !self.masked && !table_entry.masked() {
|
||||
let config = MsiIrqSourceConfig {
|
||||
high_addr: table_entry.msg_addr_hi,
|
||||
low_addr: table_entry.msg_addr_lo,
|
||||
@@ -323,15 +329,15 @@ impl MsixConfig {
|
||||
// has been injected, the pending bit in the PBA needs to be cleared.
|
||||
// All of this is valid only if MSI-X has not been masked for the whole
|
||||
// device.
|
||||
if let Some(old_entry) = old_entry {
|
||||
// Check if bit has been flipped
|
||||
if !self.masked()
|
||||
&& old_entry.masked()
|
||||
&& !self.table_entries[index].masked()
|
||||
&& self.get_pba_bit(index as u16) == 1
|
||||
{
|
||||
self.inject_msix_and_clear_pba(index);
|
||||
}
|
||||
|
||||
// Check if bit has been flipped
|
||||
if !self.masked()
|
||||
&& self.enabled()
|
||||
&& old_entry.masked()
|
||||
&& !table_entry.masked()
|
||||
&& self.get_pba_bit(index as u16) == 1
|
||||
{
|
||||
self.inject_msix_and_clear_pba(index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ use crate::{
|
||||
use anyhow::anyhow;
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use hypervisor::HypervisorVmError;
|
||||
use libc::{sysconf, _SC_PAGESIZE};
|
||||
use std::any::Any;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::io;
|
||||
@@ -413,7 +414,7 @@ impl VfioCommon {
|
||||
resources: Option<Vec<Resource>>,
|
||||
) -> Result<Vec<PciBarConfiguration>, PciDeviceError> {
|
||||
let mut bars = Vec::new();
|
||||
let mut bar_id = VFIO_PCI_BAR0_REGION_INDEX as u32;
|
||||
let mut bar_id = VFIO_PCI_BAR0_REGION_INDEX;
|
||||
|
||||
// Going through all regular regions to compute the BAR size.
|
||||
// We're not saving the BAR address to restore it, because we
|
||||
@@ -526,7 +527,7 @@ impl VfioCommon {
|
||||
}
|
||||
|
||||
// Invert and add 1 to to find size
|
||||
region_size = (!combined_size + 1) as u64;
|
||||
region_size = !combined_size + 1;
|
||||
} else {
|
||||
region_type = PciBarRegionType::Memory32BitRegion;
|
||||
|
||||
@@ -571,7 +572,12 @@ impl VfioCommon {
|
||||
PciBarRegionType::Memory64BitRegion => {
|
||||
// BAR allocation must be naturally aligned
|
||||
mmio_allocator
|
||||
.allocate(restored_bar_addr, region_size, Some(region_size))
|
||||
.allocate(
|
||||
restored_bar_addr,
|
||||
region_size,
|
||||
// SAFETY: FFI call. Trivially safe.
|
||||
Some(unsafe { sysconf(_SC_PAGESIZE) as GuestUsize }),
|
||||
)
|
||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
|
||||
}
|
||||
};
|
||||
@@ -599,7 +605,7 @@ impl VfioCommon {
|
||||
start: bar_addr,
|
||||
length: region_size,
|
||||
type_: region_type,
|
||||
index: bar_id as u32,
|
||||
index: bar_id,
|
||||
user_memory_regions: Vec::new(),
|
||||
});
|
||||
|
||||
@@ -1278,8 +1284,10 @@ impl VfioPciDevice {
|
||||
self.iommu_attached
|
||||
}
|
||||
|
||||
fn align_4k(address: u64) -> u64 {
|
||||
(address + 0xfff) & 0xffff_ffff_ffff_f000
|
||||
fn align_page_size(address: u64) -> u64 {
|
||||
// SAFETY: FFI call. Trivially safe.
|
||||
let page_size = unsafe { sysconf(_SC_PAGESIZE) as u64 };
|
||||
(address + page_size - 1) & !(page_size - 1)
|
||||
}
|
||||
|
||||
fn is_4k_aligned(address: u64) -> bool {
|
||||
@@ -1339,6 +1347,7 @@ impl VfioPciDevice {
|
||||
let mut sparse_areas = Vec::new();
|
||||
let mut current_offset = 0;
|
||||
for (range_offset, range_size) in inter_ranges {
|
||||
let range_offset = Self::align_page_size(range_offset);
|
||||
if range_offset > current_offset {
|
||||
sparse_areas.push(VfioRegionSparseMmapArea {
|
||||
offset: current_offset,
|
||||
@@ -1346,13 +1355,13 @@ impl VfioPciDevice {
|
||||
});
|
||||
}
|
||||
|
||||
current_offset = Self::align_4k(range_offset + range_size);
|
||||
current_offset = Self::align_page_size(range_offset + range_size);
|
||||
}
|
||||
|
||||
if region_size > current_offset {
|
||||
sparse_areas.push(VfioRegionSparseMmapArea {
|
||||
offset: current_offset,
|
||||
size: region_size - current_offset,
|
||||
offset: Self::align_page_size(current_offset),
|
||||
size: Self::align_page_size(region_size - current_offset),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -276,12 +276,7 @@ impl VfioUserPciDevice {
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.dma_map(
|
||||
offset,
|
||||
region.start_addr().raw_value(),
|
||||
region.len() as u64,
|
||||
fd,
|
||||
)
|
||||
.dma_map(offset, region.start_addr().raw_value(), region.len(), fd)
|
||||
.map_err(VfioUserPciDeviceError::DmaMap)
|
||||
}
|
||||
|
||||
@@ -292,7 +287,7 @@ impl VfioUserPciDevice {
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.dma_unmap(region.start_addr().raw_value(), region.len() as u64)
|
||||
.dma_unmap(region.start_addr().raw_value(), region.len())
|
||||
.map_err(VfioUserPciDeviceError::DmaUnmap)
|
||||
}
|
||||
}
|
||||
@@ -622,13 +617,13 @@ impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioUserDmaMappi
|
||||
.map_err(|e| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("Error mapping region: {}", e),
|
||||
format!("Error mapping region: {e}"),
|
||||
)
|
||||
})
|
||||
} else {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("Region not found for 0x{:x}", gpa),
|
||||
format!("Region not found for 0x{gpa:x}"),
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -641,7 +636,7 @@ impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioUserDmaMappi
|
||||
.map_err(|e| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("Error unmapping region: {}", e),
|
||||
format!("Error unmapping region: {e}"),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ edition = "2021"
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "3.2.22", features = ["wrap_help","cargo"] }
|
||||
clap = { version = "4.0.29", features = ["wrap_help","cargo"] }
|
||||
dirs = "4.0.0"
|
||||
serde = { version = "1.0.145", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.85"
|
||||
serde = { version = "1.0.150", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.89"
|
||||
test_infra = { path = "../test_infra" }
|
||||
thiserror = "1.0.37"
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
[build-dependencies]
|
||||
clap = { version = "3.2.22", features = ["cargo"] }
|
||||
clap = { version = "4.0.29", features = ["cargo"] }
|
||||
|
||||
@@ -22,5 +22,5 @@ fn main() {
|
||||
// variable GIT_HUMAN_READABLE, so that it can be reused from the binary.
|
||||
// Particularly, this is used from the main.rs to display the exact
|
||||
// version information.
|
||||
println!("cargo:rustc-env=GIT_HUMAN_READABLE={}", git_human_readable);
|
||||
println!("cargo:rustc-env=GIT_HUMAN_READABLE={git_human_readable}");
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ extern crate clap;
|
||||
|
||||
mod performance_tests;
|
||||
|
||||
use clap::{Arg, Command as ClapCommand};
|
||||
use clap::{Arg, ArgAction, Command as ClapCommand};
|
||||
use performance_tests::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
@@ -117,7 +117,7 @@ pub struct PerformanceTestOverrides {
|
||||
impl fmt::Display for PerformanceTestOverrides {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(test_iterations) = self.test_iterations {
|
||||
write!(f, "test_iterations = {}", test_iterations)?;
|
||||
write!(f, "test_iterations = {test_iterations}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -141,19 +141,19 @@ impl fmt::Display for PerformanceTestControl {
|
||||
self.test_timeout, self.test_iterations
|
||||
);
|
||||
if let Some(o) = self.num_queues {
|
||||
output = format!("{}, num_queues = {}", output, o);
|
||||
output = format!("{output}, num_queues = {o}");
|
||||
}
|
||||
if let Some(o) = self.queue_size {
|
||||
output = format!("{}, queue_size = {}", output, o);
|
||||
output = format!("{output}, queue_size = {o}");
|
||||
}
|
||||
if let Some(o) = self.net_rx {
|
||||
output = format!("{}, net_rx = {}", output, o);
|
||||
output = format!("{output}, net_rx = {o}");
|
||||
}
|
||||
if let Some(o) = &self.fio_ops {
|
||||
output = format!("{}, fio_ops = {}", output, o);
|
||||
output = format!("{output}, fio_ops = {o}");
|
||||
}
|
||||
|
||||
write!(f, "{}", output)
|
||||
write!(f, "{output}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,29 +503,28 @@ fn main() {
|
||||
Arg::new("test-filter")
|
||||
.long("test-filter")
|
||||
.help("Filter metrics tests to run based on provided keywords")
|
||||
.multiple_occurrences(true)
|
||||
.takes_value(true)
|
||||
.num_args(1)
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("list-tests")
|
||||
.long("list-tests")
|
||||
.help("Print the list of availale metrics tests")
|
||||
.multiple_occurrences(true)
|
||||
.takes_value(false)
|
||||
.num_args(0)
|
||||
.action(ArgAction::SetTrue)
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("report-file")
|
||||
.long("report-file")
|
||||
.help("Report file. Standard error is used if not specified")
|
||||
.takes_value(true),
|
||||
.num_args(1),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("iterations")
|
||||
.long("iterations")
|
||||
.help("Override number of test iterations")
|
||||
.takes_value(true),
|
||||
.num_args(1),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
@@ -537,7 +536,7 @@ fn main() {
|
||||
.filter(|t| !(cfg!(target_arch = "aarch64") && t.name == "virtio_net_latency_us"))
|
||||
.collect();
|
||||
|
||||
if cmd_arguments.is_present("list-tests") {
|
||||
if cmd_arguments.get_flag("list-tests") {
|
||||
for test in test_list.iter() {
|
||||
println!("\"{}\" ({})", test.name, test.control);
|
||||
}
|
||||
@@ -545,7 +544,7 @@ fn main() {
|
||||
return;
|
||||
}
|
||||
|
||||
let test_filter = match cmd_arguments.values_of("test-filter") {
|
||||
let test_filter = match cmd_arguments.get_many::<String>("test-filter") {
|
||||
Some(s) => s.collect(),
|
||||
None => Vec::new(),
|
||||
};
|
||||
@@ -557,7 +556,7 @@ fn main() {
|
||||
|
||||
let overrides = Arc::new(PerformanceTestOverrides {
|
||||
test_iterations: cmd_arguments
|
||||
.value_of("iterations")
|
||||
.get_one::<String>("iterations")
|
||||
.map(|s| s.parse())
|
||||
.transpose()
|
||||
.unwrap_or_default(),
|
||||
@@ -570,7 +569,7 @@ fn main() {
|
||||
metrics_report.results.push(r);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Aborting test due to error: '{:?}'", e);
|
||||
eprintln!("Aborting test due to error: '{e:?}'");
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
@@ -580,11 +579,11 @@ fn main() {
|
||||
cleanup_tests();
|
||||
|
||||
let mut report_file: Box<dyn std::io::Write + Send> =
|
||||
if let Some(file) = cmd_arguments.value_of("report-file") {
|
||||
if let Some(file) = cmd_arguments.get_one::<String>("report-file") {
|
||||
Box::new(
|
||||
std::fs::File::create(std::path::Path::new(file))
|
||||
.map_err(|e| {
|
||||
eprintln!("Error opening report file: {}: {}", file, e);
|
||||
eprintln!("Error opening report file: {file}: {e}");
|
||||
std::process::exit(1);
|
||||
})
|
||||
.unwrap(),
|
||||
@@ -600,7 +599,7 @@ fn main() {
|
||||
.as_bytes(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
eprintln!("Error writing report file: {}", e);
|
||||
eprintln!("Error writing report file: {e}");
|
||||
std::process::exit(1);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -37,8 +37,7 @@ pub fn init_tests() {
|
||||
// The test image can not be created on tmpfs (e.g. /tmp) filesystem,
|
||||
// as tmpfs does not support O_DIRECT
|
||||
assert!(exec_host_command_output(&format!(
|
||||
"dd if=/dev/zero of={} bs=1M count=4096",
|
||||
BLK_IO_TEST_IMG
|
||||
"dd if=/dev/zero of={BLK_IO_TEST_IMG} bs=1M count=4096"
|
||||
))
|
||||
.status
|
||||
.success());
|
||||
@@ -46,7 +45,7 @@ pub fn init_tests() {
|
||||
|
||||
pub fn cleanup_tests() {
|
||||
fs::remove_file(BLK_IO_TEST_IMG)
|
||||
.unwrap_or_else(|_| panic!("Failed to remove file '{}'.", BLK_IO_TEST_IMG));
|
||||
.unwrap_or_else(|_| panic!("Failed to remove file '{BLK_IO_TEST_IMG}'."));
|
||||
}
|
||||
|
||||
// Performance tests are expected to be executed sequentially, so we can
|
||||
@@ -92,7 +91,7 @@ pub fn performance_net_throughput(control: &PerformanceTestControl) -> f64 {
|
||||
);
|
||||
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(["--cpus", &format!("boot={}", num_queues)])
|
||||
.args(["--cpus", &format!("boot={num_queues}")])
|
||||
.args(["--memory", "size=4G"])
|
||||
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
||||
@@ -133,7 +132,7 @@ pub fn performance_net_latency(control: &PerformanceTestControl) -> f64 {
|
||||
);
|
||||
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(["--cpus", &format!("boot={}", num_queues)])
|
||||
.args(["--cpus", &format!("boot={num_queues}")])
|
||||
.args(["--memory", "size=4G"])
|
||||
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
||||
@@ -169,7 +168,6 @@ fn parse_boot_time_output(output: &[u8]) -> Result<f64, Error> {
|
||||
std::panic::catch_unwind(|| {
|
||||
let l: Vec<String> = String::from_utf8_lossy(output)
|
||||
.lines()
|
||||
.into_iter()
|
||||
.filter(|l| l.contains("Debug I/O port: Kernel code"))
|
||||
.map(|l| l.to_string())
|
||||
.collect();
|
||||
@@ -349,7 +347,7 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
|
||||
.to_string();
|
||||
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(["--cpus", &format!("boot={}", num_queues)])
|
||||
.args(["--cpus", &format!("boot={num_queues}")])
|
||||
.args(["--memory", "size=4G"])
|
||||
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
||||
@@ -365,7 +363,7 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
|
||||
guest.disk_config.disk(DiskType::CloudInit).unwrap()
|
||||
)
|
||||
.as_str(),
|
||||
format!("path={}", BLK_IO_TEST_IMG).as_str(),
|
||||
format!("path={BLK_IO_TEST_IMG}").as_str(),
|
||||
])
|
||||
.default_net()
|
||||
.args(["--api-socket", &api_socket])
|
||||
@@ -381,8 +379,7 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
|
||||
let fio_command = format!(
|
||||
"sudo fio --filename=/dev/vdc --name=test --output-format=json \
|
||||
--direct=1 --bs=4k --ioengine=io_uring --iodepth=64 \
|
||||
--rw={} --runtime={} --numjobs={}",
|
||||
fio_ops, test_timeout, num_queues
|
||||
--rw={fio_ops} --runtime={test_timeout} --numjobs={num_queues}"
|
||||
);
|
||||
let output = guest
|
||||
.ssh_command(&fio_command)
|
||||
|
||||
@@ -10,7 +10,7 @@ path = "src/qcow.rs"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.4.3"
|
||||
libc = "0.2.133"
|
||||
libc = "0.2.138"
|
||||
log = "0.4.17"
|
||||
remain = "0.2.4"
|
||||
vmm-sys-util = "0.10.0"
|
||||
remain = "0.2.5"
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
156
qcow/src/qcow.rs
156
qcow/src/qcow.rs
@@ -80,45 +80,41 @@ impl Display for Error {
|
||||
match self {
|
||||
BackingFilesNotSupported => write!(f, "backing files not supported"),
|
||||
CompressedBlocksNotSupported => write!(f, "compressed blocks not supported"),
|
||||
EvictingCache(e) => write!(f, "failed to evict cache: {}", e),
|
||||
FileTooBig(size) => write!(
|
||||
f,
|
||||
"file larger than max of {}: {}",
|
||||
MAX_QCOW_FILE_SIZE, size
|
||||
),
|
||||
GettingFileSize(e) => write!(f, "failed to get file size: {}", e),
|
||||
GettingRefcount(e) => write!(f, "failed to get refcount: {}", e),
|
||||
EvictingCache(e) => write!(f, "failed to evict cache: {e}"),
|
||||
FileTooBig(size) => write!(f, "file larger than max of {MAX_QCOW_FILE_SIZE}: {size}"),
|
||||
GettingFileSize(e) => write!(f, "failed to get file size: {e}"),
|
||||
GettingRefcount(e) => write!(f, "failed to get refcount: {e}"),
|
||||
InvalidClusterIndex => write!(f, "invalid cluster index"),
|
||||
InvalidClusterSize => write!(f, "invalid cluster size"),
|
||||
InvalidIndex => write!(f, "invalid index"),
|
||||
InvalidL1TableOffset => write!(f, "invalid L1 table offset"),
|
||||
InvalidL1TableSize(size) => write!(f, "invalid L1 table size {}", size),
|
||||
InvalidL1TableSize(size) => write!(f, "invalid L1 table size {size}"),
|
||||
InvalidMagic => write!(f, "invalid magic"),
|
||||
InvalidOffset(_) => write!(f, "invalid offset"),
|
||||
InvalidRefcountTableOffset => write!(f, "invalid refcount table offset"),
|
||||
InvalidRefcountTableSize(size) => write!(f, "invalid refcount table size: {}", size),
|
||||
InvalidRefcountTableSize(size) => write!(f, "invalid refcount table size: {size}"),
|
||||
NoFreeClusters => write!(f, "no free clusters"),
|
||||
NoRefcountClusters => write!(f, "no refcount clusters"),
|
||||
NotEnoughSpaceForRefcounts => write!(f, "not enough space for refcounts"),
|
||||
OpeningFile(e) => write!(f, "failed to open file: {}", e),
|
||||
ReadingData(e) => write!(f, "failed to read data: {}", e),
|
||||
ReadingHeader(e) => write!(f, "failed to read header: {}", e),
|
||||
ReadingPointers(e) => write!(f, "failed to read pointers: {}", e),
|
||||
ReadingRefCountBlock(e) => write!(f, "failed to read ref count block: {}", e),
|
||||
ReadingRefCounts(e) => write!(f, "failed to read ref counts: {}", e),
|
||||
RebuildingRefCounts(e) => write!(f, "failed to rebuild ref counts: {}", e),
|
||||
OpeningFile(e) => write!(f, "failed to open file: {e}"),
|
||||
ReadingData(e) => write!(f, "failed to read data: {e}"),
|
||||
ReadingHeader(e) => write!(f, "failed to read header: {e}"),
|
||||
ReadingPointers(e) => write!(f, "failed to read pointers: {e}"),
|
||||
ReadingRefCountBlock(e) => write!(f, "failed to read ref count block: {e}"),
|
||||
ReadingRefCounts(e) => write!(f, "failed to read ref counts: {e}"),
|
||||
RebuildingRefCounts(e) => write!(f, "failed to rebuild ref counts: {e}"),
|
||||
RefcountTableOffEnd => write!(f, "refcount table offset past file end"),
|
||||
RefcountTableTooLarge => write!(f, "too many clusters specified for refcount table"),
|
||||
SeekingFile(e) => write!(f, "failed to seek file: {}", e),
|
||||
SettingFileSize(e) => write!(f, "failed to set file size: {}", e),
|
||||
SettingRefcountRefcount(e) => write!(f, "failed to set refcount refcount: {}", e),
|
||||
SeekingFile(e) => write!(f, "failed to seek file: {e}"),
|
||||
SettingFileSize(e) => write!(f, "failed to set file size: {e}"),
|
||||
SettingRefcountRefcount(e) => write!(f, "failed to set refcount refcount: {e}"),
|
||||
SizeTooSmallForNumberOfClusters => write!(f, "size too small for number of clusters"),
|
||||
TooManyL1Entries(count) => write!(f, "l1 entry table too large: {}", count),
|
||||
TooManyRefcounts(count) => write!(f, "ref count table too large: {}", count),
|
||||
TooManyL1Entries(count) => write!(f, "l1 entry table too large: {count}"),
|
||||
TooManyRefcounts(count) => write!(f, "ref count table too large: {count}"),
|
||||
UnsupportedRefcountOrder => write!(f, "unsupported refcount order"),
|
||||
UnsupportedVersion(v) => write!(f, "unsupported version: {}", v),
|
||||
WritingData(e) => write!(f, "failed to write data: {}", e),
|
||||
WritingHeader(e) => write!(f, "failed to write header: {}", e),
|
||||
UnsupportedVersion(v) => write!(f, "unsupported version: {v}"),
|
||||
WritingData(e) => write!(f, "failed to write data: {e}"),
|
||||
WritingHeader(e) => write!(f, "failed to write header: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,7 +186,7 @@ pub struct QcowHeader {
|
||||
impl QcowHeader {
|
||||
/// Creates a QcowHeader from a reference to a file.
|
||||
pub fn new(f: &mut RawFile) -> Result<QcowHeader> {
|
||||
f.seek(SeekFrom::Start(0)).map_err(Error::ReadingHeader)?;
|
||||
f.rewind().map_err(Error::ReadingHeader)?;
|
||||
let magic = f.read_u32::<BigEndian>().map_err(Error::ReadingHeader)?;
|
||||
if magic != QCOW_MAGIC {
|
||||
return Err(Error::InvalidMagic);
|
||||
@@ -255,10 +251,10 @@ impl QcowHeader {
|
||||
let cluster_bits: u32 = DEFAULT_CLUSTER_BITS;
|
||||
let cluster_size: u32 = 0x01 << cluster_bits;
|
||||
// L2 blocks are always one cluster long. They contain cluster_size/sizeof(u64) addresses.
|
||||
let l2_size: u32 = cluster_size / size_of::<u64>() as u32;
|
||||
let entries_per_cluster: u32 = cluster_size / size_of::<u64>() as u32;
|
||||
let num_clusters: u32 = div_round_up_u64(size, u64::from(cluster_size)) as u32;
|
||||
let num_l2_clusters: u32 = div_round_up_u32(num_clusters, l2_size);
|
||||
let l1_clusters: u32 = div_round_up_u32(num_l2_clusters, cluster_size);
|
||||
let num_l2_clusters: u32 = div_round_up_u32(num_clusters, entries_per_cluster);
|
||||
let l1_clusters: u32 = div_round_up_u32(num_l2_clusters, entries_per_cluster);
|
||||
let header_clusters = div_round_up_u32(size_of::<QcowHeader>() as u32, cluster_size);
|
||||
QcowHeader {
|
||||
magic: QCOW_MAGIC,
|
||||
@@ -473,10 +469,10 @@ impl QcowFile {
|
||||
QcowFile::rebuild_refcounts(&mut raw_file, header)?;
|
||||
}
|
||||
|
||||
let l2_size = cluster_size / size_of::<u64>() as u64;
|
||||
let entries_per_cluster = cluster_size / size_of::<u64>() as u64;
|
||||
let num_clusters = div_round_up_u64(header.size, cluster_size);
|
||||
let num_l2_clusters = div_round_up_u64(num_clusters, l2_size);
|
||||
let l1_clusters = div_round_up_u64(num_l2_clusters, cluster_size);
|
||||
let num_l2_clusters = div_round_up_u64(num_clusters, entries_per_cluster);
|
||||
let l1_clusters = div_round_up_u64(num_l2_clusters, entries_per_cluster);
|
||||
let header_clusters = div_round_up_u64(size_of::<QcowHeader>() as u64, cluster_size);
|
||||
if num_l2_clusters > MAX_RAM_POINTER_TABLE_SIZE {
|
||||
return Err(Error::TooManyL1Entries(num_l2_clusters));
|
||||
@@ -559,14 +555,14 @@ impl QcowFile {
|
||||
/// Creates a new QcowFile at the given path.
|
||||
pub fn new(mut file: RawFile, version: u32, virtual_size: u64) -> Result<QcowFile> {
|
||||
let header = QcowHeader::create_for_size(version, virtual_size);
|
||||
file.seek(SeekFrom::Start(0)).map_err(Error::SeekingFile)?;
|
||||
file.rewind().map_err(Error::SeekingFile)?;
|
||||
header.write_to(&mut file)?;
|
||||
|
||||
let mut qcow = Self::from(file)?;
|
||||
|
||||
// Set the refcount for each refcount table cluster.
|
||||
let cluster_size = 0x01u64 << qcow.header.cluster_bits;
|
||||
let refcount_table_base = qcow.header.refcount_table_offset as u64;
|
||||
let refcount_table_base = qcow.header.refcount_table_offset;
|
||||
let end_cluster_addr =
|
||||
refcount_table_base + u64::from(qcow.header.refcount_table_clusters) * cluster_size;
|
||||
|
||||
@@ -705,7 +701,8 @@ impl QcowFile {
|
||||
header: QcowHeader,
|
||||
cluster_size: u64,
|
||||
) -> Result<()> {
|
||||
let l1_clusters = div_round_up_u64(u64::from(header.l1_size), cluster_size);
|
||||
let entries_per_cluster = cluster_size / size_of::<u64>() as u64;
|
||||
let l1_clusters = div_round_up_u64(u64::from(header.l1_size), entries_per_cluster);
|
||||
let l1_table_offset = header.l1_table_offset;
|
||||
for i in 0..l1_clusters {
|
||||
add_ref(refcounts, cluster_size, l1_table_offset + i * cluster_size)?;
|
||||
@@ -776,10 +773,8 @@ impl QcowFile {
|
||||
refcounts: &mut [u16],
|
||||
cluster_size: u64,
|
||||
refblock_clusters: u64,
|
||||
pointers_per_cluster: u64,
|
||||
) -> Result<Vec<u64>> {
|
||||
let refcount_table_entries = div_round_up_u64(refblock_clusters, pointers_per_cluster);
|
||||
let mut ref_table = vec![0; refcount_table_entries as usize];
|
||||
let mut ref_table = vec![0; refblock_clusters as usize];
|
||||
let mut first_free_cluster: u64 = 0;
|
||||
for refblock_addr in &mut ref_table {
|
||||
loop {
|
||||
@@ -811,10 +806,7 @@ impl QcowFile {
|
||||
) -> Result<()> {
|
||||
// Rewrite the header with lazy refcounts enabled while we are rebuilding the tables.
|
||||
header.compatible_features |= COMPATIBLE_FEATURES_LAZY_REFCOUNTS;
|
||||
raw_file
|
||||
.file_mut()
|
||||
.seek(SeekFrom::Start(0))
|
||||
.map_err(Error::SeekingFile)?;
|
||||
raw_file.file_mut().rewind().map_err(Error::SeekingFile)?;
|
||||
header.write_to(raw_file.file_mut())?;
|
||||
|
||||
for (i, refblock_addr) in ref_table.iter().enumerate() {
|
||||
@@ -849,10 +841,7 @@ impl QcowFile {
|
||||
|
||||
// Rewrite the header again, now with lazy refcounts disabled.
|
||||
header.compatible_features &= !COMPATIBLE_FEATURES_LAZY_REFCOUNTS;
|
||||
raw_file
|
||||
.file_mut()
|
||||
.seek(SeekFrom::Start(0))
|
||||
.map_err(Error::SeekingFile)?;
|
||||
raw_file.file_mut().rewind().map_err(Error::SeekingFile)?;
|
||||
header.write_to(raw_file.file_mut())?;
|
||||
|
||||
Ok(())
|
||||
@@ -872,7 +861,7 @@ impl QcowFile {
|
||||
let pointers_per_cluster = cluster_size / size_of::<u64>() as u64;
|
||||
let data_clusters = div_round_up_u64(header.size, cluster_size);
|
||||
let l2_clusters = div_round_up_u64(data_clusters, pointers_per_cluster);
|
||||
let l1_clusters = div_round_up_u64(l2_clusters, cluster_size);
|
||||
let l1_clusters = div_round_up_u64(l2_clusters, pointers_per_cluster);
|
||||
let header_clusters = div_round_up_u64(size_of::<QcowHeader>() as u64, cluster_size);
|
||||
let max_clusters = data_clusters + l2_clusters + l1_clusters + header_clusters;
|
||||
let mut max_valid_cluster_index = max_clusters;
|
||||
@@ -906,12 +895,7 @@ impl QcowFile {
|
||||
set_refcount_table_refcounts(&mut refcounts, header, cluster_size)?;
|
||||
|
||||
// Allocate clusters to store the new reference count blocks.
|
||||
let ref_table = alloc_refblocks(
|
||||
&mut refcounts,
|
||||
cluster_size,
|
||||
refblock_clusters,
|
||||
pointers_per_cluster,
|
||||
)?;
|
||||
let ref_table = alloc_refblocks(&mut refcounts, cluster_size, refblock_clusters)?;
|
||||
|
||||
// Write updated reference counts and point the reftable at them.
|
||||
write_refblocks(
|
||||
@@ -962,7 +946,7 @@ impl QcowFile {
|
||||
// Gets the offset of the given guest address in the host file. If L1, L2, or data clusters have
|
||||
// yet to be allocated, return None.
|
||||
fn file_offset_read(&mut self, address: u64) -> std::io::Result<Option<u64>> {
|
||||
if address >= self.virtual_size() as u64 {
|
||||
if address >= self.virtual_size() {
|
||||
return Err(std::io::Error::from_raw_os_error(EINVAL));
|
||||
}
|
||||
|
||||
@@ -1005,7 +989,7 @@ impl QcowFile {
|
||||
// Gets the offset of the given guest address in the host file. If L1, L2, or data clusters need
|
||||
// to be allocated, they will be.
|
||||
fn file_offset_write(&mut self, address: u64) -> std::io::Result<u64> {
|
||||
if address >= self.virtual_size() as u64 {
|
||||
if address >= self.virtual_size() {
|
||||
return Err(std::io::Error::from_raw_os_error(EINVAL));
|
||||
}
|
||||
|
||||
@@ -1122,7 +1106,7 @@ impl QcowFile {
|
||||
|
||||
// Returns true if the cluster containing `address` is already allocated.
|
||||
fn cluster_allocated(&mut self, address: u64) -> std::io::Result<bool> {
|
||||
if address >= self.virtual_size() as u64 {
|
||||
if address >= self.virtual_size() {
|
||||
return Err(std::io::Error::from_raw_os_error(EINVAL));
|
||||
}
|
||||
|
||||
@@ -1194,7 +1178,7 @@ impl QcowFile {
|
||||
// Deallocate the storage for the cluster starting at `address`.
|
||||
// Any future reads of this cluster will return all zeroes.
|
||||
fn deallocate_cluster(&mut self, address: u64) -> std::io::Result<()> {
|
||||
if address >= self.virtual_size() as u64 {
|
||||
if address >= self.virtual_size() {
|
||||
return Err(std::io::Error::from_raw_os_error(EINVAL));
|
||||
}
|
||||
|
||||
@@ -1239,7 +1223,7 @@ impl QcowFile {
|
||||
.map_err(|e| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
format!("failed to get cluster refcount: {}", e),
|
||||
format!("failed to get cluster refcount: {e}"),
|
||||
)
|
||||
})?;
|
||||
if refcount == 0 {
|
||||
@@ -1416,7 +1400,7 @@ impl Drop for QcowFile {
|
||||
|
||||
impl Read for QcowFile {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
let address: u64 = self.current_offset as u64;
|
||||
let address: u64 = self.current_offset;
|
||||
let read_count: usize = self.limit_range_file(address, buf.len());
|
||||
|
||||
let mut nread: usize = 0;
|
||||
@@ -1478,7 +1462,7 @@ impl Seek for QcowFile {
|
||||
|
||||
impl Write for QcowFile {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
let address: u64 = self.current_offset as u64;
|
||||
let address: u64 = self.current_offset;
|
||||
let write_count: usize = self.limit_range_file(address, buf.len());
|
||||
|
||||
let mut nwritten: usize = 0;
|
||||
@@ -1655,9 +1639,7 @@ where
|
||||
R: Read + Seek + SeekHole,
|
||||
{
|
||||
let src_size = reader.seek(SeekFrom::End(0)).map_err(Error::SeekingFile)?;
|
||||
reader
|
||||
.seek(SeekFrom::Start(0))
|
||||
.map_err(Error::SeekingFile)?;
|
||||
reader.rewind().map_err(Error::SeekingFile)?;
|
||||
|
||||
// Ensure the destination file is empty before writing to it.
|
||||
dst_file.set_len(0).map_err(Error::SettingFileSize)?;
|
||||
@@ -1699,10 +1681,8 @@ pub fn convert(mut src_file: RawFile, dst_file: RawFile, dst_type: ImageType) ->
|
||||
|
||||
/// Detect the type of an image file by checking for a valid qcow2 header.
|
||||
pub fn detect_image_type(file: &mut RawFile) -> Result<ImageType> {
|
||||
let orig_seek = file
|
||||
.seek(SeekFrom::Current(0))
|
||||
.map_err(Error::SeekingFile)?;
|
||||
file.seek(SeekFrom::Start(0)).map_err(Error::SeekingFile)?;
|
||||
let orig_seek = file.stream_position().map_err(Error::SeekingFile)?;
|
||||
file.rewind().map_err(Error::SeekingFile)?;
|
||||
let magic = file.read_u32::<BigEndian>().map_err(Error::ReadingHeader)?;
|
||||
let image_type = if magic == QCOW_MAGIC {
|
||||
ImageType::Qcow2
|
||||
@@ -1793,7 +1773,7 @@ mod tests {
|
||||
let mut disk_file: RawFile = RawFile::new(TempFile::new().unwrap().into_file(), false);
|
||||
disk_file.write_all(header).unwrap();
|
||||
disk_file.set_len(0x1_0000_0000).unwrap();
|
||||
disk_file.seek(SeekFrom::Start(0)).unwrap();
|
||||
disk_file.rewind().unwrap();
|
||||
|
||||
testfn(disk_file); // File closed when the function exits.
|
||||
}
|
||||
@@ -1815,7 +1795,7 @@ mod tests {
|
||||
header
|
||||
.write_to(&mut disk_file)
|
||||
.expect("Failed to write header to temporary file.");
|
||||
disk_file.seek(SeekFrom::Start(0)).unwrap();
|
||||
disk_file.rewind().unwrap();
|
||||
QcowFile::from(disk_file).expect("Failed to create Qcow from default Header");
|
||||
}
|
||||
|
||||
@@ -1826,7 +1806,7 @@ mod tests {
|
||||
header
|
||||
.write_to(&mut disk_file)
|
||||
.expect("Failed to write header to temporary file.");
|
||||
disk_file.seek(SeekFrom::Start(0)).unwrap();
|
||||
disk_file.rewind().unwrap();
|
||||
QcowFile::from(disk_file).expect("Failed to create Qcow from default Header");
|
||||
}
|
||||
|
||||
@@ -1954,7 +1934,7 @@ mod tests {
|
||||
q.write_all(b"test first bytes")
|
||||
.expect("Failed to write test string.");
|
||||
let mut buf = [0u8; 4];
|
||||
q.seek(SeekFrom::Start(0)).expect("Failed to seek.");
|
||||
q.rewind().expect("Failed to seek.");
|
||||
q.read_exact(&mut buf).expect("Failed to read.");
|
||||
assert_eq!(&buf, b"test");
|
||||
});
|
||||
@@ -2006,15 +1986,15 @@ mod tests {
|
||||
let mut q = QcowFile::from(disk_file).unwrap();
|
||||
// Write some test data.
|
||||
let b = [0x55u8; CHUNK_SIZE];
|
||||
q.seek(SeekFrom::Start(0)).expect("Failed to seek.");
|
||||
q.rewind().expect("Failed to seek.");
|
||||
q.write_all(&b).expect("Failed to write test string.");
|
||||
// Overwrite the full cluster with zeroes.
|
||||
q.seek(SeekFrom::Start(0)).expect("Failed to seek.");
|
||||
q.rewind().expect("Failed to seek.");
|
||||
let nwritten = q.write_zeroes(CHUNK_SIZE).expect("Failed to write zeroes.");
|
||||
assert_eq!(nwritten, CHUNK_SIZE);
|
||||
// Verify that the data was zeroed out.
|
||||
let mut buf = [0u8; CHUNK_SIZE];
|
||||
q.seek(SeekFrom::Start(0)).expect("Failed to seek.");
|
||||
q.rewind().expect("Failed to seek.");
|
||||
q.read_exact(&mut buf).expect("Failed to read.");
|
||||
assert_eq!(buf[0], 0);
|
||||
assert_eq!(buf[CHUNK_SIZE - 1], 0);
|
||||
@@ -2456,7 +2436,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
// Check that address 0 is still zeros.
|
||||
qcow_file.seek(SeekFrom::Start(0)).expect("Failed to seek.");
|
||||
qcow_file.rewind().expect("Failed to seek.");
|
||||
let nread = qcow_file.read(&mut readback).expect("Failed to read.");
|
||||
assert_eq!(nread, BLOCK_SIZE);
|
||||
for read in readback.iter() {
|
||||
@@ -2480,7 +2460,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn seek_cur(file: &mut QcowFile) -> u64 {
|
||||
file.seek(SeekFrom::Current(0)).unwrap()
|
||||
file.stream_position().unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2544,7 +2524,7 @@ mod tests {
|
||||
assert_eq!(seek_cur(&mut file), 0xFFFF);
|
||||
|
||||
// seek_hole at or after the end of the file should return None
|
||||
file.seek(SeekFrom::Start(0)).unwrap();
|
||||
file.rewind().unwrap();
|
||||
assert_eq!(file.seek_hole(0x30000).unwrap(), None);
|
||||
assert_eq!(seek_cur(&mut file), 0);
|
||||
assert_eq!(file.seek_hole(0x30001).unwrap(), None);
|
||||
@@ -2562,33 +2542,33 @@ mod tests {
|
||||
assert_eq!(seek_cur(&mut file), 0xFFFF);
|
||||
|
||||
// seek_hole within data should return the next hole
|
||||
file.seek(SeekFrom::Start(0)).unwrap();
|
||||
file.rewind().unwrap();
|
||||
assert_eq!(file.seek_hole(0x10000).unwrap(), Some(0x20000));
|
||||
assert_eq!(seek_cur(&mut file), 0x20000);
|
||||
file.seek(SeekFrom::Start(0)).unwrap();
|
||||
file.rewind().unwrap();
|
||||
assert_eq!(file.seek_hole(0x10001).unwrap(), Some(0x20000));
|
||||
assert_eq!(seek_cur(&mut file), 0x20000);
|
||||
file.seek(SeekFrom::Start(0)).unwrap();
|
||||
file.rewind().unwrap();
|
||||
assert_eq!(file.seek_hole(0x1FFFF).unwrap(), Some(0x20000));
|
||||
assert_eq!(seek_cur(&mut file), 0x20000);
|
||||
file.seek(SeekFrom::Start(0)).unwrap();
|
||||
file.rewind().unwrap();
|
||||
assert_eq!(file.seek_hole(0xFFFF).unwrap(), Some(0xFFFF));
|
||||
assert_eq!(seek_cur(&mut file), 0xFFFF);
|
||||
file.seek(SeekFrom::Start(0)).unwrap();
|
||||
file.rewind().unwrap();
|
||||
assert_eq!(file.seek_hole(0x10000).unwrap(), Some(0x20000));
|
||||
assert_eq!(seek_cur(&mut file), 0x20000);
|
||||
file.seek(SeekFrom::Start(0)).unwrap();
|
||||
file.rewind().unwrap();
|
||||
assert_eq!(file.seek_hole(0x1FFFF).unwrap(), Some(0x20000));
|
||||
assert_eq!(seek_cur(&mut file), 0x20000);
|
||||
file.seek(SeekFrom::Start(0)).unwrap();
|
||||
file.rewind().unwrap();
|
||||
assert_eq!(file.seek_hole(0x20000).unwrap(), Some(0x20000));
|
||||
assert_eq!(seek_cur(&mut file), 0x20000);
|
||||
file.seek(SeekFrom::Start(0)).unwrap();
|
||||
file.rewind().unwrap();
|
||||
assert_eq!(file.seek_hole(0x20001).unwrap(), Some(0x20001));
|
||||
assert_eq!(seek_cur(&mut file), 0x20001);
|
||||
|
||||
// seek_hole at EOF should return None
|
||||
file.seek(SeekFrom::Start(0)).unwrap();
|
||||
file.rewind().unwrap();
|
||||
assert_eq!(file.seek_hole(0x30000).unwrap(), None);
|
||||
assert_eq!(seek_cur(&mut file), 0);
|
||||
|
||||
@@ -2599,10 +2579,10 @@ mod tests {
|
||||
// seek_hole within [0x20000, 0x30000) should now find the hole at EOF
|
||||
assert_eq!(file.seek_hole(0x20000).unwrap(), Some(0x30000));
|
||||
assert_eq!(seek_cur(&mut file), 0x30000);
|
||||
file.seek(SeekFrom::Start(0)).unwrap();
|
||||
file.rewind().unwrap();
|
||||
assert_eq!(file.seek_hole(0x20001).unwrap(), Some(0x30000));
|
||||
assert_eq!(seek_cur(&mut file), 0x30000);
|
||||
file.seek(SeekFrom::Start(0)).unwrap();
|
||||
file.rewind().unwrap();
|
||||
assert_eq!(file.seek_hole(0x30000).unwrap(), None);
|
||||
assert_eq!(seek_cur(&mut file), 0);
|
||||
});
|
||||
|
||||
@@ -66,7 +66,7 @@ impl QcowRawFile {
|
||||
non_zero_flags: u64,
|
||||
) -> io::Result<()> {
|
||||
self.file.seek(SeekFrom::Start(offset))?;
|
||||
let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u64>(), &mut self.file);
|
||||
let mut buffer = BufWriter::with_capacity(std::mem::size_of_val(table), &mut self.file);
|
||||
for addr in table {
|
||||
let val = if *addr == 0 {
|
||||
0
|
||||
@@ -91,7 +91,7 @@ impl QcowRawFile {
|
||||
/// Writes a refcount block to the file.
|
||||
pub fn write_refcount_block(&mut self, offset: u64, table: &[u16]) -> io::Result<()> {
|
||||
self.file.seek(SeekFrom::Start(offset))?;
|
||||
let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u16>(), &mut self.file);
|
||||
let mut buffer = BufWriter::with_capacity(std::mem::size_of_val(table), &mut self.file);
|
||||
for count in table {
|
||||
buffer.write_u16::<BigEndian>(*count)?;
|
||||
}
|
||||
|
||||
@@ -31,16 +31,14 @@ impl Display for Error {
|
||||
use self::Error::*;
|
||||
|
||||
match self {
|
||||
EvictingRefCounts(e) => write!(
|
||||
f,
|
||||
"failed to write a refblock from the cache to disk: {}",
|
||||
e
|
||||
),
|
||||
EvictingRefCounts(e) => {
|
||||
write!(f, "failed to write a refblock from the cache to disk: {e}")
|
||||
}
|
||||
InvalidIndex => write!(f, "address requested is not within the range of the disk"),
|
||||
NeedCluster(addr) => write!(f, "cluster with addr={} needs to be read", addr),
|
||||
NeedCluster(addr) => write!(f, "cluster with addr={addr} needs to be read"),
|
||||
NeedNewCluster => write!(f, "new cluster needs to be allocated for refcounts"),
|
||||
ReadingRefCounts(e) => {
|
||||
write!(f, "failed to read the file into the refcount cache: {}", e)
|
||||
write!(f, "failed to read the file into the refcount cache: {e}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,6 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.133"
|
||||
libc = "0.2.138"
|
||||
log = "0.4.17"
|
||||
vmm-sys-util = "0.10.0"
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
@@ -888,7 +888,7 @@ pub(crate) mod tests {
|
||||
fn test_rate_limiter_debug() {
|
||||
let l = RateLimiter::new(1, 2, 3, 4, 5, 6).unwrap();
|
||||
assert_eq!(
|
||||
format!("{:?}", l),
|
||||
format!("{l:?}"),
|
||||
format!(
|
||||
"RateLimiter {{ bandwidth: {:?}, ops: {:?} }}",
|
||||
l.bandwidth(),
|
||||
|
||||
221
release-notes.md
221
release-notes.md
@@ -1,3 +1,16 @@
|
||||
- [v28.4](#v284)
|
||||
- [v28.3](#v283)
|
||||
- [v28.2](#v282)
|
||||
- [v28.1](#v281)
|
||||
- [v28.0](#v280)
|
||||
- [Community Engagement (Reminder)](#community-engagement-reminder)
|
||||
- [Long Term Support (LTS) Release](#long-term-support-lts-release)
|
||||
- [Virtualised TPM Support](#virtualised-tpm-support)
|
||||
- [Transparent Huge Page Support](#transparent-huge-page-support)
|
||||
- [README Quick Start Improved](#readme-quick-start-improved)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes)
|
||||
- [Removals](#removals)
|
||||
- [Contributors](#contributors)
|
||||
- [v27.0](#v270)
|
||||
- [Community Engagement](#community-engagement)
|
||||
- [Prebuilt Packages](#prebuilt-packages)
|
||||
@@ -6,41 +19,41 @@
|
||||
- [Simplified Build Feature Flags](#simplified-build-feature-flags)
|
||||
- [Asynchronous Kernel Loading](#asynchronous-kernel-loading)
|
||||
- [GDB Support for AArch64](#gdb-support-for-aarch64)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
||||
- [Deprecations](#deprecations)
|
||||
- [Contributors](#contributors)
|
||||
- [Contributors](#contributors-1)
|
||||
- [v26.0](#v260)
|
||||
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform)
|
||||
- [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
||||
- [Deprecations](#deprecations-1)
|
||||
- [Removals](#removals)
|
||||
- [Contributors](#contributors-1)
|
||||
- [Removals](#removals-1)
|
||||
- [Contributors](#contributors-2)
|
||||
- [v25.0](#v250)
|
||||
- [`ch-remote` Improvements](#ch-remote-improvements)
|
||||
- [VM "Coredump" Support](#vm-coredump-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
||||
- [Removals](#removals-1)
|
||||
- [Contributors](#contributors-2)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||
- [Removals](#removals-2)
|
||||
- [Contributors](#contributors-3)
|
||||
- [v24.0](#v240)
|
||||
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
|
||||
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
|
||||
- [Sparse Mmap support](#sparse-mmap-support)
|
||||
- [Expose Platform Serial Number](#expose-platform-serial-number)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Notable Improvements](#notable-improvements)
|
||||
- [Deprecations](#deprecations-2)
|
||||
- [New on the Website](#new-on-the-website)
|
||||
- [Contributors](#contributors-3)
|
||||
- [Contributors](#contributors-4)
|
||||
- [v23.1](#v231)
|
||||
- [v23.0](#v230)
|
||||
- [vDPA Support](#vdpa-support)
|
||||
- [Updated OS Support list](#updated-os-support-list)
|
||||
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
|
||||
- [`AMX` Support](#amx-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Deprecations](#deprecations-3)
|
||||
- [Contributors](#contributors-4)
|
||||
- [Contributors](#contributors-5)
|
||||
- [v22.1](#v221)
|
||||
- [v22.0](#v220)
|
||||
- [GDB Debug Stub Support](#gdb-debug-stub-support)
|
||||
@@ -51,13 +64,13 @@
|
||||
- [PMU Support for AArch64](#pmu-support-for-aarch64)
|
||||
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
|
||||
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Contributors](#contributors-5)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||
- [Contributors](#contributors-6)
|
||||
- [v21.0](#v210)
|
||||
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
|
||||
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
|
||||
- [Notable Bug fixes](#notable-bug-fixes-6)
|
||||
- [Contributors](#contributors-6)
|
||||
- [Notable Bug fixes](#notable-bug-fixes-7)
|
||||
- [Contributors](#contributors-7)
|
||||
- [v20.2](#v202)
|
||||
- [v20.1](#v201)
|
||||
- [v20.0](#v200)
|
||||
@@ -66,8 +79,8 @@
|
||||
- [Improved VFIO support](#improved-vfio-support)
|
||||
- [Safer code](#safer-code)
|
||||
- [Extended documentation](#extended-documentation)
|
||||
- [Notable bug fixes](#notable-bug-fixes-7)
|
||||
- [Contributors](#contributors-7)
|
||||
- [Notable bug fixes](#notable-bug-fixes-8)
|
||||
- [Contributors](#contributors-8)
|
||||
- [v19.0](#v190)
|
||||
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
|
||||
- [PCI boot time optimisations](#pci-boot-time-optimisations)
|
||||
@@ -75,8 +88,8 @@
|
||||
- [Live migration enhancements](#live-migration-enhancements)
|
||||
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
|
||||
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
|
||||
- [Notable bug fixes](#notable-bug-fixes-8)
|
||||
- [Contributors](#contributors-8)
|
||||
- [Notable bug fixes](#notable-bug-fixes-9)
|
||||
- [Contributors](#contributors-9)
|
||||
- [v18.0](#v180)
|
||||
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
|
||||
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
|
||||
@@ -86,23 +99,23 @@
|
||||
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
||||
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
||||
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
||||
- [Notable bug fixes](#notable-bug-fixes-9)
|
||||
- [Contributors](#contributors-9)
|
||||
- [Notable bug fixes](#notable-bug-fixes-10)
|
||||
- [Contributors](#contributors-10)
|
||||
- [v17.0](#v170)
|
||||
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
|
||||
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
|
||||
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
|
||||
- [Improved SGX support](#improved-sgx-support)
|
||||
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
|
||||
- [Notable bug fixes](#notable-bug-fixes-10)
|
||||
- [Contributors](#contributors-10)
|
||||
- [Notable bug fixes](#notable-bug-fixes-11)
|
||||
- [Contributors](#contributors-11)
|
||||
- [v16.0](#v160)
|
||||
- [Improved live migration support](#improved-live-migration-support)
|
||||
- [Improved `vhost-user` support](#improved-vhost-user-support)
|
||||
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
|
||||
- [Notable bug fixes](#notable-bug-fixes-11)
|
||||
- [Notable bug fixes](#notable-bug-fixes-12)
|
||||
- [Removed functionality](#removed-functionality)
|
||||
- [Contributors](#contributors-11)
|
||||
- [Contributors](#contributors-12)
|
||||
- [v15.0](#v150)
|
||||
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
||||
- [Network device rate limiting](#network-device-rate-limiting)
|
||||
@@ -110,7 +123,7 @@
|
||||
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
||||
- [Bug fixes](#bug-fixes)
|
||||
- [Deprecations](#deprecations-4)
|
||||
- [Contributors](#contributors-12)
|
||||
- [Contributors](#contributors-13)
|
||||
- [v0.14.1](#v0141)
|
||||
- [v0.14.0](#v0140)
|
||||
- [Structured event monitoring](#structured-event-monitoring)
|
||||
@@ -120,7 +133,7 @@
|
||||
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
|
||||
- [Block device rate limiting](#block-device-rate-limiting)
|
||||
- [Deprecations](#deprecations-5)
|
||||
- [Contributors](#contributors-13)
|
||||
- [Contributors](#contributors-14)
|
||||
- [v0.13.0](#v0130)
|
||||
- [Wider VFIO device support](#wider-vfio-device-support)
|
||||
- [Improved huge page support](#improved-huge-page-support)
|
||||
@@ -128,13 +141,13 @@
|
||||
- [VHD disk image support](#vhd-disk-image-support)
|
||||
- [Improved Virtio device threading](#improved-virtio-device-threading)
|
||||
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
|
||||
- [Contributors](#contributors-14)
|
||||
- [Contributors](#contributors-15)
|
||||
- [v0.12.0](#v0120)
|
||||
- [ARM64 enhancements](#arm64-enhancements)
|
||||
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
|
||||
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
|
||||
- [Enhanced "info" API](#enhanced-info-api)
|
||||
- [Contributors](#contributors-15)
|
||||
- [Contributors](#contributors-16)
|
||||
- [v0.11.0](#v0110)
|
||||
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
|
||||
- [Windows Guest Support](#windows-guest-support)
|
||||
@@ -146,15 +159,15 @@
|
||||
- [Default Log Level Changed](#default-log-level-changed)
|
||||
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
|
||||
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-12)
|
||||
- [Contributors](#contributors-16)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-13)
|
||||
- [Contributors](#contributors-17)
|
||||
- [v0.10.0](#v0100)
|
||||
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
|
||||
- [Memory Zones](#memory-zones)
|
||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
|
||||
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-13)
|
||||
- [Contributors](#contributors-17)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-14)
|
||||
- [Contributors](#contributors-18)
|
||||
- [v0.9.0](#v090)
|
||||
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
|
||||
- [Block and Network Device Statistics](#block-and-network-device-statistics)
|
||||
@@ -167,17 +180,17 @@
|
||||
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
|
||||
- [Intel SGX Support](#intel-sgx-support)
|
||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-14)
|
||||
- [Contributors](#contributors-18)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-15)
|
||||
- [Contributors](#contributors-19)
|
||||
- [v0.8.0](#v080)
|
||||
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
|
||||
- [Experimental ARM64 Support](#experimental-arm64-support)
|
||||
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
|
||||
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
|
||||
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-15)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-16)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes)
|
||||
- [Contributors](#contributors-19)
|
||||
- [Contributors](#contributors-20)
|
||||
- [v0.7.0](#v070)
|
||||
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
|
||||
- [Alternative `libc` Support](#alternative-libc-support)
|
||||
@@ -187,14 +200,14 @@
|
||||
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
||||
- [Updated Distribution Support](#updated-distribution-support)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
||||
- [Contributors](#contributors-20)
|
||||
- [Contributors](#contributors-21)
|
||||
- [v0.6.0](#v060)
|
||||
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
|
||||
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
|
||||
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
|
||||
- [Command Line Interface](#command-line-interface)
|
||||
- [PVH Boot](#pvh-boot)
|
||||
- [Contributors](#contributors-21)
|
||||
- [Contributors](#contributors-22)
|
||||
- [v0.5.1](#v051)
|
||||
- [v0.5.0](#v050)
|
||||
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
||||
@@ -202,7 +215,7 @@
|
||||
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
||||
- [Development Tools](#development-tools)
|
||||
- [Kata Containers Integration](#kata-containers-integration)
|
||||
- [Contributors](#contributors-22)
|
||||
- [Contributors](#contributors-23)
|
||||
- [v0.4.0](#v040)
|
||||
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
||||
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
||||
@@ -211,7 +224,7 @@
|
||||
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
|
||||
- [PCI BAR reprogramming](#pci-bar-reprogramming)
|
||||
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
|
||||
- [Contributors](#contributors-23)
|
||||
- [Contributors](#contributors-24)
|
||||
- [v0.3.0](#v030)
|
||||
- [Block device offloading](#block-device-offloading)
|
||||
- [Network device backend](#network-device-backend)
|
||||
@@ -238,6 +251,130 @@
|
||||
- [Unit testing](#unit-testing)
|
||||
- [Integration tests parallelization](#integration-tests-parallelization)
|
||||
|
||||
|
||||
# v28.4
|
||||
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
|
||||
* Fix VFIO on platforms with non-4k page size (#5450)
|
||||
* Fix seccomp filter lists related to virtio-console, serial and pty
|
||||
(#5506, #5524)
|
||||
* Populate APIC ID properly (#5512)
|
||||
* Ignore and warn TAP FDs in more situations (#5522)
|
||||
* Disallow concurrent CPU resizing (#5668)
|
||||
* Use wrapping add for memory offset from instruction emulator (#5719)
|
||||
* Replace unsound `static mut` with `once_cell` (#5772)
|
||||
* Fix a deadlock when TDX is enabled (#5845)
|
||||
* Bug fix to OpenAPI specification file (#5967)
|
||||
* Error out early for live migration when TDX is enabled (#6025)
|
||||
|
||||
# v28.3
|
||||
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
|
||||
* Ignore and warn TAP FDs sent via the HTTP request body (#5350)
|
||||
* Properly preserve and close valid FDs for TAP devices (#5373)
|
||||
* Only use `KVM_ARM_VCPU_PMU_V3` if available (#5360)
|
||||
* Fix seccomp filter lists for vhost-user devices (#5361)
|
||||
* Fix the offset setting while removing the entire mapping of
|
||||
`vhost-user` FS client (#5235)
|
||||
* Set vcpu thread status properly and signal exit_evt upon thread exit (#5211)
|
||||
* Populate CPUID leaf 0x4000_0010 (TSC frequency) (#5179)
|
||||
* Bug fix to OpenAPI specification file (#5186)
|
||||
|
||||
# v28.2
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
|
||||
* Fix QCOW2 refcount table size (#5034)
|
||||
* Fix unpause support on MSHV in dual binary (#5037)
|
||||
* Threads inside `virtio` devices are now shutdown on reboot (#5095)
|
||||
|
||||
# v28.1
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
|
||||
* Update dependencies including a version of `linux-loader` that
|
||||
addresses an infinite loop issue ([details](https://github.com/rust-vmm/linux-loader/security/advisories/GHSA-52h2-m2cf-9jh6))
|
||||
* Fix bugs related to `virtio-net` including an integer overflow issue
|
||||
(#4924, #4949)
|
||||
* Use host `cpuid` information for L2 cache for older KVM on x86 (#4920)
|
||||
* Improve README and documentation
|
||||
|
||||
# v28.0
|
||||
|
||||
This release has been tracked in our new [roadmap
|
||||
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
|
||||
v28.0.
|
||||
|
||||
### Community Engagement (Reminder)
|
||||
|
||||
Just a reminder that we have a new mailing list to support broader community
|
||||
discussions. Please consider
|
||||
[subscribing](https://lists.cloudhypervisor.org/g/dev/). We plan to use
|
||||
this to announce a regular meeting for those interested in talking about Cloud
|
||||
Hypervisor development.
|
||||
|
||||
### Long Term Support (LTS) Release
|
||||
|
||||
This is the first version of Cloud Hypervisor to be released under the LTS
|
||||
release process. Point releases for bug fixes will be made for the next 18
|
||||
months; live migration and live upgrade will be supported between the point
|
||||
releases of the LTS.
|
||||
|
||||
### Virtualised TPM Support
|
||||
|
||||
Support for adding an emulated CRB TPM has been added. This has it's own [TPM
|
||||
documentation](docs/tpm.md).
|
||||
|
||||
### Transparent Huge Page Support
|
||||
|
||||
By default, but controllable through `--memory thp=off` if it possible to back
|
||||
the guest memory with Transparent Huge Pages (no file backing/`shared=off`)
|
||||
then this will be used resulting in improved boot performance.
|
||||
|
||||
### README Quick Start Improved
|
||||
|
||||
The README has been refreshed with the quick start guide updated to reflect the
|
||||
different firmware options and to recommend the use of pre-built binaries.
|
||||
|
||||
### Notable Bug Fixes
|
||||
|
||||
* Inappropriate Copy-on-Write of pinned pages (e.g. VFIO) leading to higher
|
||||
memory consumption (#4835)
|
||||
* Multiple `virtio` device bug fixes found through fuzzing (#4859, #4799)
|
||||
* Large QCOW files (> 4TiB) are now supported (#4767)
|
||||
* Support for > 31 vCPUS on aarch64 (#4863)
|
||||
* Multiple fixes to OpenAPI specification file (#4720, #4811)
|
||||
* Programming of the MSI-X table has been optimised leading to faster boot on
|
||||
newer Linux kernels (#4744)
|
||||
* Error on reboot from race to close TAP devices (#4871)
|
||||
* Non-spec compliant virtio-block read-only support (#4888)
|
||||
|
||||
### Removals
|
||||
|
||||
The following functionality has been removed:
|
||||
|
||||
* Support for non-PVH firmware booting has been removed (#4511)
|
||||
* I/O ports used for older versions of firmware have been removed (#3926)
|
||||
* Deprecated API options for kernel/cmdline/initramfs have been removed (#4737)
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Anatol Belski <anbelski@linux.microsoft.com>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Fabiano Fidêncio <fabiano.fidencio@intel.com>
|
||||
* Jianyong Wu <jianyong.wu@arm.com>
|
||||
* Jinank Jain <jinankjain@microsoft.com>
|
||||
* Jinrong Liang <cloudliang@tencent.com>
|
||||
* lv.mengzhao <lv.mengzhao@zte.com.cn>
|
||||
* Michael Zhao <michael.zhao@arm.com>
|
||||
* Muminul Islam <muislam@microsoft.com>
|
||||
* Praveen K Paladugu <prapal@linux.microsoft.com>
|
||||
* Rob Bradford <robert.bradford@intel.com>
|
||||
* Sebastien Boeuf <sebastien.boeuf@intel.com>
|
||||
* Wei Liu <liuwe@microsoft.com>
|
||||
|
||||
# v27.0
|
||||
|
||||
This release has been tracked in our new [roadmap
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# When changing this file don't forget to update the tag name in the
|
||||
# .github/workflows/docker-image.yaml file if doing multiple per day
|
||||
|
||||
FROM ubuntu:20.04 as dev
|
||||
FROM ubuntu:22.04 as dev
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG RUST_TOOLCHAIN="1.62.0"
|
||||
ARG RUST_TOOLCHAIN="1.65.0"
|
||||
ARG CLH_SRC_DIR="/cloud-hypervisor"
|
||||
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
|
||||
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"
|
||||
@@ -16,40 +16,43 @@ ENV PATH="$PATH:$CARGO_HOME/bin"
|
||||
|
||||
# Install all CI dependencies
|
||||
RUN apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
||||
build-essential \
|
||||
bc \
|
||||
curl \
|
||||
wget \
|
||||
sudo \
|
||||
mtools \
|
||||
musl-tools \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
flex \
|
||||
bison \
|
||||
libelf-dev \
|
||||
qemu-utils \
|
||||
libglib2.0-dev \
|
||||
libpixman-1-dev \
|
||||
libseccomp-dev \
|
||||
libcap-ng-dev \
|
||||
socat \
|
||||
dosfstools \
|
||||
cpio \
|
||||
python \
|
||||
python3 \
|
||||
python3-setuptools \
|
||||
ntfs-3g \
|
||||
openvswitch-switch-dpdk \
|
||||
python3-distutils \
|
||||
uuid-dev \
|
||||
iperf3 \
|
||||
zip \
|
||||
git-core \
|
||||
dnsmasq \
|
||||
dmsetup \
|
||||
&& apt-get -yq upgrade \
|
||||
&& apt-get install --no-install-recommends -yq \
|
||||
build-essential \
|
||||
bc \
|
||||
curl \
|
||||
wget \
|
||||
sudo \
|
||||
mtools \
|
||||
musl-tools \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
flex \
|
||||
bison \
|
||||
libelf-dev \
|
||||
qemu-utils \
|
||||
libglib2.0-dev \
|
||||
libpixman-1-dev \
|
||||
libseccomp-dev \
|
||||
libcap-ng-dev \
|
||||
socat \
|
||||
dosfstools \
|
||||
cpio \
|
||||
python3 \
|
||||
python3-setuptools \
|
||||
ntfs-3g \
|
||||
python3-distutils \
|
||||
uuid-dev \
|
||||
iperf3 \
|
||||
zip \
|
||||
git-core \
|
||||
dnsmasq \
|
||||
dmsetup \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
iproute2 \
|
||||
dbus \
|
||||
&& apt-get install openvswitch-switch-dpdk -yq \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
@@ -112,17 +115,18 @@ RUN echo 'source $CARGO_HOME/env' >> $HOME/.bashrc \
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
git clone https://github.com/spdk/spdk \
|
||||
&& cd spdk \
|
||||
&& git checkout 6301f8915de32baed10dba1eebed556a6749211a \
|
||||
&& git checkout ef8bcce58f3f02b79c0619a297e4f17e81e62b24 \
|
||||
&& git submodule update --init \
|
||||
&& apt-get update \
|
||||
&& ./scripts/pkgdep.sh \
|
||||
&& apt-get clean \
|
||||
&& ./configure --with-vfio-user \
|
||||
&& make -j `nproc` \
|
||||
&& make -j $(nproc) TARGET_ARCHITECTURE=skylake \
|
||||
&& rm -rf /usr/local/bin/spdk-nvme \
|
||||
&& mkdir /usr/local/bin/spdk-nvme \
|
||||
&& cp ./build/bin/nvmf_tgt /usr/local/bin/spdk-nvme \
|
||||
&& cp ./scripts/rpc.py /usr/local/bin/spdk-nvme \
|
||||
&& cp -r ./scripts/rpc /usr/local/bin/spdk-nvme \
|
||||
&& cp -f ./build/bin/nvmf_tgt /usr/local/bin/spdk-nvme \
|
||||
&& cp -f ./scripts/rpc.py /usr/local/bin/spdk-nvme \
|
||||
&& cp -rf ./python /usr/local/bin \
|
||||
&& cd .. && rm -rf spdk; fi
|
||||
|
||||
# install ethr tool for performance tests
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
export BUILD_TARGET=${BUILD_TARGET-aarch64-unknown-linux-gnu}
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
CLI_NAME="Cloud Hypervisor"
|
||||
|
||||
CTR_IMAGE_TAG="cloudhypervisor/dev"
|
||||
CTR_IMAGE_VERSION="20220705-0"
|
||||
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
|
||||
CTR_IMAGE_TAG="ghcr.io/cloud-hypervisor/cloud-hypervisor"
|
||||
CTR_IMAGE_VERSION="20231220-0"
|
||||
: "${CTR_IMAGE:=${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}}"
|
||||
|
||||
DOCKER_RUNTIME="docker"
|
||||
|
||||
@@ -277,11 +277,10 @@ cmd_build() {
|
||||
[ $build = "release" ] && cargo_args+=("--release")
|
||||
cargo_args+=(--target "$target")
|
||||
|
||||
rustflags=""
|
||||
rustflags="$RUSTFLAGS"
|
||||
target_cc=""
|
||||
if [ "$(uname -m)" = "aarch64" ] && [ "$libc" = "musl" ]; then
|
||||
rustflags="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
target_cc="musl-gcc"
|
||||
rustflags="$rustflags -C link-args=-Wl,-Bstatic -C link-args=-lc"
|
||||
fi
|
||||
|
||||
$DOCKER_RUNTIME run \
|
||||
@@ -387,6 +386,12 @@ cmd_tests() {
|
||||
process_volumes_args
|
||||
target="$(uname -m)-unknown-linux-${libc}"
|
||||
|
||||
rustflags="$RUSTFLAGS"
|
||||
target_cc=""
|
||||
if [ "$(uname -m)" = "aarch64" ] && [ "$libc" = "musl" ]; then
|
||||
rustflags="$rustflags -C link-args=-Wl,-Bstatic -C link-args=-lc"
|
||||
fi
|
||||
|
||||
if [[ "$unit" = true ]]; then
|
||||
say "Running unit tests for $target..."
|
||||
$DOCKER_RUNTIME run \
|
||||
@@ -397,6 +402,8 @@ cmd_tests() {
|
||||
--cap-add net_admin \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_unit_tests.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -415,7 +422,9 @@ cmd_tests() {
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -434,7 +443,9 @@ cmd_tests() {
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_sgx.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -453,7 +464,9 @@ cmd_tests() {
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_vfio.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -472,7 +485,9 @@ cmd_tests() {
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_windows_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -491,7 +506,9 @@ cmd_tests() {
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_live_migration.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -510,7 +527,9 @@ cmd_tests() {
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_rate_limiter.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -529,7 +548,10 @@ cmd_tests() {
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
--env RUST_BACKTRACE="${RUST_BACKTRACE}" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_metrics.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
|
||||
@@ -11,15 +11,16 @@ build_spdk_nvme() {
|
||||
SPDK_DIR="$WORKLOADS_DIR/spdk"
|
||||
SPDK_REPO="https://github.com/spdk/spdk.git"
|
||||
SPDK_DEPLOY_DIR="/usr/local/bin/spdk-nvme"
|
||||
checkout_repo "$SPDK_DIR" "$SPDK_REPO" master "6301f8915de32baed10dba1eebed556a6749211a"
|
||||
checkout_repo "$SPDK_DIR" "$SPDK_REPO" master "ef8bcce58f3f02b79c0619a297e4f17e81e62b24"
|
||||
|
||||
if [ ! -f "$SPDK_DIR/.built" ]; then
|
||||
pushd $SPDK_DIR
|
||||
git submodule update --init
|
||||
apt-get update
|
||||
sed -i "/grpcio/d" scripts/pkgdep/debian.sh
|
||||
./scripts/pkgdep.sh
|
||||
./configure --with-vfio-user
|
||||
chmod +x /usr/local/lib/python3.8/dist-packages/ninja/data/bin/ninja
|
||||
chmod +x /usr/local/lib/python3.10/dist-packages/ninja/data/bin/ninja
|
||||
make -j `nproc` || exit 1
|
||||
touch .built
|
||||
popd
|
||||
@@ -29,14 +30,15 @@ build_spdk_nvme() {
|
||||
fi
|
||||
cp "$WORKLOADS_DIR/spdk/build/bin/nvmf_tgt" $SPDK_DEPLOY_DIR/nvmf_tgt
|
||||
cp "$WORKLOADS_DIR/spdk/scripts/rpc.py" $SPDK_DEPLOY_DIR/rpc.py
|
||||
cp -r "$WORKLOADS_DIR/spdk/scripts/rpc" $SPDK_DEPLOY_DIR/rpc
|
||||
cp -r "$WORKLOADS_DIR/spdk/python/spdk/" $SPDK_DEPLOY_DIR/
|
||||
cp -r "$WORKLOADS_DIR/spdk/python" $SPDK_DEPLOY_DIR/../
|
||||
}
|
||||
|
||||
build_virtiofsd() {
|
||||
VIRTIOFSD_DIR="$WORKLOADS_DIR/virtiofsd_build"
|
||||
VIRTIOFSD_REPO="https://gitlab.com/virtio-fs/virtiofsd.git"
|
||||
|
||||
checkout_repo "$VIRTIOFSD_DIR" "$VIRTIOFSD_REPO" v1.1.0 "220405d7a2606c92636d31992b5cb3036a41047b"
|
||||
checkout_repo "$VIRTIOFSD_DIR" "$VIRTIOFSD_REPO" v1.8.0 "97ea7908fe7f9bc59916671a771bdcfaf4044b45"
|
||||
|
||||
if [ ! -f "$VIRTIOFSD_DIR/.built" ]; then
|
||||
pushd $VIRTIOFSD_DIR
|
||||
@@ -152,8 +154,21 @@ update_workloads() {
|
||||
CH_RELEASE_URL="https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$LAST_RELEASE_VERSION/cloud-hypervisor-static-aarch64"
|
||||
CH_RELEASE_NAME="cloud-hypervisor-static-aarch64"
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $CH_RELEASE_URL -O "$CH_RELEASE_NAME" || exit 1
|
||||
chmod +x $CH_RELEASE_NAME
|
||||
# Repeat a few times to workaround a random wget failure
|
||||
WGET_RETRY_MAX=10
|
||||
wget_retry=0
|
||||
|
||||
until [ "$wget_retry" -ge "$WGET_RETRY_MAX" ]
|
||||
do
|
||||
time wget $CH_RELEASE_URL -O "$CH_RELEASE_NAME" && break
|
||||
wget_retry=$((wget_retry+1))
|
||||
done
|
||||
|
||||
if [ $wget_retry -ge "$WGET_RETRY_MAX" ]; then
|
||||
exit 1
|
||||
else
|
||||
chmod +x $CH_RELEASE_NAME
|
||||
fi
|
||||
popd
|
||||
|
||||
# Build custom kernel for guest VMs
|
||||
@@ -225,12 +240,6 @@ if [ $RES -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BUILD_TARGET="aarch64-unknown-linux-${CH_LIBC}"
|
||||
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
fi
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
# Test without ACPI
|
||||
|
||||
@@ -4,8 +4,6 @@ set -x
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
|
||||
export BUILD_TARGET=${BUILD_TARGET-x86_64-unknown-linux-gnu}
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
|
||||
@@ -78,11 +76,8 @@ if [ -d "$LINUX_CUSTOM_DIR" ]; then
|
||||
rm -rf $LINUX_CUSTOM_DIR
|
||||
fi
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ set -x
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
|
||||
export BUILD_TARGET=${BUILD_TARGET-x86_64-unknown-linux-gnu}
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
|
||||
@@ -69,11 +67,8 @@ if [ -d "$LINUX_CUSTOM_DIR" ]; then
|
||||
rm -rf $LINUX_CUSTOM_DIR
|
||||
fi
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
|
||||
@@ -14,12 +14,9 @@ fi
|
||||
# For now these values are default for kvm
|
||||
features=""
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --all --release $features --target $BUILD_TARGET
|
||||
|
||||
@@ -35,12 +35,9 @@ cp $FOCAL_OS_IMAGE $VFIO_DIR
|
||||
cp $FW $VFIO_DIR
|
||||
cp $VMLINUX_IMAGE $VFIO_DIR || exit 1
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --all --release $features --target $BUILD_TARGET
|
||||
|
||||
@@ -22,14 +22,6 @@ WIN_IMAGE_FILE="$WORKLOADS_DIR/$WIN_IMAGE_BASENAME"
|
||||
OVMF_FW="$WORKLOADS_DIR/CLOUDHV_EFI.fd"
|
||||
build_edk2
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
fi
|
||||
|
||||
# Check if the images are present
|
||||
if [[ ! -f ${WIN_IMAGE_FILE} || ! -f ${OVMF_FW} ]]; then
|
||||
echo "Windows image/firmware not present in the host"
|
||||
|
||||
@@ -22,12 +22,9 @@ if [ ! -f "$OVMF_FW" ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
# Check if the images are present
|
||||
|
||||
@@ -4,8 +4,6 @@ set -x
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
|
||||
export BUILD_TARGET=${BUILD_TARGET-x86_64-unknown-linux-gnu}
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
|
||||
@@ -124,7 +122,9 @@ popd
|
||||
|
||||
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
||||
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
|
||||
build_custom_linux
|
||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||
build_custom_linux
|
||||
fi
|
||||
|
||||
VIRTIOFSD="$WORKLOADS_DIR/virtiofsd"
|
||||
VIRTIOFSD_DIR="virtiofsd_build"
|
||||
@@ -132,7 +132,7 @@ if [ ! -f "$VIRTIOFSD" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
git clone "https://gitlab.com/virtio-fs/virtiofsd.git" $VIRTIOFSD_DIR
|
||||
pushd $VIRTIOFSD_DIR
|
||||
git checkout v1.1.0
|
||||
git checkout v1.8.0
|
||||
time cargo build --release
|
||||
cp target/release/virtiofsd $VIRTIOFSD || exit 1
|
||||
popd
|
||||
@@ -170,8 +170,6 @@ cp $FOCAL_OS_RAW_IMAGE $VFIO_DIR
|
||||
cp $FW $VFIO_DIR
|
||||
cp $VMLINUX_IMAGE $VFIO_DIR || exit 1
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
|
||||
cargo build --all --release $features --target $BUILD_TARGET
|
||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||
strip target/$BUILD_TARGET/release/vhost_user_net
|
||||
|
||||
@@ -5,8 +5,6 @@ source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
|
||||
export TEST_ARCH=$(uname -m)
|
||||
export BUILD_TARGET=${BUILD_TARGET-${TEST_ARCH}-unknown-linux-gnu}
|
||||
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
@@ -91,11 +89,8 @@ fi
|
||||
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
||||
build_custom_linux
|
||||
|
||||
BUILD_TARGET="${TEST_ARCH}-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "${TEST_ARCH}-unknown-linux-musl" ]]; then
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/${TEST_ARCH}-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ source $(dirname "$0")/test-util.sh
|
||||
|
||||
process_common_args "$@"
|
||||
|
||||
BUILD_TARGET=${BUILD_TARGET-x86_64-unknown-linux-gnu}
|
||||
cargo_args=("")
|
||||
|
||||
if [[ $hypervisor = "mshv" ]]; then
|
||||
@@ -15,10 +14,5 @@ elif [[ $(uname -m) = "x86_64" ]]; then
|
||||
cargo_args+=("--features tdx")
|
||||
fi
|
||||
|
||||
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
fi
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
cargo test --lib --bins --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user