mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
212 Commits
stable/v20
...
v21.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e01933c8ea | ||
|
|
c6307865eb | ||
|
|
6275d4f87e | ||
|
|
4dfe1ff77a | ||
|
|
bbda07c388 | ||
|
|
366223c9f4 | ||
|
|
375356a097 | ||
|
|
95ca79974a | ||
|
|
eb5c5f2c7f | ||
|
|
85bbf75fe8 | ||
|
|
b4566b9eab | ||
|
|
e2a8a1483f | ||
|
|
ea60d48853 | ||
|
|
658658e76c | ||
|
|
b7b3b45364 | ||
|
|
d5b4d0d951 | ||
|
|
1c18d124dc | ||
|
|
7a42ce9310 | ||
|
|
1db7718589 | ||
|
|
cf68f03ab6 | ||
|
|
4ecc778efe | ||
|
|
48ba999bd9 | ||
|
|
ef05354c81 | ||
|
|
277cfd07ba | ||
|
|
4f05b8463c | ||
|
|
c9983ff4ad | ||
|
|
714b529bb2 | ||
|
|
99bcebad74 | ||
|
|
22d86fb6d2 | ||
|
|
2eed24b4b2 | ||
|
|
be7829b752 | ||
|
|
ea2685e928 | ||
|
|
14ba3f68d3 | ||
|
|
779bc1a53a | ||
|
|
8b8daf571a | ||
|
|
482e1ca435 | ||
|
|
a61302f73f | ||
|
|
33fd0af8b3 | ||
|
|
cb243571de | ||
|
|
70f7f64e23 | ||
|
|
88952cc500 | ||
|
|
715a7d9065 | ||
|
|
1676fffaad | ||
|
|
1daef5e8c9 | ||
|
|
735658a49d | ||
|
|
b95e46565c | ||
|
|
eeba1d3ad8 | ||
|
|
271e17bd79 | ||
|
|
b9c260c0de | ||
|
|
6e78ac1837 | ||
|
|
dad5af612b | ||
|
|
101d403a6b | ||
|
|
29e3fefc3d | ||
|
|
859f72b5a5 | ||
|
|
8155be2e6b | ||
|
|
4577e5050b | ||
|
|
1952405f69 | ||
|
|
1dc913427c | ||
|
|
0a97b76c52 | ||
|
|
b204f43aae | ||
|
|
ade8d71264 | ||
|
|
92b8bdf474 | ||
|
|
84e2f6c1da | ||
|
|
e02f5c9699 | ||
|
|
2f492fbe36 | ||
|
|
c47cb868ec | ||
|
|
fb1755d85d | ||
|
|
5e1e523a90 | ||
|
|
685ca03e67 | ||
|
|
b80feb3d96 | ||
|
|
cb15ae5462 | ||
|
|
6738e45b37 | ||
|
|
c2f133990d | ||
|
|
a926bc139b | ||
|
|
5b05e0cdcd | ||
|
|
e7a2a715e0 | ||
|
|
430f72f96c | ||
|
|
901f65388a | ||
|
|
68e95d5841 | ||
|
|
c5f20c45a0 | ||
|
|
c7d1cfbd88 | ||
|
|
9c8f291b60 | ||
|
|
70af81d755 | ||
|
|
8fa3864ae8 | ||
|
|
221c1f1bdc | ||
|
|
3baebc1af0 | ||
|
|
2563b08ff0 | ||
|
|
f6333a39a5 | ||
|
|
936237d4d6 | ||
|
|
6408e8629e | ||
|
|
617b568f71 | ||
|
|
0fcbcea275 | ||
|
|
10d1922393 | ||
|
|
0162d73ed8 | ||
|
|
d57c49664f | ||
|
|
2f46647ecc | ||
|
|
9ef1187f4a | ||
|
|
e7db354c27 | ||
|
|
6ba5b0a83a | ||
|
|
2c59702e4a | ||
|
|
98ba347956 | ||
|
|
cd0aca4bcd | ||
|
|
f27cbb9caf | ||
|
|
e4763b47f1 | ||
|
|
7cc1643782 | ||
|
|
58501ed0a6 | ||
|
|
b72136ddb3 | ||
|
|
07756aa8fb | ||
|
|
c47ab55e99 | ||
|
|
a749063c8a | ||
|
|
cf2abd35d0 | ||
|
|
0dbff2a81d | ||
|
|
e355bb9fd4 | ||
|
|
aeaf432784 | ||
|
|
ccc9308ec1 | ||
|
|
129f708df7 | ||
|
|
542f05ebfa | ||
|
|
8e89a10db7 | ||
|
|
5283cb38db | ||
|
|
346bee48ad | ||
|
|
210a29f05c | ||
|
|
21a21ce51a | ||
|
|
877a537bf7 | ||
|
|
5a1e9c9bff | ||
|
|
a45939fb40 | ||
|
|
b85d29780f | ||
|
|
b3351e11b3 | ||
|
|
05720dbf25 | ||
|
|
d7ba8ad1fa | ||
|
|
748611752d | ||
|
|
9c5636204d | ||
|
|
fbbbd04ddf | ||
|
|
89af7dcb2b | ||
|
|
8737ca4d45 | ||
|
|
d186297dba | ||
|
|
09d6cdb185 | ||
|
|
c40c1778e5 | ||
|
|
58a2abbba2 | ||
|
|
b6159217b6 | ||
|
|
7bb828ecf2 | ||
|
|
4a47cdcebd | ||
|
|
8813456aef | ||
|
|
6c8bd1f476 | ||
|
|
6a76a6772d | ||
|
|
cbc388c7e2 | ||
|
|
4773e23c77 | ||
|
|
3b0d278ba3 | ||
|
|
443b64b04f | ||
|
|
ccccc94c8a | ||
|
|
3f0a33a50f | ||
|
|
32aedddb0a | ||
|
|
fa15cf6ac3 | ||
|
|
5c12c15f26 | ||
|
|
bde81405a8 | ||
|
|
9742fa5c7c | ||
|
|
3806afdc43 | ||
|
|
c6ba188586 | ||
|
|
afe386bc13 | ||
|
|
df21e15148 | ||
|
|
2883c71911 | ||
|
|
07a78842b5 | ||
|
|
91c7590ba6 | ||
|
|
e1b0630b79 | ||
|
|
2a2cea1658 | ||
|
|
3cd02403db | ||
|
|
a9f5021005 | ||
|
|
f14d0d0191 | ||
|
|
4959434219 | ||
|
|
7444c3a0c5 | ||
|
|
35d3c1f611 | ||
|
|
be5fd7c572 | ||
|
|
39172f8b54 | ||
|
|
2bcf718028 | ||
|
|
6d047bdec6 | ||
|
|
c6e534baf7 | ||
|
|
fb2b633ada | ||
|
|
8fb64859cc | ||
|
|
254d648bb7 | ||
|
|
21b0ab106c | ||
|
|
7bce72dff3 | ||
|
|
50f5f43ae3 | ||
|
|
fd3cf761be | ||
|
|
0a04c7206d | ||
|
|
58d3d4c34e | ||
|
|
eea2907daf | ||
|
|
7b5e8a3ca8 | ||
|
|
616d01aca2 | ||
|
|
637dc53a48 | ||
|
|
4b9b52fc6f | ||
|
|
3d1cfd4d55 | ||
|
|
e1c09b66ba | ||
|
|
af770c814b | ||
|
|
a29e53e436 | ||
|
|
00bb1ea1d5 | ||
|
|
bb6c93d5df | ||
|
|
90df54a245 | ||
|
|
ca9a42ece8 | ||
|
|
2f8540da70 | ||
|
|
07bef815cc | ||
|
|
e1151482fc | ||
|
|
3e536f91eb | ||
|
|
cab0b3446f | ||
|
|
7bb343dce8 | ||
|
|
9b0fe505ca | ||
|
|
03a606c7ec | ||
|
|
c452471c4e | ||
|
|
882cdda995 | ||
|
|
788d77aee5 | ||
|
|
e08c747638 | ||
|
|
b519975fc8 | ||
|
|
348def9dfb | ||
|
|
b09cbb8493 |
2
.github/workflows/quality.yaml
vendored
2
.github/workflows/quality.yaml
vendored
@@ -55,7 +55,7 @@ jobs:
|
||||
run: cargo clippy --all --all-targets --no-default-features --tests --features "mshv" -- -D warnings
|
||||
|
||||
- name: Clippy (integration tests)
|
||||
run: cargo clippy --all --all-targets --tests --features "integration_tests" -- -D warnings
|
||||
run: cargo clippy --all --all-targets --tests -- -D warnings
|
||||
|
||||
- name: Check build did not modify any files
|
||||
run: test -z "$(git status --porcelain)"
|
||||
|
||||
10
.github/workflows/release.yaml
vendored
10
.github/workflows/release.yaml
vendored
@@ -99,6 +99,16 @@ jobs:
|
||||
asset_path: target/x86_64-unknown-linux-gnu/release/ch-remote
|
||||
asset_name: ch-remote
|
||||
asset_content_type: application/octet-stream
|
||||
- name: Upload static-ch-remote
|
||||
id: upload-release-static-ch-remote
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: target/x86_64-unknown-linux-musl/release/ch-remote
|
||||
asset_name: ch-remote-static
|
||||
asset_content_type: application/octet-stream
|
||||
- name: Upload static AArch64 cloud-hypervisor
|
||||
id: upload-release-static-aarch64-cloud-hypervisor
|
||||
uses: actions/upload-release-asset@v1
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
/build
|
||||
/.cargo
|
||||
/target
|
||||
**/*.rs.bk
|
||||
**/Cargo.lock
|
||||
|
||||
335
Cargo.lock
generated
335
Cargo.lock
generated
@@ -9,21 +9,6 @@ dependencies = [
|
||||
"vm-memory",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
@@ -33,20 +18,11 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.51"
|
||||
version = "1.0.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
|
||||
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
|
||||
|
||||
[[package]]
|
||||
name = "api_client"
|
||||
@@ -101,21 +77,6 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
@@ -170,28 +131,28 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
version = "3.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
"os_str_bytes",
|
||||
"strsim",
|
||||
"term_size",
|
||||
"termcolor",
|
||||
"terminal_size",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloud-hypervisor"
|
||||
version = "20.0.0"
|
||||
version = "21.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"api_client",
|
||||
"clap",
|
||||
"credibility",
|
||||
"dirs 4.0.0",
|
||||
"epoll",
|
||||
"event_monitor",
|
||||
@@ -214,9 +175,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crc32c"
|
||||
version = "0.6.0"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "210cdf933e6a81212bfabf90cd8762f471b5922e5f6b709547673ad8e04b9448"
|
||||
checksum = "ee6b9c9389584bcba988bd0836086789b7f87ad91892d6a83d5291dbb24524b5"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
@@ -227,16 +188,6 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
|
||||
|
||||
[[package]]
|
||||
name = "credibility"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fae7a162fd5b462bc49704873a89950a655d44161add4be07e00e64c4c83a5bf"
|
||||
dependencies = [
|
||||
"failure",
|
||||
"failure_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "devices"
|
||||
version = "0.1.0"
|
||||
@@ -319,28 +270,6 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"failure_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure_derive"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fdt"
|
||||
version = "0.1.3"
|
||||
@@ -349,21 +278,15 @@ checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
@@ -371,10 +294,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7a30908dbce072eca83216eab939d2290080e00ca71611b96a09e5cdce5f3fa"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -417,6 +346,16 @@ dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
@@ -447,9 +386,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||
|
||||
[[package]]
|
||||
name = "kvm-bindings"
|
||||
@@ -464,8 +403,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kvm-ioctls"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97422ba48d7ffb66fd4d18130f72ab66f9bbbf791fb7a87b9291cdcfec437593"
|
||||
source = "git+https://github.com/rust-vmm/kvm-ioctls?branch=main#d22ef1f51852dfb055da38004e1a4fed81246f81"
|
||||
dependencies = [
|
||||
"kvm-bindings",
|
||||
"libc",
|
||||
@@ -480,9 +418,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.108"
|
||||
version = "0.2.112"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
|
||||
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
|
||||
|
||||
[[package]]
|
||||
name = "libssh2-sys"
|
||||
@@ -543,6 +481,15 @@ version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "micro_http"
|
||||
version = "0.1.0"
|
||||
@@ -552,20 +499,10 @@ dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mshv-bindings"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#8770516859e7d05193c496b77ac5ddad3ca5943a"
|
||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#b8b69b655337292037219ab765d2c94c565a076e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"serde",
|
||||
@@ -577,7 +514,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mshv-ioctls"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#8770516859e7d05193c496b77ac5ddad3ca5943a"
|
||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#b8b69b655337292037219ab765d2c94c565a076e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mshv-bindings",
|
||||
@@ -614,20 +551,11 @@ dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.71"
|
||||
version = "0.9.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73"
|
||||
checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
@@ -640,6 +568,15 @@ dependencies = [
|
||||
name = "option_parser"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
@@ -689,15 +626,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.22"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
|
||||
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
||||
|
||||
[[package]]
|
||||
name = "pnet"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b6d2a0409666964722368ef5fb74b9f93fac11c18bef3308693c16c6733f103"
|
||||
checksum = "8750e073f82219c01e771133c64718d7685aef922da8a0d430a46aed05b6341a"
|
||||
dependencies = [
|
||||
"ipnetwork",
|
||||
"pnet_base",
|
||||
@@ -709,15 +646,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pnet_base"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25488cd551a753dcaaa6fffc9f69a7610a412dd8954425bf7ffad5f7d1156fb8"
|
||||
checksum = "8205fe084bd43a3af79b3155c19feddd62e733640498842e631a2ffe107d1538"
|
||||
|
||||
[[package]]
|
||||
name = "pnet_datalink"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4d1f8ab1ef6c914cf51dc5dfe0be64088ea5f3b08bbf5a31abc70356d271198"
|
||||
checksum = "6f85aef5e52e22ff06b1b11f2eb6d52959a9e0ecad3cb3f5cc2d78cadc077f0e"
|
||||
dependencies = [
|
||||
"ipnetwork",
|
||||
"libc",
|
||||
@@ -728,9 +665,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pnet_macros"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30490e0852e58402b8fae0d39897b08a24f493023a4d6cf56b2e30f31ed57548"
|
||||
checksum = "98cc3af95fed6dc318dfede3e81320f96ad5e237c6f7c4688108b19c8e67432d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -740,18 +677,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pnet_macros_support"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4714e10f30cab023005adce048f2d30dd4ac4f093662abf2220855655ef8f90"
|
||||
checksum = "feaba58ba96abb218ec584d6caf0d3ff48922df05dbbeb1560553c197091b29e"
|
||||
dependencies = [
|
||||
"pnet_base",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pnet_packet"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8588067671d03c9f4254b2e66fecb4d8b93b5d3e703195b84f311cd137e32130"
|
||||
checksum = "f246edaaf1aaf82072d4cd38ee18bcc5dfc0464093f9ca39e4ac5962d68cf9d4"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"pnet_base",
|
||||
@@ -761,9 +698,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pnet_sys"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9a3f32b0df45515befd19eed04616f6b56a488da92afc61164ef455e955f07f"
|
||||
checksum = "028c87a5e3a48fc07df099a2025f2ef16add5993712e1494ba69a6707ee7ed06"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
@@ -771,9 +708,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pnet_transport"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "932b2916d693bcc5fa18443dc99142e0a6fd31a6ce75a511868f7174c17e2bce"
|
||||
checksum = "950f2a7961e19d22e19e84ff0a6e0955013185fe149673499662633d02b41b7a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pnet_base",
|
||||
@@ -783,9 +720,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.32"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
||||
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
@@ -803,9 +740,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.10"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -866,26 +803,20 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.6"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568"
|
||||
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
@@ -904,30 +835,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
version = "1.0.133"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||
checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.130"
|
||||
version = "1.0.133"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||
checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -936,9 +858,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.72"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527"
|
||||
checksum = "c059c05b48c5c0067d4b4b2b4f0732dd65feb52daf7e0ea09cd87e7dadc1af79"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -947,9 +869,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.10"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
|
||||
checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
@@ -966,9 +888,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.7.0"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||
|
||||
[[package]]
|
||||
name = "ssh2"
|
||||
@@ -990,15 +912,15 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.82"
|
||||
version = "1.0.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
|
||||
checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1017,16 +939,6 @@ dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term_size"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
@@ -1036,6 +948,16 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test_infra"
|
||||
version = "0.1.0"
|
||||
@@ -1050,12 +972,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
|
||||
dependencies = [
|
||||
"term_size",
|
||||
"unicode-width",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1078,12 +999,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
@@ -1105,12 +1020,6 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "versionize"
|
||||
version = "0.1.6"
|
||||
@@ -1140,9 +1049,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vfio-bindings"
|
||||
version = "0.2.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a21f546f2bda37f5a8cfb138c87f95b8e34d2d78d6a7a92ba3785f4e08604a7"
|
||||
checksum = "43449b404c488f70507dca193debd4bea361fe8089869b947adc19720e464bce"
|
||||
dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
@@ -1197,9 +1106,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vhost"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d23ddeb452fb4f837526c6298cc8a2f4948e5595b0328a3d61b5eebe51874d7"
|
||||
checksum = "3b56bf8f178fc500fe14505fca8b00dec76fc38f2304f461c8d9d7547982311d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@@ -1304,6 +1213,7 @@ name = "virtio-queue"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"memoffset",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
@@ -1338,9 +1248,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#9cfa0c8d7c3032f7958
|
||||
|
||||
[[package]]
|
||||
name = "vm-memory"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a8ebcb86ca457f9d6e14cf97009f679952eba42f0113de5db596e514cd0e43b"
|
||||
checksum = "339d4349c126fdcd87e034631d7274370cf19eb0e87b33166bcd956589fc72c5"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"libc",
|
||||
@@ -1382,7 +1292,6 @@ dependencies = [
|
||||
"bitflags",
|
||||
"block_util",
|
||||
"clap",
|
||||
"credibility",
|
||||
"devices",
|
||||
"epoll",
|
||||
"event_monitor",
|
||||
|
||||
26
Cargo.toml
26
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cloud-hypervisor"
|
||||
version = "20.0.0"
|
||||
version = "21.1.0"
|
||||
authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
default-run = "cloud-hypervisor"
|
||||
@@ -13,55 +13,51 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.51"
|
||||
anyhow = "1.0.52"
|
||||
api_client = { path = "api_client" }
|
||||
clap = { version = "2.34.0", features = ["wrap_help"] }
|
||||
clap = { version = "3.0.10", features = ["wrap_help","cargo"] }
|
||||
epoll = "4.3.1"
|
||||
event_monitor = { path = "event_monitor" }
|
||||
hypervisor = { path = "hypervisor" }
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
log = { version = "0.4.14", features = ["std"] }
|
||||
option_parser = { path = "option_parser" }
|
||||
seccompiler = "0.2.0"
|
||||
serde_json = "1.0.72"
|
||||
signal-hook = "0.3.10"
|
||||
serde_json = "1.0.75"
|
||||
signal-hook = "0.3.13"
|
||||
thiserror = "1.0.30"
|
||||
vmm = { path = "vmm" }
|
||||
vmm-sys-util = "0.9.0"
|
||||
vm-memory = "0.6.0"
|
||||
vm-memory = "0.7.0"
|
||||
|
||||
[build-dependencies]
|
||||
clap = { version = "2.34.0", features = ["wrap_help"] }
|
||||
clap = { version = "3.0.10", features = ["wrap_help"] }
|
||||
|
||||
# List of patched crates
|
||||
[patch.crates-io]
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"] }
|
||||
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||
|
||||
[dev-dependencies]
|
||||
credibility = "0.1.3"
|
||||
dirs = "4.0.0"
|
||||
lazy_static= "1.4.0"
|
||||
net_util = { path = "net_util" }
|
||||
serde_json = "1.0.72"
|
||||
serde_json = "1.0.75"
|
||||
test_infra = { path = "test_infra" }
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
[features]
|
||||
default = ["common", "kvm"]
|
||||
# Common features for all hypervisors
|
||||
common = ["acpi", "cmos", "fwdebug", "io_uring"]
|
||||
common = ["acpi", "cmos", "fwdebug"]
|
||||
acpi = ["vmm/acpi"]
|
||||
cmos = ["vmm/cmos"]
|
||||
fwdebug = ["vmm/fwdebug"]
|
||||
kvm = ["vmm/kvm"]
|
||||
mshv = ["vmm/mshv"]
|
||||
io_uring = ["vmm/io_uring"]
|
||||
tdx = ["vmm/tdx"]
|
||||
|
||||
# Integration tests require a special environment to run in
|
||||
integration_tests = []
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"acpi_tables",
|
||||
|
||||
25
Jenkinsfile
vendored
25
Jenkinsfile
vendored
@@ -22,15 +22,19 @@ pipeline{
|
||||
}
|
||||
}
|
||||
stage ('Build') {
|
||||
parallel {
|
||||
parallel {
|
||||
stage ('Worker build') {
|
||||
agent { node { label 'hirsute' } }
|
||||
environment {
|
||||
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
|
||||
}
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
|
||||
stage ('Run OpenAPI tests') {
|
||||
steps {
|
||||
sh "scripts/run_openapi_tests.sh"
|
||||
@@ -84,12 +88,16 @@ pipeline{
|
||||
}
|
||||
stage ('Worker build (musl)') {
|
||||
agent { node { label 'hirsute' } }
|
||||
environment {
|
||||
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
|
||||
}
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
|
||||
stage ('Run unit tests for musl') {
|
||||
steps {
|
||||
sh "scripts/dev_cli.sh tests --unit --libc musl"
|
||||
@@ -189,11 +197,14 @@ pipeline{
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage ('Install azure-cli') {
|
||||
steps {
|
||||
installAzureCli()
|
||||
}
|
||||
}
|
||||
stage ('Download assets') {
|
||||
steps {
|
||||
sh "sudo apt install -y azure-cli"
|
||||
sh "mkdir ${env.HOME}/workloads"
|
||||
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/OVMF-4b47d0c6c8.fd" --name OVMF-4b47d0c6c8.fd --connection-string "$AZURE_CONNECTION_STRING"'
|
||||
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/windows-server-2019.raw" --name windows-server-2019.raw --connection-string "$AZURE_CONNECTION_STRING"'
|
||||
}
|
||||
}
|
||||
@@ -278,3 +289,11 @@ def cancelPreviousBuilds() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def installAzureCli() {
|
||||
sh "sudo apt install -y ca-certificates curl apt-transport-https lsb-release gnupg"
|
||||
sh "curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null"
|
||||
sh "echo \"deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ hirsute main\" | sudo tee /etc/apt/sources.list.d/azure-cli.list"
|
||||
sh "sudo apt update"
|
||||
sh "sudo apt install -y azure-cli"
|
||||
}
|
||||
|
||||
14
README.md
14
README.md
@@ -4,6 +4,7 @@
|
||||
- [Architectures](#architectures)
|
||||
- [Guest OS](#guest-os)
|
||||
- [2. Getting Started](#2-getting-started)
|
||||
- [Preparation](#preparation)
|
||||
- [Install prerequisites](#install-prerequisites)
|
||||
- [Clone and build](#clone-and-build)
|
||||
- [Containerized builds and tests](#containerized-builds-and-tests)
|
||||
@@ -167,8 +168,7 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
||||
--disk path=focal-server-cloudimg-amd64.raw \
|
||||
--cpus boot=4 \
|
||||
--memory size=1024M \
|
||||
--net "tap=,mac=,ip=,mask=" \
|
||||
--rng
|
||||
--net "tap=,mac=,ip=,mask="
|
||||
$ popd
|
||||
```
|
||||
|
||||
@@ -186,12 +186,12 @@ To build the kernel:
|
||||
|
||||
# Clone the Cloud Hypervisor Linux branch
|
||||
$ pushd $CLOUDH
|
||||
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-5.14 linux-cloud-hypervisor
|
||||
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-5.15.12 linux-cloud-hypervisor
|
||||
$ pushd linux-cloud-hypervisor
|
||||
|
||||
# Use the cloud-hypervisor kernel config to build your kernel
|
||||
$ cp $CLOUDH/cloud-hypervisor/resources/linux-config-x86_64 .config
|
||||
$ make bzImage -j `nproc`
|
||||
$ KCFLAGS="-Wa,-mx86-used-note=no" make bzImage -j `nproc`
|
||||
$ popd
|
||||
```
|
||||
|
||||
@@ -222,8 +222,7 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
||||
--cmdline "console=hvc0 root=/dev/vda1 rw" \
|
||||
--cpus boot=4 \
|
||||
--memory size=1024M \
|
||||
--net "tap=,mac=,ip=,mask=" \
|
||||
--rng
|
||||
--net "tap=,mac=,ip=,mask="
|
||||
```
|
||||
|
||||
The above example use the `virtio-console` device as the guest console, and this
|
||||
@@ -242,8 +241,7 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
||||
--cmdline "console=ttyS0 root=/dev/vda1 rw" \
|
||||
--cpus boot=4 \
|
||||
--memory size=1024M \
|
||||
--net "tap=,mac=,ip=,mask=" \
|
||||
--rng
|
||||
--net "tap=,mac=,ip=,mask="
|
||||
```
|
||||
|
||||
# 3. Status
|
||||
|
||||
@@ -5,4 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
vm-memory = "0.6.0"
|
||||
vm-memory = "0.7.0"
|
||||
|
||||
@@ -1392,13 +1392,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_pkg_length() {
|
||||
assert_eq!(create_pkg_length(&[0u8; 62].to_vec(), true), vec![63]);
|
||||
assert_eq!(create_pkg_length(&[0u8; 62], true), vec![63]);
|
||||
assert_eq!(
|
||||
create_pkg_length(&[0u8; 64].to_vec(), true),
|
||||
create_pkg_length(&[0u8; 64], true),
|
||||
vec![1 << 6 | (66 & 0xf), 66 >> 4]
|
||||
);
|
||||
assert_eq!(
|
||||
create_pkg_length(&[0u8; 4096].to_vec(), true),
|
||||
create_pkg_length(&[0u8; 4096], true),
|
||||
vec![
|
||||
2 << 6 | (4099 & 0xf) as u8,
|
||||
(4099 >> 4) as u8,
|
||||
|
||||
@@ -11,18 +11,18 @@ tdx = []
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { path = "../acpi_tables", optional = true }
|
||||
anyhow = "1.0.51"
|
||||
anyhow = "1.0.52"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
linux-loader = { version = "0.4.0", features = ["elf", "bzimage", "pe"] }
|
||||
log = "0.4.14"
|
||||
serde = { version = "1.0.130", features = ["rc"] }
|
||||
serde_derive = "1.0.130"
|
||||
serde = { version = "1.0.133", features = ["rc"] }
|
||||
serde_derive = "1.0.133"
|
||||
thiserror = "1.0.30"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the THIRD-PARTY file.
|
||||
|
||||
use crate::NumaNodes;
|
||||
use crate::{NumaNodes, PciSpaceInfo};
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
@@ -22,7 +22,7 @@ use super::get_fdt_addr;
|
||||
use super::gic::GicDevice;
|
||||
use super::layout::{
|
||||
IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START,
|
||||
PCI_HIGH_BASE, PCI_MMCONFIG_SIZE, PCI_MMCONFIG_START,
|
||||
PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
|
||||
};
|
||||
use vm_fdt::{FdtWriter, FdtWriterResult};
|
||||
use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryRegion};
|
||||
@@ -88,7 +88,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
|
||||
device_info: &HashMap<(DeviceType, String), T, S>,
|
||||
gic_device: &dyn GicDevice,
|
||||
initrd: &Option<InitramfsConfig>,
|
||||
pci_space_address: &(u64, u64),
|
||||
pci_space_info: &[PciSpaceInfo],
|
||||
numa_nodes: &NumaNodes,
|
||||
virtio_iommu_bdf: Option<u32>,
|
||||
) -> FdtWriterResult<Vec<u8>> {
|
||||
@@ -117,12 +117,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
|
||||
create_clock_node(&mut fdt)?;
|
||||
create_psci_node(&mut fdt)?;
|
||||
create_devices_node(&mut fdt, device_info)?;
|
||||
create_pci_nodes(
|
||||
&mut fdt,
|
||||
pci_space_address.0,
|
||||
pci_space_address.1,
|
||||
virtio_iommu_bdf,
|
||||
)?;
|
||||
create_pci_nodes(&mut fdt, pci_space_info, virtio_iommu_bdf)?;
|
||||
if numa_nodes.len() > 1 {
|
||||
create_distance_map_node(&mut fdt, numa_nodes)?;
|
||||
}
|
||||
@@ -547,108 +542,145 @@ fn create_devices_node<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Buil
|
||||
|
||||
fn create_pci_nodes(
|
||||
fdt: &mut FdtWriter,
|
||||
pci_device_base: u64,
|
||||
pci_device_size: u64,
|
||||
pci_device_info: &[PciSpaceInfo],
|
||||
virtio_iommu_bdf: Option<u32>,
|
||||
) -> FdtWriterResult<()> {
|
||||
// Add node for PCIe controller.
|
||||
// See Documentation/devicetree/bindings/pci/host-generic-pci.txt in the kernel
|
||||
// and https://elinux.org/Device_Tree_Usage.
|
||||
// In multiple PCI segments setup, each PCI segment needs a PCI node.
|
||||
for pci_device_info_elem in pci_device_info.iter() {
|
||||
// EDK2 requires the PCIe high space above 4G address.
|
||||
// The actual space in CLH follows the RAM. If the RAM space is small, the PCIe high space
|
||||
// could fall bellow 4G.
|
||||
// Here we cut off PCI device space below 8G in FDT to workaround the EDK2 check.
|
||||
// But the address written in ACPI is not impacted.
|
||||
let (pci_device_base_64bit, pci_device_size_64bit) = if cfg!(feature = "acpi")
|
||||
&& (pci_device_info_elem.pci_device_space_start < PCI_HIGH_BASE)
|
||||
{
|
||||
(
|
||||
PCI_HIGH_BASE,
|
||||
pci_device_info_elem.pci_device_space_size
|
||||
- (PCI_HIGH_BASE - pci_device_info_elem.pci_device_space_start),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
pci_device_info_elem.pci_device_space_start,
|
||||
pci_device_info_elem.pci_device_space_size,
|
||||
)
|
||||
};
|
||||
// There is no specific requirement of the 32bit MMIO range, and
|
||||
// therefore at least we can make these ranges 4K aligned.
|
||||
let pci_device_size_32bit: u64 =
|
||||
MEM_32BIT_DEVICES_SIZE / ((1 << 12) * pci_device_info.len() as u64) * (1 << 12);
|
||||
let pci_device_base_32bit: u64 = MEM_32BIT_DEVICES_START.0
|
||||
+ pci_device_size_32bit * pci_device_info_elem.pci_segment_id as u64;
|
||||
|
||||
// EDK2 requires the PCIe high space above 4G address.
|
||||
// The actual space in CLH follows the RAM. If the RAM space is small, the PCIe high space
|
||||
// could fall bellow 4G.
|
||||
// Here we put it above 512G in FDT to workaround the EDK2 check.
|
||||
// But the address written in ACPI is not impacted.
|
||||
let pci_device_base_64bit: u64 = if cfg!(feature = "acpi") {
|
||||
pci_device_base + PCI_HIGH_BASE
|
||||
} else {
|
||||
pci_device_base
|
||||
};
|
||||
let pci_device_size_64bit: u64 = if cfg!(feature = "acpi") {
|
||||
pci_device_size - PCI_HIGH_BASE
|
||||
} else {
|
||||
pci_device_size
|
||||
};
|
||||
|
||||
let ranges = [
|
||||
// io addresses
|
||||
0x1000000,
|
||||
0_u32,
|
||||
0_u32,
|
||||
(MEM_PCI_IO_START.0 >> 32) as u32,
|
||||
MEM_PCI_IO_START.0 as u32,
|
||||
(MEM_PCI_IO_SIZE >> 32) as u32,
|
||||
MEM_PCI_IO_SIZE as u32,
|
||||
// mmio addresses
|
||||
0x2000000, // (ss = 10: 32-bit memory space)
|
||||
(MEM_32BIT_DEVICES_START.0 >> 32) as u32, // PCI address
|
||||
MEM_32BIT_DEVICES_START.0 as u32,
|
||||
(MEM_32BIT_DEVICES_START.0 >> 32) as u32, // CPU address
|
||||
MEM_32BIT_DEVICES_START.0 as u32,
|
||||
(MEM_32BIT_DEVICES_SIZE >> 32) as u32, // size
|
||||
MEM_32BIT_DEVICES_SIZE as u32,
|
||||
// device addresses
|
||||
0x3000000, // (ss = 11: 64-bit memory space)
|
||||
(pci_device_base_64bit >> 32) as u32, // PCI address
|
||||
pci_device_base_64bit as u32,
|
||||
(pci_device_base_64bit >> 32) as u32, // CPU address
|
||||
pci_device_base_64bit as u32,
|
||||
(pci_device_size_64bit >> 32) as u32, // size
|
||||
pci_device_size_64bit as u32,
|
||||
];
|
||||
let bus_range = [0, 0]; // Only bus 0
|
||||
let reg = [PCI_MMCONFIG_START.0, PCI_MMCONFIG_SIZE];
|
||||
|
||||
let pci_node = fdt.begin_node("pci")?;
|
||||
fdt.property_string("compatible", "pci-host-ecam-generic")?;
|
||||
fdt.property_string("device_type", "pci")?;
|
||||
fdt.property_array_u32("ranges", &ranges)?;
|
||||
fdt.property_array_u32("bus-range", &bus_range)?;
|
||||
fdt.property_u32("#address-cells", 3)?;
|
||||
fdt.property_u32("#size-cells", 2)?;
|
||||
fdt.property_array_u64("reg", ®)?;
|
||||
fdt.property_u32("#interrupt-cells", 1)?;
|
||||
fdt.property_null("interrupt-map")?;
|
||||
fdt.property_null("interrupt-map-mask")?;
|
||||
fdt.property_null("dma-coherent")?;
|
||||
fdt.property_u32("msi-parent", MSI_PHANDLE)?;
|
||||
|
||||
if let Some(virtio_iommu_bdf) = virtio_iommu_bdf {
|
||||
// See kernel document Documentation/devicetree/bindings/pci/pci-iommu.txt
|
||||
// for 'iommu-map' attribute setting.
|
||||
let iommu_map = [
|
||||
let ranges = [
|
||||
// io addresses. Since AArch64 will not use IO address,
|
||||
// we can set the same IO address range for every segment.
|
||||
0x1000000,
|
||||
0_u32,
|
||||
VIRTIO_IOMMU_PHANDLE,
|
||||
0_u32,
|
||||
virtio_iommu_bdf,
|
||||
virtio_iommu_bdf + 1,
|
||||
VIRTIO_IOMMU_PHANDLE,
|
||||
virtio_iommu_bdf + 1,
|
||||
0xffff - virtio_iommu_bdf,
|
||||
(MEM_PCI_IO_START.0 >> 32) as u32,
|
||||
MEM_PCI_IO_START.0 as u32,
|
||||
(MEM_PCI_IO_SIZE >> 32) as u32,
|
||||
MEM_PCI_IO_SIZE as u32,
|
||||
// mmio addresses
|
||||
0x2000000, // (ss = 10: 32-bit memory space)
|
||||
(pci_device_base_32bit >> 32) as u32, // PCI address
|
||||
pci_device_base_32bit as u32,
|
||||
(pci_device_base_32bit >> 32) as u32, // CPU address
|
||||
pci_device_base_32bit as u32,
|
||||
(pci_device_size_32bit >> 32) as u32, // size
|
||||
pci_device_size_32bit as u32,
|
||||
// device addresses
|
||||
0x3000000, // (ss = 11: 64-bit memory space)
|
||||
(pci_device_base_64bit >> 32) as u32, // PCI address
|
||||
pci_device_base_64bit as u32,
|
||||
(pci_device_base_64bit >> 32) as u32, // CPU address
|
||||
pci_device_base_64bit as u32,
|
||||
(pci_device_size_64bit >> 32) as u32, // size
|
||||
pci_device_size_64bit as u32,
|
||||
];
|
||||
let bus_range = [0, 0]; // Only bus 0
|
||||
let reg = [
|
||||
pci_device_info_elem.mmio_config_address,
|
||||
PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
|
||||
];
|
||||
// See kernel document Documentation/devicetree/bindings/pci/pci-msi.txt
|
||||
let msi_map = [
|
||||
// rid-base: A single cell describing the first RID matched by the entry.
|
||||
0x0,
|
||||
// msi-controller: A single phandle to an MSI controller.
|
||||
MSI_PHANDLE,
|
||||
// msi-base: An msi-specifier describing the msi-specifier produced for the
|
||||
// first RID matched by the entry.
|
||||
(pci_device_info_elem.pci_segment_id as u32) << 8,
|
||||
// length: A single cell describing how many consecutive RIDs are matched
|
||||
// following the rid-base.
|
||||
0x100,
|
||||
];
|
||||
fdt.property_array_u32("iommu-map", &iommu_map)?;
|
||||
|
||||
// See kernel document Documentation/devicetree/bindings/virtio/iommu.txt
|
||||
// for virtio-iommu node settings.
|
||||
let virtio_iommu_node_name = format!("virtio_iommu@{:x}", virtio_iommu_bdf);
|
||||
let virtio_iommu_node = fdt.begin_node(&virtio_iommu_node_name)?;
|
||||
fdt.property_u32("#iommu-cells", 1)?;
|
||||
fdt.property_string("compatible", "virtio,pci-iommu")?;
|
||||
let pci_node_name = format!("pci@{:x}", pci_device_info_elem.mmio_config_address);
|
||||
let pci_node = fdt.begin_node(&pci_node_name)?;
|
||||
|
||||
// 'reg' is a five-cell address encoded as
|
||||
// (phys.hi phys.mid phys.lo size.hi size.lo). phys.hi should contain the
|
||||
// device's BDF as 0b00000000 bbbbbbbb dddddfff 00000000. The other cells
|
||||
// should be zero.
|
||||
let reg = [virtio_iommu_bdf << 8, 0_u32, 0_u32, 0_u32, 0_u32];
|
||||
fdt.property_array_u32("reg", ®)?;
|
||||
fdt.property_u32("phandle", VIRTIO_IOMMU_PHANDLE)?;
|
||||
fdt.property_string("compatible", "pci-host-ecam-generic")?;
|
||||
fdt.property_string("device_type", "pci")?;
|
||||
fdt.property_array_u32("ranges", &ranges)?;
|
||||
fdt.property_array_u32("bus-range", &bus_range)?;
|
||||
fdt.property_u32(
|
||||
"linux,pci-domain",
|
||||
pci_device_info_elem.pci_segment_id as u32,
|
||||
)?;
|
||||
fdt.property_u32("#address-cells", 3)?;
|
||||
fdt.property_u32("#size-cells", 2)?;
|
||||
fdt.property_array_u64("reg", ®)?;
|
||||
fdt.property_u32("#interrupt-cells", 1)?;
|
||||
fdt.property_null("interrupt-map")?;
|
||||
fdt.property_null("interrupt-map-mask")?;
|
||||
fdt.property_null("dma-coherent")?;
|
||||
fdt.property_array_u32("msi-map", &msi_map)?;
|
||||
fdt.property_u32("msi-parent", MSI_PHANDLE)?;
|
||||
|
||||
fdt.end_node(virtio_iommu_node)?;
|
||||
if pci_device_info_elem.pci_segment_id == 0 {
|
||||
if let Some(virtio_iommu_bdf) = virtio_iommu_bdf {
|
||||
// See kernel document Documentation/devicetree/bindings/pci/pci-iommu.txt
|
||||
// for 'iommu-map' attribute setting.
|
||||
let iommu_map = [
|
||||
0_u32,
|
||||
VIRTIO_IOMMU_PHANDLE,
|
||||
0_u32,
|
||||
virtio_iommu_bdf,
|
||||
virtio_iommu_bdf + 1,
|
||||
VIRTIO_IOMMU_PHANDLE,
|
||||
virtio_iommu_bdf + 1,
|
||||
0xffff - virtio_iommu_bdf,
|
||||
];
|
||||
fdt.property_array_u32("iommu-map", &iommu_map)?;
|
||||
|
||||
// See kernel document Documentation/devicetree/bindings/virtio/iommu.txt
|
||||
// for virtio-iommu node settings.
|
||||
let virtio_iommu_node_name = format!("virtio_iommu@{:x}", virtio_iommu_bdf);
|
||||
let virtio_iommu_node = fdt.begin_node(&virtio_iommu_node_name)?;
|
||||
fdt.property_u32("#iommu-cells", 1)?;
|
||||
fdt.property_string("compatible", "virtio,pci-iommu")?;
|
||||
|
||||
// 'reg' is a five-cell address encoded as
|
||||
// (phys.hi phys.mid phys.lo size.hi size.lo). phys.hi should contain the
|
||||
// device's BDF as 0b00000000 bbbbbbbb dddddfff 00000000. The other cells
|
||||
// should be zero.
|
||||
let reg = [virtio_iommu_bdf << 8, 0_u32, 0_u32, 0_u32, 0_u32];
|
||||
fdt.property_array_u32("reg", ®)?;
|
||||
fdt.property_u32("phandle", VIRTIO_IOMMU_PHANDLE)?;
|
||||
|
||||
fdt.end_node(virtio_iommu_node)?;
|
||||
}
|
||||
}
|
||||
|
||||
fdt.end_node(pci_node)?;
|
||||
}
|
||||
|
||||
fdt.end_node(pci_node)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ macro_rules! VGIC_DIST_REG {
|
||||
|
||||
// List with relevant distributor registers that we will be restoring.
|
||||
// Order is taken from qemu.
|
||||
static VGIC_DIST_REGS: &'static [DistReg] = &[
|
||||
static VGIC_DIST_REGS: &[DistReg] = &[
|
||||
VGIC_DIST_REG!(GICD_STATUSR, 0, 4),
|
||||
VGIC_DIST_REG!(GICD_ICENABLER, 1, 0),
|
||||
VGIC_DIST_REG!(GICD_ISENABLER, 1, 0),
|
||||
|
||||
@@ -124,12 +124,11 @@ pub mod kvm {
|
||||
its_device: &Arc<dyn hypervisor::Device>,
|
||||
save: bool,
|
||||
) -> crate::aarch64::gic::Result<()> {
|
||||
let attr: u64;
|
||||
if save {
|
||||
attr = u64::from(kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES);
|
||||
let attr = if save {
|
||||
u64::from(kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES)
|
||||
} else {
|
||||
attr = u64::from(kvm_bindings::KVM_DEV_ARM_ITS_RESTORE_TABLES);
|
||||
}
|
||||
u64::from(kvm_bindings::KVM_DEV_ARM_ITS_RESTORE_TABLES)
|
||||
};
|
||||
|
||||
let init_gic_attr = kvm_bindings::kvm_device_attr {
|
||||
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
|
||||
|
||||
@@ -59,7 +59,7 @@ SYS_ICC_AP1Rn_EL1!(SYS_ICC_AP1R1_EL1, 1);
|
||||
SYS_ICC_AP1Rn_EL1!(SYS_ICC_AP1R2_EL1, 2);
|
||||
SYS_ICC_AP1Rn_EL1!(SYS_ICC_AP1R3_EL1, 3);
|
||||
|
||||
static VGIC_ICC_REGS: &'static [u64] = &[
|
||||
static VGIC_ICC_REGS: &[u64] = &[
|
||||
SYS_ICC_SRE_EL1,
|
||||
SYS_ICC_CTLR_EL1,
|
||||
SYS_ICC_IGRPEN0_EL1,
|
||||
@@ -91,8 +91,7 @@ fn icc_attr_access(
|
||||
flags: 0,
|
||||
};
|
||||
if set {
|
||||
#[allow(clippy::unnecessary_mut_passed)]
|
||||
gic.set_device_attr(&mut gic_icc_attr)
|
||||
gic.set_device_attr(&gic_icc_attr)
|
||||
.map_err(Error::SetDeviceAttribute)?;
|
||||
} else {
|
||||
gic.get_device_attr(&mut gic_icc_attr)
|
||||
|
||||
@@ -61,7 +61,7 @@ macro_rules! VGIC_RDIST_REG {
|
||||
}
|
||||
|
||||
// List with relevant distributor registers that we will be restoring.
|
||||
static VGIC_RDIST_REGS: &'static [RdistReg] = &[
|
||||
static VGIC_RDIST_REGS: &[RdistReg] = &[
|
||||
VGIC_RDIST_REG!(GICR_STATUSR, 4),
|
||||
VGIC_RDIST_REG!(GICR_WAKER, 4),
|
||||
VGIC_RDIST_REG!(GICR_PROPBASER, 8),
|
||||
@@ -70,7 +70,7 @@ static VGIC_RDIST_REGS: &'static [RdistReg] = &[
|
||||
];
|
||||
|
||||
// List with relevant distributor registers that we will be restoring.
|
||||
static VGIC_SGI_REGS: &'static [RdistReg] = &[
|
||||
static VGIC_SGI_REGS: &[RdistReg] = &[
|
||||
VGIC_RDIST_REG!(GICR_IGROUPR0, 4),
|
||||
VGIC_RDIST_REG!(GICR_ICENABLER0, 4),
|
||||
VGIC_RDIST_REG!(GICR_ISENABLER0, 4),
|
||||
@@ -96,8 +96,7 @@ fn redist_attr_access(
|
||||
flags: 0,
|
||||
};
|
||||
if set {
|
||||
#[allow(clippy::unnecessary_mut_passed)]
|
||||
gic.set_device_attr(&mut gic_dist_attr)
|
||||
gic.set_device_attr(&gic_dist_attr)
|
||||
.map_err(Error::SetDeviceAttribute)?;
|
||||
} else {
|
||||
gic.get_device_attr(&mut gic_dist_attr)
|
||||
@@ -110,7 +109,7 @@ fn access_redists_aux(
|
||||
gic: &Arc<dyn hypervisor::Device>,
|
||||
gicr_typer: &[u64],
|
||||
state: &mut Vec<u32>,
|
||||
reg_list: &'static [RdistReg],
|
||||
reg_list: &[RdistReg],
|
||||
idx: &mut usize,
|
||||
set: bool,
|
||||
) -> Result<()> {
|
||||
|
||||
@@ -82,6 +82,8 @@ pub const MEM_32BIT_DEVICES_SIZE: u64 = 0x2000_0000;
|
||||
/// PCI MMCONFIG space (start: after the device space at 1 GiB, length: 256MiB)
|
||||
pub const PCI_MMCONFIG_START: GuestAddress = GuestAddress(0x3000_0000);
|
||||
pub const PCI_MMCONFIG_SIZE: u64 = 256 << 20;
|
||||
// One bus with potentially 256 devices (32 slots x 8 functions).
|
||||
pub const PCI_MMIO_CONFIG_SIZE_PER_SEGMENT: u64 = 4096 * 256;
|
||||
|
||||
/// Start of RAM on 64 bit ARM.
|
||||
pub const RAM_64BIT_START: u64 = 0x4000_0000;
|
||||
@@ -104,7 +106,7 @@ pub const RSDP_POINTER: GuestAddress = GuestAddress(ACPI_START);
|
||||
pub const KERNEL_START: u64 = ACPI_START + ACPI_MAX_SIZE as u64;
|
||||
|
||||
/// Pci high memory base
|
||||
pub const PCI_HIGH_BASE: u64 = 0x80_0000_0000_u64;
|
||||
pub const PCI_HIGH_BASE: u64 = 0x2_0000_0000_u64;
|
||||
|
||||
// As per virt/kvm/arm/vgic/vgic-kvm-device.c we need
|
||||
// the number of interrupts our GIC will support to be:
|
||||
|
||||
@@ -14,16 +14,14 @@ pub mod regs;
|
||||
pub mod uefi;
|
||||
|
||||
pub use self::fdt::DeviceInfoForFdt;
|
||||
use crate::{DeviceType, GuestMemoryMmap, NumaNodes, RegionType};
|
||||
use crate::{DeviceType, GuestMemoryMmap, NumaNodes, PciSpaceInfo, RegionType};
|
||||
use gic::GicDevice;
|
||||
use log::{log_enabled, Level};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
use vm_memory::{
|
||||
Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, GuestUsize,
|
||||
};
|
||||
use vm_memory::{Address, GuestAddress, GuestMemory, GuestUsize};
|
||||
|
||||
/// Errors thrown while configuring aarch64 system.
|
||||
#[derive(Debug)]
|
||||
@@ -66,16 +64,10 @@ pub fn configure_vcpu(
|
||||
fd: &Arc<dyn hypervisor::Vcpu>,
|
||||
id: u8,
|
||||
kernel_entry_point: Option<EntryPoint>,
|
||||
vm_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
) -> super::Result<u64> {
|
||||
if let Some(kernel_entry_point) = kernel_entry_point {
|
||||
regs::setup_regs(
|
||||
fd,
|
||||
id,
|
||||
kernel_entry_point.entry_addr.raw_value(),
|
||||
&vm_memory.memory(),
|
||||
)
|
||||
.map_err(Error::RegsConfiguration)?;
|
||||
regs::setup_regs(fd, id, kernel_entry_point.entry_addr.raw_value())
|
||||
.map_err(Error::RegsConfiguration)?;
|
||||
}
|
||||
|
||||
let mpidr = fd.read_mpidr().map_err(Error::VcpuRegMpidr)?;
|
||||
@@ -140,7 +132,7 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
|
||||
vcpu_topology: Option<(u8, u8, u8)>,
|
||||
device_info: &HashMap<(DeviceType, String), T, S>,
|
||||
initrd: &Option<super::InitramfsConfig>,
|
||||
pci_space_address: &(u64, u64),
|
||||
pci_space_info: &[PciSpaceInfo],
|
||||
virtio_iommu_bdf: Option<u32>,
|
||||
gic_device: &dyn GicDevice,
|
||||
numa_nodes: &NumaNodes,
|
||||
@@ -153,7 +145,7 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
|
||||
device_info,
|
||||
gic_device,
|
||||
initrd,
|
||||
pci_space_address,
|
||||
pci_space_info,
|
||||
numa_nodes,
|
||||
virtio_iommu_bdf,
|
||||
)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
// found in the THIRD-PARTY file.
|
||||
|
||||
use super::get_fdt_addr;
|
||||
use crate::GuestMemoryMmap;
|
||||
use hypervisor::kvm::kvm_bindings::{
|
||||
kvm_regs, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM_CORE, KVM_REG_SIZE_U64,
|
||||
};
|
||||
@@ -43,12 +42,7 @@ const PSTATE_FAULT_BITS_64: u64 = PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_
|
||||
/// * `cpu_id` - Index of current vcpu.
|
||||
/// * `boot_ip` - Starting instruction pointer.
|
||||
/// * `mem` - Reserved DRAM for current VM.
|
||||
pub fn setup_regs(
|
||||
vcpu: &Arc<dyn hypervisor::Vcpu>,
|
||||
cpu_id: u8,
|
||||
boot_ip: u64,
|
||||
_mem: &GuestMemoryMmap,
|
||||
) -> Result<()> {
|
||||
pub fn setup_regs(vcpu: &Arc<dyn hypervisor::Vcpu>, cpu_id: u8, boot_ip: u64) -> Result<()> {
|
||||
let kreg_off = offset__of!(kvm_regs, regs);
|
||||
|
||||
// Get the register index of the PSTATE (Processor State) register.
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
//! Implements platform specific functionality.
|
||||
//! Supported platforms: x86_64, aarch64.
|
||||
#![allow(clippy::transmute_ptr_to_ptr, clippy::redundant_static_lifetimes)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
@@ -162,6 +161,16 @@ pub struct MmioDeviceInfo {
|
||||
pub irq: u32,
|
||||
}
|
||||
|
||||
/// Structure to describe PCI space information
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub struct PciSpaceInfo {
|
||||
pub pci_segment_id: u16,
|
||||
pub mmio_config_address: u64,
|
||||
pub pci_device_space_start: u64,
|
||||
pub pci_device_space_size: u64,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
impl DeviceInfoForFdt for MmioDeviceInfo {
|
||||
fn addr(&self) -> u64 {
|
||||
|
||||
@@ -93,6 +93,16 @@ pub const MEM_32BIT_DEVICES_SIZE: u64 = 640 << 20;
|
||||
pub const PCI_MMCONFIG_START: GuestAddress =
|
||||
GuestAddress(MEM_32BIT_DEVICES_START.0 + MEM_32BIT_DEVICES_SIZE);
|
||||
pub const PCI_MMCONFIG_SIZE: u64 = 256 << 20;
|
||||
// One bus with potentially 256 devices (32 slots x 8 functions).
|
||||
pub const PCI_MMIO_CONFIG_SIZE_PER_SEGMENT: u64 = 4096 * 256;
|
||||
|
||||
// TSS is 3 pages after the PCI MMCONFIG space
|
||||
pub const KVM_TSS_START: GuestAddress = GuestAddress(PCI_MMCONFIG_START.0 + PCI_MMCONFIG_SIZE);
|
||||
pub const KVM_TSS_SIZE: u64 = (3 * 4) << 10;
|
||||
|
||||
// Identity map is a one page region after the TSS
|
||||
pub const KVM_IDENTITY_MAP_START: GuestAddress = GuestAddress(KVM_TSS_START.0 + KVM_TSS_SIZE);
|
||||
pub const KVM_IDENTITY_MAP_SIZE: u64 = 4 << 10;
|
||||
|
||||
// IOAPIC
|
||||
pub const IOAPIC_START: GuestAddress = GuestAddress(0xfec0_0000);
|
||||
@@ -101,9 +111,6 @@ pub const IOAPIC_SIZE: u64 = 0x20;
|
||||
// APIC
|
||||
pub const APIC_START: GuestAddress = GuestAddress(0xfee0_0000);
|
||||
|
||||
/// Address for the TSS setup.
|
||||
pub const KVM_TSS_ADDRESS: GuestAddress = GuestAddress(0xfffb_d000);
|
||||
|
||||
// == End of "32-bit reserved" range. ==
|
||||
|
||||
// ** 64-bit RAM start (start: 4GiB, length: varies) **
|
||||
|
||||
@@ -315,21 +315,12 @@ impl CpuidPatch {
|
||||
|
||||
for entry in entries.iter() {
|
||||
if entry.function == function && entry.index == index {
|
||||
let reg_val: u32;
|
||||
match reg {
|
||||
CpuidReg::EAX => {
|
||||
reg_val = entry.eax;
|
||||
}
|
||||
CpuidReg::EBX => {
|
||||
reg_val = entry.ebx;
|
||||
}
|
||||
CpuidReg::ECX => {
|
||||
reg_val = entry.ecx;
|
||||
}
|
||||
CpuidReg::EDX => {
|
||||
reg_val = entry.edx;
|
||||
}
|
||||
}
|
||||
let reg_val = match reg {
|
||||
CpuidReg::EAX => entry.eax,
|
||||
CpuidReg::EBX => entry.ebx,
|
||||
CpuidReg::ECX => entry.ecx,
|
||||
CpuidReg::EDX => entry.edx,
|
||||
};
|
||||
|
||||
return (reg_val & mask) == mask;
|
||||
}
|
||||
@@ -522,19 +513,14 @@ impl CpuidFeatureEntry {
|
||||
.enumerate()
|
||||
{
|
||||
let entry = &feature_entry_list[i];
|
||||
let entry_compatible;
|
||||
match entry.compatible_check {
|
||||
let entry_compatible = match entry.compatible_check {
|
||||
CpuidCompatibleCheck::BitwiseSubset => {
|
||||
let different_feature_bits = src_vm_feature ^ dest_vm_feature;
|
||||
let src_vm_feature_bits_only = different_feature_bits & src_vm_feature;
|
||||
entry_compatible = src_vm_feature_bits_only == 0;
|
||||
}
|
||||
CpuidCompatibleCheck::Equal => {
|
||||
entry_compatible = src_vm_feature == dest_vm_feature;
|
||||
}
|
||||
CpuidCompatibleCheck::NumNotGreater => {
|
||||
entry_compatible = src_vm_feature <= dest_vm_feature;
|
||||
src_vm_feature_bits_only == 0
|
||||
}
|
||||
CpuidCompatibleCheck::Equal => src_vm_feature == dest_vm_feature,
|
||||
CpuidCompatibleCheck::NumNotGreater => src_vm_feature <= dest_vm_feature,
|
||||
};
|
||||
if !entry_compatible {
|
||||
error!(
|
||||
|
||||
@@ -6,11 +6,10 @@ edition = "2018"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
io_uring = []
|
||||
|
||||
[dependencies]
|
||||
io-uring = "0.5.2"
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
log = "0.4.14"
|
||||
qcow = { path = "../qcow" }
|
||||
thiserror = "1.0.30"
|
||||
@@ -19,7 +18,7 @@ versionize_derive = "0.1.4"
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
|
||||
virtio-queue = { path = "../virtio-queue" }
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
|
||||
@@ -2,8 +2,13 @@
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
|
||||
use libc::{ioctl, S_IFBLK, S_IFMT};
|
||||
use std::convert::TryInto;
|
||||
use std::fs::File;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use thiserror::Error;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::{ioctl_expr, ioctl_io_nr, ioctl_ioc_nr};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum DiskFileError {
|
||||
@@ -15,11 +20,96 @@ pub enum DiskFileError {
|
||||
NewAsyncIo(#[source] std::io::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DiskTopology {
|
||||
pub logical_block_size: u64,
|
||||
pub physical_block_size: u64,
|
||||
pub minimum_io_size: u64,
|
||||
pub optimal_io_size: u64,
|
||||
}
|
||||
|
||||
impl Default for DiskTopology {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
logical_block_size: 512,
|
||||
physical_block_size: 512,
|
||||
minimum_io_size: 512,
|
||||
optimal_io_size: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ioctl_io_nr!(BLKSSZGET, 0x12, 104);
|
||||
ioctl_io_nr!(BLKPBSZGET, 0x12, 123);
|
||||
ioctl_io_nr!(BLKIOMIN, 0x12, 120);
|
||||
ioctl_io_nr!(BLKIOOPT, 0x12, 121);
|
||||
|
||||
enum BlockSize {
|
||||
LogicalBlock,
|
||||
PhysicalBlock,
|
||||
MinimumIo,
|
||||
OptimalIo,
|
||||
}
|
||||
|
||||
impl DiskTopology {
|
||||
fn is_block_device(f: &mut File) -> std::io::Result<bool> {
|
||||
let mut stat = std::mem::MaybeUninit::<libc::stat>::uninit();
|
||||
let ret = unsafe { libc::fstat(f.as_raw_fd(), stat.as_mut_ptr()) };
|
||||
if ret != 0 {
|
||||
return Err(std::io::Error::last_os_error());
|
||||
}
|
||||
|
||||
let is_block = unsafe { (*stat.as_ptr()).st_mode & S_IFMT == S_IFBLK };
|
||||
Ok(is_block)
|
||||
}
|
||||
|
||||
// libc::ioctl() takes different types on different architectures
|
||||
#[allow(clippy::useless_conversion)]
|
||||
fn query_block_size(f: &mut File, block_size_type: BlockSize) -> std::io::Result<u64> {
|
||||
let mut block_size = 0;
|
||||
let ret = unsafe {
|
||||
ioctl(
|
||||
f.as_raw_fd(),
|
||||
match block_size_type {
|
||||
BlockSize::LogicalBlock => BLKSSZGET(),
|
||||
BlockSize::PhysicalBlock => BLKPBSZGET(),
|
||||
BlockSize::MinimumIo => BLKIOMIN(),
|
||||
BlockSize::OptimalIo => BLKIOOPT(),
|
||||
}
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
&mut block_size,
|
||||
)
|
||||
};
|
||||
if ret != 0 {
|
||||
return Err(std::io::Error::last_os_error());
|
||||
};
|
||||
|
||||
Ok(block_size)
|
||||
}
|
||||
|
||||
pub fn probe(f: &mut File) -> std::io::Result<Self> {
|
||||
if !Self::is_block_device(f)? {
|
||||
return Ok(DiskTopology::default());
|
||||
}
|
||||
|
||||
Ok(DiskTopology {
|
||||
logical_block_size: Self::query_block_size(f, BlockSize::LogicalBlock)?,
|
||||
physical_block_size: Self::query_block_size(f, BlockSize::PhysicalBlock)?,
|
||||
minimum_io_size: Self::query_block_size(f, BlockSize::MinimumIo)?,
|
||||
optimal_io_size: Self::query_block_size(f, BlockSize::OptimalIo)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub type DiskFileResult<T> = std::result::Result<T, DiskFileError>;
|
||||
|
||||
pub trait DiskFile: Send + Sync {
|
||||
fn size(&mut self) -> DiskFileResult<u64>;
|
||||
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>>;
|
||||
fn topology(&mut self) -> DiskTopology {
|
||||
DiskTopology::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
||||
@@ -20,9 +20,9 @@ pub mod raw_sync;
|
||||
pub mod vhd;
|
||||
pub mod vhdx_sync;
|
||||
|
||||
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult, DiskFileError, DiskFileResult};
|
||||
#[cfg(feature = "io_uring")]
|
||||
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult};
|
||||
use io_uring::{opcode, IoUring, Probe};
|
||||
use std::alloc::{alloc_zeroed, dealloc, Layout};
|
||||
use std::cmp;
|
||||
use std::convert::TryInto;
|
||||
use std::fs::File;
|
||||
@@ -30,14 +30,14 @@ use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
|
||||
use std::os::linux::fs::MetadataExt;
|
||||
use std::path::Path;
|
||||
use std::result;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::MutexGuard;
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use virtio_bindings::bindings::virtio_blk::*;
|
||||
use virtio_queue::DescriptorChain;
|
||||
use vm_memory::{
|
||||
bitmap::AtomicBitmap, bitmap::Bitmap, ByteValued, Bytes, GuestAddress, GuestMemory,
|
||||
GuestMemoryAtomic, GuestMemoryError,
|
||||
GuestMemoryError, GuestMemoryLoadGuard,
|
||||
};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
@@ -113,6 +113,8 @@ pub enum ExecuteError {
|
||||
AsyncRead(AsyncIoError),
|
||||
AsyncWrite(AsyncIoError),
|
||||
AsyncFlush(AsyncIoError),
|
||||
/// Failed allocating a temporary buffer.
|
||||
TemporaryBufferAllocation(io::Error),
|
||||
}
|
||||
|
||||
impl ExecuteError {
|
||||
@@ -129,6 +131,7 @@ impl ExecuteError {
|
||||
ExecuteError::AsyncRead(_) => VIRTIO_BLK_S_IOERR,
|
||||
ExecuteError::AsyncWrite(_) => VIRTIO_BLK_S_IOERR,
|
||||
ExecuteError::AsyncFlush(_) => VIRTIO_BLK_S_IOERR,
|
||||
ExecuteError::TemporaryBufferAllocation(_) => VIRTIO_BLK_S_IOERR,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,6 +169,14 @@ fn sector(mem: &GuestMemoryMmap, desc_addr: GuestAddress) -> result::Result<u64,
|
||||
mem.read_obj(addr).map_err(Error::GuestMemory)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AlignedOperation {
|
||||
origin_ptr: u64,
|
||||
aligned_ptr: u64,
|
||||
size: usize,
|
||||
layout: Layout,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Request {
|
||||
pub request_type: RequestType,
|
||||
@@ -173,11 +184,12 @@ pub struct Request {
|
||||
pub data_descriptors: Vec<(GuestAddress, u32)>,
|
||||
pub status_addr: GuestAddress,
|
||||
pub writeback: bool,
|
||||
pub aligned_operations: Vec<AlignedOperation>,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
pub fn parse(
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap>>,
|
||||
) -> result::Result<Request, Error> {
|
||||
let hdr_desc = desc_chain
|
||||
.next()
|
||||
@@ -198,6 +210,7 @@ impl Request {
|
||||
data_descriptors: Vec::new(),
|
||||
status_addr: GuestAddress(0),
|
||||
writeback: true,
|
||||
aligned_operations: Vec::new(),
|
||||
};
|
||||
|
||||
let status_desc;
|
||||
@@ -253,13 +266,12 @@ impl Request {
|
||||
Ok(req)
|
||||
}
|
||||
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub fn execute<T: Seek + Read + Write>(
|
||||
&self,
|
||||
disk: &mut T,
|
||||
disk_nsectors: u64,
|
||||
mem: &GuestMemoryMmap,
|
||||
disk_id: &Vec<u8>,
|
||||
disk_id: &[u8],
|
||||
) -> result::Result<u32, ExecuteError> {
|
||||
disk.seek(SeekFrom::Start(self.sector << SECTOR_SHIFT))
|
||||
.map_err(ExecuteError::Seek)?;
|
||||
@@ -294,7 +306,7 @@ impl Request {
|
||||
if (*data_len as usize) < disk_id.len() {
|
||||
return Err(ExecuteError::BadRequest(Error::InvalidOffset));
|
||||
}
|
||||
mem.write_slice(disk_id.as_slice(), *data_addr)
|
||||
mem.write_slice(disk_id, *data_addr)
|
||||
.map_err(ExecuteError::Write)?;
|
||||
}
|
||||
RequestType::Unsupported(t) => return Err(ExecuteError::Unsupported(t)),
|
||||
@@ -304,7 +316,7 @@ impl Request {
|
||||
}
|
||||
|
||||
pub fn execute_async(
|
||||
&self,
|
||||
&mut self,
|
||||
mem: &GuestMemoryMmap,
|
||||
disk_nsectors: u64,
|
||||
disk_image: &mut dyn AsyncIo,
|
||||
@@ -317,6 +329,9 @@ impl Request {
|
||||
|
||||
let mut iovecs = Vec::new();
|
||||
for (data_addr, data_len) in &self.data_descriptors {
|
||||
if *data_len == 0 {
|
||||
continue;
|
||||
}
|
||||
let mut top: u64 = u64::from(*data_len) / SECTOR_SIZE;
|
||||
if u64::from(*data_len) % SECTOR_SIZE != 0 {
|
||||
top += 1;
|
||||
@@ -328,12 +343,52 @@ impl Request {
|
||||
return Err(ExecuteError::BadRequest(Error::InvalidOffset));
|
||||
}
|
||||
|
||||
let buf = mem
|
||||
let origin_ptr = mem
|
||||
.get_slice(*data_addr, *data_len as usize)
|
||||
.map_err(ExecuteError::GetHostAddress)?
|
||||
.as_ptr();
|
||||
|
||||
// Verify the buffer alignment.
|
||||
// In case it's not properly aligned, an intermediate buffer is
|
||||
// created with the correct alignment, and a copy from/to the
|
||||
// origin buffer is performed, depending on the type of operation.
|
||||
let iov_base = if (origin_ptr as u64) % SECTOR_SIZE != 0 {
|
||||
let layout =
|
||||
Layout::from_size_align(*data_len as usize, SECTOR_SIZE as usize).unwrap();
|
||||
// Safe because layout has non-zero size
|
||||
let aligned_ptr = unsafe { alloc_zeroed(layout) };
|
||||
if aligned_ptr.is_null() {
|
||||
return Err(ExecuteError::TemporaryBufferAllocation(
|
||||
io::Error::last_os_error(),
|
||||
));
|
||||
}
|
||||
|
||||
// We need to perform the copy beforehand in case we're writing
|
||||
// data out.
|
||||
if request_type == RequestType::Out {
|
||||
// Safe because destination buffer has been allocated with
|
||||
// the proper size.
|
||||
unsafe {
|
||||
std::ptr::copy(origin_ptr as *const u8, aligned_ptr, *data_len as usize)
|
||||
};
|
||||
}
|
||||
|
||||
// Store both origin and aligned pointers for complete_async()
|
||||
// to process them.
|
||||
self.aligned_operations.push(AlignedOperation {
|
||||
origin_ptr: origin_ptr as u64,
|
||||
aligned_ptr: aligned_ptr as u64,
|
||||
size: *data_len as usize,
|
||||
layout,
|
||||
});
|
||||
|
||||
aligned_ptr as *mut libc::c_void
|
||||
} else {
|
||||
origin_ptr as *mut libc::c_void
|
||||
};
|
||||
|
||||
let iovec = libc::iovec {
|
||||
iov_base: buf as *mut libc::c_void,
|
||||
iov_base,
|
||||
iov_len: *data_len as libc::size_t,
|
||||
};
|
||||
iovecs.push(iovec);
|
||||
@@ -381,6 +436,36 @@ impl Request {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn complete_async(&mut self) -> result::Result<(), Error> {
|
||||
for aligned_operation in self.aligned_operations.drain(..) {
|
||||
// We need to perform the copy after the data has been read inside
|
||||
// the aligned buffer in case we're reading data in.
|
||||
if self.request_type == RequestType::In {
|
||||
// Safe because origin buffer has been allocated with the
|
||||
// proper size.
|
||||
unsafe {
|
||||
std::ptr::copy(
|
||||
aligned_operation.aligned_ptr as *const u8,
|
||||
aligned_operation.origin_ptr as *mut u8,
|
||||
aligned_operation.size,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
// Free the temporary aligned buffer.
|
||||
// Safe because aligned_ptr was allocated by alloc_zeroed with the same
|
||||
// layout
|
||||
unsafe {
|
||||
dealloc(
|
||||
aligned_operation.aligned_ptr as *mut u8,
|
||||
aligned_operation.layout,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_writeback(&mut self, writeback: bool) {
|
||||
self.writeback = writeback
|
||||
}
|
||||
@@ -423,7 +508,6 @@ unsafe impl ByteValued for VirtioBlockGeometry {}
|
||||
|
||||
/// Check if io_uring for block device can be used on the current system, as
|
||||
/// it correctly supports the expected io_uring features.
|
||||
#[cfg(feature = "io_uring")]
|
||||
pub fn block_io_uring_is_supported() -> bool {
|
||||
let error_msg = "io_uring not supported:";
|
||||
|
||||
@@ -471,119 +555,98 @@ pub fn block_io_uring_is_supported() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "io_uring"))]
|
||||
pub fn block_io_uring_is_supported() -> bool {
|
||||
false
|
||||
}
|
||||
pub trait AsyncAdaptor<F>
|
||||
where
|
||||
F: Read + Write + Seek,
|
||||
{
|
||||
fn read_vectored_sync(
|
||||
&mut self,
|
||||
offset: libc::off_t,
|
||||
iovecs: Vec<libc::iovec>,
|
||||
user_data: u64,
|
||||
eventfd: &EventFd,
|
||||
completion_list: &mut Vec<(u64, i32)>,
|
||||
) -> AsyncIoResult<()> {
|
||||
// Convert libc::iovec into IoSliceMut
|
||||
let mut slices = Vec::new();
|
||||
for iovec in iovecs.iter() {
|
||||
slices.push(IoSliceMut::new(unsafe { std::mem::transmute(*iovec) }));
|
||||
}
|
||||
|
||||
pub fn disk_size(file: &mut dyn Seek, semaphore: &mut Arc<Mutex<()>>) -> DiskFileResult<u64> {
|
||||
// Take the semaphore to ensure other threads are not interacting with
|
||||
// the underlying file.
|
||||
let _lock = semaphore.lock().unwrap();
|
||||
let result = {
|
||||
let mut file = self.file();
|
||||
|
||||
Ok(file.seek(SeekFrom::End(0)).map_err(DiskFileError::Size)? as u64)
|
||||
}
|
||||
// Move the cursor to the right offset
|
||||
file.seek(SeekFrom::Start(offset as u64))
|
||||
.map_err(AsyncIoError::ReadVectored)?;
|
||||
|
||||
pub trait ReadSeekFile: Read + Seek {}
|
||||
impl<F: Read + Seek> ReadSeekFile for F {}
|
||||
// Read vectored
|
||||
file.read_vectored(slices.as_mut_slice())
|
||||
.map_err(AsyncIoError::ReadVectored)?
|
||||
};
|
||||
|
||||
pub fn read_vectored_sync(
|
||||
offset: libc::off_t,
|
||||
iovecs: Vec<libc::iovec>,
|
||||
user_data: u64,
|
||||
file: &mut dyn ReadSeekFile,
|
||||
eventfd: &EventFd,
|
||||
completion_list: &mut Vec<(u64, i32)>,
|
||||
semaphore: &mut Arc<Mutex<()>>,
|
||||
) -> AsyncIoResult<()> {
|
||||
// Convert libc::iovec into IoSliceMut
|
||||
let mut slices = Vec::new();
|
||||
for iovec in iovecs.iter() {
|
||||
slices.push(IoSliceMut::new(unsafe { std::mem::transmute(*iovec) }));
|
||||
}
|
||||
|
||||
let result = {
|
||||
// Take the semaphore to ensure other threads are not interacting
|
||||
// with the underlying file.
|
||||
let _lock = semaphore.lock().unwrap();
|
||||
|
||||
// Move the cursor to the right offset
|
||||
file.seek(SeekFrom::Start(offset as u64))
|
||||
.map_err(AsyncIoError::ReadVectored)?;
|
||||
|
||||
// Read vectored
|
||||
file.read_vectored(slices.as_mut_slice())
|
||||
.map_err(AsyncIoError::ReadVectored)?
|
||||
};
|
||||
|
||||
completion_list.push((user_data, result as i32));
|
||||
eventfd.write(1).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub trait WriteSeekFile: Write + Seek {}
|
||||
impl<F: Write + Seek> WriteSeekFile for F {}
|
||||
|
||||
pub fn write_vectored_sync(
|
||||
offset: libc::off_t,
|
||||
iovecs: Vec<libc::iovec>,
|
||||
user_data: u64,
|
||||
file: &mut dyn WriteSeekFile,
|
||||
eventfd: &EventFd,
|
||||
completion_list: &mut Vec<(u64, i32)>,
|
||||
semaphore: &mut Arc<Mutex<()>>,
|
||||
) -> AsyncIoResult<()> {
|
||||
// Convert libc::iovec into IoSlice
|
||||
let mut slices = Vec::new();
|
||||
for iovec in iovecs.iter() {
|
||||
slices.push(IoSlice::new(unsafe { std::mem::transmute(*iovec) }));
|
||||
}
|
||||
|
||||
let result = {
|
||||
// Take the semaphore to ensure other threads are not interacting
|
||||
// with the underlying file.
|
||||
let _lock = semaphore.lock().unwrap();
|
||||
|
||||
// Move the cursor to the right offset
|
||||
file.seek(SeekFrom::Start(offset as u64))
|
||||
.map_err(AsyncIoError::WriteVectored)?;
|
||||
|
||||
// Write vectored
|
||||
file.write_vectored(slices.as_slice())
|
||||
.map_err(AsyncIoError::WriteVectored)?
|
||||
};
|
||||
|
||||
completion_list.push((user_data, result as i32));
|
||||
eventfd.write(1).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn fsync_sync(
|
||||
user_data: Option<u64>,
|
||||
file: &mut dyn Write,
|
||||
eventfd: &EventFd,
|
||||
completion_list: &mut Vec<(u64, i32)>,
|
||||
semaphore: &mut Arc<Mutex<()>>,
|
||||
) -> AsyncIoResult<()> {
|
||||
let result: i32 = {
|
||||
// Take the semaphore to ensure other threads are not interacting
|
||||
// with the underlying file.
|
||||
let _lock = semaphore.lock().unwrap();
|
||||
|
||||
// Flush
|
||||
file.flush().map_err(AsyncIoError::Fsync)?;
|
||||
|
||||
0
|
||||
};
|
||||
|
||||
if let Some(user_data) = user_data {
|
||||
completion_list.push((user_data, result));
|
||||
completion_list.push((user_data, result as i32));
|
||||
eventfd.write(1).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
fn write_vectored_sync(
|
||||
&mut self,
|
||||
offset: libc::off_t,
|
||||
iovecs: Vec<libc::iovec>,
|
||||
user_data: u64,
|
||||
eventfd: &EventFd,
|
||||
completion_list: &mut Vec<(u64, i32)>,
|
||||
) -> AsyncIoResult<()> {
|
||||
// Convert libc::iovec into IoSlice
|
||||
let mut slices = Vec::new();
|
||||
for iovec in iovecs.iter() {
|
||||
slices.push(IoSlice::new(unsafe { std::mem::transmute(*iovec) }));
|
||||
}
|
||||
|
||||
let result = {
|
||||
let mut file = self.file();
|
||||
|
||||
// Move the cursor to the right offset
|
||||
file.seek(SeekFrom::Start(offset as u64))
|
||||
.map_err(AsyncIoError::WriteVectored)?;
|
||||
|
||||
// Write vectored
|
||||
file.write_vectored(slices.as_slice())
|
||||
.map_err(AsyncIoError::WriteVectored)?
|
||||
};
|
||||
|
||||
completion_list.push((user_data, result as i32));
|
||||
eventfd.write(1).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fsync_sync(
|
||||
&mut self,
|
||||
user_data: Option<u64>,
|
||||
eventfd: &EventFd,
|
||||
completion_list: &mut Vec<(u64, i32)>,
|
||||
) -> AsyncIoResult<()> {
|
||||
let result: i32 = {
|
||||
let mut file = self.file();
|
||||
|
||||
// Flush
|
||||
file.flush().map_err(AsyncIoError::Fsync)?;
|
||||
|
||||
0
|
||||
};
|
||||
|
||||
if let Some(user_data) = user_data {
|
||||
completion_list.push((user_data, result));
|
||||
eventfd.write(1).unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn file(&mut self) -> MutexGuard<F>;
|
||||
}
|
||||
|
||||
pub enum ImageType {
|
||||
|
||||
@@ -2,59 +2,61 @@
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
|
||||
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileResult};
|
||||
use crate::{disk_size, fsync_sync, read_vectored_sync, write_vectored_sync};
|
||||
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
|
||||
use crate::AsyncAdaptor;
|
||||
use qcow::{QcowFile, RawFile, Result as QcowResult};
|
||||
use std::fs::File;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::io::{Seek, SeekFrom};
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
pub struct QcowDiskSync {
|
||||
qcow_file: QcowFile,
|
||||
semaphore: Arc<Mutex<()>>,
|
||||
qcow_file: Arc<Mutex<QcowFile>>,
|
||||
}
|
||||
|
||||
impl QcowDiskSync {
|
||||
pub fn new(file: File, direct_io: bool) -> QcowResult<Self> {
|
||||
Ok(QcowDiskSync {
|
||||
qcow_file: QcowFile::from(RawFile::new(file, direct_io))?,
|
||||
semaphore: Arc::new(Mutex::new(())),
|
||||
qcow_file: Arc::new(Mutex::new(QcowFile::from(RawFile::new(file, direct_io))?)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl DiskFile for QcowDiskSync {
|
||||
fn size(&mut self) -> DiskFileResult<u64> {
|
||||
disk_size(&mut self.qcow_file, &mut self.semaphore)
|
||||
let mut file = self.qcow_file.lock().unwrap();
|
||||
|
||||
Ok(file.seek(SeekFrom::End(0)).map_err(DiskFileError::Size)? as u64)
|
||||
}
|
||||
|
||||
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||
Ok(Box::new(QcowSync::new(
|
||||
self.qcow_file.clone(),
|
||||
self.semaphore.clone(),
|
||||
)) as Box<dyn AsyncIo>)
|
||||
Ok(Box::new(QcowSync::new(self.qcow_file.clone())) as Box<dyn AsyncIo>)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct QcowSync {
|
||||
qcow_file: QcowFile,
|
||||
qcow_file: Arc<Mutex<QcowFile>>,
|
||||
eventfd: EventFd,
|
||||
completion_list: Vec<(u64, i32)>,
|
||||
semaphore: Arc<Mutex<()>>,
|
||||
}
|
||||
|
||||
impl QcowSync {
|
||||
pub fn new(qcow_file: QcowFile, semaphore: Arc<Mutex<()>>) -> Self {
|
||||
pub fn new(qcow_file: Arc<Mutex<QcowFile>>) -> Self {
|
||||
QcowSync {
|
||||
qcow_file,
|
||||
eventfd: EventFd::new(libc::EFD_NONBLOCK)
|
||||
.expect("Failed creating EventFd for QcowSync"),
|
||||
completion_list: Vec::new(),
|
||||
semaphore,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncAdaptor<QcowFile> for Arc<Mutex<QcowFile>> {
|
||||
fn file(&mut self) -> MutexGuard<QcowFile> {
|
||||
self.lock().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncIo for QcowSync {
|
||||
fn notifier(&self) -> &EventFd {
|
||||
&self.eventfd
|
||||
@@ -66,14 +68,12 @@ impl AsyncIo for QcowSync {
|
||||
iovecs: Vec<libc::iovec>,
|
||||
user_data: u64,
|
||||
) -> AsyncIoResult<()> {
|
||||
read_vectored_sync(
|
||||
self.qcow_file.read_vectored_sync(
|
||||
offset,
|
||||
iovecs,
|
||||
user_data,
|
||||
&mut self.qcow_file,
|
||||
&self.eventfd,
|
||||
&mut self.completion_list,
|
||||
&mut self.semaphore,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -83,25 +83,18 @@ impl AsyncIo for QcowSync {
|
||||
iovecs: Vec<libc::iovec>,
|
||||
user_data: u64,
|
||||
) -> AsyncIoResult<()> {
|
||||
write_vectored_sync(
|
||||
self.qcow_file.write_vectored_sync(
|
||||
offset,
|
||||
iovecs,
|
||||
user_data,
|
||||
&mut self.qcow_file,
|
||||
&self.eventfd,
|
||||
&mut self.completion_list,
|
||||
&mut self.semaphore,
|
||||
)
|
||||
}
|
||||
|
||||
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
|
||||
fsync_sync(
|
||||
user_data,
|
||||
&mut self.qcow_file,
|
||||
&self.eventfd,
|
||||
&mut self.completion_list,
|
||||
&mut self.semaphore,
|
||||
)
|
||||
self.qcow_file
|
||||
.fsync_sync(user_data, &self.eventfd, &mut self.completion_list)
|
||||
}
|
||||
|
||||
fn complete(&mut self) -> Vec<(u64, i32)> {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
|
||||
use crate::async_io::{
|
||||
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult,
|
||||
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult, DiskTopology,
|
||||
};
|
||||
use io_uring::{opcode, squeue, types, IoUring};
|
||||
use std::fs::File;
|
||||
@@ -35,6 +35,15 @@ impl DiskFile for RawFileDisk {
|
||||
.map_err(DiskFileError::NewAsyncIo)?,
|
||||
) as Box<dyn AsyncIo>)
|
||||
}
|
||||
|
||||
fn topology(&mut self) -> DiskTopology {
|
||||
if let Ok(topology) = DiskTopology::probe(&mut self.file) {
|
||||
topology
|
||||
} else {
|
||||
warn!("Unable to get device topology. Using default topology");
|
||||
DiskTopology::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RawFileAsync {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
|
||||
use crate::async_io::{
|
||||
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult,
|
||||
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult, DiskTopology,
|
||||
};
|
||||
use std::fs::File;
|
||||
use std::io::{Seek, SeekFrom};
|
||||
@@ -31,6 +31,15 @@ impl DiskFile for RawFileDiskSync {
|
||||
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||
Ok(Box::new(RawFileSync::new(self.file.as_raw_fd())) as Box<dyn AsyncIo>)
|
||||
}
|
||||
|
||||
fn topology(&mut self) -> DiskTopology {
|
||||
if let Ok(topology) = DiskTopology::probe(&mut self.file) {
|
||||
topology
|
||||
} else {
|
||||
warn!("Unable to get device topology. Using default topology");
|
||||
DiskTopology::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RawFileSync {
|
||||
|
||||
@@ -3,26 +3,20 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
|
||||
use crate::{fsync_sync, read_vectored_sync, write_vectored_sync};
|
||||
use crate::AsyncAdaptor;
|
||||
use std::fs::File;
|
||||
use std::ops::DerefMut;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
use vhdx::vhdx::{Result as VhdxResult, Vhdx};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
pub struct VhdxDiskSync {
|
||||
vhdx_file: Arc<Mutex<Vhdx>>,
|
||||
semaphore: Arc<Mutex<()>>,
|
||||
}
|
||||
|
||||
impl VhdxDiskSync {
|
||||
pub fn new(f: File) -> VhdxResult<Self> {
|
||||
let vhdx = Vhdx::new(f)?;
|
||||
let vhdx_file = Arc::new(Mutex::new(vhdx));
|
||||
|
||||
Ok(VhdxDiskSync {
|
||||
vhdx_file,
|
||||
semaphore: Arc::new(Mutex::new(())),
|
||||
vhdx_file: Arc::new(Mutex::new(Vhdx::new(f)?)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -33,10 +27,10 @@ impl DiskFile for VhdxDiskSync {
|
||||
}
|
||||
|
||||
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||
Ok(Box::new(
|
||||
VhdxSync::new(self.vhdx_file.clone(), self.semaphore.clone())
|
||||
.map_err(DiskFileError::NewAsyncIo)?,
|
||||
) as Box<dyn AsyncIo>)
|
||||
Ok(
|
||||
Box::new(VhdxSync::new(self.vhdx_file.clone()).map_err(DiskFileError::NewAsyncIo)?)
|
||||
as Box<dyn AsyncIo>,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,20 +38,24 @@ pub struct VhdxSync {
|
||||
vhdx_file: Arc<Mutex<Vhdx>>,
|
||||
eventfd: EventFd,
|
||||
completion_list: Vec<(u64, i32)>,
|
||||
semaphore: Arc<Mutex<()>>,
|
||||
}
|
||||
|
||||
impl VhdxSync {
|
||||
pub fn new(vhdx_file: Arc<Mutex<Vhdx>>, semaphore: Arc<Mutex<()>>) -> std::io::Result<Self> {
|
||||
pub fn new(vhdx_file: Arc<Mutex<Vhdx>>) -> std::io::Result<Self> {
|
||||
Ok(VhdxSync {
|
||||
vhdx_file,
|
||||
eventfd: EventFd::new(libc::EFD_NONBLOCK)?,
|
||||
completion_list: Vec::new(),
|
||||
semaphore,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncAdaptor<Vhdx> for Arc<Mutex<Vhdx>> {
|
||||
fn file(&mut self) -> MutexGuard<Vhdx> {
|
||||
self.lock().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncIo for VhdxSync {
|
||||
fn notifier(&self) -> &EventFd {
|
||||
&self.eventfd
|
||||
@@ -69,14 +67,12 @@ impl AsyncIo for VhdxSync {
|
||||
iovecs: Vec<libc::iovec>,
|
||||
user_data: u64,
|
||||
) -> AsyncIoResult<()> {
|
||||
read_vectored_sync(
|
||||
self.vhdx_file.read_vectored_sync(
|
||||
offset,
|
||||
iovecs,
|
||||
user_data,
|
||||
self.vhdx_file.lock().unwrap().deref_mut(),
|
||||
&self.eventfd,
|
||||
&mut self.completion_list,
|
||||
&mut self.semaphore,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -86,25 +82,18 @@ impl AsyncIo for VhdxSync {
|
||||
iovecs: Vec<libc::iovec>,
|
||||
user_data: u64,
|
||||
) -> AsyncIoResult<()> {
|
||||
write_vectored_sync(
|
||||
self.vhdx_file.write_vectored_sync(
|
||||
offset,
|
||||
iovecs,
|
||||
user_data,
|
||||
self.vhdx_file.lock().unwrap().deref_mut(),
|
||||
&self.eventfd,
|
||||
&mut self.completion_list,
|
||||
&mut self.semaphore,
|
||||
)
|
||||
}
|
||||
|
||||
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
|
||||
fsync_sync(
|
||||
user_data,
|
||||
self.vhdx_file.lock().unwrap().deref_mut(),
|
||||
&self.eventfd,
|
||||
&mut self.completion_list,
|
||||
&mut self.semaphore,
|
||||
)
|
||||
self.vhdx_file
|
||||
.fsync_sync(user_data, &self.eventfd, &mut self.completion_list)
|
||||
}
|
||||
|
||||
fn complete(&mut self) -> Vec<(u64, i32)> {
|
||||
|
||||
@@ -6,17 +6,17 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { path = "../acpi_tables", optional = true }
|
||||
anyhow = "1.0.51"
|
||||
anyhow = "1.0.52"
|
||||
arch = { path = "../arch" }
|
||||
bitflags = "1.3.2"
|
||||
byteorder = "1.4.3"
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
log = "0.4.14"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = "0.6.0"
|
||||
vm-memory = "0.7.0"
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
|
||||
@@ -291,14 +291,13 @@ impl Rtc {
|
||||
|
||||
impl BusDevice for Rtc {
|
||||
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
||||
let v;
|
||||
let mut read_ok = true;
|
||||
|
||||
if (AMBA_ID_LOW..AMBA_ID_HIGH).contains(&offset) {
|
||||
let v = if (AMBA_ID_LOW..AMBA_ID_HIGH).contains(&offset) {
|
||||
let index = ((offset - AMBA_ID_LOW) >> 2) as usize;
|
||||
v = u32::from(PL031_ID[index]);
|
||||
u32::from(PL031_ID[index])
|
||||
} else {
|
||||
v = match offset {
|
||||
match offset {
|
||||
RTCDR => self.get_time(),
|
||||
RTCMR => {
|
||||
// Even though we are not implementing RTC alarm we return the last value
|
||||
@@ -313,8 +312,8 @@ impl BusDevice for Rtc {
|
||||
read_ok = false;
|
||||
0
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
if read_ok && data.len() <= 4 {
|
||||
write_le_u32(data, v);
|
||||
} else {
|
||||
|
||||
@@ -294,19 +294,15 @@ impl Pl011 {
|
||||
|
||||
impl BusDevice for Pl011 {
|
||||
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
||||
let v;
|
||||
let mut read_ok = true;
|
||||
if (AMBA_ID_LOW..AMBA_ID_HIGH).contains(&(offset >> 2)) {
|
||||
let v = if (AMBA_ID_LOW..AMBA_ID_HIGH).contains(&(offset >> 2)) {
|
||||
let index = ((offset - 0xfe0) >> 2) as usize;
|
||||
v = u32::from(PL011_ID[index]);
|
||||
u32::from(PL011_ID[index])
|
||||
} else {
|
||||
v = match offset >> 2 {
|
||||
match offset >> 2 {
|
||||
UARTDR => {
|
||||
let c: u32;
|
||||
let r: u32;
|
||||
|
||||
self.flags &= !PL011_FLAG_RXFF;
|
||||
c = self.read_fifo.pop_front().unwrap_or_default().into();
|
||||
let c: u32 = self.read_fifo.pop_front().unwrap_or_default().into();
|
||||
if self.read_count > 0 {
|
||||
self.read_count -= 1;
|
||||
}
|
||||
@@ -317,8 +313,7 @@ impl BusDevice for Pl011 {
|
||||
self.int_level &= !PL011_INT_RX;
|
||||
}
|
||||
self.rsr = c >> 8;
|
||||
r = c;
|
||||
r
|
||||
c
|
||||
}
|
||||
UARTRSR_UARTECR => self.rsr,
|
||||
UARTFR => self.flags,
|
||||
@@ -337,7 +332,7 @@ impl BusDevice for Pl011 {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if read_ok && data.len() <= 4 {
|
||||
write_le_u32(data, v);
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
# How to build and test Cloud Hypervisor on AArch64
|
||||
|
||||
This document introduces how to build and test Cloud Hypervisor on AArch64
|
||||
servers. Currently Cloud Hypervisor cannot be tested on Raspberry PI. Because
|
||||
on AArch64, Cloud Hypervisor requires GICv3-ITS device for PCIe MSI interrupt
|
||||
handling. But GICv3-ITS has not been equipped on any Raspberry PI product so
|
||||
far.
|
||||
|
||||
Now Cloud Hypervisor supports 2 ways of booting on AArch64: UEFI booting and
|
||||
direct-kernel booting. The document covers both of the ways.
|
||||
This document introduces how to build and test Cloud Hypervisor on AArch64.
|
||||
Currently, Cloud Hypervisor supports 2 methods of booting on AArch64: UEFI
|
||||
booting and direct-kernel booting. The document covers both methods.
|
||||
|
||||
All the steps are based on Ubuntu. We use the Ubuntu cloud image for guest VM
|
||||
disk.
|
||||
|
||||
## Hardware requirements
|
||||
|
||||
- AArch64 servers (recommended) or development boards equipped with the GICv3
|
||||
interrupt controller.
|
||||
|
||||
- On development boards that have constrained RAM resources, if the creation of
|
||||
a VM consumes a large portion of the free memory on the host, it may be required
|
||||
to enable swap. For example, this was required on a board with 3 GB of RAM
|
||||
booting a 2 GB VM at a point in time when 2.8 GB were free. Without enabling
|
||||
swap the `cloud-hypervisor` process was terminated by the OOM killer. In this
|
||||
situation memory was allocated for the virtual machine using memfd while the
|
||||
page cache was filled, leading to a situation where the kernel could not even
|
||||
drop caches. Making a small section of swap available (observably, 1 to 15 MB),
|
||||
this situation can be resolved and the resulting memory footprint of
|
||||
`cloud-hypervisor` is as expected.
|
||||
|
||||
## Getting started
|
||||
|
||||
We create a folder to build and run Cloud Hypervisor at `$HOME/cloud-hypervisor`
|
||||
|
||||
@@ -89,7 +89,9 @@ feature is enabled by default.
|
||||
## Virtio devices
|
||||
|
||||
For all virtio devices listed below, only `virtio-pci` transport layer is
|
||||
supported.
|
||||
supported. Cloud Hypervisor supports multiple PCI segments, and users can
|
||||
append `,pci_segment=<PCI_segment_number>` to the device flag in the Cloud
|
||||
Hypervisor command line to assign devices to a specific PCI segment.
|
||||
|
||||
### virtio-block
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Cloud Hypervisor Hot Plug
|
||||
|
||||
Currently Cloud Hypervisor only supports hot plugging of CPU devices.
|
||||
Currently Cloud Hypervisor supports hot plugging of CPUs devices (x86 only), PCI devices and memory resizing.
|
||||
|
||||
## Kernel support
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@ support in Cloud Hypervisor:
|
||||
1. nested-vm migration - migrating between two nested VMs whose host VMs
|
||||
are running on the same machine.
|
||||
|
||||
## Local Migration
|
||||
## Local Migration (Suitable for Live Upgrade of VMM)
|
||||
Launch the source VM (on the host machine):
|
||||
```bash
|
||||
$ target/release/cloud-hypervisor
|
||||
--kernel ~/workloads/vmlinux \
|
||||
--disk path=~/workloads/focal.raw \
|
||||
--cpus boot=1 --memory size=1G \
|
||||
--cpus boot=1 --memory size=1G,shared=on \
|
||||
--cmdline "root=/dev/vda1 console=ttyS0" \
|
||||
--serial tty --console off --api-socket=/tmp/api1
|
||||
```
|
||||
@@ -31,7 +31,7 @@ $ target/release/ch-remote --api-socket=/tmp/api2 receive-migration unix:/tmp/so
|
||||
|
||||
Start to send migration for the source VM (on the host machine):
|
||||
```bash
|
||||
$ target/release/ch-remote --api-socket=/tmp/api1 send-migration unix:/tmp/sock
|
||||
$ target/release/ch-remote --api-socket=/tmp/api1 send-migration --local unix:/tmp/sock
|
||||
```
|
||||
|
||||
When the above commands completed, the source VM should be successfully
|
||||
|
||||
39
docs/uefi.md
39
docs/uefi.md
@@ -17,7 +17,7 @@ cd edk2
|
||||
. edksetup.sh
|
||||
git submodule update --init
|
||||
|
||||
echo "ACTIVE_PLATFORM=OvmfPkg/OvmfCh.dsc" >> Conf/target.txt
|
||||
echo "ACTIVE_PLATFORM=OvmfPkg/CloudHv/CloudHvX64.dsc" >> Conf/target.txt
|
||||
echo "TARGET_ARCH=X64" >> Conf/target.txt
|
||||
echo "TOOL_CHAIN_TAG=GCC5" >> Conf/target.txt
|
||||
|
||||
@@ -25,49 +25,16 @@ make -C ./BaseTools
|
||||
build
|
||||
```
|
||||
|
||||
After the successful build, the resulting firmware binaries are available under `Build/OvmfCh/DEBUG_GCC5/FV` underneath the edk2 checkout.
|
||||
After the successful build, the resulting firmware binaries are available under `Build/CloudHvX64/DEBUG_GCC5/FV` underneath the edk2 checkout.
|
||||
|
||||
## Using OVMF Binaries
|
||||
|
||||
Any UEFI capable image can be booted using the Cloud Hypervisor specific firmware. Windows guests under Cloud Hypervisor only support UEFI boot, therefore OVMF is mandatory there.
|
||||
|
||||
To make Cloud Hypervisor use UEFI boot, pass the `OVMF.fd` file path as an argument to the `--kernel` option. The firmware file will be opened in read only mode.
|
||||
To make Cloud Hypervisor use UEFI boot, pass the `CLOUDHV.fd` file path as an argument to the `--kernel` option. The firmware file will be opened in read only mode.
|
||||
|
||||
The same firmware can be used with Cloud Hypervisor or with QEMU. This is particularly useful if using QEMU for the preparation phase.
|
||||
|
||||
## Building UEFI Firmware with Compatibility Support Module (CSM)
|
||||
|
||||
CSM is a module that allows to boot legacy operating systems using the OVMF firmware. OVMF can embed a CSM build of SeaBIOS. To build the SeaBIOS with CSM support, add `CONFIG_CSM=y` to `.config` before the build. The outcome `out/Csm16.bin` is to be moved into `OvmfPkg/Csm/Csm16/Csm16.bin` before OVMF is built. Then, the OVMF build will have to be passed the `-D CSM_ENABLE` option in order to generate a legacy aware UEFI firmware. At the current stage, all the necessary patches are included in the Cloud Hypervisor specific [SeaBIOS branch](https://github.com/cloud-hypervisor/seabios/tree/ch). Taking into account the previous instructions, the modified command sequence to compile an OVMF binary with CSM support is the following one:
|
||||
|
||||
```shell
|
||||
sudo apt-get update
|
||||
sudo apt-get install uuid-dev nasm iasl build-essential python3-distutils git libncurses-dev
|
||||
|
||||
git clone https://github.com/cloud-hypervisor/seabios -b ch
|
||||
cd seabios
|
||||
make menuconfig
|
||||
# Enable `CONFIG_CSM` and `CONFIG_QEMU_HARDWARE`
|
||||
# Please make sure `python` is in your path
|
||||
make CONFIG_CSM=y CONFIG_QEMU_HARDWARE=y
|
||||
cd ..
|
||||
|
||||
git clone https://github.com/cloud-hypervisor/edk2 -b ch
|
||||
cd edk2
|
||||
. edksetup.sh
|
||||
git submodule update --init --recursive
|
||||
cp ../seabios/out/Csm16.bin OvmfPkg/Csm/Csm16/
|
||||
|
||||
echo "ACTIVE_PLATFORM=OvmfPkg/OvmfCh.dsc" >> Conf/target.txt
|
||||
echo "TARGET_ARCH=X64" >> Conf/target.txt
|
||||
echo "TOOL_CHAIN_TAG=GCC5" >> Conf/target.txt
|
||||
|
||||
make -C ./BaseTools
|
||||
build -DCSM_ENABLE
|
||||
|
||||
```
|
||||
|
||||
Please note, that the CSM support has currently only been tested with Linux guests. There are no plans to provide legacy support for other OSes (e.g. Windows).
|
||||
|
||||
# Links
|
||||
|
||||
- [OVMF wiki](https://github.com/tianocore/tianocore.github.io/wiki/OVMF)
|
||||
|
||||
@@ -67,7 +67,7 @@ The basic command to boot a Windows image. The configuration section should be c
|
||||
|
||||
```shell
|
||||
cloud-hypervisor \
|
||||
--kernel ./$OVMF_DIR/OVMF.fd \
|
||||
--kernel ./$OVMF_DIR/CLOUDHV.fd \
|
||||
--disk path=./$IMG_FILE \
|
||||
--cpus boot=1,kvm_hyperv=on \
|
||||
--memory size=4G \
|
||||
|
||||
@@ -5,7 +5,7 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.108"
|
||||
serde = { version = "1.0.130", features = ["rc"] }
|
||||
serde_derive = "1.0.130"
|
||||
serde_json = "1.0.72"
|
||||
libc = "0.2.112"
|
||||
serde = { version = "1.0.133", features = ["rc"] }
|
||||
serde_derive = "1.0.133"
|
||||
serde_json = "1.0.75"
|
||||
|
||||
202
fuzz/Cargo.lock
generated
202
fuzz/Cargo.lock
generated
@@ -9,20 +9,11 @@ dependencies = [
|
||||
"vm-memory",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.51"
|
||||
version = "1.0.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
|
||||
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
|
||||
|
||||
[[package]]
|
||||
name = "api_client"
|
||||
@@ -77,6 +68,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
@@ -131,23 +128,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
version = "3.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
"os_str_bytes",
|
||||
"strsim",
|
||||
"term_size",
|
||||
"termcolor",
|
||||
"terminal_size",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloud-hypervisor"
|
||||
version = "19.0.0"
|
||||
version = "20.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"api_client",
|
||||
@@ -187,9 +185,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crc32c"
|
||||
version = "0.6.0"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "210cdf933e6a81212bfabf90cd8762f471b5922e5f6b709547673ad8e04b9448"
|
||||
checksum = "ee6b9c9389584bcba988bd0836086789b7f87ad91892d6a83d5291dbb24524b5"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
@@ -248,9 +246,9 @@ checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@@ -258,10 +256,16 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7a30908dbce072eca83216eab939d2290080e00ca71611b96a09e5cdce5f3fa"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -295,6 +299,16 @@ dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-uring"
|
||||
version = "0.5.2"
|
||||
@@ -307,9 +321,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||
|
||||
[[package]]
|
||||
name = "kvm-bindings"
|
||||
@@ -324,8 +338,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kvm-ioctls"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97422ba48d7ffb66fd4d18130f72ab66f9bbbf791fb7a87b9291cdcfec437593"
|
||||
source = "git+https://github.com/rust-vmm/kvm-ioctls?branch=main#d22ef1f51852dfb055da38004e1a4fed81246f81"
|
||||
dependencies = [
|
||||
"kvm-bindings",
|
||||
"libc",
|
||||
@@ -340,9 +353,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.108"
|
||||
version = "0.2.112"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
|
||||
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
@@ -373,6 +386,12 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "micro_http"
|
||||
version = "0.1.0"
|
||||
@@ -411,14 +430,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||
|
||||
[[package]]
|
||||
name = "option_parser"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pci"
|
||||
version = "0.1.0"
|
||||
@@ -443,9 +471,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.32"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
||||
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
@@ -463,9 +491,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.10"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -492,18 +520,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.6"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568"
|
||||
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||
|
||||
[[package]]
|
||||
name = "seccompiler"
|
||||
@@ -516,30 +544,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
version = "1.0.133"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||
checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.130"
|
||||
version = "1.0.133"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||
checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -548,9 +567,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.72"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527"
|
||||
checksum = "c059c05b48c5c0067d4b4b2b4f0732dd65feb52daf7e0ea09cd87e7dadc1af79"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -559,9 +578,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.10"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
|
||||
checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
@@ -584,15 +603,15 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.82"
|
||||
version = "1.0.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
|
||||
checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -600,10 +619,19 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term_size"
|
||||
version = "0.3.2"
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
|
||||
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
@@ -611,12 +639,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
|
||||
dependencies = [
|
||||
"term_size",
|
||||
"unicode-width",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -639,12 +666,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
@@ -660,12 +681,6 @@ dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "versionize"
|
||||
version = "0.1.6"
|
||||
@@ -695,9 +710,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vfio-bindings"
|
||||
version = "0.2.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a21f546f2bda37f5a8cfb138c87f95b8e34d2d78d6a7a92ba3785f4e08604a7"
|
||||
checksum = "43449b404c488f70507dca193debd4bea361fe8089869b947adc19720e464bce"
|
||||
dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
@@ -748,9 +763,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vhost"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d23ddeb452fb4f837526c6298cc8a2f4948e5595b0328a3d61b5eebe51874d7"
|
||||
checksum = "3b56bf8f178fc500fe14505fca8b00dec76fc38f2304f461c8d9d7547982311d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@@ -837,9 +852,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#720e48e435b791ec6cb
|
||||
|
||||
[[package]]
|
||||
name = "vm-memory"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a8ebcb86ca457f9d6e14cf97009f679952eba42f0113de5db596e514cd0e43b"
|
||||
checksum = "339d4349c126fdcd87e034631d7274370cf19eb0e87b33166bcd956589fc72c5"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"libc",
|
||||
@@ -950,6 +965,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
||||
@@ -10,7 +10,7 @@ cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
block_util = { path = "../block_util" }
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
libfuzzer-sys = "0.4.2"
|
||||
qcow = { path = "../qcow" }
|
||||
seccompiler = "0.2.0"
|
||||
@@ -19,13 +19,14 @@ virtio-devices = { path = "../virtio-devices" }
|
||||
virtio-queue = { path = "../virtio-queue" }
|
||||
vmm-sys-util = "0.9.0"
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vm-memory = "0.6.0"
|
||||
vm-memory = "0.7.0"
|
||||
|
||||
[dependencies.cloud-hypervisor]
|
||||
path = ".."
|
||||
|
||||
[patch.crates-io]
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"] }
|
||||
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||
|
||||
# Prevent this from interfering with workspaces
|
||||
|
||||
@@ -79,7 +79,7 @@ fuzz_target!(|bytes| {
|
||||
|
||||
let mut q = Queue::<
|
||||
GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
QueueState<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
QueueState,
|
||||
>::new(guest_memory.clone(), QUEUE_SIZE);
|
||||
q.state.ready = true;
|
||||
q.state.size = QUEUE_SIZE / 2;
|
||||
|
||||
@@ -11,19 +11,19 @@ mshv = ["mshv-ioctls", "mshv-bindings"]
|
||||
tdx = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.51"
|
||||
anyhow = "1.0.52"
|
||||
epoll = "4.3.1"
|
||||
thiserror = "1.0.30"
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
log = "0.4.14"
|
||||
kvm-ioctls = { version = "0.11.0", optional = true }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-bindings = {git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
||||
serde = { version = "1.0.130", features = ["rc"] }
|
||||
serde_derive = "1.0.130"
|
||||
serde_json = "1.0.72"
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
serde = { version = "1.0.133", features = ["rc"] }
|
||||
serde_derive = "1.0.133"
|
||||
serde_json = "1.0.75"
|
||||
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
||||
|
||||
@@ -443,4 +443,9 @@ pub trait Vcpu: Send + Sync {
|
||||
/// Return suspend registers(explicit and intercept suspend registers)
|
||||
///
|
||||
fn get_suspend_regs(&self) -> Result<SuspendRegisters>;
|
||||
#[cfg(feature = "kvm")]
|
||||
///
|
||||
/// Set the "immediate_exit" state
|
||||
///
|
||||
fn set_immediate_exit(&self, exit: bool);
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@ use std::result;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, RwLock};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use vm_memory::Address;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
// x86_64 dependencies
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@@ -47,9 +45,7 @@ use kvm_bindings::{
|
||||
kvm_enable_cap, kvm_msr_entry, MsrList, KVM_CAP_HYPERV_SYNIC, KVM_CAP_SPLIT_IRQCHIP,
|
||||
};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use x86_64::{
|
||||
check_required_kvm_extensions, FpuState, SpecialRegisters, StandardRegisters, KVM_TSS_ADDRESS,
|
||||
};
|
||||
use x86_64::{check_required_kvm_extensions, FpuState, SpecialRegisters, StandardRegisters};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use x86_64::{
|
||||
CpuId, CpuIdEntry, ExtendedControlRegisters, LapicState, MsrEntries, VcpuKvmState as CpuState,
|
||||
@@ -139,6 +135,15 @@ pub struct KvmVm {
|
||||
/// vm.set/get().unwrap()
|
||||
///
|
||||
impl vm::Vm for KvmVm {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets the address of the one-page region in the VM's address space.
|
||||
///
|
||||
fn set_identity_map_address(&self, address: u64) -> vm::Result<()> {
|
||||
self.fd
|
||||
.set_identity_map_address(address)
|
||||
.map_err(|e| vm::HypervisorVmError::SetIdentityMapAddress(e.into()))
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets the address of the three-page region in the VM's address space.
|
||||
@@ -353,10 +358,6 @@ impl vm::Vm for KvmVm {
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn enable_split_irq(&self) -> vm::Result<()> {
|
||||
// Set TSS
|
||||
self.fd
|
||||
.set_tss_address(KVM_TSS_ADDRESS.raw_value() as usize)
|
||||
.map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?;
|
||||
// Create split irqchip
|
||||
// Only the local APIC is emulated in kernel, both PICs and IOAPIC
|
||||
// are not.
|
||||
@@ -1050,9 +1051,16 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
/// potential soft lockups when being resumed.
|
||||
///
|
||||
fn notify_guest_clock_paused(&self) -> cpu::Result<()> {
|
||||
self.fd
|
||||
.kvmclock_ctrl()
|
||||
.map_err(|e| cpu::HypervisorCpuError::NotifyGuestClockPaused(e.into()))
|
||||
if let Err(e) = self.fd.kvmclock_ctrl() {
|
||||
// Linux kernel returns -EINVAL if the PV clock isn't yet initialised
|
||||
// which could be because we're still in firmware or the guest doesn't
|
||||
// use KVM clock.
|
||||
if e.errno() != libc::EINVAL {
|
||||
return Err(cpu::HypervisorCpuError::NotifyGuestClockPaused(e.into()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
||||
fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> {
|
||||
@@ -1566,6 +1574,13 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
tdx_command(&self.fd.as_raw_fd(), TdxCommand::InitVcpu, 0, hob_address)
|
||||
.map_err(cpu::HypervisorCpuError::InitializeTdx)
|
||||
}
|
||||
|
||||
///
|
||||
/// Set the "immediate_exit" state
|
||||
///
|
||||
fn set_immediate_exit(&self, exit: bool) {
|
||||
self.fd.set_kvm_immediate_exit(exit.into());
|
||||
}
|
||||
}
|
||||
|
||||
/// Device struct for KVM
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB};
|
||||
use crate::kvm::{Cap, Kvm, KvmError, KvmResult};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use vm_memory::GuestAddress;
|
||||
|
||||
///
|
||||
/// Export generically-named wrappers of kvm-bindings for Unix-based platforms
|
||||
@@ -92,8 +91,6 @@ impl SegmentRegisterOps for SegmentRegister {
|
||||
}
|
||||
}
|
||||
|
||||
pub const KVM_TSS_ADDRESS: GuestAddress = GuestAddress(0xfffb_d000);
|
||||
|
||||
pub fn boot_msr_entries() -> MsrEntries {
|
||||
MsrEntries::from_entries(&[
|
||||
msr!(msr_index::MSR_IA32_SYSENTER_CS),
|
||||
@@ -127,6 +124,15 @@ pub fn check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()> {
|
||||
if !kvm.check_extension(Cap::SplitIrqchip) {
|
||||
return Err(KvmError::CapabilityMissing(Cap::SplitIrqchip));
|
||||
}
|
||||
if !kvm.check_extension(Cap::SetIdentityMapAddr) {
|
||||
return Err(KvmError::CapabilityMissing(Cap::SetIdentityMapAddr));
|
||||
}
|
||||
if !kvm.check_extension(Cap::SetTssAddr) {
|
||||
return Err(KvmError::CapabilityMissing(Cap::SetTssAddr));
|
||||
}
|
||||
if !kvm.check_extension(Cap::ImmediateExit) {
|
||||
return Err(KvmError::CapabilityMissing(Cap::ImmediateExit));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
|
||||
@@ -345,11 +345,11 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
|
||||
// SAFETY: access_info is valid, otherwise we won't be here
|
||||
assert!(
|
||||
!(unsafe { access_info.__bindgen_anon_1.string_op() } == 1),
|
||||
(unsafe { access_info.__bindgen_anon_1.string_op() } != 1),
|
||||
"String IN/OUT not supported"
|
||||
);
|
||||
assert!(
|
||||
!(unsafe { access_info.__bindgen_anon_1.rep_prefix() } == 1),
|
||||
(unsafe { access_info.__bindgen_anon_1.rep_prefix() } != 1),
|
||||
"Rep IN/OUT not supported"
|
||||
);
|
||||
|
||||
@@ -764,6 +764,13 @@ fn hv_state_init() -> Arc<RwLock<HvState>> {
|
||||
/// vm.set/get().unwrap()
|
||||
///
|
||||
impl vm::Vm for MshvVm {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets the address of the one-page region in the VM's address space.
|
||||
///
|
||||
fn set_identity_map_address(&self, _address: u64) -> vm::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets the address of the three-page region in the VM's address space.
|
||||
|
||||
@@ -58,6 +58,11 @@ pub enum HypervisorVmError {
|
||||
#[error("Failed to create Vcpu: {0}")]
|
||||
CreateVcpu(#[source] anyhow::Error),
|
||||
///
|
||||
/// Identity map address error
|
||||
///
|
||||
#[error("Failed to set identity map address: {0}")]
|
||||
SetIdentityMapAddress(#[source] anyhow::Error),
|
||||
///
|
||||
/// TSS address error
|
||||
///
|
||||
#[error("Failed to set TSS address: {0}")]
|
||||
@@ -217,6 +222,9 @@ pub type Result<T> = std::result::Result<T, HypervisorVmError>;
|
||||
/// This crate provides a hypervisor-agnostic interfaces for Vm
|
||||
///
|
||||
pub trait Vm: Send + Sync {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
/// Sets the address of the one-page region in the VM's address space.
|
||||
fn set_identity_map_address(&self, address: u64) -> Result<()>;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
/// Sets the address of the three-page region in the VM's address space.
|
||||
fn set_tss_address(&self, offset: usize) -> Result<()>;
|
||||
|
||||
@@ -7,20 +7,20 @@ edition = "2018"
|
||||
[dependencies]
|
||||
epoll = "4.3.1"
|
||||
getrandom = "0.2"
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
log = "0.4.14"
|
||||
net_gen = { path = "../net_gen" }
|
||||
rate_limiter = { path = "../rate_limiter" }
|
||||
serde = "1.0.130"
|
||||
serde = "1.0.133"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
virtio-bindings = "0.1.0"
|
||||
virtio-queue = { path = "../virtio-queue" }
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
pnet = "0.28.0"
|
||||
serde_json = "1.0.72"
|
||||
pnet = "0.29.0"
|
||||
serde_json = "1.0.75"
|
||||
|
||||
@@ -69,6 +69,14 @@ impl TxVirtio {
|
||||
iov_len: desc.len() as libc::size_t,
|
||||
};
|
||||
iovecs.push(iovec);
|
||||
} else {
|
||||
error!(
|
||||
"Invalid descriptor chain: address = 0x{:x} length = {} write_only = {}",
|
||||
desc.addr().0,
|
||||
desc.len(),
|
||||
desc.is_write_only()
|
||||
);
|
||||
return Err(NetQueuePairError::DescriptorChainInvalid);
|
||||
}
|
||||
next_desc = desc_chain.next();
|
||||
}
|
||||
@@ -189,6 +197,14 @@ impl RxVirtio {
|
||||
iov_len: desc.len() as libc::size_t,
|
||||
};
|
||||
iovecs.push(iovec);
|
||||
} else {
|
||||
error!(
|
||||
"Invalid descriptor chain: address = 0x{:x} length = {} write_only = {}",
|
||||
desc.addr().0,
|
||||
desc.len(),
|
||||
desc.is_write_only()
|
||||
);
|
||||
return Err(NetQueuePairError::DescriptorChainInvalid);
|
||||
}
|
||||
next_desc = desc_chain.next();
|
||||
}
|
||||
@@ -282,6 +298,8 @@ pub enum NetQueuePairError {
|
||||
QueueIteratorFailed(virtio_queue::Error),
|
||||
/// Descriptor chain is too short
|
||||
DescriptorChainTooShort,
|
||||
/// Descriptor chain does not contain valid descriptors
|
||||
DescriptorChainInvalid,
|
||||
/// Failed to determine if queue needed notification
|
||||
QueueNeedsNotification(virtio_queue::Error),
|
||||
/// Failed to enable notification on the queue
|
||||
|
||||
@@ -204,7 +204,6 @@ impl Tap {
|
||||
ifreq.ifr_ifru.ifru_addr = addr;
|
||||
|
||||
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
#[allow(clippy::cast_lossless)]
|
||||
let ret =
|
||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFADDR as c_ulong, &ifreq) };
|
||||
if ret < 0 {
|
||||
@@ -230,7 +229,6 @@ impl Tap {
|
||||
let mut ifreq = self.get_ifreq();
|
||||
|
||||
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
#[allow(clippy::cast_lossless)]
|
||||
let ret =
|
||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq) };
|
||||
if ret < 0 {
|
||||
@@ -245,7 +243,6 @@ impl Tap {
|
||||
}
|
||||
|
||||
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
#[allow(clippy::cast_lossless)]
|
||||
let ret =
|
||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFHWADDR as c_ulong, &ifreq) };
|
||||
if ret < 0 {
|
||||
@@ -262,7 +259,6 @@ impl Tap {
|
||||
let ifreq = self.get_ifreq();
|
||||
|
||||
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
#[allow(clippy::cast_lossless)]
|
||||
let ret =
|
||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq) };
|
||||
if ret < 0 {
|
||||
@@ -287,7 +283,6 @@ impl Tap {
|
||||
ifreq.ifr_ifru.ifru_addr = addr;
|
||||
|
||||
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
#[allow(clippy::cast_lossless)]
|
||||
let ret =
|
||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFNETMASK as c_ulong, &ifreq) };
|
||||
if ret < 0 {
|
||||
@@ -300,7 +295,6 @@ impl Tap {
|
||||
/// Set the offload flags for the tap interface.
|
||||
pub fn set_offload(&self, flags: c_uint) -> Result<()> {
|
||||
// ioctl is safe. Called with a valid tap fd, and we check the return.
|
||||
#[allow(clippy::cast_lossless)]
|
||||
let ret =
|
||||
unsafe { ioctl_with_val(&self.tap_file, net_gen::TUNSETOFFLOAD(), flags as c_ulong) };
|
||||
if ret < 0 {
|
||||
@@ -316,7 +310,6 @@ impl Tap {
|
||||
|
||||
let mut ifreq = self.get_ifreq();
|
||||
|
||||
#[allow(clippy::cast_lossless)]
|
||||
let ret =
|
||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFFLAGS as c_ulong, &ifreq) };
|
||||
if ret < 0 {
|
||||
@@ -336,7 +329,6 @@ impl Tap {
|
||||
(net_gen::net_device_flags_IFF_UP | net_gen::net_device_flags_IFF_RUNNING) as i16;
|
||||
|
||||
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
#[allow(clippy::cast_lossless)]
|
||||
let ret =
|
||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFFLAGS as c_ulong, &ifreq) };
|
||||
if ret < 0 {
|
||||
|
||||
@@ -10,22 +10,22 @@ kvm = ["vfio-ioctls/kvm"]
|
||||
mshv = ["vfio-ioctls/mshv"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.51"
|
||||
anyhow = "1.0.52"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio-ioctls", branch = "main", default-features = false }
|
||||
vfio_user = { path = "../vfio_user" }
|
||||
vmm-sys-util = "0.9.0"
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
log = "0.4.14"
|
||||
thiserror = "1.0.30"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = "0.6.0"
|
||||
vm-memory = "0.7.0"
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
|
||||
[dependencies.vfio-bindings]
|
||||
version = "0.2.0"
|
||||
version = "0.3.1"
|
||||
features = ["fam-wrappers"]
|
||||
|
||||
@@ -740,6 +740,11 @@ impl PciConfiguration {
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_msg_ctl(LittleEndian::read_u16(data));
|
||||
} else if msix_cap_reg_idx == reg_idx && offset == 0 && data.len() == 4 {
|
||||
msix_config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_msg_ctl((LittleEndian::read_u32(data) >> 16) as u16);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -922,16 +927,19 @@ impl PciBarConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn set_register_index(mut self, reg_idx: usize) -> Self {
|
||||
self.reg_idx = reg_idx;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn set_address(mut self, addr: u64) -> Self {
|
||||
self.addr = addr;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn set_size(mut self, size: u64) -> Self {
|
||||
self.size = size;
|
||||
self
|
||||
@@ -941,6 +949,7 @@ impl PciBarConfiguration {
|
||||
self.size
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self {
|
||||
self.region_type = region_type;
|
||||
self
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
use crate::configuration::{self, PciBarRegionType};
|
||||
use std::any::Any;
|
||||
use std::fmt::{self, Display};
|
||||
use std::sync::{Arc, Barrier};
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use std::{self, io, result};
|
||||
use vm_allocator::{AddressAllocator, SystemAllocator};
|
||||
use vm_device::BusDevice;
|
||||
@@ -51,7 +51,7 @@ pub trait PciDevice: BusDevice {
|
||||
/// returns an address. Returns a Vec of (GuestAddress, GuestUsize) tuples.
|
||||
fn allocate_bars(
|
||||
&mut self,
|
||||
_allocator: &mut SystemAllocator,
|
||||
_allocator: &Arc<Mutex<SystemAllocator>>,
|
||||
_mmio_allocator: &mut AddressAllocator,
|
||||
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>> {
|
||||
Ok(Vec::new())
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
use crate::{
|
||||
msi_num_enabled_vectors, BarReprogrammingParams, MsiConfig, MsixCap, MsixConfig,
|
||||
PciBarConfiguration, PciBarRegionType, PciCapabilityId, PciClassCode, PciConfiguration,
|
||||
PciBarConfiguration, PciBarRegionType, PciBdf, PciCapabilityId, PciClassCode, PciConfiguration,
|
||||
PciDevice, PciDeviceError, PciHeaderType, PciSubclass, MSIX_TABLE_ENTRY_SIZE,
|
||||
};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
@@ -15,7 +15,7 @@ use std::collections::BTreeMap;
|
||||
use std::io;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::ptr::null_mut;
|
||||
use std::sync::{Arc, Barrier};
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use thiserror::Error;
|
||||
use vfio_bindings::bindings::vfio::*;
|
||||
use vfio_ioctls::{VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap};
|
||||
@@ -360,7 +360,7 @@ pub(crate) struct VfioCommon {
|
||||
impl VfioCommon {
|
||||
pub(crate) fn allocate_bars(
|
||||
&mut self,
|
||||
allocator: &mut SystemAllocator,
|
||||
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||
mmio_allocator: &mut AddressAllocator,
|
||||
vfio_wrapper: &dyn Vfio,
|
||||
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
|
||||
@@ -411,25 +411,27 @@ impl VfioCommon {
|
||||
let mut lower = vfio_wrapper.read_config_dword(bar_offset);
|
||||
|
||||
if io_bar {
|
||||
// Mask flag bits (lowest 2 for I/O bars)
|
||||
lower &= !0b11;
|
||||
|
||||
// BAR is not enabled
|
||||
if lower == 0 {
|
||||
bar_id += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
// IO BAR
|
||||
region_type = PciBarRegionType::IoRegion;
|
||||
|
||||
// Mask flag bits (lowest 2 for I/O bars)
|
||||
lower &= !0b11;
|
||||
|
||||
// BAR is not enabled
|
||||
if lower == 0 {
|
||||
bar_id += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Invert bits and add 1 to calculate size
|
||||
region_size = (!lower + 1) as u64;
|
||||
|
||||
// The address needs to be 4 bytes aligned.
|
||||
bar_addr = allocator
|
||||
.lock()
|
||||
.unwrap()
|
||||
.allocate_io_addresses(None, region_size, Some(0x4))
|
||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?;
|
||||
}
|
||||
@@ -476,6 +478,8 @@ impl VfioCommon {
|
||||
|
||||
// BAR allocation must be naturally aligned
|
||||
bar_addr = allocator
|
||||
.lock()
|
||||
.unwrap()
|
||||
.allocate_mmio_hole_addresses(None, region_size, Some(region_size))
|
||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?;
|
||||
}
|
||||
@@ -553,6 +557,7 @@ impl VfioCommon {
|
||||
cap: u8,
|
||||
interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||
vfio_wrapper: &dyn Vfio,
|
||||
bdf: PciBdf,
|
||||
) {
|
||||
let msg_ctl = vfio_wrapper.read_config_word((cap + 2).into());
|
||||
|
||||
@@ -573,7 +578,11 @@ impl VfioCommon {
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let msix_config = MsixConfig::new(msix_cap.table_size(), interrupt_source_group.clone(), 0);
|
||||
let msix_config = MsixConfig::new(
|
||||
msix_cap.table_size(),
|
||||
interrupt_source_group.clone(),
|
||||
bdf.into(),
|
||||
);
|
||||
|
||||
self.interrupt.msix = Some(VfioMsix {
|
||||
bar: msix_config,
|
||||
@@ -611,6 +620,7 @@ impl VfioCommon {
|
||||
&mut self,
|
||||
interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||
vfio_wrapper: &dyn Vfio,
|
||||
bdf: PciBdf,
|
||||
) {
|
||||
let mut cap_next = vfio_wrapper.read_config_byte(PCI_CONFIG_CAPABILITY_OFFSET);
|
||||
|
||||
@@ -632,7 +642,12 @@ impl VfioCommon {
|
||||
if irq_info.count > 0 {
|
||||
// Parse capability only if the VFIO device
|
||||
// supports MSI-X.
|
||||
self.parse_msix_capabilities(cap_next, interrupt_manager, vfio_wrapper);
|
||||
self.parse_msix_capabilities(
|
||||
cap_next,
|
||||
interrupt_manager,
|
||||
vfio_wrapper,
|
||||
bdf,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -964,6 +979,7 @@ impl VfioPciDevice {
|
||||
msi_interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
|
||||
iommu_attached: bool,
|
||||
bdf: PciBdf,
|
||||
) -> Result<Self, VfioPciError> {
|
||||
let device = Arc::new(device);
|
||||
device.reset();
|
||||
@@ -993,7 +1009,7 @@ impl VfioPciDevice {
|
||||
},
|
||||
};
|
||||
|
||||
common.parse_capabilities(msi_interrupt_manager, &vfio_wrapper);
|
||||
common.parse_capabilities(msi_interrupt_manager, &vfio_wrapper, bdf);
|
||||
common.initialize_legacy_interrupt(legacy_interrupt_group, &vfio_wrapper)?;
|
||||
|
||||
let vfio_pci_device = VfioPciDevice {
|
||||
@@ -1308,7 +1324,7 @@ const PCI_ROM_EXP_BAR_INDEX: usize = 12;
|
||||
impl PciDevice for VfioPciDevice {
|
||||
fn allocate_bars(
|
||||
&mut self,
|
||||
allocator: &mut SystemAllocator,
|
||||
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||
mmio_allocator: &mut AddressAllocator,
|
||||
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
|
||||
self.common
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
use crate::vfio::{Interrupt, Vfio, VfioCommon, VfioError};
|
||||
use crate::{BarReprogrammingParams, PciBarRegionType, VfioPciError};
|
||||
use crate::{
|
||||
PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
|
||||
PciBdf, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
|
||||
};
|
||||
use hypervisor::HypervisorVmError;
|
||||
use std::any::Any;
|
||||
@@ -67,6 +67,7 @@ impl VfioUserPciDevice {
|
||||
client: Arc<Mutex<Client>>,
|
||||
msi_interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
|
||||
bdf: PciBdf,
|
||||
) -> Result<Self, VfioUserPciDeviceError> {
|
||||
// This is used for the BAR and capabilities only
|
||||
let configuration = PciConfiguration::new(
|
||||
@@ -104,7 +105,7 @@ impl VfioUserPciDevice {
|
||||
},
|
||||
};
|
||||
|
||||
common.parse_capabilities(msi_interrupt_manager, &vfio_wrapper);
|
||||
common.parse_capabilities(msi_interrupt_manager, &vfio_wrapper, bdf);
|
||||
common
|
||||
.initialize_legacy_interrupt(legacy_interrupt_group, &vfio_wrapper)
|
||||
.map_err(VfioUserPciDeviceError::InitializeLegacyInterrupts)?;
|
||||
@@ -326,17 +327,33 @@ impl Vfio for VfioUserClientWrapper {
|
||||
);
|
||||
let fds: Vec<i32> = event_fds.iter().map(|e| e.as_raw_fd()).collect();
|
||||
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_irqs(
|
||||
irq_index,
|
||||
VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER,
|
||||
0,
|
||||
event_fds.len() as u32,
|
||||
&fds,
|
||||
)
|
||||
.map_err(VfioError::VfioUser)
|
||||
// Batch into blocks of 16 fds as sendmsg() has a size limit
|
||||
let mut sent_fds = 0;
|
||||
let num_fds = event_fds.len() as u32;
|
||||
while sent_fds < num_fds {
|
||||
let remaining_fds = num_fds - sent_fds;
|
||||
let count = if remaining_fds > 16 {
|
||||
16
|
||||
} else {
|
||||
remaining_fds
|
||||
};
|
||||
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_irqs(
|
||||
irq_index,
|
||||
VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER,
|
||||
sent_fds,
|
||||
count,
|
||||
&fds[sent_fds as usize..(sent_fds + count) as usize],
|
||||
)
|
||||
.map_err(VfioError::VfioUser)?;
|
||||
|
||||
sent_fds += count;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn disable_irq(&self, irq_index: u32) -> Result<(), VfioError> {
|
||||
@@ -373,7 +390,7 @@ impl Vfio for VfioUserClientWrapper {
|
||||
impl PciDevice for VfioUserPciDevice {
|
||||
fn allocate_bars(
|
||||
&mut self,
|
||||
allocator: &mut SystemAllocator,
|
||||
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||
mmio_allocator: &mut AddressAllocator,
|
||||
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
|
||||
self.common
|
||||
|
||||
@@ -10,7 +10,7 @@ path = "src/qcow.rs"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.4.3"
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
log = "0.4.14"
|
||||
remain = "0.2.2"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
@@ -4,6 +4,6 @@ version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
log = "0.4.14"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
130
release-notes.md
130
release-notes.md
@@ -1,11 +1,19 @@
|
||||
- [v21.1](#v211)
|
||||
- [v21.0](#v210)
|
||||
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
|
||||
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
|
||||
- [Notable Bug fixes](#notable-bug-fixes)
|
||||
- [Contributors](#contributors)
|
||||
- [v20.2](#v202)
|
||||
- [v20.1](#v201)
|
||||
- [v20.0](#v200)
|
||||
- [Multiple PCI segments support](#multiple-pci-segments-support)
|
||||
- [CPU pinning](#cpu-pinning)
|
||||
- [Improved VFIO support](#improved-vfio-support)
|
||||
- [Safer code](#safer-code)
|
||||
- [Extended documentation](#extended-documentation)
|
||||
- [Notable bug fixes](#notable-bug-fixes)
|
||||
- [Contributors](#contributors)
|
||||
- [Notable bug fixes](#notable-bug-fixes-1)
|
||||
- [Contributors](#contributors-1)
|
||||
- [v19.0](#v190)
|
||||
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
|
||||
- [PCI boot time optimisations](#pci-boot-time-optimisations)
|
||||
@@ -13,8 +21,8 @@
|
||||
- [Live migration enhancements](#live-migration-enhancements)
|
||||
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
|
||||
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
|
||||
- [Notable bug fixes](#notable-bug-fixes-1)
|
||||
- [Contributors](#contributors-1)
|
||||
- [Notable bug fixes](#notable-bug-fixes-2)
|
||||
- [Contributors](#contributors-2)
|
||||
- [v18.0](#v180)
|
||||
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
|
||||
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
|
||||
@@ -24,23 +32,23 @@
|
||||
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
||||
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
||||
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
||||
- [Notable bug fixes](#notable-bug-fixes-2)
|
||||
- [Contributors](#contributors-2)
|
||||
- [Notable bug fixes](#notable-bug-fixes-3)
|
||||
- [Contributors](#contributors-3)
|
||||
- [v17.0](#v170)
|
||||
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
|
||||
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
|
||||
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
|
||||
- [Improved SGX support](#improved-sgx-support)
|
||||
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
|
||||
- [Notable bug fixes](#notable-bug-fixes-3)
|
||||
- [Contributors](#contributors-3)
|
||||
- [Notable bug fixes](#notable-bug-fixes-4)
|
||||
- [Contributors](#contributors-4)
|
||||
- [v16.0](#v160)
|
||||
- [Improved live migration support](#improved-live-migration-support)
|
||||
- [Improved `vhost-user` support](#improved-vhost-user-support)
|
||||
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
|
||||
- [Notable bug fixes](#notable-bug-fixes-4)
|
||||
- [Notable bug fixes](#notable-bug-fixes-5)
|
||||
- [Removed functionality](#removed-functionality)
|
||||
- [Contributors](#contributors-4)
|
||||
- [Contributors](#contributors-5)
|
||||
- [v15.0](#v150)
|
||||
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
||||
- [Network device rate limiting](#network-device-rate-limiting)
|
||||
@@ -48,7 +56,7 @@
|
||||
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
||||
- [Bug fixes](#bug-fixes)
|
||||
- [Deprecations](#deprecations)
|
||||
- [Contributors](#contributors-5)
|
||||
- [Contributors](#contributors-6)
|
||||
- [v0.14.1](#v0141)
|
||||
- [v0.14.0](#v0140)
|
||||
- [Structured event monitoring](#structured-event-monitoring)
|
||||
@@ -58,7 +66,7 @@
|
||||
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
|
||||
- [Block device rate limiting](#block-device-rate-limiting)
|
||||
- [Deprecations](#deprecations-1)
|
||||
- [Contributors](#contributors-6)
|
||||
- [Contributors](#contributors-7)
|
||||
- [v0.13.0](#v0130)
|
||||
- [Wider VFIO device support](#wider-vfio-device-support)
|
||||
- [Improved huge page support](#improved-huge-page-support)
|
||||
@@ -66,13 +74,13 @@
|
||||
- [VHD disk image support](#vhd-disk-image-support)
|
||||
- [Improved Virtio device threading](#improved-virtio-device-threading)
|
||||
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
|
||||
- [Contributors](#contributors-7)
|
||||
- [Contributors](#contributors-8)
|
||||
- [v0.12.0](#v0120)
|
||||
- [ARM64 enhancements](#arm64-enhancements)
|
||||
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
|
||||
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
|
||||
- [Enhanced "info" API](#enhanced-info-api)
|
||||
- [Contributors](#contributors-8)
|
||||
- [Contributors](#contributors-9)
|
||||
- [v0.11.0](#v0110)
|
||||
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
|
||||
- [Windows Guest Support](#windows-guest-support)
|
||||
@@ -84,15 +92,15 @@
|
||||
- [Default Log Level Changed](#default-log-level-changed)
|
||||
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
|
||||
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Contributors](#contributors-9)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||
- [Contributors](#contributors-10)
|
||||
- [v0.10.0](#v0100)
|
||||
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
|
||||
- [Memory Zones](#memory-zones)
|
||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
|
||||
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||
- [Contributors](#contributors-10)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
||||
- [Contributors](#contributors-11)
|
||||
- [v0.9.0](#v090)
|
||||
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
|
||||
- [Block and Network Device Statistics](#block-and-network-device-statistics)
|
||||
@@ -105,17 +113,17 @@
|
||||
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
|
||||
- [Intel SGX Support](#intel-sgx-support)
|
||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
||||
- [Contributors](#contributors-11)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-8)
|
||||
- [Contributors](#contributors-12)
|
||||
- [v0.8.0](#v080)
|
||||
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
|
||||
- [Experimental ARM64 Support](#experimental-arm64-support)
|
||||
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
|
||||
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
|
||||
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-8)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-9)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes)
|
||||
- [Contributors](#contributors-12)
|
||||
- [Contributors](#contributors-13)
|
||||
- [v0.7.0](#v070)
|
||||
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
|
||||
- [Alternative `libc` Support](#alternative-libc-support)
|
||||
@@ -125,14 +133,14 @@
|
||||
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
||||
- [Updated Distribution Support](#updated-distribution-support)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
||||
- [Contributors](#contributors-13)
|
||||
- [Contributors](#contributors-14)
|
||||
- [v0.6.0](#v060)
|
||||
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
|
||||
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
|
||||
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
|
||||
- [Command Line Interface](#command-line-interface)
|
||||
- [PVH Boot](#pvh-boot)
|
||||
- [Contributors](#contributors-14)
|
||||
- [Contributors](#contributors-15)
|
||||
- [v0.5.1](#v051)
|
||||
- [v0.5.0](#v050)
|
||||
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
||||
@@ -140,7 +148,7 @@
|
||||
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
||||
- [Development Tools](#development-tools)
|
||||
- [Kata Containers Integration](#kata-containers-integration)
|
||||
- [Contributors](#contributors-15)
|
||||
- [Contributors](#contributors-16)
|
||||
- [v0.4.0](#v040)
|
||||
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
||||
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
||||
@@ -149,7 +157,7 @@
|
||||
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
|
||||
- [PCI BAR reprogramming](#pci-bar-reprogramming)
|
||||
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
|
||||
- [Contributors](#contributors-16)
|
||||
- [Contributors](#contributors-17)
|
||||
- [v0.3.0](#v030)
|
||||
- [Block device offloading](#block-device-offloading)
|
||||
- [Network device backend](#network-device-backend)
|
||||
@@ -176,6 +184,76 @@
|
||||
- [Unit testing](#unit-testing)
|
||||
- [Integration tests parallelization](#integration-tests-parallelization)
|
||||
|
||||
# v21.1
|
||||
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
|
||||
* Missing `openat()` syscall from seccomp filter (#3609)
|
||||
* Ensure MMIO/PIO exits complete before pausing (#3658)
|
||||
* Support DWORD writes to MSI-X control register (#3714)
|
||||
* VFIO ioctl reordering to fix MSI on AMD platforms (#3827)
|
||||
* Fix `virtio-net` control queue (#3829)
|
||||
|
||||
# v21.0
|
||||
|
||||
This release has been tracked through the [v21.0
|
||||
project](https://github.com/cloud-hypervisor/cloud-hypervisor/projects/24).
|
||||
|
||||
### Efficient Local Live Migration (for Live Upgrade)
|
||||
|
||||
In order to support fast live upgrade of the VMM an optimised path has been added in which the memory for the VM is not compared from source to destination. This is activated by passing `--local` to the `ch-remote send-migration` command. This means that the live upgrade can complete in the order of 50ms vs 3s. (#3566)
|
||||
|
||||
### Recommended Kernel is Now 5.15
|
||||
|
||||
Due to an issue in the `virtio-net` code in 5.14 the recommended Linux kernel is now 5.15. (#3530)
|
||||
|
||||
### Notable Bug fixes
|
||||
|
||||
* Multiple fixes were made to the OpenAPI YAML file to match the implementaion (#3555,#3562)
|
||||
* Avoid live migration deadlock when triggered during the kernel boot (#3585)
|
||||
* Support live migration within firmware (#3586)
|
||||
* Validate the `virtio-net` desciptor chain (#3548)
|
||||
* `direct=on` (`O_DIRECT`) can now be used with a guest that makes unaligned accesses (e.g. firmware) (#3587)
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Anatol Belski <anbelski@linux.microsoft.com>
|
||||
* Barret Rhoden <brho@google.com>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Fabiano Fidêncio <fabiano.fidencio@intel.com>
|
||||
* Henry Wang <Henry.Wang@arm.com>
|
||||
* Liang Zhou <zhoul110@chinatelecom.cn>
|
||||
* Michael Zhao <michael.zhao@arm.com>
|
||||
* Muhammad Falak R Wani <falakreyaz@gmail.com>
|
||||
* Muminul Islam <muislam@microsoft.com>
|
||||
* Rob Bradford <robert.bradford@intel.com>
|
||||
* Sebastien Boeuf <sebastien.boeuf@intel.com>
|
||||
* Wei Liu <liuwe@microsoft.com>
|
||||
* Ziye Yang <ziye.yang@intel.com>
|
||||
|
||||
# v20.2
|
||||
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
|
||||
* Don't error out when setting up the SIGWINCH handler (for console resize)
|
||||
when this fails due to older kernel (#3456)
|
||||
* Seccomp rules were refined to remove syscalls that are now unused
|
||||
* Fix reboot on older host kernels when SIGWINCH handler was not initialised
|
||||
(#3496)
|
||||
* Fix virtio-vsock blocking issue (#3497)
|
||||
|
||||
# v20.1
|
||||
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
|
||||
* Networking performance regression with `virtio-net` (#3450)
|
||||
* Limit file descriptors sent in `vfio-user` support (#3401)
|
||||
* Fully advertise PCI MMIO config regions in ACPI tables (#3432)
|
||||
* Set the TSS and KVM identity maps so they don't overlap with firmware RAM
|
||||
* Correctly update the `DeviceTree` on restore
|
||||
|
||||
# v20.0
|
||||
|
||||
This release has been tracked through the [v20.0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FROM ubuntu:20.04 as dev
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG RUST_TOOLCHAIN="1.56.1"
|
||||
ARG RUST_TOOLCHAIN="1.58.0"
|
||||
ARG CLH_SRC_DIR="/cloud-hypervisor"
|
||||
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
|
||||
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"
|
||||
@@ -115,10 +115,8 @@ RUN git clone --depth 1 https://gitlab.com/virtio-fs/qemu.git -b qemu5.0-virtiof
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
git clone https://github.com/spdk/spdk \
|
||||
&& cd spdk \
|
||||
&& git checkout a827fd7eeca67209d4c0aaad9a3ed55692e7e36e \
|
||||
&& git checkout 59f3cdacb13bd2a19c4a86be04792b0ee4491172 \
|
||||
&& git submodule update --init \
|
||||
&& sed -i 's/pip3 install meson/pip3 install meson==0.59.2/g' scripts/pkgdep/ubuntu.sh \
|
||||
&& sed -i 's/meson/meson==0.59.2/g' scripts/pkgdep/requirements.txt \
|
||||
&& apt-get update \
|
||||
&& ./scripts/pkgdep.sh \
|
||||
&& ./configure --with-vfio-user \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/arm64 5.14.0 Kernel Configuration
|
||||
# Linux/arm64 5.15.12 Kernel Configuration
|
||||
#
|
||||
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0"
|
||||
CONFIG_CC_IS_GCC=y
|
||||
@@ -25,6 +25,7 @@ CONFIG_THREAD_INFO_IN_TASK=y
|
||||
#
|
||||
CONFIG_INIT_ENV_ARG_LIMIT=32
|
||||
# CONFIG_COMPILE_TEST is not set
|
||||
# CONFIG_WERROR is not set
|
||||
CONFIG_LOCALVERSION=""
|
||||
# CONFIG_LOCALVERSION_AUTO is not set
|
||||
CONFIG_BUILD_SALT=""
|
||||
@@ -133,6 +134,7 @@ CONFIG_RCU_NEED_SEGCBLIST=y
|
||||
CONFIG_LOG_BUF_SHIFT=21
|
||||
CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
|
||||
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13
|
||||
# CONFIG_PRINTK_INDEX is not set
|
||||
CONFIG_GENERIC_SCHED_CLOCK=y
|
||||
|
||||
#
|
||||
@@ -202,7 +204,6 @@ CONFIG_SYSFS_SYSCALL=y
|
||||
CONFIG_FHANDLE=y
|
||||
CONFIG_POSIX_TIMERS=y
|
||||
CONFIG_PRINTK=y
|
||||
CONFIG_PRINTK_NMI=y
|
||||
CONFIG_BUG=y
|
||||
CONFIG_ELF_CORE=y
|
||||
CONFIG_BASE_FULL=y
|
||||
@@ -265,7 +266,6 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
|
||||
CONFIG_STACKTRACE_SUPPORT=y
|
||||
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
|
||||
CONFIG_LOCKDEP_SUPPORT=y
|
||||
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
|
||||
CONFIG_GENERIC_BUG=y
|
||||
CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
|
||||
CONFIG_GENERIC_HWEIGHT=y
|
||||
@@ -431,8 +431,10 @@ CONFIG_ARM64_CNP=y
|
||||
#
|
||||
CONFIG_ARM64_PTR_AUTH=y
|
||||
CONFIG_ARM64_PTR_AUTH_KERNEL=y
|
||||
CONFIG_CC_HAS_BRANCH_PROT_PAC_RET=y
|
||||
CONFIG_CC_HAS_SIGN_RETURN_ADDRESS=y
|
||||
CONFIG_AS_HAS_PAC=y
|
||||
CONFIG_AS_HAS_CFI_NEGATE_RA_STATE=y
|
||||
# end of ARMv8.3 architectural features
|
||||
|
||||
#
|
||||
@@ -446,9 +448,13 @@ CONFIG_ARM64_TLB_RANGE=y
|
||||
#
|
||||
# ARMv8.5 architectural features
|
||||
#
|
||||
CONFIG_AS_HAS_ARMV8_5=y
|
||||
CONFIG_ARM64_BTI=y
|
||||
CONFIG_CC_HAS_BRANCH_PROT_PAC_RET_BTI=y
|
||||
CONFIG_ARM64_E0PD=y
|
||||
CONFIG_ARCH_RANDOM=y
|
||||
CONFIG_ARM64_AS_HAS_MTE=y
|
||||
CONFIG_ARM64_MTE=y
|
||||
# end of ARMv8.5 architectural features
|
||||
|
||||
#
|
||||
@@ -462,6 +468,8 @@ CONFIG_ARM64_SVE=y
|
||||
CONFIG_RELOCATABLE=y
|
||||
CONFIG_RANDOMIZE_BASE=y
|
||||
CONFIG_RANDOMIZE_MODULE_REGION_FULL=y
|
||||
CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
|
||||
CONFIG_STACKPROTECTOR_PER_TASK=y
|
||||
# end of Kernel Features
|
||||
|
||||
#
|
||||
@@ -543,49 +551,6 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
|
||||
# end of CPU Frequency scaling
|
||||
# end of CPU Power Management
|
||||
|
||||
#
|
||||
# Firmware Drivers
|
||||
#
|
||||
# CONFIG_ARM_SCMI_PROTOCOL is not set
|
||||
# CONFIG_ARM_SCPI_PROTOCOL is not set
|
||||
# CONFIG_ARM_SDE_INTERFACE is not set
|
||||
CONFIG_FIRMWARE_MEMMAP=y
|
||||
CONFIG_DMIID=y
|
||||
CONFIG_DMI_SYSFS=y
|
||||
# CONFIG_FW_CFG_SYSFS is not set
|
||||
# CONFIG_ARM_FFA_TRANSPORT is not set
|
||||
# CONFIG_GOOGLE_FIRMWARE is not set
|
||||
|
||||
#
|
||||
# EFI (Extensible Firmware Interface) Support
|
||||
#
|
||||
CONFIG_EFI_ESRT=y
|
||||
CONFIG_EFI_PARAMS_FROM_FDT=y
|
||||
CONFIG_EFI_RUNTIME_WRAPPERS=y
|
||||
CONFIG_EFI_GENERIC_STUB=y
|
||||
CONFIG_EFI_ARMSTUB_DTB_LOADER=y
|
||||
CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
|
||||
# CONFIG_EFI_BOOTLOADER_CONTROL is not set
|
||||
# CONFIG_EFI_CAPSULE_LOADER is not set
|
||||
# CONFIG_EFI_TEST is not set
|
||||
# CONFIG_RESET_ATTACK_MITIGATION is not set
|
||||
# CONFIG_EFI_DISABLE_PCI_DMA is not set
|
||||
# end of EFI (Extensible Firmware Interface) Support
|
||||
|
||||
CONFIG_EFI_EARLYCON=y
|
||||
# CONFIG_EFI_CUSTOM_SSDT_OVERLAYS is not set
|
||||
CONFIG_ARM_PSCI_FW=y
|
||||
# CONFIG_ARM_PSCI_CHECKER is not set
|
||||
CONFIG_HAVE_ARM_SMCCC=y
|
||||
CONFIG_HAVE_ARM_SMCCC_DISCOVERY=y
|
||||
# CONFIG_ARM_SMCCC_SOC_ID is not set
|
||||
|
||||
#
|
||||
# Tegra firmware driver
|
||||
#
|
||||
# end of Tegra firmware driver
|
||||
# end of Firmware Drivers
|
||||
|
||||
CONFIG_ARCH_SUPPORTS_ACPI=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_ACPI_GENERIC_GSI=y
|
||||
@@ -640,6 +605,8 @@ CONFIG_HAVE_KVM_ARCH_TLB_FLUSH_ALL=y
|
||||
CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
|
||||
CONFIG_HAVE_KVM_IRQ_BYPASS=y
|
||||
CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE=y
|
||||
CONFIG_KVM_XFER_TO_GUEST_WORK=y
|
||||
# CONFIG_NVHE_EL2_DEBUG is not set
|
||||
# CONFIG_ARM64_CRYPTO is not set
|
||||
|
||||
#
|
||||
@@ -654,6 +621,7 @@ CONFIG_HAVE_KPROBES=y
|
||||
CONFIG_HAVE_KRETPROBES=y
|
||||
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
|
||||
CONFIG_HAVE_NMI=y
|
||||
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
|
||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||
CONFIG_HAVE_DMA_CONTIGUOUS=y
|
||||
CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
||||
@@ -738,15 +706,14 @@ CONFIG_BASE_SMALL=0
|
||||
# CONFIG_MODULES is not set
|
||||
CONFIG_MODULES_TREE_LOOKUP=y
|
||||
CONFIG_BLOCK=y
|
||||
CONFIG_BLK_SCSI_REQUEST=y
|
||||
CONFIG_BLK_CGROUP_RWSTAT=y
|
||||
CONFIG_BLK_DEV_BSG=y
|
||||
CONFIG_BLK_DEV_BSG_COMMON=y
|
||||
CONFIG_BLK_DEV_BSGLIB=y
|
||||
CONFIG_BLK_DEV_INTEGRITY=y
|
||||
CONFIG_BLK_DEV_INTEGRITY_T10=y
|
||||
# CONFIG_BLK_DEV_ZONED is not set
|
||||
CONFIG_BLK_DEV_THROTTLING=y
|
||||
# CONFIG_BLK_DEV_THROTTLING_LOW is not set
|
||||
CONFIG_BLK_CMDLINE_PARSER=y
|
||||
CONFIG_BLK_WBT=y
|
||||
CONFIG_BLK_WBT_MQ=y
|
||||
# CONFIG_BLK_CGROUP_IOLATENCY is not set
|
||||
@@ -936,11 +903,18 @@ CONFIG_ZONE_DMA32=y
|
||||
CONFIG_ZONE_DEVICE=y
|
||||
CONFIG_DEV_PAGEMAP_OPS=y
|
||||
# CONFIG_DEVICE_PRIVATE is not set
|
||||
CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
|
||||
CONFIG_PERCPU_STATS=y
|
||||
# CONFIG_GUP_TEST is not set
|
||||
# CONFIG_READ_ONLY_THP_FOR_FS is not set
|
||||
CONFIG_ARCH_HAS_PTE_SPECIAL=y
|
||||
CONFIG_SECRETMEM=y
|
||||
|
||||
#
|
||||
# Data Access Monitoring
|
||||
#
|
||||
# CONFIG_DAMON is not set
|
||||
# end of Data Access Monitoring
|
||||
# end of Memory Management options
|
||||
|
||||
CONFIG_NET=y
|
||||
@@ -953,6 +927,7 @@ CONFIG_PACKET=y
|
||||
CONFIG_PACKET_DIAG=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_UNIX_SCM=y
|
||||
CONFIG_AF_UNIX_OOB=y
|
||||
CONFIG_UNIX_DIAG=y
|
||||
CONFIG_TLS=y
|
||||
# CONFIG_TLS_DEVICE is not set
|
||||
@@ -1056,6 +1031,7 @@ CONFIG_NET_FLOW_LIMIT=y
|
||||
# CONFIG_AF_RXRPC is not set
|
||||
# CONFIG_AF_KCM is not set
|
||||
CONFIG_STREAM_PARSER=y
|
||||
# CONFIG_MCTP is not set
|
||||
# CONFIG_WIRELESS is not set
|
||||
# CONFIG_RFKILL is not set
|
||||
# CONFIG_NET_9P is not set
|
||||
@@ -1202,13 +1178,64 @@ CONFIG_GENERIC_ARCH_NUMA=y
|
||||
# Bus devices
|
||||
#
|
||||
# CONFIG_BRCMSTB_GISB_ARB is not set
|
||||
# CONFIG_SIMPLE_PM_BUS is not set
|
||||
# CONFIG_VEXPRESS_CONFIG is not set
|
||||
# CONFIG_MHI_BUS is not set
|
||||
# end of Bus devices
|
||||
|
||||
CONFIG_CONNECTOR=y
|
||||
CONFIG_PROC_EVENTS=y
|
||||
|
||||
#
|
||||
# Firmware Drivers
|
||||
#
|
||||
|
||||
#
|
||||
# ARM System Control and Management Interface Protocol
|
||||
#
|
||||
# CONFIG_ARM_SCMI_PROTOCOL is not set
|
||||
# end of ARM System Control and Management Interface Protocol
|
||||
|
||||
# CONFIG_ARM_SCPI_PROTOCOL is not set
|
||||
# CONFIG_ARM_SDE_INTERFACE is not set
|
||||
CONFIG_FIRMWARE_MEMMAP=y
|
||||
CONFIG_DMIID=y
|
||||
CONFIG_DMI_SYSFS=y
|
||||
# CONFIG_FW_CFG_SYSFS is not set
|
||||
CONFIG_SYSFB=y
|
||||
# CONFIG_SYSFB_SIMPLEFB is not set
|
||||
# CONFIG_ARM_FFA_TRANSPORT is not set
|
||||
# CONFIG_GOOGLE_FIRMWARE is not set
|
||||
|
||||
#
|
||||
# EFI (Extensible Firmware Interface) Support
|
||||
#
|
||||
CONFIG_EFI_ESRT=y
|
||||
CONFIG_EFI_PARAMS_FROM_FDT=y
|
||||
CONFIG_EFI_RUNTIME_WRAPPERS=y
|
||||
CONFIG_EFI_GENERIC_STUB=y
|
||||
CONFIG_EFI_ARMSTUB_DTB_LOADER=y
|
||||
CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
|
||||
# CONFIG_EFI_BOOTLOADER_CONTROL is not set
|
||||
# CONFIG_EFI_CAPSULE_LOADER is not set
|
||||
# CONFIG_EFI_TEST is not set
|
||||
# CONFIG_RESET_ATTACK_MITIGATION is not set
|
||||
# CONFIG_EFI_DISABLE_PCI_DMA is not set
|
||||
# end of EFI (Extensible Firmware Interface) Support
|
||||
|
||||
CONFIG_EFI_EARLYCON=y
|
||||
# CONFIG_EFI_CUSTOM_SSDT_OVERLAYS is not set
|
||||
CONFIG_ARM_PSCI_FW=y
|
||||
# CONFIG_ARM_PSCI_CHECKER is not set
|
||||
CONFIG_HAVE_ARM_SMCCC=y
|
||||
CONFIG_HAVE_ARM_SMCCC_DISCOVERY=y
|
||||
# CONFIG_ARM_SMCCC_SOC_ID is not set
|
||||
|
||||
#
|
||||
# Tegra firmware driver
|
||||
#
|
||||
# end of Tegra firmware driver
|
||||
# end of Firmware Drivers
|
||||
|
||||
# CONFIG_GNSS is not set
|
||||
# CONFIG_MTD is not set
|
||||
CONFIG_DTC=y
|
||||
@@ -1258,7 +1285,9 @@ CONFIG_VIRTIO_BLK=y
|
||||
#
|
||||
# NVME Support
|
||||
#
|
||||
# CONFIG_BLK_DEV_NVME is not set
|
||||
CONFIG_NVME_CORE=y
|
||||
CONFIG_BLK_DEV_NVME=y
|
||||
CONFIG_NVME_MULTIPATH=y
|
||||
# CONFIG_NVME_FC is not set
|
||||
# CONFIG_NVME_TCP is not set
|
||||
# CONFIG_NVME_TARGET is not set
|
||||
@@ -1315,7 +1344,38 @@ CONFIG_SCSI_MOD=y
|
||||
|
||||
CONFIG_HAVE_PATA_PLATFORM=y
|
||||
# CONFIG_ATA is not set
|
||||
# CONFIG_MD is not set
|
||||
CONFIG_MD=y
|
||||
# CONFIG_BLK_DEV_MD is not set
|
||||
# CONFIG_BCACHE is not set
|
||||
CONFIG_BLK_DEV_DM_BUILTIN=y
|
||||
CONFIG_BLK_DEV_DM=y
|
||||
# CONFIG_DM_DEBUG is not set
|
||||
# CONFIG_DM_UNSTRIPED is not set
|
||||
# CONFIG_DM_CRYPT is not set
|
||||
# CONFIG_DM_SNAPSHOT is not set
|
||||
# CONFIG_DM_THIN_PROVISIONING is not set
|
||||
# CONFIG_DM_CACHE is not set
|
||||
# CONFIG_DM_WRITECACHE is not set
|
||||
# CONFIG_DM_EBS is not set
|
||||
# CONFIG_DM_ERA is not set
|
||||
# CONFIG_DM_CLONE is not set
|
||||
# CONFIG_DM_MIRROR is not set
|
||||
# CONFIG_DM_RAID is not set
|
||||
# CONFIG_DM_ZERO is not set
|
||||
CONFIG_DM_MULTIPATH=y
|
||||
# CONFIG_DM_MULTIPATH_QL is not set
|
||||
# CONFIG_DM_MULTIPATH_ST is not set
|
||||
# CONFIG_DM_MULTIPATH_HST is not set
|
||||
# CONFIG_DM_MULTIPATH_IOA is not set
|
||||
# CONFIG_DM_DELAY is not set
|
||||
# CONFIG_DM_DUST is not set
|
||||
# CONFIG_DM_INIT is not set
|
||||
# CONFIG_DM_UEVENT is not set
|
||||
# CONFIG_DM_FLAKEY is not set
|
||||
# CONFIG_DM_VERITY is not set
|
||||
# CONFIG_DM_SWITCH is not set
|
||||
# CONFIG_DM_LOG_WRITES is not set
|
||||
# CONFIG_DM_INTEGRITY is not set
|
||||
# CONFIG_TARGET_CORE is not set
|
||||
# CONFIG_FUSION is not set
|
||||
|
||||
@@ -1379,7 +1439,6 @@ CONFIG_VIRTIO_NET=y
|
||||
# CONFIG_NETDEVSIM is not set
|
||||
CONFIG_NET_FAILOVER=y
|
||||
# CONFIG_ISDN is not set
|
||||
# CONFIG_NVM is not set
|
||||
|
||||
#
|
||||
# Input device support
|
||||
@@ -1523,15 +1582,15 @@ CONFIG_HW_RANDOM_VIRTIO=y
|
||||
CONFIG_HW_RANDOM_CAVIUM=y
|
||||
# CONFIG_HW_RANDOM_CCTRNG is not set
|
||||
# CONFIG_HW_RANDOM_XIPHERA is not set
|
||||
CONFIG_HW_RANDOM_ARM_SMCCC_TRNG=y
|
||||
# CONFIG_APPLICOM is not set
|
||||
CONFIG_DEVMEM=y
|
||||
CONFIG_DEVPORT=y
|
||||
# CONFIG_TCG_TPM is not set
|
||||
# CONFIG_XILLYBUS is not set
|
||||
# end of Character devices
|
||||
|
||||
# CONFIG_RANDOM_TRUST_CPU is not set
|
||||
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
|
||||
# end of Character devices
|
||||
|
||||
#
|
||||
# I2C support
|
||||
@@ -1561,12 +1620,12 @@ CONFIG_PPS_CLIENT_GPIO=y
|
||||
# PTP clock support
|
||||
#
|
||||
CONFIG_PTP_1588_CLOCK=y
|
||||
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
|
||||
|
||||
#
|
||||
# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
|
||||
#
|
||||
CONFIG_PTP_1588_CLOCK_KVM=y
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# end of PTP clock support
|
||||
|
||||
# CONFIG_PINCTRL is not set
|
||||
@@ -1620,6 +1679,7 @@ CONFIG_GPIO_PL061=y
|
||||
#
|
||||
# CONFIG_GPIO_AGGREGATOR is not set
|
||||
# CONFIG_GPIO_MOCKUP is not set
|
||||
# CONFIG_GPIO_VIRTIO is not set
|
||||
# end of Virtual GPIO drivers
|
||||
|
||||
# CONFIG_W1 is not set
|
||||
@@ -1838,7 +1898,6 @@ CONFIG_HID_GENERIC=y
|
||||
# CONFIG_HID_AUREAL is not set
|
||||
# CONFIG_HID_BELKIN is not set
|
||||
# CONFIG_HID_CHERRY is not set
|
||||
# CONFIG_HID_CHICONY is not set
|
||||
# CONFIG_HID_COUGAR is not set
|
||||
# CONFIG_HID_MACALLY is not set
|
||||
# CONFIG_HID_CMEDIA is not set
|
||||
@@ -1879,7 +1938,6 @@ CONFIG_HID_REDRAGON=y
|
||||
# CONFIG_HID_PLAYSTATION is not set
|
||||
# CONFIG_HID_PRIMAX is not set
|
||||
# CONFIG_HID_SAITEK is not set
|
||||
# CONFIG_HID_SAMSUNG is not set
|
||||
# CONFIG_HID_SEMITEK is not set
|
||||
# CONFIG_HID_SPEEDLINK is not set
|
||||
# CONFIG_HID_STEAM is not set
|
||||
@@ -2011,8 +2069,6 @@ CONFIG_DMA_OF=y
|
||||
# DMABUF options
|
||||
#
|
||||
# CONFIG_SYNC_FILE is not set
|
||||
# CONFIG_DMABUF_MOVE_NOTIFY is not set
|
||||
# CONFIG_DMABUF_DEBUG is not set
|
||||
# CONFIG_DMABUF_HEAPS is not set
|
||||
# end of DMABUF options
|
||||
|
||||
@@ -2027,13 +2083,14 @@ CONFIG_UIO_DMEM_GENIRQ=y
|
||||
# CONFIG_UIO_NETX is not set
|
||||
# CONFIG_UIO_PRUSS is not set
|
||||
# CONFIG_UIO_MF624 is not set
|
||||
CONFIG_VFIO=y
|
||||
CONFIG_VFIO_IOMMU_TYPE1=y
|
||||
CONFIG_VFIO_VIRQFD=y
|
||||
CONFIG_VFIO=y
|
||||
# CONFIG_VFIO_NOIOMMU is not set
|
||||
CONFIG_VFIO_PCI=y
|
||||
CONFIG_VFIO_PCI_CORE=y
|
||||
CONFIG_VFIO_PCI_MMAP=y
|
||||
CONFIG_VFIO_PCI_INTX=y
|
||||
CONFIG_VFIO_PCI=y
|
||||
# CONFIG_VFIO_PLATFORM is not set
|
||||
# CONFIG_VFIO_MDEV is not set
|
||||
# CONFIG_VIRT_DRIVERS is not set
|
||||
@@ -2057,6 +2114,7 @@ CONFIG_VHOST_MENU=y
|
||||
#
|
||||
# Microsoft Hyper-V guest support
|
||||
#
|
||||
# CONFIG_HYPERV is not set
|
||||
# end of Microsoft Hyper-V guest support
|
||||
|
||||
# CONFIG_GREYBUS is not set
|
||||
@@ -2118,6 +2176,8 @@ CONFIG_IOMMU_SUPPORT=y
|
||||
# end of Generic IOMMU Pagetable Support
|
||||
|
||||
# CONFIG_IOMMU_DEBUGFS is not set
|
||||
CONFIG_IOMMU_DEFAULT_DMA_STRICT=y
|
||||
# CONFIG_IOMMU_DEFAULT_DMA_LAZY is not set
|
||||
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
|
||||
CONFIG_OF_IOMMU=y
|
||||
CONFIG_IOMMU_DMA=y
|
||||
@@ -2320,7 +2380,6 @@ CONFIG_FS_POSIX_ACL=y
|
||||
CONFIG_EXPORTFS=y
|
||||
# CONFIG_EXPORTFS_BLOCK_OPS is not set
|
||||
CONFIG_FILE_LOCKING=y
|
||||
CONFIG_MANDATORY_FILE_LOCKING=y
|
||||
CONFIG_FS_ENCRYPTION=y
|
||||
CONFIG_FS_ENCRYPTION_ALGS=y
|
||||
# CONFIG_FS_VERITY is not set
|
||||
@@ -2349,12 +2408,9 @@ CONFIG_NETFS_SUPPORT=y
|
||||
# CONFIG_NETFS_STATS is not set
|
||||
CONFIG_FSCACHE=y
|
||||
# CONFIG_FSCACHE_STATS is not set
|
||||
# CONFIG_FSCACHE_HISTOGRAM is not set
|
||||
# CONFIG_FSCACHE_DEBUG is not set
|
||||
# CONFIG_FSCACHE_OBJECT_LIST is not set
|
||||
CONFIG_CACHEFILES=y
|
||||
# CONFIG_CACHEFILES_DEBUG is not set
|
||||
# CONFIG_CACHEFILES_HISTOGRAM is not set
|
||||
# end of Caches
|
||||
|
||||
#
|
||||
@@ -2375,6 +2431,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
|
||||
# CONFIG_FAT_DEFAULT_UTF8 is not set
|
||||
# CONFIG_EXFAT_FS is not set
|
||||
# CONFIG_NTFS_FS is not set
|
||||
# CONFIG_NTFS3_FS is not set
|
||||
# end of DOS/FAT/EXFAT/NT Filesystems
|
||||
|
||||
#
|
||||
@@ -2772,6 +2829,7 @@ CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y
|
||||
CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y
|
||||
CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y
|
||||
CONFIG_SWIOTLB=y
|
||||
# CONFIG_DMA_RESTRICTED_POOL is not set
|
||||
CONFIG_DMA_NONCOHERENT_MMAP=y
|
||||
CONFIG_DMA_COHERENT_POOL=y
|
||||
CONFIG_DMA_REMAP=y
|
||||
@@ -2884,8 +2942,11 @@ CONFIG_DEBUG_MEMORY_INIT=y
|
||||
# CONFIG_DEBUG_PER_CPU_MAPS is not set
|
||||
CONFIG_HAVE_ARCH_KASAN=y
|
||||
CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y
|
||||
CONFIG_HAVE_ARCH_KASAN_HW_TAGS=y
|
||||
CONFIG_HAVE_ARCH_KASAN_VMALLOC=y
|
||||
CONFIG_CC_HAS_KASAN_GENERIC=y
|
||||
CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y
|
||||
# CONFIG_KASAN is not set
|
||||
CONFIG_HAVE_ARCH_KFENCE=y
|
||||
# CONFIG_KFENCE is not set
|
||||
# end of Memory Debugging
|
||||
@@ -2962,12 +3023,12 @@ CONFIG_RCU_CPU_STALL_TIMEOUT=59
|
||||
# end of RCU Debugging
|
||||
|
||||
# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
|
||||
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
|
||||
# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
|
||||
# CONFIG_LATENCYTOP is not set
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
||||
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||
@@ -2996,7 +3057,6 @@ CONFIG_CC_HAS_SANCOV_TRACE_PC=y
|
||||
CONFIG_RUNTIME_TESTING_MENU=y
|
||||
# CONFIG_LKDTM is not set
|
||||
# CONFIG_TEST_MIN_HEAP is not set
|
||||
# CONFIG_TEST_SORT is not set
|
||||
# CONFIG_TEST_DIV64 is not set
|
||||
# CONFIG_BACKTRACE_SELF_TEST is not set
|
||||
# CONFIG_RBTREE_TEST is not set
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/x86 5.14.0 Kernel Configuration
|
||||
# Linux/x86 5.15.12 Kernel Configuration
|
||||
#
|
||||
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 10.3.0-1ubuntu1) 10.3.0"
|
||||
CONFIG_CC_VERSION_TEXT="gcc (GCC) 11.2.1 20211203 (Red Hat 11.2.1-7)"
|
||||
CONFIG_CC_IS_GCC=y
|
||||
CONFIG_GCC_VERSION=100300
|
||||
CONFIG_GCC_VERSION=110201
|
||||
CONFIG_CLANG_VERSION=0
|
||||
CONFIG_AS_IS_GNU=y
|
||||
CONFIG_AS_VERSION=23500
|
||||
CONFIG_AS_VERSION=23700
|
||||
CONFIG_LD_IS_BFD=y
|
||||
CONFIG_LD_VERSION=23500
|
||||
CONFIG_LD_VERSION=23700
|
||||
CONFIG_LLD_VERSION=0
|
||||
CONFIG_CC_CAN_LINK=y
|
||||
CONFIG_CC_CAN_LINK_STATIC=y
|
||||
CONFIG_CC_HAS_ASM_GOTO=y
|
||||
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
||||
CONFIG_CC_HAS_ASM_INLINE=y
|
||||
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
|
||||
CONFIG_IRQ_WORK=y
|
||||
@@ -25,6 +25,7 @@ CONFIG_THREAD_INFO_IN_TASK=y
|
||||
#
|
||||
CONFIG_INIT_ENV_ARG_LIMIT=32
|
||||
# CONFIG_COMPILE_TEST is not set
|
||||
# CONFIG_WERROR is not set
|
||||
CONFIG_LOCALVERSION=""
|
||||
# CONFIG_LOCALVERSION_AUTO is not set
|
||||
CONFIG_BUILD_SALT=""
|
||||
@@ -154,6 +155,7 @@ CONFIG_BUILD_BIN2C=y
|
||||
CONFIG_LOG_BUF_SHIFT=21
|
||||
CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
|
||||
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13
|
||||
# CONFIG_PRINTK_INDEX is not set
|
||||
CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
|
||||
|
||||
#
|
||||
@@ -226,7 +228,6 @@ CONFIG_SYSFS_SYSCALL=y
|
||||
CONFIG_FHANDLE=y
|
||||
CONFIG_POSIX_TIMERS=y
|
||||
CONFIG_PRINTK=y
|
||||
CONFIG_PRINTK_NMI=y
|
||||
CONFIG_BUG=y
|
||||
CONFIG_ELF_CORE=y
|
||||
CONFIG_PCSPKR_PLATFORM=y
|
||||
@@ -299,6 +300,7 @@ CONFIG_HAVE_SETUP_PER_CPU_AREA=y
|
||||
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
|
||||
CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_NR_GPIO=1024
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
|
||||
CONFIG_AUDIT_ARCH=y
|
||||
@@ -380,13 +382,13 @@ CONFIG_PERF_EVENTS_INTEL_UNCORE=y
|
||||
CONFIG_PERF_EVENTS_INTEL_RAPL=y
|
||||
CONFIG_PERF_EVENTS_INTEL_CSTATE=y
|
||||
# CONFIG_PERF_EVENTS_AMD_POWER is not set
|
||||
CONFIG_PERF_EVENTS_AMD_UNCORE=y
|
||||
# end of Performance monitoring
|
||||
|
||||
CONFIG_X86_16BIT=y
|
||||
CONFIG_X86_ESPFIX64=y
|
||||
CONFIG_X86_VSYSCALL_EMULATION=y
|
||||
# CONFIG_X86_IOPL_IOPERM is not set
|
||||
# CONFIG_I8K is not set
|
||||
# CONFIG_MICROCODE is not set
|
||||
CONFIG_X86_MSR=y
|
||||
CONFIG_X86_CPUID=y
|
||||
@@ -585,7 +587,6 @@ CONFIG_MMCONF_FAM10H=y
|
||||
# CONFIG_ISA_BUS is not set
|
||||
# CONFIG_ISA_DMA_API is not set
|
||||
CONFIG_AMD_NB=y
|
||||
# CONFIG_X86_SYSFB is not set
|
||||
# end of Bus options (PCI etc.)
|
||||
|
||||
#
|
||||
@@ -595,44 +596,6 @@ CONFIG_AMD_NB=y
|
||||
# CONFIG_X86_X32 is not set
|
||||
# end of Binary Emulations
|
||||
|
||||
#
|
||||
# Firmware Drivers
|
||||
#
|
||||
# CONFIG_EDD is not set
|
||||
CONFIG_FIRMWARE_MEMMAP=y
|
||||
CONFIG_DMIID=y
|
||||
CONFIG_DMI_SYSFS=y
|
||||
CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
|
||||
# CONFIG_FW_CFG_SYSFS is not set
|
||||
# CONFIG_GOOGLE_FIRMWARE is not set
|
||||
|
||||
#
|
||||
# EFI (Extensible Firmware Interface) Support
|
||||
#
|
||||
# CONFIG_EFI_VARS is not set
|
||||
CONFIG_EFI_ESRT=y
|
||||
CONFIG_EFI_RUNTIME_MAP=y
|
||||
# CONFIG_EFI_FAKE_MEMMAP is not set
|
||||
CONFIG_EFI_RUNTIME_WRAPPERS=y
|
||||
CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
|
||||
# CONFIG_EFI_BOOTLOADER_CONTROL is not set
|
||||
# CONFIG_EFI_CAPSULE_LOADER is not set
|
||||
# CONFIG_EFI_TEST is not set
|
||||
# CONFIG_APPLE_PROPERTIES is not set
|
||||
# CONFIG_RESET_ATTACK_MITIGATION is not set
|
||||
# CONFIG_EFI_RCI2_TABLE is not set
|
||||
# CONFIG_EFI_DISABLE_PCI_DMA is not set
|
||||
# end of EFI (Extensible Firmware Interface) Support
|
||||
|
||||
CONFIG_EFI_EARLYCON=y
|
||||
# CONFIG_EFI_CUSTOM_SSDT_OVERLAYS is not set
|
||||
|
||||
#
|
||||
# Tegra firmware driver
|
||||
#
|
||||
# end of Tegra firmware driver
|
||||
# end of Firmware Drivers
|
||||
|
||||
CONFIG_HAVE_KVM=y
|
||||
CONFIG_HAVE_KVM_IRQCHIP=y
|
||||
CONFIG_HAVE_KVM_IRQFD=y
|
||||
@@ -679,6 +642,7 @@ CONFIG_HAVE_OPTPROBES=y
|
||||
CONFIG_HAVE_KPROBES_ON_FTRACE=y
|
||||
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
|
||||
CONFIG_HAVE_NMI=y
|
||||
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
|
||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||
CONFIG_HAVE_DMA_CONTIGUOUS=y
|
||||
CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
||||
@@ -753,12 +717,14 @@ CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y
|
||||
CONFIG_ARCH_USE_MEMREMAP_PROT=y
|
||||
# CONFIG_LOCK_EVENT_COUNTS is not set
|
||||
CONFIG_ARCH_HAS_MEM_ENCRYPT=y
|
||||
CONFIG_ARCH_HAS_CC_PLATFORM=y
|
||||
CONFIG_HAVE_STATIC_CALL=y
|
||||
CONFIG_HAVE_STATIC_CALL_INLINE=y
|
||||
CONFIG_HAVE_PREEMPT_DYNAMIC=y
|
||||
CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y
|
||||
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
|
||||
CONFIG_ARCH_HAS_ELFCORE_COMPAT=y
|
||||
CONFIG_ARCH_HAS_PARANOID_L1D_FLUSH=y
|
||||
|
||||
#
|
||||
# GCOV-based kernel profiling
|
||||
@@ -775,16 +741,14 @@ CONFIG_BASE_SMALL=0
|
||||
# CONFIG_MODULES is not set
|
||||
CONFIG_MODULES_TREE_LOOKUP=y
|
||||
CONFIG_BLOCK=y
|
||||
CONFIG_BLK_SCSI_REQUEST=y
|
||||
CONFIG_BLK_CGROUP_RWSTAT=y
|
||||
CONFIG_BLK_DEV_BSG=y
|
||||
CONFIG_BLK_DEV_BSG_COMMON=y
|
||||
CONFIG_BLK_DEV_BSGLIB=y
|
||||
CONFIG_BLK_DEV_INTEGRITY=y
|
||||
CONFIG_BLK_DEV_INTEGRITY_T10=y
|
||||
# CONFIG_BLK_DEV_ZONED is not set
|
||||
CONFIG_BLK_DEV_THROTTLING=y
|
||||
# CONFIG_BLK_DEV_THROTTLING_LOW is not set
|
||||
CONFIG_BLK_CMDLINE_PARSER=y
|
||||
CONFIG_BLK_WBT=y
|
||||
CONFIG_BLK_WBT_MQ=y
|
||||
# CONFIG_BLK_CGROUP_IOLATENCY is not set
|
||||
@@ -818,6 +782,7 @@ CONFIG_EFI_PARTITION=y
|
||||
CONFIG_BLK_MQ_PCI=y
|
||||
CONFIG_BLK_MQ_VIRTIO=y
|
||||
CONFIG_BLK_PM=y
|
||||
CONFIG_BLOCK_HOLDER_DEPRECATED=y
|
||||
|
||||
#
|
||||
# IO Schedulers
|
||||
@@ -934,6 +899,12 @@ CONFIG_PERCPU_STATS=y
|
||||
# CONFIG_READ_ONLY_THP_FOR_FS is not set
|
||||
CONFIG_ARCH_HAS_PTE_SPECIAL=y
|
||||
CONFIG_SECRETMEM=y
|
||||
|
||||
#
|
||||
# Data Access Monitoring
|
||||
#
|
||||
# CONFIG_DAMON is not set
|
||||
# end of Data Access Monitoring
|
||||
# end of Memory Management options
|
||||
|
||||
CONFIG_NET=y
|
||||
@@ -946,6 +917,7 @@ CONFIG_PACKET=y
|
||||
CONFIG_PACKET_DIAG=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_UNIX_SCM=y
|
||||
CONFIG_AF_UNIX_OOB=y
|
||||
CONFIG_UNIX_DIAG=y
|
||||
CONFIG_TLS=y
|
||||
# CONFIG_TLS_DEVICE is not set
|
||||
@@ -1050,6 +1022,7 @@ CONFIG_NET_FLOW_LIMIT=y
|
||||
# CONFIG_AF_RXRPC is not set
|
||||
# CONFIG_AF_KCM is not set
|
||||
CONFIG_STREAM_PARSER=y
|
||||
# CONFIG_MCTP is not set
|
||||
# CONFIG_WIRELESS is not set
|
||||
# CONFIG_RFKILL is not set
|
||||
# CONFIG_NET_9P is not set
|
||||
@@ -1186,6 +1159,53 @@ CONFIG_GENERIC_CPU_VULNERABILITIES=y
|
||||
|
||||
CONFIG_CONNECTOR=y
|
||||
CONFIG_PROC_EVENTS=y
|
||||
|
||||
#
|
||||
# Firmware Drivers
|
||||
#
|
||||
|
||||
#
|
||||
# ARM System Control and Management Interface Protocol
|
||||
#
|
||||
# end of ARM System Control and Management Interface Protocol
|
||||
|
||||
# CONFIG_EDD is not set
|
||||
CONFIG_FIRMWARE_MEMMAP=y
|
||||
CONFIG_DMIID=y
|
||||
CONFIG_DMI_SYSFS=y
|
||||
CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
|
||||
# CONFIG_FW_CFG_SYSFS is not set
|
||||
CONFIG_SYSFB=y
|
||||
# CONFIG_SYSFB_SIMPLEFB is not set
|
||||
# CONFIG_GOOGLE_FIRMWARE is not set
|
||||
|
||||
#
|
||||
# EFI (Extensible Firmware Interface) Support
|
||||
#
|
||||
# CONFIG_EFI_VARS is not set
|
||||
CONFIG_EFI_ESRT=y
|
||||
CONFIG_EFI_RUNTIME_MAP=y
|
||||
# CONFIG_EFI_FAKE_MEMMAP is not set
|
||||
CONFIG_EFI_RUNTIME_WRAPPERS=y
|
||||
CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
|
||||
# CONFIG_EFI_BOOTLOADER_CONTROL is not set
|
||||
# CONFIG_EFI_CAPSULE_LOADER is not set
|
||||
# CONFIG_EFI_TEST is not set
|
||||
# CONFIG_APPLE_PROPERTIES is not set
|
||||
# CONFIG_RESET_ATTACK_MITIGATION is not set
|
||||
# CONFIG_EFI_RCI2_TABLE is not set
|
||||
# CONFIG_EFI_DISABLE_PCI_DMA is not set
|
||||
# end of EFI (Extensible Firmware Interface) Support
|
||||
|
||||
CONFIG_EFI_EARLYCON=y
|
||||
# CONFIG_EFI_CUSTOM_SSDT_OVERLAYS is not set
|
||||
|
||||
#
|
||||
# Tegra firmware driver
|
||||
#
|
||||
# end of Tegra firmware driver
|
||||
# end of Firmware Drivers
|
||||
|
||||
# CONFIG_GNSS is not set
|
||||
# CONFIG_MTD is not set
|
||||
# CONFIG_OF is not set
|
||||
@@ -1385,7 +1405,6 @@ CONFIG_VIRTIO_NET=y
|
||||
# CONFIG_NETDEVSIM is not set
|
||||
CONFIG_NET_FAILOVER=y
|
||||
# CONFIG_ISDN is not set
|
||||
# CONFIG_NVM is not set
|
||||
|
||||
#
|
||||
# Input device support
|
||||
@@ -1534,10 +1553,9 @@ CONFIG_HANGCHECK_TIMER=y
|
||||
# CONFIG_TCG_TPM is not set
|
||||
# CONFIG_TELCLOCK is not set
|
||||
# CONFIG_XILLYBUS is not set
|
||||
# end of Character devices
|
||||
|
||||
# CONFIG_RANDOM_TRUST_CPU is not set
|
||||
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
|
||||
# end of Character devices
|
||||
|
||||
#
|
||||
# I2C support
|
||||
@@ -1567,13 +1585,13 @@ CONFIG_PPS=y
|
||||
# PTP clock support
|
||||
#
|
||||
CONFIG_PTP_1588_CLOCK=y
|
||||
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
|
||||
|
||||
#
|
||||
# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
|
||||
#
|
||||
CONFIG_PTP_1588_CLOCK_KVM=y
|
||||
# CONFIG_PTP_1588_CLOCK_VMW is not set
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# end of PTP clock support
|
||||
|
||||
# CONFIG_PINCTRL is not set
|
||||
@@ -1629,6 +1647,7 @@ CONFIG_GPIO_PCI_IDIO_16=y
|
||||
#
|
||||
# CONFIG_GPIO_AGGREGATOR is not set
|
||||
# CONFIG_GPIO_MOCKUP is not set
|
||||
# CONFIG_GPIO_VIRTIO is not set
|
||||
# end of Virtual GPIO drivers
|
||||
|
||||
# CONFIG_W1 is not set
|
||||
@@ -1665,6 +1684,7 @@ CONFIG_X86_THERMAL_VECTOR=y
|
||||
|
||||
# CONFIG_INTEL_PCH_THERMAL is not set
|
||||
# CONFIG_INTEL_TCC_COOLING is not set
|
||||
# CONFIG_INTEL_MENLOW is not set
|
||||
# end of Intel thermal drivers
|
||||
|
||||
CONFIG_WATCHDOG=y
|
||||
@@ -1884,7 +1904,6 @@ CONFIG_HID_GENERIC=y
|
||||
# CONFIG_HID_AUREAL is not set
|
||||
# CONFIG_HID_BELKIN is not set
|
||||
# CONFIG_HID_CHERRY is not set
|
||||
# CONFIG_HID_CHICONY is not set
|
||||
# CONFIG_HID_COUGAR is not set
|
||||
# CONFIG_HID_MACALLY is not set
|
||||
# CONFIG_HID_CMEDIA is not set
|
||||
@@ -1925,7 +1944,6 @@ CONFIG_HID_REDRAGON=y
|
||||
# CONFIG_HID_PLAYSTATION is not set
|
||||
# CONFIG_HID_PRIMAX is not set
|
||||
# CONFIG_HID_SAITEK is not set
|
||||
# CONFIG_HID_SAMSUNG is not set
|
||||
# CONFIG_HID_SEMITEK is not set
|
||||
# CONFIG_HID_SPEEDLINK is not set
|
||||
# CONFIG_HID_STEAM is not set
|
||||
@@ -1982,9 +2000,10 @@ CONFIG_DMA_VIRTUAL_CHANNELS=y
|
||||
CONFIG_DMA_ACPI=y
|
||||
# CONFIG_ALTERA_MSGDMA is not set
|
||||
# CONFIG_INTEL_IDMA64 is not set
|
||||
# CONFIG_INTEL_IDXD is not set
|
||||
# CONFIG_INTEL_IDXD_COMPAT is not set
|
||||
# CONFIG_INTEL_IOATDMA is not set
|
||||
# CONFIG_PLX_DMA is not set
|
||||
# CONFIG_AMD_PTDMA is not set
|
||||
# CONFIG_QCOM_HIDMA_MGMT is not set
|
||||
# CONFIG_QCOM_HIDMA is not set
|
||||
CONFIG_DW_DMAC_CORE=y
|
||||
@@ -2006,8 +2025,6 @@ CONFIG_HSU_DMA=y
|
||||
# DMABUF options
|
||||
#
|
||||
# CONFIG_SYNC_FILE is not set
|
||||
# CONFIG_DMABUF_MOVE_NOTIFY is not set
|
||||
# CONFIG_DMABUF_DEBUG is not set
|
||||
# CONFIG_DMABUF_HEAPS is not set
|
||||
# end of DMABUF options
|
||||
|
||||
@@ -2023,14 +2040,15 @@ CONFIG_UIO_DMEM_GENIRQ=y
|
||||
# CONFIG_UIO_PRUSS is not set
|
||||
# CONFIG_UIO_MF624 is not set
|
||||
# CONFIG_UIO_HV_GENERIC is not set
|
||||
CONFIG_VFIO=y
|
||||
CONFIG_VFIO_IOMMU_TYPE1=y
|
||||
CONFIG_VFIO_VIRQFD=y
|
||||
CONFIG_VFIO=y
|
||||
# CONFIG_VFIO_NOIOMMU is not set
|
||||
CONFIG_VFIO_PCI=y
|
||||
# CONFIG_VFIO_PCI_VGA is not set
|
||||
CONFIG_VFIO_PCI_CORE=y
|
||||
CONFIG_VFIO_PCI_MMAP=y
|
||||
CONFIG_VFIO_PCI_INTX=y
|
||||
CONFIG_VFIO_PCI=y
|
||||
# CONFIG_VFIO_PCI_VGA is not set
|
||||
# CONFIG_VFIO_PCI_IGD is not set
|
||||
# CONFIG_VFIO_MDEV is not set
|
||||
CONFIG_IRQ_BYPASS_MANAGER=y
|
||||
@@ -2102,6 +2120,8 @@ CONFIG_IOMMU_SUPPORT=y
|
||||
# end of Generic IOMMU Pagetable Support
|
||||
|
||||
# CONFIG_IOMMU_DEBUGFS is not set
|
||||
# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set
|
||||
CONFIG_IOMMU_DEFAULT_DMA_LAZY=y
|
||||
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
|
||||
CONFIG_IOMMU_DMA=y
|
||||
# CONFIG_AMD_IOMMU is not set
|
||||
@@ -2272,7 +2292,6 @@ CONFIG_FS_POSIX_ACL=y
|
||||
CONFIG_EXPORTFS=y
|
||||
# CONFIG_EXPORTFS_BLOCK_OPS is not set
|
||||
CONFIG_FILE_LOCKING=y
|
||||
CONFIG_MANDATORY_FILE_LOCKING=y
|
||||
CONFIG_FS_ENCRYPTION=y
|
||||
CONFIG_FS_ENCRYPTION_ALGS=y
|
||||
# CONFIG_FS_VERITY is not set
|
||||
@@ -2301,12 +2320,9 @@ CONFIG_NETFS_SUPPORT=y
|
||||
# CONFIG_NETFS_STATS is not set
|
||||
CONFIG_FSCACHE=y
|
||||
# CONFIG_FSCACHE_STATS is not set
|
||||
# CONFIG_FSCACHE_HISTOGRAM is not set
|
||||
# CONFIG_FSCACHE_DEBUG is not set
|
||||
# CONFIG_FSCACHE_OBJECT_LIST is not set
|
||||
CONFIG_CACHEFILES=y
|
||||
# CONFIG_CACHEFILES_DEBUG is not set
|
||||
# CONFIG_CACHEFILES_HISTOGRAM is not set
|
||||
# end of Caches
|
||||
|
||||
#
|
||||
@@ -2327,6 +2343,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
|
||||
# CONFIG_FAT_DEFAULT_UTF8 is not set
|
||||
# CONFIG_EXFAT_FS is not set
|
||||
# CONFIG_NTFS_FS is not set
|
||||
# CONFIG_NTFS3_FS is not set
|
||||
# end of DOS/FAT/EXFAT/NT Filesystems
|
||||
|
||||
#
|
||||
@@ -2442,6 +2459,8 @@ CONFIG_LSM="yama,loadpin,safesetid,integrity"
|
||||
CONFIG_INIT_STACK_NONE=y
|
||||
# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
|
||||
# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
|
||||
CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y
|
||||
# CONFIG_ZERO_CALL_USED_REGS is not set
|
||||
# end of Memory initialization
|
||||
# end of Kernel hardening options
|
||||
# end of Security options
|
||||
@@ -2587,6 +2606,8 @@ CONFIG_CRYPTO_DES=y
|
||||
# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set
|
||||
# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set
|
||||
# CONFIG_CRYPTO_SM4 is not set
|
||||
# CONFIG_CRYPTO_SM4_AESNI_AVX_X86_64 is not set
|
||||
# CONFIG_CRYPTO_SM4_AESNI_AVX2_X86_64 is not set
|
||||
# CONFIG_CRYPTO_TWOFISH is not set
|
||||
CONFIG_CRYPTO_TWOFISH_COMMON=y
|
||||
CONFIG_CRYPTO_TWOFISH_X86_64=y
|
||||
@@ -2792,6 +2813,8 @@ CONFIG_HAVE_ARCH_KGDB=y
|
||||
CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
|
||||
# CONFIG_UBSAN is not set
|
||||
CONFIG_HAVE_ARCH_KCSAN=y
|
||||
CONFIG_HAVE_KCSAN_COMPILER=y
|
||||
# CONFIG_KCSAN is not set
|
||||
# end of Generic Kernel Debugging Instruments
|
||||
|
||||
CONFIG_DEBUG_KERNEL=y
|
||||
@@ -2908,7 +2931,6 @@ CONFIG_RCU_CPU_STALL_TIMEOUT=59
|
||||
# end of RCU Debugging
|
||||
|
||||
# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
|
||||
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
|
||||
# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
|
||||
# CONFIG_LATENCYTOP is not set
|
||||
CONFIG_USER_STACKTRACE_SUPPORT=y
|
||||
@@ -2934,7 +2956,6 @@ CONFIG_STRICT_DEVMEM=y
|
||||
#
|
||||
# x86 Debugging
|
||||
#
|
||||
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
|
||||
CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y
|
||||
CONFIG_X86_VERBOSE_BOOTUP=y
|
||||
CONFIG_EARLY_PRINTK=y
|
||||
@@ -2971,7 +2992,6 @@ CONFIG_CC_HAS_SANCOV_TRACE_PC=y
|
||||
CONFIG_RUNTIME_TESTING_MENU=y
|
||||
# CONFIG_LKDTM is not set
|
||||
# CONFIG_TEST_MIN_HEAP is not set
|
||||
# CONFIG_TEST_SORT is not set
|
||||
# CONFIG_TEST_DIV64 is not set
|
||||
# CONFIG_BACKTRACE_SELF_TEST is not set
|
||||
# CONFIG_RBTREE_TEST is not set
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
Name: cloud-hypervisor
|
||||
Summary: Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM.
|
||||
Version: 20.0
|
||||
Version: 21.1
|
||||
Release: 0%{?dist}
|
||||
License: ASL 2.0 or BSD-3-clause
|
||||
Group: Applications/System
|
||||
@@ -112,6 +112,12 @@ rm -rf %{buildroot}
|
||||
|
||||
|
||||
%changelog
|
||||
* Thu Mar 10 2022 Rob Bradford <robert.bradford@intel.com> 21.1-0
|
||||
- Update to 21.1
|
||||
|
||||
* Thu Jan 20 2022 Rob Bradford <robert.bradford@intel.com> 21.0-0
|
||||
- Update to 21.0
|
||||
|
||||
* Thu Dec 02 2021 Sebastien Boeuf <sebastien.boeuf@intel.com> 20.0-0
|
||||
- Update to 20.0
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
rm /tmp/ubuntu-cloudinit.img
|
||||
rm -f /tmp/ubuntu-cloudinit.img
|
||||
mkdosfs -n cidata -C /tmp/ubuntu-cloudinit.img 8192
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/user-data ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/meta-data ::
|
||||
|
||||
@@ -54,7 +54,7 @@ checkout_repo() {
|
||||
build_custom_linux() {
|
||||
SRCDIR=$PWD
|
||||
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
||||
LINUX_CUSTOM_BRANCH="ch-5.14"
|
||||
LINUX_CUSTOM_BRANCH="ch-5.15.12"
|
||||
LINUX_CUSTOM_URL="https://github.com/cloud-hypervisor/linux.git"
|
||||
|
||||
checkout_repo "$LINUX_CUSTOM_DIR" "$LINUX_CUSTOM_URL" "$LINUX_CUSTOM_BRANCH"
|
||||
@@ -102,6 +102,25 @@ build_edk2() {
|
||||
popd
|
||||
}
|
||||
|
||||
build_spdk_nvme() {
|
||||
SPDK_DIR="$WORKLOADS_DIR/spdk"
|
||||
SPDK_REPO="https://github.com/spdk/spdk.git"
|
||||
checkout_repo "$SPDK_DIR" "$SPDK_REPO" master "f9c496b8e21a8f499df268818bf8b5d8e2b19f04"
|
||||
|
||||
pushd $SPDK_DIR
|
||||
git submodule update --init
|
||||
apt-get update
|
||||
./scripts/pkgdep.sh
|
||||
./configure --with-vfio-user
|
||||
chmod +x /usr/local/lib/python3.8/dist-packages/ninja/data/bin/ninja
|
||||
make -j `nproc`
|
||||
mkdir /usr/local/bin/spdk-nvme
|
||||
cp ./build/bin/nvmf_tgt /usr/local/bin/spdk-nvme
|
||||
cp ./scripts/rpc.py /usr/local/bin/spdk-nvme
|
||||
cp -r ./scripts/rpc /usr/local/bin/spdk-nvme
|
||||
popd
|
||||
}
|
||||
|
||||
update_workloads() {
|
||||
cp scripts/sha1sums-aarch64 $WORKLOADS_DIR
|
||||
|
||||
@@ -233,6 +252,9 @@ update_workloads() {
|
||||
echo "bar" > "$SHARED_DIR/file3" || exit 1
|
||||
fi
|
||||
|
||||
# checkout and build SPDK NVMe
|
||||
build_spdk_nvme
|
||||
|
||||
# Check and build EDK2 binary
|
||||
build_edk2
|
||||
}
|
||||
@@ -245,8 +267,8 @@ if [[ "$hypervisor" = "mshv" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
features_build=""
|
||||
features_test="--features integration_tests"
|
||||
# For now these values are deafult for kvm
|
||||
features=""
|
||||
|
||||
# lock the workloads folder to avoid parallel updating by different containers
|
||||
(
|
||||
@@ -273,7 +295,7 @@ fi
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
# Test without ACPI
|
||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
||||
cargo build --all --release $features --target $BUILD_TARGET
|
||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||
strip target/$BUILD_TARGET/release/vhost_user_net
|
||||
strip target/$BUILD_TARGET/release/ch-remote
|
||||
@@ -284,17 +306,18 @@ sudo bash -c "echo 1000000 > /sys/kernel/mm/ksm/pages_to_scan"
|
||||
sudo bash -c "echo 10 > /sys/kernel/mm/ksm/sleep_millisecs"
|
||||
sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
|
||||
|
||||
# Setup huge-pages for ovs-dpdk
|
||||
echo 2048 | sudo tee /proc/sys/vm/nr_hugepages
|
||||
# Both test_vfio and ovs-dpdk rely on hugepages
|
||||
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
# Run all direct kernel boot (Device Tree) test cases in mod `parallel`
|
||||
time cargo test $features_test "tests::parallel::$test_filter"
|
||||
time cargo test $features "parallel::$test_filter"
|
||||
RES=$?
|
||||
|
||||
# Run some tests in sequence since the result could be affected by other tests
|
||||
# running in parallel.
|
||||
if [ $RES -eq 0 ]; then
|
||||
time cargo test $features_test "tests::sequential::$test_filter" -- --test-threads=1
|
||||
time cargo test $features "sequential::$test_filter" -- --test-threads=1
|
||||
RES=$?
|
||||
else
|
||||
exit $RES
|
||||
@@ -302,7 +325,7 @@ fi
|
||||
|
||||
# Run all ACPI test cases
|
||||
if [ $RES -eq 0 ]; then
|
||||
time cargo test $features_test "tests::aarch64_acpi::$test_filter"
|
||||
time cargo test $features "aarch64_acpi::$test_filter"
|
||||
RES=$?
|
||||
else
|
||||
exit $RES
|
||||
@@ -310,7 +333,7 @@ fi
|
||||
|
||||
# Run all test cases related to live migration
|
||||
if [ $RES -eq 0 ]; then
|
||||
time cargo test $features_test "tests::live_migration::$test_filter" -- --test-threads=1
|
||||
time cargo test $features "live_migration::$test_filter" -- --test-threads=1
|
||||
RES=$?
|
||||
else
|
||||
exit $RES
|
||||
|
||||
@@ -11,13 +11,11 @@ mkdir -p "$WORKLOADS_DIR"
|
||||
|
||||
process_common_args "$@"
|
||||
|
||||
# For now these values are deafult for kvm
|
||||
features_build=""
|
||||
features_test="--features integration_tests"
|
||||
# For now these values are default for kvm
|
||||
features=""
|
||||
|
||||
if [ "$hypervisor" = "mshv" ] ; then
|
||||
features_build="--no-default-features --features mshv,common"
|
||||
features_test="--no-default-features --features mshv,common,integration_tests"
|
||||
features="--no-default-features --features mshv,common"
|
||||
fi
|
||||
|
||||
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||
@@ -55,7 +53,7 @@ LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||
SRCDIR=$PWD
|
||||
pushd $WORKLOADS_DIR
|
||||
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-5.14" $LINUX_CUSTOM_DIR
|
||||
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-5.15.12" $LINUX_CUSTOM_DIR
|
||||
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
|
||||
popd
|
||||
fi
|
||||
@@ -79,7 +77,7 @@ if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
||||
cargo build --all --release $features --target $BUILD_TARGET
|
||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||
strip target/$BUILD_TARGET/release/vhost_user_net
|
||||
strip target/$BUILD_TARGET/release/ch-remote
|
||||
@@ -89,7 +87,7 @@ echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
time cargo test $features_test "tests::live_migration::$test_filter" -- --test-threads=1
|
||||
time cargo test $features "live_migration::$test_filter" -- --test-threads=1
|
||||
RES=$?
|
||||
|
||||
exit $RES
|
||||
|
||||
@@ -11,9 +11,8 @@ if [[ "$hypervisor" = "mshv" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# For now these values are deafult for kvm
|
||||
features_build=""
|
||||
features_test="--features integration_tests"
|
||||
# For now these values are default for kvm
|
||||
features=""
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
@@ -23,12 +22,12 @@ TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
||||
cargo build --all --release $features --target $BUILD_TARGET
|
||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
time cargo test $features_test "tests::sgx::$test_filter"
|
||||
time cargo test $features "sgx::$test_filter"
|
||||
RES=$?
|
||||
|
||||
exit $RES
|
||||
|
||||
@@ -5,9 +5,8 @@ source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
|
||||
process_common_args "$@"
|
||||
# For now these values are deafult for kvm
|
||||
features_build=""
|
||||
features_test="--features integration_tests"
|
||||
# For now these values are default for kvm
|
||||
features=""
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
@@ -17,12 +16,12 @@ TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
||||
cargo build --all --release $features --target $BUILD_TARGET
|
||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
time cargo test $features_test "tests::vfio::$test_filter" -- --test-threads=1
|
||||
time cargo test $features "vfio::$test_filter" -- --test-threads=1
|
||||
RES=$?
|
||||
|
||||
exit $RES
|
||||
|
||||
@@ -5,16 +5,23 @@ source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
|
||||
process_common_args "$@"
|
||||
# For now these values are deafult for kvm
|
||||
features_build=""
|
||||
features_test="--features integration_tests"
|
||||
# For now these values are default for kvm
|
||||
features=""
|
||||
|
||||
if [ "$hypervisor" = "mshv" ] ; then
|
||||
features_build="--no-default-features --features mshv,common"
|
||||
features_test="--no-default-features --features mshv,common,integration_tests"
|
||||
features="--no-default-features --features mshv,common"
|
||||
fi
|
||||
WIN_IMAGE_FILE="/root/workloads/windows-server-2019.raw"
|
||||
OVMF_FW_FILE="/root/workloads/OVMF-4b47d0c6c8.fd"
|
||||
|
||||
WORKLOADS_DIR="/root/workloads"
|
||||
OVMF_FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/edk2/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
OVMF_FW="$WORKLOADS_DIR/CLOUDHV.fd"
|
||||
if [ ! -f "$OVMF_FW" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $OVMF_FW_URL || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
@@ -24,7 +31,7 @@ CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
# Check if the images are present
|
||||
if [[ ! -f ${WIN_IMAGE_FILE} || ! -f ${OVMF_FW_FILE} ]]; then
|
||||
if [[ ! -f ${WIN_IMAGE_FILE} || ! -f ${OVMF_FW} ]]; then
|
||||
echo "Windows image/firmware not present in the host"
|
||||
exit 1
|
||||
fi
|
||||
@@ -37,14 +44,14 @@ dmsetup mknodes
|
||||
dmsetup create windows-snapshot-base --table "0 $img_blk_size snapshot-origin /dev/mapper/windows-base"
|
||||
dmsetup mknodes
|
||||
|
||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
||||
cargo build --all --release $features --target $BUILD_TARGET
|
||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
# Only run with 1 thread to avoid tests interfering with one another because
|
||||
# Windows has a static IP configured
|
||||
time cargo test $features_test "tests::windows::$test_filter"
|
||||
time cargo test $features "windows::$test_filter"
|
||||
RES=$?
|
||||
|
||||
dmsetup remove_all -f
|
||||
|
||||
@@ -11,13 +11,11 @@ mkdir -p "$WORKLOADS_DIR"
|
||||
|
||||
process_common_args "$@"
|
||||
|
||||
# For now these values are deafult for kvm
|
||||
features_build=""
|
||||
features_test="--features integration_tests"
|
||||
# For now these values are default for kvm
|
||||
features=""
|
||||
|
||||
if [ "$hypervisor" = "mshv" ] ; then
|
||||
features_build="--no-default-features --features mshv,common"
|
||||
features_test="--no-default-features --features mshv,common,integration_tests"
|
||||
features="--no-default-features --features mshv,common"
|
||||
fi
|
||||
|
||||
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||
@@ -30,6 +28,14 @@ if [ ! -f "$FW" ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
OVMF_FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/edk2/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
OVMF_FW="$WORKLOADS_DIR/CLOUDHV.fd"
|
||||
if [ ! -f "$OVMF_FW" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $OVMF_FW_URL || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
BIONIC_OS_IMAGE_NAME="bionic-server-cloudimg-amd64.qcow2"
|
||||
BIONIC_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$BIONIC_OS_IMAGE_NAME"
|
||||
BIONIC_OS_IMAGE="$WORKLOADS_DIR/$BIONIC_OS_IMAGE_NAME"
|
||||
@@ -107,7 +113,7 @@ LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||
SRCDIR=$PWD
|
||||
pushd $WORKLOADS_DIR
|
||||
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-5.14" $LINUX_CUSTOM_DIR
|
||||
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-5.15.12" $LINUX_CUSTOM_DIR
|
||||
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
|
||||
popd
|
||||
fi
|
||||
@@ -175,7 +181,7 @@ TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
||||
cargo build --all --release $features --target $BUILD_TARGET
|
||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||
strip target/$BUILD_TARGET/release/vhost_user_net
|
||||
strip target/$BUILD_TARGET/release/ch-remote
|
||||
@@ -195,14 +201,14 @@ echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
time cargo test $features_test "tests::parallel::$test_filter"
|
||||
time cargo test $features "parallel::$test_filter"
|
||||
RES=$?
|
||||
|
||||
# Run some tests in sequence since the result could be affected by other tests
|
||||
# running in parallel.
|
||||
if [ $RES -eq 0 ]; then
|
||||
export RUST_BACKTRACE=1
|
||||
time cargo test $features_test "tests::sequential::$test_filter" -- --test-threads=1
|
||||
time cargo test $features "sequential::$test_filter" -- --test-threads=1
|
||||
RES=$?
|
||||
fi
|
||||
|
||||
|
||||
@@ -13,4 +13,4 @@ if [[ $(uname -m) = "aarch64" || $hypervisor = "mshv" ]]; then
|
||||
cargo_args+=("--features $hypervisor")
|
||||
fi
|
||||
export RUST_BACKTRACE=1
|
||||
cargo test --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1;
|
||||
cargo test --lib --bins --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1;
|
||||
|
||||
@@ -9,7 +9,7 @@ extern crate clap;
|
||||
use api_client::simple_api_command;
|
||||
use api_client::simple_api_command_with_fds;
|
||||
use api_client::Error as ApiClientError;
|
||||
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||
use clap::{App, AppSettings, Arg, ArgMatches};
|
||||
use option_parser::{ByteSized, ByteSizedParseError};
|
||||
use std::fmt;
|
||||
use std::os::unix::net::UnixStream;
|
||||
@@ -263,9 +263,14 @@ fn receive_migration_api_command(socket: &mut UnixStream, url: &str) -> Result<(
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn send_migration_api_command(socket: &mut UnixStream, url: &str) -> Result<(), Error> {
|
||||
fn send_migration_api_command(
|
||||
socket: &mut UnixStream,
|
||||
url: &str,
|
||||
local: bool,
|
||||
) -> Result<(), Error> {
|
||||
let send_migration_data = vmm::api::VmSendMigrationData {
|
||||
destination_url: url.to_owned(),
|
||||
local,
|
||||
};
|
||||
simple_api_command(
|
||||
socket,
|
||||
@@ -402,6 +407,10 @@ fn do_command(matches: &ArgMatches) -> Result<(), Error> {
|
||||
.unwrap()
|
||||
.value_of("send_migration_config")
|
||||
.unwrap(),
|
||||
matches
|
||||
.subcommand_matches("send-migration")
|
||||
.unwrap()
|
||||
.is_present("send_migration_local"),
|
||||
),
|
||||
Some("receive-migration") => receive_migration_api_command(
|
||||
&mut socket,
|
||||
@@ -422,7 +431,7 @@ fn main() {
|
||||
.setting(AppSettings::SubcommandRequired)
|
||||
.about("Remotely control a cloud-hypervisor VMM.")
|
||||
.arg(
|
||||
Arg::with_name("api-socket")
|
||||
Arg::new("api-socket")
|
||||
.long("api-socket")
|
||||
.help("HTTP API socket path (UNIX domain socket).")
|
||||
.takes_value(true)
|
||||
@@ -430,97 +439,89 @@ fn main() {
|
||||
.required(true),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("add-device")
|
||||
.about("Add VFIO device")
|
||||
.arg(
|
||||
Arg::with_name("device_config")
|
||||
.index(1)
|
||||
.help(vmm::config::DeviceConfig::SYNTAX),
|
||||
),
|
||||
App::new("add-device").about("Add VFIO device").arg(
|
||||
Arg::new("device_config")
|
||||
.index(1)
|
||||
.help(vmm::config::DeviceConfig::SYNTAX),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("add-disk")
|
||||
.about("Add block device")
|
||||
.arg(
|
||||
Arg::with_name("disk_config")
|
||||
.index(1)
|
||||
.help(vmm::config::DiskConfig::SYNTAX),
|
||||
),
|
||||
App::new("add-disk").about("Add block device").arg(
|
||||
Arg::new("disk_config")
|
||||
.index(1)
|
||||
.help(vmm::config::DiskConfig::SYNTAX),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("add-fs")
|
||||
App::new("add-fs")
|
||||
.about("Add virtio-fs backed fs device")
|
||||
.arg(
|
||||
Arg::with_name("fs_config")
|
||||
Arg::new("fs_config")
|
||||
.index(1)
|
||||
.help(vmm::config::FsConfig::SYNTAX),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("add-pmem")
|
||||
App::new("add-pmem")
|
||||
.about("Add persistent memory device")
|
||||
.arg(
|
||||
Arg::with_name("pmem_config")
|
||||
Arg::new("pmem_config")
|
||||
.index(1)
|
||||
.help(vmm::config::PmemConfig::SYNTAX),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("add-net")
|
||||
.about("Add network device")
|
||||
.arg(
|
||||
Arg::with_name("net_config")
|
||||
.index(1)
|
||||
.help(vmm::config::NetConfig::SYNTAX),
|
||||
),
|
||||
App::new("add-net").about("Add network device").arg(
|
||||
Arg::new("net_config")
|
||||
.index(1)
|
||||
.help(vmm::config::NetConfig::SYNTAX),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("add-user-device")
|
||||
App::new("add-user-device")
|
||||
.about("Add userspace device")
|
||||
.arg(
|
||||
Arg::with_name("device_config")
|
||||
Arg::new("device_config")
|
||||
.index(1)
|
||||
.help(vmm::config::UserDeviceConfig::SYNTAX),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("add-vsock")
|
||||
.about("Add vsock device")
|
||||
.arg(
|
||||
Arg::with_name("vsock_config")
|
||||
.index(1)
|
||||
.help(vmm::config::VsockConfig::SYNTAX),
|
||||
),
|
||||
App::new("add-vsock").about("Add vsock device").arg(
|
||||
Arg::new("vsock_config")
|
||||
.index(1)
|
||||
.help(vmm::config::VsockConfig::SYNTAX),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("remove-device")
|
||||
App::new("remove-device")
|
||||
.about("Remove VFIO device")
|
||||
.arg(Arg::with_name("id").index(1).help("<device_id>")),
|
||||
.arg(Arg::new("id").index(1).help("<device_id>")),
|
||||
)
|
||||
.subcommand(SubCommand::with_name("info").about("Info on the VM"))
|
||||
.subcommand(SubCommand::with_name("counters").about("Counters from the VM"))
|
||||
.subcommand(SubCommand::with_name("pause").about("Pause the VM"))
|
||||
.subcommand(SubCommand::with_name("reboot").about("Reboot the VM"))
|
||||
.subcommand(SubCommand::with_name("power-button").about("Trigger a power button in the VM"))
|
||||
.subcommand(App::new("info").about("Info on the VM"))
|
||||
.subcommand(App::new("counters").about("Counters from the VM"))
|
||||
.subcommand(App::new("pause").about("Pause the VM"))
|
||||
.subcommand(App::new("reboot").about("Reboot the VM"))
|
||||
.subcommand(App::new("power-button").about("Trigger a power button in the VM"))
|
||||
.subcommand(
|
||||
SubCommand::with_name("resize")
|
||||
App::new("resize")
|
||||
.about("Resize the VM")
|
||||
.arg(
|
||||
Arg::with_name("cpus")
|
||||
Arg::new("cpus")
|
||||
.long("cpus")
|
||||
.help("New vCPUs count")
|
||||
.takes_value(true)
|
||||
.number_of_values(1),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("memory")
|
||||
Arg::new("memory")
|
||||
.long("memory")
|
||||
.help("New memory size in bytes (supports K/M/G suffix)")
|
||||
.takes_value(true)
|
||||
.number_of_values(1),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("balloon")
|
||||
Arg::new("balloon")
|
||||
.long("balloon")
|
||||
.help("New balloon size in bytes (supports K/M/G suffix)")
|
||||
.takes_value(true)
|
||||
@@ -528,57 +529,58 @@ fn main() {
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("resize-zone")
|
||||
App::new("resize-zone")
|
||||
.about("Resize a memory zone")
|
||||
.arg(
|
||||
Arg::with_name("id")
|
||||
Arg::new("id")
|
||||
.long("id")
|
||||
.help("Memory zone identifier")
|
||||
.takes_value(true)
|
||||
.number_of_values(1),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("size")
|
||||
Arg::new("size")
|
||||
.long("size")
|
||||
.help("New memory zone size in bytes (supports K/M/G suffix)")
|
||||
.takes_value(true)
|
||||
.number_of_values(1),
|
||||
),
|
||||
)
|
||||
.subcommand(SubCommand::with_name("resume").about("Resume the VM"))
|
||||
.subcommand(SubCommand::with_name("shutdown").about("Shutdown the VM"))
|
||||
.subcommand(App::new("resume").about("Resume the VM"))
|
||||
.subcommand(App::new("shutdown").about("Shutdown the VM"))
|
||||
.subcommand(
|
||||
SubCommand::with_name("snapshot")
|
||||
.about("Create a snapshot from VM")
|
||||
.arg(
|
||||
Arg::with_name("snapshot_config")
|
||||
.index(1)
|
||||
.help("<destination_url>"),
|
||||
),
|
||||
App::new("snapshot").about("Create a snapshot from VM").arg(
|
||||
Arg::new("snapshot_config")
|
||||
.index(1)
|
||||
.help("<destination_url>"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("restore")
|
||||
.about("Restore VM from a snapshot")
|
||||
.arg(
|
||||
Arg::with_name("restore_config")
|
||||
.index(1)
|
||||
.help(vmm::config::RestoreConfig::SYNTAX),
|
||||
),
|
||||
App::new("restore").about("Restore VM from a snapshot").arg(
|
||||
Arg::new("restore_config")
|
||||
.index(1)
|
||||
.help(vmm::config::RestoreConfig::SYNTAX),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("send-migration")
|
||||
App::new("send-migration")
|
||||
.about("Initiate a VM migration")
|
||||
.arg(
|
||||
Arg::with_name("send_migration_config")
|
||||
Arg::new("send_migration_config")
|
||||
.index(1)
|
||||
.help("<destination_url>"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("send_migration_local")
|
||||
.long("local")
|
||||
.takes_value(false),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("receive-migration")
|
||||
App::new("receive-migration")
|
||||
.about("Receive a VM migration")
|
||||
.arg(
|
||||
Arg::with_name("receive_migration_config")
|
||||
Arg::new("receive_migration_config")
|
||||
.index(1)
|
||||
.help("<receiver_url>"),
|
||||
),
|
||||
|
||||
261
src/main.rs
261
src/main.rs
@@ -125,27 +125,22 @@ fn prepare_default_values() -> (String, String, String) {
|
||||
(default_vcpus, default_memory, default_rng)
|
||||
}
|
||||
|
||||
fn create_app<'a, 'b>(
|
||||
fn create_app<'a>(
|
||||
default_vcpus: &'a str,
|
||||
default_memory: &'a str,
|
||||
default_rng: &'a str,
|
||||
) -> App<'a, 'b> {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let mut app: App;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
let app: App;
|
||||
|
||||
app = App::new("cloud-hypervisor")
|
||||
) -> App<'a> {
|
||||
let app = App::new("cloud-hypervisor")
|
||||
// 'BUILT_VERSION' is set by the build script 'build.rs' at
|
||||
// compile time
|
||||
.version(env!("BUILT_VERSION"))
|
||||
.author(crate_authors!())
|
||||
.about("Launch a cloud-hypervisor VMM.")
|
||||
.group(ArgGroup::with_name("vm-config").multiple(true))
|
||||
.group(ArgGroup::with_name("vmm-config").multiple(true))
|
||||
.group(ArgGroup::with_name("logging").multiple(true))
|
||||
.group(ArgGroup::new("vm-config").multiple(true))
|
||||
.group(ArgGroup::new("vmm-config").multiple(true))
|
||||
.group(ArgGroup::new("logging").multiple(true))
|
||||
.arg(
|
||||
Arg::with_name("cpus")
|
||||
Arg::new("cpus")
|
||||
.long("cpus")
|
||||
.help(
|
||||
"boot=<boot_vcpus>,max=<max_vcpus>,\
|
||||
@@ -157,7 +152,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("platform")
|
||||
Arg::new("platform")
|
||||
.long("platform")
|
||||
.help(
|
||||
"num_pci_segments=<num pci segments>",
|
||||
@@ -166,7 +161,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("memory")
|
||||
Arg::new("memory")
|
||||
.long("memory")
|
||||
.help(
|
||||
"Memory parameters \
|
||||
@@ -181,7 +176,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("memory-zone")
|
||||
Arg::new("memory-zone")
|
||||
.long("memory-zone")
|
||||
.help(
|
||||
"User defined memory zone parameters \
|
||||
@@ -198,7 +193,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("kernel")
|
||||
Arg::new("kernel")
|
||||
.long("kernel")
|
||||
.help(
|
||||
"Path to loaded kernel. This may be a kernel or firmware that supports a PVH \
|
||||
@@ -208,21 +203,21 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("initramfs")
|
||||
Arg::new("initramfs")
|
||||
.long("initramfs")
|
||||
.help("Path to initramfs image")
|
||||
.takes_value(true)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("cmdline")
|
||||
Arg::new("cmdline")
|
||||
.long("cmdline")
|
||||
.help("Kernel command line")
|
||||
.takes_value(true)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("disk")
|
||||
Arg::new("disk")
|
||||
.long("disk")
|
||||
.help(config::DiskConfig::SYNTAX)
|
||||
.takes_value(true)
|
||||
@@ -230,7 +225,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("net")
|
||||
Arg::new("net")
|
||||
.long("net")
|
||||
.help(config::NetConfig::SYNTAX)
|
||||
.takes_value(true)
|
||||
@@ -238,7 +233,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("rng")
|
||||
Arg::new("rng")
|
||||
.long("rng")
|
||||
.help(
|
||||
"Random number generator parameters \"src=<entropy_source_path>,iommu=on|off\"",
|
||||
@@ -247,14 +242,14 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("balloon")
|
||||
Arg::new("balloon")
|
||||
.long("balloon")
|
||||
.help(config::BalloonConfig::SYNTAX)
|
||||
.takes_value(true)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("fs")
|
||||
Arg::new("fs")
|
||||
.long("fs")
|
||||
.help(config::FsConfig::SYNTAX)
|
||||
.takes_value(true)
|
||||
@@ -262,7 +257,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("pmem")
|
||||
Arg::new("pmem")
|
||||
.long("pmem")
|
||||
.help(config::PmemConfig::SYNTAX)
|
||||
.takes_value(true)
|
||||
@@ -270,14 +265,14 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("serial")
|
||||
Arg::new("serial")
|
||||
.long("serial")
|
||||
.help("Control serial port: off|null|pty|tty|file=/path/to/a/file")
|
||||
.default_value("null")
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("console")
|
||||
Arg::new("console")
|
||||
.long("console")
|
||||
.help(
|
||||
"Control (virtio) console: \"off|null|pty|tty|file=/path/to/a/file,iommu=on|off\"",
|
||||
@@ -286,7 +281,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("device")
|
||||
Arg::new("device")
|
||||
.long("device")
|
||||
.help(config::DeviceConfig::SYNTAX)
|
||||
.takes_value(true)
|
||||
@@ -294,7 +289,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("user-device")
|
||||
Arg::new("user-device")
|
||||
.long("user-device")
|
||||
.help(config::UserDeviceConfig::SYNTAX)
|
||||
.takes_value(true)
|
||||
@@ -302,7 +297,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("vsock")
|
||||
Arg::new("vsock")
|
||||
.long("vsock")
|
||||
.help(config::VsockConfig::SYNTAX)
|
||||
.takes_value(true)
|
||||
@@ -310,7 +305,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("numa")
|
||||
Arg::new("numa")
|
||||
.long("numa")
|
||||
.help(config::NumaConfig::SYNTAX)
|
||||
.takes_value(true)
|
||||
@@ -318,21 +313,21 @@ fn create_app<'a, 'b>(
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("watchdog")
|
||||
Arg::new("watchdog")
|
||||
.long("watchdog")
|
||||
.help("Enable virtio-watchdog")
|
||||
.takes_value(false)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("v")
|
||||
.short("v")
|
||||
.multiple(true)
|
||||
Arg::new("v")
|
||||
.short('v')
|
||||
.multiple_occurrences(true)
|
||||
.help("Sets the level of debugging output")
|
||||
.group("logging"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("log-file")
|
||||
Arg::new("log-file")
|
||||
.long("log-file")
|
||||
.help("Log file. Standard error is used if not specified")
|
||||
.takes_value(true)
|
||||
@@ -340,7 +335,7 @@ fn create_app<'a, 'b>(
|
||||
.group("logging"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("api-socket")
|
||||
Arg::new("api-socket")
|
||||
.long("api-socket")
|
||||
.help("HTTP API socket (UNIX domain socket): path=</path/to/a/file> or fd=<fd>.")
|
||||
.takes_value(true)
|
||||
@@ -348,7 +343,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vmm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("event-monitor")
|
||||
Arg::new("event-monitor")
|
||||
.long("event-monitor")
|
||||
.help("File to report events on: path=</path/to/a/file> or fd=<fd>")
|
||||
.takes_value(true)
|
||||
@@ -356,7 +351,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vmm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("restore")
|
||||
Arg::new("restore")
|
||||
.long("restore")
|
||||
.help(config::RestoreConfig::SYNTAX)
|
||||
.takes_value(true)
|
||||
@@ -364,7 +359,7 @@ fn create_app<'a, 'b>(
|
||||
.group("vmm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("seccomp")
|
||||
Arg::new("seccomp")
|
||||
.long("seccomp")
|
||||
.takes_value(true)
|
||||
.possible_values(&["true", "false", "log"])
|
||||
@@ -372,27 +367,23 @@ fn create_app<'a, 'b>(
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
app = app.arg(
|
||||
Arg::with_name("sgx-epc")
|
||||
.long("sgx-epc")
|
||||
.help(config::SgxEpcConfig::SYNTAX)
|
||||
.takes_value(true)
|
||||
.min_values(1)
|
||||
.group("vm-config"),
|
||||
);
|
||||
}
|
||||
let app = app.arg(
|
||||
Arg::new("sgx-epc")
|
||||
.long("sgx-epc")
|
||||
.help(config::SgxEpcConfig::SYNTAX)
|
||||
.takes_value(true)
|
||||
.min_values(1)
|
||||
.group("vm-config"),
|
||||
);
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
{
|
||||
app = app.arg(
|
||||
Arg::with_name("tdx")
|
||||
.long("tdx")
|
||||
.help("TDX Support: firmware=<tdvf path>")
|
||||
.takes_value(true)
|
||||
.group("vm-config"),
|
||||
);
|
||||
}
|
||||
let app = app.arg(
|
||||
Arg::new("tdx")
|
||||
.long("tdx")
|
||||
.help("TDX Support: firmware=<tdvf path>")
|
||||
.takes_value(true)
|
||||
.group("vm-config"),
|
||||
);
|
||||
|
||||
app
|
||||
}
|
||||
@@ -513,8 +504,8 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
||||
// Before we start any threads, mask the signals we'll be
|
||||
// installing handlers for, to make sure they only ever run on the
|
||||
// dedicated signal handling thread we'll start in a bit.
|
||||
for sig in vmm::vm::HANDLED_SIGNALS {
|
||||
if let Err(e) = block_signal(sig) {
|
||||
for sig in &vmm::vm::HANDLED_SIGNALS {
|
||||
if let Err(e) = block_signal(*sig) {
|
||||
eprintln!("Error blocking signals: {}", e);
|
||||
}
|
||||
}
|
||||
@@ -534,9 +525,16 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
||||
)
|
||||
.map_err(Error::StartVmmThread)?;
|
||||
|
||||
// Can't test for "vm-config" group as some have default values. The kernel
|
||||
// Can't test for "vm-config" group as some have default values. The kernel (or tdx if enabled)
|
||||
// is the only required option for booting the VM.
|
||||
if cmd_arguments.is_present("kernel") || cmd_arguments.is_present("tdx") {
|
||||
#[cfg(feature = "tdx")]
|
||||
let tdx_or_kernel_present =
|
||||
cmd_arguments.is_present("kernel") || cmd_arguments.is_present("tdx");
|
||||
|
||||
#[cfg(not(feature = "tdx"))]
|
||||
let tdx_or_kernel_present = cmd_arguments.is_present("kernel");
|
||||
|
||||
if tdx_or_kernel_present {
|
||||
let vm_params = config::VmParams::from_arg_matches(&cmd_arguments);
|
||||
let vm_config = config::VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?;
|
||||
|
||||
@@ -586,10 +584,6 @@ fn main() {
|
||||
std::process::exit(exit_code);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate credibility;
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_tests {
|
||||
use crate::config::HotplugMethod;
|
||||
@@ -618,15 +612,11 @@ mod unit_tests {
|
||||
let cli_vm_config = get_vm_config_from_vec(cli);
|
||||
let openapi_vm_config: VmConfig = serde_json::from_str(openapi).unwrap();
|
||||
|
||||
test_block!(tb, "", {
|
||||
if equal {
|
||||
aver_eq!(tb, cli_vm_config, openapi_vm_config);
|
||||
} else {
|
||||
aver_ne!(tb, cli_vm_config, openapi_vm_config);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
if equal {
|
||||
assert_eq!(cli_vm_config, openapi_vm_config);
|
||||
} else {
|
||||
assert_ne!(cli_vm_config, openapi_vm_config);
|
||||
}
|
||||
|
||||
(cli_vm_config, openapi_vm_config)
|
||||
}
|
||||
@@ -640,70 +630,67 @@ mod unit_tests {
|
||||
let (result_vm_config, _) = compare_vm_config_cli_vs_json(&cli, openapi, true);
|
||||
|
||||
// As a second step, we validate all the default values.
|
||||
test_block!(tb, "", {
|
||||
let expected_vm_config = VmConfig {
|
||||
cpus: CpusConfig {
|
||||
boot_vcpus: 1,
|
||||
max_vcpus: 1,
|
||||
topology: None,
|
||||
kvm_hyperv: false,
|
||||
max_phys_bits: 46,
|
||||
affinity: None,
|
||||
},
|
||||
memory: MemoryConfig {
|
||||
size: 536_870_912,
|
||||
mergeable: false,
|
||||
hotplug_method: HotplugMethod::Acpi,
|
||||
hotplug_size: None,
|
||||
hotplugged_size: None,
|
||||
shared: false,
|
||||
hugepages: false,
|
||||
hugepage_size: None,
|
||||
prefault: false,
|
||||
zones: None,
|
||||
},
|
||||
kernel: Some(KernelConfig {
|
||||
path: PathBuf::from("/path/to/kernel"),
|
||||
}),
|
||||
initramfs: None,
|
||||
cmdline: CmdlineConfig {
|
||||
args: String::from(""),
|
||||
},
|
||||
disks: None,
|
||||
net: None,
|
||||
rng: RngConfig {
|
||||
src: PathBuf::from("/dev/urandom"),
|
||||
iommu: false,
|
||||
},
|
||||
balloon: None,
|
||||
fs: None,
|
||||
pmem: None,
|
||||
serial: ConsoleConfig {
|
||||
file: None,
|
||||
mode: ConsoleOutputMode::Null,
|
||||
iommu: false,
|
||||
},
|
||||
console: ConsoleConfig {
|
||||
file: None,
|
||||
mode: ConsoleOutputMode::Tty,
|
||||
iommu: false,
|
||||
},
|
||||
devices: None,
|
||||
user_devices: None,
|
||||
vsock: None,
|
||||
let expected_vm_config = VmConfig {
|
||||
cpus: CpusConfig {
|
||||
boot_vcpus: 1,
|
||||
max_vcpus: 1,
|
||||
topology: None,
|
||||
kvm_hyperv: false,
|
||||
max_phys_bits: 46,
|
||||
affinity: None,
|
||||
},
|
||||
memory: MemoryConfig {
|
||||
size: 536_870_912,
|
||||
mergeable: false,
|
||||
hotplug_method: HotplugMethod::Acpi,
|
||||
hotplug_size: None,
|
||||
hotplugged_size: None,
|
||||
shared: false,
|
||||
hugepages: false,
|
||||
hugepage_size: None,
|
||||
prefault: false,
|
||||
zones: None,
|
||||
},
|
||||
kernel: Some(KernelConfig {
|
||||
path: PathBuf::from("/path/to/kernel"),
|
||||
}),
|
||||
initramfs: None,
|
||||
cmdline: CmdlineConfig {
|
||||
args: String::from(""),
|
||||
},
|
||||
disks: None,
|
||||
net: None,
|
||||
rng: RngConfig {
|
||||
src: PathBuf::from("/dev/urandom"),
|
||||
iommu: false,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
sgx_epc: None,
|
||||
numa: None,
|
||||
watchdog: false,
|
||||
#[cfg(feature = "tdx")]
|
||||
tdx: None,
|
||||
platform: None,
|
||||
};
|
||||
},
|
||||
balloon: None,
|
||||
fs: None,
|
||||
pmem: None,
|
||||
serial: ConsoleConfig {
|
||||
file: None,
|
||||
mode: ConsoleOutputMode::Null,
|
||||
iommu: false,
|
||||
},
|
||||
console: ConsoleConfig {
|
||||
file: None,
|
||||
mode: ConsoleOutputMode::Tty,
|
||||
iommu: false,
|
||||
},
|
||||
devices: None,
|
||||
user_devices: None,
|
||||
vsock: None,
|
||||
iommu: false,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
sgx_epc: None,
|
||||
numa: None,
|
||||
watchdog: false,
|
||||
#[cfg(feature = "tdx")]
|
||||
tdx: None,
|
||||
platform: None,
|
||||
};
|
||||
|
||||
aver_eq!(tb, expected_vm_config, result_vm_config);
|
||||
Ok(())
|
||||
})
|
||||
assert_eq!(expected_vm_config, result_vm_config);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -138,6 +138,7 @@ pub trait DiskConfig {
|
||||
fn disk(&self, disk_type: DiskType) -> Option<String>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UbuntuDiskConfig {
|
||||
osdisk_path: String,
|
||||
cloudinit_path: String,
|
||||
|
||||
14705
tests/integration.rs
14705
tests/integration.rs
File diff suppressed because it is too large
Load Diff
@@ -5,16 +5,16 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.51"
|
||||
libc = "0.2.108"
|
||||
anyhow = "1.0.52"
|
||||
libc = "0.2.112"
|
||||
log = "0.4.14"
|
||||
serde = {version = ">=1.0.27", features = ["rc"] }
|
||||
serde_derive = ">=1.0.27"
|
||||
serde_json = ">=1.0.9"
|
||||
thiserror = "1.0.30"
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = ">=0.3.1"
|
||||
|
||||
[dependencies.vfio-bindings]
|
||||
version = "0.2.0"
|
||||
version = "0.3.1"
|
||||
features = ["fam-wrappers"]
|
||||
|
||||
@@ -7,8 +7,8 @@ license = "Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.4.3"
|
||||
crc32c = "0.6.0"
|
||||
libc = "0.2.108"
|
||||
crc32c = "0.6.1"
|
||||
libc = "0.2.112"
|
||||
log = "0.4.14"
|
||||
remain = "0.2.2"
|
||||
thiserror = "1.0"
|
||||
|
||||
@@ -9,11 +9,11 @@ default = []
|
||||
|
||||
[dependencies]
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
log = "0.4.14"
|
||||
virtio-bindings = "0.1.0"
|
||||
virtio-queue = { path = "../virtio-queue" }
|
||||
vm-memory = { version = "0.6.0", features = ["backend-bitmap"] }
|
||||
vm-memory = { version = "0.7.0", features = ["backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.9.0"
|
||||
vhost = { version = "0.2.0", features = ["vhost-user-slave"] }
|
||||
vhost = { version = "0.3.0", features = ["vhost-user-slave"] }
|
||||
|
||||
@@ -6,15 +6,15 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
block_util = { path = "../block_util" }
|
||||
clap = { version = "2.34.0", features = ["wrap_help"] }
|
||||
clap = { version = "3.0.10", features = ["wrap_help"] }
|
||||
env_logger = "0.9.0"
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
log = "0.4.14"
|
||||
option_parser = { path = "../option_parser" }
|
||||
qcow = { path = "../qcow" }
|
||||
vhost_user_backend = { path = "../vhost_user_backend" }
|
||||
vhost = { version = "0.2.0", features = ["vhost-user-slave"] }
|
||||
vhost = { version = "0.3.0", features = ["vhost-user-slave"] }
|
||||
virtio-bindings = "0.1.0"
|
||||
vm-memory = "0.6.0"
|
||||
vm-memory = "0.7.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
@@ -23,7 +23,7 @@ fn main() {
|
||||
.author(crate_authors!())
|
||||
.about("Launch a vhost-user-blk backend.")
|
||||
.arg(
|
||||
Arg::with_name("block-backend")
|
||||
Arg::new("block-backend")
|
||||
.long("block-backend")
|
||||
.help(vhost_user_block::SYNTAX)
|
||||
.takes_value(true)
|
||||
|
||||
@@ -5,15 +5,15 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "2.34.0", features = ["wrap_help"] }
|
||||
clap = { version = "3.0.10", features = ["wrap_help"] }
|
||||
env_logger = "0.9.0"
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
log = "0.4.14"
|
||||
net_util = { path = "../net_util" }
|
||||
option_parser = { path = "../option_parser" }
|
||||
vhost_user_backend = { path = "../vhost_user_backend" }
|
||||
vhost = { version = "0.2.0", features = ["vhost-user-slave"] }
|
||||
vhost = { version = "0.3.0", features = ["vhost-user-slave"] }
|
||||
virtio-bindings = "0.1.0"
|
||||
vm-memory = "0.6.0"
|
||||
vm-memory = "0.7.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
@@ -20,7 +20,7 @@ fn main() {
|
||||
.author(crate_authors!())
|
||||
.about("Launch a vhost-user-net backend.")
|
||||
.arg(
|
||||
Arg::with_name("net-backend")
|
||||
Arg::new("net-backend")
|
||||
.long("net-backend")
|
||||
.help(vhost_user_net::SYNTAX)
|
||||
.takes_value(true)
|
||||
|
||||
@@ -6,35 +6,34 @@ edition = "2018"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
io_uring = ["block_util/io_uring"]
|
||||
mshv = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.51"
|
||||
anyhow = "1.0.52"
|
||||
arc-swap = "1.5.0"
|
||||
block_util = { path = "../block_util" }
|
||||
byteorder = "1.4.3"
|
||||
epoll = "4.3.1"
|
||||
event_monitor = { path = "../event_monitor" }
|
||||
io-uring = "0.5.2"
|
||||
libc = "0.2.108"
|
||||
libc = "0.2.112"
|
||||
log = "0.4.14"
|
||||
net_gen = { path = "../net_gen" }
|
||||
net_util = { path = "../net_util" }
|
||||
pci = { path = "../pci" }
|
||||
rate_limiter = { path = "../rate_limiter" }
|
||||
seccompiler = "0.2.0"
|
||||
serde = "1.0.130"
|
||||
serde_derive = "1.0.130"
|
||||
serde_json = "1.0.72"
|
||||
serde = "1.0.133"
|
||||
serde_derive = "1.0.133"
|
||||
serde_json = "1.0.75"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vhost = { version = "0.2.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern"] }
|
||||
vhost = { version = "0.3.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern"] }
|
||||
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
|
||||
virtio-queue = { path = "../virtio-queue" }
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
@@ -57,6 +57,8 @@ pub enum Error {
|
||||
RequestParsing(block_util::Error),
|
||||
/// Failed to execute the request.
|
||||
RequestExecuting(block_util::ExecuteError),
|
||||
/// Failed to complete the request.
|
||||
RequestCompleting(block_util::Error),
|
||||
/// Missing the expected entry in the list of requests.
|
||||
MissingEntryRequestList,
|
||||
/// The asynchronous request returned with failure.
|
||||
@@ -188,10 +190,11 @@ impl BlockEpollHandler {
|
||||
let completion_list = self.disk_image.complete();
|
||||
for (user_data, result) in completion_list {
|
||||
let desc_index = user_data as u16;
|
||||
let request = self
|
||||
let mut request = self
|
||||
.request_list
|
||||
.remove(&desc_index)
|
||||
.ok_or(Error::MissingEntryRequestList)?;
|
||||
request.complete_async().map_err(Error::RequestCompleting)?;
|
||||
|
||||
let (status, len) = if result >= 0 {
|
||||
match request.request_type {
|
||||
@@ -422,7 +425,9 @@ impl Block {
|
||||
|
||||
let mut avail_features = (1u64 << VIRTIO_F_VERSION_1)
|
||||
| (1u64 << VIRTIO_BLK_F_FLUSH)
|
||||
| (1u64 << VIRTIO_BLK_F_CONFIG_WCE);
|
||||
| (1u64 << VIRTIO_BLK_F_CONFIG_WCE)
|
||||
| (1u64 << VIRTIO_BLK_F_BLK_SIZE)
|
||||
| (1u64 << VIRTIO_BLK_F_TOPOLOGY);
|
||||
|
||||
if iommu {
|
||||
avail_features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM;
|
||||
@@ -432,10 +437,31 @@ impl Block {
|
||||
avail_features |= 1u64 << VIRTIO_BLK_F_RO;
|
||||
}
|
||||
|
||||
let topology = disk_image.topology();
|
||||
info!("Disk topology: {:?}", topology);
|
||||
|
||||
let logical_block_size = if topology.logical_block_size > 512 {
|
||||
topology.logical_block_size
|
||||
} else {
|
||||
512
|
||||
};
|
||||
|
||||
// Calculate the exponent that maps physical block to logical block
|
||||
let mut physical_block_exp = 0;
|
||||
let mut size = logical_block_size;
|
||||
while size < topology.physical_block_size {
|
||||
physical_block_exp += 1;
|
||||
size <<= 1;
|
||||
}
|
||||
|
||||
let disk_nsectors = disk_size / SECTOR_SIZE;
|
||||
let mut config = VirtioBlockConfig {
|
||||
capacity: disk_nsectors,
|
||||
writeback: 1,
|
||||
blk_size: topology.logical_block_size as u32,
|
||||
physical_block_exp,
|
||||
min_io_size: (topology.minimum_io_size / logical_block_size) as u16,
|
||||
opt_io_size: (topology.optimal_io_size / logical_block_size) as u32,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
||||
@@ -25,7 +25,10 @@ use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use virtio_queue::{AccessPlatform, DescriptorChain, Queue};
|
||||
use vm_device::dma_mapping::ExternalDmaMapping;
|
||||
use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryError};
|
||||
use vm_memory::{
|
||||
Address, ByteValued, Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryError,
|
||||
GuestMemoryLoadGuard,
|
||||
};
|
||||
use vm_migration::VersionMapped;
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@@ -339,7 +342,7 @@ impl Request {
|
||||
// is created based on the information provided from the guest driver for
|
||||
// virtio-iommu (giving the link device_id <=> domain).
|
||||
fn parse(
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap>>,
|
||||
mapping: &Arc<IommuMapping>,
|
||||
ext_mapping: &BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
||||
ext_domain_mapping: &mut BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
||||
|
||||
@@ -38,7 +38,7 @@ use virtio_queue::{DescriptorChain, Queue};
|
||||
use vm_device::dma_mapping::ExternalDmaMapping;
|
||||
use vm_memory::{
|
||||
Address, ByteValued, Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryError,
|
||||
GuestMemoryRegion,
|
||||
GuestMemoryLoadGuard, GuestMemoryRegion,
|
||||
};
|
||||
use vm_migration::protocol::MemoryRangeTable;
|
||||
use vm_migration::{
|
||||
@@ -277,7 +277,7 @@ struct Request {
|
||||
|
||||
impl Request {
|
||||
fn parse(
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap>>,
|
||||
) -> result::Result<Request, Error> {
|
||||
let desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?;
|
||||
// The descriptor contains the request type which MUST be readable.
|
||||
|
||||
@@ -34,9 +34,7 @@ use std::{collections::HashMap, convert::TryInto};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use virtio_bindings::bindings::virtio_net::*;
|
||||
use virtio_bindings::bindings::virtio_ring::{
|
||||
VIRTIO_RING_F_EVENT_IDX, VIRTIO_RING_F_INDIRECT_DESC,
|
||||
};
|
||||
use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
|
||||
use virtio_queue::Queue;
|
||||
use vm_memory::{ByteValued, GuestMemoryAtomic};
|
||||
use vm_migration::VersionMapped;
|
||||
@@ -400,9 +398,7 @@ impl Net {
|
||||
| 1 << VIRTIO_NET_F_HOST_TSO4
|
||||
| 1 << VIRTIO_NET_F_HOST_TSO6
|
||||
| 1 << VIRTIO_NET_F_HOST_UFO
|
||||
| 1 << VIRTIO_NET_F_MRG_RXBUF
|
||||
| 1 << VIRTIO_RING_F_EVENT_IDX
|
||||
| 1 << VIRTIO_RING_F_INDIRECT_DESC
|
||||
| 1 << VIRTIO_F_VERSION_1;
|
||||
|
||||
if iommu {
|
||||
@@ -567,10 +563,13 @@ impl VirtioDevice for Net {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
|
||||
let queue_num = queues.len();
|
||||
let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into());
|
||||
if self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && queue_num % 2 != 0 {
|
||||
let cvq_queue = queues.remove(queue_num - 1);
|
||||
let mut cvq_queue = queues.remove(queue_num - 1);
|
||||
let cvq_queue_evt = queue_evts.remove(queue_num - 1);
|
||||
|
||||
cvq_queue.set_event_idx(event_idx);
|
||||
|
||||
let (kill_evt, pause_evt) = self.common.dup_eventfds();
|
||||
let mut ctrl_handler = NetCtrlEpollHandler {
|
||||
kill_evt,
|
||||
@@ -603,8 +602,6 @@ impl VirtioDevice for Net {
|
||||
self.ctrl_queue_epoll_thread = Some(epoll_threads.remove(0));
|
||||
}
|
||||
|
||||
let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into());
|
||||
|
||||
let mut epoll_threads = Vec::new();
|
||||
let mut taps = self.taps.clone();
|
||||
for i in 0..queues.len() / 2 {
|
||||
|
||||
@@ -28,7 +28,10 @@ use std::sync::{Arc, Barrier};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use virtio_queue::{DescriptorChain, Queue};
|
||||
use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryError};
|
||||
use vm_memory::{
|
||||
Address, ByteValued, Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryError,
|
||||
GuestMemoryLoadGuard,
|
||||
};
|
||||
use vm_migration::VersionMapped;
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@@ -114,7 +117,7 @@ struct Request {
|
||||
|
||||
impl Request {
|
||||
fn parse(
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap>>,
|
||||
) -> result::Result<Request, Error> {
|
||||
let desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?;
|
||||
// The descriptor contains the request type which MUST be readable.
|
||||
|
||||
@@ -90,7 +90,6 @@ fn virtio_block_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
(libc::SYS_io_uring_enter, vec![]),
|
||||
(libc::SYS_lseek, vec![]),
|
||||
(libc::SYS_mprotect, vec![]),
|
||||
(libc::SYS_openat, vec![]),
|
||||
(libc::SYS_prctl, vec![]),
|
||||
(libc::SYS_pread64, vec![]),
|
||||
(libc::SYS_preadv, vec![]),
|
||||
@@ -130,7 +129,6 @@ fn virtio_mem_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
|
||||
fn virtio_net_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_openat, vec![]),
|
||||
(libc::SYS_readv, vec![]),
|
||||
(libc::SYS_timerfd_settime, vec![]),
|
||||
(libc::SYS_writev, vec![]),
|
||||
@@ -258,6 +256,7 @@ fn virtio_thread_common() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_mmap, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_openat, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
|
||||
@@ -362,10 +362,11 @@ impl VirtioPciDevice {
|
||||
.queue_max_sizes()
|
||||
.iter()
|
||||
.map(|&s| {
|
||||
let mut queue = Queue::<
|
||||
GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
virtio_queue::QueueState<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
>::new(memory.clone(), s);
|
||||
let mut queue =
|
||||
Queue::<GuestMemoryAtomic<GuestMemoryMmap>, virtio_queue::QueueState>::new(
|
||||
memory.clone(),
|
||||
s,
|
||||
);
|
||||
queue.state.access_platform = access_platform.clone();
|
||||
queue
|
||||
})
|
||||
@@ -841,7 +842,7 @@ impl PciDevice for VirtioPciDevice {
|
||||
|
||||
fn allocate_bars(
|
||||
&mut self,
|
||||
allocator: &mut SystemAllocator,
|
||||
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||
mmio_allocator: &mut AddressAllocator,
|
||||
) -> std::result::Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError>
|
||||
{
|
||||
@@ -865,6 +866,8 @@ impl PciDevice for VirtioPciDevice {
|
||||
} else {
|
||||
let region_type = PciBarRegionType::Memory32BitRegion;
|
||||
let addr = allocator
|
||||
.lock()
|
||||
.unwrap()
|
||||
.allocate_mmio_hole_addresses(
|
||||
self.settings_bar_addr,
|
||||
CAPABILITY_BAR_SIZE,
|
||||
|
||||
@@ -173,7 +173,7 @@ impl VhostUserHandle {
|
||||
// at early stage.
|
||||
for (queue_index, queue) in queues.iter().enumerate() {
|
||||
self.vu
|
||||
.set_vring_num(queue_index, queue.actual_size())
|
||||
.set_vring_num(queue_index, queue.max_size())
|
||||
.map_err(Error::VhostUserSetVringNum)?;
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ impl VhostUserHandle {
|
||||
mmap_size: 0,
|
||||
mmap_offset: 0,
|
||||
num_queues: queues.len() as u16,
|
||||
queue_size: queues[0].actual_size(),
|
||||
queue_size: queues[0].max_size(),
|
||||
};
|
||||
let (info, fd) = self
|
||||
.vu
|
||||
@@ -203,11 +203,11 @@ impl VhostUserHandle {
|
||||
|
||||
let mut vrings_info = Vec::new();
|
||||
for (queue_index, queue) in queues.into_iter().enumerate() {
|
||||
let actual_size: usize = queue.actual_size().try_into().unwrap();
|
||||
let actual_size: usize = queue.max_size().try_into().unwrap();
|
||||
|
||||
let config_data = VringConfigData {
|
||||
queue_max_size: queue.max_size(),
|
||||
queue_size: queue.actual_size(),
|
||||
queue_size: queue.max_size(),
|
||||
flags: 0u32,
|
||||
desc_table_addr: get_host_address_range(
|
||||
mem,
|
||||
|
||||
@@ -21,7 +21,7 @@ use super::defs;
|
||||
use super::{Result, VsockError};
|
||||
use crate::{get_host_address_range, GuestMemoryMmap};
|
||||
use virtio_queue::DescriptorChain;
|
||||
use vm_memory::GuestMemoryAtomic;
|
||||
use vm_memory::GuestMemoryLoadGuard;
|
||||
|
||||
// The vsock packet header is defined by the C struct:
|
||||
//
|
||||
@@ -106,7 +106,7 @@ impl VsockPacket {
|
||||
/// creating the wrapper.
|
||||
///
|
||||
pub fn from_tx_virtq_head(
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap>>,
|
||||
) -> Result<Self> {
|
||||
let head = desc_chain.next().ok_or(VsockError::HdrDescMissing)?;
|
||||
|
||||
@@ -168,7 +168,7 @@ impl VsockPacket {
|
||||
/// descriptor. Bounds and pointer checks are performed when creating the wrapper.
|
||||
///
|
||||
pub fn from_rx_virtq_head(
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
desc_chain: &mut DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap>>,
|
||||
) -> Result<Self> {
|
||||
let head = desc_chain.next().ok_or(VsockError::HdrDescMissing)?;
|
||||
|
||||
|
||||
@@ -295,14 +295,13 @@ impl VsockEpollListener for VsockMuxer {
|
||||
'epoll: loop {
|
||||
match epoll::wait(self.epoll_file.as_raw_fd(), 0, epoll_events.as_mut_slice()) {
|
||||
Ok(ev_cnt) => {
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for i in 0..ev_cnt {
|
||||
for evt in epoll_events.iter().take(ev_cnt) {
|
||||
self.handle_event(
|
||||
epoll_events[i].data as RawFd,
|
||||
// It's ok to unwrap here, since the `epoll_events[i].events` is filled
|
||||
evt.data as RawFd,
|
||||
// It's ok to unwrap here, since the `evt.events` is filled
|
||||
// in by `epoll::wait()`, and therefore contains only valid epoll
|
||||
// flags.
|
||||
epoll::Events::from_bits(epoll_events[i].events).unwrap(),
|
||||
epoll::Events::from_bits(evt.events).unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -362,25 +361,24 @@ impl VsockMuxer {
|
||||
|
||||
/// Handle/dispatch an epoll event to its listener.
|
||||
///
|
||||
fn handle_event(&mut self, fd: RawFd, evset: epoll::Events) {
|
||||
fn handle_event(&mut self, fd: RawFd, event_set: epoll::Events) {
|
||||
debug!(
|
||||
"vsock: muxer processing event: fd={}, evset={:?}",
|
||||
fd, evset
|
||||
"vsock: muxer processing event: fd={}, event_set={:?}",
|
||||
fd, event_set
|
||||
);
|
||||
|
||||
match self.listener_map.get_mut(&fd) {
|
||||
// This event needs to be forwarded to a `MuxerConnection` that is listening for
|
||||
// it.
|
||||
//
|
||||
Some(EpollListener::Connection { key, evset }) => {
|
||||
Some(EpollListener::Connection { key, evset: _ }) => {
|
||||
let key_copy = *key;
|
||||
let evset_copy = *evset;
|
||||
// The handling of this event will most probably mutate the state of the
|
||||
// receiving connection. We'll need to check for new pending RX, event set
|
||||
// mutation, and all that, so we're wrapping the event delivery inside those
|
||||
// checks.
|
||||
self.apply_conn_mutation(key_copy, |conn| {
|
||||
conn.notify(evset_copy);
|
||||
conn.notify(event_set);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -443,7 +441,10 @@ impl VsockMuxer {
|
||||
}
|
||||
|
||||
_ => {
|
||||
info!("vsock: unexpected event: fd={:?}, evset={:?}", fd, evset);
|
||||
info!(
|
||||
"vsock: unexpected event: fd={:?}, event_set={:?}",
|
||||
fd, event_set
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,14 @@ description = "virtio queue implementation"
|
||||
repository = "https://github.com/rust-vmm/vm-virtio"
|
||||
keywords = ["virtio"]
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0 OR MIT"
|
||||
license = "Apache-2.0 OR BSD-3-Clause"
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
test-utils = []
|
||||
|
||||
[dependencies]
|
||||
vm-memory = "0.6.0"
|
||||
vm-memory = "0.7.0"
|
||||
vmm-sys-util = ">=0.8.0"
|
||||
log = ">=0.4.6"
|
||||
log = ">=0.4.6"
|
||||
|
||||
[dev-dependencies]
|
||||
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
memoffset = "~0"
|
||||
|
||||
490
virtio-queue/src/chain.rs
Normal file
490
virtio-queue/src/chain.rs
Normal file
@@ -0,0 +1,490 @@
|
||||
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE-BSD-3-Clause file.
|
||||
//
|
||||
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
//
|
||||
// Copyright © 2019 Intel Corporation
|
||||
//
|
||||
// Copyright (C) 2020-2021 Alibaba Cloud. All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::{self, Debug};
|
||||
use std::mem::size_of;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
use vm_memory::{Address, Bytes, GuestAddress, GuestMemory};
|
||||
|
||||
use crate::defs::VIRTQ_DESCRIPTOR_SIZE;
|
||||
use crate::{AccessPlatform, Descriptor, Error};
|
||||
|
||||
/// A virtio descriptor chain.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DescriptorChain<M> {
|
||||
mem: M,
|
||||
desc_table: GuestAddress,
|
||||
queue_size: u16,
|
||||
head_index: u16,
|
||||
next_index: u16,
|
||||
ttl: u16,
|
||||
is_indirect: bool,
|
||||
access_platform: Option<Arc<dyn AccessPlatform>>,
|
||||
}
|
||||
|
||||
impl<M> DescriptorChain<M>
|
||||
where
|
||||
M: Deref,
|
||||
M::Target: GuestMemory,
|
||||
{
|
||||
fn with_ttl(
|
||||
mem: M,
|
||||
desc_table: GuestAddress,
|
||||
queue_size: u16,
|
||||
ttl: u16,
|
||||
head_index: u16,
|
||||
access_platform: Option<Arc<dyn AccessPlatform>>,
|
||||
) -> Self {
|
||||
DescriptorChain {
|
||||
mem,
|
||||
desc_table,
|
||||
queue_size,
|
||||
head_index,
|
||||
next_index: head_index,
|
||||
ttl,
|
||||
is_indirect: false,
|
||||
access_platform,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `DescriptorChain` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `mem` - the `GuestMemory` object that can be used to access the buffers pointed to by the
|
||||
/// descriptor chain.
|
||||
/// * `desc_table` - the address of the descriptor table.
|
||||
/// * `queue_size` - the size of the queue, which is also the maximum size of a descriptor
|
||||
/// chain.
|
||||
/// * `head_index` - the descriptor index of the chain head.
|
||||
pub(crate) fn new(
|
||||
mem: M,
|
||||
desc_table: GuestAddress,
|
||||
queue_size: u16,
|
||||
head_index: u16,
|
||||
access_platform: Option<Arc<dyn AccessPlatform>>,
|
||||
) -> Self {
|
||||
Self::with_ttl(
|
||||
mem,
|
||||
desc_table,
|
||||
queue_size,
|
||||
queue_size,
|
||||
head_index,
|
||||
access_platform,
|
||||
)
|
||||
}
|
||||
|
||||
/// Get the descriptor index of the chain head.
|
||||
pub fn head_index(&self) -> u16 {
|
||||
self.head_index
|
||||
}
|
||||
|
||||
/// Return a `GuestMemory` object that can be used to access the buffers pointed to by the
|
||||
/// descriptor chain.
|
||||
pub fn memory(&self) -> &M::Target {
|
||||
self.mem.deref()
|
||||
}
|
||||
|
||||
/// Return an iterator that only yields the readable descriptors in the chain.
|
||||
pub fn readable(self) -> DescriptorChainRwIter<M> {
|
||||
DescriptorChainRwIter {
|
||||
chain: self,
|
||||
writable: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an iterator that only yields the writable descriptors in the chain.
|
||||
pub fn writable(self) -> DescriptorChainRwIter<M> {
|
||||
DescriptorChainRwIter {
|
||||
chain: self,
|
||||
writable: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Alters the internal state of the `DescriptorChain` to switch iterating over an
|
||||
// indirect descriptor table defined by `desc`.
|
||||
fn switch_to_indirect_table(&mut self, desc: Descriptor) -> Result<(), Error> {
|
||||
// Check the VIRTQ_DESC_F_INDIRECT flag (i.e., is_indirect) is not set inside
|
||||
// an indirect descriptor.
|
||||
// (see VIRTIO Spec, Section 2.6.5.3.1 Driver Requirements: Indirect Descriptors)
|
||||
if self.is_indirect {
|
||||
return Err(Error::InvalidIndirectDescriptor);
|
||||
}
|
||||
|
||||
// Check the target indirect descriptor table is correctly aligned.
|
||||
if desc.addr().raw_value() & (VIRTQ_DESCRIPTOR_SIZE as u64 - 1) != 0
|
||||
|| desc.len() & (VIRTQ_DESCRIPTOR_SIZE as u32 - 1) != 0
|
||||
{
|
||||
return Err(Error::InvalidIndirectDescriptorTable);
|
||||
}
|
||||
|
||||
// It is safe to do a plain division since we checked above that desc.len() is a multiple of
|
||||
// VIRTQ_DESCRIPTOR_SIZE, and VIRTQ_DESCRIPTOR_SIZE is != 0.
|
||||
let table_len = (desc.len() as usize) / VIRTQ_DESCRIPTOR_SIZE;
|
||||
if table_len > usize::from(u16::MAX) {
|
||||
return Err(Error::InvalidIndirectDescriptorTable);
|
||||
}
|
||||
|
||||
self.desc_table = desc.addr();
|
||||
// try_from cannot fail as we've checked table_len above
|
||||
self.queue_size = u16::try_from(table_len).expect("invalid table_len");
|
||||
self.next_index = 0;
|
||||
self.ttl = self.queue_size;
|
||||
self.is_indirect = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> Iterator for DescriptorChain<M>
|
||||
where
|
||||
M: Deref,
|
||||
M::Target: GuestMemory,
|
||||
{
|
||||
type Item = Descriptor;
|
||||
|
||||
/// Return the next descriptor in this descriptor chain, if there is one.
|
||||
///
|
||||
/// Note that this is distinct from the next descriptor chain returned by
|
||||
/// [`AvailIter`](struct.AvailIter.html), which is the head of the next
|
||||
/// _available_ descriptor chain.
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.ttl == 0 || self.next_index >= self.queue_size {
|
||||
return None;
|
||||
}
|
||||
|
||||
let desc_addr = self
|
||||
.desc_table
|
||||
// The multiplication can not overflow an u64 since we are multiplying an u16 with a
|
||||
// small number.
|
||||
.checked_add(self.next_index as u64 * size_of::<Descriptor>() as u64)?;
|
||||
|
||||
// The guest device driver should not touch the descriptor once submitted, so it's safe
|
||||
// to use read_obj() here.
|
||||
let mut desc = self.mem.read_obj::<Descriptor>(desc_addr).ok()?;
|
||||
// When needed, it's very important to translate the decriptor address
|
||||
// before returning the Descriptor to the consumer.
|
||||
if let Some(access_platform) = &self.access_platform {
|
||||
desc.set_addr(
|
||||
access_platform
|
||||
.translate(desc.addr().0, u64::from(desc.len()))
|
||||
.ok()?,
|
||||
);
|
||||
}
|
||||
|
||||
if desc.refers_to_indirect_table() {
|
||||
self.switch_to_indirect_table(desc).ok()?;
|
||||
return self.next();
|
||||
}
|
||||
|
||||
if desc.has_next() {
|
||||
self.next_index = desc.next();
|
||||
// It's ok to decrement `self.ttl` here because we check at the start of the method
|
||||
// that it's greater than 0.
|
||||
self.ttl -= 1;
|
||||
} else {
|
||||
self.ttl = 0;
|
||||
}
|
||||
|
||||
Some(desc)
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator for readable or writable descriptors.
|
||||
#[derive(Clone)]
|
||||
pub struct DescriptorChainRwIter<M> {
|
||||
chain: DescriptorChain<M>,
|
||||
writable: bool,
|
||||
}
|
||||
|
||||
impl<M> Iterator for DescriptorChainRwIter<M>
|
||||
where
|
||||
M: Deref,
|
||||
M::Target: GuestMemory,
|
||||
{
|
||||
type Item = Descriptor;
|
||||
|
||||
/// Return the next readable/writeable descriptor (depending on the `writable` value) in this
|
||||
/// descriptor chain, if there is one.
|
||||
///
|
||||
/// Note that this is distinct from the next descriptor chain returned by
|
||||
/// [`AvailIter`](struct.AvailIter.html), which is the head of the next
|
||||
/// _available_ descriptor chain.
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
match self.chain.next() {
|
||||
Some(v) => {
|
||||
if v.is_write_only() == self.writable {
|
||||
return Some(v);
|
||||
}
|
||||
}
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can't derive Debug, because rustc doesn't generate the `M::T: Debug` constraint
|
||||
impl<M> Debug for DescriptorChainRwIter<M>
|
||||
where
|
||||
M: Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("DescriptorChainRwIter")
|
||||
.field("chain", &self.chain)
|
||||
.field("writable", &self.writable)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::defs::{VIRTQ_DESC_F_INDIRECT, VIRTQ_DESC_F_NEXT};
|
||||
use crate::mock::{DescriptorTable, MockSplitQueue};
|
||||
use vm_memory::GuestMemoryMmap;
|
||||
|
||||
#[test]
|
||||
fn test_checked_new_descriptor_chain() {
|
||||
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
|
||||
assert!(vq.end().0 < 0x1000);
|
||||
|
||||
// index >= queue_size
|
||||
assert!(
|
||||
DescriptorChain::<&GuestMemoryMmap>::new(m, vq.start(), 16, 16, None)
|
||||
.next()
|
||||
.is_none()
|
||||
);
|
||||
|
||||
// desc_table address is way off
|
||||
assert!(DescriptorChain::<&GuestMemoryMmap>::new(
|
||||
m,
|
||||
GuestAddress(0x00ff_ffff_ffff),
|
||||
16,
|
||||
0,
|
||||
None
|
||||
)
|
||||
.next()
|
||||
.is_none());
|
||||
|
||||
{
|
||||
// the first desc has a normal len, and the next_descriptor flag is set
|
||||
// but the the index of the next descriptor is too large
|
||||
let desc = Descriptor::new(0x1000, 0x1000, VIRTQ_DESC_F_NEXT, 16);
|
||||
vq.desc_table().store(0, desc);
|
||||
|
||||
let mut c = DescriptorChain::<&GuestMemoryMmap>::new(m, vq.start(), 16, 0, None);
|
||||
c.next().unwrap();
|
||||
assert!(c.next().is_none());
|
||||
}
|
||||
|
||||
// finally, let's test an ok chain
|
||||
{
|
||||
let desc = Descriptor::new(0x1000, 0x1000, VIRTQ_DESC_F_NEXT, 1);
|
||||
vq.desc_table().store(0, desc);
|
||||
|
||||
let desc = Descriptor::new(0x2000, 0x1000, 0, 0);
|
||||
vq.desc_table().store(1, desc);
|
||||
|
||||
let mut c = DescriptorChain::<&GuestMemoryMmap>::new(m, vq.start(), 16, 0, None);
|
||||
|
||||
assert_eq!(
|
||||
c.memory() as *const GuestMemoryMmap,
|
||||
m as *const GuestMemoryMmap
|
||||
);
|
||||
|
||||
assert_eq!(c.desc_table, vq.start());
|
||||
assert_eq!(c.queue_size, 16);
|
||||
assert_eq!(c.ttl, c.queue_size);
|
||||
|
||||
let desc = c.next().unwrap();
|
||||
assert_eq!(desc.addr(), GuestAddress(0x1000));
|
||||
assert_eq!(desc.len(), 0x1000);
|
||||
assert_eq!(desc.flags(), VIRTQ_DESC_F_NEXT);
|
||||
assert_eq!(desc.next(), 1);
|
||||
assert_eq!(c.ttl, c.queue_size - 1);
|
||||
|
||||
assert!(c.next().is_some());
|
||||
// The descriptor above was the last from the chain, so `ttl` should be 0 now.
|
||||
assert_eq!(c.ttl, 0);
|
||||
assert!(c.next().is_none());
|
||||
assert_eq!(c.ttl, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ttl_wrap_around() {
|
||||
const QUEUE_SIZE: u16 = 16;
|
||||
|
||||
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x100000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, QUEUE_SIZE);
|
||||
|
||||
// Populate the entire descriptor table with entries. Only the last one should not have the
|
||||
// VIRTQ_DESC_F_NEXT set.
|
||||
for i in 0..QUEUE_SIZE - 1 {
|
||||
let desc = Descriptor::new(0x1000 * (i + 1) as u64, 0x1000, VIRTQ_DESC_F_NEXT, i + 1);
|
||||
vq.desc_table().store(i, desc);
|
||||
}
|
||||
let desc = Descriptor::new((0x1000 * 16) as u64, 0x1000, 0, 0);
|
||||
vq.desc_table().store(QUEUE_SIZE - 1, desc);
|
||||
|
||||
let mut c = DescriptorChain::<&GuestMemoryMmap>::new(m, vq.start(), QUEUE_SIZE, 0, None);
|
||||
assert_eq!(c.ttl, c.queue_size);
|
||||
|
||||
// Validate that `ttl` wraps around even when the entire descriptor table is populated.
|
||||
for i in 0..QUEUE_SIZE {
|
||||
let _desc = c.next().unwrap();
|
||||
assert_eq!(c.ttl, c.queue_size - i - 1);
|
||||
}
|
||||
assert!(c.next().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_from_indirect_descriptor() {
|
||||
// This is testing that chaining an indirect table works as expected. It is also a negative
|
||||
// test for the following requirement from the spec:
|
||||
// `A driver MUST NOT set both VIRTQ_DESC_F_INDIRECT and VIRTQ_DESC_F_NEXT in flags.`. In
|
||||
// case the driver is setting both of these flags, we check that the device doesn't panic.
|
||||
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
let dtable = vq.desc_table();
|
||||
|
||||
// Create a chain with one normal descriptor and one pointing to an indirect table.
|
||||
let desc = Descriptor::new(0x6000, 0x1000, VIRTQ_DESC_F_NEXT, 1);
|
||||
dtable.store(0, desc);
|
||||
// The spec forbids setting both VIRTQ_DESC_F_INDIRECT and VIRTQ_DESC_F_NEXT in flags. We do
|
||||
// not currently enforce this rule, we just ignore the VIRTQ_DESC_F_NEXT flag.
|
||||
let desc = Descriptor::new(0x7000, 0x1000, VIRTQ_DESC_F_INDIRECT | VIRTQ_DESC_F_NEXT, 2);
|
||||
dtable.store(1, desc);
|
||||
let desc = Descriptor::new(0x8000, 0x1000, 0, 0);
|
||||
dtable.store(2, desc);
|
||||
|
||||
let mut c: DescriptorChain<&GuestMemoryMmap> =
|
||||
DescriptorChain::new(m, vq.start(), 16, 0, None);
|
||||
|
||||
// create an indirect table with 4 chained descriptors
|
||||
let idtable = DescriptorTable::new(m, GuestAddress(0x7000), 4);
|
||||
for i in 0..4u16 {
|
||||
let desc = if i < 3 {
|
||||
Descriptor::new(0x1000 * i as u64, 0x1000, VIRTQ_DESC_F_NEXT, i + 1)
|
||||
} else {
|
||||
Descriptor::new(0x1000 * i as u64, 0x1000, 0, 0)
|
||||
};
|
||||
idtable.store(i, desc);
|
||||
}
|
||||
|
||||
assert_eq!(c.head_index(), 0);
|
||||
// Consume the first descriptor.
|
||||
c.next().unwrap();
|
||||
|
||||
// The chain logic hasn't parsed the indirect descriptor yet.
|
||||
assert!(!c.is_indirect);
|
||||
|
||||
// Try to iterate through the indirect descriptor chain.
|
||||
for i in 0..4 {
|
||||
let desc = c.next().unwrap();
|
||||
assert!(c.is_indirect);
|
||||
if i < 3 {
|
||||
assert_eq!(desc.flags(), VIRTQ_DESC_F_NEXT);
|
||||
assert_eq!(desc.next(), i + 1);
|
||||
}
|
||||
}
|
||||
// Even though we added a new descriptor after the one that is pointing to the indirect
|
||||
// table, this descriptor won't be available when parsing the chain.
|
||||
assert!(c.next().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_indirect_descriptor_err() {
|
||||
// We are testing here different misconfigurations of the indirect table. For these error
|
||||
// case scenarios, the iterator over the descriptor chain won't return a new descriptor.
|
||||
{
|
||||
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
|
||||
// Create a chain with a descriptor pointing to an invalid indirect table: addr not a
|
||||
// multiple of descriptor size.
|
||||
let desc = Descriptor::new(0x1001, 0x1000, VIRTQ_DESC_F_INDIRECT, 0);
|
||||
vq.desc_table().store(0, desc);
|
||||
|
||||
let mut c: DescriptorChain<&GuestMemoryMmap> =
|
||||
DescriptorChain::new(m, vq.start(), 16, 0, None);
|
||||
|
||||
assert!(c.next().is_none());
|
||||
}
|
||||
|
||||
{
|
||||
let m = &GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
|
||||
// Create a chain with a descriptor pointing to an invalid indirect table: len not a
|
||||
// multiple of descriptor size.
|
||||
let desc = Descriptor::new(0x1000, 0x1001, VIRTQ_DESC_F_INDIRECT, 0);
|
||||
vq.desc_table().store(0, desc);
|
||||
|
||||
let mut c: DescriptorChain<&GuestMemoryMmap> =
|
||||
DescriptorChain::new(m, vq.start(), 16, 0, None);
|
||||
|
||||
assert!(c.next().is_none());
|
||||
}
|
||||
|
||||
{
|
||||
let m = &GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
|
||||
// Create a chain with a descriptor pointing to an invalid indirect table: table len >
|
||||
// u16::MAX.
|
||||
let desc = Descriptor::new(
|
||||
0x1000,
|
||||
(u16::MAX as u32 + 1) * VIRTQ_DESCRIPTOR_SIZE as u32,
|
||||
VIRTQ_DESC_F_INDIRECT,
|
||||
0,
|
||||
);
|
||||
vq.desc_table().store(0, desc);
|
||||
|
||||
let mut c: DescriptorChain<&GuestMemoryMmap> =
|
||||
DescriptorChain::new(m, vq.start(), 16, 0, None);
|
||||
|
||||
assert!(c.next().is_none());
|
||||
}
|
||||
|
||||
{
|
||||
let m = &GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
|
||||
// Create a chain with a descriptor pointing to an indirect table.
|
||||
let desc = Descriptor::new(0x1000, 0x1000, VIRTQ_DESC_F_INDIRECT, 0);
|
||||
vq.desc_table().store(0, desc);
|
||||
// It's ok for an indirect descriptor to have flags = 0.
|
||||
let desc = Descriptor::new(0x3000, 0x1000, 0, 0);
|
||||
m.write_obj(desc, GuestAddress(0x1000)).unwrap();
|
||||
|
||||
let mut c: DescriptorChain<&GuestMemoryMmap> =
|
||||
DescriptorChain::new(m, vq.start(), 16, 0, None);
|
||||
assert!(c.next().is_some());
|
||||
|
||||
// But it's not allowed to have an indirect descriptor that points to another indirect
|
||||
// table.
|
||||
let desc = Descriptor::new(0x3000, 0x1000, VIRTQ_DESC_F_INDIRECT, 0);
|
||||
m.write_obj(desc, GuestAddress(0x1000)).unwrap();
|
||||
|
||||
let mut c: DescriptorChain<&GuestMemoryMmap> =
|
||||
DescriptorChain::new(m, vq.start(), 16, 0, None);
|
||||
|
||||
assert!(c.next().is_none());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,37 +10,50 @@ pub const VIRTQ_DESC_F_NEXT: u16 = 0x1;
|
||||
/// Marks a buffer as device write-only.
|
||||
pub const VIRTQ_DESC_F_WRITE: u16 = 0x2;
|
||||
|
||||
/// Shows that the buffer contains a list of buffer descriptors.
|
||||
/// Marks a buffer as containing a list of buffer descriptors.
|
||||
pub const VIRTQ_DESC_F_INDIRECT: u16 = 0x4;
|
||||
|
||||
/// Used flags
|
||||
/// Flag to disable guest notification for used descriptors.
|
||||
pub const VIRTQ_USED_F_NO_NOTIFY: u16 = 0x1;
|
||||
|
||||
/// This is the size of one element in the used ring, id (le32) + len (le32).
|
||||
/// Size of one element in the used ring, id (le32) + len (le32).
|
||||
pub(crate) const VIRTQ_USED_ELEMENT_SIZE: u64 = 8;
|
||||
|
||||
/// Used ring header: flags (u16) + idx (u16)
|
||||
/// Size of used ring header: flags (u16) + idx (u16)
|
||||
pub(crate) const VIRTQ_USED_RING_HEADER_SIZE: u64 = 4;
|
||||
|
||||
/// This is the size of the used ring metadata: header + avail_event (le16).
|
||||
/// Size of the used ring metadata: header + avail_event (le16).
|
||||
///
|
||||
/// The total size of the used ring is:
|
||||
/// VIRTQ_USED_RING_HMETA_SIZE + VIRTQ_USED_ELEMENT_SIZE * queue_size
|
||||
/// VIRTQ_USED_RING_META_SIZE + VIRTQ_USED_ELEMENT_SIZE * queue_size.
|
||||
pub(crate) const VIRTQ_USED_RING_META_SIZE: u64 = VIRTQ_USED_RING_HEADER_SIZE + 2;
|
||||
|
||||
/// This is the size of one element in the available ring (le16).
|
||||
/// Size of one element in the available ring (le16).
|
||||
pub(crate) const VIRTQ_AVAIL_ELEMENT_SIZE: u64 = 2;
|
||||
|
||||
/// Avail ring header: flags(u16) + idx(u16)
|
||||
/// Size of available ring header: flags(u16) + idx(u16)
|
||||
pub(crate) const VIRTQ_AVAIL_RING_HEADER_SIZE: u64 = 4;
|
||||
|
||||
/// This is the size of the available ring metadata: header + used_event (le16).
|
||||
/// Size of the available ring metadata: header + used_event (le16).
|
||||
///
|
||||
/// The total size of the available ring is:
|
||||
/// VIRTQ_AVAIL_RING_META_SIZE + VIRTQ_AVAIL_ELEMENT_SIZE * queue_size
|
||||
/// VIRTQ_AVAIL_RING_META_SIZE + VIRTQ_AVAIL_ELEMENT_SIZE * queue_size.
|
||||
pub(crate) const VIRTQ_AVAIL_RING_META_SIZE: u64 = VIRTQ_AVAIL_RING_HEADER_SIZE + 2;
|
||||
|
||||
/// Size of virtio descriptor.
|
||||
///
|
||||
/// The Virtio Spec 1.0 defines the alignment of VirtIO descriptor is 16 bytes,
|
||||
/// which fulfills the explicit constraint of GuestMemory::read_obj().
|
||||
pub(crate) const VIRTQ_DESCRIPTOR_SIZE: usize = 16;
|
||||
|
||||
/// Default guest physical address for descriptor table.
|
||||
pub(crate) const DEFAULT_DESC_TABLE_ADDR: u64 = 0x0;
|
||||
|
||||
/// Default guest physical address for available ring.
|
||||
pub(crate) const DEFAULT_AVAIL_RING_ADDR: u64 = 0x0;
|
||||
|
||||
/// Default guest physical address for used ring.
|
||||
pub(crate) const DEFAULT_USED_RING_ADDR: u64 = 0x0;
|
||||
|
||||
/// Vector value used to disable MSI for a queue.
|
||||
pub const VIRTQ_MSI_NO_VECTOR: u16 = 0xffff;
|
||||
|
||||
270
virtio-queue/src/descriptor.rs
Normal file
270
virtio-queue/src/descriptor.rs
Normal file
@@ -0,0 +1,270 @@
|
||||
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE-BSD-3-Clause file.
|
||||
//
|
||||
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
//
|
||||
// Copyright © 2019 Intel Corporation
|
||||
//
|
||||
// Copyright (C) 2020-2021 Alibaba Cloud. All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
|
||||
use vm_memory::{ByteValued, GuestAddress, Le16, Le32, Le64};
|
||||
|
||||
use crate::defs::{VIRTQ_DESC_F_INDIRECT, VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE};
|
||||
|
||||
/// A virtio descriptor constraints with C representation.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use virtio_queue::defs::{VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE};
|
||||
/// # use virtio_queue::mock::MockSplitQueue;
|
||||
/// use virtio_queue::{Descriptor, Queue};
|
||||
/// use vm_memory::{GuestAddress, GuestMemoryMmap};
|
||||
///
|
||||
/// # fn populate_queue(m: &GuestMemoryMmap) -> Queue<&GuestMemoryMmap> {
|
||||
/// # let vq = MockSplitQueue::new(m, 16);
|
||||
/// # let mut q = vq.create_queue(m);
|
||||
/// #
|
||||
/// # // We have only one chain: (0, 1).
|
||||
/// # let desc = Descriptor::new(0x1000, 0x1000, VIRTQ_DESC_F_NEXT, 1);
|
||||
/// # vq.desc_table().store(0, desc);
|
||||
/// # let desc = Descriptor::new(0x2000, 0x1000, VIRTQ_DESC_F_WRITE, 0);
|
||||
/// # vq.desc_table().store(1, desc);
|
||||
/// #
|
||||
/// # vq.avail().ring().ref_at(0).store(u16::to_le(0));
|
||||
/// # vq.avail().idx().store(u16::to_le(1));
|
||||
/// # q
|
||||
/// # }
|
||||
/// let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
/// // Populate the queue with descriptor chains and update the available ring accordingly.
|
||||
/// let mut queue = populate_queue(m);
|
||||
/// let mut i = queue.iter().unwrap();
|
||||
/// let mut c = i.next().unwrap();
|
||||
///
|
||||
/// // Get the first descriptor and access its fields.
|
||||
/// let desc = c.next().unwrap();
|
||||
/// let _addr = desc.addr();
|
||||
/// let _len = desc.len();
|
||||
/// let _flags = desc.flags();
|
||||
/// let _next = desc.next();
|
||||
/// let _is_write_only = desc.is_write_only();
|
||||
/// let _has_next = desc.has_next();
|
||||
/// let _refers_to_ind_table = desc.refers_to_indirect_table();
|
||||
/// ```
|
||||
// Note that the `ByteValued` implementation of this structure expects the `Descriptor` to store
|
||||
// only plain old data types.
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
pub struct Descriptor {
|
||||
/// Guest physical address of device specific data.
|
||||
addr: Le64,
|
||||
|
||||
/// Length of device specific data.
|
||||
len: Le32,
|
||||
|
||||
/// Includes next, write, and indirect bits.
|
||||
flags: Le16,
|
||||
|
||||
/// Index into the descriptor table of the next descriptor if flags has the `next` bit set.
|
||||
next: Le16,
|
||||
}
|
||||
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
impl Descriptor {
|
||||
/// Return the guest physical address of the descriptor buffer.
|
||||
pub fn addr(&self) -> GuestAddress {
|
||||
GuestAddress(self.addr.into())
|
||||
}
|
||||
|
||||
/// Return the length of the descriptor buffer.
|
||||
pub fn len(&self) -> u32 {
|
||||
self.len.into()
|
||||
}
|
||||
|
||||
/// Return the flags for this descriptor, including next, write and indirect bits.
|
||||
pub fn flags(&self) -> u16 {
|
||||
self.flags.into()
|
||||
}
|
||||
|
||||
/// Return the value stored in the `next` field of the descriptor.
|
||||
pub fn next(&self) -> u16 {
|
||||
self.next.into()
|
||||
}
|
||||
|
||||
/// Check whether this descriptor refers to a buffer containing an indirect descriptor table.
|
||||
pub fn refers_to_indirect_table(&self) -> bool {
|
||||
self.flags() & VIRTQ_DESC_F_INDIRECT != 0
|
||||
}
|
||||
|
||||
/// Check whether the `VIRTQ_DESC_F_NEXT` is set for the descriptor.
|
||||
pub fn has_next(&self) -> bool {
|
||||
self.flags() & VIRTQ_DESC_F_NEXT != 0
|
||||
}
|
||||
|
||||
/// Check if the driver designated this as a write only descriptor.
|
||||
///
|
||||
/// If this is false, this descriptor is read only.
|
||||
/// Write only means the the emulated device can write and the driver can read.
|
||||
pub fn is_write_only(&self) -> bool {
|
||||
self.flags() & VIRTQ_DESC_F_WRITE != 0
|
||||
}
|
||||
|
||||
/// Set the guest physical address of the descriptor buffer.
|
||||
pub fn set_addr(&mut self, addr: u64) {
|
||||
self.addr = addr.into();
|
||||
}
|
||||
}
|
||||
|
||||
impl Descriptor {
|
||||
/// Create a new descriptor.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `addr` - the guest physical address of the descriptor buffer.
|
||||
/// * `len` - the length of the descriptor buffer.
|
||||
/// * `flags` - the `flags` for the descriptor.
|
||||
/// * `next` - the `next` field of the descriptor.
|
||||
pub fn new(addr: u64, len: u32, flags: u16, next: u16) -> Self {
|
||||
Descriptor {
|
||||
addr: addr.into(),
|
||||
len: len.into(),
|
||||
flags: flags.into(),
|
||||
next: next.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the length of the descriptor buffer.
|
||||
pub fn set_len(&mut self, len: u32) {
|
||||
self.len = len.into();
|
||||
}
|
||||
|
||||
/// Set the flags for this descriptor.
|
||||
pub fn set_flags(&mut self, flags: u16) {
|
||||
self.flags = flags.into();
|
||||
}
|
||||
|
||||
/// Set the value stored in the `next` field of the descriptor.
|
||||
pub fn set_next(&mut self, next: u16) {
|
||||
self.next = next.into();
|
||||
}
|
||||
}
|
||||
|
||||
// This is safe because `Descriptor` contains only wrappers over POD types and all accesses through
|
||||
// safe `vm-memory` API will validate any garbage that could be included in there.
|
||||
unsafe impl ByteValued for Descriptor {}
|
||||
|
||||
/// Represents the contents of an element from the used virtqueue ring.
|
||||
// Note that the `ByteValued` implementation of this structure expects the `VirtqUsedElem` to store
|
||||
// only plain old data types.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Default, Debug)]
|
||||
pub struct VirtqUsedElem {
|
||||
id: Le32,
|
||||
len: Le32,
|
||||
}
|
||||
|
||||
impl VirtqUsedElem {
|
||||
/// Create a new `VirtqUsedElem` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `id` - the index of the used descriptor chain.
|
||||
/// * `len` - the total length of the descriptor chain which was used (written to).
|
||||
pub(crate) fn new(id: u32, len: u32) -> Self {
|
||||
VirtqUsedElem {
|
||||
id: id.into(),
|
||||
len: len.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
impl VirtqUsedElem {
|
||||
/// Get the index of the used descriptor chain.
|
||||
pub fn id(&self) -> u32 {
|
||||
self.id.into()
|
||||
}
|
||||
|
||||
/// Get `length` field of the used ring entry.
|
||||
pub fn len(&self) -> u32 {
|
||||
self.len.into()
|
||||
}
|
||||
}
|
||||
|
||||
// This is safe because `VirtqUsedElem` contains only wrappers over POD types and all accesses
|
||||
// through safe `vm-memory` API will validate any garbage that could be included in there.
|
||||
unsafe impl ByteValued for VirtqUsedElem {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use memoffset::offset_of;
|
||||
use std::mem::{align_of, size_of};
|
||||
|
||||
#[test]
|
||||
fn test_descriptor_offset() {
|
||||
assert_eq!(size_of::<Descriptor>(), 16);
|
||||
assert_eq!(offset_of!(Descriptor, addr), 0);
|
||||
assert_eq!(offset_of!(Descriptor, len), 8);
|
||||
assert_eq!(offset_of!(Descriptor, flags), 12);
|
||||
assert_eq!(offset_of!(Descriptor, next), 14);
|
||||
assert!(align_of::<Descriptor>() <= 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_descriptor_getter_setter() {
|
||||
let mut desc = Descriptor::new(0, 0, 0, 0);
|
||||
|
||||
desc.set_addr(0x1000);
|
||||
assert_eq!(desc.addr(), GuestAddress(0x1000));
|
||||
desc.set_len(0x2000);
|
||||
assert_eq!(desc.len(), 0x2000);
|
||||
desc.set_flags(VIRTQ_DESC_F_NEXT);
|
||||
assert_eq!(desc.flags(), VIRTQ_DESC_F_NEXT);
|
||||
assert!(desc.has_next());
|
||||
assert!(!desc.is_write_only());
|
||||
assert!(!desc.refers_to_indirect_table());
|
||||
desc.set_flags(VIRTQ_DESC_F_WRITE);
|
||||
assert_eq!(desc.flags(), VIRTQ_DESC_F_WRITE);
|
||||
assert!(!desc.has_next());
|
||||
assert!(desc.is_write_only());
|
||||
assert!(!desc.refers_to_indirect_table());
|
||||
desc.set_flags(VIRTQ_DESC_F_INDIRECT);
|
||||
assert_eq!(desc.flags(), VIRTQ_DESC_F_INDIRECT);
|
||||
assert!(!desc.has_next());
|
||||
assert!(!desc.is_write_only());
|
||||
assert!(desc.refers_to_indirect_table());
|
||||
desc.set_next(3);
|
||||
assert_eq!(desc.next(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_descriptor_copy() {
|
||||
let e1 = Descriptor::new(1, 2, VIRTQ_DESC_F_NEXT, 3);
|
||||
let mut e2 = Descriptor::default();
|
||||
|
||||
e2.as_mut_slice().copy_from_slice(e1.as_slice());
|
||||
assert_eq!(e1.addr(), e2.addr());
|
||||
assert_eq!(e1.len(), e2.len());
|
||||
assert_eq!(e1.flags(), e2.flags());
|
||||
assert_eq!(e1.next(), e2.next());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_used_elem_offset() {
|
||||
assert_eq!(offset_of!(VirtqUsedElem, id), 0);
|
||||
assert_eq!(offset_of!(VirtqUsedElem, len), 4);
|
||||
assert_eq!(size_of::<VirtqUsedElem>(), 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_used_elem_copy() {
|
||||
let e1 = VirtqUsedElem::new(3, 15);
|
||||
let mut e2 = VirtqUsedElem::new(0, 0);
|
||||
|
||||
e2.as_mut_slice().copy_from_slice(e1.as_slice());
|
||||
assert_eq!(e1.id, e2.id);
|
||||
assert_eq!(e1.len, e2.len);
|
||||
}
|
||||
}
|
||||
323
virtio-queue/src/iterator.rs
Normal file
323
virtio-queue/src/iterator.rs
Normal file
@@ -0,0 +1,323 @@
|
||||
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE-BSD-3-Clause file.
|
||||
//
|
||||
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
//
|
||||
// Copyright © 2019 Intel Corporation
|
||||
//
|
||||
// Copyright (C) 2020-2021 Alibaba Cloud. All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
|
||||
use std::num::Wrapping;
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
|
||||
use vm_memory::{Address, Bytes, GuestAddress, GuestMemory};
|
||||
|
||||
use crate::defs::{VIRTQ_AVAIL_ELEMENT_SIZE, VIRTQ_AVAIL_RING_HEADER_SIZE};
|
||||
use crate::{error, AccessPlatform, DescriptorChain, QueueState};
|
||||
|
||||
/// Consuming iterator over all available descriptor chain heads in the queue.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use virtio_queue::defs::{VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE};
|
||||
/// # use virtio_queue::mock::MockSplitQueue;
|
||||
/// use virtio_queue::{Descriptor, Queue};
|
||||
/// use vm_memory::{GuestAddress, GuestMemoryMmap};
|
||||
///
|
||||
/// # fn populate_queue(m: &GuestMemoryMmap) -> Queue<&GuestMemoryMmap> {
|
||||
/// # let vq = MockSplitQueue::new(m, 16);
|
||||
/// # let mut q = vq.create_queue(m);
|
||||
/// #
|
||||
/// # // The chains are (0, 1), (2, 3, 4) and (5, 6).
|
||||
/// # for i in 0..7 {
|
||||
/// # let flags = match i {
|
||||
/// # 1 | 6 => 0,
|
||||
/// # 2 | 5 => VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE,
|
||||
/// # 4 => VIRTQ_DESC_F_WRITE,
|
||||
/// # _ => VIRTQ_DESC_F_NEXT,
|
||||
/// # };
|
||||
/// #
|
||||
/// # let desc = Descriptor::new((0x1000 * (i + 1)) as u64, 0x1000, flags, i + 1);
|
||||
/// # vq.desc_table().store(i, desc);
|
||||
/// # }
|
||||
/// #
|
||||
/// # vq.avail().ring().ref_at(0).store(u16::to_le(0));
|
||||
/// # vq.avail().ring().ref_at(1).store(u16::to_le(2));
|
||||
/// # vq.avail().ring().ref_at(2).store(u16::to_le(5));
|
||||
/// # vq.avail().idx().store(u16::to_le(3));
|
||||
/// # q
|
||||
/// # }
|
||||
/// let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
/// // Populate the queue with descriptor chains and update the available ring accordingly.
|
||||
/// let mut queue = populate_queue(m);
|
||||
/// let mut i = queue.iter().unwrap();
|
||||
///
|
||||
/// {
|
||||
/// let mut c = i.next().unwrap();
|
||||
/// let _first_head_index = c.head_index();
|
||||
/// // We should have two descriptors in the first chain.
|
||||
/// let _desc1 = c.next().unwrap();
|
||||
/// let _desc2 = c.next().unwrap();
|
||||
/// }
|
||||
///
|
||||
/// {
|
||||
/// let c = i.next().unwrap();
|
||||
/// let _second_head_index = c.head_index();
|
||||
///
|
||||
/// let mut iter = c.writable();
|
||||
/// // We should have two writable descriptors in the second chain.
|
||||
/// let _desc1 = iter.next().unwrap();
|
||||
/// let _desc2 = iter.next().unwrap();
|
||||
/// }
|
||||
///
|
||||
/// {
|
||||
/// let c = i.next().unwrap();
|
||||
/// let _third_head_index = c.head_index();
|
||||
///
|
||||
/// let mut iter = c.readable();
|
||||
/// // We should have one readable descriptor in the third chain.
|
||||
/// let _desc1 = iter.next().unwrap();
|
||||
/// }
|
||||
/// // Let's go back one position in the available ring.
|
||||
/// i.go_to_previous_position();
|
||||
/// // We should be able to access again the third descriptor chain.
|
||||
/// let c = i.next().unwrap();
|
||||
/// let _third_head_index = c.head_index();
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct AvailIter<'b, M> {
|
||||
mem: M,
|
||||
desc_table: GuestAddress,
|
||||
avail_ring: GuestAddress,
|
||||
queue_size: u16,
|
||||
last_index: Wrapping<u16>,
|
||||
next_avail: &'b mut Wrapping<u16>,
|
||||
access_platform: &'b Option<Arc<dyn AccessPlatform>>,
|
||||
}
|
||||
|
||||
impl<'b, M> AvailIter<'b, M>
|
||||
where
|
||||
M: Deref,
|
||||
M::Target: GuestMemory + Sized,
|
||||
{
|
||||
/// Create a new instance of `AvailInter`.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `mem` - the `GuestMemory` object that can be used to access the queue buffers.
|
||||
/// * `idx` - the index of the available ring entry where the driver would put the next
|
||||
/// available descriptor chain.
|
||||
/// * `state` - the `QueueState` object from which the needed data to create the `AvailIter` can
|
||||
/// be retrieved.
|
||||
pub(crate) fn new(mem: M, idx: Wrapping<u16>, state: &'b mut QueueState) -> Self {
|
||||
AvailIter {
|
||||
mem,
|
||||
desc_table: state.desc_table,
|
||||
avail_ring: state.avail_ring,
|
||||
queue_size: state.size,
|
||||
last_index: idx,
|
||||
next_avail: &mut state.next_avail,
|
||||
access_platform: &state.access_platform,
|
||||
}
|
||||
}
|
||||
|
||||
/// Goes back one position in the available descriptor chain offered by the driver.
|
||||
///
|
||||
/// Rust does not support bidirectional iterators. This is the only way to revert the effect
|
||||
/// of an iterator increment on the queue.
|
||||
///
|
||||
/// Note: this method assumes there's only one thread manipulating the queue, so it should only
|
||||
/// be invoked in single-threaded context.
|
||||
pub fn go_to_previous_position(&mut self) {
|
||||
*self.next_avail -= Wrapping(1);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, M> Iterator for AvailIter<'b, M>
|
||||
where
|
||||
M: Clone + Deref,
|
||||
M::Target: GuestMemory,
|
||||
{
|
||||
type Item = DescriptorChain<M>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if *self.next_avail == self.last_index {
|
||||
return None;
|
||||
}
|
||||
|
||||
// These two operations can not overflow an u64 since they're working with relatively small
|
||||
// numbers compared to u64::MAX.
|
||||
let elem_off = u64::from(self.next_avail.0 % self.queue_size) * VIRTQ_AVAIL_ELEMENT_SIZE;
|
||||
let offset = VIRTQ_AVAIL_RING_HEADER_SIZE + elem_off;
|
||||
|
||||
let addr = self.avail_ring.checked_add(offset)?;
|
||||
let head_index: u16 = self
|
||||
.mem
|
||||
.load(addr, Ordering::Acquire)
|
||||
.map(u16::from_le)
|
||||
.map_err(|_| error!("Failed to read from memory {:x}", addr.raw_value()))
|
||||
.ok()?;
|
||||
|
||||
*self.next_avail += Wrapping(1);
|
||||
|
||||
Some(DescriptorChain::new(
|
||||
self.mem.clone(),
|
||||
self.desc_table,
|
||||
self.queue_size,
|
||||
head_index,
|
||||
self.access_platform.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::defs::{VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE};
|
||||
use crate::mock::MockSplitQueue;
|
||||
use crate::Descriptor;
|
||||
use vm_memory::GuestMemoryMmap;
|
||||
|
||||
#[test]
|
||||
fn test_descriptor_and_iterator() {
|
||||
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
|
||||
let mut q = vq.create_queue(m);
|
||||
|
||||
// q is currently valid
|
||||
assert!(q.is_valid());
|
||||
|
||||
// the chains are (0, 1), (2, 3, 4) and (5, 6)
|
||||
for j in 0..7 {
|
||||
let flags = match j {
|
||||
1 | 6 => 0,
|
||||
2 | 5 => VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE,
|
||||
4 => VIRTQ_DESC_F_WRITE,
|
||||
_ => VIRTQ_DESC_F_NEXT,
|
||||
};
|
||||
|
||||
let desc = Descriptor::new((0x1000 * (j + 1)) as u64, 0x1000, flags, j + 1);
|
||||
vq.desc_table().store(j, desc);
|
||||
}
|
||||
|
||||
vq.avail().ring().ref_at(0).store(u16::to_le(0));
|
||||
vq.avail().ring().ref_at(1).store(u16::to_le(2));
|
||||
vq.avail().ring().ref_at(2).store(u16::to_le(5));
|
||||
vq.avail().idx().store(u16::to_le(3));
|
||||
|
||||
let mut i = q.iter().unwrap();
|
||||
|
||||
{
|
||||
let c = i.next().unwrap();
|
||||
assert_eq!(c.head_index(), 0);
|
||||
|
||||
let mut iter = c;
|
||||
assert!(iter.next().is_some());
|
||||
assert!(iter.next().is_some());
|
||||
assert!(iter.next().is_none());
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
|
||||
{
|
||||
let c = i.next().unwrap();
|
||||
assert_eq!(c.head_index(), 2);
|
||||
|
||||
let mut iter = c.writable();
|
||||
assert!(iter.next().is_some());
|
||||
assert!(iter.next().is_some());
|
||||
assert!(iter.next().is_none());
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
|
||||
{
|
||||
let c = i.next().unwrap();
|
||||
assert_eq!(c.head_index(), 5);
|
||||
|
||||
let mut iter = c.readable();
|
||||
assert!(iter.next().is_some());
|
||||
assert!(iter.next().is_none());
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator() {
|
||||
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
|
||||
let mut q = vq.create_queue(m);
|
||||
|
||||
q.state.size = q.state.max_size;
|
||||
q.state.desc_table = vq.desc_table_addr();
|
||||
q.state.avail_ring = vq.avail_addr();
|
||||
q.state.used_ring = vq.used_addr();
|
||||
assert!(q.is_valid());
|
||||
|
||||
{
|
||||
// an invalid queue should return an iterator with no next
|
||||
q.state.ready = false;
|
||||
let mut i = q.iter().unwrap();
|
||||
assert!(i.next().is_none());
|
||||
}
|
||||
|
||||
q.state.ready = true;
|
||||
|
||||
// now let's create two simple descriptor chains
|
||||
// the chains are (0, 1) and (2, 3, 4)
|
||||
{
|
||||
for j in 0..5u16 {
|
||||
let flags = match j {
|
||||
1 | 4 => 0,
|
||||
_ => VIRTQ_DESC_F_NEXT,
|
||||
};
|
||||
|
||||
let desc = Descriptor::new((0x1000 * (j + 1)) as u64, 0x1000, flags, j + 1);
|
||||
vq.desc_table().store(j, desc);
|
||||
}
|
||||
|
||||
vq.avail().ring().ref_at(0).store(u16::to_le(0));
|
||||
vq.avail().ring().ref_at(1).store(u16::to_le(2));
|
||||
vq.avail().idx().store(u16::to_le(2));
|
||||
|
||||
let mut i = q.iter().unwrap();
|
||||
|
||||
{
|
||||
let mut c = i.next().unwrap();
|
||||
assert_eq!(c.head_index(), 0);
|
||||
|
||||
c.next().unwrap();
|
||||
assert!(c.next().is_some());
|
||||
assert!(c.next().is_none());
|
||||
assert_eq!(c.head_index(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
let mut c = i.next().unwrap();
|
||||
assert_eq!(c.head_index(), 2);
|
||||
|
||||
c.next().unwrap();
|
||||
c.next().unwrap();
|
||||
c.next().unwrap();
|
||||
assert!(c.next().is_none());
|
||||
assert_eq!(c.head_index(), 2);
|
||||
}
|
||||
|
||||
// also test go_to_previous_position() works as expected
|
||||
{
|
||||
assert!(i.next().is_none());
|
||||
i.go_to_previous_position();
|
||||
let mut c = q.iter().unwrap().next().unwrap();
|
||||
c.next().unwrap();
|
||||
c.next().unwrap();
|
||||
c.next().unwrap();
|
||||
assert!(c.next().is_none());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
370
virtio-queue/src/mock.rs
Normal file
370
virtio-queue/src/mock.rs
Normal file
@@ -0,0 +1,370 @@
|
||||
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
|
||||
|
||||
//! Utilities used by unit tests and benchmarks for mocking the driver side
|
||||
//! of the virtio protocol.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::size_of;
|
||||
|
||||
use vm_memory::{
|
||||
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestUsize,
|
||||
};
|
||||
|
||||
use crate::defs::{VIRTQ_DESC_F_INDIRECT, VIRTQ_DESC_F_NEXT};
|
||||
use crate::{Descriptor, Queue, QueueState, VirtqUsedElem};
|
||||
|
||||
/// Wrapper struct used for accessing a particular address of a GuestMemory area.
|
||||
pub struct Ref<'a, M, T> {
|
||||
mem: &'a M,
|
||||
addr: GuestAddress,
|
||||
phantom: PhantomData<*const T>,
|
||||
}
|
||||
|
||||
impl<'a, M: GuestMemory, T: ByteValued> Ref<'a, M, T> {
|
||||
fn new(mem: &'a M, addr: GuestAddress) -> Self {
|
||||
Ref {
|
||||
mem,
|
||||
addr,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Read an object of type T from the underlying memory found at self.addr.
|
||||
pub fn load(&self) -> T {
|
||||
self.mem.read_obj(self.addr).unwrap()
|
||||
}
|
||||
|
||||
/// Write an object of type T from the underlying memory found at self.addr.
|
||||
pub fn store(&self, val: T) {
|
||||
self.mem.write_obj(val, self.addr).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper struct used for accessing a subregion of a GuestMemory area.
|
||||
pub struct ArrayRef<'a, M, T> {
|
||||
mem: &'a M,
|
||||
addr: GuestAddress,
|
||||
len: usize,
|
||||
phantom: PhantomData<*const T>,
|
||||
}
|
||||
|
||||
impl<'a, M: GuestMemory, T: ByteValued> ArrayRef<'a, M, T> {
|
||||
fn new(mem: &'a M, addr: GuestAddress, len: usize) -> Self {
|
||||
ArrayRef {
|
||||
mem,
|
||||
addr,
|
||||
len,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a `Ref` object pointing to an address defined by a particular
|
||||
/// index offset in the region.
|
||||
pub fn ref_at(&self, index: usize) -> Ref<'a, M, T> {
|
||||
// TODO: add better error handling to the mock logic.
|
||||
assert!(index < self.len);
|
||||
|
||||
let addr = self
|
||||
.addr
|
||||
.checked_add((index * size_of::<T>()) as u64)
|
||||
.unwrap();
|
||||
|
||||
Ref::new(self.mem, addr)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a virtio queue ring. The only difference between the used and available rings,
|
||||
/// is the ring element type.
|
||||
pub struct SplitQueueRing<'a, M, T: ByteValued> {
|
||||
flags: Ref<'a, M, u16>,
|
||||
// The value stored here should more precisely be a `Wrapping<u16>`, but that would require a
|
||||
// `ByteValued` impl for this type, which is not provided in vm-memory. Implementing the trait
|
||||
// here would require defining a wrapper for `Wrapping<u16>` and that would be too much for a
|
||||
// mock framework that is only used in tests.
|
||||
idx: Ref<'a, M, u16>,
|
||||
ring: ArrayRef<'a, M, T>,
|
||||
// `used_event` for `AvailRing`, `avail_event` for `UsedRing`.
|
||||
event: Ref<'a, M, u16>,
|
||||
}
|
||||
|
||||
impl<'a, M: GuestMemory, T: ByteValued> SplitQueueRing<'a, M, T> {
|
||||
/// Create a new `SplitQueueRing` instance
|
||||
pub fn new(mem: &'a M, base: GuestAddress, len: u16) -> Self {
|
||||
let event_addr = base
|
||||
.checked_add(4)
|
||||
.and_then(|a| a.checked_add((size_of::<u16>() * len as usize) as u64))
|
||||
.unwrap();
|
||||
|
||||
let split_queue_ring = SplitQueueRing {
|
||||
flags: Ref::new(mem, base),
|
||||
idx: Ref::new(mem, base.checked_add(2).unwrap()),
|
||||
ring: ArrayRef::new(mem, base.checked_add(4).unwrap(), len as usize),
|
||||
event: Ref::new(mem, event_addr),
|
||||
};
|
||||
|
||||
split_queue_ring.flags.store(0);
|
||||
split_queue_ring.idx.store(0);
|
||||
split_queue_ring.event.store(0);
|
||||
|
||||
split_queue_ring
|
||||
}
|
||||
|
||||
/// Return the starting address of the `SplitQueueRing`.
|
||||
pub fn start(&self) -> GuestAddress {
|
||||
self.ring.addr
|
||||
}
|
||||
|
||||
/// Return the end address of the `SplitQueueRing`.
|
||||
pub fn end(&self) -> GuestAddress {
|
||||
self.start()
|
||||
.checked_add(self.ring.len as GuestUsize)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Return a reference to the idx field.
|
||||
pub fn idx(&self) -> &Ref<'a, M, u16> {
|
||||
&self.idx
|
||||
}
|
||||
|
||||
/// Return a reference to the ring field.
|
||||
pub fn ring(&self) -> &ArrayRef<'a, M, T> {
|
||||
&self.ring
|
||||
}
|
||||
}
|
||||
|
||||
/// The available ring is used by the driver to offer buffers to the device.
|
||||
pub type AvailRing<'a, M> = SplitQueueRing<'a, M, u16>;
|
||||
/// The used ring is where the device returns buffers once it is done with them.
|
||||
pub type UsedRing<'a, M> = SplitQueueRing<'a, M, VirtqUsedElem>;
|
||||
|
||||
/// Refers to the buffers the driver is using for the device.
|
||||
pub struct DescriptorTable<'a, M> {
|
||||
table: ArrayRef<'a, M, Descriptor>,
|
||||
len: u16,
|
||||
free_descriptors: Vec<u16>,
|
||||
}
|
||||
|
||||
impl<'a, M: GuestMemory> DescriptorTable<'a, M> {
|
||||
/// Create a new `DescriptorTable` instance
|
||||
pub fn new(mem: &'a M, addr: GuestAddress, len: u16) -> Self {
|
||||
let table = ArrayRef::new(mem, addr, len as usize);
|
||||
let free_descriptors = (0..len).rev().collect();
|
||||
|
||||
DescriptorTable {
|
||||
table,
|
||||
len,
|
||||
free_descriptors,
|
||||
}
|
||||
}
|
||||
|
||||
/// Read one descriptor from the specified index.
|
||||
pub fn load(&self, index: u16) -> Descriptor {
|
||||
self.table.ref_at(index as usize).load()
|
||||
}
|
||||
|
||||
/// Write one descriptor at the specified index.
|
||||
pub fn store(&self, index: u16, value: Descriptor) {
|
||||
self.table.ref_at(index as usize).store(value)
|
||||
}
|
||||
|
||||
/// Return the total size of the DescriptorTable in bytes.
|
||||
pub fn total_size(&self) -> u64 {
|
||||
(self.len as usize * size_of::<Descriptor>()) as u64
|
||||
}
|
||||
|
||||
/// Create a chain of descriptors.
|
||||
pub fn build_chain(&mut self, len: u16) -> u16 {
|
||||
let indices = self
|
||||
.free_descriptors
|
||||
.iter()
|
||||
.copied()
|
||||
.rev()
|
||||
.take(usize::from(len))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(indices.len(), len as usize);
|
||||
|
||||
for (pos, index_value) in indices.iter().copied().enumerate() {
|
||||
// Addresses and lens constant for now.
|
||||
let mut desc = Descriptor::new(0x1000, 0x1000, 0, 0);
|
||||
|
||||
// It's not the last descriptor in the chain.
|
||||
if pos < indices.len() - 1 {
|
||||
desc.set_flags(VIRTQ_DESC_F_NEXT);
|
||||
desc.set_next(indices[pos + 1]);
|
||||
} else {
|
||||
desc.set_flags(0);
|
||||
}
|
||||
self.store(index_value, desc);
|
||||
}
|
||||
|
||||
indices[0]
|
||||
}
|
||||
}
|
||||
|
||||
trait GuestAddressExt {
|
||||
fn align_up(&self, x: GuestUsize) -> GuestAddress;
|
||||
}
|
||||
|
||||
impl GuestAddressExt for GuestAddress {
|
||||
fn align_up(&self, x: GuestUsize) -> GuestAddress {
|
||||
Self((self.0 + (x - 1)) & !(x - 1))
|
||||
}
|
||||
}
|
||||
|
||||
/// A mock version of the virtio queue implemented from the perspective of the driver.
|
||||
pub struct MockSplitQueue<'a, M> {
|
||||
mem: &'a M,
|
||||
len: u16,
|
||||
desc_table_addr: GuestAddress,
|
||||
desc_table: DescriptorTable<'a, M>,
|
||||
avail_addr: GuestAddress,
|
||||
avail: AvailRing<'a, M>,
|
||||
used_addr: GuestAddress,
|
||||
used: UsedRing<'a, M>,
|
||||
indirect_addr: GuestAddress,
|
||||
}
|
||||
|
||||
impl<'a, M: GuestMemory> MockSplitQueue<'a, M> {
|
||||
/// Create a new `MockSplitQueue` instance with 0 as the default guest
|
||||
/// physical starting address.
|
||||
pub fn new(mem: &'a M, len: u16) -> Self {
|
||||
Self::create(mem, GuestAddress(0), len)
|
||||
}
|
||||
|
||||
/// Create a new `MockSplitQueue` instance.
|
||||
pub fn create(mem: &'a M, start: GuestAddress, len: u16) -> Self {
|
||||
const AVAIL_ALIGN: GuestUsize = 2;
|
||||
const USED_ALIGN: GuestUsize = 4;
|
||||
|
||||
let desc_table_addr = start;
|
||||
let desc_table = DescriptorTable::new(mem, desc_table_addr, len);
|
||||
|
||||
let avail_addr = start
|
||||
.checked_add(16 * len as GuestUsize)
|
||||
.unwrap()
|
||||
.align_up(AVAIL_ALIGN);
|
||||
let avail = AvailRing::new(mem, avail_addr, len);
|
||||
|
||||
let used_addr = avail.end().align_up(USED_ALIGN);
|
||||
let used = UsedRing::new(mem, used_addr, len);
|
||||
|
||||
let indirect_addr = GuestAddress(0x3000_0000);
|
||||
|
||||
MockSplitQueue {
|
||||
mem,
|
||||
len,
|
||||
desc_table_addr,
|
||||
desc_table,
|
||||
avail_addr,
|
||||
avail,
|
||||
used_addr,
|
||||
used,
|
||||
indirect_addr,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the starting address of the queue.
|
||||
pub fn start(&self) -> GuestAddress {
|
||||
self.desc_table_addr
|
||||
}
|
||||
|
||||
/// Return the end address of the queue.
|
||||
pub fn end(&self) -> GuestAddress {
|
||||
self.used.end()
|
||||
}
|
||||
|
||||
/// Descriptor table accessor.
|
||||
pub fn desc_table(&self) -> &DescriptorTable<'a, M> {
|
||||
&self.desc_table
|
||||
}
|
||||
|
||||
/// Available ring accessor.
|
||||
pub fn avail(&self) -> &AvailRing<M> {
|
||||
&self.avail
|
||||
}
|
||||
|
||||
/// Used ring accessor.
|
||||
pub fn used(&self) -> &UsedRing<M> {
|
||||
&self.used
|
||||
}
|
||||
|
||||
/// Return the starting address of the descriptor table.
|
||||
pub fn desc_table_addr(&self) -> GuestAddress {
|
||||
self.desc_table_addr
|
||||
}
|
||||
|
||||
/// Return the starting address of the available ring.
|
||||
pub fn avail_addr(&self) -> GuestAddress {
|
||||
self.avail_addr
|
||||
}
|
||||
|
||||
/// Return the starting address of the used ring.
|
||||
pub fn used_addr(&self) -> GuestAddress {
|
||||
self.used_addr
|
||||
}
|
||||
|
||||
fn update_avail_idx(&mut self, value: u16) {
|
||||
let avail_idx = self.avail.idx.load();
|
||||
self.avail.ring.ref_at(avail_idx as usize).store(value);
|
||||
self.avail.idx.store(avail_idx.wrapping_add(1));
|
||||
}
|
||||
|
||||
fn alloc_indirect_chain(&mut self, len: u16) -> GuestAddress {
|
||||
// To simplify things for now, we round up the table len as a multiple of 16. When this is
|
||||
// no longer the case, we should make sure the starting address of the descriptor table
|
||||
// we're creating below is properly aligned.
|
||||
|
||||
let table_len = if len % 16 == 0 {
|
||||
len
|
||||
} else {
|
||||
16 * (len / 16 + 1)
|
||||
};
|
||||
|
||||
let mut table = DescriptorTable::new(self.mem, self.indirect_addr, table_len);
|
||||
let head_decriptor_index = table.build_chain(len);
|
||||
// When building indirect descriptor tables, the descriptor at index 0 is supposed to be
|
||||
// first in the resulting chain. Just making sure our logic actually makes that happen.
|
||||
assert_eq!(head_decriptor_index, 0);
|
||||
|
||||
let table_addr = self.indirect_addr;
|
||||
self.indirect_addr = self.indirect_addr.checked_add(table.total_size()).unwrap();
|
||||
table_addr
|
||||
}
|
||||
|
||||
/// Add a descriptor chain to the table.
|
||||
pub fn add_chain(&mut self, len: u16) {
|
||||
let head_idx = self.desc_table.build_chain(len);
|
||||
self.update_avail_idx(head_idx);
|
||||
}
|
||||
|
||||
/// Add an indirect descriptor chain to the table.
|
||||
pub fn add_indirect_chain(&mut self, len: u16) {
|
||||
let head_idx = self.desc_table.build_chain(1);
|
||||
|
||||
// We just allocate the indirect table and forget about it for now.
|
||||
let indirect_addr = self.alloc_indirect_chain(len);
|
||||
|
||||
let mut desc = self.desc_table.load(head_idx);
|
||||
desc.set_flags(VIRTQ_DESC_F_INDIRECT);
|
||||
desc.set_addr(indirect_addr.raw_value());
|
||||
desc.set_len(u32::from(len) * size_of::<Descriptor>() as u32);
|
||||
|
||||
self.desc_table.store(head_idx, desc);
|
||||
self.update_avail_idx(head_idx);
|
||||
}
|
||||
|
||||
/// Creates a new `Queue`, using the underlying memory regions represented
|
||||
/// by the `MockSplitQueue`.
|
||||
pub fn create_queue<A: GuestAddressSpace>(&self, a: A) -> Queue<A, QueueState> {
|
||||
let mut q = Queue::<A, QueueState>::new(a, self.len);
|
||||
|
||||
q.state.size = self.len;
|
||||
q.state.ready = true;
|
||||
q.state.desc_table = self.desc_table_addr;
|
||||
q.state.avail_ring = self.avail_addr;
|
||||
q.state.used_ring = self.used_addr;
|
||||
q
|
||||
}
|
||||
}
|
||||
683
virtio-queue/src/queue.rs
Normal file
683
virtio-queue/src/queue.rs
Normal file
@@ -0,0 +1,683 @@
|
||||
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
//
|
||||
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE-BSD-3-Clause file.
|
||||
//
|
||||
// Copyright © 2019 Intel Corporation
|
||||
//
|
||||
// Copyright (C) 2020-2021 Alibaba Cloud. All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
|
||||
use std::num::Wrapping;
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use vm_memory::GuestAddressSpace;
|
||||
|
||||
use crate::{AvailIter, Error, QueueGuard, QueueState, QueueStateGuard, QueueStateT};
|
||||
|
||||
/// A convenient wrapper struct for a virtio queue, with associated `GuestMemory` object.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use virtio_queue::{Queue, QueueState};
|
||||
/// use vm_memory::{Bytes, GuestAddress, GuestAddressSpace, GuestMemoryMmap};
|
||||
///
|
||||
/// let m = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
/// let mut queue = Queue::<&GuestMemoryMmap, QueueState>::new(&m, 1024);
|
||||
///
|
||||
/// // First, the driver sets up the queue; this set up is done via writes on the bus (PCI, MMIO).
|
||||
/// queue.set_size(8);
|
||||
/// queue.set_desc_table_address(Some(0x1000), None);
|
||||
/// queue.set_avail_ring_address(Some(0x2000), None);
|
||||
/// queue.set_used_ring_address(Some(0x3000), None);
|
||||
/// queue.set_event_idx(true);
|
||||
/// queue.set_ready(true);
|
||||
/// // The user should check if the queue is valid before starting to use it.
|
||||
/// assert!(queue.is_valid());
|
||||
///
|
||||
/// // Here the driver would add entries in the available ring and then update the `idx` field of
|
||||
/// // the available ring (address = 0x2000 + 2).
|
||||
/// m.write_obj(3, GuestAddress(0x2002));
|
||||
///
|
||||
/// loop {
|
||||
/// queue.disable_notification().unwrap();
|
||||
///
|
||||
/// // Consume entries from the available ring.
|
||||
/// while let Some(chain) = queue.iter().unwrap().next() {
|
||||
/// // Process the descriptor chain, and then add an entry in the used ring and optionally
|
||||
/// // notify the driver.
|
||||
/// queue.add_used(chain.head_index(), 0x100).unwrap();
|
||||
///
|
||||
/// if queue.needs_notification().unwrap() {
|
||||
/// // Here we would notify the driver it has new entries in the used ring to consume.
|
||||
/// }
|
||||
/// }
|
||||
/// if !queue.enable_notification().unwrap() {
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // We can reset the queue at some point.
|
||||
/// queue.reset();
|
||||
/// // The queue should not be ready after reset.
|
||||
/// assert!(!queue.ready());
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Queue<M: GuestAddressSpace, S: QueueStateT = QueueState> {
|
||||
/// Guest memory object associated with the queue.
|
||||
pub mem: M,
|
||||
/// Virtio queue state.
|
||||
pub state: S,
|
||||
}
|
||||
|
||||
impl<M: GuestAddressSpace, S: QueueStateT> Queue<M, S> {
|
||||
/// Construct an empty virtio queue with the given `max_size`.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `mem` - the guest memory object that can be used to access the queue buffers.
|
||||
/// * `max_size` - the maximum size (and the default one) of the queue.
|
||||
pub fn new(mem: M, max_size: u16) -> Self {
|
||||
Queue {
|
||||
mem,
|
||||
state: S::new(max_size),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether the queue configuration is valid.
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.state.is_valid(self.mem.memory().deref())
|
||||
}
|
||||
|
||||
/// Reset the queue to the initial state.
|
||||
pub fn reset(&mut self) {
|
||||
self.state.reset()
|
||||
}
|
||||
|
||||
/// Get an exclusive reference to the underlying `QueueState` object.
|
||||
///
|
||||
/// Logically this method will acquire the underlying lock protecting the `QueueState` Object.
|
||||
/// The lock will be released when the returned object gets dropped.
|
||||
pub fn lock(&mut self) -> <S as QueueStateGuard>::G {
|
||||
self.state.lock()
|
||||
}
|
||||
|
||||
/// Get an exclusive reference to the underlying `QueueState` object with an associated
|
||||
/// `GuestMemory` object.
|
||||
///
|
||||
/// Logically this method will acquire the underlying lock protecting the `QueueState` Object.
|
||||
/// The lock will be released when the returned object gets dropped.
|
||||
pub fn lock_with_memory(
|
||||
&mut self,
|
||||
) -> QueueGuard<<M as GuestAddressSpace>::T, <S as QueueStateGuard>::G> {
|
||||
QueueGuard::new(self.state.lock(), self.mem.memory())
|
||||
}
|
||||
|
||||
/// Get the maximum size of the virtio queue.
|
||||
pub fn max_size(&self) -> u16 {
|
||||
self.state.max_size()
|
||||
}
|
||||
|
||||
/// Configure the queue size for the virtio queue.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `size` - the queue size; it should be a power of two, different than 0 and less than or
|
||||
/// equal to the value reported by `max_size()`, otherwise the queue size remains the
|
||||
/// default one (which is the maximum one).
|
||||
pub fn set_size(&mut self, size: u16) {
|
||||
self.state.set_size(size);
|
||||
}
|
||||
|
||||
/// Check whether the queue is ready to be processed.
|
||||
pub fn ready(&self) -> bool {
|
||||
self.state.ready()
|
||||
}
|
||||
|
||||
/// Configure the queue to the `ready for processing` state.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `ready` - a boolean to indicate whether the queue is ready to be used or not.
|
||||
pub fn set_ready(&mut self, ready: bool) {
|
||||
self.state.set_ready(ready)
|
||||
}
|
||||
|
||||
/// Set the descriptor table address for the queue.
|
||||
///
|
||||
/// The descriptor table address is 64-bit, the corresponding part will be updated if 'low'
|
||||
/// and/or `high` is `Some` and valid.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `low` - an optional value for the lowest 32 bits of the address.
|
||||
/// * `high` - an optional value for the highest 32 bits of the address.
|
||||
pub fn set_desc_table_address(&mut self, low: Option<u32>, high: Option<u32>) {
|
||||
self.state.set_desc_table_address(low, high);
|
||||
}
|
||||
|
||||
/// Set the available ring address for the queue.
|
||||
///
|
||||
/// The available ring address is 64-bit, the corresponding part will be updated if 'low'
|
||||
/// and/or `high` is `Some` and valid.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `low` - an optional value for the lowest 32 bits of the address.
|
||||
/// * `high` - an optional value for the highest 32 bits of the address.
|
||||
pub fn set_avail_ring_address(&mut self, low: Option<u32>, high: Option<u32>) {
|
||||
self.state.set_avail_ring_address(low, high);
|
||||
}
|
||||
|
||||
/// Set the used ring address for the queue.
|
||||
///
|
||||
/// The used ring address is 64-bit, the corresponding part will be updated if 'low'
|
||||
/// and/or `high` is `Some` and valid.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `low` - an optional value for the lowest 32 bits of the address.
|
||||
/// * `high` - an optional value for the highest 32 bits of the address.
|
||||
pub fn set_used_ring_address(&mut self, low: Option<u32>, high: Option<u32>) {
|
||||
self.state.set_used_ring_address(low, high);
|
||||
}
|
||||
|
||||
/// Enable/disable the VIRTIO_F_RING_EVENT_IDX feature for interrupt coalescing.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `enabled` - a boolean to indicate whether the VIRTIO_F_RING_EVENT_IDX feature was
|
||||
/// successfully negotiated or not.
|
||||
pub fn set_event_idx(&mut self, enabled: bool) {
|
||||
self.state.set_event_idx(enabled)
|
||||
}
|
||||
|
||||
/// Read the `idx` field from the available ring.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `order` - the memory ordering used to access the `idx` field from memory.
|
||||
pub fn avail_idx(&self, order: Ordering) -> Result<Wrapping<u16>, Error> {
|
||||
self.state.avail_idx(self.mem.memory().deref(), order)
|
||||
}
|
||||
|
||||
/// Reads the `idx` field from the used ring.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `order` - the memory ordering used to access the `idx` field from memory.
|
||||
pub fn used_idx(&self, order: Ordering) -> Result<Wrapping<u16>, Error> {
|
||||
self.state.used_idx(self.mem.memory().deref(), order)
|
||||
}
|
||||
|
||||
/// Put a used descriptor head into the used ring.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `head_index` - the index of the used descriptor chain.
|
||||
/// * `len` - the total length of the descriptor chain which was used (written to).
|
||||
pub fn add_used(&mut self, head_index: u16, len: u32) -> Result<(), Error> {
|
||||
self.state
|
||||
.add_used(self.mem.memory().deref(), head_index, len)
|
||||
}
|
||||
|
||||
/// Enable notification events from the guest driver.
|
||||
///
|
||||
/// Return true if one or more descriptors can be consumed from the available ring after
|
||||
/// notifications were enabled (and thus it's possible there will be no corresponding
|
||||
/// notification).
|
||||
pub fn enable_notification(&mut self) -> Result<bool, Error> {
|
||||
self.state.enable_notification(self.mem.memory().deref())
|
||||
}
|
||||
|
||||
/// Disable notification events from the guest driver.
|
||||
pub fn disable_notification(&mut self) -> Result<(), Error> {
|
||||
self.state.disable_notification(self.mem.memory().deref())
|
||||
}
|
||||
|
||||
/// Check whether a notification to the guest is needed.
|
||||
///
|
||||
/// Please note this method has side effects: once it returns `true`, it considers the
|
||||
/// driver will actually be notified, remember the associated index in the used ring, and
|
||||
/// won't return `true` again until the driver updates `used_event` and/or the notification
|
||||
/// conditions hold once more.
|
||||
pub fn needs_notification(&mut self) -> Result<bool, Error> {
|
||||
self.state.needs_notification(self.mem.memory().deref())
|
||||
}
|
||||
|
||||
/// Return the index of the next entry in the available ring.
|
||||
pub fn next_avail(&self) -> u16 {
|
||||
self.state.next_avail()
|
||||
}
|
||||
|
||||
/// Returns the index for the next descriptor in the used ring.
|
||||
pub fn next_used(&self) -> u16 {
|
||||
self.state.next_used()
|
||||
}
|
||||
|
||||
/// Set the index of the next entry in the available ring.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `next_avail` - the index of the next available ring entry.
|
||||
pub fn set_next_avail(&mut self, next_avail: u16) {
|
||||
self.state.set_next_avail(next_avail);
|
||||
}
|
||||
|
||||
/// Sets the index for the next descriptor in the used ring.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `next_used` - the index of the next used ring entry.
|
||||
pub fn set_next_used(&mut self, next_used: u16) {
|
||||
self.state.set_next_used(next_used);
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: GuestAddressSpace> Queue<M, QueueState> {
|
||||
/// A consuming iterator over all available descriptor chain heads offered by the driver.
|
||||
pub fn iter(&mut self) -> Result<AvailIter<'_, M::T>, Error> {
|
||||
self.state.iter(self.mem.memory())
|
||||
}
|
||||
|
||||
/// Set the queue to "ready", and update desc_table, avail_ring and
|
||||
/// used_ring addresses based on the AccessPlatform handler.
|
||||
pub fn enable(&mut self, set: bool) {
|
||||
self.state.enable(set)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::defs::{
|
||||
DEFAULT_AVAIL_RING_ADDR, DEFAULT_DESC_TABLE_ADDR, DEFAULT_USED_RING_ADDR,
|
||||
VIRTQ_DESC_F_NEXT, VIRTQ_USED_F_NO_NOTIFY,
|
||||
};
|
||||
use crate::mock::MockSplitQueue;
|
||||
use crate::Descriptor;
|
||||
|
||||
use vm_memory::{Address, Bytes, GuestAddress, GuestMemoryMmap};
|
||||
|
||||
#[test]
|
||||
fn test_queue_is_valid() {
|
||||
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
let mut q = vq.create_queue(m);
|
||||
|
||||
// q is currently valid
|
||||
assert!(q.is_valid());
|
||||
|
||||
// shouldn't be valid when not marked as ready
|
||||
q.set_ready(false);
|
||||
assert!(!q.ready());
|
||||
assert!(!q.is_valid());
|
||||
q.set_ready(true);
|
||||
|
||||
// shouldn't be allowed to set a size > max_size
|
||||
q.set_size(q.max_size() << 1);
|
||||
assert_eq!(q.state.size, q.max_size());
|
||||
|
||||
// or set the size to 0
|
||||
q.set_size(0);
|
||||
assert_eq!(q.state.size, q.max_size());
|
||||
|
||||
// or set a size which is not a power of 2
|
||||
q.set_size(11);
|
||||
assert_eq!(q.state.size, q.max_size());
|
||||
|
||||
// but should be allowed to set a size if 0 < size <= max_size and size is a power of two
|
||||
q.set_size(4);
|
||||
assert_eq!(q.state.size, 4);
|
||||
q.state.size = q.max_size();
|
||||
|
||||
// shouldn't be allowed to set an address that breaks the alignment constraint
|
||||
q.set_desc_table_address(Some(0xf), None);
|
||||
assert_eq!(q.state.desc_table.0, vq.desc_table_addr().0);
|
||||
// should be allowed to set an aligned out of bounds address
|
||||
q.set_desc_table_address(Some(0xffff_fff0), None);
|
||||
assert_eq!(q.state.desc_table.0, 0xffff_fff0);
|
||||
// but shouldn't be valid
|
||||
assert!(!q.is_valid());
|
||||
// but should be allowed to set a valid description table address
|
||||
q.set_desc_table_address(Some(0x10), None);
|
||||
assert_eq!(q.state.desc_table.0, 0x10);
|
||||
assert!(q.is_valid());
|
||||
let addr = vq.desc_table_addr().0;
|
||||
q.set_desc_table_address(Some(addr as u32), Some((addr >> 32) as u32));
|
||||
|
||||
// shouldn't be allowed to set an address that breaks the alignment constraint
|
||||
q.set_avail_ring_address(Some(0x1), None);
|
||||
assert_eq!(q.state.avail_ring.0, vq.avail_addr().0);
|
||||
// should be allowed to set an aligned out of bounds address
|
||||
q.set_avail_ring_address(Some(0xffff_fffe), None);
|
||||
assert_eq!(q.state.avail_ring.0, 0xffff_fffe);
|
||||
// but shouldn't be valid
|
||||
assert!(!q.is_valid());
|
||||
// but should be allowed to set a valid available ring address
|
||||
q.set_avail_ring_address(Some(0x2), None);
|
||||
assert_eq!(q.state.avail_ring.0, 0x2);
|
||||
assert!(q.is_valid());
|
||||
let addr = vq.avail_addr().0;
|
||||
q.set_avail_ring_address(Some(addr as u32), Some((addr >> 32) as u32));
|
||||
|
||||
// shouldn't be allowed to set an address that breaks the alignment constraint
|
||||
q.set_used_ring_address(Some(0x3), None);
|
||||
assert_eq!(q.state.used_ring.0, vq.used_addr().0);
|
||||
// should be allowed to set an aligned out of bounds address
|
||||
q.set_used_ring_address(Some(0xffff_fffc), None);
|
||||
assert_eq!(q.state.used_ring.0, 0xffff_fffc);
|
||||
// but shouldn't be valid
|
||||
assert!(!q.is_valid());
|
||||
// but should be allowed to set a valid used ring address
|
||||
q.set_used_ring_address(Some(0x4), None);
|
||||
assert_eq!(q.state.used_ring.0, 0x4);
|
||||
let addr = vq.used_addr().0;
|
||||
q.set_used_ring_address(Some(addr as u32), Some((addr >> 32) as u32));
|
||||
assert!(q.is_valid());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_used() {
|
||||
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
let mut q = vq.create_queue(m);
|
||||
|
||||
assert_eq!(u16::from_le(vq.used().idx().load()), 0);
|
||||
|
||||
// index too large
|
||||
assert!(q.add_used(16, 0x1000).is_err());
|
||||
assert_eq!(u16::from_le(vq.used().idx().load()), 0);
|
||||
|
||||
// should be ok
|
||||
q.add_used(1, 0x1000).unwrap();
|
||||
assert_eq!(q.state.next_used, Wrapping(1));
|
||||
assert_eq!(u16::from_le(vq.used().idx().load()), 1);
|
||||
|
||||
let x = vq.used().ring().ref_at(0).load();
|
||||
assert_eq!(x.id(), 1);
|
||||
assert_eq!(x.len(), 0x1000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reset_queue() {
|
||||
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
let mut q = vq.create_queue(m);
|
||||
|
||||
q.set_size(8);
|
||||
// The address set by `MockSplitQueue` for the descriptor table is DEFAULT_DESC_TABLE_ADDR,
|
||||
// so let's change it for testing the reset.
|
||||
q.set_desc_table_address(Some(0x5000), None);
|
||||
// Same for `event_idx_enabled`, `next_avail` `next_used` and `signalled_used`.
|
||||
q.set_event_idx(true);
|
||||
q.set_next_avail(2);
|
||||
q.add_used(1, 200).unwrap();
|
||||
q.state.signalled_used = Some(Wrapping(15));
|
||||
assert_eq!(q.state.size, 8);
|
||||
// `create_queue` also marks the queue as ready.
|
||||
assert!(q.state.ready);
|
||||
assert_ne!(q.state.desc_table, GuestAddress(DEFAULT_DESC_TABLE_ADDR));
|
||||
assert_ne!(q.state.avail_ring, GuestAddress(DEFAULT_AVAIL_RING_ADDR));
|
||||
assert_ne!(q.state.used_ring, GuestAddress(DEFAULT_USED_RING_ADDR));
|
||||
assert_ne!(q.state.next_avail, Wrapping(0));
|
||||
assert_ne!(q.state.next_used, Wrapping(0));
|
||||
assert_ne!(q.state.signalled_used, None);
|
||||
assert!(q.state.event_idx_enabled);
|
||||
|
||||
q.reset();
|
||||
assert_eq!(q.state.size, 16);
|
||||
assert!(!q.state.ready);
|
||||
assert_eq!(q.state.desc_table, GuestAddress(DEFAULT_DESC_TABLE_ADDR));
|
||||
assert_eq!(q.state.avail_ring, GuestAddress(DEFAULT_AVAIL_RING_ADDR));
|
||||
assert_eq!(q.state.used_ring, GuestAddress(DEFAULT_USED_RING_ADDR));
|
||||
assert_eq!(q.state.next_avail, Wrapping(0));
|
||||
assert_eq!(q.state.next_used, Wrapping(0));
|
||||
assert_eq!(q.state.signalled_used, None);
|
||||
assert!(!q.state.event_idx_enabled);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_needs_notification() {
|
||||
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let qsize = 16;
|
||||
let vq = MockSplitQueue::new(m, qsize);
|
||||
let mut q = vq.create_queue(m);
|
||||
let avail_addr = vq.avail_addr();
|
||||
|
||||
// It should always return true when EVENT_IDX isn't enabled.
|
||||
for i in 0..qsize {
|
||||
q.state.next_used = Wrapping(i);
|
||||
assert!(q.needs_notification().unwrap());
|
||||
}
|
||||
|
||||
m.write_obj::<u16>(
|
||||
u16::to_le(4),
|
||||
avail_addr.unchecked_add(4 + qsize as u64 * 2),
|
||||
)
|
||||
.unwrap();
|
||||
q.state.set_event_idx(true);
|
||||
|
||||
// Incrementing up to this value causes an `u16` to wrap back to 0.
|
||||
let wrap = u32::from(u16::MAX) + 1;
|
||||
|
||||
for i in 0..wrap + 12 {
|
||||
q.state.next_used = Wrapping(i as u16);
|
||||
// Let's test wrapping around the maximum index value as well.
|
||||
let expected = i == 5 || i == (5 + wrap) || q.state.signalled_used.is_none();
|
||||
assert_eq!(q.needs_notification().unwrap(), expected);
|
||||
}
|
||||
|
||||
m.write_obj::<u16>(8, avail_addr.unchecked_add(4 + qsize as u64 * 2))
|
||||
.unwrap();
|
||||
|
||||
// Returns `false` because `signalled_used` already passed this value.
|
||||
assert!(!q.needs_notification().unwrap());
|
||||
|
||||
m.write_obj::<u16>(15, avail_addr.unchecked_add(4 + qsize as u64 * 2))
|
||||
.unwrap();
|
||||
|
||||
assert!(!q.needs_notification().unwrap());
|
||||
q.state.next_used = Wrapping(15);
|
||||
assert!(!q.needs_notification().unwrap());
|
||||
q.state.next_used = Wrapping(0);
|
||||
assert!(q.needs_notification().unwrap());
|
||||
assert!(!q.needs_notification().unwrap());
|
||||
|
||||
m.write_obj::<u16>(u16::MAX - 3, avail_addr.unchecked_add(4 + qsize as u64 * 2))
|
||||
.unwrap();
|
||||
q.state.next_used = Wrapping(u16::MAX - 2);
|
||||
// Returns `true` because the value we wrote in the `used_event` < the next used value and
|
||||
// the last `signalled_used` is 0.
|
||||
assert!(q.needs_notification().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enable_disable_notification() {
|
||||
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
|
||||
let mut q = vq.create_queue(m);
|
||||
let used_addr = vq.used_addr();
|
||||
|
||||
assert!(!q.state.event_idx_enabled);
|
||||
|
||||
q.enable_notification().unwrap();
|
||||
let v = m.read_obj::<u16>(used_addr).map(u16::from_le).unwrap();
|
||||
assert_eq!(v, 0);
|
||||
|
||||
q.disable_notification().unwrap();
|
||||
let v = m.read_obj::<u16>(used_addr).map(u16::from_le).unwrap();
|
||||
assert_eq!(v, VIRTQ_USED_F_NO_NOTIFY);
|
||||
|
||||
q.enable_notification().unwrap();
|
||||
let v = m.read_obj::<u16>(used_addr).map(u16::from_le).unwrap();
|
||||
assert_eq!(v, 0);
|
||||
|
||||
q.set_event_idx(true);
|
||||
let avail_addr = vq.avail_addr();
|
||||
m.write_obj::<u16>(u16::to_le(2), avail_addr.unchecked_add(2))
|
||||
.unwrap();
|
||||
|
||||
assert!(q.enable_notification().unwrap());
|
||||
q.state.next_avail = Wrapping(2);
|
||||
assert!(!q.enable_notification().unwrap());
|
||||
|
||||
m.write_obj::<u16>(u16::to_le(8), avail_addr.unchecked_add(2))
|
||||
.unwrap();
|
||||
|
||||
assert!(q.enable_notification().unwrap());
|
||||
q.state.next_avail = Wrapping(8);
|
||||
assert!(!q.enable_notification().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_consume_chains_with_notif() {
|
||||
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
|
||||
let mut q = vq.create_queue(m);
|
||||
|
||||
// q is currently valid.
|
||||
assert!(q.is_valid());
|
||||
|
||||
// The chains are (0, 1), (2, 3, 4), (5, 6), (7, 8), (9, 10, 11, 12).
|
||||
for i in 0..13 {
|
||||
let flags = match i {
|
||||
1 | 4 | 6 | 8 | 12 => 0,
|
||||
_ => VIRTQ_DESC_F_NEXT,
|
||||
};
|
||||
|
||||
let desc = Descriptor::new((0x1000 * (i + 1)) as u64, 0x1000, flags, i + 1);
|
||||
vq.desc_table().store(i, desc);
|
||||
}
|
||||
|
||||
vq.avail().ring().ref_at(0).store(u16::to_le(0));
|
||||
vq.avail().ring().ref_at(1).store(u16::to_le(2));
|
||||
vq.avail().ring().ref_at(2).store(u16::to_le(5));
|
||||
vq.avail().ring().ref_at(3).store(u16::to_le(7));
|
||||
vq.avail().ring().ref_at(4).store(u16::to_le(9));
|
||||
// Let the device know it can consume chains with the index < 2.
|
||||
vq.avail().idx().store(u16::to_le(2));
|
||||
// No descriptor chains are consumed at this point.
|
||||
assert_eq!(q.next_avail(), 0);
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
loop {
|
||||
i += 1;
|
||||
q.disable_notification().unwrap();
|
||||
|
||||
while let Some(_chain) = q.iter().unwrap().next() {
|
||||
// Here the device would consume entries from the available ring, add an entry in
|
||||
// the used ring and optionally notify the driver. For the purpose of this test, we
|
||||
// don't need to do anything with the chain, only consume it.
|
||||
}
|
||||
if !q.enable_notification().unwrap() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// The chains should be consumed in a single loop iteration because there's nothing updating
|
||||
// the `idx` field of the available ring in the meantime.
|
||||
assert_eq!(i, 1);
|
||||
// The next chain that can be consumed should have index 2.
|
||||
assert_eq!(q.next_avail(), 2);
|
||||
// Let the device know it can consume one more chain.
|
||||
vq.avail().idx().store(u16::to_le(3));
|
||||
i = 0;
|
||||
|
||||
loop {
|
||||
i += 1;
|
||||
q.disable_notification().unwrap();
|
||||
|
||||
while let Some(_chain) = q.iter().unwrap().next() {
|
||||
// In a real use case, we would do something with the chain here.
|
||||
}
|
||||
|
||||
// For the simplicity of the test we are updating here the `idx` value of the available
|
||||
// ring. Ideally this should be done on a separate thread.
|
||||
// Because of this update, the loop should be iterated again to consume the new
|
||||
// available descriptor chains.
|
||||
vq.avail().idx().store(u16::to_le(4));
|
||||
if !q.enable_notification().unwrap() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert_eq!(i, 2);
|
||||
// The next chain that can be consumed should have index 4.
|
||||
assert_eq!(q.next_avail(), 4);
|
||||
|
||||
// Set an `idx` that is bigger than the number of entries added in the ring.
|
||||
// This is an allowed scenario, but the indexes of the chain will have unexpected values.
|
||||
vq.avail().idx().store(u16::to_le(7));
|
||||
loop {
|
||||
q.disable_notification().unwrap();
|
||||
|
||||
while let Some(_chain) = q.iter().unwrap().next() {
|
||||
// In a real use case, we would do something with the chain here.
|
||||
}
|
||||
if !q.enable_notification().unwrap() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert_eq!(q.next_avail(), 7);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_avail_idx() {
|
||||
// This is a negative test for the following MUST from the spec: `A driver MUST NOT
|
||||
// decrement the available idx on a virtqueue (ie. there is no way to “unexpose” buffers).`.
|
||||
// We validate that for this misconfiguration, the device does not panic.
|
||||
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vq = MockSplitQueue::new(m, 16);
|
||||
|
||||
let mut q = vq.create_queue(m);
|
||||
|
||||
// q is currently valid.
|
||||
assert!(q.is_valid());
|
||||
|
||||
// The chains are (0, 1), (2, 3, 4), (5, 6).
|
||||
for i in 0..7 {
|
||||
let flags = match i {
|
||||
1 | 4 | 6 => 0,
|
||||
_ => VIRTQ_DESC_F_NEXT,
|
||||
};
|
||||
|
||||
let desc = Descriptor::new((0x1000 * (i + 1)) as u64, 0x1000, flags, i + 1);
|
||||
vq.desc_table().store(i, desc);
|
||||
}
|
||||
|
||||
vq.avail().ring().ref_at(0).store(u16::to_le(0));
|
||||
vq.avail().ring().ref_at(1).store(u16::to_le(2));
|
||||
vq.avail().ring().ref_at(2).store(u16::to_le(5));
|
||||
// Let the device know it can consume chains with the index < 2.
|
||||
vq.avail().idx().store(u16::to_le(3));
|
||||
// No descriptor chains are consumed at this point.
|
||||
assert_eq!(q.next_avail(), 0);
|
||||
|
||||
loop {
|
||||
q.disable_notification().unwrap();
|
||||
|
||||
while let Some(_chain) = q.iter().unwrap().next() {
|
||||
// Here the device would consume entries from the available ring, add an entry in
|
||||
// the used ring and optionally notify the driver. For the purpose of this test, we
|
||||
// don't need to do anything with the chain, only consume it.
|
||||
}
|
||||
if !q.enable_notification().unwrap() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// The next chain that can be consumed should have index 3.
|
||||
assert_eq!(q.next_avail(), 3);
|
||||
assert_eq!(q.avail_idx(Ordering::Acquire).unwrap(), Wrapping(3));
|
||||
assert!(q.lock().ready());
|
||||
|
||||
// Decrement `idx` which should be forbidden. We don't enforce this thing, but we should
|
||||
// test that we don't panic in case the driver decrements it.
|
||||
vq.avail().idx().store(u16::to_le(1));
|
||||
|
||||
loop {
|
||||
q.disable_notification().unwrap();
|
||||
|
||||
while let Some(_chain) = q.iter().unwrap().next() {
|
||||
// In a real use case, we would do something with the chain here.
|
||||
}
|
||||
|
||||
if !q.enable_notification().unwrap() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user