mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
113 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62001b65e9 | ||
|
|
4be2ca4c10 | ||
|
|
5716af09a5 | ||
|
|
4ea40b4bea | ||
|
|
4528e2f1ea | ||
|
|
987ad11c90 | ||
|
|
cea708deb9 | ||
|
|
e32fa593e5 | ||
|
|
ec8fceb4a6 | ||
|
|
01aed9733c | ||
|
|
a5cd1b4fbe | ||
|
|
b268e88ba3 | ||
|
|
0659eaeba1 | ||
|
|
96528f84f9 | ||
|
|
6da5c32fd9 | ||
|
|
07cc1f6545 | ||
|
|
008f259aff | ||
|
|
aa6fefa80f | ||
|
|
87e74719ec | ||
|
|
072f06ff4c | ||
|
|
50b33db718 | ||
|
|
19dc733267 | ||
|
|
6ba949d741 | ||
|
|
9d4408ba76 | ||
|
|
f9c134471a | ||
|
|
3d5b4d0b0c | ||
|
|
ea32b67098 | ||
|
|
190d90196f | ||
|
|
fe422a45af | ||
|
|
da5fae3814 | ||
|
|
8a78043e2f | ||
|
|
fdeb778210 | ||
|
|
13c222a879 | ||
|
|
b27d9ccfab | ||
|
|
d580ed55c6 | ||
|
|
2cb8c41adc | ||
|
|
48b67ed03b | ||
|
|
e0f0065cbd | ||
|
|
1866a85a3d | ||
|
|
8338fa642f | ||
|
|
a5287c6f67 | ||
|
|
fe07617f5d | ||
|
|
1820c22ba4 | ||
|
|
f828e16d62 | ||
|
|
24998c1672 | ||
|
|
821f7994fc | ||
|
|
4182ef91e0 | ||
|
|
100c6d8142 | ||
|
|
269976c7b3 | ||
|
|
8769b78bf3 | ||
|
|
a991de9955 | ||
|
|
47c9ddfa7e | ||
|
|
2b05753716 | ||
|
|
80f4bfac00 | ||
|
|
b26b09ec0c | ||
|
|
39a6664e62 | ||
|
|
190a11f212 | ||
|
|
6ea132708c | ||
|
|
060c9de07f | ||
|
|
1433763d40 | ||
|
|
30ee2c129d | ||
|
|
9bf15ed280 | ||
|
|
ed63b352d1 | ||
|
|
8e2973fe7c | ||
|
|
3541cebbf1 | ||
|
|
1ede418dcc | ||
|
|
1b03e59152 | ||
|
|
8f56de713b | ||
|
|
2100d8c30f | ||
|
|
a3692144f0 | ||
|
|
192b19c060 | ||
|
|
67896333e3 | ||
|
|
72c8178335 | ||
|
|
1b91aa8ef3 | ||
|
|
5711f31995 | ||
|
|
aebbd1aecd | ||
|
|
06a868cb85 | ||
|
|
3f3489e38e | ||
|
|
d7edd9d51f | ||
|
|
4987d63b6a | ||
|
|
53e9c94e68 | ||
|
|
9d8bda20e5 | ||
|
|
63d7f562e5 | ||
|
|
9bd9c0cb71 | ||
|
|
d594107c0d | ||
|
|
1f13165fae | ||
|
|
12493db144 | ||
|
|
f151fdb16f | ||
|
|
bb6ca56fb0 | ||
|
|
a336533389 | ||
|
|
c4b6ed1077 | ||
|
|
3e8dda4e7d | ||
|
|
e9edb2e51c | ||
|
|
0798effcc6 | ||
|
|
6079791bca | ||
|
|
ff2330defe | ||
|
|
12b72ba3c1 | ||
|
|
92f9e20f57 | ||
|
|
3d78662498 | ||
|
|
2bc8d51a60 | ||
|
|
51002f2bae | ||
|
|
59e11f1b0b | ||
|
|
fc01e4cbec | ||
|
|
3f8186f627 | ||
|
|
6f56ef9a36 | ||
|
|
d6ed74b5b8 | ||
|
|
7fbe94a227 | ||
|
|
4a1809f596 | ||
|
|
0a4169801b | ||
|
|
20296e909a | ||
|
|
24a6a1805b | ||
|
|
dd7318e839 | ||
|
|
37444c4bab |
5
.github/dependabot.yml
vendored
5
.github/dependabot.yml
vendored
@@ -16,3 +16,8 @@ updates:
|
|||||||
allow:
|
allow:
|
||||||
- dependency-type: direct
|
- dependency-type: direct
|
||||||
- dependency-type: indirect
|
- dependency-type: indirect
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
open-pull-requests-limit: 1
|
||||||
2
.github/workflows/dco.yaml
vendored
2
.github/workflows/dco.yaml
vendored
@@ -8,7 +8,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Set up Python 3.x
|
- name: Set up Python 3.x
|
||||||
uses: actions/setup-python@v1
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: '3.x'
|
python-version: '3.x'
|
||||||
- name: Check DCO
|
- name: Check DCO
|
||||||
|
|||||||
2
.github/workflows/gitlint.yaml
vendored
2
.github/workflows/gitlint.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Set up Python 3.10
|
- name: Set up Python 3.10
|
||||||
uses: actions/setup-python@v3
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.10"
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
|||||||
93
.github/workflows/quality.yaml
vendored
93
.github/workflows/quality.yaml
vendored
@@ -50,88 +50,97 @@ jobs:
|
|||||||
git checkout ${{ github.sha }}
|
git checkout ${{ github.sha }}
|
||||||
|
|
||||||
- name: Clippy (kvm)
|
- name: Clippy (kvm)
|
||||||
uses: actions-rs/cargo@v1
|
uses: houseabsolute/actions-rust-cross@v1
|
||||||
with:
|
with:
|
||||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
args: --locked --all --all-targets --no-default-features --tests --examples --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
||||||
|
|
||||||
- name: Clippy (mshv)
|
- name: Clippy (mshv)
|
||||||
uses: actions-rs/cargo@v1
|
uses: houseabsolute/actions-rust-cross@v1
|
||||||
with:
|
with:
|
||||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "mshv" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
args: --locked --all --all-targets --no-default-features --tests --examples --features "mshv" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
||||||
|
|
||||||
- name: Clippy (mshv + kvm)
|
- name: Clippy (mshv + kvm)
|
||||||
uses: actions-rs/cargo@v1
|
uses: houseabsolute/actions-rust-cross@v1
|
||||||
with:
|
with:
|
||||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
args: --locked --all --all-targets --no-default-features --tests --examples --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
||||||
|
|
||||||
- name: Clippy (default features)
|
- name: Clippy (default features)
|
||||||
uses: actions-rs/cargo@v1
|
uses: houseabsolute/actions-rust-cross@v1
|
||||||
with:
|
with:
|
||||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --examples -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
args: --locked --all --all-targets --tests --examples -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
||||||
|
|
||||||
- name: Clippy (default features + guest_debug)
|
- name: Clippy (default features + guest_debug)
|
||||||
uses: actions-rs/cargo@v1
|
uses: houseabsolute/actions-rust-cross@v1
|
||||||
with:
|
with:
|
||||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --examples --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
args: --locked --all --all-targets --tests --examples --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
||||||
|
|
||||||
- name: Clippy (default features + pvmemcontrol)
|
- name: Clippy (default features + pvmemcontrol)
|
||||||
uses: actions-rs/cargo@v1
|
uses: houseabsolute/actions-rust-cross@v1
|
||||||
with:
|
with:
|
||||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --examples --features "pvmemcontrol" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
args: --locked --all --all-targets --tests --examples --features "pvmemcontrol" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
||||||
|
|
||||||
- name: Clippy (default features + tracing)
|
- name: Clippy (default features + tracing)
|
||||||
uses: actions-rs/cargo@v1
|
uses: houseabsolute/actions-rust-cross@v1
|
||||||
with:
|
|
||||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
|
||||||
command: clippy
|
|
||||||
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --examples --features "tracing" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
|
||||||
|
|
||||||
- name: Clippy (mshv)
|
|
||||||
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
with:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "mshv" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
- name: Clippy (mshv + kvm)
|
target: ${{ matrix.target }}
|
||||||
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
args: --locked --all --all-targets --tests --examples --features "tracing" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: clippy
|
|
||||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
|
||||||
|
|
||||||
- name: Clippy (sev_snp)
|
- name: Clippy (sev_snp)
|
||||||
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
||||||
uses: actions-rs/cargo@v1
|
uses: houseabsolute/actions-rust-cross@v1
|
||||||
with:
|
with:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "sev_snp" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
args: --locked --all --all-targets --no-default-features --tests --examples --features "sev_snp" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
||||||
|
|
||||||
- name: Clippy (igvm)
|
- name: Clippy (igvm)
|
||||||
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
||||||
uses: actions-rs/cargo@v1
|
uses: houseabsolute/actions-rust-cross@v1
|
||||||
with:
|
with:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "igvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
args: --locked --all --all-targets --no-default-features --tests --examples --features "igvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
||||||
|
|
||||||
- name: Clippy (kvm + tdx)
|
- name: Clippy (kvm + tdx)
|
||||||
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
||||||
uses: actions-rs/cargo@v1
|
uses: houseabsolute/actions-rust-cross@v1
|
||||||
with:
|
with:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "tdx,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
args: --locked --all --all-targets --no-default-features --tests --examples --features "tdx,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
|
||||||
|
|
||||||
- name: Check build did not modify any files
|
- name: Check build did not modify any files
|
||||||
run: test -z "$(git status --porcelain)"
|
run: test -z "$(git status --porcelain)"
|
||||||
@@ -143,4 +152,4 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
# Executes "typos ."
|
# Executes "typos ."
|
||||||
- uses: crate-ci/typos@v1.16.11
|
- uses: crate-ci/typos@v1.34.0
|
||||||
|
|||||||
4
.github/workflows/release.yaml
vendored
4
.github/workflows/release.yaml
vendored
@@ -39,7 +39,7 @@ jobs:
|
|||||||
matrix.platform.target == 'x86_64-unknown-linux-gnu'
|
matrix.platform.target == 'x86_64-unknown-linux-gnu'
|
||||||
run: rsync -rv --exclude=.git . ../cloud-hypervisor-${{ github.event.ref }}
|
run: rsync -rv --exclude=.git . ../cloud-hypervisor-${{ github.event.ref }}
|
||||||
- name: Build ${{ matrix.platform.target }}
|
- name: Build ${{ matrix.platform.target }}
|
||||||
uses: houseabsolute/actions-rust-cross@v0
|
uses: houseabsolute/actions-rust-cross@v1
|
||||||
with:
|
with:
|
||||||
command: build
|
command: build
|
||||||
target: ${{ matrix.platform.target }}
|
target: ${{ matrix.platform.target }}
|
||||||
@@ -86,7 +86,7 @@ jobs:
|
|||||||
name: cloud-hypervisor-${{ github.event.ref }}.tar.xz
|
name: cloud-hypervisor-${{ github.event.ref }}.tar.xz
|
||||||
- name: Create GitHub Release
|
- name: Create GitHub Release
|
||||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
draft: true
|
draft: true
|
||||||
files: |
|
files: |
|
||||||
|
|||||||
2
.github/workflows/reuse.yaml
vendored
2
.github/workflows/reuse.yaml
vendored
@@ -9,4 +9,4 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: REUSE Compliance Check
|
- name: REUSE Compliance Check
|
||||||
uses: fsfe/reuse-action@v3
|
uses: fsfe/reuse-action@v5
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@
|
|||||||
/rpm/SOURCES
|
/rpm/SOURCES
|
||||||
/.vscode
|
/.vscode
|
||||||
/vendor
|
/vendor
|
||||||
|
__pycache__
|
||||||
|
|||||||
@@ -7,15 +7,17 @@ extend-exclude = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[default.extend-words]
|
[default.extend-words]
|
||||||
ba = "ba"
|
|
||||||
CLASSE = "CLASSE"
|
CLASSE = "CLASSE"
|
||||||
conectix = "conectix"
|
|
||||||
Dake = "Dake"
|
Dake = "Dake"
|
||||||
EXTINT = "EXTINT"
|
EXTINT = "EXTINT"
|
||||||
INOUT = "INOUT"
|
INOUT = "INOUT"
|
||||||
|
SME = "SME" # Secure Memory Encryption
|
||||||
|
THR = "THR" # Transmitter Holding Register
|
||||||
|
TRANSLATER = "TRANSLATER"
|
||||||
|
ba = "ba"
|
||||||
|
conectix = "conectix"
|
||||||
liness = "liness"
|
liness = "liness"
|
||||||
outout = "outout"
|
outout = "outout"
|
||||||
TRANSLATER = "TRANSLATER"
|
|
||||||
|
|
||||||
[default.extend-identifiers]
|
[default.extend-identifiers]
|
||||||
fo = "fo"
|
fo = "fo"
|
||||||
|
|||||||
580
Cargo.lock
generated
580
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
38
Cargo.toml
38
Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
|
|||||||
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
||||||
license = "Apache-2.0 AND BSD-3-Clause"
|
license = "Apache-2.0 AND BSD-3-Clause"
|
||||||
name = "cloud-hypervisor"
|
name = "cloud-hypervisor"
|
||||||
version = "46.0.0"
|
version = "47.0.0"
|
||||||
# Minimum buildable version:
|
# Minimum buildable version:
|
||||||
# Keep in sync with version in .github/workflows/build.yaml
|
# Keep in sync with version in .github/workflows/build.yaml
|
||||||
# Policy on MSRV (see #4318):
|
# Policy on MSRV (see #4318):
|
||||||
@@ -33,6 +33,7 @@ anyhow = "1.0.94"
|
|||||||
api_client = { path = "api_client" }
|
api_client = { path = "api_client" }
|
||||||
clap = { version = "4.5.13", features = ["string"] }
|
clap = { version = "4.5.13", features = ["string"] }
|
||||||
dhat = { version = "0.3.3", optional = true }
|
dhat = { version = "0.3.3", optional = true }
|
||||||
|
env_logger = { workspace = true }
|
||||||
epoll = "4.3.3"
|
epoll = "4.3.3"
|
||||||
event_monitor = { path = "event_monitor" }
|
event_monitor = { path = "event_monitor" }
|
||||||
hypervisor = { path = "hypervisor" }
|
hypervisor = { path = "hypervisor" }
|
||||||
@@ -42,18 +43,17 @@ option_parser = { path = "option_parser" }
|
|||||||
seccompiler = { workspace = true }
|
seccompiler = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
signal-hook = "0.3.18"
|
signal-hook = "0.3.18"
|
||||||
thiserror = "2.0.6"
|
thiserror = { workspace = true }
|
||||||
tpm = { path = "tpm" }
|
tpm = { path = "tpm" }
|
||||||
tracer = { path = "tracer" }
|
tracer = { path = "tracer" }
|
||||||
vm-memory = { workspace = true }
|
vm-memory = { workspace = true }
|
||||||
vmm = { path = "vmm" }
|
vmm = { path = "vmm" }
|
||||||
vmm-sys-util = { workspace = true }
|
vmm-sys-util = { workspace = true }
|
||||||
zbus = { version = "4.4.0", optional = true }
|
zbus = { version = "5.7.1", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
dirs = "6.0.0"
|
dirs = "6.0.0"
|
||||||
net_util = { path = "net_util" }
|
net_util = { path = "net_util" }
|
||||||
once_cell = "1.20.2"
|
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
test_infra = { path = "test_infra" }
|
test_infra = { path = "test_infra" }
|
||||||
wait-timeout = "0.2.0"
|
wait-timeout = "0.2.0"
|
||||||
@@ -104,22 +104,22 @@ members = [
|
|||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
# rust-vmm crates
|
# rust-vmm crates
|
||||||
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
|
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
|
||||||
kvm-bindings = "0.10.0"
|
kvm-bindings = "0.12.0"
|
||||||
kvm-ioctls = "0.19.1"
|
kvm-ioctls = "0.22.0"
|
||||||
linux-loader = "0.13.0"
|
linux-loader = "0.13.0"
|
||||||
mshv-bindings = "0.5.1"
|
mshv-bindings = "0.5.2"
|
||||||
mshv-ioctls = "0.5.1"
|
mshv-ioctls = "0.5.2"
|
||||||
seccompiler = "0.5.0"
|
seccompiler = "0.5.0"
|
||||||
vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main" }
|
vfio-bindings = { version = "0.5.0", default-features = false }
|
||||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
vfio-ioctls = { version = "0.5.0", default-features = false }
|
||||||
vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" }
|
vfio_user = { version = "0.1.0", default-features = false }
|
||||||
vhost = { git = "https://github.com/rust-vmm/vhost", rev = "d983ae0" }
|
vhost = { version = "0.14.0", default-features = false }
|
||||||
vhost-user-backend = { git = "https://github.com/rust-vmm/vhost", rev = "d983ae0" }
|
vhost-user-backend = { version = "0.20.0", default-features = false }
|
||||||
virtio-bindings = "0.2.4"
|
virtio-bindings = "0.2.6"
|
||||||
virtio-queue = "0.14.0"
|
virtio-queue = "0.16.0"
|
||||||
vm-fdt = { git = "https://github.com/rust-vmm/vm-fdt", branch = "main" }
|
vm-fdt = { git = "https://github.com/rust-vmm/vm-fdt", branch = "main" }
|
||||||
vm-memory = "0.16.1"
|
vm-memory = "0.16.1"
|
||||||
vmm-sys-util = "0.12.1"
|
vmm-sys-util = "0.14.0"
|
||||||
|
|
||||||
# igvm crates
|
# igvm crates
|
||||||
# TODO: bump to 0.3.5 release
|
# TODO: bump to 0.3.5 release
|
||||||
@@ -128,3 +128,9 @@ igvm_defs = { git = "https://github.com/microsoft/igvm", branch = "main" }
|
|||||||
|
|
||||||
# serde crates
|
# serde crates
|
||||||
serde_json = "1.0.120"
|
serde_json = "1.0.120"
|
||||||
|
|
||||||
|
# other crates
|
||||||
|
env_logger = "0.11.8"
|
||||||
|
thiserror = "2.0.12"
|
||||||
|
uuid = { version = "1.17.0" }
|
||||||
|
zerocopy = { version = "0.8.26", default-features = false }
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ name = "api_client"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
thiserror = "2.0.6"
|
thiserror = { workspace = true }
|
||||||
vmm-sys-util = { workspace = true }
|
vmm-sys-util = { workspace = true }
|
||||||
|
|||||||
@@ -11,18 +11,24 @@ use vmm_sys_util::sock_ctrl_msg::ScmSocket;
|
|||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Error writing to or reading from HTTP socket: {0}")]
|
#[error("Error writing to or reading from HTTP socket")]
|
||||||
Socket(#[source] std::io::Error),
|
Socket(#[source] std::io::Error),
|
||||||
#[error("Error sending file descriptors: {0}")]
|
#[error("Error sending file descriptors")]
|
||||||
SocketSendFds(#[source] vmm_sys_util::errno::Error),
|
SocketSendFds(#[source] vmm_sys_util::errno::Error),
|
||||||
#[error("Error parsing HTTP status code: {0}")]
|
#[error("Error parsing HTTP status code")]
|
||||||
StatusCodeParsing(#[source] std::num::ParseIntError),
|
StatusCodeParsing(#[source] std::num::ParseIntError),
|
||||||
#[error("HTTP output is missing protocol statement")]
|
#[error("HTTP output is missing protocol statement")]
|
||||||
MissingProtocol,
|
MissingProtocol,
|
||||||
#[error("Error parsing HTTP Content-Length field: {0}")]
|
#[error("Error parsing HTTP Content-Length field")]
|
||||||
ContentLengthParsing(#[source] std::num::ParseIntError),
|
ContentLengthParsing(#[source] std::num::ParseIntError),
|
||||||
#[error("Server responded with an error: {0:?}: {1:?}")]
|
#[error("Server responded with error {0:?}: {1:?}")]
|
||||||
ServerResponse(StatusCode, Option<String>),
|
ServerResponse(
|
||||||
|
StatusCode,
|
||||||
|
// TODO: Move `api` module from `vmm` to dedicated crate and use a common type definition
|
||||||
|
Option<
|
||||||
|
String, /* Untyped: Currently Vec<String> of error messages from top to root cause */
|
||||||
|
>,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
|||||||
@@ -18,10 +18,9 @@ libc = "0.2.167"
|
|||||||
linux-loader = { workspace = true, features = ["bzimage", "elf", "pe"] }
|
linux-loader = { workspace = true, features = ["bzimage", "elf", "pe"] }
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
serde = { version = "1.0.208", features = ["derive", "rc"] }
|
serde = { version = "1.0.208", features = ["derive", "rc"] }
|
||||||
thiserror = "2.0.6"
|
thiserror = { workspace = true }
|
||||||
uuid = "1.12.1"
|
uuid = { workspace = true }
|
||||||
vm-memory = { workspace = true, features = ["backend-bitmap", "backend-mmap"] }
|
vm-memory = { workspace = true, features = ["backend-bitmap", "backend-mmap"] }
|
||||||
vm-migration = { path = "../vm-migration" }
|
|
||||||
vmm-sys-util = { workspace = true, features = ["with-serde"] }
|
vmm-sys-util = { workspace = true, features = ["with-serde"] }
|
||||||
|
|
||||||
[target.'cfg(any(target_arch = "aarch64", target_arch = "riscv64"))'.dependencies]
|
[target.'cfg(any(target_arch = "aarch64", target_arch = "riscv64"))'.dependencies]
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ pub trait DeviceInfoForFdt {
|
|||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Failure in writing FDT in memory.
|
/// Failure in writing FDT in memory.
|
||||||
#[error("Failure in writing FDT in memory: {0}")]
|
#[error("Failure in writing FDT in memory")]
|
||||||
WriteFdtToMemory(#[source] GuestMemoryError),
|
WriteFdtToMemory(#[source] GuestMemoryError),
|
||||||
}
|
}
|
||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ pub enum Error {
|
|||||||
SetupFdt,
|
SetupFdt,
|
||||||
|
|
||||||
/// Failed to write FDT to memory.
|
/// Failed to write FDT to memory.
|
||||||
#[error("Failed to write FDT to memory: {0}")]
|
#[error("Failed to write FDT to memory")]
|
||||||
WriteFdtToMemory(#[source] fdt::Error),
|
WriteFdtToMemory(#[source] fdt::Error),
|
||||||
|
|
||||||
/// Failed to create a GIC.
|
/// Failed to create a GIC.
|
||||||
@@ -44,11 +44,11 @@ pub enum Error {
|
|||||||
InitramfsAddress,
|
InitramfsAddress,
|
||||||
|
|
||||||
/// Error configuring the general purpose registers
|
/// Error configuring the general purpose registers
|
||||||
#[error("Error configuring the general purpose registers: {0}")]
|
#[error("Error configuring the general purpose registers")]
|
||||||
RegsConfiguration(#[source] hypervisor::HypervisorCpuError),
|
RegsConfiguration(#[source] hypervisor::HypervisorCpuError),
|
||||||
|
|
||||||
/// Error configuring the MPIDR register
|
/// Error configuring the MPIDR register
|
||||||
#[error("Error configuring the MPIDR register: {0}")]
|
#[error("Error configuring the MPIDR register")]
|
||||||
VcpuRegMpidr(#[source] hypervisor::HypervisorCpuError),
|
VcpuRegMpidr(#[source] hypervisor::HypervisorCpuError),
|
||||||
|
|
||||||
/// Error initializing PMU for vcpu
|
/// Error initializing PMU for vcpu
|
||||||
@@ -56,12 +56,6 @@ pub enum Error {
|
|||||||
VcpuInitPmu,
|
VcpuInitPmu,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for super::Error {
|
|
||||||
fn from(e: Error) -> super::Error {
|
|
||||||
super::Error::PlatformSpecific(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
/// Specifies the entry point address where the guest must start
|
/// Specifies the entry point address where the guest must start
|
||||||
/// executing code.
|
/// executing code.
|
||||||
|
|||||||
@@ -28,14 +28,14 @@ type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitma
|
|||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
#[error("Platform specific error (x86_64): {0}")]
|
#[error("Platform specific error (x86_64)")]
|
||||||
PlatformSpecific(#[source] x86_64::Error),
|
PlatformSpecific(#[from] x86_64::Error),
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
#[error("Platform specific error (aarch64): {0:?}")]
|
#[error("Platform specific error (aarch64)")]
|
||||||
PlatformSpecific(#[source] aarch64::Error),
|
PlatformSpecific(#[from] aarch64::Error),
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
#[error("Platform specific error (riscv64): {0:?}")]
|
#[error("Platform specific error (riscv64)")]
|
||||||
PlatformSpecific(#[source] riscv64::Error),
|
PlatformSpecific(#[from] riscv64::Error),
|
||||||
#[error("The memory map table extends past the end of guest memory")]
|
#[error("The memory map table extends past the end of guest memory")]
|
||||||
MemmapTablePastRamEnd,
|
MemmapTablePastRamEnd,
|
||||||
#[error("Error writing memory map table to guest memory")]
|
#[error("Error writing memory map table to guest memory")]
|
||||||
@@ -46,7 +46,7 @@ pub enum Error {
|
|||||||
StartInfoSetup,
|
StartInfoSetup,
|
||||||
#[error("Failed to compute initramfs address")]
|
#[error("Failed to compute initramfs address")]
|
||||||
InitramfsAddress,
|
InitramfsAddress,
|
||||||
#[error("Error writing module entry to guest memory: {0}")]
|
#[error("Error writing module entry to guest memory")]
|
||||||
ModlistSetup(#[source] vm_memory::GuestMemoryError),
|
ModlistSetup(#[source] vm_memory::GuestMemoryError),
|
||||||
#[error("RSDP extends past the end of guest memory")]
|
#[error("RSDP extends past the end of guest memory")]
|
||||||
RsdpPastRamEnd,
|
RsdpPastRamEnd,
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ pub trait DeviceInfoForFdt {
|
|||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Failure in writing FDT in memory.
|
/// Failure in writing FDT in memory.
|
||||||
#[error("Failure in writing FDT in memory: {0}")]
|
#[error("Failure in writing FDT in memory")]
|
||||||
WriteFdtToMemory(#[source] GuestMemoryError),
|
WriteFdtToMemory(#[source] GuestMemoryError),
|
||||||
}
|
}
|
||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ pub enum Error {
|
|||||||
SetupFdt,
|
SetupFdt,
|
||||||
|
|
||||||
/// Failed to write FDT to memory.
|
/// Failed to write FDT to memory.
|
||||||
#[error("Failed to write FDT to memory: {0}")]
|
#[error("Failed to write FDT to memory")]
|
||||||
WriteFdtToMemory(#[source] fdt::Error),
|
WriteFdtToMemory(#[source] fdt::Error),
|
||||||
|
|
||||||
/// Failed to create a AIA.
|
/// Failed to create a AIA.
|
||||||
@@ -42,16 +42,10 @@ pub enum Error {
|
|||||||
InitramfsAddress,
|
InitramfsAddress,
|
||||||
|
|
||||||
/// Error configuring the general purpose registers
|
/// Error configuring the general purpose registers
|
||||||
#[error("Error configuring the general purpose registers: {0}")]
|
#[error("Error configuring the general purpose registers")]
|
||||||
RegsConfiguration(#[source] hypervisor::HypervisorCpuError),
|
RegsConfiguration(#[source] hypervisor::HypervisorCpuError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for super::Error {
|
|
||||||
fn from(e: Error) -> super::Error {
|
|
||||||
super::Error::PlatformSpecific(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
/// Specifies the entry point address where the guest must start
|
/// Specifies the entry point address where the guest must start
|
||||||
/// executing code.
|
/// executing code.
|
||||||
|
|||||||
@@ -132,35 +132,35 @@ pub struct CpuidConfig {
|
|||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Error writing MP table to memory.
|
/// Error writing MP table to memory.
|
||||||
#[error("Error writing MP table to memory: {0}")]
|
#[error("Error writing MP table to memory")]
|
||||||
MpTableSetup(#[source] mptable::Error),
|
MpTableSetup(#[source] mptable::Error),
|
||||||
|
|
||||||
/// Error configuring the general purpose registers
|
/// Error configuring the general purpose registers
|
||||||
#[error("Error configuring the general purpose registers: {0}")]
|
#[error("Error configuring the general purpose registers")]
|
||||||
RegsConfiguration(#[source] regs::Error),
|
RegsConfiguration(#[source] regs::Error),
|
||||||
|
|
||||||
/// Error configuring the special registers
|
/// Error configuring the special registers
|
||||||
#[error("Error configuring the special registers: {0}")]
|
#[error("Error configuring the special registers")]
|
||||||
SregsConfiguration(#[source] regs::Error),
|
SregsConfiguration(#[source] regs::Error),
|
||||||
|
|
||||||
/// Error configuring the floating point related registers
|
/// Error configuring the floating point related registers
|
||||||
#[error("Error configuring the floating point related registers: {0}")]
|
#[error("Error configuring the floating point related registers")]
|
||||||
FpuConfiguration(#[source] regs::Error),
|
FpuConfiguration(#[source] regs::Error),
|
||||||
|
|
||||||
/// Error configuring the MSR registers
|
/// Error configuring the MSR registers
|
||||||
#[error("Error configuring the MSR registers: {0}")]
|
#[error("Error configuring the MSR registers")]
|
||||||
MsrsConfiguration(#[source] regs::Error),
|
MsrsConfiguration(#[source] regs::Error),
|
||||||
|
|
||||||
/// Failed to set supported CPUs.
|
/// Failed to set supported CPUs.
|
||||||
#[error("Failed to set supported CPUs: {0}")]
|
#[error("Failed to set supported CPUs")]
|
||||||
SetSupportedCpusFailed(#[source] anyhow::Error),
|
SetSupportedCpusFailed(#[source] anyhow::Error),
|
||||||
|
|
||||||
/// Cannot set the local interruption due to bad configuration.
|
/// Cannot set the local interruption due to bad configuration.
|
||||||
#[error("Cannot set the local interruption due to bad configuration: {0}")]
|
#[error("Cannot set the local interruption due to bad configuration")]
|
||||||
LocalIntConfiguration(#[source] anyhow::Error),
|
LocalIntConfiguration(#[source] anyhow::Error),
|
||||||
|
|
||||||
/// Error setting up SMBIOS table
|
/// Error setting up SMBIOS table
|
||||||
#[error("Error setting up SMBIOS table: {0}")]
|
#[error("Error setting up SMBIOS table")]
|
||||||
SmbiosSetup(#[source] smbios::Error),
|
SmbiosSetup(#[source] smbios::Error),
|
||||||
|
|
||||||
/// Could not find any SGX EPC section
|
/// Could not find any SGX EPC section
|
||||||
@@ -176,15 +176,15 @@ pub enum Error {
|
|||||||
MissingSgxLaunchControlFeature,
|
MissingSgxLaunchControlFeature,
|
||||||
|
|
||||||
/// Error getting supported CPUID through the hypervisor (kvm/mshv) API
|
/// Error getting supported CPUID through the hypervisor (kvm/mshv) API
|
||||||
#[error("Error getting supported CPUID through the hypervisor API: {0}")]
|
#[error("Error getting supported CPUID through the hypervisor API")]
|
||||||
CpuidGetSupported(#[source] HypervisorError),
|
CpuidGetSupported(#[source] HypervisorError),
|
||||||
|
|
||||||
/// Error populating CPUID with KVM HyperV emulation details
|
/// Error populating CPUID with KVM HyperV emulation details
|
||||||
#[error("Error populating CPUID with KVM HyperV emulation details: {0}")]
|
#[error("Error populating CPUID with KVM HyperV emulation details")]
|
||||||
CpuidKvmHyperV(#[source] vmm_sys_util::fam::Error),
|
CpuidKvmHyperV(#[source] vmm_sys_util::fam::Error),
|
||||||
|
|
||||||
/// Error populating CPUID with CPU identification
|
/// Error populating CPUID with CPU identification
|
||||||
#[error("Error populating CPUID with CPU identification: {0}")]
|
#[error("Error populating CPUID with CPU identification")]
|
||||||
CpuidIdentification(#[source] vmm_sys_util::fam::Error),
|
CpuidIdentification(#[source] vmm_sys_util::fam::Error),
|
||||||
|
|
||||||
/// Error checking CPUID compatibility
|
/// Error checking CPUID compatibility
|
||||||
@@ -192,16 +192,16 @@ pub enum Error {
|
|||||||
CpuidCheckCompatibility,
|
CpuidCheckCompatibility,
|
||||||
|
|
||||||
// Error writing EBDA address
|
// Error writing EBDA address
|
||||||
#[error("Error writing EBDA address: {0}")]
|
#[error("Error writing EBDA address")]
|
||||||
EbdaSetup(#[source] vm_memory::GuestMemoryError),
|
EbdaSetup(#[source] vm_memory::GuestMemoryError),
|
||||||
|
|
||||||
// Error getting CPU TSC frequency
|
// Error getting CPU TSC frequency
|
||||||
#[error("Error getting CPU TSC frequency: {0}")]
|
#[error("Error getting CPU TSC frequency")]
|
||||||
GetTscFrequency(#[source] HypervisorCpuError),
|
GetTscFrequency(#[source] HypervisorCpuError),
|
||||||
|
|
||||||
/// Error retrieving TDX capabilities through the hypervisor (kvm/mshv) API
|
/// Error retrieving TDX capabilities through the hypervisor (kvm/mshv) API
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
#[error("Error retrieving TDX capabilities through the hypervisor API: {0}")]
|
#[error("Error retrieving TDX capabilities through the hypervisor API")]
|
||||||
TdxCapabilities(#[source] HypervisorError),
|
TdxCapabilities(#[source] HypervisorError),
|
||||||
|
|
||||||
/// Failed to configure E820 map for bzImage
|
/// Failed to configure E820 map for bzImage
|
||||||
@@ -209,12 +209,6 @@ pub enum Error {
|
|||||||
E820Configuration,
|
E820Configuration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for super::Error {
|
|
||||||
fn from(e: Error) -> super::Error {
|
|
||||||
super::Error::PlatformSpecific(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_x2apic_id(cpu_id: u32, topology: Option<(u8, u8, u8)>) -> u32 {
|
pub fn get_x2apic_id(cpu_id: u32, topology: Option<(u8, u8, u8)>) -> u32 {
|
||||||
if let Some(t) = topology {
|
if let Some(t) = topology {
|
||||||
let thread_mask_width = u8::BITS - (t.0 - 1).leading_zeros();
|
let thread_mask_width = u8::BITS - (t.0 - 1).leading_zeros();
|
||||||
@@ -888,7 +882,7 @@ pub fn configure_vcpu(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for c in &cpuid {
|
for c in &cpuid {
|
||||||
info!("{}", c);
|
debug!("{}", c);
|
||||||
}
|
}
|
||||||
|
|
||||||
vcpu.set_cpuid2(&cpuid)
|
vcpu.set_cpuid2(&cpuid)
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
use vm_memory::ByteValued;
|
||||||
|
|
||||||
pub const MP_PROCESSOR: ::std::os::raw::c_uint = 0;
|
pub const MP_PROCESSOR: ::std::os::raw::c_uint = 0;
|
||||||
pub const MP_BUS: ::std::os::raw::c_uint = 1;
|
pub const MP_BUS: ::std::os::raw::c_uint = 1;
|
||||||
@@ -29,6 +31,13 @@ pub struct mpf_intel {
|
|||||||
pub feature5: ::std::os::raw::c_uchar,
|
pub feature5: ::std::os::raw::c_uchar,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(::core::mem::size_of::<mpf_intel>() == 16);
|
||||||
|
// SAFETY: all members of this struct are plain integers
|
||||||
|
// and the sum of their sizes is the size of the struct, so
|
||||||
|
// padding and reserved values are not possible as there
|
||||||
|
// would be nowhere for them to exist.
|
||||||
|
unsafe impl ByteValued for mpf_intel {}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
pub struct mpc_table {
|
pub struct mpc_table {
|
||||||
@@ -45,6 +54,19 @@ pub struct mpc_table {
|
|||||||
pub reserved: ::std::os::raw::c_uint,
|
pub reserved: ::std::os::raw::c_uint,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _: () = {
|
||||||
|
assert!(::core::mem::size_of::<mpc_table>() == 4 + 2 + 1 + 1 + 8 + 12 + 4 + 2 + 2 + 4 + 4);
|
||||||
|
assert!(::core::mem::size_of::<::std::os::raw::c_uint>() == 4);
|
||||||
|
assert!(::core::mem::size_of::<::std::os::raw::c_ushort>() == 2);
|
||||||
|
assert!(::core::mem::size_of::<::std::os::raw::c_uchar>() == 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// SAFETY: all members of this struct are plain integers
|
||||||
|
// and the sum of their sizes is the size of the struct, so
|
||||||
|
// padding and reserved values are not possible as there
|
||||||
|
// would be nowhere for them to exist.
|
||||||
|
unsafe impl ByteValued for mpc_table {}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
pub struct mpc_cpu {
|
pub struct mpc_cpu {
|
||||||
@@ -57,6 +79,13 @@ pub struct mpc_cpu {
|
|||||||
pub reserved: [::std::os::raw::c_uint; 2usize],
|
pub reserved: [::std::os::raw::c_uint; 2usize],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(::core::mem::size_of::<mpc_cpu>() == 20);
|
||||||
|
// SAFETY: all members of this struct are plain integers
|
||||||
|
// and the sum of their sizes is the size of the struct, so
|
||||||
|
// padding and reserved values are not possible as there
|
||||||
|
// would be nowhere for them to exist.
|
||||||
|
unsafe impl ByteValued for mpc_cpu {}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
pub struct mpc_bus {
|
pub struct mpc_bus {
|
||||||
@@ -65,6 +94,13 @@ pub struct mpc_bus {
|
|||||||
pub bustype: [::std::os::raw::c_uchar; 6usize],
|
pub bustype: [::std::os::raw::c_uchar; 6usize],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(::core::mem::size_of::<mpc_bus>() == 8);
|
||||||
|
// SAFETY: all members of this struct are plain integers
|
||||||
|
// and the sum of their sizes is the size of the struct, so
|
||||||
|
// padding and reserved values are not possible as there
|
||||||
|
// would be nowhere for them to exist.
|
||||||
|
unsafe impl ByteValued for mpc_bus {}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
pub struct mpc_ioapic {
|
pub struct mpc_ioapic {
|
||||||
@@ -75,6 +111,13 @@ pub struct mpc_ioapic {
|
|||||||
pub apicaddr: ::std::os::raw::c_uint,
|
pub apicaddr: ::std::os::raw::c_uint,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(::core::mem::size_of::<mpc_ioapic>() == 8);
|
||||||
|
// SAFETY: all members of this struct are plain integers
|
||||||
|
// and the sum of their sizes is the size of the struct, so
|
||||||
|
// padding and reserved values are not possible as there
|
||||||
|
// would be nowhere for them to exist.
|
||||||
|
unsafe impl ByteValued for mpc_ioapic {}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
pub struct mpc_intsrc {
|
pub struct mpc_intsrc {
|
||||||
@@ -87,6 +130,13 @@ pub struct mpc_intsrc {
|
|||||||
pub dstirq: ::std::os::raw::c_uchar,
|
pub dstirq: ::std::os::raw::c_uchar,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(::core::mem::size_of::<mpc_intsrc>() == 8);
|
||||||
|
// SAFETY: all members of this struct are plain integers
|
||||||
|
// and the sum of their sizes is the size of the struct, so
|
||||||
|
// padding and reserved values are not possible as there
|
||||||
|
// would be nowhere for them to exist.
|
||||||
|
unsafe impl ByteValued for mpc_intsrc {}
|
||||||
|
|
||||||
pub const MP_IRQ_SOURCE_TYPES_MP_INT: ::std::os::raw::c_uint = 0;
|
pub const MP_IRQ_SOURCE_TYPES_MP_INT: ::std::os::raw::c_uint = 0;
|
||||||
pub const MP_IRQ_SOURCE_TYPES_MP_NMI: ::std::os::raw::c_uint = 1;
|
pub const MP_IRQ_SOURCE_TYPES_MP_NMI: ::std::os::raw::c_uint = 1;
|
||||||
pub const MP_IRQ_SOURCE_TYPES_MP_EXT_INT: ::std::os::raw::c_uint = 3;
|
pub const MP_IRQ_SOURCE_TYPES_MP_EXT_INT: ::std::os::raw::c_uint = 3;
|
||||||
@@ -103,6 +153,13 @@ pub struct mpc_lintsrc {
|
|||||||
pub destapiclint: ::std::os::raw::c_uchar,
|
pub destapiclint: ::std::os::raw::c_uchar,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(::core::mem::size_of::<mpc_lintsrc>() == 8);
|
||||||
|
// SAFETY: all members of this struct are plain integers
|
||||||
|
// and the sum of their sizes is the size of the struct, so
|
||||||
|
// padding and reserved values are not possible as there
|
||||||
|
// would be nowhere for them to exist.
|
||||||
|
unsafe impl ByteValued for mpc_lintsrc {}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
pub struct mpc_oemtable {
|
pub struct mpc_oemtable {
|
||||||
@@ -112,3 +169,10 @@ pub struct mpc_oemtable {
|
|||||||
pub checksum: ::std::os::raw::c_uchar,
|
pub checksum: ::std::os::raw::c_uchar,
|
||||||
pub mpc: [::std::os::raw::c_uchar; 8usize],
|
pub mpc: [::std::os::raw::c_uchar; 8usize],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(::core::mem::size_of::<mpc_oemtable>() == 16);
|
||||||
|
// SAFETY: all members of this struct are plain integers
|
||||||
|
// and the sum of their sizes is the size of the struct, so
|
||||||
|
// padding and reserved values are not possible as there
|
||||||
|
// would be nowhere for them to exist.
|
||||||
|
unsafe impl ByteValued for mpc_oemtable {}
|
||||||
|
|||||||
@@ -59,31 +59,31 @@ pub enum Error {
|
|||||||
#[error("The MP table has too little address space to be stored")]
|
#[error("The MP table has too little address space to be stored")]
|
||||||
AddressOverflow,
|
AddressOverflow,
|
||||||
/// Failure while zeroing out the memory for the MP table.
|
/// Failure while zeroing out the memory for the MP table.
|
||||||
#[error("Failure while zeroing out the memory for the MP table: {0}")]
|
#[error("Failure while zeroing out the memory for the MP table")]
|
||||||
Clear(#[source] GuestMemoryError),
|
Clear(#[source] GuestMemoryError),
|
||||||
/// Number of CPUs exceeds the maximum supported CPUs
|
/// Number of CPUs exceeds the maximum supported CPUs
|
||||||
#[error("Number of CPUs exceeds the maximum supported CPUs")]
|
#[error("Number of CPUs exceeds the maximum supported CPUs")]
|
||||||
TooManyCpus,
|
TooManyCpus,
|
||||||
/// Failure to write the MP floating pointer.
|
/// Failure to write the MP floating pointer.
|
||||||
#[error("Failure to write the MP floating pointer: {0}")]
|
#[error("Failure to write the MP floating pointer")]
|
||||||
WriteMpfIntel(#[source] GuestMemoryError),
|
WriteMpfIntel(#[source] GuestMemoryError),
|
||||||
/// Failure to write MP CPU entry.
|
/// Failure to write MP CPU entry.
|
||||||
#[error("Failure to write MP CPU entry: {0}")]
|
#[error("Failure to write MP CPU entry")]
|
||||||
WriteMpcCpu(#[source] GuestMemoryError),
|
WriteMpcCpu(#[source] GuestMemoryError),
|
||||||
/// Failure to write MP ioapic entry.
|
/// Failure to write MP ioapic entry.
|
||||||
#[error("Failure to write MP ioapic entry: {0}")]
|
#[error("Failure to write MP ioapic entry")]
|
||||||
WriteMpcIoapic(#[source] GuestMemoryError),
|
WriteMpcIoapic(#[source] GuestMemoryError),
|
||||||
/// Failure to write MP bus entry.
|
/// Failure to write MP bus entry.
|
||||||
#[error("Failure to write MP bus entry: {0}")]
|
#[error("Failure to write MP bus entry")]
|
||||||
WriteMpcBus(#[source] GuestMemoryError),
|
WriteMpcBus(#[source] GuestMemoryError),
|
||||||
/// Failure to write MP interrupt source entry.
|
/// Failure to write MP interrupt source entry.
|
||||||
#[error("Failure to write MP interrupt source entry: {0}")]
|
#[error("Failure to write MP interrupt source entry")]
|
||||||
WriteMpcIntsrc(#[source] GuestMemoryError),
|
WriteMpcIntsrc(#[source] GuestMemoryError),
|
||||||
/// Failure to write MP local interrupt source entry.
|
/// Failure to write MP local interrupt source entry.
|
||||||
#[error("Failure to write MP local interrupt source entry: {0}")]
|
#[error("Failure to write MP local interrupt source entry")]
|
||||||
WriteMpcLintsrc(#[source] GuestMemoryError),
|
WriteMpcLintsrc(#[source] GuestMemoryError),
|
||||||
/// Failure to write MP table header.
|
/// Failure to write MP table header.
|
||||||
#[error("Failure to write MP table header: {0}")]
|
#[error("Failure to write MP table header")]
|
||||||
WriteMpcTable(#[source] GuestMemoryError),
|
WriteMpcTable(#[source] GuestMemoryError),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ const CPU_STEPPING: u32 = 0x600;
|
|||||||
const CPU_FEATURE_APIC: u32 = 0x200;
|
const CPU_FEATURE_APIC: u32 = 0x200;
|
||||||
const CPU_FEATURE_FPU: u32 = 0x001;
|
const CPU_FEATURE_FPU: u32 = 0x001;
|
||||||
|
|
||||||
fn compute_checksum<T: Copy>(v: &T) -> u8 {
|
fn compute_checksum<T: Copy + ByteValued>(v: &T) -> u8 {
|
||||||
// SAFETY: we are only reading the bytes within the size of the `T` reference `v`.
|
// SAFETY: we are only reading the bytes within the size of the `T` reference `v`.
|
||||||
let v_slice = unsafe { slice::from_raw_parts(v as *const T as *const u8, mem::size_of::<T>()) };
|
let v_slice = unsafe { slice::from_raw_parts(v as *const T as *const u8, mem::size_of::<T>()) };
|
||||||
let mut checksum: u8 = 0;
|
let mut checksum: u8 = 0;
|
||||||
|
|||||||
@@ -23,40 +23,40 @@ use crate::{EntryPoint, GuestMemoryMmap};
|
|||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Failed to get SREGs for this CPU.
|
/// Failed to get SREGs for this CPU.
|
||||||
#[error("Failed to get SREGs for this CPU: {0}")]
|
#[error("Failed to get SREGs for this CPU")]
|
||||||
GetStatusRegisters(#[source] hypervisor::HypervisorCpuError),
|
GetStatusRegisters(#[source] hypervisor::HypervisorCpuError),
|
||||||
/// Failed to set base registers for this CPU.
|
/// Failed to set base registers for this CPU.
|
||||||
#[error("Failed to set base registers for this CPU: {0}")]
|
#[error("Failed to set base registers for this CPU")]
|
||||||
SetBaseRegisters(#[source] hypervisor::HypervisorCpuError),
|
SetBaseRegisters(#[source] hypervisor::HypervisorCpuError),
|
||||||
/// Failed to configure the FPU.
|
/// Failed to configure the FPU.
|
||||||
#[error("Failed to configure the FPU: {0}")]
|
#[error("Failed to configure the FPU")]
|
||||||
SetFpuRegisters(#[source] hypervisor::HypervisorCpuError),
|
SetFpuRegisters(#[source] hypervisor::HypervisorCpuError),
|
||||||
/// Setting up MSRs failed.
|
/// Setting up MSRs failed.
|
||||||
#[error("Setting up MSRs failed: {0}")]
|
#[error("Setting up MSRs failed")]
|
||||||
SetModelSpecificRegisters(#[source] hypervisor::HypervisorCpuError),
|
SetModelSpecificRegisters(#[source] hypervisor::HypervisorCpuError),
|
||||||
/// Failed to set SREGs for this CPU.
|
/// Failed to set SREGs for this CPU.
|
||||||
#[error("Failed to set SREGs for this CPU: {0}")]
|
#[error("Failed to set SREGs for this CPU")]
|
||||||
SetStatusRegisters(#[source] hypervisor::HypervisorCpuError),
|
SetStatusRegisters(#[source] hypervisor::HypervisorCpuError),
|
||||||
/// Checking the GDT address failed.
|
/// Checking the GDT address failed.
|
||||||
#[error("Checking the GDT address failed")]
|
#[error("Checking the GDT address failed")]
|
||||||
CheckGdtAddr,
|
CheckGdtAddr,
|
||||||
/// Writing the GDT to RAM failed.
|
/// Writing the GDT to RAM failed.
|
||||||
#[error("Writing the GDT to RAM failed: {0}")]
|
#[error("Writing the GDT to RAM failed")]
|
||||||
WriteGdt(#[source] GuestMemoryError),
|
WriteGdt(#[source] GuestMemoryError),
|
||||||
/// Writing the IDT to RAM failed.
|
/// Writing the IDT to RAM failed.
|
||||||
#[error("Writing the IDT to RAM failed: {0}")]
|
#[error("Writing the IDT to RAM failed")]
|
||||||
WriteIdt(#[source] GuestMemoryError),
|
WriteIdt(#[source] GuestMemoryError),
|
||||||
/// Writing PDPTE to RAM failed.
|
/// Writing PDPTE to RAM failed.
|
||||||
#[error("Writing PDPTE to RAM failed: {0}")]
|
#[error("Writing PDPTE to RAM failed")]
|
||||||
WritePdpteAddress(#[source] GuestMemoryError),
|
WritePdpteAddress(#[source] GuestMemoryError),
|
||||||
/// Writing PDE to RAM failed.
|
/// Writing PDE to RAM failed.
|
||||||
#[error("Writing PDE to RAM failed: {0}")]
|
#[error("Writing PDE to RAM failed")]
|
||||||
WritePdeAddress(#[source] GuestMemoryError),
|
WritePdeAddress(#[source] GuestMemoryError),
|
||||||
/// Writing PML4 to RAM failed.
|
/// Writing PML4 to RAM failed.
|
||||||
#[error("Writing PML4 to RAM failed: {0}")]
|
#[error("Writing PML4 to RAM failed")]
|
||||||
WritePml4Address(#[source] GuestMemoryError),
|
WritePml4Address(#[source] GuestMemoryError),
|
||||||
/// Writing PML5 to RAM failed.
|
/// Writing PML5 to RAM failed.
|
||||||
#[error("Writing PML5 to RAM failed: {0}")]
|
#[error("Writing PML5 to RAM failed")]
|
||||||
WritePml5Address(#[source] GuestMemoryError),
|
WritePml5Address(#[source] GuestMemoryError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ pub enum Error {
|
|||||||
#[error("Failure to write additional data to memory")]
|
#[error("Failure to write additional data to memory")]
|
||||||
WriteData,
|
WriteData,
|
||||||
/// Failure to parse uuid, uuid format may be error
|
/// Failure to parse uuid, uuid format may be error
|
||||||
#[error("Failure to parse uuid: {0}")]
|
#[error("Failure to parse uuid")]
|
||||||
ParseUuid(#[source] uuid::Error),
|
ParseUuid(#[source] uuid::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ use crate::GuestMemoryMmap;
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum TdvfError {
|
pub enum TdvfError {
|
||||||
#[error("Failed read TDVF descriptor: {0}")]
|
#[error("Failed read TDVF descriptor")]
|
||||||
ReadDescriptor(#[source] std::io::Error),
|
ReadDescriptor(#[source] std::io::Error),
|
||||||
#[error("Failed read TDVF descriptor offset: {0}")]
|
#[error("Failed read TDVF descriptor offset")]
|
||||||
ReadDescriptorOffset(#[source] std::io::Error),
|
ReadDescriptorOffset(#[source] std::io::Error),
|
||||||
#[error("Failed read GUID table: {0}")]
|
#[error("Failed read GUID table")]
|
||||||
ReadGuidTable(#[source] std::io::Error),
|
ReadGuidTable(#[source] std::io::Error),
|
||||||
#[error("Invalid descriptor signature")]
|
#[error("Invalid descriptor signature")]
|
||||||
InvalidDescriptorSignature,
|
InvalidDescriptorSignature,
|
||||||
@@ -25,9 +25,9 @@ pub enum TdvfError {
|
|||||||
InvalidDescriptorSize,
|
InvalidDescriptorSize,
|
||||||
#[error("Invalid descriptor version")]
|
#[error("Invalid descriptor version")]
|
||||||
InvalidDescriptorVersion,
|
InvalidDescriptorVersion,
|
||||||
#[error("Failed to write HOB details to guest memory: {0}")]
|
#[error("Failed to write HOB details to guest memory")]
|
||||||
GuestMemoryWriteHob(#[source] GuestMemoryError),
|
GuestMemoryWriteHob(#[source] GuestMemoryError),
|
||||||
#[error("Failed to create Uuid: {0}")]
|
#[error("Failed to create Uuid")]
|
||||||
UuidCreation(#[source] uuid::Error),
|
UuidCreation(#[source] uuid::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,16 +10,16 @@ io_uring = ["dep:io-uring"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.5.0"
|
byteorder = "1.5.0"
|
||||||
crc-any = "2.4.4"
|
crc-any = "2.5.0"
|
||||||
io-uring = { version = "0.6.4", optional = true }
|
io-uring = { version = "0.6.4", optional = true }
|
||||||
libc = "0.2.167"
|
libc = "0.2.167"
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
remain = "0.2.14"
|
remain = "0.2.15"
|
||||||
serde = { version = "1.0.208", features = ["derive"] }
|
serde = { version = "1.0.208", features = ["derive"] }
|
||||||
smallvec = "1.13.2"
|
smallvec = "1.13.2"
|
||||||
thiserror = "2.0.6"
|
thiserror = { workspace = true }
|
||||||
uuid = { version = "1.12.1", features = ["v4"] }
|
uuid = { workspace = true, features = ["v4"] }
|
||||||
virtio-bindings = { workspace = true, features = ["virtio-v5_0_0"] }
|
virtio-bindings = { workspace = true }
|
||||||
virtio-queue = { workspace = true }
|
virtio-queue = { workspace = true }
|
||||||
vm-memory = { workspace = true, features = [
|
vm-memory = { workspace = true, features = [
|
||||||
"backend-atomic",
|
"backend-atomic",
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ use crate::DiskTopology;
|
|||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum DiskFileError {
|
pub enum DiskFileError {
|
||||||
/// Failed getting disk file size.
|
/// Failed getting disk file size.
|
||||||
#[error("Failed getting disk file size: {0}")]
|
#[error("Failed getting disk file size")]
|
||||||
Size(#[source] std::io::Error),
|
Size(#[source] std::io::Error),
|
||||||
/// Failed creating a new AsyncIo.
|
/// Failed creating a new AsyncIo.
|
||||||
#[error("Failed creating a new AsyncIo: {0}")]
|
#[error("Failed creating a new AsyncIo")]
|
||||||
NewAsyncIo(#[source] std::io::Error),
|
NewAsyncIo(#[source] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,19 +65,19 @@ pub trait DiskFile: Send {
|
|||||||
///
|
///
|
||||||
/// The file descriptor is supposed to be used for `fcntl()` calls but no
|
/// The file descriptor is supposed to be used for `fcntl()` calls but no
|
||||||
/// other operation.
|
/// other operation.
|
||||||
fn fd(&mut self) -> BorrowedDiskFd;
|
fn fd(&mut self) -> BorrowedDiskFd<'_>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum AsyncIoError {
|
pub enum AsyncIoError {
|
||||||
/// Failed vectored reading from file.
|
/// Failed vectored reading from file.
|
||||||
#[error("Failed vectored reading from file: {0}")]
|
#[error("Failed vectored reading from file")]
|
||||||
ReadVectored(#[source] std::io::Error),
|
ReadVectored(#[source] std::io::Error),
|
||||||
/// Failed vectored writing to file.
|
/// Failed vectored writing to file.
|
||||||
#[error("Failed vectored writing to file: {0}")]
|
#[error("Failed vectored writing to file")]
|
||||||
WriteVectored(#[source] std::io::Error),
|
WriteVectored(#[source] std::io::Error),
|
||||||
/// Failed synchronizing file.
|
/// Failed synchronizing file.
|
||||||
#[error("Failed synchronizing file: {0}")]
|
#[error("Failed synchronizing file")]
|
||||||
Fsync(#[source] std::io::Error),
|
Fsync(#[source] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ pub enum LockError {
|
|||||||
#[error("The file is already locked")]
|
#[error("The file is already locked")]
|
||||||
AlreadyLocked,
|
AlreadyLocked,
|
||||||
/// IO error.
|
/// IO error.
|
||||||
#[error("The lock state could not be checked or set: {0}")]
|
#[error("The lock state could not be checked or set")]
|
||||||
Io(#[source] io::Error),
|
Io(#[source] io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ impl DiskFile for FixedVhdDiskAsync {
|
|||||||
) as Box<dyn AsyncIo>)
|
) as Box<dyn AsyncIo>)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd(&mut self) -> BorrowedDiskFd {
|
fn fd(&mut self) -> BorrowedDiskFd<'_> {
|
||||||
BorrowedDiskFd::new(self.0.as_raw_fd())
|
BorrowedDiskFd::new(self.0.as_raw_fd())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ impl DiskFile for FixedVhdDiskSync {
|
|||||||
) as Box<dyn AsyncIo>)
|
) as Box<dyn AsyncIo>)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd(&mut self) -> BorrowedDiskFd {
|
fn fd(&mut self) -> BorrowedDiskFd<'_> {
|
||||||
BorrowedDiskFd::new(self.0.as_raw_fd())
|
BorrowedDiskFd::new(self.0.as_raw_fd())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ use vm_memory::{
|
|||||||
};
|
};
|
||||||
use vm_virtio::{AccessPlatform, Translatable};
|
use vm_virtio::{AccessPlatform, Translatable};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
use vmm_sys_util::{aio, ioctl_io_nr, ioctl_ioc_nr};
|
use vmm_sys_util::{aio, ioctl_io_nr};
|
||||||
|
|
||||||
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult};
|
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult};
|
||||||
use crate::vhdx::VhdxError;
|
use crate::vhdx::VhdxError;
|
||||||
@@ -79,21 +79,21 @@ pub enum Error {
|
|||||||
DescriptorChainTooShort,
|
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,
|
DescriptorLengthTooSmall,
|
||||||
#[error("Failed to detect image type: {0}")]
|
#[error("Failed to detect image type")]
|
||||||
DetectImageType(#[source] std::io::Error),
|
DetectImageType(#[source] std::io::Error),
|
||||||
#[error("Failure in fixed vhd: {0}")]
|
#[error("Failure in fixed vhd")]
|
||||||
FixedVhdError(#[source] std::io::Error),
|
FixedVhdError(#[source] std::io::Error),
|
||||||
#[error("Getting a block's metadata fails for any reason")]
|
#[error("Getting a block's metadata fails for any reason")]
|
||||||
GetFileMetadata,
|
GetFileMetadata,
|
||||||
#[error("The requested operation would cause a seek beyond disk end")]
|
#[error("The requested operation would cause a seek beyond disk end")]
|
||||||
InvalidOffset,
|
InvalidOffset,
|
||||||
#[error("Failure in qcow: {0}")]
|
#[error("Failure in qcow")]
|
||||||
QcowError(#[source] qcow::Error),
|
QcowError(#[source] qcow::Error),
|
||||||
#[error("Failure in raw file: {0}")]
|
#[error("Failure in raw file")]
|
||||||
RawFileError(#[source] std::io::Error),
|
RawFileError(#[source] std::io::Error),
|
||||||
#[error("The requested operation does not support multiple descriptors")]
|
#[error("The requested operation does not support multiple descriptors")]
|
||||||
TooManyDescriptors,
|
TooManyDescriptors,
|
||||||
#[error("Failure in vhdx: {0}")]
|
#[error("Failure in vhdx")]
|
||||||
VhdxError(#[source] VhdxError),
|
VhdxError(#[source] VhdxError),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,33 +131,33 @@ pub fn build_serial(disk_path: &Path) -> Vec<u8> {
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum ExecuteError {
|
pub enum ExecuteError {
|
||||||
#[error("Bad request: {0}")]
|
#[error("Bad request")]
|
||||||
BadRequest(#[source] Error),
|
BadRequest(#[source] Error),
|
||||||
#[error("Failed to flush: {0}")]
|
#[error("Failed to flush")]
|
||||||
Flush(#[source] io::Error),
|
Flush(#[source] io::Error),
|
||||||
#[error("Failed to read: {0}")]
|
#[error("Failed to read")]
|
||||||
Read(#[source] GuestMemoryError),
|
Read(#[source] GuestMemoryError),
|
||||||
#[error("Failed to read_exact: {0}")]
|
#[error("Failed to read_exact")]
|
||||||
ReadExact(#[source] io::Error),
|
ReadExact(#[source] io::Error),
|
||||||
#[error("Failed to seek: {0}")]
|
#[error("Failed to seek")]
|
||||||
Seek(#[source] io::Error),
|
Seek(#[source] io::Error),
|
||||||
#[error("Failed to write: {0}")]
|
#[error("Failed to write")]
|
||||||
Write(#[source] GuestMemoryError),
|
Write(#[source] GuestMemoryError),
|
||||||
#[error("Failed to write_all: {0}")]
|
#[error("Failed to write_all")]
|
||||||
WriteAll(#[source] io::Error),
|
WriteAll(#[source] io::Error),
|
||||||
#[error("Unsupported request: {0}")]
|
#[error("Unsupported request: {0}")]
|
||||||
Unsupported(u32),
|
Unsupported(u32),
|
||||||
#[error("Failed to submit io uring: {0}")]
|
#[error("Failed to submit io uring")]
|
||||||
SubmitIoUring(#[source] io::Error),
|
SubmitIoUring(#[source] io::Error),
|
||||||
#[error("Failed to get guest address: {0}")]
|
#[error("Failed to get guest address")]
|
||||||
GetHostAddress(#[source] GuestMemoryError),
|
GetHostAddress(#[source] GuestMemoryError),
|
||||||
#[error("Failed to async read: {0}")]
|
#[error("Failed to async read")]
|
||||||
AsyncRead(#[source] AsyncIoError),
|
AsyncRead(#[source] AsyncIoError),
|
||||||
#[error("Failed to async write: {0}")]
|
#[error("Failed to async write")]
|
||||||
AsyncWrite(#[source] AsyncIoError),
|
AsyncWrite(#[source] AsyncIoError),
|
||||||
#[error("failed to async flush: {0}")]
|
#[error("failed to async flush")]
|
||||||
AsyncFlush(#[source] AsyncIoError),
|
AsyncFlush(#[source] AsyncIoError),
|
||||||
#[error("Failed allocating a temporary buffer: {0}")]
|
#[error("Failed allocating a temporary buffer")]
|
||||||
TemporaryBufferAllocation(#[source] io::Error),
|
TemporaryBufferAllocation(#[source] io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,14 +401,20 @@ impl Request {
|
|||||||
|
|
||||||
let mut iovecs: SmallVec<[libc::iovec; DEFAULT_DESCRIPTOR_VEC_SIZE]> =
|
let mut iovecs: SmallVec<[libc::iovec; DEFAULT_DESCRIPTOR_VEC_SIZE]> =
|
||||||
SmallVec::with_capacity(self.data_descriptors.len());
|
SmallVec::with_capacity(self.data_descriptors.len());
|
||||||
for (data_addr, data_len) in &self.data_descriptors {
|
for &(data_addr, data_len) in &self.data_descriptors {
|
||||||
if *data_len == 0 {
|
let _: u32 = data_len; // compiler-checked documentation
|
||||||
|
const _: () = assert!(
|
||||||
|
core::mem::size_of::<u32>() <= core::mem::size_of::<usize>(),
|
||||||
|
"unsupported platform"
|
||||||
|
);
|
||||||
|
if data_len == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut top: u64 = u64::from(*data_len) / SECTOR_SIZE;
|
let mut top: u64 = u64::from(data_len) / SECTOR_SIZE;
|
||||||
if u64::from(*data_len) % SECTOR_SIZE != 0 {
|
if u64::from(data_len) % SECTOR_SIZE != 0 {
|
||||||
top += 1;
|
top += 1;
|
||||||
}
|
}
|
||||||
|
let data_len = data_len as usize;
|
||||||
top = top
|
top = top
|
||||||
.checked_add(sector)
|
.checked_add(sector)
|
||||||
.ok_or(ExecuteError::BadRequest(Error::InvalidOffset))?;
|
.ok_or(ExecuteError::BadRequest(Error::InvalidOffset))?;
|
||||||
@@ -417,7 +423,7 @@ impl Request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let origin_ptr = mem
|
let origin_ptr = mem
|
||||||
.get_slice(*data_addr, *data_len as usize)
|
.get_slice(data_addr, data_len)
|
||||||
.map_err(ExecuteError::GetHostAddress)?
|
.map_err(ExecuteError::GetHostAddress)?
|
||||||
.ptr_guard();
|
.ptr_guard();
|
||||||
|
|
||||||
@@ -426,8 +432,7 @@ impl Request {
|
|||||||
// created with the correct alignment, and a copy from/to the
|
// created with the correct alignment, and a copy from/to the
|
||||||
// origin buffer is performed, depending on the type of operation.
|
// origin buffer is performed, depending on the type of operation.
|
||||||
let iov_base = if (origin_ptr.as_ptr() as u64) % SECTOR_SIZE != 0 {
|
let iov_base = if (origin_ptr.as_ptr() as u64) % SECTOR_SIZE != 0 {
|
||||||
let layout =
|
let layout = Layout::from_size_align(data_len, SECTOR_SIZE as usize).unwrap();
|
||||||
Layout::from_size_align(*data_len as usize, SECTOR_SIZE as usize).unwrap();
|
|
||||||
// SAFETY: layout has non-zero size
|
// SAFETY: layout has non-zero size
|
||||||
let aligned_ptr = unsafe { alloc_zeroed(layout) };
|
let aligned_ptr = unsafe { alloc_zeroed(layout) };
|
||||||
if aligned_ptr.is_null() {
|
if aligned_ptr.is_null() {
|
||||||
@@ -441,7 +446,7 @@ impl Request {
|
|||||||
if request_type == RequestType::Out {
|
if request_type == RequestType::Out {
|
||||||
// SAFETY: destination buffer has been allocated with
|
// SAFETY: destination buffer has been allocated with
|
||||||
// the proper size.
|
// the proper size.
|
||||||
unsafe { std::ptr::copy(origin_ptr.as_ptr(), aligned_ptr, *data_len as usize) };
|
unsafe { std::ptr::copy(origin_ptr.as_ptr(), aligned_ptr, data_len) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store both origin and aligned pointers for complete_async()
|
// Store both origin and aligned pointers for complete_async()
|
||||||
@@ -449,7 +454,7 @@ impl Request {
|
|||||||
self.aligned_operations.push(AlignedOperation {
|
self.aligned_operations.push(AlignedOperation {
|
||||||
origin_ptr: origin_ptr.as_ptr() as u64,
|
origin_ptr: origin_ptr.as_ptr() as u64,
|
||||||
aligned_ptr: aligned_ptr as u64,
|
aligned_ptr: aligned_ptr as u64,
|
||||||
size: *data_len as usize,
|
size: data_len,
|
||||||
layout,
|
layout,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -460,7 +465,7 @@ impl Request {
|
|||||||
|
|
||||||
let iovec = libc::iovec {
|
let iovec = libc::iovec {
|
||||||
iov_base,
|
iov_base,
|
||||||
iov_len: *data_len as libc::size_t,
|
iov_len: data_len as libc::size_t,
|
||||||
};
|
};
|
||||||
iovecs.push(iovec);
|
iovecs.push(iovec);
|
||||||
}
|
}
|
||||||
@@ -744,7 +749,7 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&mut self) -> MutexGuard<F>;
|
fn file(&mut self) -> MutexGuard<'_, F>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ImageType {
|
pub enum ImageType {
|
||||||
|
|||||||
@@ -36,23 +36,23 @@ const MAX_NESTING_DEPTH: u32 = 10;
|
|||||||
#[sorted]
|
#[sorted]
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Backing file io error: {0}")]
|
#[error("Backing file io error")]
|
||||||
BackingFileIo(#[source] io::Error),
|
BackingFileIo(#[source] io::Error),
|
||||||
#[error("Backing file open error: {0}")]
|
#[error("Backing file open error")]
|
||||||
BackingFileOpen(#[source] Box<Error>),
|
BackingFileOpen(#[source] Box<Error>),
|
||||||
#[error("Backing file name is too long: {0} bytes over")]
|
#[error("Backing file name is too long: {0} bytes over")]
|
||||||
BackingFileTooLong(usize),
|
BackingFileTooLong(usize),
|
||||||
#[error("Compressed blocks not supported")]
|
#[error("Compressed blocks not supported")]
|
||||||
CompressedBlocksNotSupported,
|
CompressedBlocksNotSupported,
|
||||||
#[error("Failed to evict cache: {0}")]
|
#[error("Failed to evict cache")]
|
||||||
EvictingCache(#[source] io::Error),
|
EvictingCache(#[source] io::Error),
|
||||||
#[error("File larger than max of {MAX_QCOW_FILE_SIZE}: {0}")]
|
#[error("File larger than max of {MAX_QCOW_FILE_SIZE}: {0}")]
|
||||||
FileTooBig(u64),
|
FileTooBig(u64),
|
||||||
#[error("Failed to get file size: {0}")]
|
#[error("Failed to get file size")]
|
||||||
GettingFileSize(#[source] io::Error),
|
GettingFileSize(#[source] io::Error),
|
||||||
#[error("Failed to get refcount: {0}")]
|
#[error("Failed to get refcount")]
|
||||||
GettingRefcount(#[source] refcount::Error),
|
GettingRefcount(#[source] refcount::Error),
|
||||||
#[error("Failed to parse filename: {0}")]
|
#[error("Failed to parse filename")]
|
||||||
InvalidBackingFileName(#[source] str::Utf8Error),
|
InvalidBackingFileName(#[source] str::Utf8Error),
|
||||||
#[error("Invalid cluster index")]
|
#[error("Invalid cluster index")]
|
||||||
InvalidClusterIndex,
|
InvalidClusterIndex,
|
||||||
@@ -82,27 +82,27 @@ pub enum Error {
|
|||||||
NotEnoughSpaceForRefcounts,
|
NotEnoughSpaceForRefcounts,
|
||||||
#[error("Failed to open file {0}")]
|
#[error("Failed to open file {0}")]
|
||||||
OpeningFile(#[source] io::Error),
|
OpeningFile(#[source] io::Error),
|
||||||
#[error("Failed to read data: {0}")]
|
#[error("Failed to read data")]
|
||||||
ReadingData(#[source] io::Error),
|
ReadingData(#[source] io::Error),
|
||||||
#[error("Failed to read header: {0}")]
|
#[error("Failed to read header")]
|
||||||
ReadingHeader(#[source] io::Error),
|
ReadingHeader(#[source] io::Error),
|
||||||
#[error("Failed to read pointers: {0}")]
|
#[error("Failed to read pointers")]
|
||||||
ReadingPointers(#[source] io::Error),
|
ReadingPointers(#[source] io::Error),
|
||||||
#[error("Failed to read ref count block: {0}")]
|
#[error("Failed to read ref count block")]
|
||||||
ReadingRefCountBlock(#[source] refcount::Error),
|
ReadingRefCountBlock(#[source] refcount::Error),
|
||||||
#[error("Failed to read ref counts: {0}")]
|
#[error("Failed to read ref counts")]
|
||||||
ReadingRefCounts(#[source] io::Error),
|
ReadingRefCounts(#[source] io::Error),
|
||||||
#[error("Failed to rebuild ref counts: {0}")]
|
#[error("Failed to rebuild ref counts")]
|
||||||
RebuildingRefCounts(#[source] io::Error),
|
RebuildingRefCounts(#[source] io::Error),
|
||||||
#[error("Refcount table offset past file end")]
|
#[error("Refcount table offset past file end")]
|
||||||
RefcountTableOffEnd,
|
RefcountTableOffEnd,
|
||||||
#[error("Too many clusters specified for refcount")]
|
#[error("Too many clusters specified for refcount")]
|
||||||
RefcountTableTooLarge,
|
RefcountTableTooLarge,
|
||||||
#[error("Failed to seek file: {0}")]
|
#[error("Failed to seek file")]
|
||||||
SeekingFile(#[source] io::Error),
|
SeekingFile(#[source] io::Error),
|
||||||
#[error("Failed to set file size: {0}")]
|
#[error("Failed to set file size")]
|
||||||
SettingFileSize(#[source] io::Error),
|
SettingFileSize(#[source] io::Error),
|
||||||
#[error("Failed to set refcount refcount: {0}")]
|
#[error("Failed to set refcount refcount")]
|
||||||
SettingRefcountRefcount(#[source] io::Error),
|
SettingRefcountRefcount(#[source] io::Error),
|
||||||
#[error("Size too small for number of clusters")]
|
#[error("Size too small for number of clusters")]
|
||||||
SizeTooSmallForNumberOfClusters,
|
SizeTooSmallForNumberOfClusters,
|
||||||
@@ -114,9 +114,9 @@ pub enum Error {
|
|||||||
UnsupportedRefcountOrder,
|
UnsupportedRefcountOrder,
|
||||||
#[error("Unsupported version: {0}")]
|
#[error("Unsupported version: {0}")]
|
||||||
UnsupportedVersion(u32),
|
UnsupportedVersion(u32),
|
||||||
#[error("Failed to write data: {0}")]
|
#[error("Failed to write data")]
|
||||||
WritingData(#[source] io::Error),
|
WritingData(#[source] io::Error),
|
||||||
#[error("Failed to write header: {0}")]
|
#[error("Failed to write header")]
|
||||||
WritingHeader(#[source] io::Error),
|
WritingHeader(#[source] io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ impl QcowRawFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reads `count` 64 bit offsets and returns them as a vector.
|
/// Reads `count` 64 bit offsets and returns them as a vector.
|
||||||
/// `mask` optionally ands out some of the bits on the file.
|
/// `mask` optionally `&`s out some of the bits on the file.
|
||||||
pub fn read_pointer_table(
|
pub fn read_pointer_table(
|
||||||
&mut self,
|
&mut self,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
@@ -55,7 +55,7 @@ impl QcowRawFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a cluster's worth of 64 bit offsets and returns them as a vector.
|
/// Reads a cluster's worth of 64 bit offsets and returns them as a vector.
|
||||||
/// `mask` optionally ands out some of the bits on the file.
|
/// `mask` optionally `&`s out some of the bits on the file.
|
||||||
pub fn read_pointer_cluster(&mut self, offset: u64, mask: Option<u64>) -> io::Result<Vec<u64>> {
|
pub fn read_pointer_cluster(&mut self, offset: u64, mask: Option<u64>) -> io::Result<Vec<u64>> {
|
||||||
let count = self.cluster_size / size_of::<u64>() as u64;
|
let count = self.cluster_size / size_of::<u64>() as u64;
|
||||||
self.read_pointer_table(offset, count, mask)
|
self.read_pointer_table(offset, count, mask)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use crate::qcow::vec_cache::{CacheMap, Cacheable, VecCache};
|
|||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// `EvictingCache` - Error writing a refblock from the cache to disk.
|
/// `EvictingCache` - Error writing a refblock from the cache to disk.
|
||||||
#[error("Failed to write a refblock from the cache to disk: {0}")]
|
#[error("Failed to write a refblock from the cache to disk")]
|
||||||
EvictingRefCounts(#[source] io::Error),
|
EvictingRefCounts(#[source] io::Error),
|
||||||
/// `InvalidIndex` - Address requested isn't within the range of the disk.
|
/// `InvalidIndex` - Address requested isn't within the range of the disk.
|
||||||
#[error("Address requested is not within the range of the disk")]
|
#[error("Address requested is not within the range of the disk")]
|
||||||
@@ -27,7 +27,7 @@ pub enum Error {
|
|||||||
#[error("New cluster needs to be allocated for refcounts")]
|
#[error("New cluster needs to be allocated for refcounts")]
|
||||||
NeedNewCluster,
|
NeedNewCluster,
|
||||||
/// `ReadingRefCounts` - Error reading the file into the refcount cache.
|
/// `ReadingRefCounts` - Error reading the file into the refcount cache.
|
||||||
#[error("Failed to read the file into the refcount cache: {0}")]
|
#[error("Failed to read the file into the refcount cache")]
|
||||||
ReadingRefCounts(#[source] io::Error),
|
ReadingRefCounts(#[source] io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ impl<T: Cacheable> CacheMap<T> {
|
|||||||
self.map.get_mut(&index)
|
self.map.get_mut(&index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_mut(&mut self) -> IterMut<usize, T> {
|
pub fn iter_mut(&mut self) -> IterMut<'_, usize, T> {
|
||||||
self.map.iter_mut()
|
self.map.iter_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ impl DiskFile for QcowDiskSync {
|
|||||||
Ok(Box::new(QcowSync::new(self.qcow_file.clone())) as Box<dyn AsyncIo>)
|
Ok(Box::new(QcowSync::new(self.qcow_file.clone())) as Box<dyn AsyncIo>)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd(&mut self) -> BorrowedDiskFd {
|
fn fd(&mut self) -> BorrowedDiskFd<'_> {
|
||||||
let lock = self.qcow_file.lock().unwrap();
|
let lock = self.qcow_file.lock().unwrap();
|
||||||
BorrowedDiskFd::new(lock.as_raw_fd())
|
BorrowedDiskFd::new(lock.as_raw_fd())
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ impl QcowSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncAdaptor<QcowFile> for Arc<Mutex<QcowFile>> {
|
impl AsyncAdaptor<QcowFile> for Arc<Mutex<QcowFile>> {
|
||||||
fn file(&mut self) -> MutexGuard<QcowFile> {
|
fn file(&mut self) -> MutexGuard<'_, QcowFile> {
|
||||||
self.lock().unwrap()
|
self.lock().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ impl DiskFile for RawFileDisk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd(&mut self) -> BorrowedDiskFd {
|
fn fd(&mut self) -> BorrowedDiskFd<'_> {
|
||||||
BorrowedDiskFd::new(self.file.as_raw_fd())
|
BorrowedDiskFd::new(self.file.as_raw_fd())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ impl DiskFile for RawFileDiskAio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd(&mut self) -> BorrowedDiskFd {
|
fn fd(&mut self) -> BorrowedDiskFd<'_> {
|
||||||
BorrowedDiskFd::new(self.file.as_raw_fd())
|
BorrowedDiskFd::new(self.file.as_raw_fd())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ impl DiskFile for RawFileDiskSync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd(&mut self) -> BorrowedDiskFd {
|
fn fd(&mut self) -> BorrowedDiskFd<'_> {
|
||||||
BorrowedDiskFd::new(self.file.as_raw_fd())
|
BorrowedDiskFd::new(self.file.as_raw_fd())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,19 +26,19 @@ mod vhdx_metadata;
|
|||||||
#[sorted]
|
#[sorted]
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum VhdxError {
|
pub enum VhdxError {
|
||||||
#[error("Not a VHDx file: {0}")]
|
#[error("Not a VHDx file")]
|
||||||
NotVhdx(#[source] VhdxHeaderError),
|
NotVhdx(#[source] VhdxHeaderError),
|
||||||
#[error("Failed to parse VHDx header: {0}")]
|
#[error("Failed to parse VHDx header")]
|
||||||
ParseVhdxHeader(#[source] VhdxHeaderError),
|
ParseVhdxHeader(#[source] VhdxHeaderError),
|
||||||
#[error("Failed to parse VHDx metadata: {0}")]
|
#[error("Failed to parse VHDx metadata")]
|
||||||
ParseVhdxMetadata(#[source] VhdxMetadataError),
|
ParseVhdxMetadata(#[source] VhdxMetadataError),
|
||||||
#[error("Failed to parse VHDx region entries: {0}")]
|
#[error("Failed to parse VHDx region entries")]
|
||||||
ParseVhdxRegionEntry(#[source] VhdxHeaderError),
|
ParseVhdxRegionEntry(#[source] VhdxHeaderError),
|
||||||
#[error("Failed reading metadata: {0}")]
|
#[error("Failed reading metadata")]
|
||||||
ReadBatEntry(#[source] VhdxBatError),
|
ReadBatEntry(#[source] VhdxBatError),
|
||||||
#[error("Failed reading sector from disk: {0}")]
|
#[error("Failed reading sector from disk")]
|
||||||
ReadFailed(#[source] VhdxIoError),
|
ReadFailed(#[source] VhdxIoError),
|
||||||
#[error("Failed writing to sector on disk: {0}")]
|
#[error("Failed writing to sector on disk")]
|
||||||
WriteFailed(#[source] VhdxIoError),
|
WriteFailed(#[source] VhdxIoError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ pub enum VhdxBatError {
|
|||||||
InvalidBatEntry,
|
InvalidBatEntry,
|
||||||
#[error("Invalid BAT entry count")]
|
#[error("Invalid BAT entry count")]
|
||||||
InvalidEntryCount,
|
InvalidEntryCount,
|
||||||
#[error("Failed to read BAT entry: {0}")]
|
#[error("Failed to read BAT entry")]
|
||||||
ReadBat(#[source] io::Error),
|
ReadBat(#[source] io::Error),
|
||||||
#[error("Failed to write BAT entry: {0}")]
|
#[error("Failed to write BAT entry")]
|
||||||
WriteBat(#[source] io::Error),
|
WriteBat(#[source] io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ impl DiskFile for VhdxDiskSync {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd(&mut self) -> BorrowedDiskFd {
|
fn fd(&mut self) -> BorrowedDiskFd<'_> {
|
||||||
let lock = self.vhdx_file.lock().unwrap();
|
let lock = self.vhdx_file.lock().unwrap();
|
||||||
BorrowedDiskFd::new(lock.as_raw_fd())
|
BorrowedDiskFd::new(lock.as_raw_fd())
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ impl VhdxSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncAdaptor<Vhdx> for Arc<Mutex<Vhdx>> {
|
impl AsyncAdaptor<Vhdx> for Arc<Mutex<Vhdx>> {
|
||||||
fn file(&mut self) -> MutexGuard<Vhdx> {
|
fn file(&mut self) -> MutexGuard<'_, Vhdx> {
|
||||||
self.lock().unwrap()
|
self.lock().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ log = "0.4.22"
|
|||||||
num_enum = "0.7.2"
|
num_enum = "0.7.2"
|
||||||
pci = { path = "../pci" }
|
pci = { path = "../pci" }
|
||||||
serde = { version = "1.0.208", features = ["derive"] }
|
serde = { version = "1.0.208", features = ["derive"] }
|
||||||
thiserror = "2.0.6"
|
thiserror = { workspace = true }
|
||||||
tpm = { path = "../tpm" }
|
tpm = { path = "../tpm" }
|
||||||
vm-allocator = { path = "../vm-allocator" }
|
vm-allocator = { path = "../vm-allocator" }
|
||||||
vm-device = { path = "../vm-device" }
|
vm-device = { path = "../vm-device" }
|
||||||
|
|||||||
@@ -17,38 +17,38 @@ pub enum Error {
|
|||||||
#[error("Invalid delivery mode")]
|
#[error("Invalid delivery mode")]
|
||||||
InvalidDeliveryMode,
|
InvalidDeliveryMode,
|
||||||
/// Failed creating the interrupt source group.
|
/// Failed creating the interrupt source group.
|
||||||
#[error("Failed creating the interrupt source group: {0}")]
|
#[error("Failed creating the interrupt source group")]
|
||||||
CreateInterruptSourceGroup(#[source] io::Error),
|
CreateInterruptSourceGroup(#[source] io::Error),
|
||||||
/// Failed triggering the interrupt.
|
/// Failed triggering the interrupt.
|
||||||
#[error("Failed triggering the interrupt: {0}")]
|
#[error("Failed triggering the interrupt")]
|
||||||
TriggerInterrupt(#[source] io::Error),
|
TriggerInterrupt(#[source] io::Error),
|
||||||
/// Failed masking the interrupt.
|
/// Failed masking the interrupt.
|
||||||
#[error("Failed masking the interrupt: {0}")]
|
#[error("Failed masking the interrupt")]
|
||||||
MaskInterrupt(#[source] io::Error),
|
MaskInterrupt(#[source] io::Error),
|
||||||
/// Failed unmasking the interrupt.
|
/// Failed unmasking the interrupt.
|
||||||
#[error("Failed unmasking the interrupt: {0}")]
|
#[error("Failed unmasking the interrupt")]
|
||||||
UnmaskInterrupt(#[source] io::Error),
|
UnmaskInterrupt(#[source] io::Error),
|
||||||
/// Failed updating the interrupt.
|
/// Failed updating the interrupt.
|
||||||
#[error("Failed updating the interrupt: {0}")]
|
#[error("Failed updating the interrupt")]
|
||||||
UpdateInterrupt(#[source] io::Error),
|
UpdateInterrupt(#[source] io::Error),
|
||||||
/// Failed enabling the interrupt.
|
/// Failed enabling the interrupt.
|
||||||
#[error("Failed enabling the interrupt: {0}")]
|
#[error("Failed enabling the interrupt")]
|
||||||
EnableInterrupt(#[source] io::Error),
|
EnableInterrupt(#[source] io::Error),
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
/// Failed creating GIC device.
|
/// Failed creating GIC device.
|
||||||
#[error("Failed creating GIC device: {0}")]
|
#[error("Failed creating GIC device")]
|
||||||
CreateGic(#[source] hypervisor::HypervisorVmError),
|
CreateGic(#[source] hypervisor::HypervisorVmError),
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
/// Failed restoring GIC device.
|
/// Failed restoring GIC device.
|
||||||
#[error("Failed restoring GIC device: {0}")]
|
#[error("Failed restoring GIC device")]
|
||||||
RestoreGic(#[source] hypervisor::arch::aarch64::gic::Error),
|
RestoreGic(#[source] hypervisor::arch::aarch64::gic::Error),
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
/// Failed creating AIA device.
|
/// Failed creating AIA device.
|
||||||
#[error("Failed creating AIA device: {0}")]
|
#[error("Failed creating AIA device")]
|
||||||
CreateAia(#[source] hypervisor::HypervisorVmError),
|
CreateAia(#[source] hypervisor::HypervisorVmError),
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
/// Failed restoring AIA device.
|
/// Failed restoring AIA device.
|
||||||
#[error("Failed restoring AIA device: {0}")]
|
#[error("Failed restoring AIA device")]
|
||||||
RestoreAia(#[source] hypervisor::arch::riscv64::aia::Error),
|
RestoreAia(#[source] hypervisor::arch::riscv64::aia::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ pub enum Error {
|
|||||||
BadWriteOffset(u64),
|
BadWriteOffset(u64),
|
||||||
#[error("GPIO interrupt disabled by guest driver")]
|
#[error("GPIO interrupt disabled by guest driver")]
|
||||||
GpioInterruptDisabled,
|
GpioInterruptDisabled,
|
||||||
#[error("Could not trigger GPIO interrupt: {0}")]
|
#[error("Could not trigger GPIO interrupt")]
|
||||||
GpioInterruptFailure(#[source] io::Error),
|
GpioInterruptFailure(#[source] io::Error),
|
||||||
#[error("Invalid GPIO Input key triggered: {0}")]
|
#[error("Invalid GPIO Input key triggered: {0}")]
|
||||||
GpioTriggerKeyFailure(u32),
|
GpioTriggerKeyFailure(u32),
|
||||||
|
|||||||
@@ -4,16 +4,18 @@
|
|||||||
|
|
||||||
//! ARM PL031 Real Time Clock
|
//! ARM PL031 Real Time Clock
|
||||||
//!
|
//!
|
||||||
//! This module implements a PL031 Real Time Clock (RTC) that provides to provides long time base counter.
|
//! This module implements part of a PL031 Real Time Clock (RTC):
|
||||||
//! This is achieved by generating an interrupt signal after counting for a programmed number of cycles of
|
//! * provide a clock value via RTCDR
|
||||||
//! a real-time clock input.
|
//! * no alarm is implemented through the match register
|
||||||
|
//! * no interrupt is generated
|
||||||
|
//! * RTC cannot be disabled via RTCCR
|
||||||
|
//! * no test registers
|
||||||
//!
|
//!
|
||||||
|
use std::result;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use std::{io, result};
|
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use vm_device::interrupt::InterruptSourceGroup;
|
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
|
|
||||||
use crate::{read_le_u32, write_le_u32};
|
use crate::{read_le_u32, write_le_u32};
|
||||||
@@ -45,8 +47,6 @@ pub const NANOS_PER_SECOND: u64 = 1_000_000_000;
|
|||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Bad Write Offset: {0}")]
|
#[error("Bad Write Offset: {0}")]
|
||||||
BadWriteOffset(u64),
|
BadWriteOffset(u64),
|
||||||
#[error("Failed to trigger interrupt: {0}")]
|
|
||||||
InterruptFailure(#[source] io::Error),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
@@ -107,31 +107,20 @@ pub struct Rtc {
|
|||||||
match_value: u32,
|
match_value: u32,
|
||||||
// Writes to this register load an update value into the RTC.
|
// Writes to this register load an update value into the RTC.
|
||||||
load: u32,
|
load: u32,
|
||||||
imsc: u32,
|
|
||||||
ris: u32,
|
|
||||||
interrupt: Arc<dyn InterruptSourceGroup>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rtc {
|
impl Rtc {
|
||||||
/// Constructs an AMBA PL031 RTC device.
|
/// Constructs an AMBA PL031 RTC device.
|
||||||
pub fn new(interrupt: Arc<dyn InterruptSourceGroup>) -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
// This is used only for duration measuring purposes.
|
// This is used only for duration measuring purposes.
|
||||||
previous_now: Instant::now(),
|
previous_now: Instant::now(),
|
||||||
tick_offset: get_time(ClockType::Real) as i64,
|
tick_offset: get_time(ClockType::Real) as i64,
|
||||||
match_value: 0,
|
match_value: 0,
|
||||||
load: 0,
|
load: 0,
|
||||||
imsc: 0,
|
|
||||||
ris: 0,
|
|
||||||
interrupt,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trigger_interrupt(&mut self) -> Result<()> {
|
|
||||||
self.interrupt.trigger(0).map_err(Error::InterruptFailure)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_time(&self) -> u32 {
|
fn get_time(&self) -> u32 {
|
||||||
let ts = (self.tick_offset as i128)
|
let ts = (self.tick_offset as i128)
|
||||||
+ (Instant::now().duration_since(self.previous_now).as_nanos() as i128);
|
+ (Instant::now().duration_since(self.previous_now).as_nanos() as i128);
|
||||||
@@ -155,16 +144,8 @@ impl Rtc {
|
|||||||
// we want to terminate the execution of the process.
|
// we want to terminate the execution of the process.
|
||||||
self.tick_offset = seconds_to_nanoseconds(i64::from(val)).unwrap();
|
self.tick_offset = seconds_to_nanoseconds(i64::from(val)).unwrap();
|
||||||
}
|
}
|
||||||
RTCIMSC => {
|
RTCIMSC => (),
|
||||||
self.imsc = val & 1;
|
RTCICR => (),
|
||||||
self.trigger_interrupt()?;
|
|
||||||
}
|
|
||||||
RTCICR => {
|
|
||||||
// As per above mentioned doc, the interrupt is cleared by writing any data value to
|
|
||||||
// the Interrupt Clear Register.
|
|
||||||
self.ris = 0;
|
|
||||||
self.trigger_interrupt()?;
|
|
||||||
}
|
|
||||||
RTCCR => (), // ignore attempts to turn off the timer.
|
RTCCR => (), // ignore attempts to turn off the timer.
|
||||||
o => {
|
o => {
|
||||||
return Err(Error::BadWriteOffset(o));
|
return Err(Error::BadWriteOffset(o));
|
||||||
@@ -174,6 +155,12 @@ impl Rtc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Rtc {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl BusDevice for Rtc {
|
impl BusDevice for Rtc {
|
||||||
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
||||||
let mut read_ok = true;
|
let mut read_ok = true;
|
||||||
@@ -190,9 +177,9 @@ impl BusDevice for Rtc {
|
|||||||
}
|
}
|
||||||
RTCLR => self.load,
|
RTCLR => self.load,
|
||||||
RTCCR => 1, // RTC is always enabled.
|
RTCCR => 1, // RTC is always enabled.
|
||||||
RTCIMSC => self.imsc,
|
RTCIMSC => 0, // Interrupt is always disabled.
|
||||||
RTCRIS => self.ris,
|
RTCRIS => 0,
|
||||||
RTCMIS => self.ris & self.imsc,
|
RTCMIS => 0,
|
||||||
_ => {
|
_ => {
|
||||||
read_ok = false;
|
read_ok = false;
|
||||||
0
|
0
|
||||||
@@ -230,9 +217,6 @@ impl BusDevice for Rtc {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
|
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
read_be_u16, read_be_u32, read_le_i32, read_le_u16, read_le_u64, write_be_u16,
|
read_be_u16, read_be_u32, read_le_i32, read_le_u16, read_le_u64, write_be_u16,
|
||||||
@@ -366,45 +350,9 @@ mod tests {
|
|||||||
assert!(seconds_to_nanoseconds(9_223_372_037).is_none());
|
assert!(seconds_to_nanoseconds(9_223_372_037).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestInterrupt {
|
|
||||||
event_fd: EventFd,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InterruptSourceGroup for TestInterrupt {
|
|
||||||
fn trigger(&self, _index: InterruptIndex) -> result::Result<(), std::io::Error> {
|
|
||||||
self.event_fd.write(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(
|
|
||||||
&self,
|
|
||||||
_index: InterruptIndex,
|
|
||||||
_config: InterruptSourceConfig,
|
|
||||||
_masked: bool,
|
|
||||||
_set_gsi: bool,
|
|
||||||
) -> result::Result<(), std::io::Error> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_gsi(&self) -> result::Result<(), std::io::Error> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
|
|
||||||
Some(self.event_fd.try_clone().unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TestInterrupt {
|
|
||||||
fn new(event_fd: EventFd) -> Self {
|
|
||||||
TestInterrupt { event_fd }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rtc_read_write_and_event() {
|
fn test_rtc_read_write_and_event() {
|
||||||
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
|
let mut rtc = Rtc::new();
|
||||||
|
|
||||||
let mut rtc = Rtc::new(Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())));
|
|
||||||
let mut data = [0; 4];
|
let mut data = [0; 4];
|
||||||
|
|
||||||
// Read and write to the MR register.
|
// Read and write to the MR register.
|
||||||
@@ -427,15 +375,13 @@ mod tests {
|
|||||||
assert_eq!((v / NANOS_PER_SECOND) as u32, v_read);
|
assert_eq!((v / NANOS_PER_SECOND) as u32, v_read);
|
||||||
|
|
||||||
// Read and write to IMSC register.
|
// Read and write to IMSC register.
|
||||||
// Test with non zero value.
|
// Test with non zero value. Our device ignores the write.
|
||||||
let non_zero = 1;
|
let non_zero = 1;
|
||||||
write_le_u32(&mut data, non_zero);
|
write_le_u32(&mut data, non_zero);
|
||||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &data);
|
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &data);
|
||||||
// The interrupt line should be on.
|
|
||||||
assert!(rtc.interrupt.notifier(0).unwrap().read().unwrap() == 1);
|
|
||||||
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
|
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
|
||||||
let v = read_le_u32(&data);
|
let v = read_le_u32(&data);
|
||||||
assert_eq!(non_zero & 1, v);
|
assert_eq!(0, v);
|
||||||
|
|
||||||
// Now test with 0.
|
// Now test with 0.
|
||||||
write_le_u32(&mut data, 0);
|
write_le_u32(&mut data, 0);
|
||||||
@@ -447,8 +393,6 @@ mod tests {
|
|||||||
// Read and write to the ICR register.
|
// Read and write to the ICR register.
|
||||||
write_le_u32(&mut data, 1);
|
write_le_u32(&mut data, 1);
|
||||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCICR, &data);
|
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCICR, &data);
|
||||||
// The interrupt line should be on.
|
|
||||||
assert!(rtc.interrupt.notifier(0).unwrap().read().unwrap() > 1);
|
|
||||||
let v_before = read_le_u32(&data);
|
let v_before = read_le_u32(&data);
|
||||||
|
|
||||||
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCICR, &mut data);
|
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCICR, &mut data);
|
||||||
|
|||||||
@@ -53,11 +53,11 @@ pub enum Error {
|
|||||||
BadWriteOffset(u64),
|
BadWriteOffset(u64),
|
||||||
#[error("pl011: DMA not implemented")]
|
#[error("pl011: DMA not implemented")]
|
||||||
DmaNotImplemented,
|
DmaNotImplemented,
|
||||||
#[error("Failed to trigger interrupt: {0}")]
|
#[error("Failed to trigger interrupt")]
|
||||||
InterruptFailure(#[source] io::Error),
|
InterruptFailure(#[source] io::Error),
|
||||||
#[error("Failed to write: {0}")]
|
#[error("Failed to write")]
|
||||||
WriteAllFailure(#[source] io::Error),
|
WriteAllFailure(#[source] io::Error),
|
||||||
#[error("Failed to flush: {0}")]
|
#[error("Failed to flush")]
|
||||||
FlushFailure(#[source] io::Error),
|
FlushFailure(#[source] io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const MINOR_VERSION: u64 = 0;
|
|||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
// device errors
|
// device errors
|
||||||
#[error("Guest gave us bad memory addresses: {0}")]
|
#[error("Guest gave us bad memory addresses")]
|
||||||
GuestMemory(#[source] GuestMemoryError),
|
GuestMemory(#[source] GuestMemoryError),
|
||||||
#[error("Guest sent us invalid request")]
|
#[error("Guest sent us invalid request")]
|
||||||
InvalidRequest,
|
InvalidRequest,
|
||||||
@@ -51,7 +51,7 @@ pub enum Error {
|
|||||||
InvalidArgument(u64),
|
InvalidArgument(u64),
|
||||||
#[error("Unknown function code: {0}")]
|
#[error("Unknown function code: {0}")]
|
||||||
UnknownFunctionCode(u64),
|
UnknownFunctionCode(u64),
|
||||||
#[error("Libc call fail: {0}")]
|
#[error("Libc call fail")]
|
||||||
LibcFail(#[source] std::io::Error),
|
LibcFail(#[source] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ const PVPANIC_CRASH_LOADED: u8 = 1 << 1;
|
|||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum PvPanicError {
|
pub enum PvPanicError {
|
||||||
#[error("Failed creating PvPanicDevice: {0}")]
|
#[error("Failed creating PvPanicDevice")]
|
||||||
CreatePvPanicDevice(#[source] anyhow::Error),
|
CreatePvPanicDevice(#[source] anyhow::Error),
|
||||||
#[error("Failed to retrieve PciConfigurationState: {0}")]
|
#[error("Failed to retrieve PciConfigurationState")]
|
||||||
RetrievePciConfigurationState(#[source] anyhow::Error),
|
RetrievePciConfigurationState(#[source] anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ use vm_device::BusDevice;
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Emulator doesn't implement min required capabilities: {0}")]
|
#[error("Emulator doesn't implement min required capabilities")]
|
||||||
CheckCaps(#[source] anyhow::Error),
|
CheckCaps(#[source] anyhow::Error),
|
||||||
#[error("Failed to initialize tpm: {0}")]
|
#[error("Failed to initialize tpm")]
|
||||||
Init(#[source] anyhow::Error),
|
Init(#[source] anyhow::Error),
|
||||||
}
|
}
|
||||||
type Result<T> = anyhow::Result<T, Error>;
|
type Result<T> = anyhow::Result<T, Error>;
|
||||||
|
|||||||
@@ -4,14 +4,12 @@ Intel® Software Guard Extensions (Intel® SGX) is an Intel technology designed
|
|||||||
to increase the security of application code and data. Cloud Hypervisor supports
|
to increase the security of application code and data. Cloud Hypervisor supports
|
||||||
SGX virtualization through KVM. Because SGX is built on hardware features that
|
SGX virtualization through KVM. Because SGX is built on hardware features that
|
||||||
cannot be emulated in software, virtualizing SGX requires support in KVM and in
|
cannot be emulated in software, virtualizing SGX requires support in KVM and in
|
||||||
the host kernel. The required Linux and KVM changes can be found in the
|
the host kernel. The required Linux and KVM changes can be found in Linux 5.13+.
|
||||||
[KVM SGX Tree](https://github.com/intel/kvm-sgx).
|
|
||||||
|
|
||||||
Utilizing SGX in the guest requires a kernel/OS with SGX support, e.g. a kernel
|
Utilizing SGX in the guest requires a kernel/OS with SGX support, e.g. a kernel
|
||||||
since release 5.11, see
|
since release 5.11, see
|
||||||
[here](https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/linux-overview.html)
|
[here](https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/linux-overview.html).
|
||||||
or the [KVM SGX Tree](https://github.com/intel/kvm-sgx). Running KVM SGX as the
|
Running Linux 5.13+ as the guest kernel allows nested virtualization of SGX.
|
||||||
guest kernel allows nested virtualization of SGX.
|
|
||||||
|
|
||||||
For more information about SGX, please refer to the [SGX Homepage](https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/linux-overview.html).
|
For more information about SGX, please refer to the [SGX Homepage](https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/linux-overview.html).
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ tapindex=$(< /sys/class/net/macvtap0/ifindex)
|
|||||||
tapdevice="/dev/tap$tapindex"
|
tapdevice="/dev/tap$tapindex"
|
||||||
|
|
||||||
# Ensure that we can access this device
|
# Ensure that we can access this device
|
||||||
sudo chown "$UID.$UID" "$tapdevice"
|
sudo chown "$UID:$UID" "$tapdevice"
|
||||||
|
|
||||||
# Use --net fd=3 to point to fd 3 which the shell has opened to point to the /dev/tapN device
|
# Use --net fd=3 to point to fd 3 which the shell has opened to point to the /dev/tapN device
|
||||||
target/debug/cloud-hypervisor \
|
target/debug/cloud-hypervisor \
|
||||||
|
|||||||
@@ -7,6 +7,5 @@ version = "0.1.0"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
flume = "0.11.1"
|
flume = "0.11.1"
|
||||||
libc = "0.2.167"
|
libc = "0.2.167"
|
||||||
once_cell = "1.20.2"
|
|
||||||
serde = { version = "1.0.208", features = ["derive", "rc"] }
|
serde = { version = "1.0.208", features = ["derive", "rc"] }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
|||||||
@@ -8,13 +8,12 @@ use std::collections::HashMap;
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, OnceLock};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use once_cell::sync::OnceCell;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
static MONITOR: OnceCell<MonitorHandle> = OnceCell::new();
|
static MONITOR: OnceLock<MonitorHandle> = OnceLock::new();
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct Event<'a> {
|
struct Event<'a> {
|
||||||
|
|||||||
212
fuzz/Cargo.lock
generated
212
fuzz/Cargo.lock
generated
@@ -7,7 +7,7 @@ name = "acpi_tables"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#e08a3f0b0a59b98859dbf59f5aa7fd4d2eb4018a"
|
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#e08a3f0b0a59b98859dbf59f5aa7fd4d2eb4018a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy 0.8.24",
|
"zerocopy 0.8.26",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -89,7 +89,7 @@ dependencies = [
|
|||||||
"linux-loader",
|
"linux-loader",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.12",
|
||||||
"uuid",
|
"uuid",
|
||||||
"vm-fdt",
|
"vm-fdt",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
@@ -137,7 +137,7 @@ dependencies = [
|
|||||||
"remain",
|
"remain",
|
||||||
"serde",
|
"serde",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.12",
|
||||||
"uuid",
|
"uuid",
|
||||||
"virtio-bindings",
|
"virtio-bindings",
|
||||||
"virtio-queue",
|
"virtio-queue",
|
||||||
@@ -217,7 +217,6 @@ dependencies = [
|
|||||||
"micro_http",
|
"micro_http",
|
||||||
"mshv-bindings",
|
"mshv-bindings",
|
||||||
"net_util",
|
"net_util",
|
||||||
"once_cell",
|
|
||||||
"seccompiler",
|
"seccompiler",
|
||||||
"virtio-devices",
|
"virtio-devices",
|
||||||
"virtio-queue",
|
"virtio-queue",
|
||||||
@@ -311,7 +310,7 @@ dependencies = [
|
|||||||
"num_enum",
|
"num_enum",
|
||||||
"pci",
|
"pci",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.12",
|
||||||
"tpm",
|
"tpm",
|
||||||
"vm-allocator",
|
"vm-allocator",
|
||||||
"vm-device",
|
"vm-device",
|
||||||
@@ -362,7 +361,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"flume",
|
"flume",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
@@ -405,9 +403,9 @@ checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gdbstub"
|
name = "gdbstub"
|
||||||
version = "0.7.2"
|
version = "0.7.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fbcc892208d6998fb57e7c3e05883def66f8130924bba066beb0cfe71566a9f6"
|
checksum = "71d66e32caf5dd59f561be0143e413e01d651bd8498eb9aa0be8c482c81c8d31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@@ -442,14 +440,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.3.1"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi 0.13.3+wasi-0.2.2",
|
"r-efi",
|
||||||
"windows-targets",
|
"wasi 0.14.2+wasi-0.2.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -478,11 +476,11 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.12",
|
||||||
"vfio-ioctls",
|
"vfio-ioctls",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
"zerocopy 0.8.24",
|
"zerocopy 0.8.26",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -533,29 +531,30 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.69"
|
version = "0.3.77"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kvm-bindings"
|
name = "kvm-bindings"
|
||||||
version = "0.10.0"
|
version = "0.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa4933174d0cc4b77b958578cd45784071cc5ae212c2d78fbd755aaaa6dfa71a"
|
checksum = "d4b153a59bb3ca930ff8148655b2ef68c34259a623ae08cf2fb9b570b2e45363"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
"zerocopy 0.7.35",
|
"zerocopy 0.8.26",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kvm-ioctls"
|
name = "kvm-ioctls"
|
||||||
version = "0.19.1"
|
version = "0.22.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e013ae7fcd2c6a8f384104d16afe7ea02969301ea2bb2a56e44b011ebc907cab"
|
checksum = "b702df98508cb63ad89dd9beb9f6409761b30edca10d48e57941d3f11513a006"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"kvm-bindings",
|
"kvm-bindings",
|
||||||
@@ -637,7 +636,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "micro_http"
|
name = "micro_http"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#4f621532e81ee2ad096a9c9592fdacc40d19de48"
|
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#bf5098916006912f8dd35aaa6daa5579c6c297b2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
@@ -645,16 +644,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mshv-bindings"
|
name = "mshv-bindings"
|
||||||
version = "0.4.0"
|
version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "577073a0abbf515d17bfe96ca2ce49c44a68454d4179e95ce1244e858a9ebd4e"
|
checksum = "07f94f542c738f19317363222a7f415588c04cda964882479af41948ac3c3647"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
"zerocopy 0.8.24",
|
"zerocopy 0.8.26",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -678,13 +677,13 @@ name = "net_util"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"epoll",
|
"epoll",
|
||||||
"getrandom 0.3.1",
|
"getrandom 0.3.3",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"net_gen",
|
"net_gen",
|
||||||
"rate_limiter",
|
"rate_limiter",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.12",
|
||||||
"virtio-bindings",
|
"virtio-bindings",
|
||||||
"virtio-queue",
|
"virtio-queue",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
@@ -751,6 +750,9 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "option_parser"
|
name = "option_parser"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror 2.0.12",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "paste"
|
name = "paste"
|
||||||
@@ -768,7 +770,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.12",
|
||||||
"vfio-bindings",
|
"vfio-bindings",
|
||||||
"vfio-ioctls",
|
"vfio-ioctls",
|
||||||
"vfio_user",
|
"vfio_user",
|
||||||
@@ -815,6 +817,12 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r-efi"
|
||||||
|
version = "5.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -823,7 +831,7 @@ checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"zerocopy 0.8.24",
|
"zerocopy 0.8.26",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -842,7 +850,7 @@ version = "0.9.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.3.1",
|
"getrandom 0.3.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -852,21 +860,27 @@ dependencies = [
|
|||||||
"epoll",
|
"epoll",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.12",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "remain"
|
name = "remain"
|
||||||
version = "0.2.14"
|
version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46aef80f842736de545ada6ec65b81ee91504efd6853f4b96de7414c42ae7443"
|
checksum = "d7ef12e84481ab4006cb942f8682bba28ece7270743e649442027c5db87df126"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
@@ -955,9 +969,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook"
|
name = "signal-hook"
|
||||||
version = "0.3.17"
|
version = "0.3.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
|
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
@@ -1015,11 +1029,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "2.0.9"
|
version = "2.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc"
|
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl 2.0.9",
|
"thiserror-impl 2.0.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1035,9 +1049,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "2.0.9"
|
version = "2.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
|
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1070,7 +1084,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"net_gen",
|
"net_gen",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.12",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1080,7 +1094,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
@@ -1099,45 +1112,37 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.15.1"
|
version = "1.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587"
|
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.3.1",
|
"getrandom 0.3.3",
|
||||||
|
"js-sys",
|
||||||
"rand",
|
"rand",
|
||||||
"uuid-macro-internal",
|
"wasm-bindgen",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "uuid-macro-internal"
|
|
||||||
version = "1.15.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9521621447c21497fac206ffe6e9f642f977c4f82eeba9201055f64884d9cb01"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vfio-bindings"
|
name = "vfio-bindings"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#b135b8305c2cc8ec333e0cf77a780445cc98dcee"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b565663f62e091ca47db9a674c8c95c9686a000e82970f391a3cacf6470ff060"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vfio-ioctls"
|
name = "vfio-ioctls"
|
||||||
version = "0.2.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#b135b8305c2cc8ec333e0cf77a780445cc98dcee"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "61316b5e308faa8ed4a87c4130256f765e46de3442eb2e2e619840ef73456738"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"kvm-bindings",
|
"kvm-bindings",
|
||||||
"kvm-ioctls",
|
"kvm-ioctls",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"thiserror 1.0.64",
|
"thiserror 2.0.12",
|
||||||
"vfio-bindings",
|
"vfio-bindings",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
@@ -1146,15 +1151,16 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "vfio_user"
|
name = "vfio_user"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#3febcdd3fa2531623865663ca1721e1962ed9979"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed81c5ed8224d468a322e923777ed0615cad433fe61177126098af995f89cecf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 2.9.0",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror 1.0.64",
|
"thiserror 2.0.12",
|
||||||
"vfio-bindings",
|
"vfio-bindings",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
@@ -1162,8 +1168,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vhost"
|
name = "vhost"
|
||||||
version = "0.12.1"
|
version = "0.14.0"
|
||||||
source = "git+https://github.com/rust-vmm/vhost?rev=d983ae0#d983ae07f78663b7d24059667376992460b571a2"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a4dcad85a129d97d5d4b2f3c47a4affdeedd76bdcd02094bcb5d9b76cac2d05"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1174,9 +1181,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "virtio-bindings"
|
name = "virtio-bindings"
|
||||||
version = "0.2.4"
|
version = "0.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1711e61c00f8cb450bd15368152a1e37a12ef195008ddc7d0f4812f9e2b30a68"
|
checksum = "804f498a26d5a63be7bbb8bdcd3869c3f286c4c4a17108905276454da0caf8cb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "virtio-devices"
|
name = "virtio-devices"
|
||||||
@@ -1199,7 +1206,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
"serial_buffer",
|
"serial_buffer",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.12",
|
||||||
"vhost",
|
"vhost",
|
||||||
"virtio-bindings",
|
"virtio-bindings",
|
||||||
"virtio-queue",
|
"virtio-queue",
|
||||||
@@ -1213,9 +1220,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "virtio-queue"
|
name = "virtio-queue"
|
||||||
version = "0.14.0"
|
version = "0.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "872e2f3fbd70a7e6f01689720cce3d5c2c5efe52b484dd07b674246ada0e9a8d"
|
checksum = "fb0479158f863e59323771a1f684d843962f76960b86fecfec2bfa9c8f0f9180"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"virtio-bindings",
|
"virtio-bindings",
|
||||||
@@ -1239,7 +1246,7 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"hypervisor",
|
"hypervisor",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.12",
|
||||||
"vfio-ioctls",
|
"vfio-ioctls",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
@@ -1252,9 +1259,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#ef5bd734f5f66fb0772
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vm-memory"
|
name = "vm-memory"
|
||||||
version = "0.16.1"
|
version = "0.16.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1720e7240cdc739f935456eb77f370d7e9b2a3909204da1e2b47bef1137a013"
|
checksum = "1fd5e56d48353c5f54ef50bd158a0452fc82f5383da840f7b8efc31695dd3b9d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1269,7 +1276,7 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.12",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1307,7 +1314,6 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"micro_http",
|
"micro_http",
|
||||||
"net_util",
|
"net_util",
|
||||||
"once_cell",
|
|
||||||
"option_parser",
|
"option_parser",
|
||||||
"pci",
|
"pci",
|
||||||
"rate_limiter",
|
"rate_limiter",
|
||||||
@@ -1316,11 +1322,12 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serial_buffer",
|
"serial_buffer",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.12",
|
||||||
"tracer",
|
"tracer",
|
||||||
"uuid",
|
"uuid",
|
||||||
"vfio-ioctls",
|
"vfio-ioctls",
|
||||||
"vfio_user",
|
"vfio_user",
|
||||||
|
"virtio-bindings",
|
||||||
"virtio-devices",
|
"virtio-devices",
|
||||||
"virtio-queue",
|
"virtio-queue",
|
||||||
"vm-allocator",
|
"vm-allocator",
|
||||||
@@ -1329,14 +1336,14 @@ dependencies = [
|
|||||||
"vm-migration",
|
"vm-migration",
|
||||||
"vm-virtio",
|
"vm-virtio",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
"zerocopy 0.8.24",
|
"zerocopy 0.8.26",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vmm-sys-util"
|
name = "vmm-sys-util"
|
||||||
version = "0.12.1"
|
version = "0.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede"
|
checksum = "d21f366bf22bfba3e868349978766a965cbe628c323d58e026be80b8357ab789"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1352,33 +1359,33 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.13.3+wasi-0.2.2"
|
version = "0.14.2+wasi-0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
|
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wit-bindgen-rt",
|
"wit-bindgen-rt",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.93"
|
version = "0.2.100"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
|
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"rustversion",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.93"
|
version = "0.2.100"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
|
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
@@ -1387,9 +1394,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.93"
|
version = "0.2.100"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
|
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -1397,9 +1404,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.93"
|
version = "0.2.100"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1410,9 +1417,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.93"
|
version = "0.2.100"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
@@ -1520,9 +1530,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-bindgen-rt"
|
name = "wit-bindgen-rt"
|
||||||
version = "0.33.0"
|
version = "0.39.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
]
|
]
|
||||||
@@ -1539,11 +1549,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.24"
|
version = "0.8.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
|
checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive 0.8.24",
|
"zerocopy-derive 0.8.26",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1559,9 +1569,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.8.24"
|
version = "0.8.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
|
checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
@@ -24,18 +24,17 @@ libc = "0.2.155"
|
|||||||
libfuzzer-sys = "0.4.7"
|
libfuzzer-sys = "0.4.7"
|
||||||
linux-loader = { version = "0.13.0", features = ["bzimage", "elf", "pe"] }
|
linux-loader = { version = "0.13.0", features = ["bzimage", "elf", "pe"] }
|
||||||
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
|
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
|
||||||
mshv-bindings = "0.5.0"
|
mshv-bindings = "0.5.2"
|
||||||
net_util = { path = "../net_util" }
|
net_util = { path = "../net_util" }
|
||||||
once_cell = "1.19.0"
|
|
||||||
seccompiler = "0.5.0"
|
seccompiler = "0.5.0"
|
||||||
virtio-devices = { path = "../virtio-devices" }
|
virtio-devices = { path = "../virtio-devices" }
|
||||||
virtio-queue = "0.14.0"
|
virtio-queue = "0.16.0"
|
||||||
vm-device = { path = "../vm-device" }
|
vm-device = { path = "../vm-device" }
|
||||||
vm-memory = "0.16.0"
|
vm-memory = "0.16.0"
|
||||||
vm-migration = { path = "../vm-migration" }
|
vm-migration = { path = "../vm-migration" }
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vmm = { path = "../vmm", features = ["guest_debug"] }
|
vmm = { path = "../vmm", features = ["guest_debug"] }
|
||||||
vmm-sys-util = "0.12.1"
|
vmm-sys-util = "0.14.0"
|
||||||
|
|
||||||
# Prevent this from interfering with workspaces
|
# Prevent this from interfering with workspaces
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::mpsc::{channel, Receiver};
|
use std::sync::mpsc::{channel, Receiver};
|
||||||
|
use std::sync::LazyLock;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use libfuzzer_sys::{fuzz_target, Corpus};
|
use libfuzzer_sys::{fuzz_target, Corpus};
|
||||||
use micro_http::Request;
|
use micro_http::Request;
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use vm_migration::MigratableError;
|
use vm_migration::MigratableError;
|
||||||
use vmm::api::http::*;
|
use vmm::api::http::*;
|
||||||
use vmm::api::{
|
use vmm::api::{
|
||||||
@@ -24,8 +24,8 @@ use vmm::{EpollContext, EpollDispatch};
|
|||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
// Need to be ordered for test case reproducibility
|
// Need to be ordered for test case reproducibility
|
||||||
static ROUTES: Lazy<Vec<&Box<dyn EndpointHandler + Sync + Send>>> =
|
static ROUTES: LazyLock<Vec<&Box<dyn EndpointHandler + Sync + Send>>> =
|
||||||
Lazy::new(|| HTTP_ROUTES.routes.values().collect());
|
LazyLock::new(|| HTTP_ROUTES.routes.values().collect());
|
||||||
|
|
||||||
fuzz_target!(|bytes: &[u8]| -> Corpus {
|
fuzz_target!(|bytes: &[u8]| -> Corpus {
|
||||||
if bytes.len() < 2 {
|
if bytes.len() < 2 {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ serde_json = { workspace = true }
|
|||||||
serde_with = { version = "3.9.0", default-features = false, features = [
|
serde_with = { version = "3.9.0", default-features = false, features = [
|
||||||
"macros",
|
"macros",
|
||||||
] }
|
] }
|
||||||
thiserror = "2.0.6"
|
thiserror = { workspace = true }
|
||||||
vfio-ioctls = { workspace = true, default-features = false }
|
vfio-ioctls = { workspace = true, default-features = false }
|
||||||
vm-memory = { workspace = true, features = [
|
vm-memory = { workspace = true, features = [
|
||||||
"backend-atomic",
|
"backend-atomic",
|
||||||
@@ -44,7 +44,7 @@ vm-memory = { workspace = true, features = [
|
|||||||
"backend-mmap",
|
"backend-mmap",
|
||||||
] }
|
] }
|
||||||
vmm-sys-util = { workspace = true, features = ["with-serde"] }
|
vmm-sys-util = { workspace = true, features = ["with-serde"] }
|
||||||
zerocopy = { version = "0.8.24", features = ["derive"] }
|
zerocopy = { workspace = true, features = ["derive"] }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
||||||
default-features = false
|
default-features = false
|
||||||
@@ -62,4 +62,4 @@ optional = true
|
|||||||
version = "1.21.0"
|
version = "1.21.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.11.3"
|
env_logger = { workspace = true }
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ use crate::{CpuState, HypervisorDeviceError, HypervisorVmError};
|
|||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Error while calling KVM ioctl for setting up the global interrupt controller.
|
/// Error while calling KVM ioctl for setting up the global interrupt controller.
|
||||||
#[error("Failed creating GIC device: {0}")]
|
#[error("Failed creating GIC device")]
|
||||||
CreateGic(#[source] HypervisorVmError),
|
CreateGic(#[source] HypervisorVmError),
|
||||||
/// Error while setting device attributes for the GIC.
|
/// Error while setting device attributes for the GIC.
|
||||||
#[error("Failed setting device attributes for the GIC: {0}")]
|
#[error("Failed setting device attributes for the GIC")]
|
||||||
SetDeviceAttribute(#[source] HypervisorDeviceError),
|
SetDeviceAttribute(#[source] HypervisorDeviceError),
|
||||||
/// Error while getting device attributes for the GIC.
|
/// Error while getting device attributes for the GIC.
|
||||||
#[error("Failed getting device attributes for the GIC: {0}")]
|
#[error("Failed getting device attributes for the GIC")]
|
||||||
GetDeviceAttribute(#[source] HypervisorDeviceError),
|
GetDeviceAttribute(#[source] HypervisorDeviceError),
|
||||||
}
|
}
|
||||||
pub type Result<T> = result::Result<T, Error>;
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|||||||
@@ -36,58 +36,58 @@ impl<T: Debug> Display for Exception<T> {
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum PlatformError {
|
pub enum PlatformError {
|
||||||
#[error("Invalid address: {0}")]
|
#[error("Invalid address")]
|
||||||
InvalidAddress(#[source] anyhow::Error),
|
InvalidAddress(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Invalid register: {0}")]
|
#[error("Invalid register")]
|
||||||
InvalidRegister(#[source] anyhow::Error),
|
InvalidRegister(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Invalid state: {0}")]
|
#[error("Invalid state")]
|
||||||
InvalidState(#[source] anyhow::Error),
|
InvalidState(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Memory read failure: {0}")]
|
#[error("Memory read failure")]
|
||||||
MemoryReadFailure(#[source] anyhow::Error),
|
MemoryReadFailure(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Memory write failure: {0}")]
|
#[error("Memory write failure")]
|
||||||
MemoryWriteFailure(#[source] anyhow::Error),
|
MemoryWriteFailure(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Get CPU state failure: {0}")]
|
#[error("Get CPU state failure")]
|
||||||
GetCpuStateFailure(#[source] anyhow::Error),
|
GetCpuStateFailure(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Set CPU state failure: {0}")]
|
#[error("Set CPU state failure")]
|
||||||
SetCpuStateFailure(#[source] anyhow::Error),
|
SetCpuStateFailure(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Translate virtual address: {0}")]
|
#[error("Translate virtual address")]
|
||||||
TranslateVirtualAddress(#[source] anyhow::Error),
|
TranslateVirtualAddress(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Unsupported CPU Mode: {0}")]
|
#[error("Unsupported CPU Mode")]
|
||||||
UnsupportedCpuMode(#[source] anyhow::Error),
|
UnsupportedCpuMode(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Invalid instruction operand: {0}")]
|
#[error("Invalid instruction operand")]
|
||||||
InvalidOperand(#[source] anyhow::Error),
|
InvalidOperand(#[source] anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum EmulationError<T: Debug> {
|
pub enum EmulationError<T: Debug> {
|
||||||
#[error("Unsupported instruction: {0}")]
|
#[error("Unsupported instruction")]
|
||||||
UnsupportedInstruction(#[source] anyhow::Error),
|
UnsupportedInstruction(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Unsupported memory size: {0}")]
|
#[error("Unsupported memory size")]
|
||||||
UnsupportedMemorySize(#[source] anyhow::Error),
|
UnsupportedMemorySize(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Invalid operand: {0}")]
|
#[error("Invalid operand")]
|
||||||
InvalidOperand(#[source] anyhow::Error),
|
InvalidOperand(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Wrong number of operands: {0}")]
|
#[error("Wrong number of operands")]
|
||||||
WrongNumberOperands(#[source] anyhow::Error),
|
WrongNumberOperands(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Instruction Exception: {0}")]
|
#[error("Instruction Exception")]
|
||||||
InstructionException(#[source] Exception<T>),
|
InstructionException(#[source] Exception<T>),
|
||||||
|
|
||||||
#[error("Instruction fetching error: {0}")]
|
#[error("Instruction fetching error")]
|
||||||
InstructionFetchingError(#[source] anyhow::Error),
|
InstructionFetchingError(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[error("Platform emulation error: {0}")]
|
#[error("Platform emulation error")]
|
||||||
PlatformEmulationError(#[source] PlatformError),
|
PlatformEmulationError(#[source] PlatformError),
|
||||||
|
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ use crate::{AiaState, HypervisorDeviceError, HypervisorVmError};
|
|||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Error while calling KVM ioctl for setting up the global interrupt controller.
|
/// Error while calling KVM ioctl for setting up the global interrupt controller.
|
||||||
#[error("Failed creating AIA device: {0}")]
|
#[error("Failed creating AIA device")]
|
||||||
CreateAia(#[source] HypervisorVmError),
|
CreateAia(#[source] HypervisorVmError),
|
||||||
/// Error while setting device attributes for the AIA.
|
/// Error while setting device attributes for the AIA.
|
||||||
#[error("Failed setting device attributes for the AIA: {0}")]
|
#[error("Failed setting device attributes for the AIA")]
|
||||||
SetDeviceAttribute(#[source] HypervisorDeviceError),
|
SetDeviceAttribute(#[source] HypervisorDeviceError),
|
||||||
/// Error while getting device attributes for the AIA.
|
/// Error while getting device attributes for the AIA.
|
||||||
#[error("Failed getting device attributes for the AIA: {0}")]
|
#[error("Failed getting device attributes for the AIA")]
|
||||||
GetDeviceAttribute(#[source] HypervisorDeviceError),
|
GetDeviceAttribute(#[source] HypervisorDeviceError),
|
||||||
}
|
}
|
||||||
pub type Result<T> = result::Result<T, Error>;
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
#![allow(non_camel_case_types, clippy::upper_case_acronyms)]
|
#![allow(non_camel_case_types, dead_code, clippy::upper_case_acronyms)]
|
||||||
|
|
||||||
//
|
//
|
||||||
// CMP-Compare Two Operands
|
// CMP-Compare Two Operands
|
||||||
|
|||||||
@@ -490,7 +490,7 @@ macro_rules! gen_handler_match {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: CpuStateManager> Emulator<'_, T> {
|
impl<T: CpuStateManager> Emulator<'_, T> {
|
||||||
pub fn new(platform: &mut dyn PlatformEmulator<CpuState = T>) -> Emulator<T> {
|
pub fn new(platform: &mut dyn PlatformEmulator<CpuState = T>) -> Emulator<'_, T> {
|
||||||
Emulator { platform }
|
Emulator { platform }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,171 +43,171 @@ pub enum HypervisorCpuError {
|
|||||||
///
|
///
|
||||||
/// Setting standard registers error
|
/// Setting standard registers error
|
||||||
///
|
///
|
||||||
#[error("Failed to set standard register: {0}")]
|
#[error("Failed to set standard register")]
|
||||||
SetStandardRegs(#[source] anyhow::Error),
|
SetStandardRegs(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting standard registers error
|
/// Setting standard registers error
|
||||||
///
|
///
|
||||||
#[error("Failed to get standard registers: {0}")]
|
#[error("Failed to get standard registers")]
|
||||||
GetStandardRegs(#[source] anyhow::Error),
|
GetStandardRegs(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting special register error
|
/// Setting special register error
|
||||||
///
|
///
|
||||||
#[error("Failed to set special registers: {0}")]
|
#[error("Failed to set special registers")]
|
||||||
SetSpecialRegs(#[source] anyhow::Error),
|
SetSpecialRegs(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting standard register error
|
/// Getting standard register error
|
||||||
///
|
///
|
||||||
#[error("Failed to get special registers: {0}")]
|
#[error("Failed to get special registers")]
|
||||||
GetSpecialRegs(#[source] anyhow::Error),
|
GetSpecialRegs(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting floating point registers error
|
/// Setting floating point registers error
|
||||||
///
|
///
|
||||||
#[error("Failed to set floating point registers: {0}")]
|
#[error("Failed to set floating point registers")]
|
||||||
SetFloatingPointRegs(#[source] anyhow::Error),
|
SetFloatingPointRegs(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting floating point register error
|
/// Getting floating point register error
|
||||||
///
|
///
|
||||||
#[error("Failed to get floating points registers: {0}")]
|
#[error("Failed to get floating points registers")]
|
||||||
GetFloatingPointRegs(#[source] anyhow::Error),
|
GetFloatingPointRegs(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting Cpuid error
|
/// Setting Cpuid error
|
||||||
///
|
///
|
||||||
#[error("Failed to set Cpuid: {0}")]
|
#[error("Failed to set Cpuid")]
|
||||||
SetCpuid(#[source] anyhow::Error),
|
SetCpuid(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting Cpuid error
|
/// Getting Cpuid error
|
||||||
///
|
///
|
||||||
#[error("Failed to get Cpuid: {0}")]
|
#[error("Failed to get Cpuid")]
|
||||||
GetCpuid(#[source] anyhow::Error),
|
GetCpuid(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting lapic state error
|
/// Setting lapic state error
|
||||||
///
|
///
|
||||||
#[error("Failed to set Lapic state: {0}")]
|
#[error("Failed to set Lapic state")]
|
||||||
SetLapicState(#[source] anyhow::Error),
|
SetLapicState(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting Lapic state error
|
/// Getting Lapic state error
|
||||||
///
|
///
|
||||||
#[error("Failed to get Lapic state: {0}")]
|
#[error("Failed to get Lapic state")]
|
||||||
GetlapicState(#[source] anyhow::Error),
|
GetlapicState(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting MSR entries error
|
/// Setting MSR entries error
|
||||||
///
|
///
|
||||||
#[error("Failed to set Msr entries: {0}")]
|
#[error("Failed to set Msr entries")]
|
||||||
SetMsrEntries(#[source] anyhow::Error),
|
SetMsrEntries(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting Msr entries error
|
/// Getting Msr entries error
|
||||||
///
|
///
|
||||||
#[error("Failed to get Msr entries: {0}")]
|
#[error("Failed to get Msr entries")]
|
||||||
GetMsrEntries(#[source] anyhow::Error),
|
GetMsrEntries(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting multi-processing state error
|
/// Setting multi-processing state error
|
||||||
///
|
///
|
||||||
#[error("Failed to set MP state: {0}")]
|
#[error("Failed to set MP state")]
|
||||||
SetMpState(#[source] anyhow::Error),
|
SetMpState(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting multi-processing state error
|
/// Getting multi-processing state error
|
||||||
///
|
///
|
||||||
#[error("Failed to get MP state: {0}")]
|
#[error("Failed to get MP state")]
|
||||||
GetMpState(#[source] anyhow::Error),
|
GetMpState(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting Saved Processor Extended States error
|
/// Setting Saved Processor Extended States error
|
||||||
///
|
///
|
||||||
#[cfg(feature = "kvm")]
|
#[cfg(feature = "kvm")]
|
||||||
#[error("Failed to set Saved Processor Extended States: {0}")]
|
#[error("Failed to set Saved Processor Extended States")]
|
||||||
SetXsaveState(#[source] anyhow::Error),
|
SetXsaveState(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting Saved Processor Extended States error
|
/// Getting Saved Processor Extended States error
|
||||||
///
|
///
|
||||||
#[cfg(feature = "kvm")]
|
#[cfg(feature = "kvm")]
|
||||||
#[error("Failed to get Saved Processor Extended States: {0}")]
|
#[error("Failed to get Saved Processor Extended States")]
|
||||||
GetXsaveState(#[source] anyhow::Error),
|
GetXsaveState(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting the VP state components error
|
/// Getting the VP state components error
|
||||||
///
|
///
|
||||||
#[cfg(feature = "mshv")]
|
#[cfg(feature = "mshv")]
|
||||||
#[error("Failed to get VP State Components: {0}")]
|
#[error("Failed to get VP State Components")]
|
||||||
GetAllVpStateComponents(#[source] anyhow::Error),
|
GetAllVpStateComponents(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting the VP state components error
|
/// Setting the VP state components error
|
||||||
///
|
///
|
||||||
#[cfg(feature = "mshv")]
|
#[cfg(feature = "mshv")]
|
||||||
#[error("Failed to set VP State Components: {0}")]
|
#[error("Failed to set VP State Components")]
|
||||||
SetAllVpStateComponents(#[source] anyhow::Error),
|
SetAllVpStateComponents(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting Extended Control Registers error
|
/// Setting Extended Control Registers error
|
||||||
///
|
///
|
||||||
#[error("Failed to set Extended Control Registers: {0}")]
|
#[error("Failed to set Extended Control Registers")]
|
||||||
SetXcsr(#[source] anyhow::Error),
|
SetXcsr(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting Extended Control Registers error
|
/// Getting Extended Control Registers error
|
||||||
///
|
///
|
||||||
#[error("Failed to get Extended Control Registers: {0}")]
|
#[error("Failed to get Extended Control Registers")]
|
||||||
GetXcsr(#[source] anyhow::Error),
|
GetXcsr(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Running Vcpu error
|
/// Running Vcpu error
|
||||||
///
|
///
|
||||||
#[error("Failed to run vcpu: {0}")]
|
#[error("Failed to run vcpu")]
|
||||||
RunVcpu(#[source] anyhow::Error),
|
RunVcpu(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting Vcpu events error
|
/// Getting Vcpu events error
|
||||||
///
|
///
|
||||||
#[error("Failed to get Vcpu events: {0}")]
|
#[error("Failed to get Vcpu events")]
|
||||||
GetVcpuEvents(#[source] anyhow::Error),
|
GetVcpuEvents(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting Vcpu events error
|
/// Setting Vcpu events error
|
||||||
///
|
///
|
||||||
#[error("Failed to set Vcpu events: {0}")]
|
#[error("Failed to set Vcpu events")]
|
||||||
SetVcpuEvents(#[source] anyhow::Error),
|
SetVcpuEvents(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Vcpu Init error
|
/// Vcpu Init error
|
||||||
///
|
///
|
||||||
#[error("Failed to init vcpu: {0}")]
|
#[error("Failed to init vcpu")]
|
||||||
VcpuInit(#[source] anyhow::Error),
|
VcpuInit(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Vcpu Finalize error
|
/// Vcpu Finalize error
|
||||||
///
|
///
|
||||||
#[error("Failed to finalize vcpu: {0}")]
|
#[error("Failed to finalize vcpu")]
|
||||||
VcpuFinalize(#[source] anyhow::Error),
|
VcpuFinalize(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting one reg error
|
/// Setting one reg error
|
||||||
///
|
///
|
||||||
#[error("Failed to set one reg: {0}")]
|
#[error("Failed to set one reg")]
|
||||||
SetRegister(#[source] anyhow::Error),
|
SetRegister(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting one reg error
|
/// Getting one reg error
|
||||||
///
|
///
|
||||||
#[error("Failed to get one reg: {0}")]
|
#[error("Failed to get one reg")]
|
||||||
GetRegister(#[source] anyhow::Error),
|
GetRegister(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting guest clock paused error
|
/// Getting guest clock paused error
|
||||||
///
|
///
|
||||||
#[error("Failed to notify guest its clock was paused: {0}")]
|
#[error("Failed to notify guest its clock was paused")]
|
||||||
NotifyGuestClockPaused(#[source] anyhow::Error),
|
NotifyGuestClockPaused(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting debug register error
|
/// Setting debug register error
|
||||||
///
|
///
|
||||||
#[error("Failed to set debug registers: {0}")]
|
#[error("Failed to set debug registers")]
|
||||||
SetDebugRegs(#[source] anyhow::Error),
|
SetDebugRegs(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting debug register error
|
/// Getting debug register error
|
||||||
///
|
///
|
||||||
#[error("Failed to get debug registers: {0}")]
|
#[error("Failed to get debug registers")]
|
||||||
GetDebugRegs(#[source] anyhow::Error),
|
GetDebugRegs(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting misc register error
|
/// Setting misc register error
|
||||||
///
|
///
|
||||||
#[error("Failed to set misc registers: {0}")]
|
#[error("Failed to set misc registers")]
|
||||||
SetMiscRegs(#[source] anyhow::Error),
|
SetMiscRegs(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting misc register error
|
/// Getting misc register error
|
||||||
///
|
///
|
||||||
#[error("Failed to get misc registers: {0}")]
|
#[error("Failed to get misc registers")]
|
||||||
GetMiscRegs(#[source] anyhow::Error),
|
GetMiscRegs(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Write to Guest Mem
|
/// Write to Guest Mem
|
||||||
///
|
///
|
||||||
#[error("Failed to write to Guest Mem at: {0}")]
|
#[error("Failed to write to Guest Mem at")]
|
||||||
GuestMemWrite(#[source] anyhow::Error),
|
GuestMemWrite(#[source] anyhow::Error),
|
||||||
/// Enabling HyperV SynIC error
|
/// Enabling HyperV SynIC error
|
||||||
///
|
///
|
||||||
@@ -216,68 +216,68 @@ pub enum HypervisorCpuError {
|
|||||||
///
|
///
|
||||||
/// Getting AArch64 core register error
|
/// Getting AArch64 core register error
|
||||||
///
|
///
|
||||||
#[error("Failed to get aarch64 core register: {0}")]
|
#[error("Failed to get aarch64 core register")]
|
||||||
GetAarchCoreRegister(#[source] anyhow::Error),
|
GetAarchCoreRegister(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting AArch64 core register error
|
/// Setting AArch64 core register error
|
||||||
///
|
///
|
||||||
#[error("Failed to set aarch64 core register: {0}")]
|
#[error("Failed to set aarch64 core register")]
|
||||||
SetAarchCoreRegister(#[source] anyhow::Error),
|
SetAarchCoreRegister(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting RISC-V 64-bit core register error
|
/// Getting RISC-V 64-bit core register error
|
||||||
///
|
///
|
||||||
#[error("Failed to get riscv64 core register: {0}")]
|
#[error("Failed to get riscv64 core register")]
|
||||||
GetRiscvCoreRegister(#[source] anyhow::Error),
|
GetRiscvCoreRegister(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting RISC-V 64-bit core register error
|
/// Setting RISC-V 64-bit core register error
|
||||||
///
|
///
|
||||||
#[error("Failed to set riscv64 core register: {0}")]
|
#[error("Failed to set riscv64 core register")]
|
||||||
SetRiscvCoreRegister(#[source] anyhow::Error),
|
SetRiscvCoreRegister(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting registers list error
|
/// Getting registers list error
|
||||||
///
|
///
|
||||||
#[error("Failed to retrieve list of registers: {0}")]
|
#[error("Failed to retrieve list of registers")]
|
||||||
GetRegList(#[source] anyhow::Error),
|
GetRegList(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting AArch64 system register error
|
/// Getting AArch64 system register error
|
||||||
///
|
///
|
||||||
#[error("Failed to get system register: {0}")]
|
#[error("Failed to get system register")]
|
||||||
GetSysRegister(#[source] anyhow::Error),
|
GetSysRegister(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting AArch64 system register error
|
/// Setting AArch64 system register error
|
||||||
///
|
///
|
||||||
#[error("Failed to set system register: {0}")]
|
#[error("Failed to set system register")]
|
||||||
SetSysRegister(#[source] anyhow::Error),
|
SetSysRegister(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting RISC-V 64-bit non-core register error
|
/// Getting RISC-V 64-bit non-core register error
|
||||||
///
|
///
|
||||||
#[error("Failed to get non-core register: {0}")]
|
#[error("Failed to get non-core register")]
|
||||||
GetNonCoreRegister(#[source] anyhow::Error),
|
GetNonCoreRegister(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting RISC-V 64-bit non-core register error
|
/// Setting RISC-V 64-bit non-core register error
|
||||||
///
|
///
|
||||||
#[error("Failed to set non-core register: {0}")]
|
#[error("Failed to set non-core register")]
|
||||||
SetNonCoreRegister(#[source] anyhow::Error),
|
SetNonCoreRegister(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// GVA translation error
|
/// GVA translation error
|
||||||
///
|
///
|
||||||
#[error("Failed to translate GVA: {0}")]
|
#[error("Failed to translate GVA")]
|
||||||
TranslateVirtualAddress(#[source] anyhow::Error),
|
TranslateVirtualAddress(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Set cpu attribute error
|
/// Set cpu attribute error
|
||||||
///
|
///
|
||||||
#[error("Failed to set vcpu attribute: {0}")]
|
#[error("Failed to set vcpu attribute")]
|
||||||
SetVcpuAttribute(#[source] anyhow::Error),
|
SetVcpuAttribute(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Check if cpu has a certain attribute error
|
/// Check if cpu has a certain attribute error
|
||||||
///
|
///
|
||||||
#[error("Failed to check if vcpu has attribute: {0}")]
|
#[error("Failed to check if vcpu has attribute")]
|
||||||
HasVcpuAttribute(#[source] anyhow::Error),
|
HasVcpuAttribute(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Failed to initialize TDX on CPU
|
/// Failed to initialize TDX on CPU
|
||||||
///
|
///
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
#[error("Failed to initialize TDX: {0}")]
|
#[error("Failed to initialize TDX")]
|
||||||
InitializeTdx(#[source] std::io::Error),
|
InitializeTdx(#[source] std::io::Error),
|
||||||
///
|
///
|
||||||
/// Unknown TDX VM call
|
/// Unknown TDX VM call
|
||||||
@@ -295,33 +295,33 @@ pub enum HypervisorCpuError {
|
|||||||
///
|
///
|
||||||
/// Error getting TSC frequency
|
/// Error getting TSC frequency
|
||||||
///
|
///
|
||||||
#[error("Failed to get TSC frequency: {0}")]
|
#[error("Failed to get TSC frequency")]
|
||||||
GetTscKhz(#[source] anyhow::Error),
|
GetTscKhz(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Error setting TSC frequency
|
/// Error setting TSC frequency
|
||||||
///
|
///
|
||||||
#[error("Failed to set TSC frequency: {0}")]
|
#[error("Failed to set TSC frequency")]
|
||||||
SetTscKhz(#[source] anyhow::Error),
|
SetTscKhz(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Error reading value at given GPA
|
/// Error reading value at given GPA
|
||||||
///
|
///
|
||||||
#[error("Failed to read from GPA: {0}")]
|
#[error("Failed to read from GPA")]
|
||||||
GpaRead(#[source] anyhow::Error),
|
GpaRead(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Error writing value at given GPA
|
/// Error writing value at given GPA
|
||||||
///
|
///
|
||||||
#[error("Failed to write to GPA: {0}")]
|
#[error("Failed to write to GPA")]
|
||||||
GpaWrite(#[source] anyhow::Error),
|
GpaWrite(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Error getting CPUID leaf
|
/// Error getting CPUID leaf
|
||||||
///
|
///
|
||||||
#[error("Failed to get CPUID entries: {0}")]
|
#[error("Failed to get CPUID entries")]
|
||||||
GetCpuidVales(#[source] anyhow::Error),
|
GetCpuidVales(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Setting SEV control register error
|
/// Setting SEV control register error
|
||||||
///
|
///
|
||||||
#[cfg(feature = "sev_snp")]
|
#[cfg(feature = "sev_snp")]
|
||||||
#[error("Failed to set sev control register: {0}")]
|
#[error("Failed to set sev control register")]
|
||||||
SetSevControlRegister(#[source] anyhow::Error),
|
SetSevControlRegister(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Unsupported SysReg registers
|
/// Unsupported SysReg registers
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ pub enum HypervisorDeviceError {
|
|||||||
///
|
///
|
||||||
/// Set device attribute error
|
/// Set device attribute error
|
||||||
///
|
///
|
||||||
#[error("Failed to set device attribute: {0}")]
|
#[error("Failed to set device attribute")]
|
||||||
SetDeviceAttribute(#[source] anyhow::Error),
|
SetDeviceAttribute(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Get device attribute error
|
/// Get device attribute error
|
||||||
///
|
///
|
||||||
#[error("Failed to get device attribute: {0}")]
|
#[error("Failed to get device attribute")]
|
||||||
GetDeviceAttribute(#[source] anyhow::Error),
|
GetDeviceAttribute(#[source] anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,37 +27,37 @@ pub enum HypervisorError {
|
|||||||
///
|
///
|
||||||
/// Hypervisor availability check error
|
/// Hypervisor availability check error
|
||||||
///
|
///
|
||||||
#[error("Failed to check availability of the hypervisor: {0}")]
|
#[error("Failed to check availability of the hypervisor")]
|
||||||
HypervisorAvailableCheck(#[source] anyhow::Error),
|
HypervisorAvailableCheck(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// hypervisor creation error
|
/// hypervisor creation error
|
||||||
///
|
///
|
||||||
#[error("Failed to create the hypervisor: {0}")]
|
#[error("Failed to create the hypervisor")]
|
||||||
HypervisorCreate(#[source] anyhow::Error),
|
HypervisorCreate(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Vm creation failure
|
/// Vm creation failure
|
||||||
///
|
///
|
||||||
#[error("Failed to create Vm: {0}")]
|
#[error("Failed to create Vm")]
|
||||||
VmCreate(#[source] anyhow::Error),
|
VmCreate(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Vm setup failure
|
/// Vm setup failure
|
||||||
///
|
///
|
||||||
#[error("Failed to setup Vm: {0}")]
|
#[error("Failed to setup Vm")]
|
||||||
VmSetup(#[source] anyhow::Error),
|
VmSetup(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// API version error
|
/// API version error
|
||||||
///
|
///
|
||||||
#[error("Failed to get API Version: {0}")]
|
#[error("Failed to get API Version")]
|
||||||
GetApiVersion(#[source] anyhow::Error),
|
GetApiVersion(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// CpuId error
|
/// CpuId error
|
||||||
///
|
///
|
||||||
#[error("Failed to get cpuid: {0}")]
|
#[error("Failed to get cpuid")]
|
||||||
GetCpuId(#[source] anyhow::Error),
|
GetCpuId(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Failed to retrieve list of MSRs.
|
/// Failed to retrieve list of MSRs.
|
||||||
///
|
///
|
||||||
#[error("Failed to get the list of supported MSRs: {0}")]
|
#[error("Failed to get the list of supported MSRs")]
|
||||||
GetMsrList(#[source] anyhow::Error),
|
GetMsrList(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// API version is not compatible
|
/// API version is not compatible
|
||||||
@@ -67,22 +67,22 @@ pub enum HypervisorError {
|
|||||||
///
|
///
|
||||||
/// Checking extensions failed
|
/// Checking extensions failed
|
||||||
///
|
///
|
||||||
#[error("Checking extensions: {0}")]
|
#[error("Checking extensions")]
|
||||||
CheckExtensions(#[source] anyhow::Error),
|
CheckExtensions(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Failed to retrieve TDX capabilities
|
/// Failed to retrieve TDX capabilities
|
||||||
///
|
///
|
||||||
#[error("Failed to retrieve TDX capabilities: {0}")]
|
#[error("Failed to retrieve TDX capabilities")]
|
||||||
TdxCapabilities(#[source] anyhow::Error),
|
TdxCapabilities(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Failed to set partition property
|
/// Failed to set partition property
|
||||||
///
|
///
|
||||||
#[error("Failed to set partition property: {0}")]
|
#[error("Failed to set partition property")]
|
||||||
SetPartitionProperty(#[source] anyhow::Error),
|
SetPartitionProperty(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Running on an unsupported CPU
|
/// Running on an unsupported CPU
|
||||||
///
|
///
|
||||||
#[error("Unsupported CPU: {0}")]
|
#[error("Unsupported CPU")]
|
||||||
UnsupportedCpu(#[source] anyhow::Error),
|
UnsupportedCpu(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Launching a VM with unsupported VM Type
|
/// Launching a VM with unsupported VM Type
|
||||||
|
|||||||
@@ -19,31 +19,6 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::kvm::{KvmError, KvmResult};
|
use crate::kvm::{KvmError, KvmResult};
|
||||||
|
|
||||||
// This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having
|
|
||||||
// an instance of that structure.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! offset_of {
|
|
||||||
($str:ty, $field:ident) => {{
|
|
||||||
let tmp: std::mem::MaybeUninit<$str> = std::mem::MaybeUninit::uninit();
|
|
||||||
let base = tmp.as_ptr();
|
|
||||||
|
|
||||||
// Avoid warnings when nesting `unsafe` blocks.
|
|
||||||
#[allow(unused_unsafe)]
|
|
||||||
// SAFETY: The pointer is valid and aligned, just not initialised. Using `addr_of` ensures
|
|
||||||
// that we don't actually read from `base` (which would be UB) nor create an intermediate
|
|
||||||
// reference.
|
|
||||||
let member = unsafe { core::ptr::addr_of!((*base).$field) } as *const u8;
|
|
||||||
|
|
||||||
// Avoid warnings when nesting `unsafe` blocks.
|
|
||||||
#[allow(unused_unsafe)]
|
|
||||||
// SAFETY: The two pointers are within the same allocated object `tmp`. All requirements
|
|
||||||
// from offset_from are upheld.
|
|
||||||
unsafe {
|
|
||||||
member.offset_from(base as *const u8) as usize
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Following are macros that help with getting the ID of a aarch64 core register.
|
// Following are macros that help with getting the ID of a aarch64 core register.
|
||||||
// The core register are represented by the user_pt_regs structure. Look for it in
|
// The core register are represented by the user_pt_regs structure. Look for it in
|
||||||
// arch/arm64/include/uapi/asm/ptrace.h.
|
// arch/arm64/include/uapi/asm/ptrace.h.
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ use std::any::Any;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||||
|
use std::mem::offset_of;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
@@ -34,6 +36,8 @@ pub use crate::aarch64::{check_required_kvm_extensions, is_system_register, Vcpu
|
|||||||
use crate::arch::aarch64::gic::{Vgic, VgicConfig};
|
use crate::arch::aarch64::gic::{Vgic, VgicConfig};
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
use crate::arch::riscv64::aia::{Vaia, VaiaConfig};
|
use crate::arch::riscv64::aia::{Vaia, VaiaConfig};
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
use crate::arm64_core_reg_id;
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
use crate::riscv64::aia::KvmAiaImsics;
|
use crate::riscv64::aia::KvmAiaImsics;
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
@@ -41,12 +45,10 @@ pub use crate::riscv64::{
|
|||||||
aia::AiaImsicsState as AiaState, check_required_kvm_extensions, is_non_core_register,
|
aia::AiaImsicsState as AiaState, check_required_kvm_extensions, is_non_core_register,
|
||||||
VcpuKvmState,
|
VcpuKvmState,
|
||||||
};
|
};
|
||||||
use crate::vm::{self, InterruptSourceConfig, VmOps};
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
use crate::{arm64_core_reg_id, offset_of};
|
|
||||||
use crate::{cpu, hypervisor, vec_with_array_field, HypervisorType};
|
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
use crate::{offset_of, riscv64_reg_id};
|
use crate::riscv64_reg_id;
|
||||||
|
use crate::vm::{self, InterruptSourceConfig, VmOps};
|
||||||
|
use crate::{cpu, hypervisor, HypervisorType};
|
||||||
// x86_64 dependencies
|
// x86_64 dependencies
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub mod x86_64;
|
pub mod x86_64;
|
||||||
@@ -93,20 +95,20 @@ pub use kvm_bindings::{
|
|||||||
};
|
};
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
use kvm_bindings::{
|
use kvm_bindings::{
|
||||||
kvm_regs, user_fpsimd_state, user_pt_regs, KVM_GUESTDBG_USE_HW, KVM_NR_SPSR, KVM_REG_ARM64,
|
kvm_regs, user_pt_regs, KVM_GUESTDBG_USE_HW, KVM_NR_SPSR, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG,
|
||||||
KVM_REG_ARM64_SYSREG, KVM_REG_ARM64_SYSREG_CRM_MASK, KVM_REG_ARM64_SYSREG_CRN_MASK,
|
KVM_REG_ARM64_SYSREG_CRM_MASK, KVM_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_OP0_MASK,
|
||||||
KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP2_MASK,
|
KVM_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM_CORE,
|
||||||
KVM_REG_ARM_CORE, KVM_REG_SIZE_U128, KVM_REG_SIZE_U32, KVM_REG_SIZE_U64,
|
KVM_REG_SIZE_U128, KVM_REG_SIZE_U32, KVM_REG_SIZE_U64,
|
||||||
};
|
};
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
use kvm_bindings::{kvm_riscv_core, user_regs_struct, KVM_REG_RISCV_CORE};
|
use kvm_bindings::{kvm_riscv_core, KVM_REG_RISCV_CORE};
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
use kvm_bindings::{kvm_run__bindgen_ty_1, KVMIO};
|
use kvm_bindings::{kvm_run__bindgen_ty_1, KVMIO};
|
||||||
pub use kvm_ioctls::{Cap, Kvm, VcpuExit};
|
pub use kvm_ioctls::{Cap, Kvm, VcpuExit};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use vfio_ioctls::VfioDeviceFd;
|
use vfio_ioctls::VfioDeviceFd;
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
use vmm_sys_util::{ioctl::ioctl_with_val, ioctl_ioc_nr, ioctl_iowr_nr};
|
use vmm_sys_util::{ioctl::ioctl_with_val, ioctl_iowr_nr};
|
||||||
pub use {kvm_bindings, kvm_ioctls};
|
pub use {kvm_bindings, kvm_ioctls};
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
@@ -119,8 +121,6 @@ const KVM_CAP_SGX_ATTRIBUTE: u32 = 196;
|
|||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use vmm_sys_util::ioctl_io_nr;
|
use vmm_sys_util::ioctl_io_nr;
|
||||||
#[cfg(all(not(feature = "tdx"), target_arch = "x86_64"))]
|
|
||||||
use vmm_sys_util::ioctl_ioc_nr;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
ioctl_io_nr!(KVM_NMI, kvm_bindings::KVMIO, 0x9a);
|
ioctl_io_nr!(KVM_NMI, kvm_bindings::KVMIO, 0x9a);
|
||||||
@@ -693,10 +693,6 @@ impl vm::Vm for KvmVm {
|
|||||||
/// entries, as per the `KVM_SET_GSI_ROUTING` ioctl.
|
/// entries, as per the `KVM_SET_GSI_ROUTING` ioctl.
|
||||||
///
|
///
|
||||||
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
|
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
|
||||||
let mut irq_routing =
|
|
||||||
vec_with_array_field::<kvm_irq_routing, kvm_irq_routing_entry>(entries.len());
|
|
||||||
irq_routing[0].nr = entries.len() as u32;
|
|
||||||
irq_routing[0].flags = 0;
|
|
||||||
let entries: Vec<kvm_irq_routing_entry> = entries
|
let entries: Vec<kvm_irq_routing_entry> = entries
|
||||||
.iter()
|
.iter()
|
||||||
.map(|entry| match entry {
|
.map(|entry| match entry {
|
||||||
@@ -706,17 +702,11 @@ impl vm::Vm for KvmVm {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// SAFETY: irq_routing initialized with entries.len() and now it is being turned into
|
let irq_routing =
|
||||||
// entries_slice with entries.len() again. It is guaranteed to be large enough to hold
|
kvm_bindings::fam_wrappers::KvmIrqRouting::from_entries(&entries).unwrap();
|
||||||
// everything from entries.
|
|
||||||
unsafe {
|
|
||||||
let entries_slice: &mut [kvm_irq_routing_entry] =
|
|
||||||
irq_routing[0].entries.as_mut_slice(entries.len());
|
|
||||||
entries_slice.copy_from_slice(&entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fd
|
self.fd
|
||||||
.set_gsi_routing(&irq_routing[0])
|
.set_gsi_routing(&irq_routing)
|
||||||
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
|
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1450,7 +1440,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
|
|
||||||
// Now moving on to floating point registers which are stored in the user_fpsimd_state in the kernel:
|
// Now moving on to floating point registers which are stored in the user_fpsimd_state in the kernel:
|
||||||
// https://elixir.free-electrons.com/linux/v4.9.62/source/arch/arm64/include/uapi/asm/kvm.h#L53
|
// https://elixir.free-electrons.com/linux/v4.9.62/source/arch/arm64/include/uapi/asm/kvm.h#L53
|
||||||
let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs);
|
let mut off = offset_of!(kvm_regs, fp_regs.vregs);
|
||||||
for i in 0..32 {
|
for i in 0..32 {
|
||||||
let mut bytes = [0_u8; 16];
|
let mut bytes = [0_u8; 16];
|
||||||
self.fd
|
self.fd
|
||||||
@@ -1463,7 +1453,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Floating-point Status Register
|
// Floating-point Status Register
|
||||||
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
|
let off = offset_of!(kvm_regs, fp_regs.fpsr);
|
||||||
let mut bytes = [0_u8; 4];
|
let mut bytes = [0_u8; 4];
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
@@ -1473,7 +1463,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
state.fp_regs.fpsr = u32::from_le_bytes(bytes);
|
state.fp_regs.fpsr = u32::from_le_bytes(bytes);
|
||||||
|
|
||||||
// Floating-point Control Register
|
// Floating-point Control Register
|
||||||
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
|
let off = offset_of!(kvm_regs, fp_regs.fpcr);
|
||||||
let mut bytes = [0_u8; 4];
|
let mut bytes = [0_u8; 4];
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
@@ -1507,7 +1497,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
state.mode = u64::from_le_bytes(bytes);
|
state.mode = u64::from_le_bytes(bytes);
|
||||||
};
|
};
|
||||||
($reg_name:ident) => {
|
($reg_name:ident) => {
|
||||||
let off = offset_of!(kvm_riscv_core, regs, user_regs_struct, $reg_name);
|
let off = offset_of!(kvm_riscv_core, regs.$reg_name);
|
||||||
let mut bytes = [0_u8; 8];
|
let mut bytes = [0_u8; 8];
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
@@ -1654,7 +1644,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
off += std::mem::size_of::<u64>();
|
off += std::mem::size_of::<u64>();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs);
|
let mut off = offset_of!(kvm_regs, fp_regs.vregs);
|
||||||
for i in 0..32 {
|
for i in 0..32 {
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
@@ -1667,7 +1657,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
off += mem::size_of::<u128>();
|
off += mem::size_of::<u128>();
|
||||||
}
|
}
|
||||||
|
|
||||||
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
|
let off = offset_of!(kvm_regs, fp_regs.fpsr);
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -1677,7 +1667,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetAarchCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetAarchCoreRegister(e.into()))?;
|
||||||
|
|
||||||
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
|
let off = offset_of!(kvm_regs, fp_regs.fpcr);
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -1715,7 +1705,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
.map_err(|e| cpu::HypervisorCpuError::SetRiscvCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetRiscvCoreRegister(e.into()))?;
|
||||||
};
|
};
|
||||||
($reg_name:ident) => {
|
($reg_name:ident) => {
|
||||||
let off = offset_of!(kvm_riscv_core, regs, user_regs_struct, $reg_name);
|
let off = offset_of!(kvm_riscv_core, regs.$reg_name);
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -2291,10 +2281,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
///
|
///
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> cpu::Result<()> {
|
fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> cpu::Result<()> {
|
||||||
let kreg_off = offset_of!(kvm_regs, regs);
|
|
||||||
|
|
||||||
// Get the register index of the PSTATE (Processor State) register.
|
// Get the register index of the PSTATE (Processor State) register.
|
||||||
let pstate = offset_of!(user_pt_regs, pstate) + kreg_off;
|
let pstate = offset_of!(kvm_regs, regs.pstate);
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -2307,7 +2295,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
// Other vCPUs are powered off initially awaiting PSCI wakeup.
|
// Other vCPUs are powered off initially awaiting PSCI wakeup.
|
||||||
if cpu_id == 0 {
|
if cpu_id == 0 {
|
||||||
// Setting the PC (Processor Counter) to the current program address (kernel address).
|
// Setting the PC (Processor Counter) to the current program address (kernel address).
|
||||||
let pc = offset_of!(user_pt_regs, pc) + kreg_off;
|
let pc = offset_of!(kvm_regs, regs.pc);
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -2321,7 +2309,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
// "The device tree blob (dtb) must be placed on an 8-byte boundary and must
|
// "The device tree blob (dtb) must be placed on an 8-byte boundary and must
|
||||||
// not exceed 2 megabytes in size." -> https://www.kernel.org/doc/Documentation/arm64/booting.txt.
|
// not exceed 2 megabytes in size." -> https://www.kernel.org/doc/Documentation/arm64/booting.txt.
|
||||||
// We are choosing to place it the end of DRAM. See `get_fdt_addr`.
|
// We are choosing to place it the end of DRAM. See `get_fdt_addr`.
|
||||||
let regs0 = offset_of!(user_pt_regs, regs) + kreg_off;
|
let regs0 = offset_of!(kvm_regs, regs.regs);
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -2340,7 +2328,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
///
|
///
|
||||||
fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> cpu::Result<()> {
|
fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> cpu::Result<()> {
|
||||||
// Setting the A0 () to the hartid of this CPU.
|
// Setting the A0 () to the hartid of this CPU.
|
||||||
let a0 = offset_of!(kvm_riscv_core, regs, user_regs_struct, a0);
|
let a0 = offset_of!(kvm_riscv_core, regs.a0);
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -2351,7 +2339,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
.map_err(|e| cpu::HypervisorCpuError::SetRiscvCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetRiscvCoreRegister(e.into()))?;
|
||||||
|
|
||||||
// Setting the PC (Processor Counter) to the current program address (kernel address).
|
// Setting the PC (Processor Counter) to the current program address (kernel address).
|
||||||
let pc = offset_of!(kvm_riscv_core, regs, user_regs_struct, pc);
|
let pc = offset_of!(kvm_riscv_core, regs.pc);
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -2364,7 +2352,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
// Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
|
// Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
|
||||||
// "The device tree blob (dtb) must be placed on an 8-byte boundary and must
|
// "The device tree blob (dtb) must be placed on an 8-byte boundary and must
|
||||||
// not exceed 64 kilobytes in size." -> https://www.kernel.org/doc/Documentation/arch/riscv/boot.txt.
|
// not exceed 64 kilobytes in size." -> https://www.kernel.org/doc/Documentation/arch/riscv/boot.txt.
|
||||||
let a1 = offset_of!(kvm_riscv_core, regs, user_regs_struct, a1);
|
let a1 = offset_of!(kvm_riscv_core, regs.a1);
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -2956,12 +2944,16 @@ impl KvmVcpu {
|
|||||||
///
|
///
|
||||||
fn set_xsave(&self, xsave: &XsaveState) -> cpu::Result<()> {
|
fn set_xsave(&self, xsave: &XsaveState) -> cpu::Result<()> {
|
||||||
let xsave: kvm_bindings::kvm_xsave = (*xsave).clone().into();
|
let xsave: kvm_bindings::kvm_xsave = (*xsave).clone().into();
|
||||||
|
// SAFETY: Here we trust the kernel not to read past the end of the kvm_xsave struct
|
||||||
|
// when calling the kvm-ioctl library function.
|
||||||
|
unsafe {
|
||||||
self.fd
|
self.fd
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_xsave(&xsave)
|
.set_xsave(&xsave)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
@@ -3027,7 +3019,7 @@ mod tests {
|
|||||||
let vcpu0 = vm.create_vcpu(0, None).unwrap();
|
let vcpu0 = vm.create_vcpu(0, None).unwrap();
|
||||||
|
|
||||||
let core_regs = StandardRegisters::from(kvm_riscv_core {
|
let core_regs = StandardRegisters::from(kvm_riscv_core {
|
||||||
regs: user_regs_struct {
|
regs: kvm_bindings::user_regs_struct {
|
||||||
pc: 0x00,
|
pc: 0x00,
|
||||||
ra: 0x01,
|
ra: 0x01,
|
||||||
sp: 0x02,
|
sp: 0x02,
|
||||||
|
|||||||
@@ -13,41 +13,6 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::kvm::{KvmError, KvmResult};
|
use crate::kvm::{KvmError, KvmResult};
|
||||||
|
|
||||||
// This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having
|
|
||||||
// an instance of that structure.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! _offset_of {
|
|
||||||
($str:ty, $field:ident) => {{
|
|
||||||
let tmp: std::mem::MaybeUninit<$str> = std::mem::MaybeUninit::uninit();
|
|
||||||
let base = tmp.as_ptr();
|
|
||||||
|
|
||||||
// Avoid warnings when nesting `unsafe` blocks.
|
|
||||||
#[allow(unused_unsafe)]
|
|
||||||
// SAFETY: The pointer is valid and aligned, just not initialised. Using `addr_of` ensures
|
|
||||||
// that we don't actually read from `base` (which would be UB) nor create an intermediate
|
|
||||||
// reference.
|
|
||||||
let member = unsafe { core::ptr::addr_of!((*base).$field) } as *const u8;
|
|
||||||
|
|
||||||
// Avoid warnings when nesting `unsafe` blocks.
|
|
||||||
#[allow(unused_unsafe)]
|
|
||||||
// SAFETY: The two pointers are within the same allocated object `tmp`. All requirements
|
|
||||||
// from offset_from are upheld.
|
|
||||||
unsafe {
|
|
||||||
member.offset_from(base as *const u8) as usize
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! offset_of {
|
|
||||||
($reg_struct:ty, $field:ident) => {
|
|
||||||
$crate::_offset_of!($reg_struct, $field)
|
|
||||||
};
|
|
||||||
($outer_reg_struct:ty, $outer_field:ident, $($inner_reg_struct:ty, $inner_field:ident), +) => {
|
|
||||||
$crate::_offset_of!($outer_reg_struct, $outer_field) + offset_of!($($inner_reg_struct, $inner_field), +)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Following are macros that help with getting the ID of a riscv64 register, including config registers, core registers and timer registers.
|
// Following are macros that help with getting the ID of a riscv64 register, including config registers, core registers and timer registers.
|
||||||
// The register of core registers are wrapped in the `user_regs_struct` structure. See:
|
// The register of core registers are wrapped in the `user_regs_struct` structure. See:
|
||||||
// https://elixir.bootlin.com/linux/v6.10/source/arch/riscv/include/uapi/asm/kvm.h#L62
|
// https://elixir.bootlin.com/linux/v6.10/source/arch/riscv/include/uapi/asm/kvm.h#L62
|
||||||
|
|||||||
@@ -1711,10 +1711,11 @@ impl MshvVcpu {
|
|||||||
if let Some(reg_page) = self.fd.get_vp_reg_page() {
|
if let Some(reg_page) = self.fd.get_vp_reg_page() {
|
||||||
let vp_reg_page = reg_page.0;
|
let vp_reg_page = reg_page.0;
|
||||||
set_gp_regs_field_ptr!(vp_reg_page, rax, ret_rax);
|
set_gp_regs_field_ptr!(vp_reg_page, rax, ret_rax);
|
||||||
// SAFETY: access union fields
|
// SAFETY: access raw pointer to reg page, access union fields
|
||||||
unsafe {
|
unsafe {
|
||||||
(*vp_reg_page).__bindgen_anon_1.__bindgen_anon_1.rip = info.header.rip + insn_len;
|
(*vp_reg_page).__bindgen_anon_1.__bindgen_anon_1.rip = info.header.rip + insn_len;
|
||||||
(*vp_reg_page).dirty |= 1 << HV_X64_REGISTER_CLASS_IP;
|
(*vp_reg_page).dirty |= 1 << HV_X64_REGISTER_CLASS_IP;
|
||||||
|
(*vp_reg_page).dirty |= 1 << HV_X64_REGISTER_CLASS_GENERAL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let arr_reg_name_value = [
|
let arr_reg_name_value = [
|
||||||
|
|||||||
@@ -58,196 +58,196 @@ pub enum HypervisorVmError {
|
|||||||
///
|
///
|
||||||
/// Create Vcpu error
|
/// Create Vcpu error
|
||||||
///
|
///
|
||||||
#[error("Failed to create Vcpu: {0}")]
|
#[error("Failed to create Vcpu")]
|
||||||
CreateVcpu(#[source] anyhow::Error),
|
CreateVcpu(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Identity map address error
|
/// Identity map address error
|
||||||
///
|
///
|
||||||
#[error("Failed to set identity map address: {0}")]
|
#[error("Failed to set identity map address")]
|
||||||
SetIdentityMapAddress(#[source] anyhow::Error),
|
SetIdentityMapAddress(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// TSS address error
|
/// TSS address error
|
||||||
///
|
///
|
||||||
#[error("Failed to set TSS address: {0}")]
|
#[error("Failed to set TSS address")]
|
||||||
SetTssAddress(#[source] anyhow::Error),
|
SetTssAddress(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Create interrupt controller error
|
/// Create interrupt controller error
|
||||||
///
|
///
|
||||||
#[error("Failed to create interrupt controller: {0}")]
|
#[error("Failed to create interrupt controller")]
|
||||||
CreateIrq(#[source] anyhow::Error),
|
CreateIrq(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Register interrupt event error
|
/// Register interrupt event error
|
||||||
///
|
///
|
||||||
#[error("Failed to register interrupt event: {0}")]
|
#[error("Failed to register interrupt event")]
|
||||||
RegisterIrqFd(#[source] anyhow::Error),
|
RegisterIrqFd(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Un register interrupt event error
|
/// Un register interrupt event error
|
||||||
///
|
///
|
||||||
#[error("Failed to unregister interrupt event: {0}")]
|
#[error("Failed to unregister interrupt event")]
|
||||||
UnregisterIrqFd(#[source] anyhow::Error),
|
UnregisterIrqFd(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Register IO event error
|
/// Register IO event error
|
||||||
///
|
///
|
||||||
#[error("Failed to register IO event: {0}")]
|
#[error("Failed to register IO event")]
|
||||||
RegisterIoEvent(#[source] anyhow::Error),
|
RegisterIoEvent(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Unregister IO event error
|
/// Unregister IO event error
|
||||||
///
|
///
|
||||||
#[error("Failed to unregister IO event: {0}")]
|
#[error("Failed to unregister IO event")]
|
||||||
UnregisterIoEvent(#[source] anyhow::Error),
|
UnregisterIoEvent(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Set GSI routing error
|
/// Set GSI routing error
|
||||||
///
|
///
|
||||||
#[error("Failed to set GSI routing: {0}")]
|
#[error("Failed to set GSI routing")]
|
||||||
SetGsiRouting(#[source] anyhow::Error),
|
SetGsiRouting(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Create user memory error
|
/// Create user memory error
|
||||||
///
|
///
|
||||||
#[error("Failed to create user memory: {0}")]
|
#[error("Failed to create user memory")]
|
||||||
CreateUserMemory(#[source] anyhow::Error),
|
CreateUserMemory(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Remove user memory region error
|
/// Remove user memory region error
|
||||||
///
|
///
|
||||||
#[error("Failed to remove user memory: {0}")]
|
#[error("Failed to remove user memory")]
|
||||||
RemoveUserMemory(#[source] anyhow::Error),
|
RemoveUserMemory(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Create device error
|
/// Create device error
|
||||||
///
|
///
|
||||||
#[error("Failed to set GSI routing: {0}")]
|
#[error("Failed to set GSI routing")]
|
||||||
CreateDevice(#[source] anyhow::Error),
|
CreateDevice(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Get preferred target error
|
/// Get preferred target error
|
||||||
///
|
///
|
||||||
#[error("Failed to get preferred target: {0}")]
|
#[error("Failed to get preferred target")]
|
||||||
GetPreferredTarget(#[source] anyhow::Error),
|
GetPreferredTarget(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Enable split Irq error
|
/// Enable split Irq error
|
||||||
///
|
///
|
||||||
#[error("Failed to enable split Irq: {0}")]
|
#[error("Failed to enable split Irq")]
|
||||||
EnableSplitIrq(#[source] anyhow::Error),
|
EnableSplitIrq(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Enable SGX attribute error
|
/// Enable SGX attribute error
|
||||||
///
|
///
|
||||||
#[error("Failed to enable SGX attribute: {0}")]
|
#[error("Failed to enable SGX attribute")]
|
||||||
EnableSgxAttribute(#[source] anyhow::Error),
|
EnableSgxAttribute(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Get clock error
|
/// Get clock error
|
||||||
///
|
///
|
||||||
#[error("Failed to get clock: {0}")]
|
#[error("Failed to get clock")]
|
||||||
GetClock(#[source] anyhow::Error),
|
GetClock(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Set clock error
|
/// Set clock error
|
||||||
///
|
///
|
||||||
#[error("Failed to set clock: {0}")]
|
#[error("Failed to set clock")]
|
||||||
SetClock(#[source] anyhow::Error),
|
SetClock(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Create passthrough device
|
/// Create passthrough device
|
||||||
///
|
///
|
||||||
#[error("Failed to create passthrough device: {0}")]
|
#[error("Failed to create passthrough device")]
|
||||||
CreatePassthroughDevice(#[source] anyhow::Error),
|
CreatePassthroughDevice(#[source] anyhow::Error),
|
||||||
/// Write to Guest memory
|
/// Write to Guest memory
|
||||||
///
|
///
|
||||||
#[error("Failed to write to guest memory: {0}")]
|
#[error("Failed to write to guest memory")]
|
||||||
GuestMemWrite(#[source] anyhow::Error),
|
GuestMemWrite(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Read Guest memory
|
/// Read Guest memory
|
||||||
///
|
///
|
||||||
#[error("Failed to read guest memory: {0}")]
|
#[error("Failed to read guest memory")]
|
||||||
GuestMemRead(#[source] anyhow::Error),
|
GuestMemRead(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Read from MMIO Bus
|
/// Read from MMIO Bus
|
||||||
///
|
///
|
||||||
#[error("Failed to read from MMIO Bus: {0}")]
|
#[error("Failed to read from MMIO Bus")]
|
||||||
MmioBusRead(#[source] anyhow::Error),
|
MmioBusRead(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Write to MMIO Bus
|
/// Write to MMIO Bus
|
||||||
///
|
///
|
||||||
#[error("Failed to write to MMIO Bus: {0}")]
|
#[error("Failed to write to MMIO Bus")]
|
||||||
MmioBusWrite(#[source] anyhow::Error),
|
MmioBusWrite(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Read from IO Bus
|
/// Read from IO Bus
|
||||||
///
|
///
|
||||||
#[error("Failed to read from IO Bus: {0}")]
|
#[error("Failed to read from IO Bus")]
|
||||||
IoBusRead(#[source] anyhow::Error),
|
IoBusRead(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Write to IO Bus
|
/// Write to IO Bus
|
||||||
///
|
///
|
||||||
#[error("Failed to write to IO Bus: {0}")]
|
#[error("Failed to write to IO Bus")]
|
||||||
IoBusWrite(#[source] anyhow::Error),
|
IoBusWrite(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Start dirty log error
|
/// Start dirty log error
|
||||||
///
|
///
|
||||||
#[error("Failed to get dirty log: {0}")]
|
#[error("Failed to get dirty log")]
|
||||||
StartDirtyLog(#[source] anyhow::Error),
|
StartDirtyLog(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Stop dirty log error
|
/// Stop dirty log error
|
||||||
///
|
///
|
||||||
#[error("Failed to get dirty log: {0}")]
|
#[error("Failed to get dirty log")]
|
||||||
StopDirtyLog(#[source] anyhow::Error),
|
StopDirtyLog(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Get dirty log error
|
/// Get dirty log error
|
||||||
///
|
///
|
||||||
#[error("Failed to get dirty log: {0}")]
|
#[error("Failed to get dirty log")]
|
||||||
GetDirtyLog(#[source] anyhow::Error),
|
GetDirtyLog(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Assert virtual interrupt error
|
/// Assert virtual interrupt error
|
||||||
///
|
///
|
||||||
#[error("Failed to assert virtual Interrupt: {0}")]
|
#[error("Failed to assert virtual Interrupt")]
|
||||||
AssertVirtualInterrupt(#[source] anyhow::Error),
|
AssertVirtualInterrupt(#[source] anyhow::Error),
|
||||||
|
|
||||||
#[cfg(feature = "sev_snp")]
|
#[cfg(feature = "sev_snp")]
|
||||||
///
|
///
|
||||||
/// Error initializing SEV-SNP on the VM
|
/// Error initializing SEV-SNP on the VM
|
||||||
///
|
///
|
||||||
#[error("Failed to initialize SEV-SNP: {0}")]
|
#[error("Failed to initialize SEV-SNP")]
|
||||||
InitializeSevSnp(#[source] std::io::Error),
|
InitializeSevSnp(#[source] std::io::Error),
|
||||||
|
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
///
|
///
|
||||||
/// Error initializing TDX on the VM
|
/// Error initializing TDX on the VM
|
||||||
///
|
///
|
||||||
#[error("Failed to initialize TDX: {0}")]
|
#[error("Failed to initialize TDX")]
|
||||||
InitializeTdx(#[source] std::io::Error),
|
InitializeTdx(#[source] std::io::Error),
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
///
|
///
|
||||||
/// Error finalizing the TDX configuration on the VM
|
/// Error finalizing the TDX configuration on the VM
|
||||||
///
|
///
|
||||||
#[error("Failed to finalize TDX: {0}")]
|
#[error("Failed to finalize TDX")]
|
||||||
FinalizeTdx(#[source] std::io::Error),
|
FinalizeTdx(#[source] std::io::Error),
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
///
|
///
|
||||||
/// Error initializing the TDX memory region
|
/// Error initializing the TDX memory region
|
||||||
///
|
///
|
||||||
#[error("Failed to initialize memory region TDX: {0}")]
|
#[error("Failed to initialize memory region TDX")]
|
||||||
InitMemRegionTdx(#[source] std::io::Error),
|
InitMemRegionTdx(#[source] std::io::Error),
|
||||||
///
|
///
|
||||||
/// Create Vgic error
|
/// Create Vgic error
|
||||||
///
|
///
|
||||||
#[error("Failed to create Vgic: {0}")]
|
#[error("Failed to create Vgic")]
|
||||||
CreateVgic(#[source] anyhow::Error),
|
CreateVgic(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Create Vaia error
|
/// Create Vaia error
|
||||||
///
|
///
|
||||||
#[error("Failed to create Vaia: {0}")]
|
#[error("Failed to create Vaia")]
|
||||||
CreateVaia(#[source] anyhow::Error),
|
CreateVaia(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Import isolated pages error
|
/// Import isolated pages error
|
||||||
///
|
///
|
||||||
#[error("Failed to import isolated pages: {0}")]
|
#[error("Failed to import isolated pages")]
|
||||||
ImportIsolatedPages(#[source] anyhow::Error),
|
ImportIsolatedPages(#[source] anyhow::Error),
|
||||||
/// Failed to complete isolated import
|
/// Failed to complete isolated import
|
||||||
///
|
///
|
||||||
#[error("Failed to complete isolated import: {0}")]
|
#[error("Failed to complete isolated import")]
|
||||||
CompleteIsolatedImport(#[source] anyhow::Error),
|
CompleteIsolatedImport(#[source] anyhow::Error),
|
||||||
/// Failed to set VM property
|
/// Failed to set VM property
|
||||||
///
|
///
|
||||||
#[error("Failed to set VM property: {0}")]
|
#[error("Failed to set VM property")]
|
||||||
SetVmProperty(#[source] anyhow::Error),
|
SetVmProperty(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Modify GPA host access error
|
/// Modify GPA host access error
|
||||||
///
|
///
|
||||||
#[cfg(feature = "sev_snp")]
|
#[cfg(feature = "sev_snp")]
|
||||||
#[error("Failed to modify GPA host access: {0}")]
|
#[error("Failed to modify GPA host access")]
|
||||||
ModifyGpaHostAccess(#[source] anyhow::Error),
|
ModifyGpaHostAccess(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Failed to mmap
|
/// Failed to mmap
|
||||||
@@ -258,7 +258,7 @@ pub enum HypervisorVmError {
|
|||||||
///
|
///
|
||||||
/// Failed to initialize VM
|
/// Failed to initialize VM
|
||||||
///
|
///
|
||||||
#[error("Failed to initialize VM: {0}")]
|
#[error("Failed to initialize VM")]
|
||||||
InitializeVm(#[source] anyhow::Error),
|
InitializeVm(#[source] anyhow::Error),
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ version = "0.1.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
epoll = "4.3.3"
|
epoll = "4.3.3"
|
||||||
getrandom = "0.3.1"
|
getrandom = "0.3.3"
|
||||||
libc = "0.2.167"
|
libc = "0.2.167"
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
net_gen = { path = "../net_gen" }
|
net_gen = { path = "../net_gen" }
|
||||||
rate_limiter = { path = "../rate_limiter" }
|
rate_limiter = { path = "../rate_limiter" }
|
||||||
serde = { version = "1.0.208", features = ["derive"] }
|
serde = { version = "1.0.208", features = ["derive"] }
|
||||||
thiserror = "2.0.6"
|
thiserror = { workspace = true }
|
||||||
virtio-bindings = { workspace = true }
|
virtio-bindings = { workspace = true }
|
||||||
virtio-queue = { workspace = true }
|
virtio-queue = { workspace = true }
|
||||||
vm-memory = { workspace = true, features = [
|
vm-memory = { workspace = true, features = [
|
||||||
@@ -24,7 +24,6 @@ vm-virtio = { path = "../vm-virtio" }
|
|||||||
vmm-sys-util = { workspace = true }
|
vmm-sys-util = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
once_cell = "1.20.2"
|
|
||||||
pnet = "0.35.0"
|
pnet = "0.35.0"
|
||||||
pnet_datalink = "0.35.0"
|
pnet_datalink = "0.35.0"
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
|||||||
@@ -4,19 +4,17 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use libc::c_uint;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use virtio_bindings::virtio_net::{
|
use virtio_bindings::virtio_net::{
|
||||||
VIRTIO_NET_CTRL_GUEST_OFFLOADS, VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, VIRTIO_NET_CTRL_MQ,
|
VIRTIO_NET_CTRL_GUEST_OFFLOADS, VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, VIRTIO_NET_CTRL_MQ,
|
||||||
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN,
|
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN,
|
||||||
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, VIRTIO_NET_ERR, VIRTIO_NET_F_GUEST_CSUM,
|
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, VIRTIO_NET_ERR, VIRTIO_NET_OK,
|
||||||
VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
|
|
||||||
VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_OK,
|
|
||||||
};
|
};
|
||||||
use virtio_queue::{Queue, QueueT};
|
use virtio_queue::{Queue, QueueT};
|
||||||
use vm_memory::{ByteValued, Bytes, GuestMemoryError};
|
use vm_memory::{ByteValued, Bytes, GuestMemoryError};
|
||||||
use vm_virtio::{AccessPlatform, Translatable};
|
use vm_virtio::{AccessPlatform, Translatable};
|
||||||
|
|
||||||
|
use super::virtio_features_to_tap_offload;
|
||||||
use crate::{GuestMemoryMmap, Tap};
|
use crate::{GuestMemoryMmap, Tap};
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
@@ -163,24 +161,3 @@ impl CtrlQueue {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn virtio_features_to_tap_offload(features: u64) -> c_uint {
|
|
||||||
let mut tap_offloads: c_uint = 0;
|
|
||||||
if features & (1 << VIRTIO_NET_F_GUEST_CSUM) != 0 {
|
|
||||||
tap_offloads |= net_gen::TUN_F_CSUM;
|
|
||||||
}
|
|
||||||
if features & (1 << VIRTIO_NET_F_GUEST_TSO4) != 0 {
|
|
||||||
tap_offloads |= net_gen::TUN_F_TSO4;
|
|
||||||
}
|
|
||||||
if features & (1 << VIRTIO_NET_F_GUEST_TSO6) != 0 {
|
|
||||||
tap_offloads |= net_gen::TUN_F_TSO6;
|
|
||||||
}
|
|
||||||
if features & (1 << VIRTIO_NET_F_GUEST_ECN) != 0 {
|
|
||||||
tap_offloads |= net_gen::TUN_F_TSO_ECN;
|
|
||||||
}
|
|
||||||
if features & (1 << VIRTIO_NET_F_GUEST_UFO) != 0 {
|
|
||||||
tap_offloads |= net_gen::TUN_F_UFO;
|
|
||||||
}
|
|
||||||
|
|
||||||
tap_offloads
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ pub use tap::{Error as TapError, Tap};
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Failed to create a socket: {0}")]
|
#[error("Failed to create a socket")]
|
||||||
CreateSocket(#[source] IoError),
|
CreateSocket(#[source] IoError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,27 +12,27 @@ use super::{vnet_hdr_len, MacAddr, Tap, TapError};
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Failed to convert an hexadecimal string into an integer: {0}")]
|
#[error("Failed to convert an hexadecimal string into an integer")]
|
||||||
ConvertHexStringToInt(#[source] std::num::ParseIntError),
|
ConvertHexStringToInt(#[source] 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,
|
MultiQueueNoTapSupport,
|
||||||
#[error("Error related to the multiqueue support (no support device side)")]
|
#[error("Error related to the multiqueue support (no support device side)")]
|
||||||
MultiQueueNoDeviceSupport,
|
MultiQueueNoDeviceSupport,
|
||||||
#[error("Failed to read the TAP flags from sysfs: {0}")]
|
#[error("Failed to read the TAP flags from sysfs")]
|
||||||
ReadSysfsTunFlags(#[source] io::Error),
|
ReadSysfsTunFlags(#[source] io::Error),
|
||||||
#[error("Open tap device failed: {0}")]
|
#[error("Open tap device failed")]
|
||||||
TapOpen(#[source] TapError),
|
TapOpen(#[source] TapError),
|
||||||
#[error("Setting tap IP and/or netmask failed: {0}")]
|
#[error("Setting tap IP and/or netmask failed")]
|
||||||
TapSetIpNetmask(#[source] TapError),
|
TapSetIpNetmask(#[source] TapError),
|
||||||
#[error("Setting MAC address failed: {0}")]
|
#[error("Setting MAC address failed")]
|
||||||
TapSetMac(#[source] TapError),
|
TapSetMac(#[source] TapError),
|
||||||
#[error("Getting MAC address failed: {0}")]
|
#[error("Getting MAC address failed")]
|
||||||
TapGetMac(#[source] TapError),
|
TapGetMac(#[source] TapError),
|
||||||
#[error("Setting vnet header size failed: {0}")]
|
#[error("Setting vnet header size failed")]
|
||||||
TapSetVnetHdrSize(#[source] TapError),
|
TapSetVnetHdrSize(#[source] TapError),
|
||||||
#[error("Setting MTU failed: {0}")]
|
#[error("Setting MTU failed")]
|
||||||
TapSetMtu(#[source] TapError),
|
TapSetMtu(#[source] TapError),
|
||||||
#[error("Enabling tap interface failed: {0}")]
|
#[error("Enabling tap interface failed")]
|
||||||
TapEnable(#[source] TapError),
|
TapEnable(#[source] TapError),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,9 +58,10 @@ fn check_mq_support(if_name: &Option<&str>, queue_pairs: usize) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new virtio network device with the given IP address and
|
/// Opens a Tap device and configures it.
|
||||||
/// netmask.
|
///
|
||||||
pub fn open_tap(
|
/// Afterward, further RX queues can be opened with a common config.
|
||||||
|
fn open_tap_rx_q_0(
|
||||||
if_name: Option<&str>,
|
if_name: Option<&str>,
|
||||||
ip_addr: Option<IpAddr>,
|
ip_addr: Option<IpAddr>,
|
||||||
netmask: Option<IpAddr>,
|
netmask: Option<IpAddr>,
|
||||||
@@ -68,29 +69,17 @@ pub fn open_tap(
|
|||||||
mtu: Option<u16>,
|
mtu: Option<u16>,
|
||||||
num_rx_q: usize,
|
num_rx_q: usize,
|
||||||
flags: Option<i32>,
|
flags: Option<i32>,
|
||||||
) -> Result<Vec<Tap>> {
|
) -> Result<Tap> {
|
||||||
let mut taps: Vec<Tap> = Vec::new();
|
|
||||||
let mut ifname: String = String::new();
|
|
||||||
let vnet_hdr_size = vnet_hdr_len() as i32;
|
|
||||||
// Check if the given interface exists before we create it.
|
// Check if the given interface exists before we create it.
|
||||||
let tap_existed = if_name.is_some_and(|n| Path::new(&format!("/sys/class/net/{n}")).exists());
|
let tap_exists = if_name.is_some_and(|n| Path::new(&format!("/sys/class/net/{n}")).exists());
|
||||||
|
|
||||||
// In case the tap interface already exists, check if the number of
|
let tap = match if_name {
|
||||||
// queues is appropriate. The tap might not support multiqueue while
|
|
||||||
// the number of queues indicates the user expects multiple queues, or
|
|
||||||
// on the contrary, the tap might support multiqueue while the number
|
|
||||||
// of queues indicates the user doesn't expect multiple queues.
|
|
||||||
check_mq_support(&if_name, num_rx_q)?;
|
|
||||||
|
|
||||||
for i in 0..num_rx_q {
|
|
||||||
let tap: Tap;
|
|
||||||
if i == 0 {
|
|
||||||
tap = match if_name {
|
|
||||||
Some(name) => Tap::open_named(name, num_rx_q, flags).map_err(Error::TapOpen)?,
|
Some(name) => Tap::open_named(name, num_rx_q, flags).map_err(Error::TapOpen)?,
|
||||||
|
// Create a new Tap device in Linux, if none was specified.
|
||||||
None => Tap::new(num_rx_q).map_err(Error::TapOpen)?,
|
None => Tap::new(num_rx_q).map_err(Error::TapOpen)?,
|
||||||
};
|
};
|
||||||
// Don't overwrite ip configuration of existing interfaces:
|
// Don't overwrite ip configuration of existing interfaces:
|
||||||
if !tap_existed {
|
if !tap_exists {
|
||||||
if let Some(ip) = ip_addr {
|
if let Some(ip) = ip_addr {
|
||||||
tap.set_ip_addr(ip, netmask)
|
tap.set_ip_addr(ip, netmask)
|
||||||
.map_err(Error::TapSetIpNetmask)?;
|
.map_err(Error::TapSetIpNetmask)?;
|
||||||
@@ -111,14 +100,46 @@ pub fn open_tap(
|
|||||||
}
|
}
|
||||||
tap.enable().map_err(Error::TapEnable)?;
|
tap.enable().map_err(Error::TapEnable)?;
|
||||||
|
|
||||||
tap.set_vnet_hdr_size(vnet_hdr_size)
|
tap.set_vnet_hdr_size(vnet_hdr_len() as i32)
|
||||||
.map_err(Error::TapSetVnetHdrSize)?;
|
.map_err(Error::TapSetVnetHdrSize)?;
|
||||||
|
|
||||||
|
Ok(tap)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new virtio network device with the given IP address and
|
||||||
|
/// netmask.
|
||||||
|
pub fn open_tap(
|
||||||
|
if_name: Option<&str>,
|
||||||
|
ip_addr: Option<IpAddr>,
|
||||||
|
netmask: Option<IpAddr>,
|
||||||
|
host_mac: &mut Option<MacAddr>,
|
||||||
|
mtu: Option<u16>,
|
||||||
|
num_rx_q: usize,
|
||||||
|
flags: Option<i32>,
|
||||||
|
) -> Result<Vec<Tap>> {
|
||||||
|
let mut taps: Vec<Tap> = Vec::new();
|
||||||
|
let mut ifname: String = String::new();
|
||||||
|
|
||||||
|
// In case the tap interface already exists, check if the number of
|
||||||
|
// queues is appropriate. The tap might not support multiqueue while
|
||||||
|
// the number of queues indicates the user expects multiple queues, or
|
||||||
|
// on the contrary, the tap might support multiqueue while the number
|
||||||
|
// of queues indicates the user doesn't expect multiple queues.
|
||||||
|
check_mq_support(&if_name, num_rx_q)?;
|
||||||
|
|
||||||
|
for i in 0..num_rx_q {
|
||||||
|
let tap: Tap;
|
||||||
|
if i == 0 {
|
||||||
|
// Special handling is required for the first RX queue, such as
|
||||||
|
// configuring the device. Subsequent iterations will then use the
|
||||||
|
// same device.
|
||||||
|
tap = open_tap_rx_q_0(if_name, ip_addr, netmask, host_mac, mtu, num_rx_q, flags)?;
|
||||||
|
// Set the name of the tap device we open in subsequent iterations.
|
||||||
ifname = String::from_utf8(tap.get_if_name()).unwrap();
|
ifname = String::from_utf8(tap.get_if_name()).unwrap();
|
||||||
} else {
|
} else {
|
||||||
tap = Tap::open_named(ifname.as_str(), num_rx_q, flags).map_err(Error::TapOpen)?;
|
tap = Tap::open_named(ifname.as_str(), num_rx_q, flags).map_err(Error::TapOpen)?;
|
||||||
|
|
||||||
tap.set_vnet_hdr_size(vnet_hdr_size)
|
tap.set_vnet_hdr_size(vnet_hdr_len() as i32)
|
||||||
.map_err(Error::TapSetVnetHdrSize)?;
|
.map_err(Error::TapSetVnetHdrSize)?;
|
||||||
}
|
}
|
||||||
taps.push(tap);
|
taps.push(tap);
|
||||||
|
|||||||
@@ -353,27 +353,27 @@ pub struct NetCounters {
|
|||||||
pub enum NetQueuePairError {
|
pub enum NetQueuePairError {
|
||||||
#[error("No memory configured")]
|
#[error("No memory configured")]
|
||||||
NoMemoryConfigured,
|
NoMemoryConfigured,
|
||||||
#[error("Error registering listener: {0}")]
|
#[error("Error registering listener")]
|
||||||
RegisterListener(#[source] io::Error),
|
RegisterListener(#[source] io::Error),
|
||||||
#[error("Error unregistering listener: {0}")]
|
#[error("Error unregistering listener")]
|
||||||
UnregisterListener(#[source] io::Error),
|
UnregisterListener(#[source] io::Error),
|
||||||
#[error("Error writing to the TAP device: {0}")]
|
#[error("Error writing to the TAP device")]
|
||||||
WriteTap(#[source] io::Error),
|
WriteTap(#[source] io::Error),
|
||||||
#[error("Error reading from the TAP device: {0}")]
|
#[error("Error reading from the TAP device")]
|
||||||
ReadTap(#[source] io::Error),
|
ReadTap(#[source] io::Error),
|
||||||
#[error("Error related to guest memory: {0}")]
|
#[error("Error related to guest memory")]
|
||||||
GuestMemory(#[source] vm_memory::GuestMemoryError),
|
GuestMemory(#[source] vm_memory::GuestMemoryError),
|
||||||
#[error("Returned an error while iterating through the queue: {0}")]
|
#[error("Returned an error while iterating through the queue")]
|
||||||
QueueIteratorFailed(#[source] virtio_queue::Error),
|
QueueIteratorFailed(#[source] virtio_queue::Error),
|
||||||
#[error("Descriptor chain is too short")]
|
#[error("Descriptor chain is too short")]
|
||||||
DescriptorChainTooShort,
|
DescriptorChainTooShort,
|
||||||
#[error("Descriptor chain does not contain valid descriptors")]
|
#[error("Descriptor chain does not contain valid descriptors")]
|
||||||
DescriptorChainInvalid,
|
DescriptorChainInvalid,
|
||||||
#[error("Failed to determine if queue needed notification: {0}")]
|
#[error("Failed to determine if queue needed notification")]
|
||||||
QueueNeedsNotification(#[source] virtio_queue::Error),
|
QueueNeedsNotification(#[source] virtio_queue::Error),
|
||||||
#[error("Failed to enable notification on the queue: {0}")]
|
#[error("Failed to enable notification on the queue")]
|
||||||
QueueEnableNotification(#[source] virtio_queue::Error),
|
QueueEnableNotification(#[source] virtio_queue::Error),
|
||||||
#[error("Failed to add used index to the queue: {0}")]
|
#[error("Failed to add used index to the queue")]
|
||||||
QueueAddUsed(#[source] virtio_queue::Error),
|
QueueAddUsed(#[source] virtio_queue::Error),
|
||||||
#[error("Descriptor with invalid virtio-net header")]
|
#[error("Descriptor with invalid virtio-net header")]
|
||||||
DescriptorInvalidHeader,
|
DescriptorInvalidHeader,
|
||||||
|
|||||||
@@ -20,23 +20,32 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::mac::MAC_ADDR_LEN;
|
use crate::mac::MAC_ADDR_LEN;
|
||||||
|
|
||||||
|
/// Maximum length of a network interface name in Linux, excluding any NUL byte.
|
||||||
|
///
|
||||||
|
/// This corresponds to `IFNAMSIZ` in Linux [[0]].
|
||||||
|
///
|
||||||
|
/// [0]: https://elixir.bootlin.com/linux/v6.12/source/include/uapi/linux/if.h#L33
|
||||||
|
const MAX_INTERFACE_NAME_LEN: usize = 15;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Couldn't open /dev/net/tun: {0}")]
|
#[error("Couldn't open /dev/net/tun")]
|
||||||
OpenTun(#[source] IoError),
|
OpenTun(#[source] IoError),
|
||||||
#[error("Unable to configure tap interface: {0}")]
|
#[error("Unable to configure tap interface")]
|
||||||
ConfigureTap(#[source] IoError),
|
ConfigureTap(#[source] IoError),
|
||||||
#[error("Unable to retrieve features: {0}")]
|
#[error("Unable to retrieve features")]
|
||||||
GetFeatures(#[source] IoError),
|
GetFeatures(#[source] IoError),
|
||||||
#[error("Missing multiqueue support in the kernel")]
|
#[error("Missing multiqueue support in the kernel")]
|
||||||
MultiQueueKernelSupport,
|
MultiQueueKernelSupport,
|
||||||
#[error("ioctl ({0}) failed: {1}")]
|
#[error("ioctl ({0}) failed: {1}")]
|
||||||
IoctlError(c_ulong, #[source] IoError),
|
IoctlError(c_ulong, #[source] IoError),
|
||||||
#[error("Failed to create a socket: {0}")]
|
#[error("Failed to create a socket")]
|
||||||
NetUtil(#[source] NetUtilError),
|
NetUtil(#[source] NetUtilError),
|
||||||
#[error("Invalid interface name")]
|
#[error("Interface name too long (max length is {MAX_INTERFACE_NAME_LEN}): {0}")]
|
||||||
InvalidIfname,
|
IfnameTooLong(String),
|
||||||
#[error("Error parsing MAC data: {0}")]
|
#[error("Invalid interface name (does it exist?): {0}")]
|
||||||
|
InvalidIfname(String),
|
||||||
|
#[error("Error parsing MAC data")]
|
||||||
MacParsing(#[source] IoError),
|
MacParsing(#[source] IoError),
|
||||||
#[error("Invalid netmask")]
|
#[error("Invalid netmask")]
|
||||||
InvalidNetmask,
|
InvalidNetmask,
|
||||||
@@ -76,16 +85,14 @@ impl std::clone::Clone for Tap {
|
|||||||
fn build_terminated_if_name(if_name: &str) -> Result<Vec<u8>> {
|
fn build_terminated_if_name(if_name: &str) -> Result<Vec<u8>> {
|
||||||
// Convert the string slice to bytes, and shadow the variable,
|
// Convert the string slice to bytes, and shadow the variable,
|
||||||
// since we no longer need the &str version.
|
// since we no longer need the &str version.
|
||||||
let if_name = if_name.as_bytes();
|
let bytes = if_name.as_bytes();
|
||||||
|
|
||||||
// TODO: the 16usize limit of the if_name member from struct Tap is pretty arbitrary.
|
if bytes.len() > MAX_INTERFACE_NAME_LEN {
|
||||||
// We leave it as is for now, but this should be refactored at some point.
|
return Err(Error::IfnameTooLong(if_name.to_string()));
|
||||||
if if_name.len() > 15 {
|
|
||||||
return Err(Error::InvalidIfname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut terminated_if_name = vec![b'\0'; if_name.len() + 1];
|
let mut terminated_if_name = vec![b'\0'; bytes.len() + 1];
|
||||||
terminated_if_name[..if_name.len()].copy_from_slice(if_name);
|
terminated_if_name[..bytes.len()].copy_from_slice(bytes);
|
||||||
|
|
||||||
Ok(terminated_if_name)
|
Ok(terminated_if_name)
|
||||||
}
|
}
|
||||||
@@ -313,7 +320,10 @@ impl Tap {
|
|||||||
// SAFETY: ifru_ivalue contains the ifindex and is set by the previous ioctl
|
// SAFETY: ifru_ivalue contains the ifindex and is set by the previous ioctl
|
||||||
unsafe {
|
unsafe {
|
||||||
match ifreq.ifr_ifru.ifru_ivalue {
|
match ifreq.ifr_ifru.ifru_ivalue {
|
||||||
0 => return Err(Error::InvalidIfname),
|
0 => {
|
||||||
|
let name = String::from_utf8_lossy(&self.if_name).to_string();
|
||||||
|
return Err(Error::InvalidIfname(name));
|
||||||
|
}
|
||||||
i => i,
|
i => i,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -506,11 +516,10 @@ impl AsRawFd for Tap {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::sync::{mpsc, Mutex};
|
use std::sync::{mpsc, LazyLock, Mutex};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{str, thread};
|
use std::{str, thread};
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket};
|
use pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket};
|
||||||
use pnet::packet::ip::IpNextHeaderProtocols;
|
use pnet::packet::ip::IpNextHeaderProtocols;
|
||||||
use pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet};
|
use pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet};
|
||||||
@@ -525,13 +534,14 @@ mod tests {
|
|||||||
static DATA_STRING: &str = "test for tap";
|
static DATA_STRING: &str = "test for tap";
|
||||||
static SUBNET_MASK: &str = "255.255.255.0";
|
static SUBNET_MASK: &str = "255.255.255.0";
|
||||||
|
|
||||||
// We needed to have a mutex as a global variable, so we used once_cell for testing. The main
|
// We needed to have a mutex as a global variable, so we use a once cell for testing. The main
|
||||||
// potential problem, caused by tests being run in parallel by cargo, is creating different
|
// potential problem, caused by tests being run in parallel by cargo, is creating different
|
||||||
// TAPs and trying to associate the same address, so we hide the IP address &str behind this
|
// TAPs and trying to associate the same address, so we hide the IP address &str behind this
|
||||||
// mutex, more as a convention to remember to lock it at the very beginning of each function
|
// mutex, more as a convention to remember to lock it at the very beginning of each function
|
||||||
// susceptible to this issue. Another variant is to use a different IP address per function,
|
// susceptible to this issue. Another variant is to use a different IP address per function,
|
||||||
// but we must remember to pick an unique one each time.
|
// but we must remember to pick an unique one each time.
|
||||||
static TAP_IP_LOCK: Lazy<Mutex<&'static str>> = Lazy::new(|| Mutex::new("192.168.241.1"));
|
static TAP_IP_LOCK: LazyLock<Mutex<&'static str>> =
|
||||||
|
LazyLock::new(|| Mutex::new("192.168.241.1"));
|
||||||
|
|
||||||
// Describes the outcomes we are currently interested in when parsing a packet (we use
|
// Describes the outcomes we are currently interested in when parsing a packet (we use
|
||||||
// an UDP packet for testing).
|
// an UDP packet for testing).
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ name = "option_parser"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
thiserror = "2.0.6"
|
thiserror = { workspace = true }
|
||||||
|
|||||||
@@ -306,11 +306,11 @@ pub struct Tuple<S, T>(pub Vec<(S, T)>);
|
|||||||
pub enum TupleError {
|
pub enum TupleError {
|
||||||
#[error("invalid value: {0}")]
|
#[error("invalid value: {0}")]
|
||||||
InvalidValue(String),
|
InvalidValue(String),
|
||||||
#[error("split outside brackets: {0}")]
|
#[error("split outside brackets")]
|
||||||
SplitOutsideBrackets(#[source] OptionParserError),
|
SplitOutsideBrackets(#[source] OptionParserError),
|
||||||
#[error("invalid integer list: {0}")]
|
#[error("invalid integer list")]
|
||||||
InvalidIntegerList(#[source] IntegerListParseError),
|
InvalidIntegerList(#[source] IntegerListParseError),
|
||||||
#[error("invalid integer: {0}")]
|
#[error("invalid integer")]
|
||||||
InvalidInteger(#[source] ParseIntError),
|
InvalidInteger(#[source] ParseIntError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ version = "0.1.0"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
kvm = ["vfio-ioctls/kvm"]
|
kvm = ["hypervisor/kvm", "vfio-ioctls/kvm"]
|
||||||
mshv = ["vfio-ioctls/mshv"]
|
mshv = ["hypervisor/mshv", "vfio-ioctls/mshv"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.94"
|
anyhow = "1.0.94"
|
||||||
@@ -16,7 +16,7 @@ hypervisor = { path = "../hypervisor" }
|
|||||||
libc = "0.2.167"
|
libc = "0.2.167"
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
serde = { version = "1.0.208", features = ["derive"] }
|
serde = { version = "1.0.208", features = ["derive"] }
|
||||||
thiserror = "2.0.6"
|
thiserror = { workspace = true }
|
||||||
vfio-bindings = { workspace = true, features = ["fam-wrappers"] }
|
vfio-bindings = { workspace = true, features = ["fam-wrappers"] }
|
||||||
vfio-ioctls = { workspace = true, default-features = false }
|
vfio-ioctls = { workspace = true, default-features = false }
|
||||||
vfio_user = { workspace = true }
|
vfio_user = { workspace = true }
|
||||||
|
|||||||
@@ -27,16 +27,16 @@ const NUM_DEVICE_IDS: usize = 32;
|
|||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum PciRootError {
|
pub enum PciRootError {
|
||||||
/// Could not allocate device address space for the device.
|
/// Could not allocate device address space for the device.
|
||||||
#[error("Could not allocate device address space for the device: {0}")]
|
#[error("Could not allocate device address space for the device")]
|
||||||
AllocateDeviceAddrs(#[source] PciDeviceError),
|
AllocateDeviceAddrs(#[source] PciDeviceError),
|
||||||
/// Could not allocate an IRQ number.
|
/// Could not allocate an IRQ number.
|
||||||
#[error("Could not allocate an IRQ number")]
|
#[error("Could not allocate an IRQ number")]
|
||||||
AllocateIrq,
|
AllocateIrq,
|
||||||
/// Could not add a device to the port io bus.
|
/// Could not add a device to the port io bus.
|
||||||
#[error("Could not add a device to the port io bus: {0}")]
|
#[error("Could not add a device to the port io bus")]
|
||||||
PioInsert(#[source] vm_device::BusError),
|
PioInsert(#[source] vm_device::BusError),
|
||||||
/// Could not add a device to the mmio bus.
|
/// Could not add a device to the mmio bus.
|
||||||
#[error("Could not add a device to the mmio bus: {0}")]
|
#[error("Could not add a device to the mmio bus")]
|
||||||
MmioInsert(#[source] vm_device::BusError),
|
MmioInsert(#[source] vm_device::BusError),
|
||||||
/// Could not find an available device slot on the PCI bus.
|
/// Could not find an available device slot on the PCI bus.
|
||||||
#[error("Could not find an available device slot on the PCI bus")]
|
#[error("Could not find an available device slot on the PCI bus")]
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ use crate::PciBarConfiguration;
|
|||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Setup of the device capabilities failed.
|
/// Setup of the device capabilities failed.
|
||||||
#[error("Setup of the device capabilities failed: {0}")]
|
#[error("Setup of the device capabilities failed")]
|
||||||
CapabilitiesSetup(#[source] configuration::Error),
|
CapabilitiesSetup(#[source] configuration::Error),
|
||||||
/// Allocating space for an IO BAR failed.
|
/// Allocating space for an IO BAR failed.
|
||||||
#[error("Allocating space for an IO BAR failed")]
|
#[error("Allocating space for an IO BAR failed")]
|
||||||
IoAllocationFailed(u64),
|
IoAllocationFailed(u64),
|
||||||
/// Registering an IO BAR failed.
|
/// Registering an IO BAR failed.
|
||||||
#[error("Registering an IO BAR failed: {0}")]
|
#[error("Registering an IO BAR failed")]
|
||||||
IoRegistrationFailed(u64, #[source] configuration::Error),
|
IoRegistrationFailed(u64, #[source] configuration::Error),
|
||||||
/// Expected resource not found.
|
/// Expected resource not found.
|
||||||
#[error("Expected resource not found")]
|
#[error("Expected resource not found")]
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ pub fn msi_num_enabled_vectors(msg_ctl: u16) -> usize {
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Failed enabling the interrupt route: {0}")]
|
#[error("Failed enabling the interrupt route")]
|
||||||
EnableInterruptRoute(#[source] io::Error),
|
EnableInterruptRoute(#[source] io::Error),
|
||||||
#[error("Failed updating the interrupt route: {0}")]
|
#[error("Failed updating the interrupt route")]
|
||||||
UpdateInterruptRoute(#[source] io::Error),
|
UpdateInterruptRoute(#[source] io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ pub const MSIX_CONFIG_ID: &str = "msix_config";
|
|||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Failed enabling the interrupt route.
|
/// Failed enabling the interrupt route.
|
||||||
#[error("Failed enabling the interrupt route: {0}")]
|
#[error("Failed enabling the interrupt route")]
|
||||||
EnableInterruptRoute(#[source] io::Error),
|
EnableInterruptRoute(#[source] io::Error),
|
||||||
/// Failed updating the interrupt route.
|
/// Failed updating the interrupt route.
|
||||||
#[error("Failed updating the interrupt route: {0}")]
|
#[error("Failed updating the interrupt route")]
|
||||||
UpdateInterruptRoute(#[source] io::Error),
|
UpdateInterruptRoute(#[source] io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,17 +47,17 @@ pub(crate) const VFIO_COMMON_ID: &str = "vfio_common";
|
|||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum VfioPciError {
|
pub enum VfioPciError {
|
||||||
#[error("Failed to create user memory region: {0}")]
|
#[error("Failed to create user memory region")]
|
||||||
CreateUserMemoryRegion(#[source] HypervisorVmError),
|
CreateUserMemoryRegion(#[source] HypervisorVmError),
|
||||||
#[error("Failed to DMA map: {0} for device {1} (guest BDF: {2})")]
|
#[error("Failed to DMA map: {0} for device {1} (guest BDF: {2})")]
|
||||||
DmaMap(#[source] vfio_ioctls::VfioError, PathBuf, PciBdf),
|
DmaMap(#[source] vfio_ioctls::VfioError, PathBuf, PciBdf),
|
||||||
#[error("Failed to DMA unmap: {0} for device {1} (guest BDF: {2})")]
|
#[error("Failed to DMA unmap: {0} for device {1} (guest BDF: {2})")]
|
||||||
DmaUnmap(#[source] vfio_ioctls::VfioError, PathBuf, PciBdf),
|
DmaUnmap(#[source] vfio_ioctls::VfioError, PathBuf, PciBdf),
|
||||||
#[error("Failed to enable INTx: {0}")]
|
#[error("Failed to enable INTx")]
|
||||||
EnableIntx(#[source] VfioError),
|
EnableIntx(#[source] VfioError),
|
||||||
#[error("Failed to enable MSI: {0}")]
|
#[error("Failed to enable MSI")]
|
||||||
EnableMsi(#[source] VfioError),
|
EnableMsi(#[source] VfioError),
|
||||||
#[error("Failed to enable MSI-x: {0}")]
|
#[error("Failed to enable MSI-x")]
|
||||||
EnableMsix(#[source] VfioError),
|
EnableMsix(#[source] VfioError),
|
||||||
#[error("Failed to mmap the area")]
|
#[error("Failed to mmap the area")]
|
||||||
MmapArea,
|
MmapArea,
|
||||||
@@ -67,13 +67,13 @@ pub enum VfioPciError {
|
|||||||
RegionAlignment,
|
RegionAlignment,
|
||||||
#[error("Invalid region size")]
|
#[error("Invalid region size")]
|
||||||
RegionSize,
|
RegionSize,
|
||||||
#[error("Failed to retrieve MsiConfigState: {0}")]
|
#[error("Failed to retrieve MsiConfigState")]
|
||||||
RetrieveMsiConfigState(#[source] anyhow::Error),
|
RetrieveMsiConfigState(#[source] anyhow::Error),
|
||||||
#[error("Failed to retrieve MsixConfigState: {0}")]
|
#[error("Failed to retrieve MsixConfigState")]
|
||||||
RetrieveMsixConfigState(#[source] anyhow::Error),
|
RetrieveMsixConfigState(#[source] anyhow::Error),
|
||||||
#[error("Failed to retrieve PciConfigurationState: {0}")]
|
#[error("Failed to retrieve PciConfigurationState")]
|
||||||
RetrievePciConfigurationState(#[source] anyhow::Error),
|
RetrievePciConfigurationState(#[source] anyhow::Error),
|
||||||
#[error("Failed to retrieve VfioCommonState: {0}")]
|
#[error("Failed to retrieve VfioCommonState")]
|
||||||
RetrieveVfioCommonState(#[source] anyhow::Error),
|
RetrieveVfioCommonState(#[source] anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,9 +318,9 @@ impl MmioRegionRange for Vec<MmioRegion> {
|
|||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum VfioError {
|
pub enum VfioError {
|
||||||
#[error("Kernel VFIO error: {0}")]
|
#[error("Kernel VFIO error")]
|
||||||
KernelVfio(#[source] vfio_ioctls::VfioError),
|
KernelVfio(#[source] vfio_ioctls::VfioError),
|
||||||
#[error("VFIO user error: {0}")]
|
#[error("VFIO user error")]
|
||||||
VfioUser(#[source] vfio_user::Error),
|
VfioUser(#[source] vfio_user::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,17 +40,17 @@ pub struct VfioUserPciDevice {
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum VfioUserPciDeviceError {
|
pub enum VfioUserPciDeviceError {
|
||||||
#[error("Client error: {0}")]
|
#[error("Client error")]
|
||||||
Client(#[source] VfioUserError),
|
Client(#[source] VfioUserError),
|
||||||
#[error("Failed to map VFIO PCI region into guest: {0}")]
|
#[error("Failed to map VFIO PCI region into guest")]
|
||||||
MapRegionGuest(#[source] HypervisorVmError),
|
MapRegionGuest(#[source] HypervisorVmError),
|
||||||
#[error("Failed to DMA map: {0}")]
|
#[error("Failed to DMA map")]
|
||||||
DmaMap(#[source] VfioUserError),
|
DmaMap(#[source] VfioUserError),
|
||||||
#[error("Failed to DMA unmap: {0}")]
|
#[error("Failed to DMA unmap")]
|
||||||
DmaUnmap(#[source] VfioUserError),
|
DmaUnmap(#[source] VfioUserError),
|
||||||
#[error("Failed to initialize legacy interrupts: {0}")]
|
#[error("Failed to initialize legacy interrupts")]
|
||||||
InitializeLegacyInterrupts(#[source] VfioPciError),
|
InitializeLegacyInterrupts(#[source] VfioPciError),
|
||||||
#[error("Failed to create VfioCommon: {0}")]
|
#[error("Failed to create VfioCommon")]
|
||||||
CreateVfioCommon(#[source] VfioPciError),
|
CreateVfioCommon(#[source] VfioPciError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,5 +11,4 @@ dirs = "6.0.0"
|
|||||||
serde = { version = "1.0.208", features = ["derive", "rc"] }
|
serde = { version = "1.0.208", features = ["derive", "rc"] }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
test_infra = { path = "../test_infra" }
|
test_infra = { path = "../test_infra" }
|
||||||
thiserror = "2.0.6"
|
thiserror = { workspace = true }
|
||||||
wait-timeout = "0.2.0"
|
|
||||||
|
|||||||
@@ -24,18 +24,12 @@ pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-arm64-custom-20210929-
|
|||||||
enum Error {
|
enum Error {
|
||||||
#[error("boot time could not be parsed")]
|
#[error("boot time could not be parsed")]
|
||||||
BootTimeParse,
|
BootTimeParse,
|
||||||
#[error("infrastructure failure: {0}")]
|
#[error("infrastructure failure")]
|
||||||
Infra(#[source] InfraError),
|
Infra(#[from] InfraError),
|
||||||
#[error("restore time could not be parsed")]
|
#[error("restore time could not be parsed")]
|
||||||
RestoreTimeParse,
|
RestoreTimeParse,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<InfraError> for Error {
|
|
||||||
fn from(e: InfraError) -> Self {
|
|
||||||
Self::Infra(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const BLK_IO_TEST_IMG: &str = "/var/tmp/ch-blk-io-test.img";
|
const BLK_IO_TEST_IMG: &str = "/var/tmp/ch-blk-io-test.img";
|
||||||
|
|
||||||
pub fn init_tests() {
|
pub fn init_tests() {
|
||||||
@@ -74,9 +68,9 @@ fn direct_kernel_boot_path() -> PathBuf {
|
|||||||
|
|
||||||
let mut kernel_path = workload_path;
|
let mut kernel_path = workload_path;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
kernel_path.push("vmlinux");
|
kernel_path.push("vmlinux-x86_64");
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
kernel_path.push("Image");
|
kernel_path.push("Image-arm64");
|
||||||
|
|
||||||
kernel_path
|
kernel_path
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ version = "0.1.0"
|
|||||||
epoll = "4.3.3"
|
epoll = "4.3.3"
|
||||||
libc = "0.2.167"
|
libc = "0.2.167"
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
thiserror = "2.0.6"
|
thiserror = { workspace = true }
|
||||||
vmm-sys-util = { workspace = true }
|
vmm-sys-util = { workspace = true }
|
||||||
|
|||||||
@@ -23,23 +23,23 @@ pub enum Error {
|
|||||||
ThreadSpawn(#[source] io::Error),
|
ThreadSpawn(#[source] io::Error),
|
||||||
|
|
||||||
/// Cannot create epoll context.
|
/// Cannot create epoll context.
|
||||||
#[error("Error creating epoll context: {0}")]
|
#[error("Error creating epoll context")]
|
||||||
Epoll(#[source] io::Error),
|
Epoll(#[source] io::Error),
|
||||||
|
|
||||||
/// Cannot create EventFd.
|
/// Cannot create EventFd.
|
||||||
#[error("Error creating EventFd: {0}")]
|
#[error("Error creating EventFd")]
|
||||||
EventFd(#[source] io::Error),
|
EventFd(#[source] io::Error),
|
||||||
|
|
||||||
/// Cannot create RateLimiter.
|
/// Cannot create RateLimiter.
|
||||||
#[error("Error creating RateLimiter: {0}")]
|
#[error("Error creating RateLimiter")]
|
||||||
RateLimiter(#[source] io::Error),
|
RateLimiter(#[source] io::Error),
|
||||||
|
|
||||||
/// Cannot read from EventFd.
|
/// Cannot read from EventFd.
|
||||||
#[error("Error reading from EventFd: {0}")]
|
#[error("Error reading from EventFd")]
|
||||||
EventFdRead(#[source] io::Error),
|
EventFdRead(#[source] io::Error),
|
||||||
|
|
||||||
/// Cannot write to EventFd.
|
/// Cannot write to EventFd.
|
||||||
#[error("Error writing to EventFd: {0}")]
|
#[error("Error writing to EventFd")]
|
||||||
EventFdWrite(#[source] io::Error),
|
EventFdWrite(#[source] io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ pub enum Error {
|
|||||||
#[error("Event handler was called spuriously: {0}")]
|
#[error("Event handler was called spuriously: {0}")]
|
||||||
SpuriousRateLimiterEvent(&'static str),
|
SpuriousRateLimiterEvent(&'static str),
|
||||||
/// The event handler encounters while TimerFd::wait()
|
/// The event handler encounters while TimerFd::wait()
|
||||||
#[error("Failed to wait for the timer: {0}")]
|
#[error("Failed to wait for the timer")]
|
||||||
TimerFdWaitError(#[source] std::io::Error),
|
TimerFdWaitError(#[source] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,7 +486,7 @@ impl RateLimiter {
|
|||||||
/// Updates the parameters of the token buckets associated with this RateLimiter.
|
/// Updates the parameters of the token buckets associated with this RateLimiter.
|
||||||
// TODO: Please note that, right now, the buckets become full after being updated.
|
// TODO: Please note that, right now, the buckets become full after being updated.
|
||||||
pub fn update_buckets(&mut self, bytes: BucketUpdate, ops: BucketUpdate) {
|
pub fn update_buckets(&mut self, bytes: BucketUpdate, ops: BucketUpdate) {
|
||||||
let mut guard = self.inner.lock().unwrap();
|
let guard = self.inner.get_mut().unwrap();
|
||||||
match bytes {
|
match bytes {
|
||||||
BucketUpdate::Disabled => guard.bandwidth = None,
|
BucketUpdate::Disabled => guard.bandwidth = None,
|
||||||
BucketUpdate::Update(tb) => guard.bandwidth = Some(tb),
|
BucketUpdate::Update(tb) => guard.bandwidth = Some(tb),
|
||||||
|
|||||||
237
release-notes.md
237
release-notes.md
@@ -1,50 +1,57 @@
|
|||||||
|
- [v47.0](#v470)
|
||||||
|
- [Block Device Error Reporting to the Guest](#block-device-error-reporting-to-the-guest)
|
||||||
|
- [Nice Error Messages on Exit](#nice-error-messages-on-exit)
|
||||||
|
- [Alphabetically Sorted CLI Options for ch-remote](#alphabetically-sorted-cli-options-for-ch-remote)
|
||||||
|
- [Notable Bug Fixes](#notable-bug-fixes)
|
||||||
|
- [Deprecations](#deprecations)
|
||||||
|
- [Contributors](#contributors)
|
||||||
- [v46.0](#v460)
|
- [v46.0](#v460)
|
||||||
- [File-level Locking Support with `--disk`](#file-level-locking-support-with---disk)
|
- [File-level Locking Support with `--disk`](#file-level-locking-support-with---disk)
|
||||||
- [Improved Error Reporting with VM Resizing](#improved-error-reporting-with-vm-resizing)
|
- [Improved Error Reporting with VM Resizing](#improved-error-reporting-with-vm-resizing)
|
||||||
- [IPv6 Address Support with `--net`](#ipv6-address-support-with---net)
|
- [IPv6 Address Support with `--net`](#ipv6-address-support-with---net)
|
||||||
- [Experimental AArch64 Support with the MSHV Hypervisor](#experimental-aarch64-support-with-the-mshv-hypervisor)
|
- [Experimental AArch64 Support with the MSHV Hypervisor](#experimental-aarch64-support-with-the-mshv-hypervisor)
|
||||||
- [Deprecated SGX Support](#deprecated-sgx-support)
|
- [Deprecated SGX Support](#deprecated-sgx-support)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes)
|
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
||||||
- [Contributors](#contributors)
|
- [Contributors](#contributors-1)
|
||||||
- [v45.0](#v450)
|
- [v45.0](#v450)
|
||||||
- [Experimental `riscv64` Architecture Support](#experimental-riscv64-architecture-support)
|
- [Experimental `riscv64` Architecture Support](#experimental-riscv64-architecture-support)
|
||||||
- [Alphabetically Sorted CLI Options](#alphabetically-sorted-cli-options)
|
- [Alphabetically Sorted CLI Options](#alphabetically-sorted-cli-options)
|
||||||
- [Improved Downtime of VM Live Migration](#improved-downtime-of-vm-live-migration)
|
- [Improved Downtime of VM Live Migration](#improved-downtime-of-vm-live-migration)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
||||||
- [Contributors](#contributors-1)
|
- [Contributors](#contributors-2)
|
||||||
- [v44.0](#v440)
|
- [v44.0](#v440)
|
||||||
- [Configurable `virtio-iommu` Address Width](#configurable-virtio-iommu-address-width)
|
- [Configurable `virtio-iommu` Address Width](#configurable-virtio-iommu-address-width)
|
||||||
- [Notable Performance Improvements](#notable-performance-improvements)
|
- [Notable Performance Improvements](#notable-performance-improvements)
|
||||||
- [New Fuzzers](#new-fuzzers)
|
- [New Fuzzers](#new-fuzzers)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||||
- [Contributors](#contributors-2)
|
- [Contributors](#contributors-3)
|
||||||
- [v43.0](#v430)
|
- [v43.0](#v430)
|
||||||
- [Live Migration over TCP Connections](#live-migration-over-tcp-connections)
|
- [Live Migration over TCP Connections](#live-migration-over-tcp-connections)
|
||||||
- [Notable Performance Improvements](#notable-performance-improvements-1)
|
- [Notable Performance Improvements](#notable-performance-improvements-1)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||||
- [Contributors](#contributors-3)
|
- [Contributors](#contributors-4)
|
||||||
- [v42.0](#v420)
|
- [v42.0](#v420)
|
||||||
- [SVE/SVE2 Support on AArch64](#svesve2-support-on-aarch64)
|
- [SVE/SVE2 Support on AArch64](#svesve2-support-on-aarch64)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||||
- [Sponsorships](#sponsorships)
|
- [Sponsorships](#sponsorships)
|
||||||
- [Contributors](#contributors-4)
|
- [Contributors](#contributors-5)
|
||||||
- [v41.0](#v410)
|
- [v41.0](#v410)
|
||||||
- [Experimental "Pvmemcontrol" Support](#experimental-pvmemcontrol-support)
|
- [Experimental "Pvmemcontrol" Support](#experimental-pvmemcontrol-support)
|
||||||
- [Sandboxing With Landlock Support](#sandboxing-with-landlock-support)
|
- [Sandboxing With Landlock Support](#sandboxing-with-landlock-support)
|
||||||
- [Notable Performance Improvements](#notable-performance-improvements-2)
|
- [Notable Performance Improvements](#notable-performance-improvements-2)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
|
||||||
- [Contributors](#contributors-5)
|
|
||||||
- [v40.0](#v400)
|
|
||||||
- [Support for Restoring File Descriptor Backed Network Devices](#support-for-restoring-file-descriptor-backed-network-devices)
|
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||||
- [Contributors](#contributors-6)
|
- [Contributors](#contributors-6)
|
||||||
|
- [v40.0](#v400)
|
||||||
|
- [Support for Restoring File Descriptor Backed Network Devices](#support-for-restoring-file-descriptor-backed-network-devices)
|
||||||
|
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
||||||
|
- [Contributors](#contributors-7)
|
||||||
- [v39.0](#v390)
|
- [v39.0](#v390)
|
||||||
- [Variable Sizing of PCI Apertures for Segments](#variable-sizing-of-pci-apertures-for-segments)
|
- [Variable Sizing of PCI Apertures for Segments](#variable-sizing-of-pci-apertures-for-segments)
|
||||||
- [Direct Booting with bzImages](#direct-booting-with-bzimages)
|
- [Direct Booting with bzImages](#direct-booting-with-bzimages)
|
||||||
- [Support for NVIDIA GPUDirect P2P Support](#support-for-nvidia-gpudirect-p2p-support)
|
- [Support for NVIDIA GPUDirect P2P Support](#support-for-nvidia-gpudirect-p2p-support)
|
||||||
- [Guest NMI Injection Support](#guest-nmi-injection-support)
|
- [Guest NMI Injection Support](#guest-nmi-injection-support)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
- [Notable Bug Fixes](#notable-bug-fixes-8)
|
||||||
- [Contributors](#contributors-7)
|
- [Contributors](#contributors-8)
|
||||||
- [v38.0](#v380)
|
- [v38.0](#v380)
|
||||||
- [Group Rate Limiter on Block Devices](#group-rate-limiter-on-block-devices)
|
- [Group Rate Limiter on Block Devices](#group-rate-limiter-on-block-devices)
|
||||||
- [CPU Pinning Support for Block Device Worker Thread](#cpu-pinning-support-for-block-device-worker-thread)
|
- [CPU Pinning Support for Block Device Worker Thread](#cpu-pinning-support-for-block-device-worker-thread)
|
||||||
@@ -52,16 +59,16 @@
|
|||||||
- [New 'debug-console' Device](#new-debug-console-device)
|
- [New 'debug-console' Device](#new-debug-console-device)
|
||||||
- [Improved VFIO Device Support](#improved-vfio-device-support)
|
- [Improved VFIO Device Support](#improved-vfio-device-support)
|
||||||
- [Extended CPU Affinity Support](#extended-cpu-affinity-support)
|
- [Extended CPU Affinity Support](#extended-cpu-affinity-support)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-8)
|
- [Notable Bug Fixes](#notable-bug-fixes-9)
|
||||||
- [Contributors](#contributors-8)
|
- [Contributors](#contributors-9)
|
||||||
- [v37.0](#v370)
|
- [v37.0](#v370)
|
||||||
- [Long Term Support (LTS) Release](#long-term-support-lts-release)
|
- [Long Term Support (LTS) Release](#long-term-support-lts-release)
|
||||||
- [Multiple PCI segments Support for 32-bit VFIO devices](#multiple-pci-segments-support-for-32-bit-vfio-devices)
|
- [Multiple PCI segments Support for 32-bit VFIO devices](#multiple-pci-segments-support-for-32-bit-vfio-devices)
|
||||||
- [Configurable Named TAP Devices](#configurable-named-tap-devices)
|
- [Configurable Named TAP Devices](#configurable-named-tap-devices)
|
||||||
- [TTY Output from Both Serial Device and Virtio Console](#tty-output-from-both-serial-device-and-virtio-console)
|
- [TTY Output from Both Serial Device and Virtio Console](#tty-output-from-both-serial-device-and-virtio-console)
|
||||||
- [Faster VM Restoration from Snapshots](#faster-vm-restoration-from-snapshots)
|
- [Faster VM Restoration from Snapshots](#faster-vm-restoration-from-snapshots)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-9)
|
- [Notable Bug Fixes](#notable-bug-fixes-10)
|
||||||
- [Contributors](#contributors-9)
|
- [Contributors](#contributors-10)
|
||||||
- [v36.0](#v360)
|
- [v36.0](#v360)
|
||||||
- [Command Line Changes](#command-line-changes)
|
- [Command Line Changes](#command-line-changes)
|
||||||
- [Enabled Features Reported via API Endpoint and CLI](#enabled-features-reported-via-api-endpoint-and-cli)
|
- [Enabled Features Reported via API Endpoint and CLI](#enabled-features-reported-via-api-endpoint-and-cli)
|
||||||
@@ -70,31 +77,31 @@
|
|||||||
- [Unix Socket Backend for Serial Port](#unix-socket-backend-for-serial-port)
|
- [Unix Socket Backend for Serial Port](#unix-socket-backend-for-serial-port)
|
||||||
- [AIO Backend for Block Devices](#aio-backend-for-block-devices)
|
- [AIO Backend for Block Devices](#aio-backend-for-block-devices)
|
||||||
- [Documentation Improvements](#documentation-improvements)
|
- [Documentation Improvements](#documentation-improvements)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-10)
|
- [Notable Bug Fixes](#notable-bug-fixes-11)
|
||||||
- [Contributors](#contributors-10)
|
- [Contributors](#contributors-11)
|
||||||
- [v35.0](#v350)
|
- [v35.0](#v350)
|
||||||
- [`virtio-vsock` Support for Linux Guest Kernel v6.3+](#virtio-vsock-support-for-linux-guest-kernel-v63)
|
- [`virtio-vsock` Support for Linux Guest Kernel v6.3+](#virtio-vsock-support-for-linux-guest-kernel-v63)
|
||||||
- [User Specified Serial Number for `virtio-block`](#user-specified-serial-number-for-virtio-block)
|
- [User Specified Serial Number for `virtio-block`](#user-specified-serial-number-for-virtio-block)
|
||||||
- [vCPU TSC Frequency Included in Migration State](#vcpu-tsc-frequency-included-in-migration-state)
|
- [vCPU TSC Frequency Included in Migration State](#vcpu-tsc-frequency-included-in-migration-state)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-11)
|
- [Notable Bug Fixes](#notable-bug-fixes-12)
|
||||||
- [Contributors](#contributors-11)
|
- [Contributors](#contributors-12)
|
||||||
- [v34.0](#v340)
|
- [v34.0](#v340)
|
||||||
- [Paravirtualised Panic Device Support](#paravirtualised-panic-device-support)
|
- [Paravirtualised Panic Device Support](#paravirtualised-panic-device-support)
|
||||||
- [Improvements to VM Core Dump](#improvements-to-vm-core-dump)
|
- [Improvements to VM Core Dump](#improvements-to-vm-core-dump)
|
||||||
- [QCOW2 Support for Backing Files](#qcow2-support-for-backing-files)
|
- [QCOW2 Support for Backing Files](#qcow2-support-for-backing-files)
|
||||||
- [Minimum Host Kernel Bump](#minimum-host-kernel-bump)
|
- [Minimum Host Kernel Bump](#minimum-host-kernel-bump)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-12)
|
- [Notable Bug Fixes](#notable-bug-fixes-13)
|
||||||
- [Contributors](#contributors-12)
|
- [Contributors](#contributors-13)
|
||||||
- [v33.0](#v330)
|
- [v33.0](#v330)
|
||||||
- [D-Bus based API](#d-bus-based-api)
|
- [D-Bus based API](#d-bus-based-api)
|
||||||
- [Expose Host CPU Cache Details for AArch64](#expose-host-cpu-cache-details-for-aarch64)
|
- [Expose Host CPU Cache Details for AArch64](#expose-host-cpu-cache-details-for-aarch64)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-13)
|
- [Notable Bug Fixes](#notable-bug-fixes-14)
|
||||||
- [Contributors](#contributors-13)
|
- [Contributors](#contributors-14)
|
||||||
- [v32.0](#v320)
|
- [v32.0](#v320)
|
||||||
- [Increased PCI Segment Limit](#increased-pci-segment-limit)
|
- [Increased PCI Segment Limit](#increased-pci-segment-limit)
|
||||||
- [API Changes](#api-changes)
|
- [API Changes](#api-changes)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-14)
|
- [Notable Bug Fixes](#notable-bug-fixes-15)
|
||||||
- [Contributors](#contributors-14)
|
- [Contributors](#contributors-15)
|
||||||
- [v31.1](#v311)
|
- [v31.1](#v311)
|
||||||
- [v31.0](#v310)
|
- [v31.0](#v310)
|
||||||
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
|
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
|
||||||
@@ -102,15 +109,15 @@
|
|||||||
- [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler)
|
- [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler)
|
||||||
- [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile)
|
- [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile)
|
||||||
- [Documentation Improvements](#documentation-improvements-1)
|
- [Documentation Improvements](#documentation-improvements-1)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-15)
|
- [Notable Bug Fixes](#notable-bug-fixes-16)
|
||||||
- [Contributors](#contributors-15)
|
- [Contributors](#contributors-16)
|
||||||
- [v30.0](#v300)
|
- [v30.0](#v300)
|
||||||
- [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size)
|
- [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size)
|
||||||
- [Basic vfio-user Server Support](#basic-vfio-user-server-support)
|
- [Basic vfio-user Server Support](#basic-vfio-user-server-support)
|
||||||
- [Heap Profiling Support](#heap-profiling-support)
|
- [Heap Profiling Support](#heap-profiling-support)
|
||||||
- [Documentation Improvements](#documentation-improvements-2)
|
- [Documentation Improvements](#documentation-improvements-2)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-16)
|
- [Notable Bug Fixes](#notable-bug-fixes-17)
|
||||||
- [Contributors](#contributors-16)
|
- [Contributors](#contributors-17)
|
||||||
- [v28.2](#v282)
|
- [v28.2](#v282)
|
||||||
- [v29.0](#v290)
|
- [v29.0](#v290)
|
||||||
- [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm)
|
- [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm)
|
||||||
@@ -120,10 +127,10 @@
|
|||||||
- [`AArch64` Documentation Integration](#aarch64-documentation-integration)
|
- [`AArch64` Documentation Integration](#aarch64-documentation-integration)
|
||||||
- [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement)
|
- [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement)
|
||||||
- [TCP Offload Control](#tcp-offload-control)
|
- [TCP Offload Control](#tcp-offload-control)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-17)
|
- [Notable Bug Fixes](#notable-bug-fixes-18)
|
||||||
- [Removals](#removals)
|
- [Removals](#removals)
|
||||||
- [Deprecations](#deprecations)
|
- [Deprecations](#deprecations-1)
|
||||||
- [Contributors](#contributors-17)
|
- [Contributors](#contributors-18)
|
||||||
- [v28.1](#v281)
|
- [v28.1](#v281)
|
||||||
- [v28.0](#v280)
|
- [v28.0](#v280)
|
||||||
- [Community Engagement (Reminder)](#community-engagement-reminder)
|
- [Community Engagement (Reminder)](#community-engagement-reminder)
|
||||||
@@ -131,9 +138,9 @@
|
|||||||
- [Virtualised TPM Support](#virtualised-tpm-support)
|
- [Virtualised TPM Support](#virtualised-tpm-support)
|
||||||
- [Transparent Huge Page Support](#transparent-huge-page-support)
|
- [Transparent Huge Page Support](#transparent-huge-page-support)
|
||||||
- [README Quick Start Improved](#readme-quick-start-improved)
|
- [README Quick Start Improved](#readme-quick-start-improved)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-18)
|
- [Notable Bug Fixes](#notable-bug-fixes-19)
|
||||||
- [Removals](#removals-1)
|
- [Removals](#removals-1)
|
||||||
- [Contributors](#contributors-18)
|
- [Contributors](#contributors-19)
|
||||||
- [v27.0](#v270)
|
- [v27.0](#v270)
|
||||||
- [Community Engagement](#community-engagement)
|
- [Community Engagement](#community-engagement)
|
||||||
- [Prebuilt Packages](#prebuilt-packages)
|
- [Prebuilt Packages](#prebuilt-packages)
|
||||||
@@ -142,41 +149,41 @@
|
|||||||
- [Simplified Build Feature Flags](#simplified-build-feature-flags)
|
- [Simplified Build Feature Flags](#simplified-build-feature-flags)
|
||||||
- [Asynchronous Kernel Loading](#asynchronous-kernel-loading)
|
- [Asynchronous Kernel Loading](#asynchronous-kernel-loading)
|
||||||
- [GDB Support for AArch64](#gdb-support-for-aarch64)
|
- [GDB Support for AArch64](#gdb-support-for-aarch64)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-19)
|
- [Notable Bug Fixes](#notable-bug-fixes-20)
|
||||||
- [Deprecations](#deprecations-1)
|
- [Deprecations](#deprecations-2)
|
||||||
- [Contributors](#contributors-19)
|
- [Contributors](#contributors-20)
|
||||||
- [v26.0](#v260)
|
- [v26.0](#v260)
|
||||||
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform)
|
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform)
|
||||||
- [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support)
|
- [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-20)
|
- [Notable Bug Fixes](#notable-bug-fixes-21)
|
||||||
- [Deprecations](#deprecations-2)
|
- [Deprecations](#deprecations-3)
|
||||||
- [Removals](#removals-2)
|
- [Removals](#removals-2)
|
||||||
- [Contributors](#contributors-20)
|
- [Contributors](#contributors-21)
|
||||||
- [v25.0](#v250)
|
- [v25.0](#v250)
|
||||||
- [`ch-remote` Improvements](#ch-remote-improvements-1)
|
- [`ch-remote` Improvements](#ch-remote-improvements-1)
|
||||||
- [VM "Coredump" Support](#vm-coredump-support)
|
- [VM "Coredump" Support](#vm-coredump-support)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-21)
|
- [Notable Bug Fixes](#notable-bug-fixes-22)
|
||||||
- [Removals](#removals-3)
|
- [Removals](#removals-3)
|
||||||
- [Contributors](#contributors-21)
|
- [Contributors](#contributors-22)
|
||||||
- [v24.0](#v240)
|
- [v24.0](#v240)
|
||||||
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
|
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
|
||||||
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
|
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
|
||||||
- [Sparse Mmap support](#sparse-mmap-support)
|
- [Sparse Mmap support](#sparse-mmap-support)
|
||||||
- [Expose Platform Serial Number](#expose-platform-serial-number)
|
- [Expose Platform Serial Number](#expose-platform-serial-number)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-22)
|
- [Notable Bug Fixes](#notable-bug-fixes-23)
|
||||||
- [Notable Improvements](#notable-improvements)
|
- [Notable Improvements](#notable-improvements)
|
||||||
- [Deprecations](#deprecations-3)
|
- [Deprecations](#deprecations-4)
|
||||||
- [New on the Website](#new-on-the-website)
|
- [New on the Website](#new-on-the-website)
|
||||||
- [Contributors](#contributors-22)
|
- [Contributors](#contributors-23)
|
||||||
- [v23.1](#v231)
|
- [v23.1](#v231)
|
||||||
- [v23.0](#v230)
|
- [v23.0](#v230)
|
||||||
- [vDPA Support](#vdpa-support)
|
- [vDPA Support](#vdpa-support)
|
||||||
- [Updated OS Support list](#updated-os-support-list)
|
- [Updated OS Support list](#updated-os-support-list)
|
||||||
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
|
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
|
||||||
- [`AMX` Support](#amx-support)
|
- [`AMX` Support](#amx-support)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-23)
|
- [Notable Bug Fixes](#notable-bug-fixes-24)
|
||||||
- [Deprecations](#deprecations-4)
|
- [Deprecations](#deprecations-5)
|
||||||
- [Contributors](#contributors-23)
|
- [Contributors](#contributors-24)
|
||||||
- [v22.1](#v221)
|
- [v22.1](#v221)
|
||||||
- [v22.0](#v220)
|
- [v22.0](#v220)
|
||||||
- [GDB Debug Stub Support](#gdb-debug-stub-support)
|
- [GDB Debug Stub Support](#gdb-debug-stub-support)
|
||||||
@@ -187,13 +194,13 @@
|
|||||||
- [PMU Support for AArch64](#pmu-support-for-aarch64)
|
- [PMU Support for AArch64](#pmu-support-for-aarch64)
|
||||||
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
|
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
|
||||||
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
|
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-24)
|
- [Notable Bug Fixes](#notable-bug-fixes-25)
|
||||||
- [Contributors](#contributors-24)
|
- [Contributors](#contributors-25)
|
||||||
- [v21.0](#v210)
|
- [v21.0](#v210)
|
||||||
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
|
- [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)
|
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
|
||||||
- [Notable Bug fixes](#notable-bug-fixes-25)
|
- [Notable Bug fixes](#notable-bug-fixes-26)
|
||||||
- [Contributors](#contributors-25)
|
- [Contributors](#contributors-26)
|
||||||
- [v20.2](#v202)
|
- [v20.2](#v202)
|
||||||
- [v20.1](#v201)
|
- [v20.1](#v201)
|
||||||
- [v20.0](#v200)
|
- [v20.0](#v200)
|
||||||
@@ -202,8 +209,8 @@
|
|||||||
- [Improved VFIO support](#improved-vfio-support)
|
- [Improved VFIO support](#improved-vfio-support)
|
||||||
- [Safer code](#safer-code)
|
- [Safer code](#safer-code)
|
||||||
- [Extended documentation](#extended-documentation)
|
- [Extended documentation](#extended-documentation)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-26)
|
- [Notable bug fixes](#notable-bug-fixes-27)
|
||||||
- [Contributors](#contributors-26)
|
- [Contributors](#contributors-27)
|
||||||
- [v19.0](#v190)
|
- [v19.0](#v190)
|
||||||
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
|
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
|
||||||
- [PCI boot time optimisations](#pci-boot-time-optimisations)
|
- [PCI boot time optimisations](#pci-boot-time-optimisations)
|
||||||
@@ -211,8 +218,8 @@
|
|||||||
- [Live migration enhancements](#live-migration-enhancements)
|
- [Live migration enhancements](#live-migration-enhancements)
|
||||||
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
|
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
|
||||||
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
|
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-27)
|
- [Notable bug fixes](#notable-bug-fixes-28)
|
||||||
- [Contributors](#contributors-27)
|
- [Contributors](#contributors-28)
|
||||||
- [v18.0](#v180)
|
- [v18.0](#v180)
|
||||||
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
|
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
|
||||||
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
|
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
|
||||||
@@ -222,31 +229,31 @@
|
|||||||
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
||||||
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
||||||
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-28)
|
- [Notable bug fixes](#notable-bug-fixes-29)
|
||||||
- [Contributors](#contributors-28)
|
- [Contributors](#contributors-29)
|
||||||
- [v17.0](#v170)
|
- [v17.0](#v170)
|
||||||
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
|
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
|
||||||
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
|
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
|
||||||
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
|
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
|
||||||
- [Improved SGX support](#improved-sgx-support)
|
- [Improved SGX support](#improved-sgx-support)
|
||||||
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
|
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-29)
|
- [Notable bug fixes](#notable-bug-fixes-30)
|
||||||
- [Contributors](#contributors-29)
|
- [Contributors](#contributors-30)
|
||||||
- [v16.0](#v160)
|
- [v16.0](#v160)
|
||||||
- [Improved live migration support](#improved-live-migration-support)
|
- [Improved live migration support](#improved-live-migration-support)
|
||||||
- [Improved `vhost-user` support](#improved-vhost-user-support)
|
- [Improved `vhost-user` support](#improved-vhost-user-support)
|
||||||
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
|
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-30)
|
- [Notable bug fixes](#notable-bug-fixes-31)
|
||||||
- [Removed functionality](#removed-functionality)
|
- [Removed functionality](#removed-functionality)
|
||||||
- [Contributors](#contributors-30)
|
- [Contributors](#contributors-31)
|
||||||
- [v15.0](#v150)
|
- [v15.0](#v150)
|
||||||
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
||||||
- [Network device rate limiting](#network-device-rate-limiting)
|
- [Network device rate limiting](#network-device-rate-limiting)
|
||||||
- [Support for runtime control of `virtio-net` guest offload](#support-for-runtime-control-of-virtio-net-guest-offload)
|
- [Support for runtime control of `virtio-net` guest offload](#support-for-runtime-control-of-virtio-net-guest-offload)
|
||||||
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
||||||
- [Bug fixes](#bug-fixes)
|
- [Bug fixes](#bug-fixes)
|
||||||
- [Deprecations](#deprecations-5)
|
- [Deprecations](#deprecations-6)
|
||||||
- [Contributors](#contributors-31)
|
- [Contributors](#contributors-32)
|
||||||
- [v0.14.1](#v0141)
|
- [v0.14.1](#v0141)
|
||||||
- [v0.14.0](#v0140)
|
- [v0.14.0](#v0140)
|
||||||
- [Structured event monitoring](#structured-event-monitoring)
|
- [Structured event monitoring](#structured-event-monitoring)
|
||||||
@@ -255,8 +262,8 @@
|
|||||||
- [Updated hotplug documentation](#updated-hotplug-documentation)
|
- [Updated hotplug documentation](#updated-hotplug-documentation)
|
||||||
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
|
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
|
||||||
- [Block device rate limiting](#block-device-rate-limiting)
|
- [Block device rate limiting](#block-device-rate-limiting)
|
||||||
- [Deprecations](#deprecations-6)
|
- [Deprecations](#deprecations-7)
|
||||||
- [Contributors](#contributors-32)
|
- [Contributors](#contributors-33)
|
||||||
- [v0.13.0](#v0130)
|
- [v0.13.0](#v0130)
|
||||||
- [Wider VFIO device support](#wider-vfio-device-support)
|
- [Wider VFIO device support](#wider-vfio-device-support)
|
||||||
- [Improved huge page support](#improved-huge-page-support)
|
- [Improved huge page support](#improved-huge-page-support)
|
||||||
@@ -264,13 +271,13 @@
|
|||||||
- [VHD disk image support](#vhd-disk-image-support)
|
- [VHD disk image support](#vhd-disk-image-support)
|
||||||
- [Improved Virtio device threading](#improved-virtio-device-threading)
|
- [Improved Virtio device threading](#improved-virtio-device-threading)
|
||||||
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
|
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
|
||||||
- [Contributors](#contributors-33)
|
- [Contributors](#contributors-34)
|
||||||
- [v0.12.0](#v0120)
|
- [v0.12.0](#v0120)
|
||||||
- [ARM64 enhancements](#arm64-enhancements)
|
- [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)
|
- [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)
|
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
|
||||||
- [Enhanced "info" API](#enhanced-info-api)
|
- [Enhanced "info" API](#enhanced-info-api)
|
||||||
- [Contributors](#contributors-34)
|
- [Contributors](#contributors-35)
|
||||||
- [v0.11.0](#v0110)
|
- [v0.11.0](#v0110)
|
||||||
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
|
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
|
||||||
- [Windows Guest Support](#windows-guest-support)
|
- [Windows Guest Support](#windows-guest-support)
|
||||||
@@ -282,15 +289,15 @@
|
|||||||
- [Default Log Level Changed](#default-log-level-changed)
|
- [Default Log Level Changed](#default-log-level-changed)
|
||||||
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
|
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
|
||||||
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
|
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-31)
|
- [Notable Bug Fixes](#notable-bug-fixes-32)
|
||||||
- [Contributors](#contributors-35)
|
- [Contributors](#contributors-36)
|
||||||
- [v0.10.0](#v0100)
|
- [v0.10.0](#v0100)
|
||||||
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
|
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
|
||||||
- [Memory Zones](#memory-zones)
|
- [Memory Zones](#memory-zones)
|
||||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
|
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
|
||||||
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
|
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-32)
|
- [Notable Bug Fixes](#notable-bug-fixes-33)
|
||||||
- [Contributors](#contributors-36)
|
- [Contributors](#contributors-37)
|
||||||
- [v0.9.0](#v090)
|
- [v0.9.0](#v090)
|
||||||
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
|
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
|
||||||
- [Block and Network Device Statistics](#block-and-network-device-statistics)
|
- [Block and Network Device Statistics](#block-and-network-device-statistics)
|
||||||
@@ -303,17 +310,17 @@
|
|||||||
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
|
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
|
||||||
- [Intel SGX Support](#intel-sgx-support)
|
- [Intel SGX Support](#intel-sgx-support)
|
||||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
|
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-33)
|
- [Notable Bug Fixes](#notable-bug-fixes-34)
|
||||||
- [Contributors](#contributors-37)
|
- [Contributors](#contributors-38)
|
||||||
- [v0.8.0](#v080)
|
- [v0.8.0](#v080)
|
||||||
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
|
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
|
||||||
- [Experimental ARM64 Support](#experimental-arm64-support)
|
- [Experimental ARM64 Support](#experimental-arm64-support)
|
||||||
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
|
- [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)
|
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
|
||||||
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
|
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-34)
|
- [Notable Bug Fixes](#notable-bug-fixes-35)
|
||||||
- [Command Line and API Changes](#command-line-and-api-changes)
|
- [Command Line and API Changes](#command-line-and-api-changes)
|
||||||
- [Contributors](#contributors-38)
|
- [Contributors](#contributors-39)
|
||||||
- [v0.7.0](#v070)
|
- [v0.7.0](#v070)
|
||||||
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
|
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
|
||||||
- [Alternative `libc` Support](#alternative-libc-support)
|
- [Alternative `libc` Support](#alternative-libc-support)
|
||||||
@@ -323,14 +330,14 @@
|
|||||||
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
||||||
- [Updated Distribution Support](#updated-distribution-support)
|
- [Updated Distribution Support](#updated-distribution-support)
|
||||||
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
||||||
- [Contributors](#contributors-39)
|
- [Contributors](#contributors-40)
|
||||||
- [v0.6.0](#v060)
|
- [v0.6.0](#v060)
|
||||||
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
|
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
|
||||||
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
|
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
|
||||||
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
|
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
|
||||||
- [Command Line Interface](#command-line-interface)
|
- [Command Line Interface](#command-line-interface)
|
||||||
- [PVH Boot](#pvh-boot)
|
- [PVH Boot](#pvh-boot)
|
||||||
- [Contributors](#contributors-40)
|
- [Contributors](#contributors-41)
|
||||||
- [v0.5.1](#v051)
|
- [v0.5.1](#v051)
|
||||||
- [v0.5.0](#v050)
|
- [v0.5.0](#v050)
|
||||||
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
||||||
@@ -338,7 +345,7 @@
|
|||||||
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
||||||
- [Development Tools](#development-tools)
|
- [Development Tools](#development-tools)
|
||||||
- [Kata Containers Integration](#kata-containers-integration)
|
- [Kata Containers Integration](#kata-containers-integration)
|
||||||
- [Contributors](#contributors-41)
|
- [Contributors](#contributors-42)
|
||||||
- [v0.4.0](#v040)
|
- [v0.4.0](#v040)
|
||||||
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
||||||
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
||||||
@@ -347,7 +354,7 @@
|
|||||||
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
|
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
|
||||||
- [PCI BAR reprogramming](#pci-bar-reprogramming)
|
- [PCI BAR reprogramming](#pci-bar-reprogramming)
|
||||||
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
|
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
|
||||||
- [Contributors](#contributors-42)
|
- [Contributors](#contributors-43)
|
||||||
- [v0.3.0](#v030)
|
- [v0.3.0](#v030)
|
||||||
- [Block device offloading](#block-device-offloading)
|
- [Block device offloading](#block-device-offloading)
|
||||||
- [Network device backend](#network-device-backend)
|
- [Network device backend](#network-device-backend)
|
||||||
@@ -374,6 +381,66 @@
|
|||||||
- [Unit testing](#unit-testing)
|
- [Unit testing](#unit-testing)
|
||||||
- [Integration tests parallelization](#integration-tests-parallelization)
|
- [Integration tests parallelization](#integration-tests-parallelization)
|
||||||
|
|
||||||
|
# v47.0
|
||||||
|
|
||||||
|
This release has been tracked in [v47.0
|
||||||
|
group](https://github.com/orgs/cloud-hypervisor/projects/6/views/4?filterQuery=release%3A%22Release+47%22)
|
||||||
|
of our [roadmap project](https://github.com/orgs/cloud-hypervisor/projects/6/).
|
||||||
|
|
||||||
|
### Block Device Error Reporting to the Guest
|
||||||
|
|
||||||
|
Instead of exiting on I/O errors, the `virtio-block` device now reports
|
||||||
|
errors to the guest using `VIRTIO_BLK_S_IOERR`. It improves the user
|
||||||
|
experience particularly when the guest rootfs is not backed by the
|
||||||
|
affected block device. (#7107)
|
||||||
|
|
||||||
|
### Nice Error Messages on Exit
|
||||||
|
|
||||||
|
We now have the chain of errors being reported and printed nicely, when
|
||||||
|
Cloud Hypervisor or ch-remote exits on errors. (#7066)
|
||||||
|
|
||||||
|
### Alphabetically Sorted CLI Options for ch-remote
|
||||||
|
|
||||||
|
To improve readability, ch-remote now prints help information in
|
||||||
|
alphabetical order. (#7130)
|
||||||
|
|
||||||
|
### Notable Bug Fixes
|
||||||
|
|
||||||
|
* Error out early when block device serial is too long (#7124)
|
||||||
|
* Fix partial commands being discarded for `virtio-vsock` (#7195)
|
||||||
|
* Disable the broken interrupt support for the `rtc_pl031` device to
|
||||||
|
prevent spurious guest interrupts (#7199)
|
||||||
|
|
||||||
|
### Deprecations
|
||||||
|
|
||||||
|
* A default IP (`192.168.249.1`) and mask (`255.255.255.0`) are
|
||||||
|
currently assigned to the `virtio-net` device if no value is specified
|
||||||
|
by users. Such behavior is now deprecated. Users of this behavior will
|
||||||
|
receive a warning message and should make adjustments. The behavior
|
||||||
|
will be removed in two release cycles (v49.0).
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
Many thanks to everyone who has contributed to our release:
|
||||||
|
|
||||||
|
* Alyssa Ross <hi@alyssa.is>
|
||||||
|
* Bo Chen <bchen@crusoe.ai>
|
||||||
|
* Demi Marie Obenour <demiobenour@gmail.com>
|
||||||
|
* Gauthier Jolly <contact@gjolly.fr>
|
||||||
|
* Hengqi Chen <hengqi.chen@gmail.com>
|
||||||
|
* Jinank Jain <jinankjain@microsoft.com>
|
||||||
|
* Jinrong Liang <cloudliang@tencent.com>
|
||||||
|
* Jean-Philippe Brucker <jean-philippe@linaro.org>
|
||||||
|
* Maximilian Güntner <code@mguentner.de>
|
||||||
|
* Muminul Islam <muislam@microsoft.com>
|
||||||
|
* Nuno Das Neves <nunodasneves@linux.microsoft.com>
|
||||||
|
* Philipp Schuster <philipp.schuster@cyberus-technology.de>
|
||||||
|
* Ruoqing He <heruoqing@iscas.ac.cn>
|
||||||
|
* Songqian Li <sionli@tencent.com>
|
||||||
|
* Wei Liu <liuwe@microsoft.com>
|
||||||
|
* Yi Wang <foxywang@tencent.com>
|
||||||
|
* ninollei <ninollx@hotmail.com>
|
||||||
|
|
||||||
# v46.0
|
# v46.0
|
||||||
|
|
||||||
This release has been tracked in [v46.0
|
This release has been tracked in [v46.0
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ class TitleStartsWithComponent(LineRule):
|
|||||||
'README',
|
'README',
|
||||||
'resources',
|
'resources',
|
||||||
'scripts',
|
'scripts',
|
||||||
|
'seccomp',
|
||||||
'serial_buffer',
|
'serial_buffer',
|
||||||
'test_data',
|
'test_data',
|
||||||
'test_infra',
|
'test_infra',
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ update_workloads() {
|
|||||||
mkdir -p "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"
|
mkdir -p "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"
|
||||||
# Mount the 'raw' image, replace the compressed kernel file and umount the working folder
|
# Mount the 'raw' image, replace the compressed kernel file and umount the working folder
|
||||||
guestmount -a "$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_NAME" -m /dev/sda1 "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR" || exit 1
|
guestmount -a "$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_NAME" -m /dev/sda1 "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR" || exit 1
|
||||||
cp "$WORKLOADS_DIR"/Image.gz "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"/boot/vmlinuz
|
cp "$WORKLOADS_DIR"/Image-arm64.gz "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"/boot/vmlinuz
|
||||||
guestunmount "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"
|
guestunmount "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"
|
||||||
|
|
||||||
# Build virtiofsd
|
# Build virtiofsd
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ chmod +x $CH_RELEASE_NAME
|
|||||||
popd || exit
|
popd || exit
|
||||||
|
|
||||||
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
||||||
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
|
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux-x86_64"
|
||||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||||
# Prepare linux image (build from source or download pre-built)
|
# Prepare linux image (build from source or download pre-built)
|
||||||
prepare_linux
|
prepare_linux
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ fi
|
|||||||
popd || exit
|
popd || exit
|
||||||
|
|
||||||
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
||||||
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
|
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux-x86_64"
|
||||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||||
# Prepare linux image (build from source or download pre-built)
|
# Prepare linux image (build from source or download pre-built)
|
||||||
prepare_linux
|
prepare_linux
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
set -x
|
||||||
|
|
||||||
hypervisor="kvm"
|
hypervisor="kvm"
|
||||||
test_filter=""
|
test_filter=""
|
||||||
build_kernel=false
|
build_kernel=false
|
||||||
@@ -56,11 +58,11 @@ build_custom_linux() {
|
|||||||
make ch_defconfig
|
make ch_defconfig
|
||||||
make -j "$(nproc)"
|
make -j "$(nproc)"
|
||||||
if [ "${ARCH}" == "x86_64" ]; then
|
if [ "${ARCH}" == "x86_64" ]; then
|
||||||
cp vmlinux "$WORKLOADS_DIR/" || exit 1
|
cp vmlinux "$WORKLOADS_DIR/vmlinux-x86_64" || exit 1
|
||||||
cp arch/x86/boot/bzImage "$WORKLOADS_DIR/" || exit 1
|
cp arch/x86/boot/bzImage "$WORKLOADS_DIR/bzImage-x86_64" || exit 1
|
||||||
elif [ "${ARCH}" == "aarch64" ]; then
|
elif [ "${ARCH}" == "aarch64" ]; then
|
||||||
cp arch/arm64/boot/Image "$WORKLOADS_DIR/" || exit 1
|
cp arch/arm64/boot/Image "$WORKLOADS_DIR/Image-arm64" || exit 1
|
||||||
cp arch/arm64/boot/Image.gz "$WORKLOADS_DIR/" || exit 1
|
cp arch/arm64/boot/Image.gz "$WORKLOADS_DIR/Image-arm64.gz" || exit 1
|
||||||
fi
|
fi
|
||||||
popd || exit
|
popd || exit
|
||||||
}
|
}
|
||||||
@@ -138,7 +140,7 @@ download_hypervisor_fw() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
download_linux() {
|
download_linux() {
|
||||||
KERNEL_TAG="ch-release-v6.12.8-20250114"
|
KERNEL_TAG="ch-release-v6.12.8-20250613"
|
||||||
if [ -n "$AUTH_DOWNLOAD_TOKEN" ]; then
|
if [ -n "$AUTH_DOWNLOAD_TOKEN" ]; then
|
||||||
echo "Using authenticated download from GitHub"
|
echo "Using authenticated download from GitHub"
|
||||||
KERNEL_URLS=$(curl --silent https://api.github.com/repos/cloud-hypervisor/linux/releases/tags/${KERNEL_TAG} \
|
KERNEL_URLS=$(curl --silent https://api.github.com/repos/cloud-hypervisor/linux/releases/tags/${KERNEL_TAG} \
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "../test_util.rs"]
|
||||||
|
mod test_util;
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
@@ -13,6 +17,7 @@ use api_client::{
|
|||||||
Error as ApiClientError,
|
Error as ApiClientError,
|
||||||
};
|
};
|
||||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||||
|
use log::error;
|
||||||
use option_parser::{ByteSized, ByteSizedParseError};
|
use option_parser::{ByteSized, ByteSizedParseError};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use vmm::config::RestoreConfig;
|
use vmm::config::RestoreConfig;
|
||||||
@@ -27,38 +32,38 @@ type ApiResult = Result<(), Error>;
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
enum Error {
|
enum Error {
|
||||||
#[error("http client error: {0}")]
|
#[error("http client error")]
|
||||||
HttpApiClient(#[source] ApiClientError),
|
HttpApiClient(#[source] ApiClientError),
|
||||||
#[cfg(feature = "dbus_api")]
|
#[cfg(feature = "dbus_api")]
|
||||||
#[error("dbus api client error: {0}")]
|
#[error("dbus api client error")]
|
||||||
DBusApiClient(#[source] zbus::Error),
|
DBusApiClient(#[source] zbus::Error),
|
||||||
#[error("Error parsing CPU count: {0}")]
|
#[error("Error parsing CPU count")]
|
||||||
InvalidCpuCount(#[source] std::num::ParseIntError),
|
InvalidCpuCount(#[source] std::num::ParseIntError),
|
||||||
#[error("Error parsing memory size: {0}")]
|
#[error("Error parsing memory size")]
|
||||||
InvalidMemorySize(#[source] ByteSizedParseError),
|
InvalidMemorySize(#[source] ByteSizedParseError),
|
||||||
#[error("Error parsing balloon size: {0}")]
|
#[error("Error parsing balloon size")]
|
||||||
InvalidBalloonSize(#[source] ByteSizedParseError),
|
InvalidBalloonSize(#[source] ByteSizedParseError),
|
||||||
#[error("Error parsing device syntax: {0}")]
|
#[error("Error parsing device syntax")]
|
||||||
AddDeviceConfig(#[source] vmm::config::Error),
|
AddDeviceConfig(#[source] vmm::config::Error),
|
||||||
#[error("Error parsing disk syntax: {0}")]
|
#[error("Error parsing disk syntax")]
|
||||||
AddDiskConfig(#[source] vmm::config::Error),
|
AddDiskConfig(#[source] vmm::config::Error),
|
||||||
#[error("Error parsing filesystem syntax: {0}")]
|
#[error("Error parsing filesystem syntax")]
|
||||||
AddFsConfig(#[source] vmm::config::Error),
|
AddFsConfig(#[source] vmm::config::Error),
|
||||||
#[error("Error parsing persistent memory syntax: {0}")]
|
#[error("Error parsing persistent memory syntax")]
|
||||||
AddPmemConfig(#[source] vmm::config::Error),
|
AddPmemConfig(#[source] vmm::config::Error),
|
||||||
#[error("Error parsing network syntax: {0}")]
|
#[error("Error parsing network syntax")]
|
||||||
AddNetConfig(#[source] vmm::config::Error),
|
AddNetConfig(#[source] vmm::config::Error),
|
||||||
#[error("Error parsing user device syntax: {0}")]
|
#[error("Error parsing user device syntax")]
|
||||||
AddUserDeviceConfig(#[source] vmm::config::Error),
|
AddUserDeviceConfig(#[source] vmm::config::Error),
|
||||||
#[error("Error parsing vDPA device syntax: {0}")]
|
#[error("Error parsing vDPA device syntax")]
|
||||||
AddVdpaConfig(#[source] vmm::config::Error),
|
AddVdpaConfig(#[source] vmm::config::Error),
|
||||||
#[error("Error parsing vsock syntax: {0}")]
|
#[error("Error parsing vsock syntax")]
|
||||||
AddVsockConfig(#[source] vmm::config::Error),
|
AddVsockConfig(#[source] vmm::config::Error),
|
||||||
#[error("Error parsing restore syntax: {0}")]
|
#[error("Error parsing restore syntax")]
|
||||||
Restore(#[source] vmm::config::Error),
|
Restore(#[source] vmm::config::Error),
|
||||||
#[error("Error reading from stdin: {0}")]
|
#[error("Error reading from stdin")]
|
||||||
ReadingStdin(#[source] std::io::Error),
|
ReadingStdin(#[source] std::io::Error),
|
||||||
#[error("Error reading from file: {0}")]
|
#[error("Error reading from file")]
|
||||||
ReadingFile(#[source] std::io::Error),
|
ReadingFile(#[source] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -899,48 +904,49 @@ fn create_data(path: &str) -> Result<String, Error> {
|
|||||||
Ok(data)
|
Ok(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
/// Returns all [`Arg`]s in alphabetical order.
|
||||||
let app = Command::new("ch-remote")
|
///
|
||||||
.author(env!("CARGO_PKG_AUTHORS"))
|
/// This is the order used in the `--help` output.
|
||||||
.version(env!("BUILD_VERSION"))
|
fn get_cli_args() -> Box<[Arg]> {
|
||||||
.about("Remotely control a cloud-hypervisor VMM.")
|
[
|
||||||
.arg_required_else_help(true)
|
|
||||||
.subcommand_required(true)
|
|
||||||
.args([
|
|
||||||
Arg::new("api-socket")
|
Arg::new("api-socket")
|
||||||
.long("api-socket")
|
.long("api-socket")
|
||||||
.help("HTTP API socket path (UNIX domain socket).")
|
.help("HTTP API socket path (UNIX domain socket).")
|
||||||
.num_args(1),
|
.num_args(1),
|
||||||
#[cfg(feature = "dbus_api")]
|
#[cfg(feature = "dbus_api")]
|
||||||
Arg::new("dbus-service-name")
|
|
||||||
.long("dbus-service-name")
|
|
||||||
.help("Well known name of the dbus service")
|
|
||||||
.num_args(1),
|
|
||||||
#[cfg(feature = "dbus_api")]
|
|
||||||
Arg::new("dbus-object-path")
|
Arg::new("dbus-object-path")
|
||||||
.long("dbus-object-path")
|
.long("dbus-object-path")
|
||||||
.help("Object path which the interface is being served at")
|
.help("Object path which the interface is being served at")
|
||||||
.num_args(1),
|
.num_args(1),
|
||||||
#[cfg(feature = "dbus_api")]
|
#[cfg(feature = "dbus_api")]
|
||||||
|
Arg::new("dbus-service-name")
|
||||||
|
.long("dbus-service-name")
|
||||||
|
.help("Well known name of the dbus service")
|
||||||
|
.num_args(1),
|
||||||
|
#[cfg(feature = "dbus_api")]
|
||||||
Arg::new("dbus-system-bus")
|
Arg::new("dbus-system-bus")
|
||||||
.long("dbus-system-bus")
|
.long("dbus-system-bus")
|
||||||
.action(ArgAction::SetTrue)
|
.action(ArgAction::SetTrue)
|
||||||
.num_args(0)
|
.num_args(0)
|
||||||
.help("Use the system bus instead of a session bus"),
|
.help("Use the system bus instead of a session bus"),
|
||||||
])
|
]
|
||||||
.subcommand(
|
.to_vec()
|
||||||
|
.into_boxed_slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns all [`Command`]s in alphabetical order.
|
||||||
|
///
|
||||||
|
/// This is the order used in the `--help` output.
|
||||||
|
fn get_cli_commands_sorted() -> Box<[Command]> {
|
||||||
|
[
|
||||||
Command::new("add-device").about("Add VFIO device").arg(
|
Command::new("add-device").about("Add VFIO device").arg(
|
||||||
Arg::new("device_config")
|
Arg::new("device_config")
|
||||||
.index(1)
|
.index(1)
|
||||||
.help(DeviceConfig::SYNTAX),
|
.help(DeviceConfig::SYNTAX),
|
||||||
),
|
),
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("add-disk")
|
Command::new("add-disk")
|
||||||
.about("Add block device")
|
.about("Add block device")
|
||||||
.arg(Arg::new("disk_config").index(1).help(DiskConfig::SYNTAX)),
|
.arg(Arg::new("disk_config").index(1).help(DiskConfig::SYNTAX)),
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("add-fs")
|
Command::new("add-fs")
|
||||||
.about("Add virtio-fs backed fs device")
|
.about("Add virtio-fs backed fs device")
|
||||||
.arg(
|
.arg(
|
||||||
@@ -948,8 +954,9 @@ fn main() {
|
|||||||
.index(1)
|
.index(1)
|
||||||
.help(vmm::vm_config::FsConfig::SYNTAX),
|
.help(vmm::vm_config::FsConfig::SYNTAX),
|
||||||
),
|
),
|
||||||
)
|
Command::new("add-net")
|
||||||
.subcommand(
|
.about("Add network device")
|
||||||
|
.arg(Arg::new("net_config").index(1).help(NetConfig::SYNTAX)),
|
||||||
Command::new("add-pmem")
|
Command::new("add-pmem")
|
||||||
.about("Add persistent memory device")
|
.about("Add persistent memory device")
|
||||||
.arg(
|
.arg(
|
||||||
@@ -957,13 +964,6 @@ fn main() {
|
|||||||
.index(1)
|
.index(1)
|
||||||
.help(vmm::vm_config::PmemConfig::SYNTAX),
|
.help(vmm::vm_config::PmemConfig::SYNTAX),
|
||||||
),
|
),
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("add-net")
|
|
||||||
.about("Add network device")
|
|
||||||
.arg(Arg::new("net_config").index(1).help(NetConfig::SYNTAX)),
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("add-user-device")
|
Command::new("add-user-device")
|
||||||
.about("Add userspace device")
|
.about("Add userspace device")
|
||||||
.arg(
|
.arg(
|
||||||
@@ -971,30 +971,45 @@ fn main() {
|
|||||||
.index(1)
|
.index(1)
|
||||||
.help(UserDeviceConfig::SYNTAX),
|
.help(UserDeviceConfig::SYNTAX),
|
||||||
),
|
),
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("add-vdpa")
|
Command::new("add-vdpa")
|
||||||
.about("Add vDPA device")
|
.about("Add vDPA device")
|
||||||
.arg(Arg::new("vdpa_config").index(1).help(VdpaConfig::SYNTAX)),
|
.arg(Arg::new("vdpa_config").index(1).help(VdpaConfig::SYNTAX)),
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("add-vsock")
|
Command::new("add-vsock")
|
||||||
.about("Add vsock device")
|
.about("Add vsock device")
|
||||||
.arg(Arg::new("vsock_config").index(1).help(VsockConfig::SYNTAX)),
|
.arg(Arg::new("vsock_config").index(1).help(VsockConfig::SYNTAX)),
|
||||||
)
|
Command::new("boot").about("Boot a created VM"),
|
||||||
.subcommand(
|
Command::new("coredump")
|
||||||
|
.about("Create a coredump from VM")
|
||||||
|
.arg(Arg::new("coredump_config").index(1).help("<file_path>")),
|
||||||
|
Command::new("counters").about("Counters from the VM"),
|
||||||
|
Command::new("create")
|
||||||
|
.about("Create VM from a JSON configuration")
|
||||||
|
.arg(Arg::new("path").index(1).default_value("-")),
|
||||||
|
Command::new("delete").about("Delete a VM"),
|
||||||
|
Command::new("info").about("Info on the VM"),
|
||||||
|
Command::new("nmi").about("Trigger NMI"),
|
||||||
|
Command::new("pause").about("Pause the VM"),
|
||||||
|
Command::new("ping").about("Ping the VMM to check for API server availability"),
|
||||||
|
Command::new("power-button").about("Trigger a power button in the VM"),
|
||||||
|
Command::new("reboot").about("Reboot the VM"),
|
||||||
|
Command::new("receive-migration")
|
||||||
|
.about("Receive a VM migration")
|
||||||
|
.arg(
|
||||||
|
Arg::new("receive_migration_config")
|
||||||
|
.index(1)
|
||||||
|
.help("<receiver_url>"),
|
||||||
|
),
|
||||||
Command::new("remove-device")
|
Command::new("remove-device")
|
||||||
.about("Remove VFIO and PCI device")
|
.about("Remove VFIO and PCI device")
|
||||||
.arg(Arg::new("id").index(1).help("<device_id>")),
|
.arg(Arg::new("id").index(1).help("<device_id>")),
|
||||||
)
|
|
||||||
.subcommand(Command::new("info").about("Info on the VM"))
|
|
||||||
.subcommand(Command::new("counters").about("Counters from the VM"))
|
|
||||||
.subcommand(Command::new("pause").about("Pause the VM"))
|
|
||||||
.subcommand(Command::new("reboot").about("Reboot the VM"))
|
|
||||||
.subcommand(Command::new("power-button").about("Trigger a power button in the VM"))
|
|
||||||
.subcommand(
|
|
||||||
Command::new("resize")
|
Command::new("resize")
|
||||||
.about("Resize the VM")
|
.about("Resize the VM")
|
||||||
|
.arg(
|
||||||
|
Arg::new("balloon")
|
||||||
|
.long("balloon")
|
||||||
|
.help("New balloon size in bytes (supports K/M/G suffix)")
|
||||||
|
.num_args(1),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("cpus")
|
Arg::new("cpus")
|
||||||
.long("cpus")
|
.long("cpus")
|
||||||
@@ -1006,15 +1021,7 @@ fn main() {
|
|||||||
.long("memory")
|
.long("memory")
|
||||||
.help("New memory size in bytes (supports K/M/G suffix)")
|
.help("New memory size in bytes (supports K/M/G suffix)")
|
||||||
.num_args(1),
|
.num_args(1),
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new("balloon")
|
|
||||||
.long("balloon")
|
|
||||||
.help("New balloon size in bytes (supports K/M/G suffix)")
|
|
||||||
.num_args(1),
|
|
||||||
),
|
),
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("resize-zone")
|
Command::new("resize-zone")
|
||||||
.about("Resize a memory zone")
|
.about("Resize a memory zone")
|
||||||
.arg(
|
.arg(
|
||||||
@@ -1029,21 +1036,6 @@ fn main() {
|
|||||||
.help("New memory zone size in bytes (supports K/M/G suffix)")
|
.help("New memory zone size in bytes (supports K/M/G suffix)")
|
||||||
.num_args(1),
|
.num_args(1),
|
||||||
),
|
),
|
||||||
)
|
|
||||||
.subcommand(Command::new("resume").about("Resume the VM"))
|
|
||||||
.subcommand(Command::new("boot").about("Boot a created VM"))
|
|
||||||
.subcommand(Command::new("delete").about("Delete a VM"))
|
|
||||||
.subcommand(Command::new("shutdown").about("Shutdown the VM"))
|
|
||||||
.subcommand(
|
|
||||||
Command::new("snapshot")
|
|
||||||
.about("Create a snapshot from VM")
|
|
||||||
.arg(
|
|
||||||
Arg::new("snapshot_config")
|
|
||||||
.index(1)
|
|
||||||
.help("<destination_url>"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("restore")
|
Command::new("restore")
|
||||||
.about("Restore VM from a snapshot")
|
.about("Restore VM from a snapshot")
|
||||||
.arg(
|
.arg(
|
||||||
@@ -1051,13 +1043,7 @@ fn main() {
|
|||||||
.index(1)
|
.index(1)
|
||||||
.help(RestoreConfig::SYNTAX),
|
.help(RestoreConfig::SYNTAX),
|
||||||
),
|
),
|
||||||
)
|
Command::new("resume").about("Resume the VM"),
|
||||||
.subcommand(
|
|
||||||
Command::new("coredump")
|
|
||||||
.about("Create a coredump from VM")
|
|
||||||
.arg(Arg::new("coredump_config").index(1).help("<file_path>")),
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("send-migration")
|
Command::new("send-migration")
|
||||||
.about("Initiate a VM migration")
|
.about("Initiate a VM migration")
|
||||||
.arg(
|
.arg(
|
||||||
@@ -1071,24 +1057,30 @@ fn main() {
|
|||||||
.num_args(0)
|
.num_args(0)
|
||||||
.action(ArgAction::SetTrue),
|
.action(ArgAction::SetTrue),
|
||||||
),
|
),
|
||||||
)
|
Command::new("shutdown").about("Shutdown the VM"),
|
||||||
.subcommand(
|
Command::new("shutdown-vmm").about("Shutdown the VMM"),
|
||||||
Command::new("receive-migration")
|
Command::new("snapshot")
|
||||||
.about("Receive a VM migration")
|
.about("Create a snapshot from VM")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("receive_migration_config")
|
Arg::new("snapshot_config")
|
||||||
.index(1)
|
.index(1)
|
||||||
.help("<receiver_url>"),
|
.help("<destination_url>"),
|
||||||
),
|
),
|
||||||
)
|
]
|
||||||
.subcommand(
|
.to_vec()
|
||||||
Command::new("create")
|
.into_boxed_slice()
|
||||||
.about("Create VM from a JSON configuration")
|
}
|
||||||
.arg(Arg::new("path").index(1).default_value("-")),
|
|
||||||
)
|
fn main() {
|
||||||
.subcommand(Command::new("ping").about("Ping the VMM to check for API server availability"))
|
env_logger::init();
|
||||||
.subcommand(Command::new("shutdown-vmm").about("Shutdown the VMM"))
|
let app = Command::new("ch-remote")
|
||||||
.subcommand(Command::new("nmi").about("Trigger NMI"));
|
.author(env!("CARGO_PKG_AUTHORS"))
|
||||||
|
.version(env!("BUILD_VERSION"))
|
||||||
|
.about("Remotely control a cloud-hypervisor VMM.")
|
||||||
|
.arg_required_else_help(true)
|
||||||
|
.subcommand_required(true)
|
||||||
|
.args(get_cli_args())
|
||||||
|
.subcommands(get_cli_commands_sorted());
|
||||||
|
|
||||||
let matches = app.get_matches();
|
let matches = app.get_matches();
|
||||||
|
|
||||||
@@ -1102,7 +1094,7 @@ fn main() {
|
|||||||
#[cfg(not(feature = "dbus_api"))]
|
#[cfg(not(feature = "dbus_api"))]
|
||||||
(Some(api_sock),) => TargetApi::HttpApi(
|
(Some(api_sock),) => TargetApi::HttpApi(
|
||||||
UnixStream::connect(api_sock).unwrap_or_else(|e| {
|
UnixStream::connect(api_sock).unwrap_or_else(|e| {
|
||||||
eprintln!("Error opening HTTP socket: {e}");
|
error!("Error opening HTTP socket: {e}");
|
||||||
process::exit(1)
|
process::exit(1)
|
||||||
}),
|
}),
|
||||||
PhantomData,
|
PhantomData,
|
||||||
@@ -1110,7 +1102,7 @@ fn main() {
|
|||||||
#[cfg(feature = "dbus_api")]
|
#[cfg(feature = "dbus_api")]
|
||||||
(Some(api_sock), None, None) => TargetApi::HttpApi(
|
(Some(api_sock), None, None) => TargetApi::HttpApi(
|
||||||
UnixStream::connect(api_sock).unwrap_or_else(|e| {
|
UnixStream::connect(api_sock).unwrap_or_else(|e| {
|
||||||
eprintln!("Error opening HTTP socket: {e}");
|
error!("Error opening HTTP socket: {e}");
|
||||||
process::exit(1)
|
process::exit(1)
|
||||||
}),
|
}),
|
||||||
PhantomData,
|
PhantomData,
|
||||||
@@ -1124,25 +1116,124 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.map_err(Error::DBusApiClient)
|
.map_err(Error::DBusApiClient)
|
||||||
.unwrap_or_else(|e| {
|
.unwrap_or_else(|e| {
|
||||||
eprintln!("Error creating D-Bus proxy: {e}");
|
error!("Error creating D-Bus proxy: {e}");
|
||||||
process::exit(1)
|
process::exit(1)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
#[cfg(feature = "dbus_api")]
|
#[cfg(feature = "dbus_api")]
|
||||||
(Some(_), Some(_) | None, Some(_) | None) => {
|
(Some(_), Some(_) | None, Some(_) | None) => {
|
||||||
println!(
|
error!(
|
||||||
"`api-socket` and (dbus-service-name or dbus-object-path) are mutually exclusive"
|
"`api-socket` and (dbus-service-name or dbus-object-path) are mutually exclusive"
|
||||||
);
|
);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println!("Please either provide the api-socket option or dbus-service-name and dbus-object-path options");
|
error!("Please either provide the api-socket option or dbus-service-name and dbus-object-path options");
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = target_api.do_command(&matches) {
|
if let Err(top_error) = target_api.do_command(&matches) {
|
||||||
eprintln!("Error running command: {e}");
|
// Helper to join strings with a newline.
|
||||||
|
fn join_strs(mut acc: String, next: String) -> String {
|
||||||
|
if !acc.is_empty() {
|
||||||
|
acc.push('\n');
|
||||||
|
}
|
||||||
|
acc.push_str(&next);
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function helps to modify the Display representation of remote
|
||||||
|
// API failures so that it aligns with the regular output of error
|
||||||
|
// messages. As we transfer a deep/rich chain of errors as String via
|
||||||
|
// the HTTP API, the nested error chain is lost. We retrieve it from
|
||||||
|
// the error response.
|
||||||
|
//
|
||||||
|
// In case the repose itself is broken, the error is printed directly
|
||||||
|
// by using the `X` level.
|
||||||
|
fn server_api_error_display_modifier(
|
||||||
|
level: usize,
|
||||||
|
indention: usize,
|
||||||
|
error: &(dyn std::error::Error + 'static),
|
||||||
|
) -> Option<String> {
|
||||||
|
if let Some(api_client::Error::ServerResponse(status_code, body)) =
|
||||||
|
error.downcast_ref::<api_client::Error>()
|
||||||
|
{
|
||||||
|
let body = body.as_ref().map(|body| body.as_str()).unwrap_or("");
|
||||||
|
|
||||||
|
// Retrieve the list of error messages back.
|
||||||
|
let lines: Vec<&str> = match serde_json::from_str(body) {
|
||||||
|
Ok(json) => json,
|
||||||
|
Err(e) => {
|
||||||
|
return Some(format!(
|
||||||
|
"{idention}X: Can't get remote's error messages from JSON response: {e}: body='{body}'",
|
||||||
|
idention = " ".repeat(indention)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let error_status = format!("Server responded with {status_code:?}");
|
||||||
|
// Prepend the error status line to the lines iter.
|
||||||
|
let lines = std::iter::once(error_status.as_str()).chain(lines);
|
||||||
|
let error_msg_multiline = lines
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, error_msg)| (index + level, error_msg))
|
||||||
|
.map(|(level, error_msg)| {
|
||||||
|
format!(
|
||||||
|
"{idention}{level}: {error_msg}",
|
||||||
|
idention = " ".repeat(indention)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.fold(String::new(), join_strs);
|
||||||
|
|
||||||
|
return Some(error_msg_multiline);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
let top_error: &dyn std::error::Error = &top_error;
|
||||||
|
cloud_hypervisor::cli_print_error_chain(
|
||||||
|
top_error,
|
||||||
|
"ch-remote",
|
||||||
|
server_api_error_display_modifier,
|
||||||
|
);
|
||||||
process::exit(1)
|
process::exit(1)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::test_util::assert_args_sorted;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cli_args_sorted() {
|
||||||
|
let args = get_cli_args();
|
||||||
|
assert_args_sorted(|| args.iter());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cli_commands_sorted() {
|
||||||
|
let commands = get_cli_commands_sorted();
|
||||||
|
|
||||||
|
// check commands itself are sorted
|
||||||
|
let iter = commands.iter().zip(commands.iter().skip(1));
|
||||||
|
for (command, next) in iter {
|
||||||
|
assert_ne!(
|
||||||
|
command.get_name().cmp(next.get_name()),
|
||||||
|
Ordering::Greater,
|
||||||
|
"commands not alphabetically sorted: command={}, next={}",
|
||||||
|
command.get_name(),
|
||||||
|
next.get_name()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check args of commands sorted
|
||||||
|
for command in commands {
|
||||||
|
assert_args_sorted(|| command.get_arguments());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
46
src/lib.rs
Normal file
46
src/lib.rs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// Copyright © 2025 Cyberus Technology GmbH
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use log::error;
|
||||||
|
|
||||||
|
/// Prints a chain of errors to the user in a consistent manner.
|
||||||
|
/// The user will see a clear chain of errors, followed by debug output
|
||||||
|
/// for opening issues.
|
||||||
|
pub fn cli_print_error_chain<'a>(
|
||||||
|
top_error: &'a (dyn Error + 'static),
|
||||||
|
component: &str,
|
||||||
|
// Function optionally returning the display representation of an error.
|
||||||
|
display_modifier: impl Fn(
|
||||||
|
/* level */ usize,
|
||||||
|
/*indention */ usize,
|
||||||
|
&'a (dyn Error + 'static),
|
||||||
|
) -> Option<String>,
|
||||||
|
) {
|
||||||
|
let msg = format!("Error: {component} exited with the following");
|
||||||
|
if top_error.source().is_none() {
|
||||||
|
error!("{msg} error:");
|
||||||
|
error!(" {top_error}");
|
||||||
|
} else {
|
||||||
|
error!("{msg} chain of errors:");
|
||||||
|
std::iter::successors(Some(top_error), |sub_error| {
|
||||||
|
// Dereference necessary to mitigate rustc compiler bug.
|
||||||
|
// See <https://github.com/rust-lang/rust/issues/141673>
|
||||||
|
(*sub_error).source()
|
||||||
|
})
|
||||||
|
.enumerate()
|
||||||
|
.for_each(|(level, error)| {
|
||||||
|
// Special case: handling of HTTP Server responses in ch-remote
|
||||||
|
if let Some(message) = display_modifier(level, 2, error) {
|
||||||
|
error!("{message}");
|
||||||
|
} else {
|
||||||
|
error!(" {level}: {error}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
error!("");
|
||||||
|
error!("Debug Info: {top_error:?}");
|
||||||
|
}
|
||||||
78
src/main.rs
78
src/main.rs
@@ -3,6 +3,9 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_util;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
@@ -12,7 +15,7 @@ use std::{env, io};
|
|||||||
use clap::{Arg, ArgAction, ArgGroup, ArgMatches, Command};
|
use clap::{Arg, ArgAction, ArgGroup, ArgMatches, Command};
|
||||||
use event_monitor::event;
|
use event_monitor::event;
|
||||||
use libc::EFD_NONBLOCK;
|
use libc::EFD_NONBLOCK;
|
||||||
use log::{warn, LevelFilter};
|
use log::{error, warn, LevelFilter};
|
||||||
use option_parser::OptionParser;
|
use option_parser::OptionParser;
|
||||||
use seccompiler::SeccompAction;
|
use seccompiler::SeccompAction;
|
||||||
use signal_hook::consts::SIGSYS;
|
use signal_hook::consts::SIGSYS;
|
||||||
@@ -40,34 +43,34 @@ static ALLOC: dhat::Alloc = dhat::Alloc;
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
enum Error {
|
enum Error {
|
||||||
#[error("Failed to create API EventFd: {0}")]
|
#[error("Failed to create API EventFd")]
|
||||||
CreateApiEventFd(#[source] std::io::Error),
|
CreateApiEventFd(#[source] std::io::Error),
|
||||||
#[cfg(feature = "guest_debug")]
|
#[cfg(feature = "guest_debug")]
|
||||||
#[error("Failed to create Debug EventFd: {0}")]
|
#[error("Failed to create Debug EventFd")]
|
||||||
CreateDebugEventFd(#[source] std::io::Error),
|
CreateDebugEventFd(#[source] std::io::Error),
|
||||||
#[error("Failed to create exit EventFd: {0}")]
|
#[error("Failed to create exit EventFd")]
|
||||||
CreateExitEventFd(#[source] std::io::Error),
|
CreateExitEventFd(#[source] std::io::Error),
|
||||||
#[error("Failed to open hypervisor interface (is hypervisor interface available?): {0}")]
|
#[error("Failed to open hypervisor interface (is hypervisor interface available?)")]
|
||||||
CreateHypervisor(#[source] hypervisor::HypervisorError),
|
CreateHypervisor(#[source] hypervisor::HypervisorError),
|
||||||
#[error("Failed to start the VMM thread: {0}")]
|
#[error("Failed to start the VMM thread")]
|
||||||
StartVmmThread(#[source] vmm::Error),
|
StartVmmThread(#[source] vmm::Error),
|
||||||
#[error("Error parsing config: {0}")]
|
#[error("Error parsing config")]
|
||||||
ParsingConfig(#[source] vmm::config::Error),
|
ParsingConfig(#[source] vmm::config::Error),
|
||||||
#[error("Error creating VM: {0:?}")]
|
#[error("Error creating VM")]
|
||||||
VmCreate(#[source] vmm::api::ApiError),
|
VmCreate(#[source] vmm::api::ApiError),
|
||||||
#[error("Error booting VM: {0:?}")]
|
#[error("Error booting VM")]
|
||||||
VmBoot(#[source] vmm::api::ApiError),
|
VmBoot(#[source] vmm::api::ApiError),
|
||||||
#[error("Error restoring VM: {0:?}")]
|
#[error("Error restoring VM")]
|
||||||
VmRestore(#[source] vmm::api::ApiError),
|
VmRestore(#[source] vmm::api::ApiError),
|
||||||
#[error("Error parsing restore: {0}")]
|
#[error("Error parsing restore")]
|
||||||
ParsingRestore(#[source] vmm::config::Error),
|
ParsingRestore(#[source] vmm::config::Error),
|
||||||
#[error("Failed to join on VMM thread: {0:?}")]
|
#[error("Failed to join on VMM thread: {0:?}")]
|
||||||
ThreadJoin(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
|
ThreadJoin(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
|
||||||
#[error("VMM thread exited with error: {0}")]
|
#[error("VMM thread exited with error")]
|
||||||
VmmThread(#[source] vmm::Error),
|
VmmThread(#[source] vmm::Error),
|
||||||
#[error("Error parsing --api-socket: {0}")]
|
#[error("Error parsing --api-socket")]
|
||||||
ParsingApiSocket(#[source] std::num::ParseIntError),
|
ParsingApiSocket(#[source] std::num::ParseIntError),
|
||||||
#[error("Error parsing --event-monitor: {0}")]
|
#[error("Error parsing --event-monitor")]
|
||||||
ParsingEventMonitor(#[source] option_parser::OptionParserError),
|
ParsingEventMonitor(#[source] option_parser::OptionParserError),
|
||||||
#[cfg(feature = "dbus_api")]
|
#[cfg(feature = "dbus_api")]
|
||||||
#[error("`--dbus-object-path` option isn't provided")]
|
#[error("`--dbus-object-path` option isn't provided")]
|
||||||
@@ -77,37 +80,37 @@ enum Error {
|
|||||||
MissingDBusServiceName,
|
MissingDBusServiceName,
|
||||||
#[error("Error parsing --event-monitor: path or fd required")]
|
#[error("Error parsing --event-monitor: path or fd required")]
|
||||||
BareEventMonitor,
|
BareEventMonitor,
|
||||||
#[error("Error doing event monitor I/O: {0}")]
|
#[error("Error doing event monitor I/O")]
|
||||||
EventMonitorIo(#[source] std::io::Error),
|
EventMonitorIo(#[source] std::io::Error),
|
||||||
#[error("Event monitor thread failed: {0}")]
|
#[error("Event monitor thread failed")]
|
||||||
EventMonitorThread(#[source] vmm::Error),
|
EventMonitorThread(#[source] vmm::Error),
|
||||||
#[cfg(feature = "guest_debug")]
|
#[cfg(feature = "guest_debug")]
|
||||||
#[error("Error parsing --gdb: {0}")]
|
#[error("Error parsing --gdb")]
|
||||||
ParsingGdb(#[source] option_parser::OptionParserError),
|
ParsingGdb(#[source] option_parser::OptionParserError),
|
||||||
#[cfg(feature = "guest_debug")]
|
#[cfg(feature = "guest_debug")]
|
||||||
#[error("Error parsing --gdb: path required")]
|
#[error("Error parsing --gdb: path required")]
|
||||||
BareGdb,
|
BareGdb,
|
||||||
#[error("Error creating log file: {0}")]
|
#[error("Error creating log file")]
|
||||||
LogFileCreation(#[source] std::io::Error),
|
LogFileCreation(#[source] std::io::Error),
|
||||||
#[error("Error setting up logger: {0}")]
|
#[error("Error setting up logger")]
|
||||||
LoggerSetup(#[source] log::SetLoggerError),
|
LoggerSetup(#[source] log::SetLoggerError),
|
||||||
#[error("Failed to gracefully shutdown http api: {0}")]
|
#[error("Failed to gracefully shutdown http api")]
|
||||||
HttpApiShutdown(#[source] vmm::Error),
|
HttpApiShutdown(#[source] vmm::Error),
|
||||||
#[error("Failed to create Landlock object: {0}")]
|
#[error("Failed to create Landlock object")]
|
||||||
CreateLandlock(#[source] LandlockError),
|
CreateLandlock(#[source] LandlockError),
|
||||||
#[error("Failed to apply Landlock: {0}")]
|
#[error("Failed to apply Landlock")]
|
||||||
ApplyLandlock(#[source] LandlockError),
|
ApplyLandlock(#[source] LandlockError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
enum FdTableError {
|
enum FdTableError {
|
||||||
#[error("Failed to create event fd: {0}")]
|
#[error("Failed to create event fd")]
|
||||||
CreateEventFd(#[source] std::io::Error),
|
CreateEventFd(#[source] std::io::Error),
|
||||||
#[error("Failed to obtain file limit: {0}")]
|
#[error("Failed to obtain file limit")]
|
||||||
GetRLimit(#[source] std::io::Error),
|
GetRLimit(#[source] std::io::Error),
|
||||||
#[error("Error calling fcntl with F_GETFD: {0}")]
|
#[error("Error calling fcntl with F_GETFD")]
|
||||||
GetFd(#[source] std::io::Error),
|
GetFd(#[source] std::io::Error),
|
||||||
#[error("Failed to duplicate file handle: {0}")]
|
#[error("Failed to duplicate file handle")]
|
||||||
Dup2(#[source] std::io::Error),
|
Dup2(#[source] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,7 +561,7 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
|||||||
signal_hook::low_level::emulate_default_handler(SIGSYS).unwrap();
|
signal_hook::low_level::emulate_default_handler(SIGSYS).unwrap();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
.map_err(|e| eprintln!("Error adding SIGSYS signal handler: {e}"))
|
.map_err(|e| error!("Error adding SIGSYS signal handler: {e}"))
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,13 +575,13 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
|||||||
// dedicated signal handling thread we'll start in a bit.
|
// dedicated signal handling thread we'll start in a bit.
|
||||||
for sig in &vmm::vm::Vm::HANDLED_SIGNALS {
|
for sig in &vmm::vm::Vm::HANDLED_SIGNALS {
|
||||||
if let Err(e) = block_signal(*sig) {
|
if let Err(e) = block_signal(*sig) {
|
||||||
eprintln!("Error blocking signals: {e}");
|
error!("Error blocking signals: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for sig in &vmm::Vmm::HANDLED_SIGNALS {
|
for sig in &vmm::Vmm::HANDLED_SIGNALS {
|
||||||
if let Err(e) = block_signal(*sig) {
|
if let Err(e) = block_signal(*sig) {
|
||||||
eprintln!("Error blocking signals: {e}");
|
error!("Error blocking signals: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -880,8 +883,8 @@ fn main() {
|
|||||||
path.map(|s| std::fs::remove_file(s).ok());
|
path.map(|s| std::fs::remove_file(s).ok());
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(top_error) => {
|
||||||
eprintln!("{e}");
|
cloud_hypervisor::cli_print_error_chain(&top_error, "Cloud Hypervisor", |_, _, _| None);
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -894,7 +897,6 @@ fn main() {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod unit_tests {
|
mod unit_tests {
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use vmm::config::VmParams;
|
use vmm::config::VmParams;
|
||||||
@@ -905,6 +907,7 @@ mod unit_tests {
|
|||||||
PayloadConfig, RngConfig, VmConfig,
|
PayloadConfig, RngConfig, VmConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::test_util::assert_args_sorted;
|
||||||
use crate::{create_app, get_cli_options_sorted, prepare_default_values};
|
use crate::{create_app, get_cli_options_sorted, prepare_default_values};
|
||||||
|
|
||||||
fn get_vm_config_from_vec(args: &[&str]) -> VmConfig {
|
fn get_vm_config_from_vec(args: &[&str]) -> VmConfig {
|
||||||
@@ -2014,15 +2017,6 @@ mod unit_tests {
|
|||||||
let (default_vcpus, default_memory, default_rng) = prepare_default_values();
|
let (default_vcpus, default_memory, default_rng) = prepare_default_values();
|
||||||
let args = get_cli_options_sorted(default_vcpus, default_memory, default_rng);
|
let args = get_cli_options_sorted(default_vcpus, default_memory, default_rng);
|
||||||
|
|
||||||
let iter = args.iter().zip(args.iter().skip(1));
|
assert_args_sorted(|| args.iter())
|
||||||
for (elem, next) in iter {
|
|
||||||
assert_ne!(
|
|
||||||
elem.get_id().cmp(next.get_id()),
|
|
||||||
Ordering::Greater,
|
|
||||||
"items not alphabetically sorted: elem={}, next={}",
|
|
||||||
elem.get_id(),
|
|
||||||
next.get_id()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/test_util.rs
Normal file
24
src/test_util.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright © 2025 Cyberus Technology GmbH
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
//! Test utilities.
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
use clap::Arg;
|
||||||
|
|
||||||
|
/// Ensures that all [`Arg`]s are sorted alphabetically.
|
||||||
|
pub fn assert_args_sorted<'a, F: Fn() -> R, R: Iterator<Item = &'a Arg>>(get_base_iter: F) {
|
||||||
|
let iter = get_base_iter().zip(get_base_iter().skip(1));
|
||||||
|
for (arg, next) in iter {
|
||||||
|
assert_ne!(
|
||||||
|
arg.get_id().cmp(next.get_id()),
|
||||||
|
Ordering::Greater,
|
||||||
|
"args not alphabetically sorted: arg={}, next={}",
|
||||||
|
arg.get_id(),
|
||||||
|
next.get_id()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user