mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
369 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b132cd2145 | ||
|
|
a650b8645f | ||
|
|
f94a5fb4e3 | ||
|
|
00800b8499 | ||
|
|
0b311f6c4c | ||
|
|
8063c00e67 | ||
|
|
4f611c8654 | ||
|
|
d291b87288 | ||
|
|
51787d30da | ||
|
|
63579341e1 | ||
|
|
9c0872def7 | ||
|
|
5dfc49c9fa | ||
|
|
65f8c3682f | ||
|
|
c87466eea2 | ||
|
|
6c365617ee | ||
|
|
30da293d8f | ||
|
|
67bfd4e234 | ||
|
|
46bbe0e612 | ||
|
|
216f330f4e | ||
|
|
bd075872d4 | ||
|
|
7fd5f41623 | ||
|
|
93237f0106 | ||
|
|
0c82e7593d | ||
|
|
1999ab5707 | ||
|
|
5c22f02f32 | ||
|
|
c7afb44c5a | ||
|
|
b0afeeeb65 | ||
|
|
cb53a8b40c | ||
|
|
adf5881757 | ||
|
|
44eca31642 | ||
|
|
b57d7b258d | ||
|
|
d7decfd525 | ||
|
|
2716bc3311 | ||
|
|
9cf0dee264 | ||
|
|
d8b3d07825 | ||
|
|
3d66e86604 | ||
|
|
a2164873ac | ||
|
|
7f8cf4f8e7 | ||
|
|
aedbd7ae27 | ||
|
|
bb4461e951 | ||
|
|
54fe5fb9f5 | ||
|
|
5a9e7ee7fe | ||
|
|
2e664dca64 | ||
|
|
a26f86f8ad | ||
|
|
fde13889f4 | ||
|
|
65ec6631fb | ||
|
|
6ac8dc8745 | ||
|
|
2f514523dd | ||
|
|
92f559f6f2 | ||
|
|
3972e38371 | ||
|
|
a1a016526f | ||
|
|
a5692a95c1 | ||
|
|
0fd25b3246 | ||
|
|
e6127df703 | ||
|
|
559657eecc | ||
|
|
66f1ec0063 | ||
|
|
13d081ac47 | ||
|
|
b12f4ccade | ||
|
|
1f8bca4840 | ||
|
|
833eb2ebe6 | ||
|
|
7c7f0f1f5f | ||
|
|
d445ec7633 | ||
|
|
039e758f15 | ||
|
|
eb55d0809e | ||
|
|
ecde44617b | ||
|
|
58e567b309 | ||
|
|
fa0140a183 | ||
|
|
c6c5e4ee87 | ||
|
|
a64bdcf3f5 | ||
|
|
439823e7ea | ||
|
|
9019086625 | ||
|
|
bccd7c7e48 | ||
|
|
f1dc7f442a | ||
|
|
32b855df3a | ||
|
|
8fa1098629 | ||
|
|
41cec53bb8 | ||
|
|
fd9f14893b | ||
|
|
7c8719b4ea | ||
|
|
335a4e1cc0 | ||
|
|
6dbbd0363f | ||
|
|
40e1ad3f62 | ||
|
|
094625242d | ||
|
|
b3569f084d | ||
|
|
3800212def | ||
|
|
e9f5052fcd | ||
|
|
a583b055f5 | ||
|
|
2b33e66bb4 | ||
|
|
92ceef52c8 | ||
|
|
d7baa58e11 | ||
|
|
2d39b6ed06 | ||
|
|
ed31ca9041 | ||
|
|
06b880e99f | ||
|
|
742ca68070 | ||
|
|
f950cb1fdb | ||
|
|
c6c5dca651 | ||
|
|
d646e10079 | ||
|
|
efe0429a9a | ||
|
|
1f3321c50e | ||
|
|
c0d51eecf1 | ||
|
|
1b9dc80469 | ||
|
|
43d32a7288 | ||
|
|
27e04e41bf | ||
|
|
41ac48d332 | ||
|
|
2afaed9111 | ||
|
|
f1ea69474d | ||
|
|
cac42301f8 | ||
|
|
ada85f68f6 | ||
|
|
64b4b7205e | ||
|
|
4a4352f9d9 | ||
|
|
81ba70a497 | ||
|
|
7df7061610 | ||
|
|
c021dda267 | ||
|
|
f48b05eee6 | ||
|
|
3b59e57001 | ||
|
|
49069d8474 | ||
|
|
8eaefa6e8e | ||
|
|
a1b996ac37 | ||
|
|
4ddc6ffd73 | ||
|
|
94fb9f817d | ||
|
|
133a5a858a | ||
|
|
3a18860326 | ||
|
|
0d0013c46e | ||
|
|
86d243938e | ||
|
|
a7a15d56dd | ||
|
|
65dc1c83a9 | ||
|
|
3edaa8adb6 | ||
|
|
9260c3816e | ||
|
|
5d45d6d0fb | ||
|
|
957d3a7443 | ||
|
|
04949755c0 | ||
|
|
b8dbb26647 | ||
|
|
3fe7d61a02 | ||
|
|
c2862b6947 | ||
|
|
03b01c02cd | ||
|
|
435d769511 | ||
|
|
9ba6767a90 | ||
|
|
3742cc42ae | ||
|
|
e0dd2e41c2 | ||
|
|
f1495b5767 | ||
|
|
6bd4bdfa26 | ||
|
|
ade3a9c8f6 | ||
|
|
15e2763753 | ||
|
|
8b87b752b5 | ||
|
|
7864f91a2b | ||
|
|
6ab93a08ec | ||
|
|
fd41892065 | ||
|
|
dbeb922882 | ||
|
|
0bb2060ca7 | ||
|
|
8b585b96c1 | ||
|
|
ccb604e1e1 | ||
|
|
0e65ca4a6c | ||
|
|
7e280b6f70 | ||
|
|
90034fd6ba | ||
|
|
642309f141 | ||
|
|
5da8a1c08e | ||
|
|
465db7f08c | ||
|
|
55c5961f43 | ||
|
|
7c3582b4a8 | ||
|
|
979797786d | ||
|
|
62120f9afe | ||
|
|
56c11600db | ||
|
|
f2336413be | ||
|
|
0fd6521759 | ||
|
|
4a2d3cb4f5 | ||
|
|
3fe20cc09a | ||
|
|
fd581b1afb | ||
|
|
1e732bf532 | ||
|
|
ad8295e11d | ||
|
|
fe1f0ef49e | ||
|
|
f9fcc3722f | ||
|
|
c0cbaff519 | ||
|
|
ebaea6fe0f | ||
|
|
0150de55d2 | ||
|
|
75e3a3d982 | ||
|
|
3b10699743 | ||
|
|
d0798aad59 | ||
|
|
e52175c2ab | ||
|
|
ffd1411e7c | ||
|
|
a14ebbb758 | ||
|
|
02358d3091 | ||
|
|
025447e8cc | ||
|
|
d582121143 | ||
|
|
38b8e387ea | ||
|
|
3538afc1fe | ||
|
|
d96614fe42 | ||
|
|
7076684124 | ||
|
|
fa07d83565 | ||
|
|
80f6dda932 | ||
|
|
f160572f9d | ||
|
|
9626288d4f | ||
|
|
e2f9c4e756 | ||
|
|
e674577ea9 | ||
|
|
49db713124 | ||
|
|
f0aa70c78b | ||
|
|
db3bd6bb16 | ||
|
|
5e7a77e5f9 | ||
|
|
ea753b4f32 | ||
|
|
5587245bf2 | ||
|
|
bc5f70d1ed | ||
|
|
0e16ffbcff | ||
|
|
3a0429c998 | ||
|
|
7f29cef5d2 | ||
|
|
4a32f17aad | ||
|
|
0c452ac895 | ||
|
|
32353fa389 | ||
|
|
33e2a7121e | ||
|
|
2eb984b45d | ||
|
|
3bcd3e7f4c | ||
|
|
58966e952d | ||
|
|
f809f44c02 | ||
|
|
c0cc5cb01d | ||
|
|
da4fdeb017 | ||
|
|
f5f63130bf | ||
|
|
cb8075e53b | ||
|
|
30c5aeff23 | ||
|
|
86d09f6caa | ||
|
|
7db7410920 | ||
|
|
64c76693c4 | ||
|
|
c622b43f85 | ||
|
|
1651253777 | ||
|
|
3824f17516 | ||
|
|
8ab3aaee6a | ||
|
|
12f11b5619 | ||
|
|
16a9882153 | ||
|
|
2caf5e3b2b | ||
|
|
218be2642e | ||
|
|
cd0df05808 | ||
|
|
4ff0686d37 | ||
|
|
288cea917e | ||
|
|
d3f66f8702 | ||
|
|
8e1ba99e8d | ||
|
|
3ffc105f83 | ||
|
|
b1bd87df19 | ||
|
|
3f9e8d676a | ||
|
|
fe82322727 | ||
|
|
e89e5c9beb | ||
|
|
e85ac2695f | ||
|
|
c2c813599d | ||
|
|
3c0817a1b7 | ||
|
|
387d56879b | ||
|
|
f24f35b65d | ||
|
|
28926c7454 | ||
|
|
24543e7076 | ||
|
|
21474e280d | ||
|
|
5f722d0d3f | ||
|
|
06f57abdf9 | ||
|
|
42c19e14c5 | ||
|
|
058a61148c | ||
|
|
425902b296 | ||
|
|
54f39aa8cb | ||
|
|
1108bd1967 | ||
|
|
707cea2182 | ||
|
|
c47e3b8689 | ||
|
|
5bd7a1f03c | ||
|
|
c614dcb9f7 | ||
|
|
7fe399598d | ||
|
|
25a38b25c4 | ||
|
|
b9fb849b83 | ||
|
|
0c00da1dd8 | ||
|
|
28fb2d3235 | ||
|
|
bf39146caa | ||
|
|
1dfe4eda5c | ||
|
|
5530795898 | ||
|
|
db06ef78ba | ||
|
|
95c6ee3e6a | ||
|
|
d4168056be | ||
|
|
592a65f52e | ||
|
|
6e101f479c | ||
|
|
6d4862245d | ||
|
|
78abbfa604 | ||
|
|
664c9e3eb3 | ||
|
|
1f71c28656 | ||
|
|
30e06eaaba | ||
|
|
0ed196820e | ||
|
|
bde2370b18 | ||
|
|
960a9e0ff7 | ||
|
|
3277c27e0d | ||
|
|
dea10b5500 | ||
|
|
691d9b16db | ||
|
|
400a351bb0 | ||
|
|
fa9fb26952 | ||
|
|
938b0bfcec | ||
|
|
a5a2e591c9 | ||
|
|
677c8831af | ||
|
|
634c53ea50 | ||
|
|
657660e5c2 | ||
|
|
b60e6f7cb1 | ||
|
|
4a7c858fdc | ||
|
|
85a72efed7 | ||
|
|
8afdcb98d4 | ||
|
|
6c36c60330 | ||
|
|
6239b8ad7a | ||
|
|
4fed2d4ed7 | ||
|
|
ec0c1b01c4 | ||
|
|
f77ea5a2ce | ||
|
|
f17aa3755f | ||
|
|
744a049007 | ||
|
|
e70bd069b3 | ||
|
|
bfeb3120f5 | ||
|
|
ce6d88d187 | ||
|
|
56fe4c61af | ||
|
|
1d1a087fc5 | ||
|
|
f1276c58d2 | ||
|
|
da33eb5e8c | ||
|
|
fdeb4f7c46 | ||
|
|
7388f71228 | ||
|
|
eebf4f10e3 | ||
|
|
3d1b2eb4e5 | ||
|
|
16740b4fcd | ||
|
|
e97fe7a43e | ||
|
|
87eed369cd | ||
|
|
79f4c2db01 | ||
|
|
6df8f0bbf3 | ||
|
|
bbd0667b98 | ||
|
|
b40633f92c | ||
|
|
2f47bea809 | ||
|
|
f38360deb6 | ||
|
|
fc8facddee | ||
|
|
bf9f79081a | ||
|
|
ec1679406e | ||
|
|
17107c59ac | ||
|
|
62f17ccf8c | ||
|
|
cb03540ffd | ||
|
|
0270d697ab | ||
|
|
47529796d0 | ||
|
|
1c786610b7 | ||
|
|
4a99d3dbaf | ||
|
|
e6aa792c01 | ||
|
|
eb6daa2fc3 | ||
|
|
f767e97fa5 | ||
|
|
f076819d81 | ||
|
|
3c8e280bf1 | ||
|
|
c1ecfd23be | ||
|
|
80de77a6e6 | ||
|
|
adb3dcdc13 | ||
|
|
e972eb7c74 | ||
|
|
203dfdc156 | ||
|
|
6ccf037972 | ||
|
|
4a04d1f8f2 | ||
|
|
c274ce4d49 | ||
|
|
047432a81b | ||
|
|
8358d100cc | ||
|
|
82aa0e1222 | ||
|
|
edca82c4bd | ||
|
|
7e9c61ab18 | ||
|
|
f81220ae2d | ||
|
|
4ca066f077 | ||
|
|
88ed85247e | ||
|
|
de1af55e22 | ||
|
|
bf059914a6 | ||
|
|
3952cc6629 | ||
|
|
e15cac55aa | ||
|
|
824c0c962d | ||
|
|
37521ddff7 | ||
|
|
11e9f43305 | ||
|
|
89218b6d1e | ||
|
|
da95c0d784 | ||
|
|
1795afadb8 | ||
|
|
a87d1bbaa1 | ||
|
|
babece08c6 | ||
|
|
5a9779f88c | ||
|
|
45d3db48cf | ||
|
|
f03258bb2a | ||
|
|
5264d545dd | ||
|
|
6175cc0977 | ||
|
|
0c34846ef6 | ||
|
|
4f172ae4b6 | ||
|
|
0f12fe9b3b | ||
|
|
6e084572d4 |
19
.github/workflows/build.yaml
vendored
19
.github/workflows/build.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
- stable
|
- stable
|
||||||
- beta
|
- beta
|
||||||
- nightly
|
- nightly
|
||||||
- 1.56
|
- "1.60"
|
||||||
target:
|
target:
|
||||||
- x86_64-unknown-linux-gnu
|
- x86_64-unknown-linux-gnu
|
||||||
- x86_64-unknown-linux-musl
|
- x86_64-unknown-linux-musl
|
||||||
@@ -39,25 +39,28 @@ jobs:
|
|||||||
git checkout $GITHUB_SHA
|
git checkout $GITHUB_SHA
|
||||||
|
|
||||||
- name: Build (default features)
|
- name: Build (default features)
|
||||||
run: cargo rustc --bin cloud-hypervisor -- -D warnings
|
run: cargo rustc --locked --bin cloud-hypervisor -- -D warnings
|
||||||
|
|
||||||
- name: Build (common + kvm)
|
- name: Build (common + kvm)
|
||||||
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "common,kvm" -- -D warnings
|
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "common,kvm" -- -D warnings
|
||||||
|
|
||||||
- name: Build (default features + tdx)
|
- name: Build (default features + tdx)
|
||||||
run: cargo rustc --bin cloud-hypervisor --features "tdx" -- -D warnings
|
run: cargo rustc --locked --bin cloud-hypervisor --features "tdx" -- -D warnings
|
||||||
|
|
||||||
- name: Build (default features + amx)
|
- name: Build (default features + amx)
|
||||||
run: cargo rustc --bin cloud-hypervisor --features "amx" -- -D warnings
|
run: cargo rustc --locked --bin cloud-hypervisor --features "amx" -- -D warnings
|
||||||
|
|
||||||
- name: Build (default features + gdb)
|
- name: Build (default features + gdb)
|
||||||
run: cargo rustc --bin cloud-hypervisor --features "gdb" -- -D warnings
|
run: cargo rustc --locked --bin cloud-hypervisor --features "gdb" -- -D warnings
|
||||||
|
|
||||||
|
- name: Build (default features + guest_debug)
|
||||||
|
run: cargo rustc --locked --bin cloud-hypervisor --features "guest_debug" -- -D warnings
|
||||||
|
|
||||||
- name: Build (common + mshv)
|
- name: Build (common + mshv)
|
||||||
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "common,mshv" -- -D warnings
|
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "common,mshv" -- -D warnings
|
||||||
|
|
||||||
- name: Release Build (default features)
|
- name: Release Build (default features)
|
||||||
run: cargo build --all --release --target=${{ matrix.target }}
|
run: cargo build --locked --all --release --target=${{ matrix.target }}
|
||||||
|
|
||||||
- name: Check build did not modify any files
|
- name: Check build did not modify any files
|
||||||
run: test -z "$(git status --porcelain)"
|
run: test -z "$(git status --porcelain)"
|
||||||
|
|||||||
13
.github/workflows/quality.yaml
vendored
13
.github/workflows/quality.yaml
vendored
@@ -34,19 +34,22 @@ jobs:
|
|||||||
run: cargo fmt -- --check
|
run: cargo fmt -- --check
|
||||||
|
|
||||||
- name: Clippy (common + kvm)
|
- name: Clippy (common + kvm)
|
||||||
run: cargo clippy --all --all-targets --no-default-features --tests --features "common,kvm" -- -D warnings
|
run: cargo clippy --locked --all --all-targets --no-default-features --tests --features "common,kvm" -- -D warnings
|
||||||
|
|
||||||
- name: Clippy (default features)
|
- name: Clippy (default features)
|
||||||
run: cargo clippy --all --all-targets --tests -- -D warnings
|
run: cargo clippy --locked --all --all-targets --tests -- -D warnings
|
||||||
|
|
||||||
- name: Clippy (default features + amx)
|
- name: Clippy (default features + amx)
|
||||||
run: cargo clippy --all --all-targets --tests --features "amx" -- -D warnings
|
run: cargo clippy --locked --all --all-targets --tests --features "amx" -- -D warnings
|
||||||
|
|
||||||
- name: Clippy (default features + gdb)
|
- name: Clippy (default features + gdb)
|
||||||
run: cargo clippy --all --all-targets --tests --features "gdb" -- -D warnings
|
run: cargo clippy --locked --all --all-targets --tests --features "gdb" -- -D warnings
|
||||||
|
|
||||||
|
- name: Clippy (default features + guest_debug)
|
||||||
|
run: cargo clippy --locked --all --all-targets --tests --features "guest_debug" -- -D warnings
|
||||||
|
|
||||||
- name: Clippy (common + mshv)
|
- name: Clippy (common + mshv)
|
||||||
run: cargo clippy --all --all-targets --no-default-features --tests --features "common,mshv" -- -D warnings
|
run: cargo clippy --locked --all --all-targets --no-default-features --tests --features "common,mshv" -- -D warnings
|
||||||
|
|
||||||
- name: Check build did not modify any files
|
- name: Check build did not modify any files
|
||||||
run: test -z "$(git status --porcelain)"
|
run: test -z "$(git status --porcelain)"
|
||||||
|
|||||||
10
.github/workflows/release.yaml
vendored
10
.github/workflows/release.yaml
vendored
@@ -16,23 +16,23 @@ jobs:
|
|||||||
- name: Install Rust toolchain (x86_64-unknown-linux-gnu)
|
- name: Install Rust toolchain (x86_64-unknown-linux-gnu)
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: 1.58
|
toolchain: "1.62"
|
||||||
target: x86_64-unknown-linux-gnu
|
target: x86_64-unknown-linux-gnu
|
||||||
- name: Install Rust toolchain (x86_64-unknown-linux-musl)
|
- name: Install Rust toolchain (x86_64-unknown-linux-musl)
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: 1.58
|
toolchain: "1.62"
|
||||||
target: x86_64-unknown-linux-musl
|
target: x86_64-unknown-linux-musl
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
toolchain: 1.58
|
toolchain: "1.62"
|
||||||
command: build
|
command: build
|
||||||
args: --all --release --target=x86_64-unknown-linux-gnu
|
args: --all --release --target=x86_64-unknown-linux-gnu
|
||||||
- name: Static Build
|
- name: Static Build
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
toolchain: 1.58
|
toolchain: "1.62"
|
||||||
command: build
|
command: build
|
||||||
args: --all --release --target=x86_64-unknown-linux-musl
|
args: --all --release --target=x86_64-unknown-linux-musl
|
||||||
- name: Strip cloud-hypervisor binaries
|
- name: Strip cloud-hypervisor binaries
|
||||||
@@ -40,7 +40,7 @@ jobs:
|
|||||||
- name: Install Rust toolchain (aarch64-unknown-linux-musl)
|
- name: Install Rust toolchain (aarch64-unknown-linux-musl)
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: 1.58
|
toolchain: "1.62"
|
||||||
target: aarch64-unknown-linux-musl
|
target: aarch64-unknown-linux-musl
|
||||||
override: true
|
override: true
|
||||||
- name: Static Build (AArch64)
|
- name: Static Build (AArch64)
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,3 +4,4 @@
|
|||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
**/Cargo.lock
|
**/Cargo.lock
|
||||||
**/rusty-tags.vi
|
**/rusty-tags.vi
|
||||||
|
/rpm/SOURCES
|
||||||
|
|||||||
2
CODEOWNERS
Normal file
2
CODEOWNERS
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Add the list of code owners here (using their GitHub username)
|
||||||
|
* @cloud-hypervisor/cloud-hypervisor-reviewers
|
||||||
@@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
Cloud Hypervisor is an open source project licensed under the [Apache v2
|
Cloud Hypervisor is an open source project licensed under the [Apache v2
|
||||||
License](https://opensource.org/licenses/Apache-2.0) and the [BSD 3
|
License](https://opensource.org/licenses/Apache-2.0) and the [BSD 3
|
||||||
Clause](https://opensource.org/licenses/BSD-3-Clause) license. Contributions
|
Clause](https://opensource.org/licenses/BSD-3-Clause) license. Individual files
|
||||||
can be made under either license or both. Individual files contain details of
|
contain details of their licensing and changes to that file are under the same
|
||||||
their licensing and changes to that file are under the same license unless the
|
license unless the contribution changes the license of the file. When importing
|
||||||
contribution changes the license of the file. When importing code from a third
|
code from a third party project (e.g. Firecracker or CrosVM) please respect the
|
||||||
party project (e.g. Firecracker or CrosVM) please respect the license of those
|
license of those projects.
|
||||||
projects.
|
|
||||||
|
New code should be under the [Apache v2
|
||||||
|
License](https://opensource.org/licenses/Apache-2.0).
|
||||||
|
|
||||||
## Coding Style
|
## Coding Style
|
||||||
|
|
||||||
@@ -63,11 +65,9 @@ you want to merge your changes to `cloud-hypervisor`:
|
|||||||
2. Within your fork, create a branch for your contribution.
|
2. Within your fork, create a branch for your contribution.
|
||||||
3. [Create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)
|
3. [Create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)
|
||||||
against the main branch of the Cloud Hypervisor repository.
|
against the main branch of the Cloud Hypervisor repository.
|
||||||
4. Add reviewers to your pull request and then work with your reviewers to address
|
4. To update your pull request amend existing commits whenever applicable and
|
||||||
any comments and obtain minimum of 2 [maintainers](MAINTAINERS.md) approvals.
|
|
||||||
To update your pull request amend existing commits whenever applicable and
|
|
||||||
then push the new changes to your pull request branch.
|
then push the new changes to your pull request branch.
|
||||||
5. Once the pull request is approved, one of the maintainers will merge it.
|
5. Once the pull request is approved it can be integrated.
|
||||||
|
|
||||||
## Issue tracking
|
## Issue tracking
|
||||||
|
|
||||||
|
|||||||
268
Cargo.lock
generated
268
Cargo.lock
generated
@@ -20,9 +20,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.56"
|
version = "1.0.58"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
|
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "api_client"
|
name = "api_client"
|
||||||
@@ -50,7 +50,6 @@ dependencies = [
|
|||||||
"linux-loader",
|
"linux-loader",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"versionize",
|
"versionize",
|
||||||
"versionize_derive",
|
"versionize_derive",
|
||||||
@@ -131,24 +130,33 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "3.1.8"
|
version = "3.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
|
checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty",
|
"atty",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"clap_lex",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"lazy_static",
|
"once_cell",
|
||||||
"os_str_bytes",
|
|
||||||
"strsim",
|
"strsim",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"terminal_size",
|
"terminal_size",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||||
|
dependencies = [
|
||||||
|
"os_str_bytes",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cloud-hypervisor"
|
name = "cloud-hypervisor"
|
||||||
version = "23.0.0"
|
version = "25.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"api_client",
|
"api_client",
|
||||||
@@ -157,10 +165,10 @@ dependencies = [
|
|||||||
"epoll",
|
"epoll",
|
||||||
"event_monitor",
|
"event_monitor",
|
||||||
"hypervisor",
|
"hypervisor",
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"net_util",
|
"net_util",
|
||||||
|
"once_cell",
|
||||||
"option_parser",
|
"option_parser",
|
||||||
"seccompiler",
|
"seccompiler",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -198,6 +206,7 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"epoll",
|
"epoll",
|
||||||
|
"hypervisor",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"versionize",
|
"versionize",
|
||||||
@@ -257,7 +266,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -269,9 +277,9 @@ checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gdbstub"
|
name = "gdbstub"
|
||||||
version = "0.6.1"
|
version = "0.6.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9fa2ca5d6b045de372cef3991f873389b421b4cabcfbe52f7787fae8b8b37906"
|
checksum = "1c1f9371c87c11642ee94dcf92cb48b1484ba250b8e8bff3df71c28651f3f4e7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@@ -283,9 +291,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gdbstub_arch"
|
name = "gdbstub_arch"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "51dc4b5718ac76d21e8605c0966dd32d80273b89b11e6cfef467b04e45934d37"
|
checksum = "c24f469ba9556c5a063d6df35a8a338025fccf96ecae44f330a156b686f7a268"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gdbstub",
|
"gdbstub",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -293,9 +301,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.6"
|
version = "0.2.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
|
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -310,9 +318,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.11.2"
|
version = "0.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
@@ -344,7 +352,6 @@ dependencies = [
|
|||||||
"mshv-bindings",
|
"mshv-bindings",
|
||||||
"mshv-ioctls",
|
"mshv-ioctls",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
@@ -363,9 +370,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.8.1"
|
version = "1.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
|
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@@ -392,18 +399,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnetwork"
|
name = "ipnetwork"
|
||||||
version = "0.18.0"
|
version = "0.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4088d739b183546b239688ddbc79891831df421773df95e236daf7867866d355"
|
checksum = "1f84f1612606f3753f205a4e9a2efd6fe5b4c573a6269b2cc6c3003d44a0d127"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.1"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kvm-bindings"
|
name = "kvm-bindings"
|
||||||
@@ -418,7 +425,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "kvm-ioctls"
|
name = "kvm-ioctls"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "git+https://github.com/rust-vmm/kvm-ioctls?branch=main#1e03e29cdfbb0cb108a98de7a78045a5a517f18e"
|
source = "git+https://github.com/rust-vmm/kvm-ioctls?branch=main#ccf0bda07485b2433616de998c000aa5f04ce806"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kvm-bindings",
|
"kvm-bindings",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -433,9 +440,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.123"
|
version = "0.2.126"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd"
|
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libssh2-sys"
|
name = "libssh2-sys"
|
||||||
@@ -453,9 +460,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libz-sys"
|
name = "libz-sys"
|
||||||
version = "1.1.5"
|
version = "1.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f35facd4a5673cb5a48822be2be1d4236c1c99cb4113cab7061ac720d5bf859"
|
checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -484,9 +491,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.16"
|
version = "0.4.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
|
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
@@ -499,14 +506,14 @@ checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.4.1"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "micro_http"
|
name = "micro_http"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#a730d86940081ad044cdfbc1285c1db6d3048392"
|
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#863b0370ba7e57f7df5b908ada9e5b44809ccae9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
@@ -515,7 +522,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "mshv-bindings"
|
name = "mshv-bindings"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#75cf309d566c3d9ba91e81582a7864032ecc5bbb"
|
source = "git+https://github.com/rust-vmm/mshv?branch=main#7ac1b80bff7220171c9a626b23b51620ca774468"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -527,7 +534,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "mshv-ioctls"
|
name = "mshv-ioctls"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#75cf309d566c3d9ba91e81582a7864032ecc5bbb"
|
source = "git+https://github.com/rust-vmm/mshv?branch=main#7ac1b80bff7220171c9a626b23b51620ca774468"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"mshv-bindings",
|
"mshv-bindings",
|
||||||
@@ -547,11 +554,12 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"epoll",
|
"epoll",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"net_gen",
|
"net_gen",
|
||||||
|
"once_cell",
|
||||||
"pnet",
|
"pnet",
|
||||||
|
"pnet_datalink",
|
||||||
"rate_limiter",
|
"rate_limiter",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -565,28 +573,40 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "no-std-net"
|
||||||
version = "0.2.14"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-src"
|
name = "once_cell"
|
||||||
version = "111.18.0+1.1.1n"
|
version = "1.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7897a926e1e8d00219127dc020130eca4292e5ca666dd592480d72c3eca2ff6c"
|
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-src"
|
||||||
|
version = "111.22.0+1.1.1q"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f31f0d509d1c1ae9cada2f9539ff8f37933831fd5098879e482aa687d659853"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.72"
|
version = "0.9.74"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
|
checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"cc",
|
"cc",
|
||||||
@@ -602,12 +622,9 @@ version = "0.1.0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_str_bytes"
|
name = "os_str_bytes"
|
||||||
version = "6.0.0"
|
version = "6.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
@@ -650,7 +667,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"versionize",
|
"versionize",
|
||||||
"versionize_derive",
|
"versionize_derive",
|
||||||
@@ -671,7 +687,6 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"dirs",
|
"dirs",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"test_infra",
|
"test_infra",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -686,29 +701,30 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet"
|
name = "pnet"
|
||||||
version = "0.29.0"
|
version = "0.31.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8750e073f82219c01e771133c64718d7685aef922da8a0d430a46aed05b6341a"
|
checksum = "0caaf5b11fd907ff15cf14a4477bfabca4b37ab9e447a4f8dead969a59cdafad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ipnetwork",
|
|
||||||
"pnet_base",
|
"pnet_base",
|
||||||
"pnet_datalink",
|
"pnet_datalink",
|
||||||
"pnet_packet",
|
"pnet_packet",
|
||||||
"pnet_sys",
|
|
||||||
"pnet_transport",
|
"pnet_transport",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_base"
|
name = "pnet_base"
|
||||||
version = "0.29.0"
|
version = "0.31.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8205fe084bd43a3af79b3155c19feddd62e733640498842e631a2ffe107d1538"
|
checksum = "f9d3a993d49e5fd5d4d854d6999d4addca1f72d86c65adf224a36757161c02b6"
|
||||||
|
dependencies = [
|
||||||
|
"no-std-net",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_datalink"
|
name = "pnet_datalink"
|
||||||
version = "0.29.0"
|
version = "0.31.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f85aef5e52e22ff06b1b11f2eb6d52959a9e0ecad3cb3f5cc2d78cadc077f0e"
|
checksum = "e466faf03a98ad27f6e15cd27a2b7cc89e73e640a43527742977bc503c37f8aa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ipnetwork",
|
"ipnetwork",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -719,9 +735,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_macros"
|
name = "pnet_macros"
|
||||||
version = "0.29.0"
|
version = "0.31.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "98cc3af95fed6dc318dfede3e81320f96ad5e237c6f7c4688108b19c8e67432d"
|
checksum = "48dd52a5211fac27e7acb14cfc9f30ae16ae0e956b7b779c8214c74559cef4c3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -731,18 +747,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_macros_support"
|
name = "pnet_macros_support"
|
||||||
version = "0.29.0"
|
version = "0.31.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "feaba58ba96abb218ec584d6caf0d3ff48922df05dbbeb1560553c197091b29e"
|
checksum = "89de095dc7739349559913aed1ef6a11e73ceade4897dadc77c5e09de6740750"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pnet_base",
|
"pnet_base",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_packet"
|
name = "pnet_packet"
|
||||||
version = "0.29.0"
|
version = "0.31.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f246edaaf1aaf82072d4cd38ee18bcc5dfc0464093f9ca39e4ac5962d68cf9d4"
|
checksum = "bc3b5111e697c39c8b9795b9fdccbc301ab696699e88b9ea5a4e4628978f495f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glob",
|
"glob",
|
||||||
"pnet_base",
|
"pnet_base",
|
||||||
@@ -752,9 +768,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_sys"
|
name = "pnet_sys"
|
||||||
version = "0.29.0"
|
version = "0.31.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "028c87a5e3a48fc07df099a2025f2ef16add5993712e1494ba69a6707ee7ed06"
|
checksum = "328e231f0add6d247d82421bf3790b4b33b39c8930637f428eef24c4c6a90805"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"winapi",
|
"winapi",
|
||||||
@@ -762,9 +778,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_transport"
|
name = "pnet_transport"
|
||||||
version = "0.29.0"
|
version = "0.31.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "950f2a7961e19d22e19e84ff0a6e0955013185fe149673499662633d02b41b7a"
|
checksum = "ff597185e6f1f5671b3122e4dba892a1c73e17c17e723d7669bd9299cbe7f124"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"pnet_base",
|
"pnet_base",
|
||||||
@@ -774,11 +790,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.37"
|
version = "1.0.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
|
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -794,9 +810,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.18"
|
version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@@ -832,9 +848,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.5.5"
|
version = "1.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
|
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -843,15 +859,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.25"
|
version = "0.6.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "remain"
|
name = "remain"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "70ba1e78fa68412cb93ef642fd4d20b9a941be49ee9333875ebaf13112673ea7"
|
checksum = "0c35270ea384ac1762895831cc8acb96f171468e52cec82ed9186f9416209fa4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -869,9 +885,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.9"
|
version = "1.0.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
@@ -890,21 +906,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.7"
|
version = "1.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
|
checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.136"
|
version = "1.0.138"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.136"
|
version = "1.0.138"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
|
checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -913,9 +932,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.79"
|
version = "1.0.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
|
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@@ -924,9 +943,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook"
|
name = "signal-hook"
|
||||||
version = "0.3.13"
|
version = "0.3.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
|
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
@@ -943,9 +962,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.8.0"
|
version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ssh2"
|
name = "ssh2"
|
||||||
@@ -973,13 +992,13 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.91"
|
version = "1.0.98"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
|
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"unicode-xid",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1019,8 +1038,8 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs",
|
"dirs",
|
||||||
"epoll",
|
"epoll",
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
"libc",
|
||||||
|
"once_cell",
|
||||||
"ssh2",
|
"ssh2",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
"wait-timeout",
|
"wait-timeout",
|
||||||
@@ -1037,18 +1056,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.30"
|
version = "1.0.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.30"
|
version = "1.0.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1056,16 +1075,22 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-ident"
|
||||||
version = "0.2.2"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "0.8.2"
|
version = "1.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
@@ -1115,7 +1140,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "vfio-ioctls"
|
name = "vfio-ioctls"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#f75a77c1ab6349c105bc1462a65508726b4c2e0f"
|
source = "git+https://github.com/rust-vmm/vfio?branch=main#38272d3f06bbc0b4b3cfa3f5da07fd1c1c89e4d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"kvm-bindings",
|
"kvm-bindings",
|
||||||
@@ -1174,9 +1199,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vhost-user-backend"
|
name = "vhost-user-backend"
|
||||||
version = "0.3.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1490f2028d4f119b2292efe218b5f8cfc6471f039b53b6a6eb5d9513e964facc"
|
checksum = "3eeb6723bbee20dbc2db95c575941922fb96e77eb41786ecd1c8c03348709c4c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
@@ -1249,7 +1274,6 @@ dependencies = [
|
|||||||
"rate_limiter",
|
"rate_limiter",
|
||||||
"seccompiler",
|
"seccompiler",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"versionize",
|
"versionize",
|
||||||
@@ -1267,9 +1291,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "virtio-queue"
|
name = "virtio-queue"
|
||||||
version = "0.2.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3785325315e6496fa88673842ee6cd198b9658e88e8b0e1ad48a5dc818b221dc"
|
checksum = "519c0a333c871650269cba303bc108075d52a0c0d64f9b91fae61829b53725af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
@@ -1290,8 +1314,8 @@ name = "vm-device"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"hypervisor",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"vfio-ioctls",
|
"vfio-ioctls",
|
||||||
@@ -1306,9 +1330,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#ca35d96191f8232bd7a
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vm-memory"
|
name = "vm-memory"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "339d4349c126fdcd87e034631d7274370cf19eb0e87b33166bcd956589fc72c5"
|
checksum = "767ed8aaebbff902e02e6d3749dc2baef55e46565f8a6414a065e5baee4b4a81"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1321,7 +1345,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"versionize",
|
"versionize",
|
||||||
@@ -1356,18 +1379,17 @@ dependencies = [
|
|||||||
"gdbstub",
|
"gdbstub",
|
||||||
"gdbstub_arch",
|
"gdbstub_arch",
|
||||||
"hypervisor",
|
"hypervisor",
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
"libc",
|
||||||
"linux-loader",
|
"linux-loader",
|
||||||
"log",
|
"log",
|
||||||
"micro_http",
|
"micro_http",
|
||||||
"net_util",
|
"net_util",
|
||||||
|
"once_cell",
|
||||||
"option_parser",
|
"option_parser",
|
||||||
"pci",
|
"pci",
|
||||||
"qcow",
|
"qcow",
|
||||||
"seccompiler",
|
"seccompiler",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -1410,9 +1432,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.10.2+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
|
|||||||
27
Cargo.toml
27
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cloud-hypervisor"
|
name = "cloud-hypervisor"
|
||||||
version = "23.0.0"
|
version = "25.0.0"
|
||||||
authors = ["The Cloud Hypervisor Authors"]
|
authors = ["The Cloud Hypervisor Authors"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
default-run = "cloud-hypervisor"
|
default-run = "cloud-hypervisor"
|
||||||
@@ -10,31 +10,31 @@ description = "Open source Virtual Machine Monitor (VMM) that runs on top of KVM
|
|||||||
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
||||||
# Minimum buildable version:
|
# Minimum buildable version:
|
||||||
# Keep in sync with version in .github/workflows/build.yaml
|
# Keep in sync with version in .github/workflows/build.yaml
|
||||||
rust-version = "1.56"
|
rust-version = "1.60"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.56"
|
anyhow = "1.0.58"
|
||||||
api_client = { path = "api_client" }
|
api_client = { path = "api_client" }
|
||||||
clap = { version = "3.1.8", features = ["wrap_help","cargo"] }
|
clap = { version = "3.2.8", features = ["wrap_help","cargo"] }
|
||||||
epoll = "4.3.1"
|
epoll = "4.3.1"
|
||||||
event_monitor = { path = "event_monitor" }
|
event_monitor = { path = "event_monitor" }
|
||||||
hypervisor = { path = "hypervisor" }
|
hypervisor = { path = "hypervisor" }
|
||||||
libc = "0.2.123"
|
libc = "0.2.126"
|
||||||
log = { version = "0.4.16", features = ["std"] }
|
log = { version = "0.4.17", features = ["std"] }
|
||||||
option_parser = { path = "option_parser" }
|
option_parser = { path = "option_parser" }
|
||||||
seccompiler = "0.2.0"
|
seccompiler = "0.2.0"
|
||||||
serde_json = "1.0.79"
|
serde_json = "1.0.82"
|
||||||
signal-hook = "0.3.13"
|
signal-hook = "0.3.14"
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.31"
|
||||||
vmm = { path = "vmm" }
|
vmm = { path = "vmm" }
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
vm-memory = "0.7.0"
|
vm-memory = "0.8.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
clap = { version = "3.1.8", features = ["cargo"] }
|
clap = { version = "3.2.8", features = ["cargo"] }
|
||||||
|
|
||||||
# List of patched crates
|
# List of patched crates
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
@@ -44,9 +44,9 @@ versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_deri
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
lazy_static= "1.4.0"
|
|
||||||
net_util = { path = "net_util" }
|
net_util = { path = "net_util" }
|
||||||
serde_json = "1.0.79"
|
once_cell = "1.13.0"
|
||||||
|
serde_json = "1.0.82"
|
||||||
test_infra = { path = "test_infra" }
|
test_infra = { path = "test_infra" }
|
||||||
wait-timeout = "0.2.0"
|
wait-timeout = "0.2.0"
|
||||||
|
|
||||||
@@ -58,6 +58,7 @@ amx = ["vmm/amx"]
|
|||||||
cmos = ["vmm/cmos"]
|
cmos = ["vmm/cmos"]
|
||||||
fwdebug = ["vmm/fwdebug"]
|
fwdebug = ["vmm/fwdebug"]
|
||||||
gdb = ["vmm/gdb"]
|
gdb = ["vmm/gdb"]
|
||||||
|
guest_debug = ["vmm/guest_debug"]
|
||||||
kvm = ["vmm/kvm"]
|
kvm = ["vmm/kvm"]
|
||||||
mshv = ["vmm/mshv"]
|
mshv = ["vmm/mshv"]
|
||||||
tdx = ["vmm/tdx"]
|
tdx = ["vmm/tdx"]
|
||||||
|
|||||||
24
Jenkinsfile
vendored
24
Jenkinsfile
vendored
@@ -23,6 +23,19 @@ pipeline{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stage ('Check for fuzzer cargo files only changes') {
|
||||||
|
when {
|
||||||
|
expression {
|
||||||
|
return fuzzCargoFileOnly()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
runWorkers = false
|
||||||
|
echo "Fuzzer cargo files only changes, no need to run the CI"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stage ('Check for RFC/WIP builds') {
|
stage ('Check for RFC/WIP builds') {
|
||||||
when {
|
when {
|
||||||
changeRequest comparator: 'REGEXP', title: '.*(rfc|RFC|wip|WIP).*'
|
changeRequest comparator: 'REGEXP', title: '.*(rfc|RFC|wip|WIP).*'
|
||||||
@@ -402,3 +415,14 @@ def boolean docsFileOnly() {
|
|||||||
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v '\\.md'"
|
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v '\\.md'"
|
||||||
) != 0
|
) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def boolean fuzzCargoFileOnly() {
|
||||||
|
if (env.CHANGE_TARGET == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sh(
|
||||||
|
returnStatus: true,
|
||||||
|
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v -E 'fuzz\\/Cargo.(toml|lock)'"
|
||||||
|
) != 0
|
||||||
|
}
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -88,12 +88,10 @@ Hypervisor. Here, all the steps are based on Ubuntu, for other Linux
|
|||||||
distributions please replace the package manager and package name.
|
distributions please replace the package manager and package name.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Install git
|
# Install build-essential, git, and qemu-img
|
||||||
$ sudo apt install git
|
$ sudo apt install git build-essential qemu-img
|
||||||
# Install rust tool chain
|
# Install rust tool chain
|
||||||
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||||
# Install build-essential
|
|
||||||
$ sudo apt install build-essential
|
|
||||||
# If you want to build statically linked binary please add musl target
|
# If you want to build statically linked binary please add musl target
|
||||||
$ rustup target add x86_64-unknown-linux-musl
|
$ rustup target add x86_64-unknown-linux-musl
|
||||||
```
|
```
|
||||||
@@ -168,7 +166,7 @@ cloud image. Here we will use a Ubuntu image:
|
|||||||
$ pushd $CLOUDH
|
$ pushd $CLOUDH
|
||||||
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
|
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
|
||||||
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-server-cloudimg-amd64.raw
|
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-server-cloudimg-amd64.raw
|
||||||
$ wget https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/download/0.3.2/hypervisor-fw
|
$ wget https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/download/0.4.0/hypervisor-fw
|
||||||
$ popd
|
$ popd
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -291,6 +289,8 @@ As of 2022-04-05, the following cloud images are supported:
|
|||||||
Direct kernel boot to userspace should work with a rootfs from most
|
Direct kernel boot to userspace should work with a rootfs from most
|
||||||
distributions.
|
distributions.
|
||||||
|
|
||||||
|
Further details can be found in the [release documentation](docs/releases.md).
|
||||||
|
|
||||||
## Hot Plug
|
## Hot Plug
|
||||||
|
|
||||||
Cloud Hypervisor supports hotplug of CPUs, passthrough devices (VFIO),
|
Cloud Hypervisor supports hotplug of CPUs, passthrough devices (VFIO),
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
vm-memory = "0.7.0"
|
vm-memory = "0.8.0"
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ impl Aml for Path {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for part in self.name_parts.clone().iter_mut() {
|
for part in self.name_parts.clone().iter_mut() {
|
||||||
bytes.extend_from_slice(&part.to_vec());
|
bytes.extend_from_slice(part.as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,18 +10,17 @@ tdx = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
acpi_tables = { path = "../acpi_tables" }
|
acpi_tables = { path = "../acpi_tables" }
|
||||||
anyhow = "1.0.56"
|
anyhow = "1.0.58"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
hypervisor = { path = "../hypervisor" }
|
hypervisor = { path = "../hypervisor" }
|
||||||
libc = "0.2.123"
|
libc = "0.2.126"
|
||||||
linux-loader = { version = "0.4.0", features = ["elf", "bzimage", "pe"] }
|
linux-loader = { version = "0.4.0", features = ["elf", "bzimage", "pe"] }
|
||||||
log = "0.4.16"
|
log = "0.4.17"
|
||||||
serde = { version = "1.0.136", features = ["rc"] }
|
serde = { version = "1.0.138", features = ["rc", "derive"] }
|
||||||
serde_derive = "1.0.136"
|
thiserror = "1.0.31"
|
||||||
thiserror = "1.0.30"
|
|
||||||
versionize = "0.1.6"
|
versionize = "0.1.6"
|
||||||
versionize_derive = "0.1.4"
|
versionize_derive = "0.1.4"
|
||||||
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-bitmap"] }
|
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||||
vm-migration = { path = "../vm-migration" }
|
vm-migration = { path = "../vm-migration" }
|
||||||
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
||||||
|
|
||||||
|
|||||||
@@ -8,17 +8,18 @@
|
|||||||
|
|
||||||
use crate::{NumaNodes, PciSpaceInfo};
|
use crate::{NumaNodes, PciSpaceInfo};
|
||||||
use byteorder::{BigEndian, ByteOrder};
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
|
use hypervisor::arch::aarch64::gic::Vgic;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use super::super::DeviceType;
|
use super::super::DeviceType;
|
||||||
use super::super::GuestMemoryMmap;
|
use super::super::GuestMemoryMmap;
|
||||||
use super::super::InitramfsConfig;
|
use super::super::InitramfsConfig;
|
||||||
use super::gic::GicDevice;
|
|
||||||
use super::layout::{
|
use super::layout::{
|
||||||
IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START,
|
IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START,
|
||||||
PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
|
PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
|
||||||
@@ -90,7 +91,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
|
|||||||
vcpu_mpidr: Vec<u64>,
|
vcpu_mpidr: Vec<u64>,
|
||||||
vcpu_topology: Option<(u8, u8, u8)>,
|
vcpu_topology: Option<(u8, u8, u8)>,
|
||||||
device_info: &HashMap<(DeviceType, String), T, S>,
|
device_info: &HashMap<(DeviceType, String), T, S>,
|
||||||
gic_device: &dyn GicDevice,
|
gic_device: &Arc<Mutex<dyn Vgic>>,
|
||||||
initrd: &Option<InitramfsConfig>,
|
initrd: &Option<InitramfsConfig>,
|
||||||
pci_space_info: &[PciSpaceInfo],
|
pci_space_info: &[PciSpaceInfo],
|
||||||
numa_nodes: &NumaNodes,
|
numa_nodes: &NumaNodes,
|
||||||
@@ -315,18 +316,18 @@ fn create_chosen_node(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_gic_node(fdt: &mut FdtWriter, gic_device: &dyn GicDevice) -> FdtWriterResult<()> {
|
fn create_gic_node(fdt: &mut FdtWriter, gic_device: &Arc<Mutex<dyn Vgic>>) -> FdtWriterResult<()> {
|
||||||
let gic_reg_prop = gic_device.device_properties();
|
let gic_reg_prop = gic_device.lock().unwrap().device_properties();
|
||||||
|
|
||||||
let intc_node = fdt.begin_node("intc")?;
|
let intc_node = fdt.begin_node("intc")?;
|
||||||
|
|
||||||
fdt.property_string("compatible", gic_device.fdt_compatibility())?;
|
fdt.property_string("compatible", gic_device.lock().unwrap().fdt_compatibility())?;
|
||||||
fdt.property_null("interrupt-controller")?;
|
fdt.property_null("interrupt-controller")?;
|
||||||
// "interrupt-cells" field specifies the number of cells needed to encode an
|
// "interrupt-cells" field specifies the number of cells needed to encode an
|
||||||
// interrupt source. The type shall be a <u32> and the value shall be 3 if no PPI affinity description
|
// interrupt source. The type shall be a <u32> and the value shall be 3 if no PPI affinity description
|
||||||
// is required.
|
// is required.
|
||||||
fdt.property_u32("#interrupt-cells", 3)?;
|
fdt.property_u32("#interrupt-cells", 3)?;
|
||||||
fdt.property_array_u64("reg", gic_reg_prop)?;
|
fdt.property_array_u64("reg", &gic_reg_prop)?;
|
||||||
fdt.property_u32("phandle", GIC_PHANDLE)?;
|
fdt.property_u32("phandle", GIC_PHANDLE)?;
|
||||||
fdt.property_u32("#address-cells", 2)?;
|
fdt.property_u32("#address-cells", 2)?;
|
||||||
fdt.property_u32("#size-cells", 2)?;
|
fdt.property_u32("#size-cells", 2)?;
|
||||||
@@ -334,18 +335,18 @@ fn create_gic_node(fdt: &mut FdtWriter, gic_device: &dyn GicDevice) -> FdtWriter
|
|||||||
|
|
||||||
let gic_intr_prop = [
|
let gic_intr_prop = [
|
||||||
GIC_FDT_IRQ_TYPE_PPI,
|
GIC_FDT_IRQ_TYPE_PPI,
|
||||||
gic_device.fdt_maint_irq(),
|
gic_device.lock().unwrap().fdt_maint_irq(),
|
||||||
IRQ_TYPE_LEVEL_HI,
|
IRQ_TYPE_LEVEL_HI,
|
||||||
];
|
];
|
||||||
fdt.property_array_u32("interrupts", &gic_intr_prop)?;
|
fdt.property_array_u32("interrupts", &gic_intr_prop)?;
|
||||||
|
|
||||||
if gic_device.msi_compatible() {
|
if gic_device.lock().unwrap().msi_compatible() {
|
||||||
let msic_node = fdt.begin_node("msic")?;
|
let msic_node = fdt.begin_node("msic")?;
|
||||||
fdt.property_string("compatible", gic_device.msi_compatibility())?;
|
fdt.property_string("compatible", gic_device.lock().unwrap().msi_compatibility())?;
|
||||||
fdt.property_null("msi-controller")?;
|
fdt.property_null("msi-controller")?;
|
||||||
fdt.property_u32("phandle", MSI_PHANDLE)?;
|
fdt.property_u32("phandle", MSI_PHANDLE)?;
|
||||||
let msi_reg_prop = gic_device.msi_properties();
|
let msi_reg_prop = gic_device.lock().unwrap().msi_properties();
|
||||||
fdt.property_array_u64("reg", msi_reg_prop)?;
|
fdt.property_array_u64("reg", &msi_reg_prop)?;
|
||||||
fdt.end_node(msic_node)?;
|
fdt.end_node(msic_node)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,262 +0,0 @@
|
|||||||
// Copyright 2021 Arm Limited (or its affiliates). All rights reserved.
|
|
||||||
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
//
|
|
||||||
// This file implements the GicV3 device.
|
|
||||||
|
|
||||||
pub mod kvm {
|
|
||||||
use crate::aarch64::gic::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
|
||||||
use crate::aarch64::gic::icc_regs::{get_icc_regs, set_icc_regs};
|
|
||||||
use crate::aarch64::gic::kvm::{save_pending_tables, KvmGicDevice};
|
|
||||||
use crate::aarch64::gic::redist_regs::{
|
|
||||||
construct_gicr_typers, get_redist_regs, set_redist_regs,
|
|
||||||
};
|
|
||||||
use crate::aarch64::gic::GicDevice;
|
|
||||||
use crate::layout;
|
|
||||||
use anyhow::anyhow;
|
|
||||||
use hypervisor::kvm::kvm_bindings;
|
|
||||||
use hypervisor::CpuState;
|
|
||||||
use std::any::Any;
|
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::{boxed::Box, result};
|
|
||||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
|
||||||
use versionize_derive::Versionize;
|
|
||||||
use vm_memory::Address;
|
|
||||||
use vm_migration::{
|
|
||||||
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable,
|
|
||||||
VersionMapped,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Errors thrown while saving/restoring the GICv3.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
/// Error in saving RDIST pending tables into guest RAM.
|
|
||||||
SavePendingTables(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GIC distributor registers.
|
|
||||||
SaveDistributorRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GIC distributor registers.
|
|
||||||
RestoreDistributorRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GIC distributor control registers.
|
|
||||||
SaveDistributorCtrlRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GIC distributor control registers.
|
|
||||||
RestoreDistributorCtrlRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GIC redistributor registers.
|
|
||||||
SaveRedistributorRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GIC redistributor registers.
|
|
||||||
RestoreRedistributorRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GIC CPU interface registers.
|
|
||||||
SaveIccRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GIC CPU interface registers.
|
|
||||||
RestoreIccRegisters(crate::aarch64::gic::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
|
||||||
|
|
||||||
pub struct KvmGicV3 {
|
|
||||||
/// The hypervisor agnostic device for the GicV3
|
|
||||||
device: Arc<dyn hypervisor::Device>,
|
|
||||||
|
|
||||||
/// Vector holding values of GICR_TYPER for each vCPU
|
|
||||||
gicr_typers: Vec<u64>,
|
|
||||||
|
|
||||||
/// GIC device properties, to be used for setting up the fdt entry
|
|
||||||
properties: [u64; 4],
|
|
||||||
|
|
||||||
/// Number of CPUs handled by the device
|
|
||||||
vcpu_count: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Versionize)]
|
|
||||||
pub struct Gicv3State {
|
|
||||||
dist: Vec<u32>,
|
|
||||||
rdist: Vec<u32>,
|
|
||||||
icc: Vec<u32>,
|
|
||||||
// special register that enables interrupts and affinity routing
|
|
||||||
gicd_ctlr: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VersionMapped for Gicv3State {}
|
|
||||||
|
|
||||||
impl KvmGicV3 {
|
|
||||||
// Device trees specific constants
|
|
||||||
pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9;
|
|
||||||
|
|
||||||
/// Get the address of the GIC distributor.
|
|
||||||
pub fn get_dist_addr() -> u64 {
|
|
||||||
layout::GIC_V3_DIST_START.raw_value()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the size of the GIC distributor.
|
|
||||||
pub fn get_dist_size() -> u64 {
|
|
||||||
layout::GIC_V3_DIST_SIZE
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the address of the GIC redistributors.
|
|
||||||
pub fn get_redists_addr(vcpu_count: u64) -> u64 {
|
|
||||||
KvmGicV3::get_dist_addr() - KvmGicV3::get_redists_size(vcpu_count)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the size of the GIC redistributors.
|
|
||||||
pub fn get_redists_size(vcpu_count: u64) -> u64 {
|
|
||||||
vcpu_count * layout::GIC_V3_REDIST_SIZE
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Save the state of GIC.
|
|
||||||
fn state(&self, gicr_typers: &[u64]) -> Result<Gicv3State> {
|
|
||||||
let gicd_ctlr =
|
|
||||||
read_ctlr(self.device()).map_err(Error::SaveDistributorCtrlRegisters)?;
|
|
||||||
|
|
||||||
let dist_state =
|
|
||||||
get_dist_regs(self.device()).map_err(Error::SaveDistributorRegisters)?;
|
|
||||||
|
|
||||||
let rdist_state = get_redist_regs(self.device(), gicr_typers)
|
|
||||||
.map_err(Error::SaveRedistributorRegisters)?;
|
|
||||||
|
|
||||||
let icc_state =
|
|
||||||
get_icc_regs(self.device(), gicr_typers).map_err(Error::SaveIccRegisters)?;
|
|
||||||
|
|
||||||
Ok(Gicv3State {
|
|
||||||
dist: dist_state,
|
|
||||||
rdist: rdist_state,
|
|
||||||
icc: icc_state,
|
|
||||||
gicd_ctlr,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Restore the state of GIC.
|
|
||||||
fn set_state(&mut self, gicr_typers: &[u64], state: &Gicv3State) -> Result<()> {
|
|
||||||
write_ctlr(self.device(), state.gicd_ctlr)
|
|
||||||
.map_err(Error::RestoreDistributorCtrlRegisters)?;
|
|
||||||
|
|
||||||
set_dist_regs(self.device(), &state.dist)
|
|
||||||
.map_err(Error::RestoreDistributorRegisters)?;
|
|
||||||
|
|
||||||
set_redist_regs(self.device(), gicr_typers, &state.rdist)
|
|
||||||
.map_err(Error::RestoreRedistributorRegisters)?;
|
|
||||||
|
|
||||||
set_icc_regs(self.device(), gicr_typers, &state.icc)
|
|
||||||
.map_err(Error::RestoreIccRegisters)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GicDevice for KvmGicV3 {
|
|
||||||
fn device(&self) -> &Arc<dyn hypervisor::Device> {
|
|
||||||
&self.device
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fdt_compatibility(&self) -> &str {
|
|
||||||
"arm,gic-v3"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fdt_maint_irq(&self) -> u32 {
|
|
||||||
KvmGicV3::ARCH_GIC_V3_MAINT_IRQ
|
|
||||||
}
|
|
||||||
|
|
||||||
fn device_properties(&self) -> &[u64] {
|
|
||||||
&self.properties
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vcpu_count(&self) -> u64 {
|
|
||||||
self.vcpu_count
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_its_device(&mut self, _its_device: Option<Arc<dyn hypervisor::Device>>) {}
|
|
||||||
|
|
||||||
fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
|
|
||||||
let gicr_typers = construct_gicr_typers(vcpu_states);
|
|
||||||
self.gicr_typers = gicr_typers;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any_concrete_mut(&mut self) -> &mut dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KvmGicDevice for KvmGicV3 {
|
|
||||||
fn version() -> u32 {
|
|
||||||
kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_device(
|
|
||||||
device: Arc<dyn hypervisor::Device>,
|
|
||||||
vcpu_count: u64,
|
|
||||||
) -> Box<dyn GicDevice> {
|
|
||||||
Box::new(KvmGicV3 {
|
|
||||||
device,
|
|
||||||
gicr_typers: vec![0; vcpu_count.try_into().unwrap()],
|
|
||||||
properties: [
|
|
||||||
KvmGicV3::get_dist_addr(),
|
|
||||||
KvmGicV3::get_dist_size(),
|
|
||||||
KvmGicV3::get_redists_addr(vcpu_count),
|
|
||||||
KvmGicV3::get_redists_size(vcpu_count),
|
|
||||||
],
|
|
||||||
vcpu_count,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_device_attributes(
|
|
||||||
_vm: &Arc<dyn hypervisor::Vm>,
|
|
||||||
gic_device: &mut dyn GicDevice,
|
|
||||||
) -> crate::aarch64::gic::Result<()> {
|
|
||||||
/* Setting up the distributor attribute.
|
|
||||||
We are placing the GIC below 1GB so we need to substract the size of the distributor.
|
|
||||||
*/
|
|
||||||
Self::set_device_attribute(
|
|
||||||
gic_device.device(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
|
|
||||||
u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_DIST),
|
|
||||||
&KvmGicV3::get_dist_addr() as *const u64 as u64,
|
|
||||||
0,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
/* Setting up the redistributors' attribute.
|
|
||||||
We are calculating here the start of the redistributors address. We have one per CPU.
|
|
||||||
*/
|
|
||||||
Self::set_device_attribute(
|
|
||||||
gic_device.device(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
|
|
||||||
u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_REDIST),
|
|
||||||
&KvmGicV3::get_redists_addr(gic_device.vcpu_count()) as *const u64 as u64,
|
|
||||||
0,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const GIC_V3_SNAPSHOT_ID: &str = "gic-v3";
|
|
||||||
impl Snapshottable for KvmGicV3 {
|
|
||||||
fn id(&self) -> String {
|
|
||||||
GIC_V3_SNAPSHOT_ID.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
|
||||||
let gicr_typers = self.gicr_typers.clone();
|
|
||||||
Snapshot::new_from_versioned_state(&self.id(), &self.state(&gicr_typers).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
|
||||||
let gicr_typers = self.gicr_typers.clone();
|
|
||||||
self.set_state(&gicr_typers, &snapshot.to_versioned_state(&self.id())?)
|
|
||||||
.map_err(|e| {
|
|
||||||
MigratableError::Restore(anyhow!("Could not restore GICv3 state {:?}", e))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Pausable for KvmGicV3 {
|
|
||||||
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
|
|
||||||
// Flush redistributors pending tables to guest RAM.
|
|
||||||
save_pending_tables(self.device()).map_err(|e| {
|
|
||||||
MigratableError::Pause(anyhow!("Could not save GICv3 GIC pending tables {:?}", e))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Transportable for KvmGicV3 {}
|
|
||||||
impl Migratable for KvmGicV3 {}
|
|
||||||
}
|
|
||||||
@@ -1,514 +0,0 @@
|
|||||||
// Copyright 2021 Arm Limited (or its affiliates). All rights reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
//
|
|
||||||
// This file implements the GicV3 device with ITS (Virtual Interrupt Translation Service).
|
|
||||||
|
|
||||||
pub mod kvm {
|
|
||||||
use crate::aarch64::gic::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
|
||||||
use crate::aarch64::gic::icc_regs::{get_icc_regs, set_icc_regs};
|
|
||||||
use crate::aarch64::gic::redist_regs::{
|
|
||||||
construct_gicr_typers, get_redist_regs, set_redist_regs,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::aarch64::gic::gicv3::kvm::KvmGicV3;
|
|
||||||
use crate::aarch64::gic::kvm::{save_pending_tables, KvmGicDevice};
|
|
||||||
use crate::aarch64::gic::GicDevice;
|
|
||||||
use crate::layout;
|
|
||||||
use anyhow::anyhow;
|
|
||||||
use hypervisor::kvm::kvm_bindings;
|
|
||||||
use hypervisor::CpuState;
|
|
||||||
use std::any::Any;
|
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::{boxed::Box, result};
|
|
||||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
|
||||||
use versionize_derive::Versionize;
|
|
||||||
use vm_migration::{
|
|
||||||
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable,
|
|
||||||
VersionMapped,
|
|
||||||
};
|
|
||||||
|
|
||||||
const GITS_CTLR: u32 = 0x0000;
|
|
||||||
const GITS_IIDR: u32 = 0x0004;
|
|
||||||
const GITS_CBASER: u32 = 0x0080;
|
|
||||||
const GITS_CWRITER: u32 = 0x0088;
|
|
||||||
const GITS_CREADR: u32 = 0x0090;
|
|
||||||
const GITS_BASER: u32 = 0x0100;
|
|
||||||
|
|
||||||
/// Errors thrown while saving/restoring the GICv3ITS.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
/// Error in saving RDIST pending tables into guest RAM.
|
|
||||||
SavePendingTables(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GIC distributor registers.
|
|
||||||
SaveDistributorRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GIC distributor registers.
|
|
||||||
RestoreDistributorRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GIC distributor control registers.
|
|
||||||
SaveDistributorCtrlRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GIC distributor control registers.
|
|
||||||
RestoreDistributorCtrlRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GIC redistributor registers.
|
|
||||||
SaveRedistributorRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GIC redistributor registers.
|
|
||||||
RestoreRedistributorRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GIC CPU interface registers.
|
|
||||||
SaveIccRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GIC CPU interface registers.
|
|
||||||
RestoreIccRegisters(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GICv3ITS IIDR register.
|
|
||||||
SaveITSIIDR(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GICv3ITS IIDR register.
|
|
||||||
RestoreITSIIDR(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GICv3ITS CBASER register.
|
|
||||||
SaveITSCBASER(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GICv3ITS CBASER register.
|
|
||||||
RestoreITSCBASER(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GICv3ITS CREADR register.
|
|
||||||
SaveITSCREADR(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GICv3ITS CREADR register.
|
|
||||||
RestoreITSCREADR(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GICv3ITS CWRITER register.
|
|
||||||
SaveITSCWRITER(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GICv3ITS CWRITER register.
|
|
||||||
RestoreITSCWRITER(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GICv3ITS BASER register.
|
|
||||||
SaveITSBASER(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GICv3ITS BASER register.
|
|
||||||
RestoreITSBASER(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GICv3ITS CTLR register.
|
|
||||||
SaveITSCTLR(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GICv3ITS CTLR register.
|
|
||||||
RestoreITSCTLR(crate::aarch64::gic::Error),
|
|
||||||
/// Error in saving GICv3ITS restore tables.
|
|
||||||
SaveITSTables(crate::aarch64::gic::Error),
|
|
||||||
/// Error in restoring GICv3ITS restore tables.
|
|
||||||
RestoreITSTables(crate::aarch64::gic::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
|
||||||
|
|
||||||
/// Access an ITS device attribute.
|
|
||||||
///
|
|
||||||
/// This is a helper function to get/set the ITS device attribute depending
|
|
||||||
/// the bool parameter `set` provided.
|
|
||||||
pub fn gicv3_its_attr_access(
|
|
||||||
its_device: &Arc<dyn hypervisor::Device>,
|
|
||||||
group: u32,
|
|
||||||
attr: u32,
|
|
||||||
val: &u64,
|
|
||||||
set: bool,
|
|
||||||
) -> crate::aarch64::gic::Result<()> {
|
|
||||||
let mut gicv3_its_attr = kvm_bindings::kvm_device_attr {
|
|
||||||
group,
|
|
||||||
attr: attr as u64,
|
|
||||||
addr: val as *const u64 as u64,
|
|
||||||
flags: 0,
|
|
||||||
};
|
|
||||||
if set {
|
|
||||||
its_device
|
|
||||||
.set_device_attr(&gicv3_its_attr)
|
|
||||||
.map_err(crate::aarch64::gic::Error::SetDeviceAttribute)?;
|
|
||||||
} else {
|
|
||||||
its_device
|
|
||||||
.get_device_attr(&mut gicv3_its_attr)
|
|
||||||
.map_err(crate::aarch64::gic::Error::GetDeviceAttribute)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Function that saves/restores ITS tables into guest RAM.
|
|
||||||
///
|
|
||||||
/// The tables get flushed to guest RAM whenever the VM gets stopped.
|
|
||||||
pub fn gicv3_its_tables_access(
|
|
||||||
its_device: &Arc<dyn hypervisor::Device>,
|
|
||||||
save: bool,
|
|
||||||
) -> crate::aarch64::gic::Result<()> {
|
|
||||||
let attr = if save {
|
|
||||||
u64::from(kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES)
|
|
||||||
} else {
|
|
||||||
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,
|
|
||||||
attr,
|
|
||||||
addr: 0,
|
|
||||||
flags: 0,
|
|
||||||
};
|
|
||||||
its_device
|
|
||||||
.set_device_attr(&init_gic_attr)
|
|
||||||
.map_err(crate::aarch64::gic::Error::SetDeviceAttribute)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct KvmGicV3Its {
|
|
||||||
/// The hypervisor agnostic device for the GicV3
|
|
||||||
device: Arc<dyn hypervisor::Device>,
|
|
||||||
|
|
||||||
/// The hypervisor agnostic device for the Its device
|
|
||||||
its_device: Option<Arc<dyn hypervisor::Device>>,
|
|
||||||
|
|
||||||
/// Vector holding values of GICR_TYPER for each vCPU
|
|
||||||
gicr_typers: Vec<u64>,
|
|
||||||
|
|
||||||
/// GIC device properties, to be used for setting up the fdt entry
|
|
||||||
gic_properties: [u64; 4],
|
|
||||||
|
|
||||||
/// MSI device properties, to be used for setting up the fdt entry
|
|
||||||
msi_properties: [u64; 2],
|
|
||||||
|
|
||||||
/// Number of CPUs handled by the device
|
|
||||||
vcpu_count: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Versionize)]
|
|
||||||
pub struct Gicv3ItsState {
|
|
||||||
dist: Vec<u32>,
|
|
||||||
rdist: Vec<u32>,
|
|
||||||
icc: Vec<u32>,
|
|
||||||
// special register that enables interrupts and affinity routing
|
|
||||||
gicd_ctlr: u32,
|
|
||||||
its_ctlr: u64,
|
|
||||||
its_iidr: u64,
|
|
||||||
its_cbaser: u64,
|
|
||||||
its_cwriter: u64,
|
|
||||||
its_creadr: u64,
|
|
||||||
its_baser: [u64; 8],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VersionMapped for Gicv3ItsState {}
|
|
||||||
|
|
||||||
impl KvmGicV3Its {
|
|
||||||
fn get_msi_size() -> u64 {
|
|
||||||
layout::GIC_V3_ITS_SIZE
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_msi_addr(vcpu_count: u64) -> u64 {
|
|
||||||
KvmGicV3::get_redists_addr(vcpu_count) - KvmGicV3Its::get_msi_size()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Save the state of GICv3ITS.
|
|
||||||
fn state(&self, gicr_typers: &[u64]) -> Result<Gicv3ItsState> {
|
|
||||||
let gicd_ctlr =
|
|
||||||
read_ctlr(self.device()).map_err(Error::SaveDistributorCtrlRegisters)?;
|
|
||||||
|
|
||||||
let dist_state =
|
|
||||||
get_dist_regs(self.device()).map_err(Error::SaveDistributorRegisters)?;
|
|
||||||
|
|
||||||
let rdist_state = get_redist_regs(self.device(), gicr_typers)
|
|
||||||
.map_err(Error::SaveRedistributorRegisters)?;
|
|
||||||
|
|
||||||
let icc_state =
|
|
||||||
get_icc_regs(self.device(), gicr_typers).map_err(Error::SaveIccRegisters)?;
|
|
||||||
|
|
||||||
let its_baser_state: [u64; 8] = [0; 8];
|
|
||||||
for i in 0..8 {
|
|
||||||
gicv3_its_attr_access(
|
|
||||||
self.its_device().unwrap(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
||||||
GITS_BASER + i * 8,
|
|
||||||
&its_baser_state[i as usize],
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.map_err(Error::SaveITSBASER)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let its_ctlr_state: u64 = 0;
|
|
||||||
gicv3_its_attr_access(
|
|
||||||
self.its_device().unwrap(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
||||||
GITS_CTLR,
|
|
||||||
&its_ctlr_state,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.map_err(Error::SaveITSCTLR)?;
|
|
||||||
|
|
||||||
let its_cbaser_state: u64 = 0;
|
|
||||||
gicv3_its_attr_access(
|
|
||||||
self.its_device().unwrap(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
||||||
GITS_CBASER,
|
|
||||||
&its_cbaser_state,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.map_err(Error::SaveITSCBASER)?;
|
|
||||||
|
|
||||||
let its_creadr_state: u64 = 0;
|
|
||||||
gicv3_its_attr_access(
|
|
||||||
self.its_device().unwrap(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
||||||
GITS_CREADR,
|
|
||||||
&its_creadr_state,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.map_err(Error::SaveITSCREADR)?;
|
|
||||||
|
|
||||||
let its_cwriter_state: u64 = 0;
|
|
||||||
gicv3_its_attr_access(
|
|
||||||
self.its_device().unwrap(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
||||||
GITS_CWRITER,
|
|
||||||
&its_cwriter_state,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.map_err(Error::SaveITSCWRITER)?;
|
|
||||||
|
|
||||||
let its_iidr_state: u64 = 0;
|
|
||||||
gicv3_its_attr_access(
|
|
||||||
self.its_device().unwrap(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
||||||
GITS_IIDR,
|
|
||||||
&its_iidr_state,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.map_err(Error::SaveITSIIDR)?;
|
|
||||||
|
|
||||||
Ok(Gicv3ItsState {
|
|
||||||
dist: dist_state,
|
|
||||||
rdist: rdist_state,
|
|
||||||
icc: icc_state,
|
|
||||||
gicd_ctlr,
|
|
||||||
its_ctlr: its_ctlr_state,
|
|
||||||
its_iidr: its_iidr_state,
|
|
||||||
its_cbaser: its_cbaser_state,
|
|
||||||
its_cwriter: its_cwriter_state,
|
|
||||||
its_creadr: its_creadr_state,
|
|
||||||
its_baser: its_baser_state,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Restore the state of GICv3ITS.
|
|
||||||
fn set_state(&mut self, gicr_typers: &[u64], state: &Gicv3ItsState) -> Result<()> {
|
|
||||||
write_ctlr(self.device(), state.gicd_ctlr)
|
|
||||||
.map_err(Error::RestoreDistributorCtrlRegisters)?;
|
|
||||||
|
|
||||||
set_dist_regs(self.device(), &state.dist)
|
|
||||||
.map_err(Error::RestoreDistributorRegisters)?;
|
|
||||||
|
|
||||||
set_redist_regs(self.device(), gicr_typers, &state.rdist)
|
|
||||||
.map_err(Error::RestoreRedistributorRegisters)?;
|
|
||||||
|
|
||||||
set_icc_regs(self.device(), gicr_typers, &state.icc)
|
|
||||||
.map_err(Error::RestoreIccRegisters)?;
|
|
||||||
|
|
||||||
//Restore GICv3ITS registers
|
|
||||||
gicv3_its_attr_access(
|
|
||||||
self.its_device().unwrap(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
||||||
GITS_IIDR,
|
|
||||||
&state.its_iidr,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.map_err(Error::RestoreITSIIDR)?;
|
|
||||||
|
|
||||||
gicv3_its_attr_access(
|
|
||||||
self.its_device().unwrap(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
||||||
GITS_CBASER,
|
|
||||||
&state.its_cbaser,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.map_err(Error::RestoreITSCBASER)?;
|
|
||||||
|
|
||||||
gicv3_its_attr_access(
|
|
||||||
self.its_device().unwrap(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
||||||
GITS_CREADR,
|
|
||||||
&state.its_creadr,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.map_err(Error::RestoreITSCREADR)?;
|
|
||||||
|
|
||||||
gicv3_its_attr_access(
|
|
||||||
self.its_device().unwrap(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
||||||
GITS_CWRITER,
|
|
||||||
&state.its_cwriter,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.map_err(Error::RestoreITSCWRITER)?;
|
|
||||||
|
|
||||||
for i in 0..8 {
|
|
||||||
gicv3_its_attr_access(
|
|
||||||
self.its_device().unwrap(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
||||||
GITS_BASER + i * 8,
|
|
||||||
&state.its_baser[i as usize],
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.map_err(Error::RestoreITSBASER)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore ITS tables
|
|
||||||
gicv3_its_tables_access(self.its_device().unwrap(), false)
|
|
||||||
.map_err(Error::RestoreITSTables)?;
|
|
||||||
|
|
||||||
gicv3_its_attr_access(
|
|
||||||
self.its_device().unwrap(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
|
||||||
GITS_CTLR,
|
|
||||||
&state.its_ctlr,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.map_err(Error::RestoreITSCTLR)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GicDevice for KvmGicV3Its {
|
|
||||||
fn device(&self) -> &Arc<dyn hypervisor::Device> {
|
|
||||||
&self.device
|
|
||||||
}
|
|
||||||
|
|
||||||
fn its_device(&self) -> Option<&Arc<dyn hypervisor::Device>> {
|
|
||||||
self.its_device.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fdt_compatibility(&self) -> &str {
|
|
||||||
"arm,gic-v3"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn msi_compatible(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn msi_compatibility(&self) -> &str {
|
|
||||||
"arm,gic-v3-its"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fdt_maint_irq(&self) -> u32 {
|
|
||||||
KvmGicV3::ARCH_GIC_V3_MAINT_IRQ
|
|
||||||
}
|
|
||||||
|
|
||||||
fn msi_properties(&self) -> &[u64] {
|
|
||||||
&self.msi_properties
|
|
||||||
}
|
|
||||||
|
|
||||||
fn device_properties(&self) -> &[u64] {
|
|
||||||
&self.gic_properties
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vcpu_count(&self) -> u64 {
|
|
||||||
self.vcpu_count
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_its_device(&mut self, its_device: Option<Arc<dyn hypervisor::Device>>) {
|
|
||||||
self.its_device = its_device;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
|
|
||||||
let gicr_typers = construct_gicr_typers(vcpu_states);
|
|
||||||
self.gicr_typers = gicr_typers;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any_concrete_mut(&mut self) -> &mut dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KvmGicDevice for KvmGicV3Its {
|
|
||||||
fn version() -> u32 {
|
|
||||||
KvmGicV3::version()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_device(
|
|
||||||
device: Arc<dyn hypervisor::Device>,
|
|
||||||
vcpu_count: u64,
|
|
||||||
) -> Box<dyn GicDevice> {
|
|
||||||
Box::new(KvmGicV3Its {
|
|
||||||
device,
|
|
||||||
its_device: None,
|
|
||||||
gicr_typers: vec![0; vcpu_count.try_into().unwrap()],
|
|
||||||
gic_properties: [
|
|
||||||
KvmGicV3::get_dist_addr(),
|
|
||||||
KvmGicV3::get_dist_size(),
|
|
||||||
KvmGicV3::get_redists_addr(vcpu_count),
|
|
||||||
KvmGicV3::get_redists_size(vcpu_count),
|
|
||||||
],
|
|
||||||
msi_properties: [
|
|
||||||
KvmGicV3Its::get_msi_addr(vcpu_count),
|
|
||||||
KvmGicV3Its::get_msi_size(),
|
|
||||||
],
|
|
||||||
vcpu_count,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_device_attributes(
|
|
||||||
vm: &Arc<dyn hypervisor::Vm>,
|
|
||||||
gic_device: &mut dyn GicDevice,
|
|
||||||
) -> crate::aarch64::gic::Result<()> {
|
|
||||||
KvmGicV3::init_device_attributes(vm, gic_device)?;
|
|
||||||
|
|
||||||
let mut its_device = kvm_bindings::kvm_create_device {
|
|
||||||
type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS,
|
|
||||||
fd: 0,
|
|
||||||
flags: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let its_fd = vm
|
|
||||||
.create_device(&mut its_device)
|
|
||||||
.map_err(crate::aarch64::gic::Error::CreateGic)?;
|
|
||||||
|
|
||||||
Self::set_device_attribute(
|
|
||||||
&its_fd,
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
|
|
||||||
u64::from(kvm_bindings::KVM_VGIC_ITS_ADDR_TYPE),
|
|
||||||
&KvmGicV3Its::get_msi_addr(gic_device.vcpu_count()) as *const u64 as u64,
|
|
||||||
0,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Self::set_device_attribute(
|
|
||||||
&its_fd,
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
|
|
||||||
u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
gic_device.set_its_device(Some(its_fd));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const GIC_V3_ITS_SNAPSHOT_ID: &str = "gic-v3-its";
|
|
||||||
impl Snapshottable for KvmGicV3Its {
|
|
||||||
fn id(&self) -> String {
|
|
||||||
GIC_V3_ITS_SNAPSHOT_ID.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
|
||||||
let gicr_typers = self.gicr_typers.clone();
|
|
||||||
Snapshot::new_from_versioned_state(&self.id(), &self.state(&gicr_typers).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
|
||||||
let gicr_typers = self.gicr_typers.clone();
|
|
||||||
self.set_state(&gicr_typers, &snapshot.to_versioned_state(&self.id())?)
|
|
||||||
.map_err(|e| {
|
|
||||||
MigratableError::Restore(anyhow!("Could not restore GICv3ITS state {:?}", e))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Pausable for KvmGicV3Its {
|
|
||||||
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
|
|
||||||
// Flush redistributors pending tables to guest RAM.
|
|
||||||
save_pending_tables(self.device()).map_err(|e| {
|
|
||||||
MigratableError::Pause(anyhow!(
|
|
||||||
"Could not save GICv3ITS GIC pending tables {:?}",
|
|
||||||
e
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
// Flush ITS tables to guest RAM.
|
|
||||||
gicv3_its_tables_access(self.its_device().unwrap(), true).map_err(|e| {
|
|
||||||
MigratableError::Pause(anyhow!("Could not save GICv3ITS ITS tables {:?}", e))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Transportable for KvmGicV3Its {}
|
|
||||||
impl Migratable for KvmGicV3Its {}
|
|
||||||
}
|
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
// Copyright 2021 Arm Limited (or its affiliates). All rights reserved.
|
|
||||||
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
pub mod dist_regs;
|
|
||||||
pub mod gicv3;
|
|
||||||
pub mod gicv3_its;
|
|
||||||
pub mod icc_regs;
|
|
||||||
pub mod redist_regs;
|
|
||||||
|
|
||||||
pub use self::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
|
||||||
pub use self::icc_regs::{get_icc_regs, set_icc_regs};
|
|
||||||
pub use self::redist_regs::{get_redist_regs, set_redist_regs};
|
|
||||||
use hypervisor::CpuState;
|
|
||||||
use std::any::Any;
|
|
||||||
use std::result;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
/// Errors thrown while setting up the GIC.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
/// Error while calling KVM ioctl for setting up the global interrupt controller.
|
|
||||||
CreateGic(hypervisor::HypervisorVmError),
|
|
||||||
/// Error while setting device attributes for the GIC.
|
|
||||||
SetDeviceAttribute(hypervisor::HypervisorDeviceError),
|
|
||||||
/// Error while getting device attributes for the GIC.
|
|
||||||
GetDeviceAttribute(hypervisor::HypervisorDeviceError),
|
|
||||||
}
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
|
||||||
|
|
||||||
pub trait GicDevice: Send {
|
|
||||||
/// Returns the hypervisor agnostic Device of the GIC device
|
|
||||||
fn device(&self) -> &Arc<dyn hypervisor::Device>;
|
|
||||||
|
|
||||||
/// Returns the hypervisor agnostic Device of the ITS device
|
|
||||||
fn its_device(&self) -> Option<&Arc<dyn hypervisor::Device>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the fdt compatibility property of the device
|
|
||||||
fn fdt_compatibility(&self) -> &str;
|
|
||||||
|
|
||||||
/// Returns the maint_irq fdt property of the device
|
|
||||||
fn fdt_maint_irq(&self) -> u32;
|
|
||||||
|
|
||||||
/// Returns an array with GIC device properties
|
|
||||||
fn device_properties(&self) -> &[u64];
|
|
||||||
|
|
||||||
/// Returns the number of vCPUs this GIC handles
|
|
||||||
fn vcpu_count(&self) -> u64;
|
|
||||||
|
|
||||||
/// Returns whether the GIC device is MSI compatible or not
|
|
||||||
fn msi_compatible(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the MSI compatibility property of the device
|
|
||||||
fn msi_compatibility(&self) -> &str {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the MSI reg property of the device
|
|
||||||
fn msi_properties(&self) -> &[u64] {
|
|
||||||
&[]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_its_device(&mut self, its_device: Option<Arc<dyn hypervisor::Device>>);
|
|
||||||
|
|
||||||
/// Get the values of GICR_TYPER for each vCPU.
|
|
||||||
fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]);
|
|
||||||
|
|
||||||
/// Downcast the trait object to its concrete type.
|
|
||||||
fn as_any_concrete_mut(&mut self) -> &mut dyn Any;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod kvm {
|
|
||||||
use super::GicDevice;
|
|
||||||
use super::Result;
|
|
||||||
use crate::aarch64::gic::gicv3_its::kvm::KvmGicV3Its;
|
|
||||||
use crate::layout;
|
|
||||||
use hypervisor::kvm::kvm_bindings;
|
|
||||||
use std::boxed::Box;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
/// Trait for GIC devices.
|
|
||||||
pub trait KvmGicDevice: Send + Sync + GicDevice {
|
|
||||||
/// Returns the GIC version of the device
|
|
||||||
fn version() -> u32;
|
|
||||||
|
|
||||||
/// Create the GIC device object
|
|
||||||
fn create_device(
|
|
||||||
device: Arc<dyn hypervisor::Device>,
|
|
||||||
vcpu_count: u64,
|
|
||||||
) -> Box<dyn GicDevice>;
|
|
||||||
|
|
||||||
/// Setup the device-specific attributes
|
|
||||||
fn init_device_attributes(
|
|
||||||
vm: &Arc<dyn hypervisor::Vm>,
|
|
||||||
gic_device: &mut dyn GicDevice,
|
|
||||||
) -> Result<()>;
|
|
||||||
|
|
||||||
/// Initialize a GIC device
|
|
||||||
fn init_device(vm: &Arc<dyn hypervisor::Vm>) -> Result<Arc<dyn hypervisor::Device>> {
|
|
||||||
let mut gic_device = kvm_bindings::kvm_create_device {
|
|
||||||
type_: Self::version(),
|
|
||||||
fd: 0,
|
|
||||||
flags: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
vm.create_device(&mut gic_device)
|
|
||||||
.map_err(super::Error::CreateGic)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set a GIC device attribute
|
|
||||||
fn set_device_attribute(
|
|
||||||
device: &Arc<dyn hypervisor::Device>,
|
|
||||||
group: u32,
|
|
||||||
attr: u64,
|
|
||||||
addr: u64,
|
|
||||||
flags: u32,
|
|
||||||
) -> Result<()> {
|
|
||||||
let attr = kvm_bindings::kvm_device_attr {
|
|
||||||
flags,
|
|
||||||
group,
|
|
||||||
attr,
|
|
||||||
addr,
|
|
||||||
};
|
|
||||||
device
|
|
||||||
.set_device_attr(&attr)
|
|
||||||
.map_err(super::Error::SetDeviceAttribute)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a GIC device attribute
|
|
||||||
fn get_device_attribute(
|
|
||||||
device: &Arc<dyn hypervisor::Device>,
|
|
||||||
group: u32,
|
|
||||||
attr: u64,
|
|
||||||
addr: u64,
|
|
||||||
flags: u32,
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut attr = kvm_bindings::kvm_device_attr {
|
|
||||||
flags,
|
|
||||||
group,
|
|
||||||
attr,
|
|
||||||
addr,
|
|
||||||
};
|
|
||||||
device
|
|
||||||
.get_device_attr(&mut attr)
|
|
||||||
.map_err(super::Error::GetDeviceAttribute)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finalize the setup of a GIC device
|
|
||||||
fn finalize_device(gic_device: &dyn GicDevice) -> Result<()> {
|
|
||||||
/* We need to tell the kernel how many irqs to support with this vgic.
|
|
||||||
* See the `layout` module for details.
|
|
||||||
*/
|
|
||||||
let nr_irqs: u32 = layout::IRQ_NUM;
|
|
||||||
let nr_irqs_ptr = &nr_irqs as *const u32;
|
|
||||||
Self::set_device_attribute(
|
|
||||||
gic_device.device(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
|
|
||||||
0,
|
|
||||||
nr_irqs_ptr as u64,
|
|
||||||
0,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
/* Finalize the GIC.
|
|
||||||
* See https://code.woboq.org/linux/linux/virt/kvm/arm/vgic/vgic-kvm-device.c.html#211.
|
|
||||||
*/
|
|
||||||
Self::set_device_attribute(
|
|
||||||
gic_device.device(),
|
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
|
|
||||||
u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Method to initialize the GIC device
|
|
||||||
#[allow(clippy::new_ret_no_self)]
|
|
||||||
fn new(vm: &Arc<dyn hypervisor::Vm>, vcpu_count: u64) -> Result<Box<dyn GicDevice>> {
|
|
||||||
let vgic_fd = Self::init_device(vm)?;
|
|
||||||
|
|
||||||
let mut device = Self::create_device(vgic_fd, vcpu_count);
|
|
||||||
|
|
||||||
Self::init_device_attributes(vm, &mut *device)?;
|
|
||||||
|
|
||||||
Self::finalize_device(&*device)?;
|
|
||||||
|
|
||||||
Ok(device)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a GICv3-ITS device.
|
|
||||||
///
|
|
||||||
pub fn create_gic(vm: &Arc<dyn hypervisor::Vm>, vcpu_count: u64) -> Result<Box<dyn GicDevice>> {
|
|
||||||
debug!("creating a GICv3-ITS");
|
|
||||||
KvmGicV3Its::new(vm, vcpu_count)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Function that saves RDIST pending tables into guest RAM.
|
|
||||||
///
|
|
||||||
/// The tables get flushed to guest RAM whenever the VM gets stopped.
|
|
||||||
pub fn save_pending_tables(gic: &Arc<dyn hypervisor::Device>) -> Result<()> {
|
|
||||||
let init_gic_attr = kvm_bindings::kvm_device_attr {
|
|
||||||
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
|
|
||||||
attr: u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES),
|
|
||||||
addr: 0,
|
|
||||||
flags: 0,
|
|
||||||
};
|
|
||||||
gic.set_device_attr(&init_gic_attr)
|
|
||||||
.map_err(super::Error::SetDeviceAttribute)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,23 +4,19 @@
|
|||||||
|
|
||||||
/// Module for the flattened device tree.
|
/// Module for the flattened device tree.
|
||||||
pub mod fdt;
|
pub mod fdt;
|
||||||
/// Module for the global interrupt controller configuration.
|
|
||||||
pub mod gic;
|
|
||||||
/// Layout for this aarch64 system.
|
/// Layout for this aarch64 system.
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
/// Logic for configuring aarch64 registers.
|
|
||||||
pub mod regs;
|
|
||||||
/// Module for loading UEFI binary.
|
/// Module for loading UEFI binary.
|
||||||
pub mod uefi;
|
pub mod uefi;
|
||||||
|
|
||||||
pub use self::fdt::DeviceInfoForFdt;
|
pub use self::fdt::DeviceInfoForFdt;
|
||||||
use crate::{DeviceType, GuestMemoryMmap, NumaNodes, PciSpaceInfo, RegionType};
|
use crate::{DeviceType, GuestMemoryMmap, NumaNodes, PciSpaceInfo, RegionType};
|
||||||
use gic::GicDevice;
|
use hypervisor::arch::aarch64::gic::Vgic;
|
||||||
use log::{log_enabled, Level};
|
use log::{log_enabled, Level};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex};
|
||||||
use vm_memory::{Address, GuestAddress, GuestMemory, GuestUsize};
|
use vm_memory::{Address, GuestAddress, GuestMemory, GuestUsize};
|
||||||
|
|
||||||
/// Errors thrown while configuring aarch64 system.
|
/// Errors thrown while configuring aarch64 system.
|
||||||
@@ -33,13 +29,13 @@ pub enum Error {
|
|||||||
WriteFdtToMemory(fdt::Error),
|
WriteFdtToMemory(fdt::Error),
|
||||||
|
|
||||||
/// Failed to create a GIC.
|
/// Failed to create a GIC.
|
||||||
SetupGic(gic::Error),
|
SetupGic,
|
||||||
|
|
||||||
/// Failed to compute the initramfs address.
|
/// Failed to compute the initramfs address.
|
||||||
InitramfsAddress,
|
InitramfsAddress,
|
||||||
|
|
||||||
/// Error configuring the general purpose registers
|
/// Error configuring the general purpose registers
|
||||||
RegsConfiguration(regs::Error),
|
RegsConfiguration(hypervisor::HypervisorCpuError),
|
||||||
|
|
||||||
/// Error configuring the MPIDR register
|
/// Error configuring the MPIDR register
|
||||||
VcpuRegMpidr(hypervisor::HypervisorCpuError),
|
VcpuRegMpidr(hypervisor::HypervisorCpuError),
|
||||||
@@ -50,7 +46,7 @@ pub enum Error {
|
|||||||
|
|
||||||
impl From<Error> for super::Error {
|
impl From<Error> for super::Error {
|
||||||
fn from(e: Error) -> super::Error {
|
fn from(e: Error) -> super::Error {
|
||||||
super::Error::AArch64Setup(e)
|
super::Error::PlatformSpecific(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,16 +60,20 @@ pub struct EntryPoint {
|
|||||||
|
|
||||||
/// Configure the specified VCPU, and return its MPIDR.
|
/// Configure the specified VCPU, and return its MPIDR.
|
||||||
pub fn configure_vcpu(
|
pub fn configure_vcpu(
|
||||||
fd: &Arc<dyn hypervisor::Vcpu>,
|
vcpu: &Arc<dyn hypervisor::Vcpu>,
|
||||||
id: u8,
|
id: u8,
|
||||||
kernel_entry_point: Option<EntryPoint>,
|
kernel_entry_point: Option<EntryPoint>,
|
||||||
) -> super::Result<u64> {
|
) -> super::Result<u64> {
|
||||||
if let Some(kernel_entry_point) = kernel_entry_point {
|
if let Some(kernel_entry_point) = kernel_entry_point {
|
||||||
regs::setup_regs(fd, id, kernel_entry_point.entry_addr.raw_value())
|
vcpu.setup_regs(
|
||||||
.map_err(Error::RegsConfiguration)?;
|
id,
|
||||||
|
kernel_entry_point.entry_addr.raw_value(),
|
||||||
|
super::layout::FDT_START.raw_value(),
|
||||||
|
)
|
||||||
|
.map_err(Error::RegsConfiguration)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mpidr = fd.read_mpidr().map_err(Error::VcpuRegMpidr)?;
|
let mpidr = vcpu.read_mpidr().map_err(Error::VcpuRegMpidr)?;
|
||||||
Ok(mpidr)
|
Ok(mpidr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
|
|||||||
initrd: &Option<super::InitramfsConfig>,
|
initrd: &Option<super::InitramfsConfig>,
|
||||||
pci_space_info: &[PciSpaceInfo],
|
pci_space_info: &[PciSpaceInfo],
|
||||||
virtio_iommu_bdf: Option<u32>,
|
virtio_iommu_bdf: Option<u32>,
|
||||||
gic_device: &dyn GicDevice,
|
gic_device: &Arc<Mutex<dyn Vgic>>,
|
||||||
numa_nodes: &NumaNodes,
|
numa_nodes: &NumaNodes,
|
||||||
pmu_supported: bool,
|
pmu_supported: bool,
|
||||||
) -> super::Result<()> {
|
) -> super::Result<()> {
|
||||||
@@ -185,10 +185,10 @@ pub fn initramfs_load_addr(
|
|||||||
if guest_mem.address_in_range(offset) {
|
if guest_mem.address_in_range(offset) {
|
||||||
Ok(offset.raw_value())
|
Ok(offset.raw_value())
|
||||||
} else {
|
} else {
|
||||||
Err(super::Error::AArch64Setup(Error::InitramfsAddress))
|
Err(super::Error::PlatformSpecific(Error::InitramfsAddress))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => Err(super::Error::AArch64Setup(Error::InitramfsAddress)),
|
None => Err(super::Error::PlatformSpecific(Error::InitramfsAddress)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
//
|
|
||||||
// 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 THIRD-PARTY file.
|
|
||||||
|
|
||||||
use hypervisor::kvm::kvm_bindings::{
|
|
||||||
kvm_regs, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM_CORE, KVM_REG_SIZE_U64,
|
|
||||||
};
|
|
||||||
use hypervisor::{arm64_core_reg_id, offset__of};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::{mem, result};
|
|
||||||
use vm_memory::Address;
|
|
||||||
|
|
||||||
/// Errors thrown while setting aarch64 registers.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
/// Failed to set core register (PC, PSTATE or general purpose ones).
|
|
||||||
SetCoreRegister(hypervisor::HypervisorCpuError),
|
|
||||||
/// Failed to get a system register.
|
|
||||||
GetSysRegister(hypervisor::HypervisorCpuError),
|
|
||||||
}
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
// PSR (Processor State Register) bits.
|
|
||||||
// Taken from arch/arm64/include/uapi/asm/ptrace.h.
|
|
||||||
const PSR_MODE_EL1h: u64 = 0x0000_0005;
|
|
||||||
const PSR_F_BIT: u64 = 0x0000_0040;
|
|
||||||
const PSR_I_BIT: u64 = 0x0000_0080;
|
|
||||||
const PSR_A_BIT: u64 = 0x0000_0100;
|
|
||||||
const PSR_D_BIT: u64 = 0x0000_0200;
|
|
||||||
// Taken from arch/arm64/kvm/inject_fault.c.
|
|
||||||
const PSTATE_FAULT_BITS_64: u64 = PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT;
|
|
||||||
|
|
||||||
/// Configure core registers for a given CPU.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
|
|
||||||
/// * `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) -> Result<()> {
|
|
||||||
let kreg_off = offset__of!(kvm_regs, regs);
|
|
||||||
|
|
||||||
// Get the register index of the PSTATE (Processor State) register.
|
|
||||||
let pstate = offset__of!(user_pt_regs, pstate) + kreg_off;
|
|
||||||
vcpu.set_reg(
|
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate),
|
|
||||||
PSTATE_FAULT_BITS_64,
|
|
||||||
)
|
|
||||||
.map_err(Error::SetCoreRegister)?;
|
|
||||||
|
|
||||||
// Other vCPUs are powered off initially awaiting PSCI wakeup.
|
|
||||||
if cpu_id == 0 {
|
|
||||||
// Setting the PC (Processor Counter) to the current program address (kernel address).
|
|
||||||
let pc = offset__of!(user_pt_regs, pc) + kreg_off;
|
|
||||||
vcpu.set_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), boot_ip as u64)
|
|
||||||
.map_err(Error::SetCoreRegister)?;
|
|
||||||
|
|
||||||
// Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
|
|
||||||
// "The device tree blob (dtb) must be placed on an 8-byte boundary and must
|
|
||||||
// not exceed 2 megabytes in size." -> https://www.kernel.org/doc/Documentation/arm64/booting.txt.
|
|
||||||
// We are choosing to place it the end of DRAM. See `get_fdt_addr`.
|
|
||||||
let regs0 = offset__of!(user_pt_regs, regs) + kreg_off;
|
|
||||||
vcpu.set_reg(
|
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
|
|
||||||
super::layout::FDT_START.raw_value(),
|
|
||||||
)
|
|
||||||
.map_err(Error::SetCoreRegister)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -9,15 +9,15 @@
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[macro_use]
|
|
||||||
extern crate serde_derive;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use crate::x86_64::SgxEpcSection;
|
use crate::x86_64::SgxEpcSection;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use thiserror::Error;
|
||||||
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
|
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
|
||||||
use versionize_derive::Versionize;
|
use versionize_derive::Versionize;
|
||||||
use vm_migration::VersionMapped;
|
use vm_migration::VersionMapped;
|
||||||
@@ -26,31 +26,27 @@ type GuestMemoryMmap = vm_memory::GuestMemoryMmap<vm_memory::bitmap::AtomicBitma
|
|||||||
type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitmap>;
|
type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitmap>;
|
||||||
|
|
||||||
/// Type for returning error code.
|
/// Type for returning error code.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
/// X86_64 specific error triggered during system configuration.
|
#[error("Platform specific error (x86_64): {0:?}")]
|
||||||
X86_64Setup(x86_64::Error),
|
PlatformSpecific(x86_64::Error),
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
/// AArch64 specific error triggered during system configuration.
|
#[error("Platform specific error (aarch64): {0:?}")]
|
||||||
AArch64Setup(aarch64::Error),
|
PlatformSpecific(aarch64::Error),
|
||||||
/// The zero page extends past the end of guest_mem.
|
#[error("The memory map table extends past the end of guest memory")]
|
||||||
ZeroPagePastRamEnd,
|
|
||||||
/// Error writing the zero page of guest memory.
|
|
||||||
ZeroPageSetup(vm_memory::GuestMemoryError),
|
|
||||||
/// The memory map table extends past the end of guest memory.
|
|
||||||
MemmapTablePastRamEnd,
|
MemmapTablePastRamEnd,
|
||||||
/// Error writing memory map table to guest memory.
|
#[error("Error writing memory map table to guest memory")]
|
||||||
MemmapTableSetup,
|
MemmapTableSetup,
|
||||||
/// The hvm_start_info structure extends past the end of guest memory.
|
#[error("The hvm_start_info structure extends past the end of guest memory")]
|
||||||
StartInfoPastRamEnd,
|
StartInfoPastRamEnd,
|
||||||
/// Error writing hvm_start_info to guest memory.
|
#[error("Error writing hvm_start_info to guest memory")]
|
||||||
StartInfoSetup,
|
StartInfoSetup,
|
||||||
/// Failed to compute initramfs address.
|
#[error("Failed to compute initramfs address")]
|
||||||
InitramfsAddress,
|
InitramfsAddress,
|
||||||
/// Error writing module entry to guest memory.
|
#[error("Error writing module entry to guest memory: {0}")]
|
||||||
ModlistSetup(vm_memory::GuestMemoryError),
|
ModlistSetup(#[source] vm_memory::GuestMemoryError),
|
||||||
/// RSDP Beyond Guest Memory
|
#[error("RSDP extends past the end of guest memory")]
|
||||||
RsdpPastRamEnd,
|
RsdpPastRamEnd,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +54,7 @@ pub enum Error {
|
|||||||
pub type Result<T> = result::Result<T, Error>;
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
/// Type for memory region types.
|
/// Type for memory region types.
|
||||||
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize, Versionize)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize, Versionize)]
|
||||||
pub enum RegionType {
|
pub enum RegionType {
|
||||||
/// RAM type
|
/// RAM type
|
||||||
Ram,
|
Ram,
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ pub mod regs;
|
|||||||
use crate::GuestMemoryMmap;
|
use crate::GuestMemoryMmap;
|
||||||
use crate::InitramfsConfig;
|
use crate::InitramfsConfig;
|
||||||
use crate::RegionType;
|
use crate::RegionType;
|
||||||
use hypervisor::{CpuId, CpuIdEntry, HypervisorError, CPUID_FLAG_VALID_INDEX};
|
use hypervisor::x86_64::{CpuId, CpuIdEntry, CPUID_FLAG_VALID_INDEX};
|
||||||
|
use hypervisor::HypervisorError;
|
||||||
use linux_loader::loader::bootparam::boot_params;
|
use linux_loader::loader::bootparam::boot_params;
|
||||||
use linux_loader::loader::elf::start_info::{
|
use linux_loader::loader::elf::start_info::{
|
||||||
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
|
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
|
||||||
@@ -197,7 +198,7 @@ pub enum Error {
|
|||||||
|
|
||||||
impl From<Error> for super::Error {
|
impl From<Error> for super::Error {
|
||||||
fn from(e: Error) -> super::Error {
|
fn from(e: Error) -> super::Error {
|
||||||
super::Error::X86_64Setup(e)
|
super::Error::PlatformSpecific(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -743,7 +744,7 @@ pub fn generate_common_cpuid(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure_vcpu(
|
pub fn configure_vcpu(
|
||||||
fd: &Arc<dyn hypervisor::Vcpu>,
|
vcpu: &Arc<dyn hypervisor::Vcpu>,
|
||||||
id: u8,
|
id: u8,
|
||||||
kernel_entry_point: Option<EntryPoint>,
|
kernel_entry_point: Option<EntryPoint>,
|
||||||
vm_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
|
vm_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
|
||||||
@@ -755,23 +756,23 @@ pub fn configure_vcpu(
|
|||||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
|
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
|
||||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
|
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
|
||||||
|
|
||||||
fd.set_cpuid2(&cpuid)
|
vcpu.set_cpuid2(&cpuid)
|
||||||
.map_err(|e| Error::SetSupportedCpusFailed(e.into()))?;
|
.map_err(|e| Error::SetSupportedCpusFailed(e.into()))?;
|
||||||
|
|
||||||
if kvm_hyperv {
|
if kvm_hyperv {
|
||||||
fd.enable_hyperv_synic().unwrap();
|
vcpu.enable_hyperv_synic().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
regs::setup_msrs(fd).map_err(Error::MsrsConfiguration)?;
|
regs::setup_msrs(vcpu).map_err(Error::MsrsConfiguration)?;
|
||||||
if let Some(kernel_entry_point) = kernel_entry_point {
|
if let Some(kernel_entry_point) = kernel_entry_point {
|
||||||
if let Some(entry_addr) = kernel_entry_point.entry_addr {
|
if let Some(entry_addr) = kernel_entry_point.entry_addr {
|
||||||
// Safe to unwrap because this method is called after the VM is configured
|
// Safe to unwrap because this method is called after the VM is configured
|
||||||
regs::setup_regs(fd, entry_addr.raw_value()).map_err(Error::RegsConfiguration)?;
|
regs::setup_regs(vcpu, entry_addr.raw_value()).map_err(Error::RegsConfiguration)?;
|
||||||
regs::setup_fpu(fd).map_err(Error::FpuConfiguration)?;
|
regs::setup_fpu(vcpu).map_err(Error::FpuConfiguration)?;
|
||||||
regs::setup_sregs(&vm_memory.memory(), fd).map_err(Error::SregsConfiguration)?;
|
regs::setup_sregs(&vm_memory.memory(), vcpu).map_err(Error::SregsConfiguration)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
interrupts::set_lint(fd).map_err(|e| Error::LocalIntConfiguration(e.into()))?;
|
interrupts::set_lint(vcpu).map_err(|e| Error::LocalIntConfiguration(e.into()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -838,13 +839,14 @@ pub fn configure_system(
|
|||||||
_num_cpus: u8,
|
_num_cpus: u8,
|
||||||
rsdp_addr: Option<GuestAddress>,
|
rsdp_addr: Option<GuestAddress>,
|
||||||
sgx_epc_region: Option<SgxEpcRegion>,
|
sgx_epc_region: Option<SgxEpcRegion>,
|
||||||
|
serial_number: Option<&str>,
|
||||||
) -> super::Result<()> {
|
) -> super::Result<()> {
|
||||||
// Write EBDA address to location where ACPICA expects to find it
|
// Write EBDA address to location where ACPICA expects to find it
|
||||||
guest_mem
|
guest_mem
|
||||||
.write_obj((layout::EBDA_START.0 >> 4) as u16, layout::EBDA_POINTER)
|
.write_obj((layout::EBDA_START.0 >> 4) as u16, layout::EBDA_POINTER)
|
||||||
.map_err(Error::EbdaSetup)?;
|
.map_err(Error::EbdaSetup)?;
|
||||||
|
|
||||||
let size = smbios::setup_smbios(guest_mem).map_err(Error::SmbiosSetup)?;
|
let size = smbios::setup_smbios(guest_mem, serial_number).map_err(Error::SmbiosSetup)?;
|
||||||
|
|
||||||
// Place the MP table after the SMIOS table aligned to 16 bytes
|
// Place the MP table after the SMIOS table aligned to 16 bytes
|
||||||
let offset = GuestAddress(layout::SMBIOS_START).unchecked_add(size);
|
let offset = GuestAddress(layout::SMBIOS_START).unchecked_add(size);
|
||||||
@@ -1193,6 +1195,7 @@ mod tests {
|
|||||||
1,
|
1,
|
||||||
Some(layout::RSDP_POINTER),
|
Some(layout::RSDP_POINTER),
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
assert!(config_err.is_err());
|
assert!(config_err.is_err());
|
||||||
|
|
||||||
@@ -1206,7 +1209,7 @@ mod tests {
|
|||||||
.collect();
|
.collect();
|
||||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||||
|
|
||||||
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
|
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None, None).unwrap();
|
||||||
|
|
||||||
// Now assigning some memory that is equal to the start of the 32bit memory hole.
|
// Now assigning some memory that is equal to the start of the 32bit memory hole.
|
||||||
let mem_size = 3328 << 20;
|
let mem_size = 3328 << 20;
|
||||||
@@ -1217,9 +1220,9 @@ mod tests {
|
|||||||
.map(|r| (r.0, r.1))
|
.map(|r| (r.0, r.1))
|
||||||
.collect();
|
.collect();
|
||||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||||
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
|
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None, None).unwrap();
|
||||||
|
|
||||||
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
|
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None, None).unwrap();
|
||||||
|
|
||||||
// Now assigning some memory that falls after the 32bit memory hole.
|
// Now assigning some memory that falls after the 32bit memory hole.
|
||||||
let mem_size = 3330 << 20;
|
let mem_size = 3330 << 20;
|
||||||
@@ -1230,9 +1233,9 @@ mod tests {
|
|||||||
.map(|r| (r.0, r.1))
|
.map(|r| (r.0, r.1))
|
||||||
.collect();
|
.collect();
|
||||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||||
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
|
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None, None).unwrap();
|
||||||
|
|
||||||
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
|
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None, None).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
use crate::layout::{BOOT_GDT_START, BOOT_IDT_START, PVH_INFO_START};
|
use crate::layout::{BOOT_GDT_START, BOOT_IDT_START, PVH_INFO_START};
|
||||||
use crate::GuestMemoryMmap;
|
use crate::GuestMemoryMmap;
|
||||||
use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt};
|
use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt};
|
||||||
use hypervisor::arch::x86::regs::*;
|
use hypervisor::arch::x86::regs::CR0_PE;
|
||||||
use hypervisor::x86_64::{FpuState, SpecialRegisters, StandardRegisters};
|
use hypervisor::x86_64::{FpuState, SpecialRegisters, StandardRegisters};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{mem, result};
|
use std::{mem, result};
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ fn write_string(
|
|||||||
Ok(curptr)
|
Ok(curptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_smbios(mem: &GuestMemoryMmap) -> Result<u64> {
|
pub fn setup_smbios(mem: &GuestMemoryMmap, serial_number: Option<&str>) -> Result<u64> {
|
||||||
let physptr = GuestAddress(SMBIOS_START)
|
let physptr = GuestAddress(SMBIOS_START)
|
||||||
.checked_add(mem::size_of::<Smbios30Entrypoint>() as u64)
|
.checked_add(mem::size_of::<Smbios30Entrypoint>() as u64)
|
||||||
.ok_or(Error::NotEnoughMemory)?;
|
.ok_or(Error::NotEnoughMemory)?;
|
||||||
@@ -195,11 +195,15 @@ pub fn setup_smbios(mem: &GuestMemoryMmap) -> Result<u64> {
|
|||||||
handle,
|
handle,
|
||||||
manufacturer: 1, // First string written in this section
|
manufacturer: 1, // First string written in this section
|
||||||
product_name: 2, // Second string written in this section
|
product_name: 2, // Second string written in this section
|
||||||
|
serial_number: serial_number.map(|_| 3).unwrap_or_default(), // 3rd string
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
curptr = write_and_incr(mem, smbios_sysinfo, curptr)?;
|
curptr = write_and_incr(mem, smbios_sysinfo, curptr)?;
|
||||||
curptr = write_string(mem, "Cloud Hypervisor", curptr)?;
|
curptr = write_string(mem, "Cloud Hypervisor", curptr)?;
|
||||||
curptr = write_string(mem, "cloud-hypervisor", curptr)?;
|
curptr = write_string(mem, "cloud-hypervisor", curptr)?;
|
||||||
|
if let Some(serial_number) = serial_number {
|
||||||
|
curptr = write_string(mem, serial_number, curptr)?;
|
||||||
|
}
|
||||||
curptr = write_and_incr(mem, 0u8, curptr)?;
|
curptr = write_and_incr(mem, 0u8, curptr)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,7 +267,7 @@ mod tests {
|
|||||||
fn entrypoint_checksum() {
|
fn entrypoint_checksum() {
|
||||||
let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(SMBIOS_START), 4096)]).unwrap();
|
let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(SMBIOS_START), 4096)]).unwrap();
|
||||||
|
|
||||||
setup_smbios(&mem).unwrap();
|
setup_smbios(&mem, None).unwrap();
|
||||||
|
|
||||||
let smbios_ep: Smbios30Entrypoint = mem.read_obj(GuestAddress(SMBIOS_START)).unwrap();
|
let smbios_ep: Smbios30Entrypoint = mem.read_obj(GuestAddress(SMBIOS_START)).unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -9,16 +9,16 @@ default = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
io-uring = "0.5.2"
|
io-uring = "0.5.2"
|
||||||
libc = "0.2.123"
|
libc = "0.2.126"
|
||||||
log = "0.4.16"
|
log = "0.4.17"
|
||||||
qcow = { path = "../qcow" }
|
qcow = { path = "../qcow" }
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.31"
|
||||||
versionize = "0.1.6"
|
versionize = "0.1.6"
|
||||||
versionize_derive = "0.1.4"
|
versionize_derive = "0.1.4"
|
||||||
vhdx = { path = "../vhdx" }
|
vhdx = { path = "../vhdx" }
|
||||||
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
|
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
|
||||||
virtio-queue = "0.2.0"
|
virtio-queue = "0.4.0"
|
||||||
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ impl DiskTopology {
|
|||||||
|
|
||||||
pub type DiskFileResult<T> = std::result::Result<T, DiskFileError>;
|
pub type DiskFileResult<T> = std::result::Result<T, DiskFileError>;
|
||||||
|
|
||||||
pub trait DiskFile: Send + Sync {
|
pub trait DiskFile: Send {
|
||||||
fn size(&mut self) -> DiskFileResult<u64>;
|
fn size(&mut self) -> DiskFileResult<u64>;
|
||||||
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>>;
|
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>>;
|
||||||
fn topology(&mut self) -> DiskTopology {
|
fn topology(&mut self) -> DiskTopology {
|
||||||
@@ -127,7 +127,7 @@ pub enum AsyncIoError {
|
|||||||
|
|
||||||
pub type AsyncIoResult<T> = std::result::Result<T, AsyncIoError>;
|
pub type AsyncIoResult<T> = std::result::Result<T, AsyncIoError>;
|
||||||
|
|
||||||
pub trait AsyncIo: Send + Sync {
|
pub trait AsyncIo: Send {
|
||||||
fn notifier(&self) -> &EventFd;
|
fn notifier(&self) -> &EventFd;
|
||||||
fn read_vectored(
|
fn read_vectored(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ impl ExecuteError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum RequestType {
|
pub enum RequestType {
|
||||||
In,
|
In,
|
||||||
Out,
|
Out,
|
||||||
|
|||||||
@@ -6,17 +6,18 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
acpi_tables = { path = "../acpi_tables" }
|
acpi_tables = { path = "../acpi_tables" }
|
||||||
anyhow = "1.0.56"
|
anyhow = "1.0.58"
|
||||||
arch = { path = "../arch" }
|
arch = { path = "../arch" }
|
||||||
bitflags = "1.3.2"
|
bitflags = "1.3.2"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
epoll = "4.3.1"
|
epoll = "4.3.1"
|
||||||
libc = "0.2.123"
|
hypervisor = { path = "../hypervisor" }
|
||||||
log = "0.4.16"
|
libc = "0.2.126"
|
||||||
|
log = "0.4.17"
|
||||||
versionize = "0.1.6"
|
versionize = "0.1.6"
|
||||||
versionize_derive = "0.1.4"
|
versionize_derive = "0.1.4"
|
||||||
vm-device = { path = "../vm-device" }
|
vm-device = { path = "../vm-device" }
|
||||||
vm-memory = "0.7.0"
|
vm-memory = "0.8.0"
|
||||||
vm-migration = { path = "../vm-migration" }
|
vm-migration = { path = "../vm-migration" }
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
|
|
||||||
|
|||||||
@@ -4,30 +4,34 @@
|
|||||||
|
|
||||||
use super::interrupt_controller::{Error, InterruptController};
|
use super::interrupt_controller::{Error, InterruptController};
|
||||||
extern crate arch;
|
extern crate arch;
|
||||||
use arch::aarch64::gic::GicDevice;
|
use anyhow::anyhow;
|
||||||
|
use arch::layout;
|
||||||
|
use hypervisor::{arch::aarch64::gic::Vgic, CpuState};
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use vm_device::interrupt::{
|
use vm_device::interrupt::{
|
||||||
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
|
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
|
||||||
LegacyIrqSourceConfig, MsiIrqGroupConfig,
|
LegacyIrqSourceConfig, MsiIrqGroupConfig,
|
||||||
};
|
};
|
||||||
|
use vm_memory::Address;
|
||||||
|
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
// Reserve 32 IRQs for legacy device.
|
// Reserve 32 IRQs for legacy devices.
|
||||||
pub const IRQ_LEGACY_BASE: usize = arch::layout::IRQ_BASE as usize;
|
pub const IRQ_LEGACY_BASE: usize = layout::IRQ_BASE as usize;
|
||||||
pub const IRQ_LEGACY_COUNT: usize = 32;
|
pub const IRQ_LEGACY_COUNT: usize = 32;
|
||||||
|
|
||||||
// This Gic struct implements InterruptController to provide interrupt delivery service.
|
// Gic (Generic Interupt Controller) struct provides all the functionality of a
|
||||||
// The Gic source files in arch/ folder maintain the Aarch64 specific Gic device.
|
// GIC device. It wraps a hypervisor-emulated GIC device (Vgic) provided by the
|
||||||
// The 2 Gic instances could be merged together.
|
// `hypervisor` crate.
|
||||||
// Leave this refactoring to future. Two options may be considered:
|
// Gic struct also implements InterruptController to provide interrupt delivery
|
||||||
// 1. Move Gic*.rs from arch/ folder here.
|
// service.
|
||||||
// 2. Move this file and ioapic.rs to arch/, as they are architecture specific.
|
|
||||||
pub struct Gic {
|
pub struct Gic {
|
||||||
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||||
gic_device: Option<Arc<Mutex<Box<dyn GicDevice>>>>,
|
// The hypervisor agnostic virtual GIC
|
||||||
|
vgic: Option<Arc<Mutex<dyn Vgic>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gic {
|
impl Gic {
|
||||||
@@ -44,16 +48,32 @@ impl Gic {
|
|||||||
|
|
||||||
Ok(Gic {
|
Ok(Gic {
|
||||||
interrupt_source_group,
|
interrupt_source_group,
|
||||||
gic_device: None,
|
vgic: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_gic_device(&mut self, gic_device: Arc<Mutex<Box<dyn GicDevice>>>) {
|
pub fn create_vgic(
|
||||||
self.gic_device = Some(gic_device);
|
&mut self,
|
||||||
|
vm: &Arc<dyn hypervisor::Vm>,
|
||||||
|
vcpu_count: u64,
|
||||||
|
) -> Result<Arc<Mutex<dyn Vgic>>> {
|
||||||
|
let vgic = vm
|
||||||
|
.create_vgic(
|
||||||
|
vcpu_count,
|
||||||
|
layout::GIC_V3_DIST_START.raw_value(),
|
||||||
|
layout::GIC_V3_DIST_SIZE,
|
||||||
|
layout::GIC_V3_REDIST_SIZE,
|
||||||
|
layout::GIC_V3_ITS_SIZE,
|
||||||
|
layout::IRQ_NUM,
|
||||||
|
)
|
||||||
|
.map_err(Error::CreateGic)?;
|
||||||
|
self.vgic = Some(vgic.clone());
|
||||||
|
Ok(vgic.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_gic_device(&self) -> Option<&Arc<Mutex<Box<dyn GicDevice>>>> {
|
pub fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
|
||||||
self.gic_device.as_ref()
|
let vgic = self.vgic.as_ref().unwrap().clone();
|
||||||
|
vgic.lock().unwrap().set_gicr_typers(vcpu_states);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,3 +117,43 @@ impl InterruptController for Gic {
|
|||||||
self.interrupt_source_group.notifier(irq as InterruptIndex)
|
self.interrupt_source_group.notifier(irq as InterruptIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const GIC_V3_ITS_SNAPSHOT_ID: &str = "gic-v3-its";
|
||||||
|
impl Snapshottable for Gic {
|
||||||
|
fn id(&self) -> String {
|
||||||
|
GIC_V3_ITS_SNAPSHOT_ID.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
|
let vgic = self.vgic.as_ref().unwrap().clone();
|
||||||
|
let state = vgic.lock().unwrap().state().unwrap();
|
||||||
|
Snapshot::new_from_state(&self.id(), &state)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
||||||
|
let vgic = self.vgic.as_ref().unwrap().clone();
|
||||||
|
vgic.lock()
|
||||||
|
.unwrap()
|
||||||
|
.set_state(&snapshot.to_state(&self.id())?)
|
||||||
|
.map_err(|e| {
|
||||||
|
MigratableError::Restore(anyhow!("Could not restore GICv3ITS state {:?}", e))
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pausable for Gic {
|
||||||
|
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
|
||||||
|
// Flush tables to guest RAM
|
||||||
|
let vgic = self.vgic.as_ref().unwrap().clone();
|
||||||
|
vgic.lock().unwrap().save_data_tables().map_err(|e| {
|
||||||
|
MigratableError::Pause(anyhow!(
|
||||||
|
"Could not save GICv3ITS GIC pending tables {:?}",
|
||||||
|
e
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Transportable for Gic {}
|
||||||
|
impl Migratable for Gic {}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ pub enum Error {
|
|||||||
UpdateInterrupt(io::Error),
|
UpdateInterrupt(io::Error),
|
||||||
/// Failed enabling the interrupt.
|
/// Failed enabling the interrupt.
|
||||||
EnableInterrupt(io::Error),
|
EnableInterrupt(io::Error),
|
||||||
|
/// Failed creating GIC device.
|
||||||
|
CreateGic(hypervisor::HypervisorVmError),
|
||||||
}
|
}
|
||||||
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
|
|||||||
86
devices/src/legacy/debug_port.rs
Normal file
86
devices/src/legacy/debug_port.rs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// Copyright © 2022 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::time::Instant;
|
||||||
|
use vm_device::BusDevice;
|
||||||
|
|
||||||
|
/// Debug I/O port, see:
|
||||||
|
/// https://www.intel.com/content/www/us/en/support/articles/000005500/boards-and-kits.html
|
||||||
|
///
|
||||||
|
/// Since we're not a physical platform, we can freely assign code ranges for
|
||||||
|
/// debugging specific parts of our virtual platform.
|
||||||
|
pub enum DebugIoPortRange {
|
||||||
|
Firmware,
|
||||||
|
Bootloader,
|
||||||
|
Kernel,
|
||||||
|
Userspace,
|
||||||
|
Custom,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
const DEBUG_IOPORT_PREFIX: &str = "Debug I/O port";
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
impl DebugIoPortRange {
|
||||||
|
fn from_u8(value: u8) -> DebugIoPortRange {
|
||||||
|
match value {
|
||||||
|
0x00..=0x1f => DebugIoPortRange::Firmware,
|
||||||
|
0x20..=0x3f => DebugIoPortRange::Bootloader,
|
||||||
|
0x40..=0x5f => DebugIoPortRange::Kernel,
|
||||||
|
0x60..=0x7f => DebugIoPortRange::Userspace,
|
||||||
|
_ => DebugIoPortRange::Custom,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
impl fmt::Display for DebugIoPortRange {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
DebugIoPortRange::Firmware => write!(f, "{}: Firmware", DEBUG_IOPORT_PREFIX),
|
||||||
|
DebugIoPortRange::Bootloader => write!(f, "{}: Bootloader", DEBUG_IOPORT_PREFIX),
|
||||||
|
DebugIoPortRange::Kernel => write!(f, "{}: Kernel", DEBUG_IOPORT_PREFIX),
|
||||||
|
DebugIoPortRange::Userspace => write!(f, "{}: Userspace", DEBUG_IOPORT_PREFIX),
|
||||||
|
DebugIoPortRange::Custom => write!(f, "{}: Custom", DEBUG_IOPORT_PREFIX),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DebugPort {
|
||||||
|
timestamp: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugPort {
|
||||||
|
pub fn new(timestamp: Instant) -> Self {
|
||||||
|
Self { timestamp }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BusDevice for DebugPort {
|
||||||
|
fn read(&mut self, _base: u64, _offset: u64, _data: &mut [u8]) {
|
||||||
|
error!("Invalid read to debug port")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(
|
||||||
|
&mut self,
|
||||||
|
_base: u64,
|
||||||
|
_offset: u64,
|
||||||
|
data: &[u8],
|
||||||
|
) -> Option<std::sync::Arc<std::sync::Barrier>> {
|
||||||
|
let elapsed = self.timestamp.elapsed();
|
||||||
|
|
||||||
|
let code = data[0];
|
||||||
|
warn!(
|
||||||
|
"[{} code 0x{:x}] {}.{:>06} seconds",
|
||||||
|
DebugIoPortRange::from_u8(code),
|
||||||
|
code,
|
||||||
|
elapsed.as_secs(),
|
||||||
|
elapsed.as_micros()
|
||||||
|
);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,8 @@
|
|||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
mod cmos;
|
mod cmos;
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
mod debug_port;
|
||||||
#[cfg(feature = "fwdebug")]
|
#[cfg(feature = "fwdebug")]
|
||||||
mod fwdebug;
|
mod fwdebug;
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
@@ -18,6 +20,8 @@ mod serial;
|
|||||||
mod uart_pl011;
|
mod uart_pl011;
|
||||||
|
|
||||||
pub use self::cmos::Cmos;
|
pub use self::cmos::Cmos;
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub use self::debug_port::DebugPort;
|
||||||
#[cfg(feature = "fwdebug")]
|
#[cfg(feature = "fwdebug")]
|
||||||
pub use self::fwdebug::FwDebugDevice;
|
pub use self::fwdebug::FwDebugDevice;
|
||||||
pub use self::i8042::I8042Device;
|
pub use self::i8042::I8042Device;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use crate::{read_le_u32, write_le_u32};
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
|
use std::time::Instant;
|
||||||
use std::{io, result};
|
use std::{io, result};
|
||||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||||
use versionize_derive::Versionize;
|
use versionize_derive::Versionize;
|
||||||
@@ -120,6 +121,7 @@ impl Pl011 {
|
|||||||
id: String,
|
id: String,
|
||||||
irq: Arc<dyn InterruptSourceGroup>,
|
irq: Arc<dyn InterruptSourceGroup>,
|
||||||
out: Option<Box<dyn io::Write + Send>>,
|
out: Option<Box<dyn io::Write + Send>>,
|
||||||
|
timestamp: Instant,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
@@ -140,7 +142,7 @@ impl Pl011 {
|
|||||||
read_trigger: 1u32,
|
read_trigger: 1u32,
|
||||||
irq,
|
irq,
|
||||||
out,
|
out,
|
||||||
timestamp: std::time::Instant::now(),
|
timestamp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,6 +497,7 @@ mod tests {
|
|||||||
String::from(SERIAL_NAME),
|
String::from(SERIAL_NAME),
|
||||||
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||||
Some(Box::new(pl011_out.clone())),
|
Some(Box::new(pl011_out.clone())),
|
||||||
|
Instant::now(),
|
||||||
);
|
);
|
||||||
|
|
||||||
pl011.write(0, UARTDR as u64, &[b'x', b'y']);
|
pl011.write(0, UARTDR as u64, &[b'x', b'y']);
|
||||||
@@ -515,6 +518,7 @@ mod tests {
|
|||||||
String::from(SERIAL_NAME),
|
String::from(SERIAL_NAME),
|
||||||
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||||
Some(Box::new(pl011_out)),
|
Some(Box::new(pl011_out)),
|
||||||
|
Instant::now(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// write 1 to the interrupt event fd, so that read doesn't block in case the event fd
|
// write 1 to the interrupt event fd, so that read doesn't block in case the event fd
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ Trigger power button of the VM | `/vm.power-button` | N/A
|
|||||||
Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted
|
Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted
|
||||||
Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused
|
Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused
|
||||||
Task a snapshot of the VM | `/vm.snapshot` | `/schemas/VmSnapshotConfig`| N/A | The VM is paused
|
Task a snapshot of the VM | `/vm.snapshot` | `/schemas/VmSnapshotConfig`| N/A | The VM is paused
|
||||||
|
Perform a coredump of the VM | `/vm.coredump` | `/schemas/VmCoredumpData` | N/A | The VM is paused
|
||||||
Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted
|
Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted
|
||||||
Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
|
Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
|
||||||
Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
|
Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
|
||||||
|
|||||||
@@ -6,22 +6,22 @@ This document describes the device model supported by `cloud-hypervisor`.
|
|||||||
|
|
||||||
| Device | Build configurable | Enabled by default | Runtime configurable |
|
| Device | Build configurable | Enabled by default | Runtime configurable |
|
||||||
| :----: | :----: | :----: | :----: |
|
| :----: | :----: | :----: | :----: |
|
||||||
| Serial port | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
|
| Serial port | :x: | :x: | :heavy_check_mark: |
|
||||||
| RTC/CMOS | :heavy_check_mark: | :heavy_check_mark: | :negative_squared_cross_mark: |
|
| RTC/CMOS | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||||
| I/O APIC | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
|
| I/O APIC | :x: | :x: | :heavy_check_mark: |
|
||||||
| i8042 shutdown/reboot | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :negative_squared_cross_mark: |
|
| i8042 shutdown/reboot | :x: | :x: | :x: |
|
||||||
| ACPI shutdown/reboot | :negative_squared_cross_mark: | :heavy_check_mark: | :negative_squared_cross_mark: |
|
| ACPI shutdown/reboot | :x: | :heavy_check_mark: | :x: |
|
||||||
| virtio-blk | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
|
| virtio-blk | :x: | :x: | :heavy_check_mark: |
|
||||||
| virtio-console | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
|
| virtio-console | :x: | :x: | :heavy_check_mark: |
|
||||||
| virtio-iommu | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
|
| virtio-iommu | :x: | :x: | :heavy_check_mark: |
|
||||||
| virtio-net | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
|
| virtio-net | :x: | :x: | :heavy_check_mark: |
|
||||||
| virtio-pmem | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
|
| virtio-pmem | :x: | :x: | :heavy_check_mark: |
|
||||||
| virtio-rng | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
|
| virtio-rng | :x: | :x: | :heavy_check_mark: |
|
||||||
| virtio-vsock | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
|
| virtio-vsock | :x: | :x: | :heavy_check_mark: |
|
||||||
| vhost-user-blk | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
|
| vhost-user-blk | :x: | :x: | :heavy_check_mark: |
|
||||||
| vhost-user-fs | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
|
| vhost-user-fs | :x: | :x: | :heavy_check_mark: |
|
||||||
| vhost-user-net | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
|
| vhost-user-net | :x: | :x: | :heavy_check_mark: |
|
||||||
| VFIO | :heavy_check_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
|
| VFIO | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||||
|
|
||||||
## Legacy devices
|
## Legacy devices
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ bucket is unbounded in speed which allows for bursts bound in size by
|
|||||||
the amount of tokens available. Once the token bucket is empty,
|
the amount of tokens available. Once the token bucket is empty,
|
||||||
consumption speed is bound by the "refill-rate". Similarly, Cloud
|
consumption speed is bound by the "refill-rate". Similarly, Cloud
|
||||||
Hypervisor provides another three options for limiting I/O operations,
|
Hypervisor provides another three options for limiting I/O operations,
|
||||||
i.e., `ops_size` (I/O operations), `bw_one_time_burst` (I/O operations),
|
i.e., `ops_size` (I/O operations), `ops_one_time_burst` (I/O operations),
|
||||||
and `bw_refill_time` (ms).
|
and `ops_refill_time` (ms).
|
||||||
|
|
||||||
One caveat in the I/O throttling is that every-time the bucket gets
|
One caveat in the I/O throttling is that every-time the bucket gets
|
||||||
empty, it will stop I/O operations for a fixed amount of time
|
empty, it will stop I/O operations for a fixed amount of time
|
||||||
|
|||||||
@@ -43,3 +43,22 @@ $ perf report -g
|
|||||||
```
|
```
|
||||||
|
|
||||||
If profiling with a network device attached either the TAP device must be already created and configured or the profiling must be done as root so that the TAP device can be created.
|
If profiling with a network device attached either the TAP device must be already created and configured or the profiling must be done as root so that the TAP device can be created.
|
||||||
|
|
||||||
|
## Userspace only profiling with LBR
|
||||||
|
|
||||||
|
The use of LBR (Last Branch Record; available since Haswell) offers lower
|
||||||
|
overhead if only userspace profiling is required. This lower overhead can allow
|
||||||
|
a higher frequency of sampling. This also removes the requirement to compile
|
||||||
|
with custom `RUSTFLAGS` however debug symbols should still be included:
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ perf record --call-graph lbr --all-user --user-callchains -g target/release/cloud-hypervisor \
|
||||||
|
--kernel ~/src/linux/vmlinux \
|
||||||
|
--pmem file=~/workloads/focal.raw \
|
||||||
|
--cpus boot=1 --memory size=1G \
|
||||||
|
--cmdline "root=/dev/pmem0p1 console=ttyS0" \
|
||||||
|
--serial tty --console off \
|
||||||
|
--api-socket=/tmp/api1
|
||||||
|
```
|
||||||
|
|||||||
103
docs/releases.md
Executable file
103
docs/releases.md
Executable file
@@ -0,0 +1,103 @@
|
|||||||
|
# Release Documentation
|
||||||
|
|
||||||
|
## Abstract
|
||||||
|
|
||||||
|
This document provides guidance to users, downstream maintainers and
|
||||||
|
any other consumers of the Cloud Hypervisor project, this document
|
||||||
|
describes the release process, release cadence, stability expectations and
|
||||||
|
related topics.
|
||||||
|
|
||||||
|
## Basic Terms
|
||||||
|
|
||||||
|
### Stability
|
||||||
|
|
||||||
|
For Cloud Hypervisor the following areas are subject to stability guarantees:
|
||||||
|
|
||||||
|
- [REST API](api.md#rest-api)
|
||||||
|
- [Command line options](api.md#command-line-interface)
|
||||||
|
- [Device Model](device_model.md)
|
||||||
|
- Device tree, device list, ACPI, Hyper-V enlightenments and any other
|
||||||
|
features exposed to guest
|
||||||
|
- KVM compatibility
|
||||||
|
- Rust edition compatibility
|
||||||
|
|
||||||
|
This list is incomplete but this document serves as a best effort guide to stability
|
||||||
|
across releases.
|
||||||
|
|
||||||
|
### Experimental features
|
||||||
|
|
||||||
|
Experimental features are under active development and no guarantees are made about their stability.
|
||||||
|
|
||||||
|
List of experimental features:
|
||||||
|
|
||||||
|
- TDX
|
||||||
|
- vfio-user
|
||||||
|
- vDPA
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
Security fixes should be included in a new point release.
|
||||||
|
|
||||||
|
For security issues an advisory will be published via the GitHub security advisory process along with the release. Watching the project on GitHub will notify you of those issues.
|
||||||
|
|
||||||
|
## Releases
|
||||||
|
|
||||||
|
### Versioning
|
||||||
|
|
||||||
|
The versioning scheme uses `MAJOR.POINT` pattern:
|
||||||
|
|
||||||
|
- `MAJOR` can introduce incompatible changes along with support for new features. Changes to the [API](api.md#rest-api),
|
||||||
|
[CLI options](api.md#command-line-interface) and [device model](device_model.md)
|
||||||
|
require a notice at least 2 releases in advance for the actual change to take
|
||||||
|
place.
|
||||||
|
- `POINT` contains bug fixes and/or security fixes.
|
||||||
|
|
||||||
|
### Major Release Cadence
|
||||||
|
|
||||||
|
Cloud Hypervisor is under active development. A new major release is issued approximately
|
||||||
|
every 6 weeks. Point releases are issued on demand, when important bug fixes are in
|
||||||
|
the queue. A major release would receive bug fixes for the next two cycles (~12 weeks)
|
||||||
|
and then be considered EOL.
|
||||||
|
|
||||||
|
```
|
||||||
|
+ - Active release support
|
||||||
|
E - EOL
|
||||||
|
|
||||||
|
2021 2022 2023
|
||||||
|
| | | | | | | | |
|
||||||
|
18.0 | | | ++++++++E
|
||||||
|
19.0 | | | |++++++++E
|
||||||
|
20.0 | | | | ++++++++E
|
||||||
|
21.0 | | | | | ++++++++E
|
||||||
|
22.0 | | | | | +++++++++E
|
||||||
|
23.0 | | | | | | +++++++++E
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Major Release Stability Considerations
|
||||||
|
|
||||||
|
Snapshot/restore support is not compatible across `MAJOR` versions.
|
||||||
|
Live migration support is not compatible across `MAJOR` versions.
|
||||||
|
|
||||||
|
### LTS Release Cadence
|
||||||
|
|
||||||
|
A regular release is promoted to LTS every 12 months. An LTS release is supported for 18 months. This gives a 6 months window for users to move to the new LTS.
|
||||||
|
|
||||||
|
```
|
||||||
|
+ - Active release support
|
||||||
|
E - EOL
|
||||||
|
|
||||||
|
2022 2023 2024 2025 2026
|
||||||
|
| | | | | | | | | | | | | | | | |
|
||||||
|
23.0 | |+++++++++++++++++++++++++++++E
|
||||||
|
43.0 | | | | | |+++++++++++++++++++++++++++++E
|
||||||
|
63.0 | | | | | | | | | |+++++++++++++++++++++++++++++E
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### LTS Stablity Considerations
|
||||||
|
|
||||||
|
An LTS release is just a `MAJOR` release for which point releases are made for
|
||||||
|
longer following the same rules for what can be backported to a `POINT` release.
|
||||||
|
The focus lays on critical and security bug fixes which are pulled at the
|
||||||
|
maintainer's discretion.
|
||||||
@@ -75,8 +75,7 @@ Here is an example how to create a bridge and add two DPDK ports to it
|
|||||||
ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev
|
ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev
|
||||||
# create two DPDK ports and add them to the bridge
|
# create two DPDK ports and add them to the bridge
|
||||||
ovs-vsctl add-port ovsbr0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuser
|
ovs-vsctl add-port ovsbr0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuser
|
||||||
ovs-vsctl add-port ovsbr0 vhost-user2 -- set Interface vhost-user2
|
ovs-vsctl add-port ovsbr0 vhost-user2 -- set Interface vhost-user2 type=dpdkvhostuser
|
||||||
type=dpdkvhostuser
|
|
||||||
# set the number of rx queues
|
# set the number of rx queues
|
||||||
ovs-vsctl set Interface vhost-user1 options:n_rxq=2
|
ovs-vsctl set Interface vhost-user1 options:n_rxq=2
|
||||||
ovs-vsctl set Interface vhost-user2 options:n_rxq=2
|
ovs-vsctl set Interface vhost-user2 options:n_rxq=2
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ authors = ["The Cloud Hypervisor Authors"]
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2.123"
|
libc = "0.2.126"
|
||||||
serde = { version = "1.0.136", features = ["rc"] }
|
serde = { version = "1.0.138", features = ["rc", "derive"] }
|
||||||
serde_derive = "1.0.136"
|
serde_json = "1.0.82"
|
||||||
serde_json = "1.0.79"
|
|
||||||
|
|||||||
@@ -3,12 +3,11 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
#[macro_use]
|
use serde::Serialize;
|
||||||
extern crate serde_derive;
|
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
@@ -50,6 +49,9 @@ pub fn event_log(source: &str, event: &str, properties: Option<&HashMap<Cow<str>
|
|||||||
properties,
|
properties,
|
||||||
};
|
};
|
||||||
serde_json::to_writer_pretty(file, &e).ok();
|
serde_json::to_writer_pretty(file, &e).ok();
|
||||||
|
|
||||||
|
let mut file = file;
|
||||||
|
file.write_all(b"\n\n").ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
204
fuzz/Cargo.lock
generated
204
fuzz/Cargo.lock
generated
@@ -11,9 +11,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.56"
|
version = "1.0.58"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
|
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "api_client"
|
name = "api_client"
|
||||||
@@ -24,9 +24,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arbitrary"
|
name = "arbitrary"
|
||||||
version = "1.1.0"
|
version = "1.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c38b6b6b79f671c25e1a3e785b7b82d7562ffc9cd3efdc98627e5668a2472490"
|
checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arc-swap"
|
name = "arc-swap"
|
||||||
@@ -47,7 +47,6 @@ dependencies = [
|
|||||||
"linux-loader",
|
"linux-loader",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"versionize",
|
"versionize",
|
||||||
"versionize_derive",
|
"versionize_derive",
|
||||||
@@ -128,24 +127,33 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "3.1.8"
|
version = "3.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
|
checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty",
|
"atty",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"clap_lex",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"lazy_static",
|
"once_cell",
|
||||||
"os_str_bytes",
|
|
||||||
"strsim",
|
"strsim",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"terminal_size",
|
"terminal_size",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||||
|
dependencies = [
|
||||||
|
"os_str_bytes",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cloud-hypervisor"
|
name = "cloud-hypervisor"
|
||||||
version = "22.0.0"
|
version = "24.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"api_client",
|
"api_client",
|
||||||
@@ -208,6 +216,7 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"epoll",
|
"epoll",
|
||||||
|
"hypervisor",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"versionize",
|
"versionize",
|
||||||
@@ -234,7 +243,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -244,35 +252,11 @@ version = "0.1.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
|
checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gdbstub"
|
|
||||||
version = "0.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9fa2ca5d6b045de372cef3991f873389b421b4cabcfbe52f7787fae8b8b37906"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"cfg-if",
|
|
||||||
"log",
|
|
||||||
"managed",
|
|
||||||
"num-traits",
|
|
||||||
"paste",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gdbstub_arch"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "51dc4b5718ac76d21e8605c0966dd32d80273b89b11e6cfef467b04e45934d37"
|
|
||||||
dependencies = [
|
|
||||||
"gdbstub",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.6"
|
version = "0.2.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
|
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -281,9 +265,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.11.2"
|
version = "0.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
@@ -306,7 +290,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
@@ -325,9 +308,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.8.1"
|
version = "1.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
|
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@@ -345,9 +328,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.1"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kvm-bindings"
|
name = "kvm-bindings"
|
||||||
@@ -377,9 +360,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.123"
|
version = "0.2.126"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd"
|
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libfuzzer-sys"
|
name = "libfuzzer-sys"
|
||||||
@@ -403,25 +386,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.16"
|
version = "0.4.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
|
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "managed"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "micro_http"
|
name = "micro_http"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -458,20 +429,11 @@ dependencies = [
|
|||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-traits"
|
|
||||||
version = "0.2.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.10.0"
|
version = "1.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "option_parser"
|
name = "option_parser"
|
||||||
@@ -479,18 +441,9 @@ version = "0.1.0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_str_bytes"
|
name = "os_str_bytes"
|
||||||
version = "6.0.0"
|
version = "6.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "paste"
|
|
||||||
version = "1.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pci"
|
name = "pci"
|
||||||
@@ -502,7 +455,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"versionize",
|
"versionize",
|
||||||
"versionize_derive",
|
"versionize_derive",
|
||||||
@@ -518,11 +470,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.37"
|
version = "1.0.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
|
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -538,9 +490,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.18"
|
version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@@ -556,9 +508,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "remain"
|
name = "remain"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "70ba1e78fa68412cb93ef642fd4d20b9a941be49ee9333875ebaf13112673ea7"
|
checksum = "0c35270ea384ac1762895831cc8acb96f171468e52cec82ed9186f9416209fa4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -576,9 +528,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.9"
|
version = "1.0.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "seccompiler"
|
name = "seccompiler"
|
||||||
@@ -591,21 +543,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.7"
|
version = "1.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
|
checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.136"
|
version = "1.0.138"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.136"
|
version = "1.0.138"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
|
checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -614,9 +569,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.79"
|
version = "1.0.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
|
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@@ -625,9 +580,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook"
|
name = "signal-hook"
|
||||||
version = "0.3.13"
|
version = "0.3.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
|
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
@@ -656,13 +611,13 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.91"
|
version = "1.0.98"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
|
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"unicode-xid",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -695,18 +650,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.30"
|
version = "1.0.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.30"
|
version = "1.0.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -714,16 +669,16 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-ident"
|
||||||
version = "0.2.2"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "0.8.2"
|
version = "1.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
@@ -847,7 +802,6 @@ dependencies = [
|
|||||||
"rate_limiter",
|
"rate_limiter",
|
||||||
"seccompiler",
|
"seccompiler",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"versionize",
|
"versionize",
|
||||||
@@ -865,9 +819,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "virtio-queue"
|
name = "virtio-queue"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3785325315e6496fa88673842ee6cd198b9658e88e8b0e1ad48a5dc818b221dc"
|
checksum = "88f2d73c184c18f8acc32dab77fcb6e3af92d53262538d3a68aa474810d6863c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
@@ -888,8 +842,8 @@ name = "vm-device"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"hypervisor",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"vfio-ioctls",
|
"vfio-ioctls",
|
||||||
@@ -904,9 +858,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#720e48e435b791ec6cb
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vm-memory"
|
name = "vm-memory"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "339d4349c126fdcd87e034631d7274370cf19eb0e87b33166bcd956589fc72c5"
|
checksum = "767ed8aaebbff902e02e6d3749dc2baef55e46565f8a6414a065e5baee4b4a81"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -919,7 +873,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"versionize",
|
"versionize",
|
||||||
@@ -951,21 +904,18 @@ dependencies = [
|
|||||||
"devices",
|
"devices",
|
||||||
"epoll",
|
"epoll",
|
||||||
"event_monitor",
|
"event_monitor",
|
||||||
"gdbstub",
|
|
||||||
"gdbstub_arch",
|
|
||||||
"hypervisor",
|
"hypervisor",
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
"libc",
|
||||||
"linux-loader",
|
"linux-loader",
|
||||||
"log",
|
"log",
|
||||||
"micro_http",
|
"micro_http",
|
||||||
"net_util",
|
"net_util",
|
||||||
|
"once_cell",
|
||||||
"option_parser",
|
"option_parser",
|
||||||
"pci",
|
"pci",
|
||||||
"qcow",
|
"qcow",
|
||||||
"seccompiler",
|
"seccompiler",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -999,9 +949,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.10.2+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
|
|||||||
@@ -10,16 +10,16 @@ cargo-fuzz = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
block_util = { path = "../block_util" }
|
block_util = { path = "../block_util" }
|
||||||
libc = "0.2.123"
|
libc = "0.2.126"
|
||||||
libfuzzer-sys = "0.4.3"
|
libfuzzer-sys = "0.4.3"
|
||||||
qcow = { path = "../qcow" }
|
qcow = { path = "../qcow" }
|
||||||
seccompiler = "0.2.0"
|
seccompiler = "0.2.0"
|
||||||
vhdx = { path = "../vhdx" }
|
vhdx = { path = "../vhdx" }
|
||||||
virtio-devices = { path = "../virtio-devices" }
|
virtio-devices = { path = "../virtio-devices" }
|
||||||
virtio-queue = "0.2.0"
|
virtio-queue = "0.4.0"
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vm-memory = "0.7.0"
|
vm-memory = "0.8.0"
|
||||||
|
|
||||||
[dependencies.cloud-hypervisor]
|
[dependencies.cloud-hypervisor]
|
||||||
path = ".."
|
path = ".."
|
||||||
|
|||||||
@@ -11,19 +11,18 @@ mshv = ["mshv-ioctls", "mshv-bindings"]
|
|||||||
tdx = []
|
tdx = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.56"
|
anyhow = "1.0.58"
|
||||||
epoll = "4.3.1"
|
epoll = "4.3.1"
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.31"
|
||||||
libc = "0.2.123"
|
libc = "0.2.126"
|
||||||
log = "0.4.16"
|
log = "0.4.17"
|
||||||
kvm-ioctls = { version = "0.11.0", optional = true }
|
kvm-ioctls = { version = "0.11.0", optional = true }
|
||||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
|
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||||
mshv-bindings = {git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
mshv-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}
|
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
||||||
serde = { version = "1.0.136", features = ["rc"] }
|
serde = { version = "1.0.138", features = ["rc", "derive"] }
|
||||||
serde_derive = "1.0.136"
|
serde_json = "1.0.82"
|
||||||
serde_json = "1.0.79"
|
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic"] }
|
||||||
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic"] }
|
|
||||||
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
||||||
|
|||||||
59
hypervisor/src/arch/aarch64/gic.rs
Normal file
59
hypervisor/src/arch/aarch64/gic.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
||||||
|
|
||||||
|
use crate::{CpuState, Device, GicState, HypervisorDeviceError, HypervisorVmError};
|
||||||
|
use std::any::Any;
|
||||||
|
use std::result;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// Errors thrown while setting up the VGIC.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Error while calling KVM ioctl for setting up the global interrupt controller.
|
||||||
|
CreateGic(HypervisorVmError),
|
||||||
|
/// Error while setting device attributes for the GIC.
|
||||||
|
SetDeviceAttribute(HypervisorDeviceError),
|
||||||
|
/// Error while getting device attributes for the GIC.
|
||||||
|
GetDeviceAttribute(HypervisorDeviceError),
|
||||||
|
}
|
||||||
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
|
/// Hypervisor agnostic interface for a virtualized GIC
|
||||||
|
pub trait Vgic: Send + Sync {
|
||||||
|
/// Returns the fdt compatibility property of the device
|
||||||
|
fn fdt_compatibility(&self) -> &str;
|
||||||
|
|
||||||
|
/// Returns the maint_irq fdt property of the device
|
||||||
|
fn fdt_maint_irq(&self) -> u32;
|
||||||
|
|
||||||
|
/// Returns an array with GIC device properties
|
||||||
|
fn device_properties(&self) -> [u64; 4];
|
||||||
|
|
||||||
|
/// Returns the number of vCPUs this GIC handles
|
||||||
|
fn vcpu_count(&self) -> u64;
|
||||||
|
|
||||||
|
/// Returns whether the GIC device is MSI compatible or not
|
||||||
|
fn msi_compatible(&self) -> bool;
|
||||||
|
|
||||||
|
/// Returns the MSI compatibility property of the device
|
||||||
|
fn msi_compatibility(&self) -> &str;
|
||||||
|
|
||||||
|
/// Returns the MSI reg property of the device
|
||||||
|
fn msi_properties(&self) -> [u64; 2];
|
||||||
|
|
||||||
|
fn set_its_device(&mut self, its_device: Option<Arc<dyn Device>>);
|
||||||
|
|
||||||
|
/// Get the values of GICR_TYPER for each vCPU.
|
||||||
|
fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]);
|
||||||
|
|
||||||
|
/// Downcast the trait object to its concrete type.
|
||||||
|
fn as_any_concrete_mut(&mut self) -> &mut dyn Any;
|
||||||
|
|
||||||
|
/// Save the state of GICv3ITS.
|
||||||
|
fn state(&self) -> Result<GicState>;
|
||||||
|
|
||||||
|
/// Restore the state of GICv3ITS.
|
||||||
|
fn set_state(&mut self, state: &GicState) -> Result<()>;
|
||||||
|
|
||||||
|
/// Saves GIC internal data tables into RAM.
|
||||||
|
fn save_data_tables(&self) -> Result<()>;
|
||||||
|
}
|
||||||
3
hypervisor/src/arch/aarch64/mod.rs
Normal file
3
hypervisor/src/arch/aarch64/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
||||||
|
|
||||||
|
pub mod gic;
|
||||||
@@ -99,7 +99,7 @@ pub enum EmulationError<T: Debug> {
|
|||||||
/// A CpuState is an architecture specific type, representing a CPU state.
|
/// A CpuState is an architecture specific type, representing a CPU state.
|
||||||
/// The emulator and its instruction handlers modify a given CPU state and
|
/// The emulator and its instruction handlers modify a given CPU state and
|
||||||
/// eventually ask the platform to commit it back through `set_cpu_state`.
|
/// eventually ask the platform to commit it back through `set_cpu_state`.
|
||||||
pub trait PlatformEmulator: Send + Sync {
|
pub trait PlatformEmulator {
|
||||||
type CpuState: Clone;
|
type CpuState: Clone;
|
||||||
|
|
||||||
/// Read guest memory into a u8 slice.
|
/// Read guest memory into a u8 slice.
|
||||||
|
|||||||
@@ -10,9 +10,14 @@
|
|||||||
//
|
//
|
||||||
// Copyright © 2020, Microsoft Corporation
|
// Copyright © 2020, Microsoft Corporation
|
||||||
//
|
//
|
||||||
|
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
pub mod emulator;
|
pub mod emulator;
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod x86;
|
pub mod x86;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
pub mod aarch64;
|
||||||
|
|||||||
@@ -28,14 +28,11 @@ fn get_op<T: CpuStateManager>(
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
match op_size {
|
if !matches!(op_size, 1 | 2 | 4 | 8) {
|
||||||
1 | 2 | 4 | 8 => {}
|
return Err(PlatformError::InvalidOperand(anyhow!(
|
||||||
_ => {
|
"Invalid operand size {:?}",
|
||||||
return Err(PlatformError::InvalidOperand(anyhow!(
|
op_size
|
||||||
"Invalid operand size {:?}",
|
)));
|
||||||
op_size
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = match insn
|
let value = match insn
|
||||||
@@ -81,14 +78,11 @@ fn set_op<T: CpuStateManager>(
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
match op_size {
|
if !matches!(op_size, 1 | 2 | 4 | 8) {
|
||||||
1 | 2 | 4 | 8 => {}
|
return Err(PlatformError::InvalidOperand(anyhow!(
|
||||||
_ => {
|
"Invalid operand size {:?}",
|
||||||
return Err(PlatformError::InvalidOperand(anyhow!(
|
op_size
|
||||||
"Invalid operand size {:?}",
|
)));
|
||||||
op_size
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match insn
|
match insn
|
||||||
|
|||||||
@@ -6,9 +6,8 @@
|
|||||||
|
|
||||||
use crate::arch::emulator::{EmulationError, EmulationResult, PlatformEmulator, PlatformError};
|
use crate::arch::emulator::{EmulationError, EmulationResult, PlatformEmulator, PlatformError};
|
||||||
use crate::arch::x86::emulator::instructions::*;
|
use crate::arch::x86::emulator::instructions::*;
|
||||||
use crate::arch::x86::regs::*;
|
use crate::arch::x86::regs::{CR0_PE, EFER_LMA};
|
||||||
use crate::arch::x86::*;
|
use crate::arch::x86::{segment_type_expand_down, segment_type_ro, Exception, SegmentRegisterOps};
|
||||||
use crate::arch::x86::{Exception, SegmentRegisterOps};
|
|
||||||
use crate::x86_64::{SegmentRegister, SpecialRegisters, StandardRegisters};
|
use crate::x86_64::{SegmentRegister, SpecialRegisters, StandardRegisters};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use iced_x86::*;
|
use iced_x86::*;
|
||||||
@@ -17,7 +16,7 @@ use iced_x86::*;
|
|||||||
mod instructions;
|
mod instructions;
|
||||||
|
|
||||||
/// x86 CPU modes
|
/// x86 CPU modes
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum CpuMode {
|
pub enum CpuMode {
|
||||||
/// Real mode
|
/// Real mode
|
||||||
Real,
|
Real,
|
||||||
|
|||||||
@@ -12,6 +12,12 @@
|
|||||||
use crate::aarch64::VcpuInit;
|
use crate::aarch64::VcpuInit;
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
use crate::aarch64::{RegList, Register, StandardRegisters};
|
use crate::aarch64::{RegList, Register, StandardRegisters};
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
use crate::kvm::{TdxExitDetails, TdxExitStatus};
|
||||||
|
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
||||||
|
use crate::x86_64::SuspendRegisters;
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
use crate::x86_64::Xsave;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use crate::x86_64::{CpuId, LapicState};
|
use crate::x86_64::{CpuId, LapicState};
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
@@ -23,12 +29,6 @@ use crate::CpuState;
|
|||||||
use crate::DeviceAttr;
|
use crate::DeviceAttr;
|
||||||
#[cfg(feature = "kvm")]
|
#[cfg(feature = "kvm")]
|
||||||
use crate::MpState;
|
use crate::MpState;
|
||||||
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
|
||||||
use crate::SuspendRegisters;
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
use crate::Xsave;
|
|
||||||
#[cfg(feature = "tdx")]
|
|
||||||
use crate::{TdxExitDetails, TdxExitStatus};
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||||
use vm_memory::GuestAddress;
|
use vm_memory::GuestAddress;
|
||||||
@@ -453,6 +453,11 @@ pub trait Vcpu: Send + Sync {
|
|||||||
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
||||||
fn read_mpidr(&self) -> Result<u64>;
|
fn read_mpidr(&self) -> Result<u64>;
|
||||||
///
|
///
|
||||||
|
/// Configure core registers for a given CPU.
|
||||||
|
///
|
||||||
|
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
||||||
|
fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> Result<()>;
|
||||||
|
///
|
||||||
/// Retrieve the vCPU state.
|
/// Retrieve the vCPU state.
|
||||||
/// This function is necessary to snapshot the VM
|
/// This function is necessary to snapshot the VM
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -7,13 +7,13 @@
|
|||||||
// Copyright 2018-2019 CrowdStrike, Inc.
|
// Copyright 2018-2019 CrowdStrike, Inc.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
use crate::kvm::TdxCapabilities;
|
||||||
use crate::vm::Vm;
|
use crate::vm::Vm;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use crate::x86_64::CpuId;
|
use crate::x86_64::CpuId;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use crate::x86_64::MsrList;
|
use crate::x86_64::MsrList;
|
||||||
#[cfg(feature = "tdx")]
|
|
||||||
use crate::TdxCapabilities;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@@ -66,6 +66,11 @@ pub enum HypervisorError {
|
|||||||
///
|
///
|
||||||
#[error("Failed to retrieve TDX capabilities:{0}")]
|
#[error("Failed to retrieve TDX capabilities:{0}")]
|
||||||
TdxCapabilities(#[source] anyhow::Error),
|
TdxCapabilities(#[source] anyhow::Error),
|
||||||
|
///
|
||||||
|
/// Failed to set partition property
|
||||||
|
///
|
||||||
|
#[error("Failed to set partition property:{0}")]
|
||||||
|
SetPartitionProperty(#[source] anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use super::{Error, Result};
|
use crate::arch::aarch64::gic::{Error, Result};
|
||||||
use crate::layout::IRQ_BASE;
|
use crate::kvm::kvm_bindings::{
|
||||||
use hypervisor::kvm::kvm_bindings::{
|
|
||||||
kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
|
kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
|
||||||
};
|
};
|
||||||
|
use crate::Device;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -77,12 +77,7 @@ static VGIC_DIST_REGS: &[DistReg] = &[
|
|||||||
VGIC_DIST_REG!(GICD_IPRIORITYR, 8, 0),
|
VGIC_DIST_REG!(GICD_IPRIORITYR, 8, 0),
|
||||||
];
|
];
|
||||||
|
|
||||||
fn dist_attr_access(
|
fn dist_attr_access(gic: &Arc<dyn Device>, offset: u32, val: &u32, set: bool) -> Result<()> {
|
||||||
gic: &Arc<dyn hypervisor::Device>,
|
|
||||||
offset: u32,
|
|
||||||
val: &u32,
|
|
||||||
set: bool,
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut gic_dist_attr = kvm_device_attr {
|
let mut gic_dist_attr = kvm_device_attr {
|
||||||
group: KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
|
group: KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
|
||||||
attr: offset as u64,
|
attr: offset as u64,
|
||||||
@@ -100,18 +95,18 @@ fn dist_attr_access(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the distributor control register.
|
/// Get the distributor control register.
|
||||||
pub fn read_ctlr(gic: &Arc<dyn hypervisor::Device>) -> Result<u32> {
|
pub fn read_ctlr(gic: &Arc<dyn Device>) -> Result<u32> {
|
||||||
let val: u32 = 0;
|
let val: u32 = 0;
|
||||||
dist_attr_access(gic, GICD_CTLR, &val, false)?;
|
dist_attr_access(gic, GICD_CTLR, &val, false)?;
|
||||||
Ok(val)
|
Ok(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the distributor control register.
|
/// Set the distributor control register.
|
||||||
pub fn write_ctlr(gic: &Arc<dyn hypervisor::Device>, val: u32) -> Result<()> {
|
pub fn write_ctlr(gic: &Arc<dyn Device>, val: u32) -> Result<()> {
|
||||||
dist_attr_access(gic, GICD_CTLR, &val, true)
|
dist_attr_access(gic, GICD_CTLR, &val, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_interrupts_num(gic: &Arc<dyn hypervisor::Device>) -> Result<u32> {
|
fn get_interrupts_num(gic: &Arc<dyn Device>) -> Result<u32> {
|
||||||
let num_irq = 0;
|
let num_irq = 0;
|
||||||
|
|
||||||
let mut nr_irqs_attr = kvm_device_attr {
|
let mut nr_irqs_attr = kvm_device_attr {
|
||||||
@@ -125,7 +120,12 @@ fn get_interrupts_num(gic: &Arc<dyn hypervisor::Device>) -> Result<u32> {
|
|||||||
Ok(num_irq)
|
Ok(num_irq)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_reg_len(gic: &Arc<dyn hypervisor::Device>, reg: &DistReg, base: u32) -> Result<u32> {
|
fn compute_reg_len(gic: &Arc<dyn Device>, reg: &DistReg, base: u32) -> Result<u32> {
|
||||||
|
// FIXME:
|
||||||
|
// Redefine some GIC constants to avoid the dependency on `layout` crate.
|
||||||
|
// This is temporary solution, will be fixed in future refactoring.
|
||||||
|
const LAYOUT_IRQ_BASE: u32 = 32;
|
||||||
|
|
||||||
let mut end = base;
|
let mut end = base;
|
||||||
let num_irq = get_interrupts_num(gic)?;
|
let num_irq = get_interrupts_num(gic)?;
|
||||||
if reg.length > 0 {
|
if reg.length > 0 {
|
||||||
@@ -138,8 +138,8 @@ fn compute_reg_len(gic: &Arc<dyn hypervisor::Device>, reg: &DistReg, base: u32)
|
|||||||
// This is the type of register that takes into account the number of interrupts
|
// This is the type of register that takes into account the number of interrupts
|
||||||
// that the model has. It is also the type of register where
|
// that the model has. It is also the type of register where
|
||||||
// a register relates to multiple interrupts.
|
// a register relates to multiple interrupts.
|
||||||
end = base + (reg.bpi as u32 * (num_irq - IRQ_BASE) / 8);
|
end = base + (reg.bpi as u32 * (num_irq - LAYOUT_IRQ_BASE) / 8);
|
||||||
if reg.bpi as u32 * (num_irq - IRQ_BASE) % 8 > 0 {
|
if reg.bpi as u32 * (num_irq - LAYOUT_IRQ_BASE) % 8 > 0 {
|
||||||
end += REG_SIZE as u32;
|
end += REG_SIZE as u32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,7 +147,7 @@ fn compute_reg_len(gic: &Arc<dyn hypervisor::Device>, reg: &DistReg, base: u32)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set distributor registers of the GIC.
|
/// Set distributor registers of the GIC.
|
||||||
pub fn set_dist_regs(gic: &Arc<dyn hypervisor::Device>, state: &[u32]) -> Result<()> {
|
pub fn set_dist_regs(gic: &Arc<dyn Device>, state: &[u32]) -> Result<()> {
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
|
|
||||||
for dreg in VGIC_DIST_REGS {
|
for dreg in VGIC_DIST_REGS {
|
||||||
@@ -164,7 +164,7 @@ pub fn set_dist_regs(gic: &Arc<dyn hypervisor::Device>, state: &[u32]) -> Result
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
/// Get distributor registers of the GIC.
|
/// Get distributor registers of the GIC.
|
||||||
pub fn get_dist_regs(gic: &Arc<dyn hypervisor::Device>) -> Result<Vec<u32>> {
|
pub fn get_dist_regs(gic: &Arc<dyn Device>) -> Result<Vec<u32>> {
|
||||||
let mut state = Vec::new();
|
let mut state = Vec::new();
|
||||||
|
|
||||||
for dreg in VGIC_DIST_REGS {
|
for dreg in VGIC_DIST_REGS {
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
|
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
||||||
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use super::{Error, Result};
|
use crate::arch::aarch64::gic::{Error, Result};
|
||||||
use hypervisor::kvm::kvm_bindings::{
|
use crate::kvm::kvm_bindings::{
|
||||||
kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, KVM_REG_ARM64_SYSREG_CRM_MASK,
|
kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, KVM_REG_ARM64_SYSREG_CRM_MASK,
|
||||||
KVM_REG_ARM64_SYSREG_CRM_SHIFT, KVM_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_CRN_SHIFT,
|
KVM_REG_ARM64_SYSREG_CRM_SHIFT, KVM_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_CRN_SHIFT,
|
||||||
KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_SHIFT, KVM_REG_ARM64_SYSREG_OP1_MASK,
|
KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_SHIFT, KVM_REG_ARM64_SYSREG_OP1_MASK,
|
||||||
KVM_REG_ARM64_SYSREG_OP1_SHIFT, KVM_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM64_SYSREG_OP2_SHIFT,
|
KVM_REG_ARM64_SYSREG_OP1_SHIFT, KVM_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM64_SYSREG_OP2_SHIFT,
|
||||||
};
|
};
|
||||||
|
use crate::Device;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
const KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT: u32 = 32;
|
const KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT: u32 = 32;
|
||||||
@@ -78,7 +80,7 @@ static VGIC_ICC_REGS: &[u64] = &[
|
|||||||
];
|
];
|
||||||
|
|
||||||
fn icc_attr_access(
|
fn icc_attr_access(
|
||||||
gic: &Arc<dyn hypervisor::Device>,
|
gic: &Arc<dyn Device>,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
typer: u64,
|
typer: u64,
|
||||||
val: &u32,
|
val: &u32,
|
||||||
@@ -101,7 +103,7 @@ fn icc_attr_access(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get ICC registers.
|
/// Get ICC registers.
|
||||||
pub fn get_icc_regs(gic: &Arc<dyn hypervisor::Device>, gicr_typer: &[u64]) -> Result<Vec<u32>> {
|
pub fn get_icc_regs(gic: &Arc<dyn Device>, gicr_typer: &[u64]) -> Result<Vec<u32>> {
|
||||||
let mut state: Vec<u32> = Vec::new();
|
let mut state: Vec<u32> = Vec::new();
|
||||||
// We need this for the ICC_AP<m>R<n>_EL1 registers.
|
// We need this for the ICC_AP<m>R<n>_EL1 registers.
|
||||||
let mut num_priority_bits = 0;
|
let mut num_priority_bits = 0;
|
||||||
@@ -154,11 +156,7 @@ pub fn get_icc_regs(gic: &Arc<dyn hypervisor::Device>, gicr_typer: &[u64]) -> Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set ICC registers.
|
/// Set ICC registers.
|
||||||
pub fn set_icc_regs(
|
pub fn set_icc_regs(gic: &Arc<dyn Device>, gicr_typer: &[u64], state: &[u32]) -> Result<()> {
|
||||||
gic: &Arc<dyn hypervisor::Device>,
|
|
||||||
gicr_typer: &[u64],
|
|
||||||
state: &[u32],
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut num_priority_bits = 0;
|
let mut num_priority_bits = 0;
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
for ix in gicr_typer {
|
for ix in gicr_typer {
|
||||||
615
hypervisor/src/kvm/aarch64/gic/mod.rs
Normal file
615
hypervisor/src/kvm/aarch64/gic/mod.rs
Normal file
@@ -0,0 +1,615 @@
|
|||||||
|
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
||||||
|
|
||||||
|
mod dist_regs;
|
||||||
|
mod icc_regs;
|
||||||
|
mod redist_regs;
|
||||||
|
|
||||||
|
use crate::arch::aarch64::gic::{Error, Result, Vgic};
|
||||||
|
use crate::kvm::kvm_bindings;
|
||||||
|
use crate::{CpuState, Device, Vm};
|
||||||
|
use dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
||||||
|
use icc_regs::{get_icc_regs, set_icc_regs};
|
||||||
|
use redist_regs::{construct_gicr_typers, get_redist_regs, set_redist_regs};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::any::Any;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
const GITS_CTLR: u32 = 0x0000;
|
||||||
|
const GITS_IIDR: u32 = 0x0004;
|
||||||
|
const GITS_CBASER: u32 = 0x0080;
|
||||||
|
const GITS_CWRITER: u32 = 0x0088;
|
||||||
|
const GITS_CREADR: u32 = 0x0090;
|
||||||
|
const GITS_BASER: u32 = 0x0100;
|
||||||
|
|
||||||
|
/// Access an ITS device attribute.
|
||||||
|
///
|
||||||
|
/// This is a helper function to get/set the ITS device attribute depending
|
||||||
|
/// the bool parameter `set` provided.
|
||||||
|
pub fn gicv3_its_attr_access(
|
||||||
|
its_device: &Arc<dyn Device>,
|
||||||
|
group: u32,
|
||||||
|
attr: u32,
|
||||||
|
val: &u64,
|
||||||
|
set: bool,
|
||||||
|
) -> Result<()> {
|
||||||
|
let mut gicv3_its_attr = kvm_bindings::kvm_device_attr {
|
||||||
|
group,
|
||||||
|
attr: attr as u64,
|
||||||
|
addr: val as *const u64 as u64,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
if set {
|
||||||
|
its_device
|
||||||
|
.set_device_attr(&gicv3_its_attr)
|
||||||
|
.map_err(Error::SetDeviceAttribute)
|
||||||
|
} else {
|
||||||
|
its_device
|
||||||
|
.get_device_attr(&mut gicv3_its_attr)
|
||||||
|
.map_err(Error::GetDeviceAttribute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Function that saves/restores ITS tables into guest RAM.
|
||||||
|
///
|
||||||
|
/// The tables get flushed to guest RAM whenever the VM gets stopped.
|
||||||
|
pub fn gicv3_its_tables_access(its_device: &Arc<dyn Device>, save: bool) -> Result<()> {
|
||||||
|
let attr = if save {
|
||||||
|
u64::from(kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES)
|
||||||
|
} else {
|
||||||
|
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,
|
||||||
|
attr,
|
||||||
|
addr: 0,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
its_device
|
||||||
|
.set_device_attr(&init_gic_attr)
|
||||||
|
.map_err(Error::SetDeviceAttribute)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct KvmGicV3Its {
|
||||||
|
/// The hypervisor agnostic device for the GicV3
|
||||||
|
device: Arc<dyn Device>,
|
||||||
|
|
||||||
|
/// The hypervisor agnostic device for the Its device
|
||||||
|
its_device: Option<Arc<dyn Device>>,
|
||||||
|
|
||||||
|
/// Vector holding values of GICR_TYPER for each vCPU
|
||||||
|
gicr_typers: Vec<u64>,
|
||||||
|
|
||||||
|
/// GIC distributor address
|
||||||
|
dist_addr: u64,
|
||||||
|
|
||||||
|
/// GIC distributor size
|
||||||
|
dist_size: u64,
|
||||||
|
|
||||||
|
/// GIC distributors address
|
||||||
|
redists_addr: u64,
|
||||||
|
|
||||||
|
/// GIC distributors size
|
||||||
|
redists_size: u64,
|
||||||
|
|
||||||
|
/// GIC MSI address
|
||||||
|
msi_addr: u64,
|
||||||
|
|
||||||
|
/// GIC MSI size
|
||||||
|
msi_size: u64,
|
||||||
|
|
||||||
|
/// Number of CPUs handled by the device
|
||||||
|
vcpu_count: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default, Serialize, Deserialize)]
|
||||||
|
pub struct Gicv3ItsState {
|
||||||
|
dist: Vec<u32>,
|
||||||
|
rdist: Vec<u32>,
|
||||||
|
icc: Vec<u32>,
|
||||||
|
// special register that enables interrupts and affinity routing
|
||||||
|
gicd_ctlr: u32,
|
||||||
|
its_ctlr: u64,
|
||||||
|
its_iidr: u64,
|
||||||
|
its_cbaser: u64,
|
||||||
|
its_cwriter: u64,
|
||||||
|
its_creadr: u64,
|
||||||
|
its_baser: [u64; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KvmGicV3Its {
|
||||||
|
/// Device trees specific constants
|
||||||
|
pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9;
|
||||||
|
|
||||||
|
/// Returns the GIC version of the device
|
||||||
|
fn version() -> u32 {
|
||||||
|
kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device(&self) -> &Arc<dyn Device> {
|
||||||
|
&self.device
|
||||||
|
}
|
||||||
|
|
||||||
|
fn its_device(&self) -> Option<&Arc<dyn Device>> {
|
||||||
|
self.its_device.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Setup the device-specific attributes
|
||||||
|
fn init_device_attributes(&mut self, vm: &dyn Vm, nr_irqs: u32) -> Result<()> {
|
||||||
|
// GicV3 part attributes
|
||||||
|
/* Setting up the distributor attribute.
|
||||||
|
We are placing the GIC below 1GB so we need to substract the size of the distributor.
|
||||||
|
*/
|
||||||
|
Self::set_device_attribute(
|
||||||
|
self.device(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||||
|
u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_DIST),
|
||||||
|
&self.dist_addr as *const u64 as u64,
|
||||||
|
0,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
/* Setting up the redistributors' attribute.
|
||||||
|
We are calculating here the start of the redistributors address. We have one per CPU.
|
||||||
|
*/
|
||||||
|
Self::set_device_attribute(
|
||||||
|
self.device(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||||
|
u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_REDIST),
|
||||||
|
&self.redists_addr as *const u64 as u64,
|
||||||
|
0,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// ITS part attributes
|
||||||
|
let mut its_device = kvm_bindings::kvm_create_device {
|
||||||
|
type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS,
|
||||||
|
fd: 0,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let its_fd = vm
|
||||||
|
.create_device(&mut its_device)
|
||||||
|
.map_err(Error::CreateGic)?;
|
||||||
|
|
||||||
|
Self::set_device_attribute(
|
||||||
|
&its_fd,
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||||
|
u64::from(kvm_bindings::KVM_VGIC_ITS_ADDR_TYPE),
|
||||||
|
&self.msi_addr as *const u64 as u64,
|
||||||
|
0,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Self::set_device_attribute(
|
||||||
|
&its_fd,
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
|
||||||
|
u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.set_its_device(Some(its_fd));
|
||||||
|
|
||||||
|
/* We need to tell the kernel how many irqs to support with this vgic.
|
||||||
|
* See the `layout` module for details.
|
||||||
|
*/
|
||||||
|
let nr_irqs_ptr = &nr_irqs as *const u32;
|
||||||
|
Self::set_device_attribute(
|
||||||
|
self.device(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
|
||||||
|
0,
|
||||||
|
nr_irqs_ptr as u64,
|
||||||
|
0,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
/* Finalize the GIC.
|
||||||
|
* See https://code.woboq.org/linux/linux/virt/kvm/arm/vgic/vgic-kvm-device.c.html#211.
|
||||||
|
*/
|
||||||
|
Self::set_device_attribute(
|
||||||
|
self.device(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
|
||||||
|
u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a KVM Vgic device
|
||||||
|
fn create_device(vm: &dyn Vm) -> Result<Arc<dyn Device>> {
|
||||||
|
let mut gic_device = kvm_bindings::kvm_create_device {
|
||||||
|
type_: Self::version(),
|
||||||
|
fd: 0,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.create_device(&mut gic_device).map_err(Error::CreateGic)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a GIC device attribute
|
||||||
|
fn set_device_attribute(
|
||||||
|
device: &Arc<dyn Device>,
|
||||||
|
group: u32,
|
||||||
|
attr: u64,
|
||||||
|
addr: u64,
|
||||||
|
flags: u32,
|
||||||
|
) -> Result<()> {
|
||||||
|
let attr = kvm_bindings::kvm_device_attr {
|
||||||
|
flags,
|
||||||
|
group,
|
||||||
|
attr,
|
||||||
|
addr,
|
||||||
|
};
|
||||||
|
device
|
||||||
|
.set_device_attr(&attr)
|
||||||
|
.map_err(Error::SetDeviceAttribute)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Method to initialize the GIC device
|
||||||
|
#[allow(clippy::new_ret_no_self)]
|
||||||
|
pub fn new(
|
||||||
|
vm: &dyn Vm,
|
||||||
|
vcpu_count: u64,
|
||||||
|
dist_addr: u64,
|
||||||
|
dist_size: u64,
|
||||||
|
redist_size: u64,
|
||||||
|
msi_size: u64,
|
||||||
|
nr_irqs: u32,
|
||||||
|
) -> Result<KvmGicV3Its> {
|
||||||
|
let vgic = Self::create_device(vm)?;
|
||||||
|
let redists_size: u64 = redist_size * vcpu_count;
|
||||||
|
let redists_addr: u64 = dist_addr - redists_size;
|
||||||
|
let msi_addr: u64 = redists_addr - msi_size;
|
||||||
|
|
||||||
|
let mut gic_device = KvmGicV3Its {
|
||||||
|
device: vgic,
|
||||||
|
its_device: None,
|
||||||
|
gicr_typers: vec![0; vcpu_count.try_into().unwrap()],
|
||||||
|
dist_addr,
|
||||||
|
dist_size,
|
||||||
|
redists_addr,
|
||||||
|
redists_size,
|
||||||
|
msi_addr,
|
||||||
|
msi_size,
|
||||||
|
vcpu_count,
|
||||||
|
};
|
||||||
|
|
||||||
|
gic_device.init_device_attributes(vm, nr_irqs)?;
|
||||||
|
|
||||||
|
Ok(gic_device)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vgic for KvmGicV3Its {
|
||||||
|
fn fdt_compatibility(&self) -> &str {
|
||||||
|
"arm,gic-v3"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn msi_compatible(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn msi_compatibility(&self) -> &str {
|
||||||
|
"arm,gic-v3-its"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fdt_maint_irq(&self) -> u32 {
|
||||||
|
KvmGicV3Its::ARCH_GIC_V3_MAINT_IRQ
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vcpu_count(&self) -> u64 {
|
||||||
|
self.vcpu_count
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_properties(&self) -> [u64; 4] {
|
||||||
|
[
|
||||||
|
self.dist_addr,
|
||||||
|
self.dist_size,
|
||||||
|
self.redists_addr,
|
||||||
|
self.redists_size,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn msi_properties(&self) -> [u64; 2] {
|
||||||
|
[self.msi_addr, self.msi_size]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_its_device(&mut self, its_device: Option<Arc<dyn Device>>) {
|
||||||
|
self.its_device = its_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
|
||||||
|
let gicr_typers = construct_gicr_typers(vcpu_states);
|
||||||
|
self.gicr_typers = gicr_typers;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_concrete_mut(&mut self) -> &mut dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Save the state of GICv3ITS.
|
||||||
|
fn state(&self) -> Result<Gicv3ItsState> {
|
||||||
|
let gicr_typers = self.gicr_typers.clone();
|
||||||
|
|
||||||
|
let gicd_ctlr = read_ctlr(self.device())?;
|
||||||
|
|
||||||
|
let dist_state = get_dist_regs(self.device())?;
|
||||||
|
|
||||||
|
let rdist_state = get_redist_regs(self.device(), &gicr_typers)?;
|
||||||
|
|
||||||
|
let icc_state = get_icc_regs(self.device(), &gicr_typers)?;
|
||||||
|
|
||||||
|
let its_baser_state: [u64; 8] = [0; 8];
|
||||||
|
for i in 0..8 {
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_BASER + i * 8,
|
||||||
|
&its_baser_state[i as usize],
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let its_ctlr_state: u64 = 0;
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CTLR,
|
||||||
|
&its_ctlr_state,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let its_cbaser_state: u64 = 0;
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CBASER,
|
||||||
|
&its_cbaser_state,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let its_creadr_state: u64 = 0;
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CREADR,
|
||||||
|
&its_creadr_state,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let its_cwriter_state: u64 = 0;
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CWRITER,
|
||||||
|
&its_cwriter_state,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let its_iidr_state: u64 = 0;
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_IIDR,
|
||||||
|
&its_iidr_state,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(Gicv3ItsState {
|
||||||
|
dist: dist_state,
|
||||||
|
rdist: rdist_state,
|
||||||
|
icc: icc_state,
|
||||||
|
gicd_ctlr,
|
||||||
|
its_ctlr: its_ctlr_state,
|
||||||
|
its_iidr: its_iidr_state,
|
||||||
|
its_cbaser: its_cbaser_state,
|
||||||
|
its_cwriter: its_cwriter_state,
|
||||||
|
its_creadr: its_creadr_state,
|
||||||
|
its_baser: its_baser_state,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Restore the state of GICv3ITS.
|
||||||
|
fn set_state(&mut self, state: &Gicv3ItsState) -> Result<()> {
|
||||||
|
let gicr_typers = self.gicr_typers.clone();
|
||||||
|
|
||||||
|
write_ctlr(self.device(), state.gicd_ctlr)?;
|
||||||
|
|
||||||
|
set_dist_regs(self.device(), &state.dist)?;
|
||||||
|
|
||||||
|
set_redist_regs(self.device(), &gicr_typers, &state.rdist)?;
|
||||||
|
|
||||||
|
set_icc_regs(self.device(), &gicr_typers, &state.icc)?;
|
||||||
|
|
||||||
|
//Restore GICv3ITS registers
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_IIDR,
|
||||||
|
&state.its_iidr,
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CBASER,
|
||||||
|
&state.its_cbaser,
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CREADR,
|
||||||
|
&state.its_creadr,
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CWRITER,
|
||||||
|
&state.its_cwriter,
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
for i in 0..8 {
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_BASER + i * 8,
|
||||||
|
&state.its_baser[i as usize],
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore ITS tables
|
||||||
|
gicv3_its_tables_access(self.its_device().unwrap(), false)?;
|
||||||
|
|
||||||
|
gicv3_its_attr_access(
|
||||||
|
self.its_device().unwrap(),
|
||||||
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||||
|
GITS_CTLR,
|
||||||
|
&state.its_ctlr,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Saves GIC internal data tables into RAM, including:
|
||||||
|
/// - RDIST pending tables
|
||||||
|
/// - ITS tables into guest RAM.
|
||||||
|
fn save_data_tables(&self) -> Result<()> {
|
||||||
|
// Flash RDIST pending tables
|
||||||
|
let init_gic_attr = kvm_bindings::kvm_device_attr {
|
||||||
|
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
|
||||||
|
attr: u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES),
|
||||||
|
addr: 0,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
self.device()
|
||||||
|
.set_device_attr(&init_gic_attr)
|
||||||
|
.map_err(Error::SetDeviceAttribute)?;
|
||||||
|
// Flush ITS tables to guest RAM.
|
||||||
|
gicv3_its_tables_access(self.its_device().unwrap(), true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::aarch64::gic::{
|
||||||
|
get_dist_regs, get_icc_regs, get_redist_regs, set_dist_regs, set_icc_regs, set_redist_regs,
|
||||||
|
};
|
||||||
|
use crate::kvm::KvmGicV3Its;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_create_gic() {
|
||||||
|
let hv = crate::new().unwrap();
|
||||||
|
let vm = hv.create_vm().unwrap();
|
||||||
|
|
||||||
|
assert!(KvmGicV3Its::new(
|
||||||
|
&*vm,
|
||||||
|
1,
|
||||||
|
0x0900_0000 - 0x01_0000,
|
||||||
|
0x01_0000,
|
||||||
|
0x02_0000,
|
||||||
|
0x02_0000,
|
||||||
|
256
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_set_dist_regs() {
|
||||||
|
let hv = crate::new().unwrap();
|
||||||
|
let vm = hv.create_vm().unwrap();
|
||||||
|
let _ = vm.create_vcpu(0, None).unwrap();
|
||||||
|
let gic = KvmGicV3Its::new(
|
||||||
|
&*vm,
|
||||||
|
1,
|
||||||
|
0x0900_0000 - 0x01_0000,
|
||||||
|
0x01_0000,
|
||||||
|
0x02_0000,
|
||||||
|
0x02_0000,
|
||||||
|
256,
|
||||||
|
)
|
||||||
|
.expect("Cannot create gic");
|
||||||
|
|
||||||
|
let res = get_dist_regs(gic.device());
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let state = res.unwrap();
|
||||||
|
assert_eq!(state.len(), 568);
|
||||||
|
|
||||||
|
let res = set_dist_regs(gic.device(), &state);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_set_redist_regs() {
|
||||||
|
let hv = crate::new().unwrap();
|
||||||
|
let vm = hv.create_vm().unwrap();
|
||||||
|
let _ = vm.create_vcpu(0, None).unwrap();
|
||||||
|
let gic = KvmGicV3Its::new(
|
||||||
|
&*vm,
|
||||||
|
1,
|
||||||
|
0x0900_0000 - 0x01_0000,
|
||||||
|
0x01_0000,
|
||||||
|
0x02_0000,
|
||||||
|
0x02_0000,
|
||||||
|
256,
|
||||||
|
)
|
||||||
|
.expect("Cannot create gic");
|
||||||
|
|
||||||
|
let gicr_typer = vec![123];
|
||||||
|
let res = get_redist_regs(gic.device(), &gicr_typer);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let state = res.unwrap();
|
||||||
|
println!("{}", state.len());
|
||||||
|
assert!(state.len() == 24);
|
||||||
|
|
||||||
|
assert!(set_redist_regs(gic.device(), &gicr_typer, &state).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_set_icc_regs() {
|
||||||
|
let hv = crate::new().unwrap();
|
||||||
|
let vm = hv.create_vm().unwrap();
|
||||||
|
let _ = vm.create_vcpu(0, None).unwrap();
|
||||||
|
let gic = KvmGicV3Its::new(
|
||||||
|
&*vm,
|
||||||
|
1,
|
||||||
|
0x0900_0000 - 0x01_0000,
|
||||||
|
0x01_0000,
|
||||||
|
0x02_0000,
|
||||||
|
0x02_0000,
|
||||||
|
256,
|
||||||
|
)
|
||||||
|
.expect("Cannot create gic");
|
||||||
|
|
||||||
|
let gicr_typer = vec![123];
|
||||||
|
let res = get_icc_regs(gic.device(), &gicr_typer);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let state = res.unwrap();
|
||||||
|
println!("{}", state.len());
|
||||||
|
assert!(state.len() == 9);
|
||||||
|
|
||||||
|
assert!(set_icc_regs(gic.device(), &gicr_typer, &state).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_save_data_tables() {
|
||||||
|
let hv = crate::new().unwrap();
|
||||||
|
let vm = hv.create_vm().unwrap();
|
||||||
|
let _ = vm.create_vcpu(0, None).unwrap();
|
||||||
|
let gic = vm
|
||||||
|
.create_vgic(
|
||||||
|
1,
|
||||||
|
0x0900_0000 - 0x01_0000,
|
||||||
|
0x01_0000,
|
||||||
|
0x02_0000,
|
||||||
|
0x02_0000,
|
||||||
|
256,
|
||||||
|
)
|
||||||
|
.expect("Cannot create gic");
|
||||||
|
|
||||||
|
assert!(gic.lock().unwrap().save_data_tables().is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
|
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
||||||
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use super::{Error, Result};
|
use crate::arch::aarch64::gic::{Error, Result};
|
||||||
use hypervisor::kvm::kvm_bindings::{kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS};
|
use crate::kvm::kvm_bindings::{kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS};
|
||||||
use hypervisor::CpuState;
|
use crate::{CpuState, Device};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
// Relevant redistributor registers that we want to save/restore.
|
// Relevant redistributor registers that we want to save/restore.
|
||||||
@@ -83,7 +84,7 @@ static VGIC_SGI_REGS: &[RdistReg] = &[
|
|||||||
];
|
];
|
||||||
|
|
||||||
fn redist_attr_access(
|
fn redist_attr_access(
|
||||||
gic: &Arc<dyn hypervisor::Device>,
|
gic: &Arc<dyn Device>,
|
||||||
offset: u32,
|
offset: u32,
|
||||||
typer: u64,
|
typer: u64,
|
||||||
val: &u32,
|
val: &u32,
|
||||||
@@ -106,7 +107,7 @@ fn redist_attr_access(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn access_redists_aux(
|
fn access_redists_aux(
|
||||||
gic: &Arc<dyn hypervisor::Device>,
|
gic: &Arc<dyn Device>,
|
||||||
gicr_typer: &[u64],
|
gicr_typer: &[u64],
|
||||||
state: &mut Vec<u32>,
|
state: &mut Vec<u32>,
|
||||||
reg_list: &[RdistReg],
|
reg_list: &[RdistReg],
|
||||||
@@ -136,7 +137,7 @@ fn access_redists_aux(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get redistributor registers.
|
/// Get redistributor registers.
|
||||||
pub fn get_redist_regs(gic: &Arc<dyn hypervisor::Device>, gicr_typer: &[u64]) -> Result<Vec<u32>> {
|
pub fn get_redist_regs(gic: &Arc<dyn Device>, gicr_typer: &[u64]) -> Result<Vec<u32>> {
|
||||||
let mut state = Vec::new();
|
let mut state = Vec::new();
|
||||||
let mut idx: usize = 0;
|
let mut idx: usize = 0;
|
||||||
access_redists_aux(
|
access_redists_aux(
|
||||||
@@ -153,11 +154,7 @@ pub fn get_redist_regs(gic: &Arc<dyn hypervisor::Device>, gicr_typer: &[u64]) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set redistributor registers.
|
/// Set redistributor registers.
|
||||||
pub fn set_redist_regs(
|
pub fn set_redist_regs(gic: &Arc<dyn Device>, gicr_typer: &[u64], state: &[u32]) -> Result<()> {
|
||||||
gic: &Arc<dyn hypervisor::Device>,
|
|
||||||
gicr_typer: &[u64],
|
|
||||||
state: &[u32],
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut idx: usize = 0;
|
let mut idx: usize = 0;
|
||||||
let mut mut_state = state.to_owned();
|
let mut mut_state = state.to_owned();
|
||||||
access_redists_aux(
|
access_redists_aux(
|
||||||
@@ -8,9 +8,8 @@
|
|||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
||||||
///
|
pub mod gic;
|
||||||
/// Export generically-named wrappers of kvm-bindings for Unix-based platforms
|
|
||||||
///
|
|
||||||
use crate::kvm::{KvmError, KvmResult};
|
use crate::kvm::{KvmError, KvmResult};
|
||||||
use kvm_bindings::{
|
use kvm_bindings::{
|
||||||
kvm_mp_state, kvm_one_reg, kvm_regs, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG,
|
kvm_mp_state, kvm_one_reg, kvm_regs, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG,
|
||||||
@@ -23,7 +22,7 @@ use kvm_bindings::{
|
|||||||
pub use kvm_bindings::{
|
pub use kvm_bindings::{
|
||||||
kvm_one_reg as Register, kvm_regs as StandardRegisters, kvm_vcpu_init as VcpuInit, RegList,
|
kvm_one_reg as Register, kvm_regs as StandardRegisters, kvm_vcpu_init as VcpuInit, RegList,
|
||||||
};
|
};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
pub use {kvm_ioctls::Cap, kvm_ioctls::Kvm};
|
pub use {kvm_ioctls::Cap, kvm_ioctls::Kvm};
|
||||||
|
|
||||||
// This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having
|
// This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having
|
||||||
|
|||||||
@@ -8,20 +8,24 @@
|
|||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
use crate::aarch64::gic::KvmGicV3Its;
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
pub use crate::aarch64::{
|
pub use crate::aarch64::{
|
||||||
check_required_kvm_extensions, is_system_register, VcpuInit, VcpuKvmState as CpuState,
|
check_required_kvm_extensions, gic::Gicv3ItsState as GicState, is_system_register, VcpuInit,
|
||||||
MPIDR_EL1,
|
VcpuKvmState as CpuState, MPIDR_EL1,
|
||||||
};
|
};
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
use crate::arch::aarch64::gic::Vgic;
|
||||||
use crate::cpu;
|
use crate::cpu;
|
||||||
use crate::device;
|
use crate::device;
|
||||||
use crate::hypervisor;
|
use crate::hypervisor;
|
||||||
use crate::vec_with_array_field;
|
use crate::vec_with_array_field;
|
||||||
use crate::vm::{self, VmmOps};
|
use crate::vm::{self, InterruptSourceConfig, VmOps};
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
use crate::{arm64_core_reg_id, offset__of};
|
use crate::{arm64_core_reg_id, offset__of};
|
||||||
use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd};
|
use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
@@ -31,6 +35,8 @@ use std::os::unix::io::{AsRawFd, RawFd};
|
|||||||
use std::result;
|
use std::result;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
use std::sync::Mutex;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
// x86_64 dependencies
|
// x86_64 dependencies
|
||||||
@@ -154,7 +160,7 @@ pub struct TdxCapabilities {
|
|||||||
pub cpuid_configs: [TdxCpuidConfig; TDX_MAX_NR_CPUID_CONFIGS],
|
pub cpuid_configs: [TdxCpuidConfig; TDX_MAX_NR_CPUID_CONFIGS],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
pub struct KvmVmState {}
|
pub struct KvmVmState {}
|
||||||
|
|
||||||
pub use KvmVmState as VmState;
|
pub use KvmVmState as VmState;
|
||||||
@@ -234,7 +240,7 @@ impl vm::Vm for KvmVm {
|
|||||||
fn create_vcpu(
|
fn create_vcpu(
|
||||||
&self,
|
&self,
|
||||||
id: u8,
|
id: u8,
|
||||||
vmmops: Option<Arc<dyn VmmOps>>,
|
vm_ops: Option<Arc<dyn VmOps>>,
|
||||||
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
|
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
|
||||||
let vc = self
|
let vc = self
|
||||||
.fd
|
.fd
|
||||||
@@ -244,12 +250,37 @@ impl vm::Vm for KvmVm {
|
|||||||
fd: vc,
|
fd: vc,
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
msrs: self.msrs.clone(),
|
msrs: self.msrs.clone(),
|
||||||
vmmops,
|
vm_ops,
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
hyperv_synic: AtomicBool::new(false),
|
hyperv_synic: AtomicBool::new(false),
|
||||||
};
|
};
|
||||||
Ok(Arc::new(vcpu))
|
Ok(Arc::new(vcpu))
|
||||||
}
|
}
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
///
|
||||||
|
/// Creates a virtual GIC device.
|
||||||
|
///
|
||||||
|
fn create_vgic(
|
||||||
|
&self,
|
||||||
|
vcpu_count: u64,
|
||||||
|
dist_addr: u64,
|
||||||
|
dist_size: u64,
|
||||||
|
redist_size: u64,
|
||||||
|
msi_size: u64,
|
||||||
|
nr_irqs: u32,
|
||||||
|
) -> vm::Result<Arc<Mutex<dyn Vgic>>> {
|
||||||
|
let gic_device = KvmGicV3Its::new(
|
||||||
|
self,
|
||||||
|
vcpu_count,
|
||||||
|
dist_addr,
|
||||||
|
dist_size,
|
||||||
|
redist_size,
|
||||||
|
msi_size,
|
||||||
|
nr_irqs,
|
||||||
|
)
|
||||||
|
.map_err(|e| vm::HypervisorVmError::CreateVgic(anyhow!("Vgic error {:?}", e)))?;
|
||||||
|
Ok(Arc::new(Mutex::new(gic_device)))
|
||||||
|
}
|
||||||
///
|
///
|
||||||
/// Registers an event to be signaled whenever a certain address is written to.
|
/// Registers an event to be signaled whenever a certain address is written to.
|
||||||
///
|
///
|
||||||
@@ -284,6 +315,64 @@ impl vm::Vm for KvmVm {
|
|||||||
.unregister_ioevent(fd, addr, NoDatamatch)
|
.unregister_ioevent(fd, addr, NoDatamatch)
|
||||||
.map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into()))
|
.map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Constructs a routing entry
|
||||||
|
///
|
||||||
|
fn make_routing_entry(
|
||||||
|
&self,
|
||||||
|
gsi: u32,
|
||||||
|
config: &InterruptSourceConfig,
|
||||||
|
) -> kvm_irq_routing_entry {
|
||||||
|
match &config {
|
||||||
|
InterruptSourceConfig::MsiIrq(cfg) => {
|
||||||
|
let mut kvm_route = kvm_irq_routing_entry {
|
||||||
|
gsi,
|
||||||
|
type_: KVM_IRQ_ROUTING_MSI,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
kvm_route.u.msi.address_lo = cfg.low_addr;
|
||||||
|
kvm_route.u.msi.address_hi = cfg.high_addr;
|
||||||
|
kvm_route.u.msi.data = cfg.data;
|
||||||
|
|
||||||
|
if self.check_extension(crate::kvm::Cap::MsiDevid) {
|
||||||
|
// On AArch64, there is limitation on the range of the 'devid',
|
||||||
|
// it can not be greater than 65536 (the max of u16).
|
||||||
|
//
|
||||||
|
// BDF can not be used directly, because 'segment' is in high
|
||||||
|
// 16 bits. The layout of the u32 BDF is:
|
||||||
|
// |---- 16 bits ----|-- 8 bits --|-- 5 bits --|-- 3 bits --|
|
||||||
|
// | segment | bus | device | function |
|
||||||
|
//
|
||||||
|
// Now that we support 1 bus only in a segment, we can build a
|
||||||
|
// 'devid' by replacing the 'bus' bits with the low 8 bits of
|
||||||
|
// 'segment' data.
|
||||||
|
// This way we can resolve the range checking problem and give
|
||||||
|
// different `devid` to all the devices. Limitation is that at
|
||||||
|
// most 256 segments can be supported.
|
||||||
|
//
|
||||||
|
let modified_devid = (cfg.devid & 0x00ff_0000) >> 8 | cfg.devid & 0xff;
|
||||||
|
|
||||||
|
kvm_route.flags = KVM_MSI_VALID_DEVID;
|
||||||
|
kvm_route.u.msi.__bindgen_anon_1.devid = modified_devid;
|
||||||
|
}
|
||||||
|
kvm_route
|
||||||
|
}
|
||||||
|
InterruptSourceConfig::LegacyIrq(cfg) => {
|
||||||
|
let mut kvm_route = kvm_irq_routing_entry {
|
||||||
|
gsi,
|
||||||
|
type_: KVM_IRQ_ROUTING_IRQCHIP,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
kvm_route.u.irqchip.irqchip = cfg.irqchip;
|
||||||
|
kvm_route.u.irqchip.pin = cfg.pin;
|
||||||
|
|
||||||
|
kvm_route
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Sets the GSI routing table entries, overwriting any previously set
|
/// Sets the GSI routing table entries, overwriting any previously set
|
||||||
/// entries, as per the `KVM_SET_GSI_ROUTING` ioctl.
|
/// entries, as per the `KVM_SET_GSI_ROUTING` ioctl.
|
||||||
@@ -816,7 +905,7 @@ pub struct KvmVcpu {
|
|||||||
fd: VcpuFd,
|
fd: VcpuFd,
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
msrs: MsrEntries,
|
msrs: MsrEntries,
|
||||||
vmmops: Option<Arc<dyn vm::VmmOps>>,
|
vm_ops: Option<Arc<dyn vm::VmOps>>,
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
hyperv_synic: AtomicBool,
|
hyperv_synic: AtomicBool,
|
||||||
}
|
}
|
||||||
@@ -1056,8 +1145,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
Ok(run) => match run {
|
Ok(run) => match run {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
VcpuExit::IoIn(addr, data) => {
|
VcpuExit::IoIn(addr, data) => {
|
||||||
if let Some(vmmops) = &self.vmmops {
|
if let Some(vm_ops) = &self.vm_ops {
|
||||||
return vmmops
|
return vm_ops
|
||||||
.pio_read(addr.into(), data)
|
.pio_read(addr.into(), data)
|
||||||
.map(|_| cpu::VmExit::Ignore)
|
.map(|_| cpu::VmExit::Ignore)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
||||||
@@ -1067,8 +1156,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
}
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
VcpuExit::IoOut(addr, data) => {
|
VcpuExit::IoOut(addr, data) => {
|
||||||
if let Some(vmmops) = &self.vmmops {
|
if let Some(vm_ops) = &self.vm_ops {
|
||||||
return vmmops
|
return vm_ops
|
||||||
.pio_write(addr.into(), data)
|
.pio_write(addr.into(), data)
|
||||||
.map(|_| cpu::VmExit::Ignore)
|
.map(|_| cpu::VmExit::Ignore)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
||||||
@@ -1100,8 +1189,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VcpuExit::MmioRead(addr, data) => {
|
VcpuExit::MmioRead(addr, data) => {
|
||||||
if let Some(vmmops) = &self.vmmops {
|
if let Some(vm_ops) = &self.vm_ops {
|
||||||
return vmmops
|
return vm_ops
|
||||||
.mmio_read(addr, data)
|
.mmio_read(addr, data)
|
||||||
.map(|_| cpu::VmExit::Ignore)
|
.map(|_| cpu::VmExit::Ignore)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
||||||
@@ -1110,8 +1199,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
Ok(cpu::VmExit::MmioRead(addr, data))
|
Ok(cpu::VmExit::MmioRead(addr, data))
|
||||||
}
|
}
|
||||||
VcpuExit::MmioWrite(addr, data) => {
|
VcpuExit::MmioWrite(addr, data) => {
|
||||||
if let Some(vmmops) = &self.vmmops {
|
if let Some(vm_ops) = &self.vm_ops {
|
||||||
return vmmops
|
return vm_ops
|
||||||
.mmio_write(addr, data)
|
.mmio_write(addr, data)
|
||||||
.map(|_| cpu::VmExit::Ignore)
|
.map(|_| cpu::VmExit::Ignore)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
||||||
@@ -1477,6 +1566,51 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
.get_one_reg(MPIDR_EL1)
|
.get_one_reg(MPIDR_EL1)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))
|
||||||
}
|
}
|
||||||
|
///
|
||||||
|
/// Configure core registers for a given CPU.
|
||||||
|
///
|
||||||
|
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
||||||
|
fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> cpu::Result<()> {
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
// PSR (Processor State Register) bits.
|
||||||
|
// Taken from arch/arm64/include/uapi/asm/ptrace.h.
|
||||||
|
const PSR_MODE_EL1h: u64 = 0x0000_0005;
|
||||||
|
const PSR_F_BIT: u64 = 0x0000_0040;
|
||||||
|
const PSR_I_BIT: u64 = 0x0000_0080;
|
||||||
|
const PSR_A_BIT: u64 = 0x0000_0100;
|
||||||
|
const PSR_D_BIT: u64 = 0x0000_0200;
|
||||||
|
// Taken from arch/arm64/kvm/inject_fault.c.
|
||||||
|
const PSTATE_FAULT_BITS_64: u64 =
|
||||||
|
PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT;
|
||||||
|
|
||||||
|
let kreg_off = offset__of!(kvm_regs, regs);
|
||||||
|
|
||||||
|
// Get the register index of the PSTATE (Processor State) register.
|
||||||
|
let pstate = offset__of!(user_pt_regs, pstate) + kreg_off;
|
||||||
|
self.set_reg(
|
||||||
|
arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate),
|
||||||
|
PSTATE_FAULT_BITS_64,
|
||||||
|
)
|
||||||
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
|
|
||||||
|
// Other vCPUs are powered off initially awaiting PSCI wakeup.
|
||||||
|
if cpu_id == 0 {
|
||||||
|
// Setting the PC (Processor Counter) to the current program address (kernel address).
|
||||||
|
let pc = offset__of!(user_pt_regs, pc) + kreg_off;
|
||||||
|
self.set_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), boot_ip as u64)
|
||||||
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
|
|
||||||
|
// Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
|
||||||
|
// "The device tree blob (dtb) must be placed on an 8-byte boundary and must
|
||||||
|
// not exceed 2 megabytes in size." -> https://www.kernel.org/doc/Documentation/arm64/booting.txt.
|
||||||
|
// We are choosing to place it the end of DRAM. See `get_fdt_addr`.
|
||||||
|
let regs0 = offset__of!(user_pt_regs, regs) + kreg_off;
|
||||||
|
self.set_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0), fdt_start)
|
||||||
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// Get the current CPU state
|
/// Get the current CPU state
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB};
|
use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB};
|
||||||
use crate::kvm::{Cap, Kvm, KvmError, KvmResult};
|
use crate::kvm::{Cap, Kvm, KvmError, KvmResult};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Export generically-named wrappers of kvm-bindings for Unix-based platforms
|
/// Export generically-named wrappers of kvm-bindings for Unix-based platforms
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
//! - arm64
|
//! - arm64
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
#![allow(clippy::significant_drop_in_scrutinee)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate anyhow;
|
extern crate anyhow;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
@@ -37,10 +39,10 @@ pub mod kvm;
|
|||||||
pub mod mshv;
|
pub mod mshv;
|
||||||
|
|
||||||
/// Hypevisor related module
|
/// Hypevisor related module
|
||||||
pub mod hypervisor;
|
mod hypervisor;
|
||||||
|
|
||||||
/// Vm related module
|
/// Vm related module
|
||||||
pub mod vm;
|
mod vm;
|
||||||
|
|
||||||
/// CPU related module
|
/// CPU related module
|
||||||
mod cpu;
|
mod cpu;
|
||||||
@@ -48,18 +50,32 @@ mod cpu;
|
|||||||
/// Device related module
|
/// Device related module
|
||||||
mod device;
|
mod device;
|
||||||
|
|
||||||
pub use crate::hypervisor::{Hypervisor, HypervisorError};
|
|
||||||
pub use cpu::{HypervisorCpuError, Vcpu, VmExit};
|
pub use cpu::{HypervisorCpuError, Vcpu, VmExit};
|
||||||
pub use device::{Device, HypervisorDeviceError};
|
pub use device::{Device, HypervisorDeviceError};
|
||||||
#[cfg(feature = "tdx")]
|
pub use hypervisor::{Hypervisor, HypervisorError};
|
||||||
pub use kvm::TdxCapabilities;
|
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||||
|
pub use kvm::x86_64;
|
||||||
|
#[cfg(all(feature = "kvm", target_arch = "aarch64"))]
|
||||||
|
pub use kvm::{aarch64, GicState};
|
||||||
|
// Aliased types exposed from both hypervisors
|
||||||
#[cfg(feature = "kvm")]
|
#[cfg(feature = "kvm")]
|
||||||
pub use kvm::*;
|
pub use kvm::{
|
||||||
|
ClockData, CpuState, CreateDevice, DeviceAttr, DeviceFd, IoEventAddress, IrqRoutingEntry,
|
||||||
|
MemoryRegion, MpState, VcpuEvents, VcpuExit, VmState,
|
||||||
|
};
|
||||||
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
||||||
pub use mshv::*;
|
pub use mshv::x86_64;
|
||||||
pub use vm::{DataMatch, HypervisorVmError, Vm};
|
// Aliased types exposed from both hypervisors
|
||||||
|
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
||||||
|
pub use mshv::{
|
||||||
|
CpuState, CreateDevice, DeviceAttr, DeviceFd, IoEventAddress, IrqRoutingEntry, MemoryRegion,
|
||||||
|
MpState, VcpuEvents, VcpuExit, VmState,
|
||||||
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
pub use vm::{
|
||||||
|
DataMatch, HypervisorVmError, InterruptSourceConfig, LegacyIrqSourceConfig, MsiIrqSourceConfig,
|
||||||
|
Vm, VmOps,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn new() -> std::result::Result<Arc<dyn Hypervisor>, HypervisorError> {
|
pub fn new() -> std::result::Result<Arc<dyn Hypervisor>, HypervisorError> {
|
||||||
#[cfg(feature = "kvm")]
|
#[cfg(feature = "kvm")]
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ use crate::cpu;
|
|||||||
use crate::cpu::Vcpu;
|
use crate::cpu::Vcpu;
|
||||||
use crate::hypervisor;
|
use crate::hypervisor;
|
||||||
use crate::vec_with_array_field;
|
use crate::vec_with_array_field;
|
||||||
use crate::vm::{self, VmmOps};
|
use crate::vm::{self, InterruptSourceConfig, VmOps};
|
||||||
pub use mshv_bindings::*;
|
pub use mshv_bindings::*;
|
||||||
pub use mshv_ioctls::IoEventAddress;
|
pub use mshv_ioctls::IoEventAddress;
|
||||||
use mshv_ioctls::{set_registers_64, Mshv, NoDatamatch, VcpuFd, VmFd};
|
use mshv_ioctls::{set_registers_64, Mshv, NoDatamatch, VcpuFd, VmFd};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use vm::DataMatch;
|
use vm::DataMatch;
|
||||||
@@ -108,6 +108,17 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default Microsoft Hypervisor behavior for unimplemented MSR is to
|
||||||
|
// send a fault to the guest if it tries to access it. It is possible
|
||||||
|
// to override this behavior with a more suitable option i.e., ignore
|
||||||
|
// writes from the guest and return zero in attempt to read unimplemented
|
||||||
|
// MSR.
|
||||||
|
fd.set_partition_property(
|
||||||
|
hv_partition_property_code_HV_PARTITION_PROPERTY_UNIMPLEMENTED_MSR_ACTION,
|
||||||
|
hv_unimplemented_msr_action_HV_UNIMPLEMENTED_MSR_ACTION_IGNORE_WRITE_READ_ZERO as u64,
|
||||||
|
)
|
||||||
|
.map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?;
|
||||||
|
|
||||||
let msr_list = self.get_msr_list()?;
|
let msr_list = self.get_msr_list()?;
|
||||||
let num_msrs = msr_list.as_fam_struct_ref().nmsrs as usize;
|
let num_msrs = msr_list.as_fam_struct_ref().nmsrs as usize;
|
||||||
let mut msrs = MsrEntries::new(num_msrs).unwrap();
|
let mut msrs = MsrEntries::new(num_msrs).unwrap();
|
||||||
@@ -122,7 +133,7 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
|||||||
fd: vm_fd,
|
fd: vm_fd,
|
||||||
msrs,
|
msrs,
|
||||||
hv_state: hv_state_init(),
|
hv_state: hv_state_init(),
|
||||||
vmmops: None,
|
vm_ops: None,
|
||||||
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
|
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -151,7 +162,7 @@ pub struct MshvVcpu {
|
|||||||
cpuid: CpuId,
|
cpuid: CpuId,
|
||||||
msrs: MsrEntries,
|
msrs: MsrEntries,
|
||||||
hv_state: Arc<RwLock<HvState>>, // Mshv State
|
hv_state: Arc<RwLock<HvState>>, // Mshv State
|
||||||
vmmops: Option<Arc<dyn vm::VmmOps>>,
|
vm_ops: Option<Arc<dyn vm::VmOps>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of Vcpu trait for Microsoft Hypervisor
|
/// Implementation of Vcpu trait for Microsoft Hypervisor
|
||||||
@@ -355,14 +366,14 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
|
|
||||||
if is_write {
|
if is_write {
|
||||||
let data = (info.rax as u32).to_le_bytes();
|
let data = (info.rax as u32).to_le_bytes();
|
||||||
if let Some(vmmops) = &self.vmmops {
|
if let Some(vm_ops) = &self.vm_ops {
|
||||||
vmmops
|
vm_ops
|
||||||
.pio_write(port.into(), &data[0..len])
|
.pio_write(port.into(), &data[0..len])
|
||||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Some(vmmops) = &self.vmmops {
|
if let Some(vm_ops) = &self.vm_ops {
|
||||||
vmmops
|
vm_ops
|
||||||
.pio_read(port.into(), &mut data[0..len])
|
.pio_read(port.into(), &mut data[0..len])
|
||||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
|
||||||
}
|
}
|
||||||
@@ -655,9 +666,9 @@ impl<'a> PlatformEmulator for MshvEmulatorContext<'a> {
|
|||||||
gpa
|
gpa
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(vmmops) = &self.vcpu.vmmops {
|
if let Some(vm_ops) = &self.vcpu.vm_ops {
|
||||||
if vmmops.guest_mem_read(gpa, data).is_err() {
|
if vm_ops.guest_mem_read(gpa, data).is_err() {
|
||||||
vmmops
|
vm_ops
|
||||||
.mmio_read(gpa, data)
|
.mmio_read(gpa, data)
|
||||||
.map_err(|e| PlatformError::MemoryReadFailure(e.into()))?;
|
.map_err(|e| PlatformError::MemoryReadFailure(e.into()))?;
|
||||||
}
|
}
|
||||||
@@ -675,9 +686,9 @@ impl<'a> PlatformEmulator for MshvEmulatorContext<'a> {
|
|||||||
gpa
|
gpa
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(vmmops) = &self.vcpu.vmmops {
|
if let Some(vm_ops) = &self.vcpu.vm_ops {
|
||||||
if vmmops.guest_mem_write(gpa, data).is_err() {
|
if vm_ops.guest_mem_write(gpa, data).is_err() {
|
||||||
vmmops
|
vm_ops
|
||||||
.mmio_write(gpa, data)
|
.mmio_write(gpa, data)
|
||||||
.map_err(|e| PlatformError::MemoryWriteFailure(e.into()))?;
|
.map_err(|e| PlatformError::MemoryWriteFailure(e.into()))?;
|
||||||
}
|
}
|
||||||
@@ -746,7 +757,7 @@ pub struct MshvVm {
|
|||||||
msrs: MsrEntries,
|
msrs: MsrEntries,
|
||||||
// Hypervisor State
|
// Hypervisor State
|
||||||
hv_state: Arc<RwLock<HvState>>,
|
hv_state: Arc<RwLock<HvState>>,
|
||||||
vmmops: Option<Arc<dyn vm::VmmOps>>,
|
vm_ops: Option<Arc<dyn vm::VmOps>>,
|
||||||
dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>,
|
dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -816,7 +827,7 @@ impl vm::Vm for MshvVm {
|
|||||||
fn create_vcpu(
|
fn create_vcpu(
|
||||||
&self,
|
&self,
|
||||||
id: u8,
|
id: u8,
|
||||||
vmmops: Option<Arc<dyn VmmOps>>,
|
vm_ops: Option<Arc<dyn VmOps>>,
|
||||||
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
|
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
|
||||||
let vcpu_fd = self
|
let vcpu_fd = self
|
||||||
.fd
|
.fd
|
||||||
@@ -828,7 +839,7 @@ impl vm::Vm for MshvVm {
|
|||||||
cpuid: CpuId::new(1).unwrap(),
|
cpuid: CpuId::new(1).unwrap(),
|
||||||
msrs: self.msrs.clone(),
|
msrs: self.msrs.clone(),
|
||||||
hv_state: self.hv_state.clone(),
|
hv_state: self.hv_state.clone(),
|
||||||
vmmops,
|
vm_ops,
|
||||||
};
|
};
|
||||||
Ok(Arc::new(vcpu))
|
Ok(Arc::new(vcpu))
|
||||||
}
|
}
|
||||||
@@ -957,6 +968,27 @@ impl vm::Vm for MshvVm {
|
|||||||
.map_err(|e| vm::HypervisorVmError::CreatePassthroughDevice(e.into()))
|
.map_err(|e| vm::HypervisorVmError::CreatePassthroughDevice(e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Constructs a routing entry
|
||||||
|
///
|
||||||
|
fn make_routing_entry(
|
||||||
|
&self,
|
||||||
|
gsi: u32,
|
||||||
|
config: &InterruptSourceConfig,
|
||||||
|
) -> mshv_msi_routing_entry {
|
||||||
|
match config {
|
||||||
|
InterruptSourceConfig::MsiIrq(cfg) => mshv_msi_routing_entry {
|
||||||
|
gsi,
|
||||||
|
address_lo: cfg.low_addr,
|
||||||
|
address_hi: cfg.high_addr,
|
||||||
|
data: cfg.data,
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
|
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
|
||||||
let mut msi_routing =
|
let mut msi_routing =
|
||||||
vec_with_array_field::<mshv_msi_routing, mshv_msi_routing_entry>(entries.len());
|
vec_with_array_field::<mshv_msi_routing, mshv_msi_routing_entry>(entries.len());
|
||||||
@@ -1027,6 +1059,3 @@ impl vm::Vm for MshvVm {
|
|||||||
.map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into()))
|
.map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub use hv_cpuid_entry as CpuIdEntry;
|
|
||||||
|
|
||||||
pub const CPUID_FLAG_VALID_INDEX: u32 = 0;
|
|
||||||
|
|||||||
@@ -8,13 +8,14 @@
|
|||||||
//
|
//
|
||||||
//
|
//
|
||||||
use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB};
|
use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Export generically-named wrappers of mshv_bindings for Unix-based platforms
|
/// Export generically-named wrappers of mshv_bindings for Unix-based platforms
|
||||||
///
|
///
|
||||||
pub use {
|
pub use {
|
||||||
|
mshv_bindings::hv_cpuid_entry as CpuIdEntry,
|
||||||
mshv_bindings::mshv_user_mem_region as MemoryRegion, mshv_bindings::msr_entry as MsrEntry,
|
mshv_bindings::mshv_user_mem_region as MemoryRegion, mshv_bindings::msr_entry as MsrEntry,
|
||||||
mshv_bindings::CpuId, mshv_bindings::DebugRegisters,
|
mshv_bindings::CpuId, mshv_bindings::DebugRegisters,
|
||||||
mshv_bindings::FloatingPointUnit as FpuState, mshv_bindings::LapicState,
|
mshv_bindings::FloatingPointUnit as FpuState, mshv_bindings::LapicState,
|
||||||
@@ -25,6 +26,8 @@ pub use {
|
|||||||
mshv_bindings::Xcrs as ExtendedControlRegisters,
|
mshv_bindings::Xcrs as ExtendedControlRegisters,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const CPUID_FLAG_VALID_INDEX: u32 = 0;
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct VcpuMshvState {
|
pub struct VcpuMshvState {
|
||||||
pub msrs: MsrEntries,
|
pub msrs: MsrEntries,
|
||||||
|
|||||||
@@ -10,23 +10,27 @@
|
|||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
use crate::aarch64::VcpuInit;
|
use crate::aarch64::VcpuInit;
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
use crate::arch::aarch64::gic::Vgic;
|
||||||
use crate::cpu::Vcpu;
|
use crate::cpu::Vcpu;
|
||||||
use crate::device::Device;
|
use crate::device::Device;
|
||||||
|
#[cfg(feature = "kvm")]
|
||||||
|
use crate::kvm::KvmVmState as VmState;
|
||||||
|
#[cfg(feature = "mshv")]
|
||||||
|
use crate::mshv::HvState as VmState;
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
use crate::x86_64::CpuId;
|
use crate::x86_64::CpuId;
|
||||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||||
use crate::ClockData;
|
use crate::ClockData;
|
||||||
use crate::CreateDevice;
|
use crate::CreateDevice;
|
||||||
#[cfg(feature = "mshv")]
|
|
||||||
use crate::HvState as VmState;
|
|
||||||
#[cfg(feature = "kvm")]
|
|
||||||
use crate::KvmVmState as VmState;
|
|
||||||
use crate::{IoEventAddress, IrqRoutingEntry, MemoryRegion};
|
use crate::{IoEventAddress, IrqRoutingEntry, MemoryRegion};
|
||||||
#[cfg(feature = "kvm")]
|
#[cfg(feature = "kvm")]
|
||||||
use kvm_ioctls::Cap;
|
use kvm_ioctls::Cap;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
use std::sync::Mutex;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
@@ -210,12 +214,50 @@ pub enum HypervisorVmError {
|
|||||||
///
|
///
|
||||||
#[error("Failed to initialize memory region TDX: {0}")]
|
#[error("Failed to initialize memory region TDX: {0}")]
|
||||||
InitMemRegionTdx(#[source] std::io::Error),
|
InitMemRegionTdx(#[source] std::io::Error),
|
||||||
|
///
|
||||||
|
/// Create Vgic error
|
||||||
|
///
|
||||||
|
#[error("Failed to create Vgic: {0}")]
|
||||||
|
CreateVgic(#[source] anyhow::Error),
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
/// Result type for returning from a function
|
/// Result type for returning from a function
|
||||||
///
|
///
|
||||||
pub type Result<T> = std::result::Result<T, HypervisorVmError>;
|
pub type Result<T> = std::result::Result<T, HypervisorVmError>;
|
||||||
|
|
||||||
|
/// Configuration data for legacy interrupts.
|
||||||
|
///
|
||||||
|
/// On x86 platforms, legacy interrupts means those interrupts routed through PICs or IOAPICs.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct LegacyIrqSourceConfig {
|
||||||
|
pub irqchip: u32,
|
||||||
|
pub pin: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration data for MSI/MSI-X interrupts.
|
||||||
|
///
|
||||||
|
/// On x86 platforms, these interrupts are vectors delivered directly to the LAPIC.
|
||||||
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
|
pub struct MsiIrqSourceConfig {
|
||||||
|
/// High address to delivery message signaled interrupt.
|
||||||
|
pub high_addr: u32,
|
||||||
|
/// Low address to delivery message signaled interrupt.
|
||||||
|
pub low_addr: u32,
|
||||||
|
/// Data to write to delivery message signaled interrupt.
|
||||||
|
pub data: u32,
|
||||||
|
/// Unique ID of the device to delivery message signaled interrupt.
|
||||||
|
pub devid: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration data for an interrupt source.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum InterruptSourceConfig {
|
||||||
|
/// Configuration data for Legacy interrupts.
|
||||||
|
LegacyIrq(LegacyIrqSourceConfig),
|
||||||
|
/// Configuration data for PciMsi, PciMsix and generic MSI interrupts.
|
||||||
|
MsiIrq(MsiIrqSourceConfig),
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Trait to represent a Vm
|
/// Trait to represent a Vm
|
||||||
///
|
///
|
||||||
@@ -235,7 +277,18 @@ pub trait Vm: Send + Sync {
|
|||||||
/// Unregister an event that will, when signaled, trigger the `gsi` IRQ.
|
/// Unregister an event that will, when signaled, trigger the `gsi` IRQ.
|
||||||
fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()>;
|
fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()>;
|
||||||
/// Creates a new KVM vCPU file descriptor and maps the memory corresponding
|
/// Creates a new KVM vCPU file descriptor and maps the memory corresponding
|
||||||
fn create_vcpu(&self, id: u8, vmmops: Option<Arc<dyn VmmOps>>) -> Result<Arc<dyn Vcpu>>;
|
fn create_vcpu(&self, id: u8, vm_ops: Option<Arc<dyn VmOps>>) -> Result<Arc<dyn Vcpu>>;
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
fn create_vgic(
|
||||||
|
&self,
|
||||||
|
vcpu_count: u64,
|
||||||
|
dist_addr: u64,
|
||||||
|
dist_size: u64,
|
||||||
|
redist_size: u64,
|
||||||
|
msi_size: u64,
|
||||||
|
nr_irqs: u32,
|
||||||
|
) -> Result<Arc<Mutex<dyn Vgic>>>;
|
||||||
|
|
||||||
/// Registers an event to be signaled whenever a certain address is written to.
|
/// Registers an event to be signaled whenever a certain address is written to.
|
||||||
fn register_ioevent(
|
fn register_ioevent(
|
||||||
&self,
|
&self,
|
||||||
@@ -245,6 +298,8 @@ pub trait Vm: Send + Sync {
|
|||||||
) -> Result<()>;
|
) -> Result<()>;
|
||||||
/// Unregister an event from a certain address it has been previously registered to.
|
/// Unregister an event from a certain address it has been previously registered to.
|
||||||
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>;
|
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>;
|
||||||
|
// Construct a routing entry
|
||||||
|
fn make_routing_entry(&self, gsi: u32, config: &InterruptSourceConfig) -> IrqRoutingEntry;
|
||||||
/// Sets the GSI routing table entries, overwriting any previously set
|
/// Sets the GSI routing table entries, overwriting any previously set
|
||||||
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> Result<()>;
|
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> Result<()>;
|
||||||
/// Creates a memory region structure that can be used with {create/remove}_user_memory_region
|
/// Creates a memory region structure that can be used with {create/remove}_user_memory_region
|
||||||
@@ -309,7 +364,7 @@ pub trait Vm: Send + Sync {
|
|||||||
) -> Result<()>;
|
) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait VmmOps: Send + Sync {
|
pub trait VmOps: Send + Sync {
|
||||||
fn guest_mem_write(&self, gpa: u64, buf: &[u8]) -> Result<usize>;
|
fn guest_mem_write(&self, gpa: u64, buf: &[u8]) -> Result<usize>;
|
||||||
fn guest_mem_read(&self, gpa: u64, buf: &mut [u8]) -> Result<usize>;
|
fn guest_mem_read(&self, gpa: u64, buf: &mut [u8]) -> Result<usize>;
|
||||||
fn mmio_read(&self, gpa: u64, data: &mut [u8]) -> Result<()>;
|
fn mmio_read(&self, gpa: u64, data: &mut [u8]) -> Result<()>;
|
||||||
|
|||||||
@@ -7,20 +7,21 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
epoll = "4.3.1"
|
epoll = "4.3.1"
|
||||||
getrandom = "0.2"
|
getrandom = "0.2"
|
||||||
libc = "0.2.123"
|
libc = "0.2.126"
|
||||||
log = "0.4.16"
|
log = "0.4.17"
|
||||||
net_gen = { path = "../net_gen" }
|
net_gen = { path = "../net_gen" }
|
||||||
rate_limiter = { path = "../rate_limiter" }
|
rate_limiter = { path = "../rate_limiter" }
|
||||||
serde = "1.0.136"
|
serde = "1.0.138"
|
||||||
versionize = "0.1.6"
|
versionize = "0.1.6"
|
||||||
versionize_derive = "0.1.4"
|
versionize_derive = "0.1.4"
|
||||||
virtio-bindings = "0.1.0"
|
virtio-bindings = "0.1.0"
|
||||||
virtio-queue = "0.2.0"
|
virtio-queue = "0.4.0"
|
||||||
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
lazy_static = "1.4.0"
|
once_cell = "1.13.0"
|
||||||
pnet = "0.29.0"
|
pnet = "0.31.0"
|
||||||
serde_json = "1.0.79"
|
pnet_datalink = "0.31.0"
|
||||||
|
serde_json = "1.0.82"
|
||||||
|
|||||||
@@ -5,11 +5,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the THIRD-PARTY file.
|
// found in the THIRD-PARTY file.
|
||||||
|
|
||||||
// This is only used by the tests module from tap.rs, but we cannot use #[macro_use] unless the
|
|
||||||
// reference to lazy_static is declared at the root level of the importing crate.
|
|
||||||
#[cfg(test)]
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use serde::ser::{Serialize, Serializer};
|
|||||||
|
|
||||||
pub const MAC_ADDR_LEN: usize = 6;
|
pub const MAC_ADDR_LEN: usize = 6;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct MacAddr {
|
pub struct MacAddr {
|
||||||
bytes: [u8; MAC_ADDR_LEN],
|
bytes: [u8; MAC_ADDR_LEN],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -321,15 +321,13 @@ impl Tap {
|
|||||||
|
|
||||||
// If TAP device is already up don't try and enable it
|
// If TAP device is already up don't try and enable it
|
||||||
let ifru_flags = unsafe { ifreq.ifr_ifru.ifru_flags };
|
let ifru_flags = unsafe { ifreq.ifr_ifru.ifru_flags };
|
||||||
if ifru_flags
|
if ifru_flags & net_gen::net_device_flags_IFF_UP as i16
|
||||||
& (net_gen::net_device_flags_IFF_UP | net_gen::net_device_flags_IFF_RUNNING) as i16
|
== net_gen::net_device_flags_IFF_UP as i16
|
||||||
== (net_gen::net_device_flags_IFF_UP | net_gen::net_device_flags_IFF_RUNNING) as i16
|
|
||||||
{
|
{
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
ifreq.ifr_ifru.ifru_flags =
|
ifreq.ifr_ifru.ifru_flags = net_gen::net_device_flags_IFF_UP as i16;
|
||||||
(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.
|
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||||
let ret =
|
let ret =
|
||||||
@@ -395,38 +393,35 @@ impl AsRawFd for Tap {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
extern crate pnet;
|
|
||||||
|
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::sync::{mpsc, Mutex};
|
use std::sync::{mpsc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use self::pnet::datalink::Channel::Ethernet;
|
use once_cell::sync::Lazy;
|
||||||
use self::pnet::datalink::{self, DataLinkReceiver, DataLinkSender, NetworkInterface};
|
|
||||||
use self::pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket};
|
use pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket};
|
||||||
use self::pnet::packet::ip::IpNextHeaderProtocols;
|
use pnet::packet::ip::IpNextHeaderProtocols;
|
||||||
use self::pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet};
|
use pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet};
|
||||||
use self::pnet::packet::udp::{MutableUdpPacket, UdpPacket};
|
use pnet::packet::udp::{MutableUdpPacket, UdpPacket};
|
||||||
use self::pnet::packet::{MutablePacket, Packet};
|
use pnet::packet::{MutablePacket, Packet};
|
||||||
use self::pnet::util::MacAddr;
|
use pnet::util::MacAddr;
|
||||||
|
use pnet_datalink::Channel::Ethernet;
|
||||||
|
use pnet_datalink::{DataLinkReceiver, DataLinkSender, NetworkInterface};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
static DATA_STRING: &str = "test for tap";
|
static DATA_STRING: &str = "test for tap";
|
||||||
static SUBNET_MASK: &str = "255.255.255.0";
|
static SUBNET_MASK: &str = "255.255.255.0";
|
||||||
|
|
||||||
// We needed to have a mutex as a global variable, so we used the crate that provides the
|
// We needed to have a mutex as a global variable, so we used once_cell for testing. The main
|
||||||
// lazy_static! macro for testing. The main potential problem, caused by tests being run in
|
// potential problem, caused by tests being run in parallel by cargo, is creating different
|
||||||
// parallel by cargo, is creating different TAPs and trying to associate the same address,
|
// TAPs and trying to associate the same address, so we hide the IP address &str behind this
|
||||||
// so we hide the IP address &str behind this mutex, more as a convention to remember to lock
|
// mutex, more as a convention to remember to lock it at the very beginning of each function
|
||||||
// it at the very beginning of each function susceptible to this issue. Another variant is
|
// susceptible to this issue. Another variant is to use a different IP address per function,
|
||||||
// to use a different IP address per function, but we must remember to pick an unique one
|
// but we must remember to pick an unique one each time.
|
||||||
// each time.
|
static TAP_IP_LOCK: Lazy<Mutex<&'static str>> = Lazy::new(|| Mutex::new("192.168.241.1"));
|
||||||
lazy_static! {
|
|
||||||
static ref TAP_IP_LOCK: Mutex<&'static str> = Mutex::new("192.168.241.1");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Describes the outcomes we are currently interested in when parsing a packet (we use
|
// Describes the outcomes we are currently interested in when parsing a packet (we use
|
||||||
// an UDP packet for testing).
|
// an UDP packet for testing).
|
||||||
@@ -543,10 +538,10 @@ mod tests {
|
|||||||
let interface_name_matches = |iface: &NetworkInterface| iface.name == ifname;
|
let interface_name_matches = |iface: &NetworkInterface| iface.name == ifname;
|
||||||
|
|
||||||
// Find the network interface with the provided name.
|
// Find the network interface with the provided name.
|
||||||
let interfaces = datalink::interfaces();
|
let interfaces = pnet_datalink::interfaces();
|
||||||
let interface = interfaces.into_iter().find(interface_name_matches).unwrap();
|
let interface = interfaces.into_iter().find(interface_name_matches).unwrap();
|
||||||
|
|
||||||
if let Ok(Ethernet(tx, rx)) = datalink::channel(&interface, Default::default()) {
|
if let Ok(Ethernet(tx, rx)) = pnet_datalink::channel(&interface, Default::default()) {
|
||||||
(interface.mac.unwrap(), tx, rx)
|
(interface.mac.unwrap(), tx, rx)
|
||||||
} else {
|
} else {
|
||||||
panic!("datalink channel error or unhandled channel type");
|
panic!("datalink channel error or unhandled channel type");
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ impl OptionParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for option in split_commas_outside_brackets(input)?.iter() {
|
for option in split_commas_outside_brackets(input)?.iter() {
|
||||||
let parts: Vec<&str> = option.split('=').collect();
|
let parts: Vec<&str> = option.splitn(2, '=').collect();
|
||||||
|
|
||||||
match self.options.get_mut(parts[0]) {
|
match self.options.get_mut(parts[0]) {
|
||||||
None => return Err(OptionParserError::UnknownOption(parts[0].to_owned())),
|
None => return Err(OptionParserError::UnknownOption(parts[0].to_owned())),
|
||||||
|
|||||||
@@ -10,22 +10,21 @@ kvm = ["vfio-ioctls/kvm"]
|
|||||||
mshv = ["vfio-ioctls/mshv"]
|
mshv = ["vfio-ioctls/mshv"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.56"
|
anyhow = "1.0.58"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
hypervisor = { path = "../hypervisor" }
|
hypervisor = { path = "../hypervisor" }
|
||||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||||
vfio_user = { path = "../vfio_user" }
|
vfio_user = { path = "../vfio_user" }
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
libc = "0.2.123"
|
libc = "0.2.126"
|
||||||
log = "0.4.16"
|
log = "0.4.17"
|
||||||
serde = "1.0.136"
|
serde = { version="1.0.138", features=["derive"] }
|
||||||
serde_derive = "1.0.136"
|
thiserror = "1.0.31"
|
||||||
thiserror = "1.0.30"
|
|
||||||
versionize = "0.1.6"
|
versionize = "0.1.6"
|
||||||
versionize_derive = "0.1.4"
|
versionize_derive = "0.1.4"
|
||||||
vm-allocator = { path = "../vm-allocator" }
|
vm-allocator = { path = "../vm-allocator" }
|
||||||
vm-device = { path = "../vm-device" }
|
vm-device = { path = "../vm-device" }
|
||||||
vm-memory = "0.7.0"
|
vm-memory = "0.8.0"
|
||||||
vm-migration = { path = "../vm-migration" }
|
vm-migration = { path = "../vm-migration" }
|
||||||
|
|
||||||
[dependencies.vfio-bindings]
|
[dependencies.vfio-bindings]
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ use crate::configuration::{
|
|||||||
PciBarRegionType, PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType,
|
PciBarRegionType, PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType,
|
||||||
};
|
};
|
||||||
use crate::device::{DeviceRelocation, Error as PciDeviceError, PciDevice};
|
use crate::device::{DeviceRelocation, Error as PciDeviceError, PciDevice};
|
||||||
|
use crate::PciBarConfiguration;
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::sync::{Arc, Barrier, Mutex};
|
use std::sync::{Arc, Barrier, Mutex};
|
||||||
use vm_device::{Bus, BusDevice};
|
use vm_device::{Bus, BusDevice};
|
||||||
use vm_memory::{Address, GuestAddress, GuestUsize};
|
|
||||||
|
|
||||||
const VENDOR_ID_INTEL: u16 = 0x8086;
|
const VENDOR_ID_INTEL: u16 = 0x8086;
|
||||||
const DEVICE_ID_INTEL_VIRT_PCIE_HOST: u16 = 0x0d57;
|
const DEVICE_ID_INTEL_VIRT_PCIE_HOST: u16 = 0x0d57;
|
||||||
@@ -88,6 +88,10 @@ impl PciDevice for PciRoot {
|
|||||||
fn as_any(&mut self) -> &mut dyn Any {
|
fn as_any(&mut self) -> &mut dyn Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn id(&self) -> Option<String> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PciBus {
|
pub struct PciBus {
|
||||||
@@ -118,21 +122,21 @@ impl PciBus {
|
|||||||
dev: Arc<Mutex<dyn BusDevice>>,
|
dev: Arc<Mutex<dyn BusDevice>>,
|
||||||
#[cfg(target_arch = "x86_64")] io_bus: &Bus,
|
#[cfg(target_arch = "x86_64")] io_bus: &Bus,
|
||||||
mmio_bus: &Bus,
|
mmio_bus: &Bus,
|
||||||
bars: Vec<(GuestAddress, GuestUsize, PciBarRegionType)>,
|
bars: Vec<PciBarConfiguration>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for (address, size, type_) in bars {
|
for bar in bars {
|
||||||
match type_ {
|
match bar.region_type() {
|
||||||
PciBarRegionType::IoRegion => {
|
PciBarRegionType::IoRegion => {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
io_bus
|
io_bus
|
||||||
.insert(dev.clone(), address.raw_value(), size)
|
.insert(dev.clone(), bar.addr(), bar.size())
|
||||||
.map_err(PciRootError::PioInsert)?;
|
.map_err(PciRootError::PioInsert)?;
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
error!("I/O region is not supported");
|
error!("I/O region is not supported");
|
||||||
}
|
}
|
||||||
PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
|
PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
|
||||||
mmio_bus
|
mmio_bus
|
||||||
.insert(dev.clone(), address.raw_value(), size)
|
.insert(dev.clone(), bar.addr(), bar.size())
|
||||||
.map_err(PciRootError::MmioInsert)?;
|
.map_err(PciRootError::MmioInsert)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use std::fmt::{self, Display};
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
|
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
|
||||||
use versionize_derive::Versionize;
|
use versionize_derive::Versionize;
|
||||||
|
use vm_device::PciBarType;
|
||||||
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped};
|
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped};
|
||||||
|
|
||||||
// The number of 32bit registers in the config space, 4096 bytes.
|
// The number of 32bit registers in the config space, 4096 bytes.
|
||||||
@@ -18,6 +19,7 @@ const STATUS_REG: usize = 1;
|
|||||||
const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
|
const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
|
||||||
const BAR0_REG: usize = 4;
|
const BAR0_REG: usize = 4;
|
||||||
const ROM_BAR_REG: usize = 12;
|
const ROM_BAR_REG: usize = 12;
|
||||||
|
const ROM_BAR_IDX: usize = 6;
|
||||||
const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
|
const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
|
||||||
const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
|
const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
|
||||||
const ROM_BAR_ADDR_MASK: u32 = 0xffff_f800;
|
const ROM_BAR_ADDR_MASK: u32 = 0xffff_f800;
|
||||||
@@ -185,7 +187,7 @@ pub trait PciProgrammingInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Types of PCI capabilities.
|
/// Types of PCI capabilities.
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@@ -319,24 +321,55 @@ pub struct PciConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// See pci_regs.h in kernel
|
/// See pci_regs.h in kernel
|
||||||
#[derive(Copy, Clone, PartialEq, Versionize, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Versionize, Debug)]
|
||||||
pub enum PciBarRegionType {
|
pub enum PciBarRegionType {
|
||||||
Memory32BitRegion = 0,
|
Memory32BitRegion = 0,
|
||||||
IoRegion = 0x01,
|
IoRegion = 0x01,
|
||||||
Memory64BitRegion = 0x04,
|
Memory64BitRegion = 0x04,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<PciBarType> for PciBarRegionType {
|
||||||
|
fn from(type_: PciBarType) -> Self {
|
||||||
|
match type_ {
|
||||||
|
PciBarType::Io => PciBarRegionType::IoRegion,
|
||||||
|
PciBarType::Mmio32 => PciBarRegionType::Memory32BitRegion,
|
||||||
|
PciBarType::Mmio64 => PciBarRegionType::Memory64BitRegion,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::from_over_into)]
|
||||||
|
impl Into<PciBarType> for PciBarRegionType {
|
||||||
|
fn into(self) -> PciBarType {
|
||||||
|
match self {
|
||||||
|
PciBarRegionType::IoRegion => PciBarType::Io,
|
||||||
|
PciBarRegionType::Memory32BitRegion => PciBarType::Mmio32,
|
||||||
|
PciBarRegionType::Memory64BitRegion => PciBarType::Mmio64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum PciBarPrefetchable {
|
pub enum PciBarPrefetchable {
|
||||||
NotPrefetchable = 0,
|
NotPrefetchable = 0,
|
||||||
Prefetchable = 0x08,
|
Prefetchable = 0x08,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::from_over_into)]
|
||||||
|
impl Into<bool> for PciBarPrefetchable {
|
||||||
|
fn into(self) -> bool {
|
||||||
|
match self {
|
||||||
|
PciBarPrefetchable::NotPrefetchable => false,
|
||||||
|
PciBarPrefetchable::Prefetchable => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct PciBarConfiguration {
|
pub struct PciBarConfiguration {
|
||||||
addr: u64,
|
addr: u64,
|
||||||
size: u64,
|
size: u64,
|
||||||
reg_idx: usize,
|
idx: usize,
|
||||||
region_type: PciBarRegionType,
|
region_type: PciBarRegionType,
|
||||||
prefetchable: PciBarPrefetchable,
|
prefetchable: PciBarPrefetchable,
|
||||||
}
|
}
|
||||||
@@ -556,22 +589,23 @@ impl PciConfiguration {
|
|||||||
|
|
||||||
/// Adds a region specified by `config`. Configures the specified BAR(s) to
|
/// Adds a region specified by `config`. Configures the specified BAR(s) to
|
||||||
/// report this region and size to the guest kernel. Enforces a few constraints
|
/// report this region and size to the guest kernel. Enforces a few constraints
|
||||||
/// (i.e, region size must be power of two, register not already used). Returns 'None' on
|
/// (i.e, region size must be power of two, register not already used).
|
||||||
/// failure all, `Some(BarIndex)` on success.
|
pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<()> {
|
||||||
pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<usize> {
|
let bar_idx = config.idx;
|
||||||
if self.bars[config.reg_idx].used {
|
let reg_idx = BAR0_REG + bar_idx;
|
||||||
return Err(Error::BarInUse(config.reg_idx));
|
|
||||||
|
if self.bars[bar_idx].used {
|
||||||
|
return Err(Error::BarInUse(bar_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.size.count_ones() != 1 {
|
if config.size.count_ones() != 1 {
|
||||||
return Err(Error::BarSizeInvalid(config.size));
|
return Err(Error::BarSizeInvalid(config.size));
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.reg_idx >= NUM_BAR_REGS {
|
if bar_idx >= NUM_BAR_REGS {
|
||||||
return Err(Error::BarInvalid(config.reg_idx));
|
return Err(Error::BarInvalid(bar_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
let bar_idx = BAR0_REG + config.reg_idx;
|
|
||||||
let end_addr = config
|
let end_addr = config
|
||||||
.addr
|
.addr
|
||||||
.checked_add(config.size - 1)
|
.checked_add(config.size - 1)
|
||||||
@@ -584,20 +618,20 @@ impl PciConfiguration {
|
|||||||
|
|
||||||
// Encode the BAR size as expected by the software running in
|
// Encode the BAR size as expected by the software running in
|
||||||
// the guest.
|
// the guest.
|
||||||
self.bars[config.reg_idx].size =
|
self.bars[bar_idx].size =
|
||||||
encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
|
encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
|
||||||
}
|
}
|
||||||
PciBarRegionType::Memory64BitRegion => {
|
PciBarRegionType::Memory64BitRegion => {
|
||||||
if config.reg_idx + 1 >= NUM_BAR_REGS {
|
if bar_idx + 1 >= NUM_BAR_REGS {
|
||||||
return Err(Error::BarInvalid64(config.reg_idx));
|
return Err(Error::BarInvalid64(bar_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
if end_addr > u64::max_value() {
|
if end_addr > u64::max_value() {
|
||||||
return Err(Error::BarAddressInvalid(config.addr, config.size));
|
return Err(Error::BarAddressInvalid(config.addr, config.size));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.bars[config.reg_idx + 1].used {
|
if self.bars[bar_idx + 1].used {
|
||||||
return Err(Error::BarInUse64(config.reg_idx));
|
return Err(Error::BarInUse64(bar_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode the BAR size as expected by the software running in
|
// Encode the BAR size as expected by the software running in
|
||||||
@@ -605,12 +639,12 @@ impl PciConfiguration {
|
|||||||
let (bar_size_hi, bar_size_lo) =
|
let (bar_size_hi, bar_size_lo) =
|
||||||
encode_64_bits_bar_size(config.size).ok_or(Error::Encode64BarSize)?;
|
encode_64_bits_bar_size(config.size).ok_or(Error::Encode64BarSize)?;
|
||||||
|
|
||||||
self.registers[bar_idx + 1] = (config.addr >> 32) as u32;
|
self.registers[reg_idx + 1] = (config.addr >> 32) as u32;
|
||||||
self.writable_bits[bar_idx + 1] = 0xffff_ffff;
|
self.writable_bits[reg_idx + 1] = 0xffff_ffff;
|
||||||
self.bars[config.reg_idx + 1].addr = self.registers[bar_idx + 1];
|
self.bars[bar_idx + 1].addr = self.registers[reg_idx + 1];
|
||||||
self.bars[config.reg_idx].size = bar_size_lo;
|
self.bars[bar_idx].size = bar_size_lo;
|
||||||
self.bars[config.reg_idx + 1].size = bar_size_hi;
|
self.bars[bar_idx + 1].size = bar_size_hi;
|
||||||
self.bars[config.reg_idx + 1].used = true;
|
self.bars[bar_idx + 1].used = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,26 +656,30 @@ impl PciConfiguration {
|
|||||||
PciBarRegionType::IoRegion => (BAR_IO_ADDR_MASK, config.region_type as u32),
|
PciBarRegionType::IoRegion => (BAR_IO_ADDR_MASK, config.region_type as u32),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.registers[bar_idx] = ((config.addr as u32) & mask) | lower_bits;
|
self.registers[reg_idx] = ((config.addr as u32) & mask) | lower_bits;
|
||||||
self.writable_bits[bar_idx] = mask;
|
self.writable_bits[reg_idx] = mask;
|
||||||
self.bars[config.reg_idx].addr = self.registers[bar_idx];
|
self.bars[bar_idx].addr = self.registers[reg_idx];
|
||||||
self.bars[config.reg_idx].used = true;
|
self.bars[bar_idx].used = true;
|
||||||
self.bars[config.reg_idx].r#type = Some(config.region_type);
|
self.bars[bar_idx].r#type = Some(config.region_type);
|
||||||
Ok(config.reg_idx)
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds rom expansion BAR.
|
/// Adds rom expansion BAR.
|
||||||
pub fn add_pci_rom_bar(&mut self, config: &PciBarConfiguration, active: u32) -> Result<usize> {
|
pub fn add_pci_rom_bar(&mut self, config: &PciBarConfiguration, active: u32) -> Result<()> {
|
||||||
|
let bar_idx = config.idx;
|
||||||
|
let reg_idx = ROM_BAR_REG;
|
||||||
|
|
||||||
if self.rom_bar_used {
|
if self.rom_bar_used {
|
||||||
return Err(Error::RomBarInUse(config.reg_idx));
|
return Err(Error::RomBarInUse(bar_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.size.count_ones() != 1 {
|
if config.size.count_ones() != 1 {
|
||||||
return Err(Error::RomBarSizeInvalid(config.size));
|
return Err(Error::RomBarSizeInvalid(config.size));
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.reg_idx != ROM_BAR_REG {
|
if bar_idx != ROM_BAR_IDX {
|
||||||
return Err(Error::RomBarInvalid(config.reg_idx));
|
return Err(Error::RomBarInvalid(bar_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
let end_addr = config
|
let end_addr = config
|
||||||
@@ -653,13 +691,14 @@ impl PciConfiguration {
|
|||||||
return Err(Error::RomBarAddressInvalid(config.addr, config.size));
|
return Err(Error::RomBarAddressInvalid(config.addr, config.size));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.registers[config.reg_idx] = (config.addr as u32) | active;
|
self.registers[reg_idx] = (config.addr as u32) | active;
|
||||||
self.writable_bits[config.reg_idx] = ROM_BAR_ADDR_MASK;
|
self.writable_bits[reg_idx] = ROM_BAR_ADDR_MASK;
|
||||||
self.rom_bar_addr = self.registers[config.reg_idx];
|
self.rom_bar_addr = self.registers[reg_idx];
|
||||||
self.rom_bar_size =
|
self.rom_bar_size =
|
||||||
encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
|
encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
|
||||||
self.rom_bar_used = true;
|
self.rom_bar_used = true;
|
||||||
Ok(config.reg_idx)
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the address of the given BAR region.
|
/// Returns the address of the given BAR region.
|
||||||
@@ -911,7 +950,7 @@ impl Snapshottable for PciConfiguration {
|
|||||||
impl Default for PciBarConfiguration {
|
impl Default for PciBarConfiguration {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
PciBarConfiguration {
|
PciBarConfiguration {
|
||||||
reg_idx: 0,
|
idx: 0,
|
||||||
addr: 0,
|
addr: 0,
|
||||||
size: 0,
|
size: 0,
|
||||||
region_type: PciBarRegionType::Memory64BitRegion,
|
region_type: PciBarRegionType::Memory64BitRegion,
|
||||||
@@ -922,13 +961,13 @@ impl Default for PciBarConfiguration {
|
|||||||
|
|
||||||
impl PciBarConfiguration {
|
impl PciBarConfiguration {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
reg_idx: usize,
|
idx: usize,
|
||||||
size: u64,
|
size: u64,
|
||||||
region_type: PciBarRegionType,
|
region_type: PciBarRegionType,
|
||||||
prefetchable: PciBarPrefetchable,
|
prefetchable: PciBarPrefetchable,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
PciBarConfiguration {
|
PciBarConfiguration {
|
||||||
reg_idx,
|
idx,
|
||||||
addr: 0,
|
addr: 0,
|
||||||
size,
|
size,
|
||||||
region_type,
|
region_type,
|
||||||
@@ -937,8 +976,8 @@ impl PciBarConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn set_register_index(mut self, reg_idx: usize) -> Self {
|
pub fn set_index(mut self, idx: usize) -> Self {
|
||||||
self.reg_idx = reg_idx;
|
self.idx = idx;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -954,15 +993,31 @@ impl PciBarConfiguration {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_size(&self) -> u64 {
|
|
||||||
self.size
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self {
|
pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self {
|
||||||
self.region_type = region_type;
|
self.region_type = region_type;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn idx(&self) -> usize {
|
||||||
|
self.idx
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addr(&self) -> u64 {
|
||||||
|
self.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> u64 {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn region_type(&self) -> PciBarRegionType {
|
||||||
|
self.region_type
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prefetchable(&self) -> PciBarPrefetchable {
|
||||||
|
self.prefetchable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
use crate::configuration::{self, PciBarRegionType};
|
use crate::configuration::{self, PciBarRegionType};
|
||||||
|
use crate::PciBarConfiguration;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use std::sync::{Arc, Barrier, Mutex};
|
use std::sync::{Arc, Barrier, Mutex};
|
||||||
use std::{self, io, result};
|
use std::{self, io, result};
|
||||||
use vm_allocator::{AddressAllocator, SystemAllocator};
|
use vm_allocator::{AddressAllocator, SystemAllocator};
|
||||||
use vm_device::BusDevice;
|
use vm_device::{BusDevice, Resource};
|
||||||
use vm_memory::{GuestAddress, GuestUsize};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@@ -19,6 +19,8 @@ pub enum Error {
|
|||||||
IoAllocationFailed(u64),
|
IoAllocationFailed(u64),
|
||||||
/// Registering an IO BAR failed.
|
/// Registering an IO BAR failed.
|
||||||
IoRegistrationFailed(u64, configuration::Error),
|
IoRegistrationFailed(u64, configuration::Error),
|
||||||
|
/// Expected resource not found.
|
||||||
|
MissingResource,
|
||||||
}
|
}
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
@@ -34,6 +36,7 @@ impl Display for Error {
|
|||||||
IoRegistrationFailed(addr, e) => {
|
IoRegistrationFailed(addr, e) => {
|
||||||
write!(f, "failed to register an IO BAR, addr={} err={}", addr, e)
|
write!(f, "failed to register an IO BAR, addr={} err={}", addr, e)
|
||||||
}
|
}
|
||||||
|
MissingResource => write!(f, "failed to find expected resource"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,7 +56,8 @@ pub trait PciDevice: BusDevice {
|
|||||||
&mut self,
|
&mut self,
|
||||||
_allocator: &Arc<Mutex<SystemAllocator>>,
|
_allocator: &Arc<Mutex<SystemAllocator>>,
|
||||||
_mmio_allocator: &mut AddressAllocator,
|
_mmio_allocator: &mut AddressAllocator,
|
||||||
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>> {
|
_resources: Option<Vec<Resource>>,
|
||||||
|
) -> Result<Vec<PciBarConfiguration>> {
|
||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,6 +107,9 @@ pub trait PciDevice: BusDevice {
|
|||||||
/// Provides a mutable reference to the Any trait. This is useful to let
|
/// Provides a mutable reference to the Any trait. This is useful to let
|
||||||
/// the caller have access to the underlying type behind the trait.
|
/// the caller have access to the underlying type behind the trait.
|
||||||
fn as_any(&mut self) -> &mut dyn Any;
|
fn as_any(&mut self) -> &mut dyn Any;
|
||||||
|
|
||||||
|
/// Optionally returns a unique identifier.
|
||||||
|
fn id(&self) -> Option<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This trait defines a set of functions which can be triggered whenever a
|
/// This trait defines a set of functions which can be triggered whenever a
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ pub const PCI_CONFIG_IO_PORT: u64 = 0xcf8;
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub const PCI_CONFIG_IO_PORT_SIZE: u64 = 0x8;
|
pub const PCI_CONFIG_IO_PORT_SIZE: u64 = 0x8;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd)]
|
||||||
pub struct PciBdf(u32);
|
pub struct PciBdf(u32);
|
||||||
|
|
||||||
struct PciBdfVisitor;
|
struct PciBdfVisitor;
|
||||||
|
|||||||
@@ -3,11 +3,17 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
|
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
|
||||||
//
|
//
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
|
use std::io;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use thiserror::Error;
|
||||||
|
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||||
|
use versionize_derive::Versionize;
|
||||||
use vm_device::interrupt::{
|
use vm_device::interrupt::{
|
||||||
InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig,
|
InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig,
|
||||||
};
|
};
|
||||||
|
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped};
|
||||||
|
|
||||||
// MSI control masks
|
// MSI control masks
|
||||||
const MSI_CTL_ENABLE: u16 = 0x1;
|
const MSI_CTL_ENABLE: u16 = 0x1;
|
||||||
@@ -32,7 +38,15 @@ pub fn msi_num_enabled_vectors(msg_ctl: u16) -> usize {
|
|||||||
1 << field
|
1 << field
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Error, Debug)]
|
||||||
|
enum Error {
|
||||||
|
#[error("Failed enabling the interrupt route: {0}")]
|
||||||
|
EnableInterruptRoute(io::Error),
|
||||||
|
#[error("Failed updating the interrupt route: {0}")]
|
||||||
|
UpdateInterruptRoute(io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default, Versionize)]
|
||||||
pub struct MsiCap {
|
pub struct MsiCap {
|
||||||
// Message Control Register
|
// Message Control Register
|
||||||
// 0: MSI enable.
|
// 0: MSI enable.
|
||||||
@@ -157,8 +171,15 @@ impl MsiCap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MsiConfig {
|
#[derive(Versionize)]
|
||||||
|
struct MsiConfigState {
|
||||||
cap: MsiCap,
|
cap: MsiCap,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VersionMapped for MsiConfigState {}
|
||||||
|
|
||||||
|
pub struct MsiConfig {
|
||||||
|
pub cap: MsiCap,
|
||||||
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +196,39 @@ impl MsiConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn state(&self) -> MsiConfigState {
|
||||||
|
MsiConfigState { cap: self.cap }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_state(&mut self, state: &MsiConfigState) -> Result<(), Error> {
|
||||||
|
self.cap = state.cap;
|
||||||
|
|
||||||
|
if self.enabled() {
|
||||||
|
for idx in 0..self.num_enabled_vectors() {
|
||||||
|
let config = MsiIrqSourceConfig {
|
||||||
|
high_addr: self.cap.msg_addr_hi,
|
||||||
|
low_addr: self.cap.msg_addr_lo,
|
||||||
|
data: self.cap.msg_data as u32,
|
||||||
|
devid: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.interrupt_source_group
|
||||||
|
.update(
|
||||||
|
idx as InterruptIndex,
|
||||||
|
InterruptSourceConfig::MsiIrq(config),
|
||||||
|
self.cap.vector_masked(idx),
|
||||||
|
)
|
||||||
|
.map_err(Error::UpdateInterruptRoute)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.interrupt_source_group
|
||||||
|
.enable()
|
||||||
|
.map_err(Error::EnableInterruptRoute)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn enabled(&self) -> bool {
|
pub fn enabled(&self) -> bool {
|
||||||
self.cap.enabled()
|
self.cap.enabled()
|
||||||
}
|
}
|
||||||
@@ -222,3 +276,26 @@ impl MsiConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Pausable for MsiConfig {}
|
||||||
|
|
||||||
|
impl Snapshottable for MsiConfig {
|
||||||
|
fn id(&self) -> String {
|
||||||
|
String::from("msi_config")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
|
Snapshot::new_from_versioned_state(&self.id(), &self.state())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
||||||
|
self.set_state(&snapshot.to_versioned_state(&self.id())?)
|
||||||
|
.map_err(|e| {
|
||||||
|
MigratableError::Restore(anyhow!(
|
||||||
|
"Could not restore state for {}: {:?}",
|
||||||
|
self.id(),
|
||||||
|
e
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -441,7 +441,7 @@ impl Snapshottable for MsixConfig {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default, Versionize)]
|
||||||
pub struct MsixCap {
|
pub struct MsixCap {
|
||||||
// Message Control Register
|
// Message Control Register
|
||||||
// 10-0: MSI-X Table size
|
// 10-0: MSI-X Table size
|
||||||
|
|||||||
901
pci/src/vfio.rs
901
pci/src/vfio.rs
File diff suppressed because it is too large
Load Diff
@@ -3,11 +3,12 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
use crate::vfio::{Interrupt, Vfio, VfioCommon, VfioError};
|
use crate::vfio::{Interrupt, UserMemoryRegion, Vfio, VfioCommon, VfioError};
|
||||||
use crate::{BarReprogrammingParams, PciBarRegionType, VfioPciError};
|
use crate::{BarReprogrammingParams, PciBarConfiguration, VfioPciError};
|
||||||
use crate::{
|
use crate::{
|
||||||
PciBdf, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
|
PciBdf, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
|
||||||
};
|
};
|
||||||
|
use anyhow::anyhow;
|
||||||
use hypervisor::HypervisorVmError;
|
use hypervisor::HypervisorVmError;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::os::unix::prelude::AsRawFd;
|
use std::os::unix::prelude::AsRawFd;
|
||||||
@@ -21,19 +22,20 @@ use vfio_user::{Client, Error as VfioUserError};
|
|||||||
use vm_allocator::{AddressAllocator, SystemAllocator};
|
use vm_allocator::{AddressAllocator, SystemAllocator};
|
||||||
use vm_device::dma_mapping::ExternalDmaMapping;
|
use vm_device::dma_mapping::ExternalDmaMapping;
|
||||||
use vm_device::interrupt::{InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig};
|
use vm_device::interrupt::{InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig};
|
||||||
use vm_device::BusDevice;
|
use vm_device::{BusDevice, Resource};
|
||||||
use vm_memory::bitmap::AtomicBitmap;
|
use vm_memory::bitmap::AtomicBitmap;
|
||||||
use vm_memory::{
|
use vm_memory::{
|
||||||
Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryRegion, GuestRegionMmap,
|
Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryRegion, GuestRegionMmap,
|
||||||
GuestUsize,
|
|
||||||
};
|
};
|
||||||
|
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
pub struct VfioUserPciDevice {
|
pub struct VfioUserPciDevice {
|
||||||
|
id: String,
|
||||||
vm: Arc<dyn hypervisor::Vm>,
|
vm: Arc<dyn hypervisor::Vm>,
|
||||||
client: Arc<Mutex<Client>>,
|
client: Arc<Mutex<Client>>,
|
||||||
vfio_wrapper: VfioUserClientWrapper,
|
|
||||||
common: VfioCommon,
|
common: VfioCommon,
|
||||||
|
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
@@ -62,12 +64,16 @@ impl PciSubclass for PciVfioUserSubclass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VfioUserPciDevice {
|
impl VfioUserPciDevice {
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
id: String,
|
||||||
vm: &Arc<dyn hypervisor::Vm>,
|
vm: &Arc<dyn hypervisor::Vm>,
|
||||||
client: Arc<Mutex<Client>>,
|
client: Arc<Mutex<Client>>,
|
||||||
msi_interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
msi_interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||||
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
|
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
|
||||||
bdf: PciBdf,
|
bdf: PciBdf,
|
||||||
|
restoring: bool,
|
||||||
|
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
|
||||||
) -> Result<Self, VfioUserPciDeviceError> {
|
) -> Result<Self, VfioUserPciDeviceError> {
|
||||||
// This is used for the BAR and capabilities only
|
// This is used for the BAR and capabilities only
|
||||||
let configuration = PciConfiguration::new(
|
let configuration = PciConfiguration::new(
|
||||||
@@ -103,29 +109,31 @@ impl VfioUserPciDevice {
|
|||||||
msi: None,
|
msi: None,
|
||||||
msix: None,
|
msix: None,
|
||||||
},
|
},
|
||||||
|
msi_interrupt_manager,
|
||||||
|
legacy_interrupt_group,
|
||||||
|
vfio_wrapper: Arc::new(vfio_wrapper) as Arc<dyn Vfio>,
|
||||||
};
|
};
|
||||||
|
|
||||||
common.parse_capabilities(msi_interrupt_manager, &vfio_wrapper, bdf);
|
// No need to parse capabilities from the device if on the restore path.
|
||||||
common
|
// The initialization will be performed later when restore() will be
|
||||||
.initialize_legacy_interrupt(legacy_interrupt_group, &vfio_wrapper)
|
// called.
|
||||||
.map_err(VfioUserPciDeviceError::InitializeLegacyInterrupts)?;
|
if !restoring {
|
||||||
|
common.parse_capabilities(bdf);
|
||||||
|
common
|
||||||
|
.initialize_legacy_interrupt()
|
||||||
|
.map_err(VfioUserPciDeviceError::InitializeLegacyInterrupts)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
id,
|
||||||
vm: vm.clone(),
|
vm: vm.clone(),
|
||||||
client,
|
client,
|
||||||
vfio_wrapper,
|
|
||||||
common,
|
common,
|
||||||
|
memory_slot,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_mmio_regions<F>(
|
pub fn map_mmio_regions(&mut self) -> Result<(), VfioUserPciDeviceError> {
|
||||||
&mut self,
|
|
||||||
vm: &Arc<dyn hypervisor::Vm>,
|
|
||||||
mem_slot: F,
|
|
||||||
) -> Result<(), VfioUserPciDeviceError>
|
|
||||||
where
|
|
||||||
F: Fn() -> u32,
|
|
||||||
{
|
|
||||||
for mmio_region in &mut self.common.mmio_regions {
|
for mmio_region in &mut self.common.mmio_regions {
|
||||||
let region_flags = self
|
let region_flags = self
|
||||||
.client
|
.client
|
||||||
@@ -143,6 +151,15 @@ impl VfioUserPciDevice {
|
|||||||
.file_offset
|
.file_offset
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
|
let sparse_areas = self
|
||||||
|
.client
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.region(mmio_region.index)
|
||||||
|
.unwrap()
|
||||||
|
.sparse_areas
|
||||||
|
.clone();
|
||||||
|
|
||||||
if region_flags & VFIO_REGION_INFO_FLAG_MMAP != 0 {
|
if region_flags & VFIO_REGION_INFO_FLAG_MMAP != 0 {
|
||||||
let mut prot = 0;
|
let mut prot = 0;
|
||||||
if region_flags & VFIO_REGION_INFO_FLAG_READ != 0 {
|
if region_flags & VFIO_REGION_INFO_FLAG_READ != 0 {
|
||||||
@@ -152,41 +169,58 @@ impl VfioUserPciDevice {
|
|||||||
prot |= libc::PROT_WRITE;
|
prot |= libc::PROT_WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
let host_addr = unsafe {
|
let mmaps = if sparse_areas.is_empty() {
|
||||||
libc::mmap(
|
vec![vfio_region_sparse_mmap_area {
|
||||||
null_mut(),
|
offset: 0,
|
||||||
mmio_region.length as usize,
|
size: mmio_region.length,
|
||||||
prot,
|
}]
|
||||||
libc::MAP_SHARED,
|
} else {
|
||||||
file_offset.as_ref().unwrap().file().as_raw_fd(),
|
sparse_areas
|
||||||
file_offset.as_ref().unwrap().start() as libc::off_t,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if host_addr == libc::MAP_FAILED {
|
for s in mmaps.iter() {
|
||||||
error!(
|
let host_addr = unsafe {
|
||||||
"Could not mmap regions, error:{}",
|
libc::mmap(
|
||||||
std::io::Error::last_os_error()
|
null_mut(),
|
||||||
|
s.size as usize,
|
||||||
|
prot,
|
||||||
|
libc::MAP_SHARED,
|
||||||
|
file_offset.as_ref().unwrap().file().as_raw_fd(),
|
||||||
|
file_offset.as_ref().unwrap().start() as libc::off_t
|
||||||
|
+ s.offset as libc::off_t,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if host_addr == libc::MAP_FAILED {
|
||||||
|
error!(
|
||||||
|
"Could not mmap regions, error:{}",
|
||||||
|
std::io::Error::last_os_error()
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let user_memory_region = UserMemoryRegion {
|
||||||
|
slot: (self.memory_slot)(),
|
||||||
|
start: mmio_region.start.0 + s.offset,
|
||||||
|
size: s.size,
|
||||||
|
host_addr: host_addr as u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
mmio_region.user_memory_regions.push(user_memory_region);
|
||||||
|
|
||||||
|
let mem_region = self.vm.make_user_memory_region(
|
||||||
|
user_memory_region.slot,
|
||||||
|
user_memory_region.start,
|
||||||
|
user_memory_region.size,
|
||||||
|
user_memory_region.host_addr,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
continue;
|
|
||||||
|
self.vm
|
||||||
|
.create_user_memory_region(mem_region)
|
||||||
|
.map_err(VfioUserPciDeviceError::MapRegionGuest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let slot = mem_slot();
|
|
||||||
let mem_region = vm.make_user_memory_region(
|
|
||||||
slot,
|
|
||||||
mmio_region.start.0,
|
|
||||||
mmio_region.length as u64,
|
|
||||||
host_addr as u64,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
vm.create_user_memory_region(mem_region)
|
|
||||||
.map_err(VfioUserPciDeviceError::MapRegionGuest)?;
|
|
||||||
|
|
||||||
mmio_region.mem_slot = Some(slot);
|
|
||||||
mmio_region.host_addr = Some(host_addr as u64);
|
|
||||||
mmio_region.mmap_size = Some(mmio_region.length as usize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,17 +229,13 @@ impl VfioUserPciDevice {
|
|||||||
|
|
||||||
pub fn unmap_mmio_regions(&mut self) {
|
pub fn unmap_mmio_regions(&mut self) {
|
||||||
for mmio_region in self.common.mmio_regions.iter() {
|
for mmio_region in self.common.mmio_regions.iter() {
|
||||||
if let (Some(host_addr), Some(mmap_size), Some(mem_slot)) = (
|
for user_memory_region in mmio_region.user_memory_regions.iter() {
|
||||||
mmio_region.host_addr,
|
|
||||||
mmio_region.mmap_size,
|
|
||||||
mmio_region.mem_slot,
|
|
||||||
) {
|
|
||||||
// Remove region
|
// Remove region
|
||||||
let r = self.vm.make_user_memory_region(
|
let r = self.vm.make_user_memory_region(
|
||||||
mem_slot,
|
user_memory_region.slot,
|
||||||
mmio_region.start.raw_value(),
|
user_memory_region.start,
|
||||||
mmap_size as u64,
|
user_memory_region.size,
|
||||||
host_addr as u64,
|
user_memory_region.host_addr,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
@@ -214,7 +244,13 @@ impl VfioUserPciDevice {
|
|||||||
error!("Could not remove the userspace memory region: {}", e);
|
error!("Could not remove the userspace memory region: {}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret = unsafe { libc::munmap(host_addr as *mut libc::c_void, mmap_size) };
|
// Remove mmaps
|
||||||
|
let ret = unsafe {
|
||||||
|
libc::munmap(
|
||||||
|
user_memory_region.host_addr as *mut libc::c_void,
|
||||||
|
user_memory_region.size as usize,
|
||||||
|
)
|
||||||
|
};
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
error!(
|
error!(
|
||||||
"Could not unmap region {}, error:{}",
|
"Could not unmap region {}, error:{}",
|
||||||
@@ -392,9 +428,10 @@ impl PciDevice for VfioUserPciDevice {
|
|||||||
&mut self,
|
&mut self,
|
||||||
allocator: &Arc<Mutex<SystemAllocator>>,
|
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||||
mmio_allocator: &mut AddressAllocator,
|
mmio_allocator: &mut AddressAllocator,
|
||||||
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
|
resources: Option<Vec<Resource>>,
|
||||||
|
) -> Result<Vec<PciBarConfiguration>, PciDeviceError> {
|
||||||
self.common
|
self.common
|
||||||
.allocate_bars(allocator, mmio_allocator, &self.vfio_wrapper)
|
.allocate_bars(allocator, mmio_allocator, resources)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn free_bars(
|
fn free_bars(
|
||||||
@@ -425,22 +462,19 @@ impl PciDevice for VfioUserPciDevice {
|
|||||||
offset: u64,
|
offset: u64,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Option<Arc<Barrier>> {
|
) -> Option<Arc<Barrier>> {
|
||||||
self.common
|
self.common.write_config_register(reg_idx, offset, data)
|
||||||
.write_config_register(reg_idx, offset, data, &self.vfio_wrapper)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_config_register(&mut self, reg_idx: usize) -> u32 {
|
fn read_config_register(&mut self, reg_idx: usize) -> u32 {
|
||||||
self.common
|
self.common.read_config_register(reg_idx)
|
||||||
.read_config_register(reg_idx, &self.vfio_wrapper)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_bar(&mut self, base: u64, offset: u64, data: &mut [u8]) {
|
fn read_bar(&mut self, base: u64, offset: u64, data: &mut [u8]) {
|
||||||
self.common.read_bar(base, offset, data, &self.vfio_wrapper)
|
self.common.read_bar(base, offset, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_bar(&mut self, base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
fn write_bar(&mut self, base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||||
self.common
|
self.common.write_bar(base, offset, data)
|
||||||
.write_bar(base, offset, data, &self.vfio_wrapper)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_bar(&mut self, old_base: u64, new_base: u64) -> Result<(), std::io::Error> {
|
fn move_bar(&mut self, old_base: u64, new_base: u64) -> Result<(), std::io::Error> {
|
||||||
@@ -449,35 +483,41 @@ impl PciDevice for VfioUserPciDevice {
|
|||||||
if mmio_region.start.raw_value() == old_base {
|
if mmio_region.start.raw_value() == old_base {
|
||||||
mmio_region.start = GuestAddress(new_base);
|
mmio_region.start = GuestAddress(new_base);
|
||||||
|
|
||||||
if let Some(mem_slot) = mmio_region.mem_slot {
|
for user_memory_region in mmio_region.user_memory_regions.iter_mut() {
|
||||||
if let Some(host_addr) = mmio_region.host_addr {
|
// Remove old region
|
||||||
// Remove original region
|
let old_region = self.vm.make_user_memory_region(
|
||||||
let old_region = self.vm.make_user_memory_region(
|
user_memory_region.slot,
|
||||||
mem_slot,
|
user_memory_region.start,
|
||||||
old_base,
|
user_memory_region.size,
|
||||||
mmio_region.length as u64,
|
user_memory_region.host_addr,
|
||||||
host_addr as u64,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
self.vm
|
self.vm
|
||||||
.remove_user_memory_region(old_region)
|
.remove_user_memory_region(old_region)
|
||||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
|
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
|
||||||
|
|
||||||
let new_region = self.vm.make_user_memory_region(
|
// Update the user memory region with the correct start address.
|
||||||
mem_slot,
|
if new_base > old_base {
|
||||||
new_base,
|
user_memory_region.start += new_base - old_base;
|
||||||
mmio_region.length as u64,
|
} else {
|
||||||
host_addr as u64,
|
user_memory_region.start -= old_base - new_base;
|
||||||
false,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.vm
|
|
||||||
.create_user_memory_region(new_region)
|
|
||||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Insert new region
|
||||||
|
let new_region = self.vm.make_user_memory_region(
|
||||||
|
user_memory_region.slot,
|
||||||
|
user_memory_region.start,
|
||||||
|
user_memory_region.size,
|
||||||
|
user_memory_region.host_addr,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.vm
|
||||||
|
.create_user_memory_region(new_region)
|
||||||
|
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
|
||||||
}
|
}
|
||||||
info!("Moved bar 0x{:x} -> 0x{:x}", old_base, new_base);
|
info!("Moved bar 0x{:x} -> 0x{:x}", old_base, new_base);
|
||||||
}
|
}
|
||||||
@@ -485,6 +525,10 @@ impl PciDevice for VfioUserPciDevice {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn id(&self) -> Option<String> {
|
||||||
|
Some(self.id.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for VfioUserPciDevice {
|
impl Drop for VfioUserPciDevice {
|
||||||
@@ -493,18 +537,18 @@ impl Drop for VfioUserPciDevice {
|
|||||||
|
|
||||||
if let Some(msix) = &self.common.interrupt.msix {
|
if let Some(msix) = &self.common.interrupt.msix {
|
||||||
if msix.bar.enabled() {
|
if msix.bar.enabled() {
|
||||||
self.common.disable_msix(&self.vfio_wrapper);
|
self.common.disable_msix();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(msi) = &self.common.interrupt.msi {
|
if let Some(msi) = &self.common.interrupt.msi {
|
||||||
if msi.cfg.enabled() {
|
if msi.cfg.enabled() {
|
||||||
self.common.disable_msi(&self.vfio_wrapper)
|
self.common.disable_msi()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.common.interrupt.intx_in_use() {
|
if self.common.interrupt.intx_in_use() {
|
||||||
self.common.disable_intx(&self.vfio_wrapper);
|
self.common.disable_intx();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = self.client.lock().unwrap().shutdown() {
|
if let Err(e) = self.client.lock().unwrap().shutdown() {
|
||||||
@@ -513,6 +557,40 @@ impl Drop for VfioUserPciDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Pausable for VfioUserPciDevice {}
|
||||||
|
|
||||||
|
impl Snapshottable for VfioUserPciDevice {
|
||||||
|
fn id(&self) -> String {
|
||||||
|
self.id.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
|
let mut vfio_pci_dev_snapshot = Snapshot::new(&self.id);
|
||||||
|
|
||||||
|
// Snapshot VfioCommon
|
||||||
|
vfio_pci_dev_snapshot.add_snapshot(self.common.snapshot()?);
|
||||||
|
|
||||||
|
Ok(vfio_pci_dev_snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
||||||
|
// Restore VfioCommon
|
||||||
|
if let Some(vfio_common_snapshot) = snapshot.snapshots.get(&self.common.id()) {
|
||||||
|
self.common.restore(*vfio_common_snapshot.clone())?;
|
||||||
|
self.map_mmio_regions().map_err(|e| {
|
||||||
|
MigratableError::Restore(anyhow!(
|
||||||
|
"Could not map MMIO regions for VfioUserPciDevice on restore {:?}",
|
||||||
|
e
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Transportable for VfioUserPciDevice {}
|
||||||
|
impl Migratable for VfioUserPciDevice {}
|
||||||
|
|
||||||
pub struct VfioUserDmaMapping<M: GuestAddressSpace> {
|
pub struct VfioUserDmaMapping<M: GuestAddressSpace> {
|
||||||
client: Arc<Mutex<Client>>,
|
client: Arc<Mutex<Client>>,
|
||||||
memory: Arc<M>,
|
memory: Arc<M>,
|
||||||
@@ -546,10 +624,10 @@ impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioUserDmaMappi
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
return Err(std::io::Error::new(
|
Err(std::io::Error::new(
|
||||||
std::io::ErrorKind::Other,
|
std::io::ErrorKind::Other,
|
||||||
format!("Region not found for 0x{:x}", gpa),
|
format!("Region not found for 0x{:x}", gpa),
|
||||||
));
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ edition = "2021"
|
|||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "3.1.8", features = ["wrap_help","cargo"] }
|
clap = { version = "3.2.8", features = ["wrap_help","cargo"] }
|
||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
serde = { version = "1.0.136", features = ["rc"] }
|
serde = { version = "1.0.138", features = ["rc", "derive"] }
|
||||||
serde_derive = "1.0.136"
|
serde_json = "1.0.82"
|
||||||
serde_json = "1.0.78"
|
|
||||||
test_infra = { path = "../test_infra" }
|
test_infra = { path = "../test_infra" }
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.31"
|
||||||
wait-timeout = "0.2.0"
|
wait-timeout = "0.2.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
clap = { version = "3.1.8", features = ["cargo"] }
|
clap = { version = "3.2.8", features = ["cargo"] }
|
||||||
|
|||||||
@@ -12,8 +12,14 @@ mod performance_tests;
|
|||||||
|
|
||||||
use clap::{Arg, Command as ClapCommand};
|
use clap::{Arg, Command as ClapCommand};
|
||||||
use performance_tests::*;
|
use performance_tests::*;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{env, fmt, process::Command, sync::mpsc::channel, thread, time::Duration};
|
use std::{
|
||||||
|
env, fmt,
|
||||||
|
process::Command,
|
||||||
|
sync::{mpsc::channel, Arc},
|
||||||
|
thread,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
@@ -47,18 +53,30 @@ impl Default for MetricsReport {
|
|||||||
let mut git_human_readable = "".to_string();
|
let mut git_human_readable = "".to_string();
|
||||||
if let Ok(git_out) = Command::new("git").args(&["describe", "--dirty"]).output() {
|
if let Ok(git_out) = Command::new("git").args(&["describe", "--dirty"]).output() {
|
||||||
if git_out.status.success() {
|
if git_out.status.success() {
|
||||||
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
|
git_human_readable = String::from_utf8(git_out.stdout)
|
||||||
git_human_readable = git_out_str.trim().to_string();
|
.unwrap()
|
||||||
}
|
.trim()
|
||||||
|
.to_string();
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"Error generating human readable git reference: {}",
|
||||||
|
String::from_utf8(git_out.stderr).unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut git_revision = "".to_string();
|
let mut git_revision = "".to_string();
|
||||||
if let Ok(git_out) = Command::new("git").args(&["rev-parse", "HEAD"]).output() {
|
if let Ok(git_out) = Command::new("git").args(&["rev-parse", "HEAD"]).output() {
|
||||||
if git_out.status.success() {
|
if git_out.status.success() {
|
||||||
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
|
git_revision = String::from_utf8(git_out.stdout)
|
||||||
git_revision = git_out_str.trim().to_string();
|
.unwrap()
|
||||||
}
|
.trim()
|
||||||
|
.to_string();
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"Error generating git reference: {}",
|
||||||
|
String::from_utf8(git_out.stderr).unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,9 +86,15 @@ impl Default for MetricsReport {
|
|||||||
.output()
|
.output()
|
||||||
{
|
{
|
||||||
if git_out.status.success() {
|
if git_out.status.success() {
|
||||||
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
|
git_commit_date = String::from_utf8(git_out.stdout)
|
||||||
git_commit_date = git_out_str.trim().to_string();
|
.unwrap()
|
||||||
}
|
.trim()
|
||||||
|
.to_string();
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"Error generating git commit date: {}",
|
||||||
|
String::from_utf8(git_out.stderr).unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +108,21 @@ impl Default for MetricsReport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct PerformanceTestOverrides {
|
||||||
|
test_iterations: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PerformanceTestOverrides {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if let Some(test_iterations) = self.test_iterations {
|
||||||
|
write!(f, "test_iterations = {}", test_iterations)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PerformanceTestControl {
|
pub struct PerformanceTestControl {
|
||||||
test_timeout: u32,
|
test_timeout: u32,
|
||||||
test_iterations: u32,
|
test_iterations: u32,
|
||||||
@@ -91,6 +130,7 @@ pub struct PerformanceTestControl {
|
|||||||
queue_size: Option<u32>,
|
queue_size: Option<u32>,
|
||||||
net_rx: Option<bool>,
|
net_rx: Option<bool>,
|
||||||
fio_ops: Option<FioOps>,
|
fio_ops: Option<FioOps>,
|
||||||
|
num_boot_vcpus: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for PerformanceTestControl {
|
impl fmt::Display for PerformanceTestControl {
|
||||||
@@ -125,6 +165,7 @@ impl PerformanceTestControl {
|
|||||||
queue_size: None,
|
queue_size: None,
|
||||||
net_rx: None,
|
net_rx: None,
|
||||||
fio_ops: None,
|
fio_ops: None,
|
||||||
|
num_boot_vcpus: Some(1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,9 +181,12 @@ struct PerformanceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PerformanceTest {
|
impl PerformanceTest {
|
||||||
pub fn run(&self) -> PerformanceTestResult {
|
pub fn run(&self, overrides: &PerformanceTestOverrides) -> PerformanceTestResult {
|
||||||
let mut metrics = Vec::new();
|
let mut metrics = Vec::new();
|
||||||
for _ in 0..self.control.test_iterations {
|
for _ in 0..overrides
|
||||||
|
.test_iterations
|
||||||
|
.unwrap_or(self.control.test_iterations)
|
||||||
|
{
|
||||||
metrics.push((self.func_ptr)(&self.control));
|
metrics.push((self.func_ptr)(&self.control));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,8 +206,9 @@ impl PerformanceTest {
|
|||||||
|
|
||||||
// Calculate the timeout for each test
|
// Calculate the timeout for each test
|
||||||
// Note: To cover the setup/cleanup time, 20s is added for each iteration of the test
|
// Note: To cover the setup/cleanup time, 20s is added for each iteration of the test
|
||||||
pub fn calc_timeout(&self) -> u64 {
|
pub fn calc_timeout(&self, test_iterations: &Option<u32>) -> u64 {
|
||||||
((self.control.test_timeout + 20) * self.control.test_iterations) as u64
|
((self.control.test_timeout + 20) * test_iterations.unwrap_or(self.control.test_iterations))
|
||||||
|
as u64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +261,7 @@ mod adjuster {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TEST_LIST: [PerformanceTest; 15] = [
|
const TEST_LIST: [PerformanceTest; 17] = [
|
||||||
PerformanceTest {
|
PerformanceTest {
|
||||||
name: "boot_time_ms",
|
name: "boot_time_ms",
|
||||||
func_ptr: performance_boot_time,
|
func_ptr: performance_boot_time,
|
||||||
@@ -237,6 +282,28 @@ const TEST_LIST: [PerformanceTest; 15] = [
|
|||||||
},
|
},
|
||||||
unit_adjuster: adjuster::s_to_ms,
|
unit_adjuster: adjuster::s_to_ms,
|
||||||
},
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "boot_time_16_vcpus_ms",
|
||||||
|
func_ptr: performance_boot_time,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
test_timeout: 2,
|
||||||
|
test_iterations: 10,
|
||||||
|
num_boot_vcpus: Some(16),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
unit_adjuster: adjuster::s_to_ms,
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "boot_time_16_vcpus_pmem_ms",
|
||||||
|
func_ptr: performance_boot_time_pmem,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
test_timeout: 2,
|
||||||
|
test_iterations: 10,
|
||||||
|
num_boot_vcpus: Some(16),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
unit_adjuster: adjuster::s_to_ms,
|
||||||
|
},
|
||||||
PerformanceTest {
|
PerformanceTest {
|
||||||
name: "virtio_net_latency_us",
|
name: "virtio_net_latency_us",
|
||||||
func_ptr: performance_net_latency,
|
func_ptr: performance_net_latency,
|
||||||
@@ -381,12 +448,20 @@ const TEST_LIST: [PerformanceTest; 15] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
fn run_test_with_timeout(test: &'static PerformanceTest) -> Result<PerformanceTestResult, Error> {
|
fn run_test_with_timeout(
|
||||||
|
test: &'static PerformanceTest,
|
||||||
|
overrides: &Arc<PerformanceTestOverrides>,
|
||||||
|
) -> Result<PerformanceTestResult, Error> {
|
||||||
let (sender, receiver) = channel::<Result<PerformanceTestResult, Error>>();
|
let (sender, receiver) = channel::<Result<PerformanceTestResult, Error>>();
|
||||||
|
let test_iterations = overrides.test_iterations;
|
||||||
|
let overrides = overrides.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
println!("Test '{}' running .. ({})", test.name, test.control);
|
println!(
|
||||||
|
"Test '{}' running .. (control: {}, overrides: {})",
|
||||||
|
test.name, test.control, overrides
|
||||||
|
);
|
||||||
|
|
||||||
let output = match std::panic::catch_unwind(|| test.run()) {
|
let output = match std::panic::catch_unwind(|| test.run(&overrides)) {
|
||||||
Ok(test_result) => {
|
Ok(test_result) => {
|
||||||
println!(
|
println!(
|
||||||
"Test '{}' .. ok: mean = {}, std_dev = {}",
|
"Test '{}' .. ok: mean = {}, std_dev = {}",
|
||||||
@@ -401,7 +476,7 @@ fn run_test_with_timeout(test: &'static PerformanceTest) -> Result<PerformanceTe
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Todo: Need to cleanup/kill all hanging child processes
|
// Todo: Need to cleanup/kill all hanging child processes
|
||||||
let test_timeout = test.calc_timeout();
|
let test_timeout = test.calc_timeout(&test_iterations);
|
||||||
receiver
|
receiver
|
||||||
.recv_timeout(Duration::from_secs(test_timeout))
|
.recv_timeout(Duration::from_secs(test_timeout))
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
@@ -445,6 +520,12 @@ fn main() {
|
|||||||
.help("Report file. Standard error is used if not specified")
|
.help("Report file. Standard error is used if not specified")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("iterations")
|
||||||
|
.long("iterations")
|
||||||
|
.help("Override number of test iterations")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
// It seems that the tool (ethr) used for testing the virtio-net latency
|
// It seems that the tool (ethr) used for testing the virtio-net latency
|
||||||
@@ -473,9 +554,17 @@ fn main() {
|
|||||||
|
|
||||||
init_tests();
|
init_tests();
|
||||||
|
|
||||||
|
let overrides = Arc::new(PerformanceTestOverrides {
|
||||||
|
test_iterations: cmd_arguments
|
||||||
|
.value_of("iterations")
|
||||||
|
.map(|s| s.parse())
|
||||||
|
.transpose()
|
||||||
|
.unwrap_or_default(),
|
||||||
|
});
|
||||||
|
|
||||||
for test in test_list.iter() {
|
for test in test_list.iter() {
|
||||||
if test_filter.is_empty() || test_filter.iter().any(|&s| test.name.contains(s)) {
|
if test_filter.is_empty() || test_filter.iter().any(|&s| test.name.contains(s)) {
|
||||||
match run_test_with_timeout(test) {
|
match run_test_with_timeout(test, &overrides) {
|
||||||
Ok(r) => {
|
Ok(r) => {
|
||||||
metrics_report.results.push(r);
|
metrics_report.results.push(r);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,6 +238,7 @@ pub fn performance_net_throughput(control: &PerformanceTestControl) -> f64 {
|
|||||||
.default_disks()
|
.default_disks()
|
||||||
.args(&["--net", net_params.as_str()])
|
.args(&["--net", net_params.as_str()])
|
||||||
.capture_output()
|
.capture_output()
|
||||||
|
.verbosity(VerbosityLevel::Warn)
|
||||||
.set_print_cmd(false)
|
.set_print_cmd(false)
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -367,6 +368,7 @@ pub fn performance_net_latency(control: &PerformanceTestControl) -> f64 {
|
|||||||
.default_disks()
|
.default_disks()
|
||||||
.args(&["--net", net_params.as_str()])
|
.args(&["--net", net_params.as_str()])
|
||||||
.capture_output()
|
.capture_output()
|
||||||
|
.verbosity(VerbosityLevel::Warn)
|
||||||
.set_print_cmd(false)
|
.set_print_cmd(false)
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -472,7 +474,12 @@ fn parse_boot_time_output(output: &[u8]) -> Result<f64, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn measure_boot_time(cmd: &mut GuestCommand, test_timeout: u32) -> Result<f64, Error> {
|
fn measure_boot_time(cmd: &mut GuestCommand, test_timeout: u32) -> Result<f64, Error> {
|
||||||
let mut child = cmd.capture_output().set_print_cmd(false).spawn().unwrap();
|
let mut child = cmd
|
||||||
|
.capture_output()
|
||||||
|
.verbosity(VerbosityLevel::Warn)
|
||||||
|
.set_print_cmd(false)
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
thread::sleep(Duration::new(test_timeout as u64, 0));
|
thread::sleep(Duration::new(test_timeout as u64, 0));
|
||||||
let _ = child.kill();
|
let _ = child.kill();
|
||||||
@@ -499,6 +506,10 @@ pub fn performance_boot_time(control: &PerformanceTestControl) -> f64 {
|
|||||||
let mut cmd = GuestCommand::new(&guest);
|
let mut cmd = GuestCommand::new(&guest);
|
||||||
|
|
||||||
let c = cmd
|
let c = cmd
|
||||||
|
.args(&[
|
||||||
|
"--cpus",
|
||||||
|
&format!("boot={}", control.num_boot_vcpus.unwrap_or(1)),
|
||||||
|
])
|
||||||
.args(&["--memory", "size=1G"])
|
.args(&["--memory", "size=1G"])
|
||||||
.args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
.args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||||
.args(&["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
.args(&["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
||||||
@@ -522,6 +533,10 @@ pub fn performance_boot_time_pmem(control: &PerformanceTestControl) -> f64 {
|
|||||||
let guest = performance_test_new_guest(Box::new(focal));
|
let guest = performance_test_new_guest(Box::new(focal));
|
||||||
let mut cmd = GuestCommand::new(&guest);
|
let mut cmd = GuestCommand::new(&guest);
|
||||||
let c = cmd
|
let c = cmd
|
||||||
|
.args(&[
|
||||||
|
"--cpus",
|
||||||
|
&format!("boot={}", control.num_boot_vcpus.unwrap_or(1)),
|
||||||
|
])
|
||||||
.args(&["--memory", "size=1G,hugepages=on"])
|
.args(&["--memory", "size=1G,hugepages=on"])
|
||||||
.args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
.args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||||
.args(&["--cmdline", "root=/dev/pmem0p1 console=ttyS0 quiet rw"])
|
.args(&["--cmdline", "root=/dev/pmem0p1 console=ttyS0 quiet rw"])
|
||||||
@@ -655,6 +670,7 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
|
|||||||
.default_net()
|
.default_net()
|
||||||
.args(&["--api-socket", &api_socket])
|
.args(&["--api-socket", &api_socket])
|
||||||
.capture_output()
|
.capture_output()
|
||||||
|
.verbosity(VerbosityLevel::Warn)
|
||||||
.set_print_cmd(false)
|
.set_print_cmd(false)
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ path = "src/qcow.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
libc = "0.2.123"
|
libc = "0.2.126"
|
||||||
log = "0.4.16"
|
log = "0.4.17"
|
||||||
remain = "0.2.2"
|
remain = "0.2.3"
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
|
|||||||
@@ -516,6 +516,19 @@ impl QcowFile {
|
|||||||
|
|
||||||
let l2_entries = cluster_size / size_of::<u64>() as u64;
|
let l2_entries = cluster_size / size_of::<u64>() as u64;
|
||||||
|
|
||||||
|
// Check for compressed blocks
|
||||||
|
for l2_addr_disk in l1_table.get_values() {
|
||||||
|
if *l2_addr_disk != 0 {
|
||||||
|
if let Err(e) = Self::read_l2_cluster(&mut raw_file, *l2_addr_disk) {
|
||||||
|
if let Some(os_error) = e.raw_os_error() {
|
||||||
|
if os_error == ENOTSUP {
|
||||||
|
return Err(Error::CompressedBlocksNotSupported);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut qcow = QcowFile {
|
let mut qcow = QcowFile {
|
||||||
raw_file,
|
raw_file,
|
||||||
header,
|
header,
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2.123"
|
libc = "0.2.126"
|
||||||
log = "0.4.16"
|
log = "0.4.17"
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ pub enum BucketReduction {
|
|||||||
|
|
||||||
/// TokenBucket provides a lower level interface to rate limiting with a
|
/// TokenBucket provides a lower level interface to rate limiting with a
|
||||||
/// configurable capacity, refill-rate and initial burst.
|
/// configurable capacity, refill-rate and initial burst.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct TokenBucket {
|
pub struct TokenBucket {
|
||||||
// Bucket defining traits.
|
// Bucket defining traits.
|
||||||
size: u64,
|
size: u64,
|
||||||
|
|||||||
221
release-notes.md
221
release-notes.md
@@ -1,11 +1,28 @@
|
|||||||
|
- [v25.0](#v250)
|
||||||
|
- [`ch-remote` Improvements](#ch-remote-improvements)
|
||||||
|
- [VM "Coredump" Support](#vm-coredump-support)
|
||||||
|
- [Notable Bug Fixes](#notable-bug-fixes)
|
||||||
|
- [Removals](#removals)
|
||||||
|
- [Contributors](#contributors)
|
||||||
|
- [v24.0](#v240)
|
||||||
|
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
|
||||||
|
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
|
||||||
|
- [Sparse Mmap support](#sparse-mmap-support)
|
||||||
|
- [Expose Platform Serial Number](#expose-platform-serial-number)
|
||||||
|
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
||||||
|
- [Notable Improvements](#notable-improvements)
|
||||||
|
- [Deprecations](#deprecations)
|
||||||
|
- [New on the Website](#new-on-the-website)
|
||||||
|
- [Contributors](#contributors-1)
|
||||||
|
- [v23.1](#v231)
|
||||||
- [v23.0](#v230)
|
- [v23.0](#v230)
|
||||||
- [vDPA Support](#vdpa-support)
|
- [vDPA Support](#vdpa-support)
|
||||||
- [Updated OS Support list](#updated-os-support-list)
|
- [Updated OS Support list](#updated-os-support-list)
|
||||||
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
|
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
|
||||||
- [`AMX` Support](#amx-support)
|
- [`AMX` Support](#amx-support)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes)
|
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
||||||
- [Deprecations](#deprecations)
|
- [Deprecations](#deprecations-1)
|
||||||
- [Contributors](#contributors)
|
- [Contributors](#contributors-2)
|
||||||
- [v22.1](#v221)
|
- [v22.1](#v221)
|
||||||
- [v22.0](#v220)
|
- [v22.0](#v220)
|
||||||
- [GDB Debug Stub Support](#gdb-debug-stub-support)
|
- [GDB Debug Stub Support](#gdb-debug-stub-support)
|
||||||
@@ -16,13 +33,13 @@
|
|||||||
- [PMU Support for AArch64](#pmu-support-for-aarch64)
|
- [PMU Support for AArch64](#pmu-support-for-aarch64)
|
||||||
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
|
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
|
||||||
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
|
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||||
- [Contributors](#contributors-1)
|
- [Contributors](#contributors-3)
|
||||||
- [v21.0](#v210)
|
- [v21.0](#v210)
|
||||||
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
|
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
|
||||||
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
|
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
|
||||||
- [Notable Bug fixes](#notable-bug-fixes-2)
|
- [Notable Bug fixes](#notable-bug-fixes-4)
|
||||||
- [Contributors](#contributors-2)
|
- [Contributors](#contributors-4)
|
||||||
- [v20.2](#v202)
|
- [v20.2](#v202)
|
||||||
- [v20.1](#v201)
|
- [v20.1](#v201)
|
||||||
- [v20.0](#v200)
|
- [v20.0](#v200)
|
||||||
@@ -31,8 +48,8 @@
|
|||||||
- [Improved VFIO support](#improved-vfio-support)
|
- [Improved VFIO support](#improved-vfio-support)
|
||||||
- [Safer code](#safer-code)
|
- [Safer code](#safer-code)
|
||||||
- [Extended documentation](#extended-documentation)
|
- [Extended documentation](#extended-documentation)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-3)
|
- [Notable bug fixes](#notable-bug-fixes-5)
|
||||||
- [Contributors](#contributors-3)
|
- [Contributors](#contributors-5)
|
||||||
- [v19.0](#v190)
|
- [v19.0](#v190)
|
||||||
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
|
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
|
||||||
- [PCI boot time optimisations](#pci-boot-time-optimisations)
|
- [PCI boot time optimisations](#pci-boot-time-optimisations)
|
||||||
@@ -40,8 +57,8 @@
|
|||||||
- [Live migration enhancements](#live-migration-enhancements)
|
- [Live migration enhancements](#live-migration-enhancements)
|
||||||
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
|
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
|
||||||
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
|
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-4)
|
- [Notable bug fixes](#notable-bug-fixes-6)
|
||||||
- [Contributors](#contributors-4)
|
- [Contributors](#contributors-6)
|
||||||
- [v18.0](#v180)
|
- [v18.0](#v180)
|
||||||
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
|
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
|
||||||
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
|
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
|
||||||
@@ -51,31 +68,31 @@
|
|||||||
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
||||||
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
||||||
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-5)
|
- [Notable bug fixes](#notable-bug-fixes-7)
|
||||||
- [Contributors](#contributors-5)
|
- [Contributors](#contributors-7)
|
||||||
- [v17.0](#v170)
|
- [v17.0](#v170)
|
||||||
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
|
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
|
||||||
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
|
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
|
||||||
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
|
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
|
||||||
- [Improved SGX support](#improved-sgx-support)
|
- [Improved SGX support](#improved-sgx-support)
|
||||||
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
|
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-6)
|
- [Notable bug fixes](#notable-bug-fixes-8)
|
||||||
- [Contributors](#contributors-6)
|
- [Contributors](#contributors-8)
|
||||||
- [v16.0](#v160)
|
- [v16.0](#v160)
|
||||||
- [Improved live migration support](#improved-live-migration-support)
|
- [Improved live migration support](#improved-live-migration-support)
|
||||||
- [Improved `vhost-user` support](#improved-vhost-user-support)
|
- [Improved `vhost-user` support](#improved-vhost-user-support)
|
||||||
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
|
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-7)
|
- [Notable bug fixes](#notable-bug-fixes-9)
|
||||||
- [Removed functionality](#removed-functionality)
|
- [Removed functionality](#removed-functionality)
|
||||||
- [Contributors](#contributors-7)
|
- [Contributors](#contributors-9)
|
||||||
- [v15.0](#v150)
|
- [v15.0](#v150)
|
||||||
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
||||||
- [Network device rate limiting](#network-device-rate-limiting)
|
- [Network device rate limiting](#network-device-rate-limiting)
|
||||||
- [Support for runtime control of `virtio-net` guest offload](#support-for-runtime-control-of-virtio-net-guest-offload)
|
- [Support for runtime control of `virtio-net` guest offload](#support-for-runtime-control-of-virtio-net-guest-offload)
|
||||||
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
||||||
- [Bug fixes](#bug-fixes)
|
- [Bug fixes](#bug-fixes)
|
||||||
- [Deprecations](#deprecations-1)
|
- [Deprecations](#deprecations-2)
|
||||||
- [Contributors](#contributors-8)
|
- [Contributors](#contributors-10)
|
||||||
- [v0.14.1](#v0141)
|
- [v0.14.1](#v0141)
|
||||||
- [v0.14.0](#v0140)
|
- [v0.14.0](#v0140)
|
||||||
- [Structured event monitoring](#structured-event-monitoring)
|
- [Structured event monitoring](#structured-event-monitoring)
|
||||||
@@ -84,8 +101,8 @@
|
|||||||
- [Updated hotplug documentation](#updated-hotplug-documentation)
|
- [Updated hotplug documentation](#updated-hotplug-documentation)
|
||||||
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
|
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
|
||||||
- [Block device rate limiting](#block-device-rate-limiting)
|
- [Block device rate limiting](#block-device-rate-limiting)
|
||||||
- [Deprecations](#deprecations-2)
|
- [Deprecations](#deprecations-3)
|
||||||
- [Contributors](#contributors-9)
|
- [Contributors](#contributors-11)
|
||||||
- [v0.13.0](#v0130)
|
- [v0.13.0](#v0130)
|
||||||
- [Wider VFIO device support](#wider-vfio-device-support)
|
- [Wider VFIO device support](#wider-vfio-device-support)
|
||||||
- [Improved huge page support](#improved-huge-page-support)
|
- [Improved huge page support](#improved-huge-page-support)
|
||||||
@@ -93,13 +110,13 @@
|
|||||||
- [VHD disk image support](#vhd-disk-image-support)
|
- [VHD disk image support](#vhd-disk-image-support)
|
||||||
- [Improved Virtio device threading](#improved-virtio-device-threading)
|
- [Improved Virtio device threading](#improved-virtio-device-threading)
|
||||||
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
|
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
|
||||||
- [Contributors](#contributors-10)
|
- [Contributors](#contributors-12)
|
||||||
- [v0.12.0](#v0120)
|
- [v0.12.0](#v0120)
|
||||||
- [ARM64 enhancements](#arm64-enhancements)
|
- [ARM64 enhancements](#arm64-enhancements)
|
||||||
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
|
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
|
||||||
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
|
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
|
||||||
- [Enhanced "info" API](#enhanced-info-api)
|
- [Enhanced "info" API](#enhanced-info-api)
|
||||||
- [Contributors](#contributors-11)
|
- [Contributors](#contributors-13)
|
||||||
- [v0.11.0](#v0110)
|
- [v0.11.0](#v0110)
|
||||||
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
|
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
|
||||||
- [Windows Guest Support](#windows-guest-support)
|
- [Windows Guest Support](#windows-guest-support)
|
||||||
@@ -111,15 +128,15 @@
|
|||||||
- [Default Log Level Changed](#default-log-level-changed)
|
- [Default Log Level Changed](#default-log-level-changed)
|
||||||
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
|
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
|
||||||
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
|
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-8)
|
- [Notable Bug Fixes](#notable-bug-fixes-10)
|
||||||
- [Contributors](#contributors-12)
|
- [Contributors](#contributors-14)
|
||||||
- [v0.10.0](#v0100)
|
- [v0.10.0](#v0100)
|
||||||
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
|
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
|
||||||
- [Memory Zones](#memory-zones)
|
- [Memory Zones](#memory-zones)
|
||||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
|
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
|
||||||
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
|
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-9)
|
- [Notable Bug Fixes](#notable-bug-fixes-11)
|
||||||
- [Contributors](#contributors-13)
|
- [Contributors](#contributors-15)
|
||||||
- [v0.9.0](#v090)
|
- [v0.9.0](#v090)
|
||||||
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
|
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
|
||||||
- [Block and Network Device Statistics](#block-and-network-device-statistics)
|
- [Block and Network Device Statistics](#block-and-network-device-statistics)
|
||||||
@@ -132,17 +149,17 @@
|
|||||||
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
|
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
|
||||||
- [Intel SGX Support](#intel-sgx-support)
|
- [Intel SGX Support](#intel-sgx-support)
|
||||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
|
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-10)
|
- [Notable Bug Fixes](#notable-bug-fixes-12)
|
||||||
- [Contributors](#contributors-14)
|
- [Contributors](#contributors-16)
|
||||||
- [v0.8.0](#v080)
|
- [v0.8.0](#v080)
|
||||||
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
|
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
|
||||||
- [Experimental ARM64 Support](#experimental-arm64-support)
|
- [Experimental ARM64 Support](#experimental-arm64-support)
|
||||||
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
|
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
|
||||||
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
|
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
|
||||||
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
|
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-11)
|
- [Notable Bug Fixes](#notable-bug-fixes-13)
|
||||||
- [Command Line and API Changes](#command-line-and-api-changes)
|
- [Command Line and API Changes](#command-line-and-api-changes)
|
||||||
- [Contributors](#contributors-15)
|
- [Contributors](#contributors-17)
|
||||||
- [v0.7.0](#v070)
|
- [v0.7.0](#v070)
|
||||||
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
|
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
|
||||||
- [Alternative `libc` Support](#alternative-libc-support)
|
- [Alternative `libc` Support](#alternative-libc-support)
|
||||||
@@ -152,14 +169,14 @@
|
|||||||
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
||||||
- [Updated Distribution Support](#updated-distribution-support)
|
- [Updated Distribution Support](#updated-distribution-support)
|
||||||
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
||||||
- [Contributors](#contributors-16)
|
- [Contributors](#contributors-18)
|
||||||
- [v0.6.0](#v060)
|
- [v0.6.0](#v060)
|
||||||
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
|
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
|
||||||
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
|
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
|
||||||
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
|
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
|
||||||
- [Command Line Interface](#command-line-interface)
|
- [Command Line Interface](#command-line-interface)
|
||||||
- [PVH Boot](#pvh-boot)
|
- [PVH Boot](#pvh-boot)
|
||||||
- [Contributors](#contributors-17)
|
- [Contributors](#contributors-19)
|
||||||
- [v0.5.1](#v051)
|
- [v0.5.1](#v051)
|
||||||
- [v0.5.0](#v050)
|
- [v0.5.0](#v050)
|
||||||
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
||||||
@@ -167,7 +184,7 @@
|
|||||||
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
||||||
- [Development Tools](#development-tools)
|
- [Development Tools](#development-tools)
|
||||||
- [Kata Containers Integration](#kata-containers-integration)
|
- [Kata Containers Integration](#kata-containers-integration)
|
||||||
- [Contributors](#contributors-18)
|
- [Contributors](#contributors-20)
|
||||||
- [v0.4.0](#v040)
|
- [v0.4.0](#v040)
|
||||||
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
||||||
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
||||||
@@ -176,7 +193,7 @@
|
|||||||
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
|
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
|
||||||
- [PCI BAR reprogramming](#pci-bar-reprogramming)
|
- [PCI BAR reprogramming](#pci-bar-reprogramming)
|
||||||
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
|
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
|
||||||
- [Contributors](#contributors-19)
|
- [Contributors](#contributors-21)
|
||||||
- [v0.3.0](#v030)
|
- [v0.3.0](#v030)
|
||||||
- [Block device offloading](#block-device-offloading)
|
- [Block device offloading](#block-device-offloading)
|
||||||
- [Network device backend](#network-device-backend)
|
- [Network device backend](#network-device-backend)
|
||||||
@@ -203,6 +220,140 @@
|
|||||||
- [Unit testing](#unit-testing)
|
- [Unit testing](#unit-testing)
|
||||||
- [Integration tests parallelization](#integration-tests-parallelization)
|
- [Integration tests parallelization](#integration-tests-parallelization)
|
||||||
|
|
||||||
|
# v25.0
|
||||||
|
|
||||||
|
This release has been tracked through the [v25.0
|
||||||
|
project](https://github.com/cloud-hypervisor/cloud-hypervisor/projects/29).
|
||||||
|
|
||||||
|
### `ch-remote` Improvements
|
||||||
|
|
||||||
|
The `ch-remote` command has gained support for creating the VM from a JSON
|
||||||
|
config and support for booting and deleting the VM from the VMM.
|
||||||
|
|
||||||
|
### VM "Coredump" Support
|
||||||
|
|
||||||
|
Under the `guest_debug` feature flag it is now possible to extract the memory
|
||||||
|
of the guest for use in debugging with e.g. the `crash` utility. (#4012)
|
||||||
|
|
||||||
|
### Notable Bug Fixes
|
||||||
|
|
||||||
|
* Always restore console mode on exit (#4249, #4248)
|
||||||
|
* Restore vCPUs in numerical order which fixes aarch64 snapshot/restore (#4244)
|
||||||
|
* Don't try and configure `IFF_RUNNING` on TAP devices (#4279)
|
||||||
|
* Propagate configured queue size through to vhost-user backend (#4286)
|
||||||
|
* Always Program vCPU CPUID before running the vCPU to fix running on Linux
|
||||||
|
5.16 (#4156)
|
||||||
|
* Enable ACPI MADT "Online Capable" flag for hotpluggable vCPUs to fix newer
|
||||||
|
Linux guest
|
||||||
|
|
||||||
|
### Removals
|
||||||
|
|
||||||
|
The following functionality has been removed:
|
||||||
|
|
||||||
|
* The `mergeable` option from the `virtio-pmem` support has been removed
|
||||||
|
(#3968)
|
||||||
|
* The `dax` option from the `virtio-fs` support has been removed (#3889)
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
Many thanks to everyone who has contributed to our release:
|
||||||
|
|
||||||
|
* Dylan Bargatze <dbargatz@users.noreply.github.com>
|
||||||
|
* Jinank Jain <jinankjain@microsoft.com>
|
||||||
|
* Michael Zhao <michael.zhao@arm.com>
|
||||||
|
* Rob Bradford <robert.bradford@intel.com>
|
||||||
|
* Sebastien Boeuf <sebastien.boeuf@intel.com>
|
||||||
|
* Wei Liu <liuwe@microsoft.com>
|
||||||
|
* Yi Wang <wang.yi59@zte.com.cn>
|
||||||
|
|
||||||
|
# v24.0
|
||||||
|
|
||||||
|
This release has been tracked through the [v24.0
|
||||||
|
project](https://github.com/cloud-hypervisor/cloud-hypervisor/projects/28).
|
||||||
|
|
||||||
|
### Bypass Mode for `virtio-iommu`
|
||||||
|
|
||||||
|
`virtio-iommu` specification describes how a device can be attached by default
|
||||||
|
to a bypass domain. This feature is particularly helpful for booting a VM with
|
||||||
|
guest software which doesn't support `virtio-iommu` but still need to access
|
||||||
|
the device. Now that Cloud Hypervisor supports this feature, it can boot a VM
|
||||||
|
with Rust Hypervisor Firmware or OVMF even if the `virtio-block` device exposing
|
||||||
|
the disk image is placed behind a virtual IOMMU.
|
||||||
|
|
||||||
|
### Ensure Identifiers Uniqueness
|
||||||
|
|
||||||
|
Multiple checks have been added to the code to prevent devices with identical
|
||||||
|
identifiers from being created, and therefore avoid unexpected behaviors at boot
|
||||||
|
or whenever a device was hot plugged into the VM.
|
||||||
|
|
||||||
|
### Sparse Mmap support
|
||||||
|
|
||||||
|
Sparse mmap support has been added to both VFIO and vfio-user devices. This
|
||||||
|
allows the device regions that are not fully mappable to be partially mapped.
|
||||||
|
And the more a device region can be mapped into the guest address space, the
|
||||||
|
fewer VM exits will be generated when this device is accessed. This directly
|
||||||
|
impacts the performance related to this device.
|
||||||
|
|
||||||
|
### Expose Platform Serial Number
|
||||||
|
|
||||||
|
A new `serial_number` option has been added to `--platform`, allowing a user to
|
||||||
|
set a specific serial number for the platform. This number is exposed to the
|
||||||
|
guest through the SMBIOS.
|
||||||
|
|
||||||
|
### Notable Bug Fixes
|
||||||
|
|
||||||
|
* Fix loading RAW firmware (#4072)
|
||||||
|
* Reject compressed QCOW images (#4055)
|
||||||
|
* Reject virtio-mem resize if device is not activated (#4003)
|
||||||
|
* Fix potential mmap leaks from VFIO/vfio-user MMIO regions (#4069)
|
||||||
|
* Fix algorithm finding HOB memory resources (#3983)
|
||||||
|
|
||||||
|
### Notable Improvements
|
||||||
|
|
||||||
|
* Refactor interrupt handling (#4083)
|
||||||
|
* Load kernel asynchronously (#4022)
|
||||||
|
* Only create ACPI memory manager DSDT when resizable (#4013)
|
||||||
|
|
||||||
|
### Deprecations
|
||||||
|
|
||||||
|
Deprecated features will be removed in a subsequent release and users should
|
||||||
|
plan to use alternatives
|
||||||
|
|
||||||
|
* The `mergeable` option from the `virtio-pmem` support has been deprecated
|
||||||
|
(#3968)
|
||||||
|
* The `dax` option from the `virtio-fs` support has been deprecated (#3889)
|
||||||
|
|
||||||
|
### New on the Website
|
||||||
|
|
||||||
|
A new blog post [Achieving Bare Metal Performance Within a Virtual
|
||||||
|
Machine](https://www.cloudhypervisor.org/blog/achieving-bare-metal-performance-within-a-virtual-machine)
|
||||||
|
has been added to the Cloud Hypervisor website.
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
Many thanks to everyone who has contributed to our release:
|
||||||
|
|
||||||
|
* Anatol Belski <anbelski@linux.microsoft.com>
|
||||||
|
* Bo Chen <chen.bo@intel.com>
|
||||||
|
* Fabiano Fidêncio <fabiano.fidencio@intel.com>
|
||||||
|
* LiHui <andrewli@kubesphere.io>
|
||||||
|
* Maksym Pavlenko <pavlenko.maksym@gmail.com>
|
||||||
|
* Rob Bradford <robert.bradford@intel.com>
|
||||||
|
* Sebastien Boeuf <sebastien.boeuf@intel.com>
|
||||||
|
* Steven Dake <steven.dake@gmail.com>
|
||||||
|
* Vincent Batts <vbatts@hashbangbash.com>
|
||||||
|
* Wei Liu <liuwe@microsoft.com>
|
||||||
|
|
||||||
|
# v23.1
|
||||||
|
|
||||||
|
This is a bug fix release. The following issues have been addressed:
|
||||||
|
|
||||||
|
* Add some missing seccomp rules
|
||||||
|
* Remove `virtio-fs` filesystem entries from config on removal
|
||||||
|
* Do not delete API socket on API server start (#4026)
|
||||||
|
* Reject `virtio-mem` resize if the guest doesn't activate the device
|
||||||
|
* Fix OpenAPI naming of I/O throttling knobs
|
||||||
|
|
||||||
# v23.0
|
# v23.0
|
||||||
|
|
||||||
This release has been tracked through the [v23.0
|
This release has been tracked through the [v23.0
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
FROM ubuntu:20.04 as dev
|
FROM ubuntu:20.04 as dev
|
||||||
|
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ARG RUST_TOOLCHAIN="1.59.0"
|
ARG RUST_TOOLCHAIN="1.62.0"
|
||||||
ARG CLH_SRC_DIR="/cloud-hypervisor"
|
ARG CLH_SRC_DIR="/cloud-hypervisor"
|
||||||
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
|
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
|
||||||
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"
|
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"
|
||||||
|
|||||||
@@ -1,25 +1,32 @@
|
|||||||
# This spec file assumes you're building on an environment where:
|
# If this flag is set to 1, rustup installation needs to exist on the system and
|
||||||
# * You have access to the internet during the build
|
# <arch>-unknown-linux-gnu target is required.
|
||||||
# * You have rustup installed on your system
|
# If this flag is set to 0, distro specific Rust packages will be pulled into the build environment.
|
||||||
# * You have both x86_64-unknown-linux-gnu and x86_64-unknown-linux-musl
|
|
||||||
# targets installed.
|
|
||||||
|
|
||||||
%define using_rustup 1
|
%define using_rustup 1
|
||||||
|
# If this flag is set to 1, <arch>-unknown-linux-musl target is required.
|
||||||
%define using_musl_libc 1
|
%define using_musl_libc 1
|
||||||
|
# If this flag is set to 1, the vendored crates archive and cargo.toml need to be prepared and
|
||||||
|
# offline build is implied. Attached script update_src can be used for the vendorization.
|
||||||
|
# If this flag is set to 0, access to the internet is required during the build.
|
||||||
|
%define using_vendored_crates 0
|
||||||
|
|
||||||
Name: cloud-hypervisor
|
Name: cloud-hypervisor
|
||||||
Summary: Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM.
|
Summary: Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM.
|
||||||
Version: 23.0
|
Version: 25.0
|
||||||
Release: 0%{?dist}
|
Release: 0%{?dist}
|
||||||
License: ASL 2.0 or BSD-3-clause
|
License: ASL 2.0 or BSD-3-clause
|
||||||
Group: Applications/System
|
Group: Applications/System
|
||||||
Source0: https://github.com/cloud-hypervisor/cloud-hypervisor/archive/v%{version}.tar.gz
|
Source0: https://github.com/cloud-hypervisor/cloud-hypervisor/archive/v%{version}.tar.gz
|
||||||
ExclusiveArch: x86_64
|
%if 0%{?using_vendored_crates}
|
||||||
|
Source1: vendor.tar.gz
|
||||||
|
Source2: config.toml
|
||||||
|
%endif
|
||||||
|
ExclusiveArch: x86_64 aarch64
|
||||||
|
|
||||||
BuildRequires: gcc
|
BuildRequires: gcc
|
||||||
BuildRequires: glibc-devel
|
BuildRequires: glibc-devel
|
||||||
BuildRequires: binutils
|
BuildRequires: binutils
|
||||||
BuildRequires: git
|
BuildRequires: git
|
||||||
|
BuildRequires: openssl-devel
|
||||||
|
|
||||||
%if ! 0%{?using_rustup}
|
%if ! 0%{?using_rustup}
|
||||||
BuildRequires: rust
|
BuildRequires: rust
|
||||||
@@ -31,29 +38,51 @@ Requires: glibc
|
|||||||
Requires: libgcc
|
Requires: libgcc
|
||||||
Requires: libcap
|
Requires: libcap
|
||||||
|
|
||||||
|
%ifarch x86_64
|
||||||
|
%define rust_def_target x86_64-unknown-linux-gnu
|
||||||
|
%if 0%{?using_musl_libc}
|
||||||
|
%define rust_musl_target x86_64-unknown-linux-musl
|
||||||
|
%endif
|
||||||
|
%endif
|
||||||
|
%ifarch aarch64
|
||||||
|
%define rust_def_target aarch64-unknown-linux-gnu
|
||||||
|
%if 0%{?using_musl_libc}
|
||||||
|
%define rust_musl_target aarch64-unknown-linux-musl
|
||||||
|
%endif
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%if 0%{?using_vendored_crates}
|
||||||
|
%define cargo_offline --offline
|
||||||
|
%endif
|
||||||
|
|
||||||
%description
|
%description
|
||||||
Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM. The project focuses on exclusively running modern, cloud workloads, on top of a limited set of hardware architectures and platforms. Cloud workloads refers to those that are usually run by customers inside a cloud provider. For our purposes this means modern Linux* distributions with most I/O handled by paravirtualised devices (i.e. virtio), no requirement for legacy devices and recent CPUs and KVM.
|
Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM. The project focuses on exclusively running modern, cloud workloads, on top of a limited set of hardware architectures and platforms. Cloud workloads refers to those that are usually run by customers inside a cloud provider. For our purposes this means modern Linux* distributions with most I/O handled by paravirtualised devices (i.e. virtio), no requirement for legacy devices and recent CPUs and KVM.
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
|
|
||||||
%setup -q
|
%setup -q
|
||||||
|
%if 0%{?using_vendored_crates}
|
||||||
|
tar xf %{SOURCE1}
|
||||||
|
mkdir -p .cargo
|
||||||
|
cp %{SOURCE2} .cargo/
|
||||||
|
%endif
|
||||||
|
|
||||||
%install
|
%install
|
||||||
rm -rf %{buildroot}
|
rm -rf %{buildroot}
|
||||||
install -d %{buildroot}%{_bindir}
|
install -d %{buildroot}%{_bindir}
|
||||||
install -D -m755 ./target/x86_64-unknown-linux-gnu/release/cloud-hypervisor %{buildroot}%{_bindir}
|
install -D -m755 ./target/%{rust_def_target}/release/cloud-hypervisor %{buildroot}%{_bindir}
|
||||||
install -D -m755 ./target/x86_64-unknown-linux-gnu/release/ch-remote %{buildroot}%{_bindir}
|
install -D -m755 ./target/%{rust_def_target}/release/ch-remote %{buildroot}%{_bindir}
|
||||||
install -d %{buildroot}%{_libdir}
|
install -d %{buildroot}%{_libdir}
|
||||||
install -d %{buildroot}%{_libdir}/cloud-hypervisor
|
install -d %{buildroot}%{_libdir}/cloud-hypervisor
|
||||||
install -D -m755 target/x86_64-unknown-linux-gnu/release/vhost_user_block %{buildroot}%{_libdir}/cloud-hypervisor
|
install -D -m755 target/%{rust_def_target}/release/vhost_user_block %{buildroot}%{_libdir}/cloud-hypervisor
|
||||||
install -D -m755 target/x86_64-unknown-linux-gnu/release/vhost_user_net %{buildroot}%{_libdir}/cloud-hypervisor
|
install -D -m755 target/%{rust_def_target}/release/vhost_user_net %{buildroot}%{_libdir}/cloud-hypervisor
|
||||||
|
|
||||||
%if 0%{?using_musl_libc}
|
%if 0%{?using_musl_libc}
|
||||||
install -d %{buildroot}%{_libdir}/cloud-hypervisor/static
|
install -d %{buildroot}%{_libdir}/cloud-hypervisor/static
|
||||||
install -D -m755 target/x86_64-unknown-linux-musl/release/cloud-hypervisor %{buildroot}%{_libdir}/cloud-hypervisor/static
|
install -D -m755 target/%{rust_musl_target}/release/cloud-hypervisor %{buildroot}%{_libdir}/cloud-hypervisor/static
|
||||||
install -D -m755 target/x86_64-unknown-linux-musl/release/vhost_user_block %{buildroot}%{_libdir}/cloud-hypervisor/static
|
install -D -m755 target/%{rust_musl_target}/release/vhost_user_block %{buildroot}%{_libdir}/cloud-hypervisor/static
|
||||||
install -D -m755 target/x86_64-unknown-linux-musl/release/vhost_user_net %{buildroot}%{_libdir}/cloud-hypervisor/static
|
install -D -m755 target/%{rust_musl_target}/release/vhost_user_net %{buildroot}%{_libdir}/cloud-hypervisor/static
|
||||||
install -D -m755 target/x86_64-unknown-linux-musl/release/ch-remote %{buildroot}%{_libdir}/cloud-hypervisor/static
|
install -D -m755 target/%{rust_musl_target}/release/ch-remote %{buildroot}%{_libdir}/cloud-hypervisor/static
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
|
||||||
@@ -74,21 +103,25 @@ fi
|
|||||||
echo ${cargo_version}
|
echo ${cargo_version}
|
||||||
|
|
||||||
%if 0%{?using_rustup}
|
%if 0%{?using_rustup}
|
||||||
rustup target list --installed | grep x86_64-unknown-linux-gnu
|
rustup target list --installed | grep -e "%{rust_def_target}"
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
echo "Target x86_64-unknown-linux-gnu not found, please install(#rustup target add x86_64-unknown-linux-gnu). exiting"
|
echo "Target %{rust_def_target} not found, please install(#rustup target add %{rust_def_target}). exiting"
|
||||||
fi
|
fi
|
||||||
%if 0%{?using_musl_libc}
|
%if 0%{?using_musl_libc}
|
||||||
rustup target list --installed | grep x86_64-unknown-linux-musl
|
rustup target list --installed | grep -e "%{rust_musl_target}"
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
echo "Target x86_64-unknown-linux-musl not found, please install(#rustup target add x86_64-unknown-linux-musl). exiting"
|
echo "Target %{rust_musl_target} not found, please install(#rustup target add %{rust_musl_target}). exiting"
|
||||||
fi
|
fi
|
||||||
%endif
|
%endif
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
cargo build --release --target=x86_64-unknown-linux-gnu --all
|
%if 0%{?using_vendored_crates}
|
||||||
|
# For vendored build, prepend this so openssl-sys doesn't trigger full OpenSSL build
|
||||||
|
export OPENSSL_NO_VENDOR=1
|
||||||
|
%endif
|
||||||
|
cargo build --release --target=%{rust_def_target} --all %{cargo_offline}
|
||||||
%if 0%{?using_musl_libc}
|
%if 0%{?using_musl_libc}
|
||||||
cargo build --release --target=x86_64-unknown-linux-musl --all
|
cargo build --release --target=%{rust_musl_target} --all %{cargo_offline}
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
|
||||||
@@ -112,6 +145,18 @@ rm -rf %{buildroot}
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu Jul 07 2022 Rob Bradford <robert.bradford@intel.com> 25.0-0
|
||||||
|
- Update to 25.0
|
||||||
|
|
||||||
|
* Wed May 25 2022 Sebastien Boeuf <sebastien.boeuf@intel.com> 24.0-0
|
||||||
|
- Update to 24.0
|
||||||
|
|
||||||
|
* Tue May 18 2022 Anatol Belski <anbelski@linux.microsoft.com> - 23.1-0
|
||||||
|
- Update to 23.1
|
||||||
|
- Add support for aarch64 build
|
||||||
|
- Add offline build configuration using vendored crates
|
||||||
|
- Fix dependency for openssl-sys
|
||||||
|
|
||||||
* Thu Apr 13 2022 Rob Bradford <robert.bradford@intel.com> 23.0-0
|
* Thu Apr 13 2022 Rob Bradford <robert.bradford@intel.com> 23.0-0
|
||||||
- Update to 23.0
|
- Update to 23.0
|
||||||
|
|
||||||
|
|||||||
36
rpm/update_src
Normal file
36
rpm/update_src
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CH_VER=$1
|
||||||
|
CH_SPEC_DIR=$(pwd)
|
||||||
|
CH_TMP_DIR=$CH_SPEC_DIR/ch_tmp
|
||||||
|
CH_SRC_DIR=$CH_SPEC_DIR/SOURCES
|
||||||
|
|
||||||
|
if [ -z $CH_VER ]; then
|
||||||
|
echo "Replace sources with the given <version>"
|
||||||
|
echo "Usage: $0 <version>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf $CH_TMP_DIR
|
||||||
|
if [ ! -d $CH_SRC_DIR ]; then
|
||||||
|
mkdir $CH_SRC_DIR
|
||||||
|
fi
|
||||||
|
rm -f $CH_SRC_DIR/v*.tar.gz $CH_SRC_DIR/config.toml $CH_SRC_DIR/vendor.tar.gz
|
||||||
|
|
||||||
|
|
||||||
|
wget https://github.com/cloud-hypervisor/cloud-hypervisor/archive/v${CH_VER}.tar.gz -O $CH_SRC_DIR/v${CH_VER}.tar.gz
|
||||||
|
mkdir $CH_TMP_DIR
|
||||||
|
tar xf $CH_SRC_DIR/v${CH_VER}.tar.gz -C $CH_TMP_DIR --strip-components=1
|
||||||
|
|
||||||
|
|
||||||
|
pushd $CH_TMP_DIR
|
||||||
|
|
||||||
|
cargo vendor > $CH_SRC_DIR/config.toml
|
||||||
|
tar czvf $CH_SRC_DIR/vendor.tar.gz vendor
|
||||||
|
|
||||||
|
popd
|
||||||
|
|
||||||
|
rm -rf $CH_TMP_DIR
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
CLI_NAME="Cloud Hypervisor"
|
CLI_NAME="Cloud Hypervisor"
|
||||||
|
|
||||||
CTR_IMAGE_TAG="cloudhypervisor/dev"
|
CTR_IMAGE_TAG="cloudhypervisor/dev"
|
||||||
CTR_IMAGE_VERSION="20220405-0"
|
CTR_IMAGE_VERSION="20220705-0"
|
||||||
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
|
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
|
||||||
|
|
||||||
DOCKER_RUNTIME="docker"
|
DOCKER_RUNTIME="docker"
|
||||||
@@ -226,6 +226,11 @@ cmd_build() {
|
|||||||
} ;;
|
} ;;
|
||||||
"--debug") { build="debug"; } ;;
|
"--debug") { build="debug"; } ;;
|
||||||
"--release") { build="release"; } ;;
|
"--release") { build="release"; } ;;
|
||||||
|
"--runtime")
|
||||||
|
shift
|
||||||
|
DOCKER_RUNTIME="$1"
|
||||||
|
export DOCKER_RUNTIME
|
||||||
|
;;
|
||||||
"--libc")
|
"--libc")
|
||||||
shift
|
shift
|
||||||
[[ "$1" =~ ^(musl|gnu)$ ]] ||
|
[[ "$1" =~ ^(musl|gnu)$ ]] ||
|
||||||
|
|||||||
@@ -192,6 +192,15 @@ update_workloads() {
|
|||||||
fi
|
fi
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
# Download Cloud Hypervisor binary from its last stable release
|
||||||
|
LAST_RELEASE_VERSION="v23.0"
|
||||||
|
CH_RELEASE_URL="https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$LAST_RELEASE_VERSION/cloud-hypervisor-static-aarch64"
|
||||||
|
CH_RELEASE_NAME="cloud-hypervisor-static-aarch64"
|
||||||
|
pushd $WORKLOADS_DIR
|
||||||
|
time wget --quiet $CH_RELEASE_URL -O "$CH_RELEASE_NAME" || exit 1
|
||||||
|
chmod +x $CH_RELEASE_NAME
|
||||||
|
popd
|
||||||
|
|
||||||
# Build custom kernel for guest VMs
|
# Build custom kernel for guest VMs
|
||||||
build_custom_linux
|
build_custom_linux
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,15 @@ if [ $? -ne 0 ]; then
|
|||||||
fi
|
fi
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
# Download Cloud Hypervisor binary from its last stable release
|
||||||
|
LAST_RELEASE_VERSION="v23.0"
|
||||||
|
CH_RELEASE_URL="https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$LAST_RELEASE_VERSION/cloud-hypervisor-static"
|
||||||
|
CH_RELEASE_NAME="cloud-hypervisor-static"
|
||||||
|
pushd $WORKLOADS_DIR
|
||||||
|
time wget --quiet $CH_RELEASE_URL -O "$CH_RELEASE_NAME" || exit 1
|
||||||
|
chmod +x $CH_RELEASE_NAME
|
||||||
|
popd
|
||||||
|
|
||||||
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
||||||
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
|
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
|
||||||
|
|
||||||
|
|||||||
@@ -113,6 +113,9 @@ if [ -n "$test_filter" ]; then
|
|||||||
test_binary_args+=("--test-filter $test_filter")
|
test_binary_args+=("--test-filter $test_filter")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Ensure that git commands can be run in this directory (for metrics report)
|
||||||
|
git config --global --add safe.directory $PWD
|
||||||
|
|
||||||
export RUST_BACKTRACE=1
|
export RUST_BACKTRACE=1
|
||||||
time target/$BUILD_TARGET/release/performance-metrics ${test_binary_args[*]}
|
time target/$BUILD_TARGET/release/performance-metrics ${test_binary_args[*]}
|
||||||
RES=$?
|
RES=$?
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ cargo_args=("")
|
|||||||
if [[ $hypervisor = "mshv" ]]; then
|
if [[ $hypervisor = "mshv" ]]; then
|
||||||
cargo_args+=("--no-default-features")
|
cargo_args+=("--no-default-features")
|
||||||
cargo_args+=("--features common,$hypervisor")
|
cargo_args+=("--features common,$hypervisor")
|
||||||
|
elif [[ $(uname -m) = "x86_64" ]]; then
|
||||||
|
cargo_args+=("--features tdx")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
|
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use api_client::Error as ApiClientError;
|
|||||||
use clap::{Arg, ArgMatches, Command};
|
use clap::{Arg, ArgMatches, Command};
|
||||||
use option_parser::{ByteSized, ByteSizedParseError};
|
use option_parser::{ByteSized, ByteSizedParseError};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::io::Read;
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
@@ -31,6 +32,8 @@ enum Error {
|
|||||||
AddVdpaConfig(vmm::config::Error),
|
AddVdpaConfig(vmm::config::Error),
|
||||||
AddVsockConfig(vmm::config::Error),
|
AddVsockConfig(vmm::config::Error),
|
||||||
Restore(vmm::config::Error),
|
Restore(vmm::config::Error),
|
||||||
|
ReadingStdin(std::io::Error),
|
||||||
|
ReadingFile(std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
@@ -51,6 +54,8 @@ impl fmt::Display for Error {
|
|||||||
AddVdpaConfig(e) => write!(f, "Error parsing vDPA device syntax: {}", e),
|
AddVdpaConfig(e) => write!(f, "Error parsing vDPA device syntax: {}", e),
|
||||||
AddVsockConfig(e) => write!(f, "Error parsing vsock syntax: {}", e),
|
AddVsockConfig(e) => write!(f, "Error parsing vsock syntax: {}", e),
|
||||||
Restore(e) => write!(f, "Error parsing restore syntax: {}", e),
|
Restore(e) => write!(f, "Error parsing restore syntax: {}", e),
|
||||||
|
ReadingStdin(e) => write!(f, "Error reading from stdin: {}", e),
|
||||||
|
ReadingFile(e) => write!(f, "Error reading from file: {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,6 +269,20 @@ fn restore_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Erro
|
|||||||
.map_err(Error::ApiClient)
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn coredump_api_command(socket: &mut UnixStream, destination_url: &str) -> Result<(), Error> {
|
||||||
|
let coredump_config = vmm::api::VmCoredumpData {
|
||||||
|
destination_url: String::from(destination_url),
|
||||||
|
};
|
||||||
|
|
||||||
|
simple_api_command(
|
||||||
|
socket,
|
||||||
|
"PUT",
|
||||||
|
"coredump",
|
||||||
|
Some(&serde_json::to_string(&coredump_config).unwrap()),
|
||||||
|
)
|
||||||
|
.map_err(Error::ApiClient)
|
||||||
|
}
|
||||||
|
|
||||||
fn receive_migration_api_command(socket: &mut UnixStream, url: &str) -> Result<(), Error> {
|
fn receive_migration_api_command(socket: &mut UnixStream, url: &str) -> Result<(), Error> {
|
||||||
let receive_migration_data = vmm::api::VmReceiveMigrationData {
|
let receive_migration_data = vmm::api::VmReceiveMigrationData {
|
||||||
receiver_url: url.to_owned(),
|
receiver_url: url.to_owned(),
|
||||||
@@ -295,6 +314,19 @@ fn send_migration_api_command(
|
|||||||
.map_err(Error::ApiClient)
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_api_command(socket: &mut UnixStream, path: &str) -> Result<(), Error> {
|
||||||
|
let mut data = String::default();
|
||||||
|
if path == "-" {
|
||||||
|
std::io::stdin()
|
||||||
|
.read_to_string(&mut data)
|
||||||
|
.map_err(Error::ReadingStdin)?;
|
||||||
|
} else {
|
||||||
|
data = std::fs::read_to_string(path).map_err(Error::ReadingFile)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_api_command(socket, "PUT", "create", Some(&data)).map_err(Error::ApiClient)
|
||||||
|
}
|
||||||
|
|
||||||
fn do_command(matches: &ArgMatches) -> Result<(), Error> {
|
fn do_command(matches: &ArgMatches) -> Result<(), Error> {
|
||||||
let mut socket =
|
let mut socket =
|
||||||
UnixStream::connect(matches.value_of("api-socket").unwrap()).map_err(Error::Connect)?;
|
UnixStream::connect(matches.value_of("api-socket").unwrap()).map_err(Error::Connect)?;
|
||||||
@@ -422,6 +454,14 @@ fn do_command(matches: &ArgMatches) -> Result<(), Error> {
|
|||||||
.value_of("restore_config")
|
.value_of("restore_config")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
|
Some("coredump") => coredump_api_command(
|
||||||
|
&mut socket,
|
||||||
|
matches
|
||||||
|
.subcommand_matches("coredump")
|
||||||
|
.unwrap()
|
||||||
|
.value_of("coredump_config")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
Some("send-migration") => send_migration_api_command(
|
Some("send-migration") => send_migration_api_command(
|
||||||
&mut socket,
|
&mut socket,
|
||||||
matches
|
matches
|
||||||
@@ -442,6 +482,14 @@ fn do_command(matches: &ArgMatches) -> Result<(), Error> {
|
|||||||
.value_of("receive_migration_config")
|
.value_of("receive_migration_config")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
|
Some("create") => create_api_command(
|
||||||
|
&mut socket,
|
||||||
|
matches
|
||||||
|
.subcommand_matches("create")
|
||||||
|
.unwrap()
|
||||||
|
.value_of("path")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
Some(c) => simple_api_command(&mut socket, "PUT", c, None).map_err(Error::ApiClient),
|
Some(c) => simple_api_command(&mut socket, "PUT", c, None).map_err(Error::ApiClient),
|
||||||
None => unreachable!(),
|
None => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -576,6 +624,8 @@ fn main() {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(Command::new("resume").about("Resume the VM"))
|
.subcommand(Command::new("resume").about("Resume the VM"))
|
||||||
|
.subcommand(Command::new("boot").about("Boot a created VM"))
|
||||||
|
.subcommand(Command::new("delete").about("Delete a VM"))
|
||||||
.subcommand(Command::new("shutdown").about("Shutdown the VM"))
|
.subcommand(Command::new("shutdown").about("Shutdown the VM"))
|
||||||
.subcommand(
|
.subcommand(
|
||||||
Command::new("snapshot")
|
Command::new("snapshot")
|
||||||
@@ -595,6 +645,11 @@ fn main() {
|
|||||||
.help(vmm::config::RestoreConfig::SYNTAX),
|
.help(vmm::config::RestoreConfig::SYNTAX),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.subcommand(
|
||||||
|
Command::new("coredump")
|
||||||
|
.about("Create a coredump from VM")
|
||||||
|
.arg(Arg::new("coredump_config").index(1).help("<file_path>")),
|
||||||
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
Command::new("send-migration")
|
Command::new("send-migration")
|
||||||
.about("Initiate a VM migration")
|
.about("Initiate a VM migration")
|
||||||
@@ -617,6 +672,11 @@ fn main() {
|
|||||||
.index(1)
|
.index(1)
|
||||||
.help("<receiver_url>"),
|
.help("<receiver_url>"),
|
||||||
),
|
),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
Command::new("create")
|
||||||
|
.about("Create VM from a JSON configuration")
|
||||||
|
.arg(Arg::new("path").index(1).default_value("-")),
|
||||||
);
|
);
|
||||||
|
|
||||||
let matches = app.get_matches();
|
let matches = app.get_matches();
|
||||||
|
|||||||
44
src/main.rs
44
src/main.rs
@@ -23,6 +23,7 @@ use thiserror::Error;
|
|||||||
use vmm::config;
|
use vmm::config;
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
use vmm_sys_util::signal::block_signal;
|
use vmm_sys_util::signal::block_signal;
|
||||||
|
use vmm_sys_util::terminal::Terminal;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
enum Error {
|
enum Error {
|
||||||
@@ -161,7 +162,7 @@ fn create_app<'a>(
|
|||||||
Arg::new("platform")
|
Arg::new("platform")
|
||||||
.long("platform")
|
.long("platform")
|
||||||
.help(
|
.help(
|
||||||
"num_pci_segments=<num pci segments>,iommu_segments=<list_of_segments>",
|
"num_pci_segments=<num pci segments>,iommu_segments=<list_of_segments>,serial_number=<(DMI) device serial number>",
|
||||||
)
|
)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
@@ -623,6 +624,13 @@ fn main() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let on_tty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
|
||||||
|
if on_tty {
|
||||||
|
// Don't forget to set the terminal in canonical mode
|
||||||
|
// before to exit.
|
||||||
|
std::io::stdin().lock().set_canon_mode().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
std::process::exit(exit_code);
|
std::process::exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1323,40 +1331,6 @@ mod unit_tests {
|
|||||||
}"#,
|
}"#,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
(
|
|
||||||
vec![
|
|
||||||
"cloud-hypervisor",
|
|
||||||
"--kernel",
|
|
||||||
"/path/to/kernel",
|
|
||||||
"--pmem",
|
|
||||||
"file=/path/to/img/1,size=1G,mergeable=on",
|
|
||||||
],
|
|
||||||
r#"{
|
|
||||||
"kernel": {"path": "/path/to/kernel"},
|
|
||||||
"pmem": [
|
|
||||||
{"file": "/path/to/img/1", "size": 1073741824, "mergeable": true}
|
|
||||||
]
|
|
||||||
}"#,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
(
|
|
||||||
vec![
|
|
||||||
"cloud-hypervisor",
|
|
||||||
"--kernel",
|
|
||||||
"/path/to/kernel",
|
|
||||||
"--pmem",
|
|
||||||
"file=/path/to/img/1,size=1G,mergeable=off",
|
|
||||||
],
|
|
||||||
r#"{
|
|
||||||
"kernel": {"path": "/path/to/kernel"},
|
|
||||||
"pmem": [
|
|
||||||
{"file": "/path/to/img/1", "size": 1073741824, "mergeable": false}
|
|
||||||
]
|
|
||||||
}"#,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|(cli, openapi, equal)| {
|
.for_each(|(cli, openapi, equal)| {
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
epoll = "4.3.1"
|
epoll = "4.3.1"
|
||||||
lazy_static = "1.4.0"
|
libc = "0.2.126"
|
||||||
libc = "0.2.123"
|
once_cell = "1.13.0"
|
||||||
ssh2 = { version = "0.9.1", features = ["vendored-openssl"]}
|
ssh2 = { version = "0.9.1", features = ["vendored-openssl"]}
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
wait-timeout = "0.2.0"
|
wait-timeout = "0.2.0"
|
||||||
|
|||||||
@@ -3,12 +3,11 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
#[macro_use]
|
use once_cell::sync::Lazy;
|
||||||
extern crate lazy_static;
|
|
||||||
|
|
||||||
use ssh2::Session;
|
use ssh2::Session;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
|
use std::fmt::Debug;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
@@ -51,7 +50,7 @@ pub struct GuestNetworkConfig {
|
|||||||
|
|
||||||
pub const DEFAULT_TCP_LISTENER_MESSAGE: &str = "booted";
|
pub const DEFAULT_TCP_LISTENER_MESSAGE: &str = "booted";
|
||||||
pub const DEFAULT_TCP_LISTENER_PORT: u16 = 8000;
|
pub const DEFAULT_TCP_LISTENER_PORT: u16 = 8000;
|
||||||
pub const DEFAULT_TCP_LISTENER_TIMEOUT: i32 = 80;
|
pub const DEFAULT_TCP_LISTENER_TIMEOUT: i32 = 120;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum WaitForBootError {
|
pub enum WaitForBootError {
|
||||||
@@ -721,9 +720,7 @@ pub fn exec_host_command_output(command: &str) -> Output {
|
|||||||
|
|
||||||
pub const PIPE_SIZE: i32 = 32 << 20;
|
pub const PIPE_SIZE: i32 = 32 << 20;
|
||||||
|
|
||||||
lazy_static! {
|
static NEXT_VM_ID: Lazy<Mutex<u8>> = Lazy::new(|| Mutex::new(1));
|
||||||
static ref NEXT_VM_ID: Mutex<u8> = Mutex::new(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Guest {
|
pub struct Guest {
|
||||||
pub tmp_dir: TempDir,
|
pub tmp_dir: TempDir,
|
||||||
@@ -831,30 +828,12 @@ impl Guest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn api_create_body(
|
pub fn api_create_body(&self, cpu_count: u8, kernel_path: &str, kernel_cmd: &str) -> String {
|
||||||
&self,
|
|
||||||
cpu_count: u8,
|
|
||||||
_fw_path: &str,
|
|
||||||
_kernel_path: &str,
|
|
||||||
_kernel_cmd: &str,
|
|
||||||
) -> String {
|
|
||||||
#[cfg(all(target_arch = "x86_64", not(feature = "mshv")))]
|
|
||||||
format! {"{{\"cpus\":{{\"boot_vcpus\":{},\"max_vcpus\":{}}},\"kernel\":{{\"path\":\"{}\"}},\"cmdline\":{{\"args\": \"\"}},\"net\":[{{\"ip\":\"{}\", \"mask\":\"255.255.255.0\", \"mac\":\"{}\"}}], \"disks\":[{{\"path\":\"{}\"}}, {{\"path\":\"{}\"}}]}}",
|
|
||||||
cpu_count,
|
|
||||||
cpu_count,
|
|
||||||
_fw_path,
|
|
||||||
self.network.host_ip,
|
|
||||||
self.network.guest_mac,
|
|
||||||
self.disk_config.disk(DiskType::OperatingSystem).unwrap().as_str(),
|
|
||||||
self.disk_config.disk(DiskType::CloudInit).unwrap().as_str(),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(target_arch = "aarch64", feature = "mshv"))]
|
|
||||||
format! {"{{\"cpus\":{{\"boot_vcpus\":{},\"max_vcpus\":{}}},\"kernel\":{{\"path\":\"{}\"}},\"cmdline\":{{\"args\": \"{}\"}},\"net\":[{{\"ip\":\"{}\", \"mask\":\"255.255.255.0\", \"mac\":\"{}\"}}], \"disks\":[{{\"path\":\"{}\"}}, {{\"path\":\"{}\"}}]}}",
|
format! {"{{\"cpus\":{{\"boot_vcpus\":{},\"max_vcpus\":{}}},\"kernel\":{{\"path\":\"{}\"}},\"cmdline\":{{\"args\": \"{}\"}},\"net\":[{{\"ip\":\"{}\", \"mask\":\"255.255.255.0\", \"mac\":\"{}\"}}], \"disks\":[{{\"path\":\"{}\"}}, {{\"path\":\"{}\"}}]}}",
|
||||||
cpu_count,
|
cpu_count,
|
||||||
cpu_count,
|
cpu_count,
|
||||||
_kernel_path,
|
kernel_path,
|
||||||
_kernel_cmd,
|
kernel_cmd,
|
||||||
self.network.host_ip,
|
self.network.host_ip,
|
||||||
self.network.guest_mac,
|
self.network.guest_mac,
|
||||||
self.disk_config.disk(DiskType::OperatingSystem).unwrap().as_str(),
|
self.disk_config.disk(DiskType::OperatingSystem).unwrap().as_str(),
|
||||||
@@ -984,13 +963,6 @@ impl Guest {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_entropy(&self) -> Result<u32, Error> {
|
|
||||||
self.ssh_command("cat /proc/sys/kernel/random/entropy_avail")?
|
|
||||||
.trim()
|
|
||||||
.parse()
|
|
||||||
.map_err(Error::Parsing)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_pci_bridge_class(&self) -> Result<String, Error> {
|
pub fn get_pci_bridge_class(&self) -> Result<String, Error> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.ssh_command("cat /sys/bus/pci/devices/0000:00:00.0/class")?
|
.ssh_command("cat /sys/bus/pci/devices/0000:00:00.0/class")?
|
||||||
@@ -1036,50 +1008,6 @@ impl Guest {
|
|||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn valid_virtio_fs_cache_size(
|
|
||||||
&self,
|
|
||||||
dax: bool,
|
|
||||||
cache_size: Option<u64>,
|
|
||||||
) -> Result<bool, Error> {
|
|
||||||
// SHM region is called different things depending on kernel
|
|
||||||
let shm_region = self
|
|
||||||
.ssh_command("sudo grep 'virtio[0-9]\\|virtio-pci-shm' /proc/iomem || true")?
|
|
||||||
.trim()
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
if shm_region.is_empty() {
|
|
||||||
return Ok(!dax);
|
|
||||||
}
|
|
||||||
|
|
||||||
// From this point, the region is not empty, hence it is an error
|
|
||||||
// if DAX is off.
|
|
||||||
if !dax {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
let cache = if let Some(cache) = cache_size {
|
|
||||||
cache
|
|
||||||
} else {
|
|
||||||
// 8Gib by default
|
|
||||||
0x0002_0000_0000
|
|
||||||
};
|
|
||||||
|
|
||||||
let args: Vec<&str> = shm_region.split(':').collect();
|
|
||||||
if args.is_empty() {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
let args: Vec<&str> = args[0].trim().split('-').collect();
|
|
||||||
if args.len() != 2 {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
let start_addr = u64::from_str_radix(args[0], 16).map_err(Error::Parsing)?;
|
|
||||||
let end_addr = u64::from_str_radix(args[1], 16).map_err(Error::Parsing)?;
|
|
||||||
|
|
||||||
Ok(cache == (end_addr - start_addr + 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check_vsock(&self, socket: &str) {
|
pub fn check_vsock(&self, socket: &str) {
|
||||||
// Listen from guest on vsock CID=3 PORT=16
|
// Listen from guest on vsock CID=3 PORT=16
|
||||||
// SOCKET-LISTEN:<domain>:<protocol>:<local-address>
|
// SOCKET-LISTEN:<domain>:<protocol>:<local-address>
|
||||||
@@ -1159,7 +1087,12 @@ impl Guest {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_devices_common(&self, socket: Option<&String>, console_text: Option<&String>) {
|
pub fn check_devices_common(
|
||||||
|
&self,
|
||||||
|
socket: Option<&String>,
|
||||||
|
console_text: Option<&String>,
|
||||||
|
pmem_path: Option<&String>,
|
||||||
|
) {
|
||||||
// Check block devices are readable
|
// Check block devices are readable
|
||||||
self.ssh_command("sudo dd if=/dev/vda of=/dev/null bs=1M iflag=direct count=1024")
|
self.ssh_command("sudo dd if=/dev/vda of=/dev/null bs=1M iflag=direct count=1024")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -1178,6 +1111,63 @@ impl Guest {
|
|||||||
self.ssh_command(&console_cmd).unwrap();
|
self.ssh_command(&console_cmd).unwrap();
|
||||||
}
|
}
|
||||||
// The net device is 'automatically' exercised through the above 'ssh' commands
|
// The net device is 'automatically' exercised through the above 'ssh' commands
|
||||||
|
|
||||||
|
// Check if the pmem device is usable
|
||||||
|
if let Some(pmem_path) = pmem_path {
|
||||||
|
assert_eq!(
|
||||||
|
self.ssh_command(&format!("ls {}", pmem_path))
|
||||||
|
.unwrap()
|
||||||
|
.trim(),
|
||||||
|
pmem_path
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
self.ssh_command(&format!("sudo mount {} /mnt", pmem_path))
|
||||||
|
.unwrap(),
|
||||||
|
""
|
||||||
|
);
|
||||||
|
assert_eq!(self.ssh_command("ls /mnt").unwrap(), "lost+found\n");
|
||||||
|
self.ssh_command("echo test123 | sudo tee /mnt/test")
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(self.ssh_command("sudo umount /mnt").unwrap(), "");
|
||||||
|
assert_eq!(self.ssh_command("ls /mnt").unwrap(), "");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
self.ssh_command(&format!("sudo mount {} /mnt", pmem_path))
|
||||||
|
.unwrap(),
|
||||||
|
""
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
self.ssh_command("sudo cat /mnt/test || true")
|
||||||
|
.unwrap()
|
||||||
|
.trim(),
|
||||||
|
"test123"
|
||||||
|
);
|
||||||
|
self.ssh_command("sudo rm /mnt/test").unwrap();
|
||||||
|
assert_eq!(self.ssh_command("sudo umount /mnt").unwrap(), "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum VerbosityLevel {
|
||||||
|
Warn,
|
||||||
|
Info,
|
||||||
|
Debug,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VerbosityLevel {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Warn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToString for VerbosityLevel {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
use VerbosityLevel::*;
|
||||||
|
match self {
|
||||||
|
Warn => "".to_string(),
|
||||||
|
Info => "-v".to_string(),
|
||||||
|
Debug => "-vv".to_string(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1186,22 +1176,29 @@ pub struct GuestCommand<'a> {
|
|||||||
guest: &'a Guest,
|
guest: &'a Guest,
|
||||||
capture_output: bool,
|
capture_output: bool,
|
||||||
print_cmd: bool,
|
print_cmd: bool,
|
||||||
|
verbosity: VerbosityLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GuestCommand<'a> {
|
impl<'a> GuestCommand<'a> {
|
||||||
pub fn new(guest: &'a Guest) -> Self {
|
pub fn new(guest: &'a Guest) -> Self {
|
||||||
Self::new_with_binary_name(guest, "cloud-hypervisor")
|
Self::new_with_binary_path(guest, &clh_command("cloud-hypervisor"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_binary_name(guest: &'a Guest, binary_name: &str) -> Self {
|
pub fn new_with_binary_path(guest: &'a Guest, binary_path: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
command: Command::new(clh_command(binary_name)),
|
command: Command::new(binary_path),
|
||||||
guest,
|
guest,
|
||||||
capture_output: false,
|
capture_output: false,
|
||||||
print_cmd: true,
|
print_cmd: true,
|
||||||
|
verbosity: VerbosityLevel::Info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn verbosity(&mut self, verbosity: VerbosityLevel) -> &mut Self {
|
||||||
|
self.verbosity = verbosity;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn capture_output(&mut self) -> &mut Self {
|
pub fn capture_output(&mut self) -> &mut Self {
|
||||||
self.capture_output = true;
|
self.capture_output = true;
|
||||||
self
|
self
|
||||||
@@ -1213,6 +1210,17 @@ impl<'a> GuestCommand<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn(&mut self) -> io::Result<Child> {
|
pub fn spawn(&mut self) -> io::Result<Child> {
|
||||||
|
use VerbosityLevel::*;
|
||||||
|
match &self.verbosity {
|
||||||
|
Warn => {}
|
||||||
|
Info => {
|
||||||
|
self.command.arg("-v");
|
||||||
|
}
|
||||||
|
Debug => {
|
||||||
|
self.command.arg("-vv");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if self.print_cmd {
|
if self.print_cmd {
|
||||||
println!(
|
println!(
|
||||||
"\n\n==== Start cloud-hypervisor command-line ====\n\n\
|
"\n\n==== Start cloud-hypervisor command-line ====\n\n\
|
||||||
@@ -1225,7 +1233,6 @@ impl<'a> GuestCommand<'a> {
|
|||||||
if self.capture_output {
|
if self.capture_output {
|
||||||
let child = self
|
let child = self
|
||||||
.command
|
.command
|
||||||
.arg("-v")
|
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
@@ -1245,7 +1252,7 @@ impl<'a> GuestCommand<'a> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.command.arg("-v").spawn()
|
self.command.spawn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1168
tests/integration.rs
1168
tests/integration.rs
File diff suppressed because it is too large
Load Diff
@@ -5,14 +5,14 @@ authors = ["The Cloud Hypervisor Authors"]
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.56"
|
anyhow = "1.0.58"
|
||||||
libc = "0.2.123"
|
libc = "0.2.126"
|
||||||
log = "0.4.16"
|
log = "0.4.17"
|
||||||
serde = {version = ">=1.0.27", features = ["rc"] }
|
serde = {version = ">=1.0.27", features = ["rc"] }
|
||||||
serde_derive = ">=1.0.27"
|
serde_derive = ">=1.0.27"
|
||||||
serde_json = ">=1.0.9"
|
serde_json = ">=1.0.9"
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.31"
|
||||||
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic"] }
|
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic"] }
|
||||||
vmm-sys-util = ">=0.3.1"
|
vmm-sys-util = ">=0.3.1"
|
||||||
|
|
||||||
[dependencies.vfio-bindings]
|
[dependencies.vfio-bindings]
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
use std::fs::File;
|
||||||
use std::io::{IoSlice, Read, Write};
|
use std::io::{IoSlice, Read, Write};
|
||||||
|
use std::mem::size_of;
|
||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
use std::os::unix::prelude::RawFd;
|
use std::os::unix::prelude::RawFd;
|
||||||
@@ -49,7 +51,7 @@ impl Default for Command {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
enum HeaderFlags {
|
enum HeaderFlags {
|
||||||
Command = 0,
|
Command = 0,
|
||||||
Reply = 1,
|
Reply = 1,
|
||||||
@@ -234,6 +236,7 @@ pub struct Region {
|
|||||||
pub index: u32,
|
pub index: u32,
|
||||||
pub size: u64,
|
pub size: u64,
|
||||||
pub file_offset: Option<FileOffset>,
|
pub file_offset: Option<FileOffset>,
|
||||||
|
pub sparse_areas: Vec<vfio_region_sparse_mmap_area>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -294,7 +297,7 @@ impl Client {
|
|||||||
message_id: self.next_message_id.0,
|
message_id: self.next_message_id.0,
|
||||||
command: Command::Version,
|
command: Command::Version,
|
||||||
flags: HeaderFlags::Command as u32,
|
flags: HeaderFlags::Command as u32,
|
||||||
message_size: (std::mem::size_of::<Version>() + version_data.len() + 1) as u32,
|
message_size: (size_of::<Version>() + version_data.len() + 1) as u32,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
major: 0,
|
major: 0,
|
||||||
@@ -330,7 +333,7 @@ impl Client {
|
|||||||
|
|
||||||
let mut server_version_data = Vec::new();
|
let mut server_version_data = Vec::new();
|
||||||
server_version_data.resize(
|
server_version_data.resize(
|
||||||
server_version.header.message_size as usize - std::mem::size_of::<Version>(),
|
server_version.header.message_size as usize - size_of::<Version>(),
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
self.stream
|
self.stream
|
||||||
@@ -361,10 +364,10 @@ impl Client {
|
|||||||
message_id: self.next_message_id.0,
|
message_id: self.next_message_id.0,
|
||||||
command: Command::DmaMap,
|
command: Command::DmaMap,
|
||||||
flags: HeaderFlags::Command as u32,
|
flags: HeaderFlags::Command as u32,
|
||||||
message_size: std::mem::size_of::<DmaMap>() as u32,
|
message_size: size_of::<DmaMap>() as u32,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
argsz: (std::mem::size_of::<DmaMap>() - std::mem::size_of::<Header>()) as u32,
|
argsz: (size_of::<DmaMap>() - size_of::<Header>()) as u32,
|
||||||
flags: DmaMapFlags::ReadWrite,
|
flags: DmaMapFlags::ReadWrite,
|
||||||
offset,
|
offset,
|
||||||
address,
|
address,
|
||||||
@@ -391,10 +394,10 @@ impl Client {
|
|||||||
message_id: self.next_message_id.0,
|
message_id: self.next_message_id.0,
|
||||||
command: Command::DmaUnmap,
|
command: Command::DmaUnmap,
|
||||||
flags: HeaderFlags::Command as u32,
|
flags: HeaderFlags::Command as u32,
|
||||||
message_size: std::mem::size_of::<DmaUnmap>() as u32,
|
message_size: size_of::<DmaUnmap>() as u32,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
argsz: (std::mem::size_of::<DmaUnmap>() - std::mem::size_of::<Header>()) as u32,
|
argsz: (size_of::<DmaUnmap>() - size_of::<Header>()) as u32,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
address,
|
address,
|
||||||
size,
|
size,
|
||||||
@@ -420,7 +423,7 @@ impl Client {
|
|||||||
message_id: self.next_message_id.0,
|
message_id: self.next_message_id.0,
|
||||||
command: Command::DeviceReset,
|
command: Command::DeviceReset,
|
||||||
flags: HeaderFlags::Command as u32,
|
flags: HeaderFlags::Command as u32,
|
||||||
message_size: std::mem::size_of::<DeviceReset>() as u32,
|
message_size: size_of::<DeviceReset>() as u32,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -445,10 +448,10 @@ impl Client {
|
|||||||
message_id: self.next_message_id.0,
|
message_id: self.next_message_id.0,
|
||||||
command: Command::DeviceGetInfo,
|
command: Command::DeviceGetInfo,
|
||||||
flags: HeaderFlags::Command as u32,
|
flags: HeaderFlags::Command as u32,
|
||||||
message_size: std::mem::size_of::<DeviceGetInfo>() as u32,
|
message_size: size_of::<DeviceGetInfo>() as u32,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
argsz: std::mem::size_of::<DeviceGetInfo>() as u32,
|
argsz: size_of::<DeviceGetInfo>() as u32,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
debug!("Command: {:?}", get_info);
|
debug!("Command: {:?}", get_info);
|
||||||
@@ -474,20 +477,62 @@ impl Client {
|
|||||||
let num_regions = reply.num_regions;
|
let num_regions = reply.num_regions;
|
||||||
let mut regions = Vec::new();
|
let mut regions = Vec::new();
|
||||||
for index in 0..num_regions {
|
for index in 0..num_regions {
|
||||||
let get_region_info = DeviceGetRegionInfo {
|
let (region_info, fd, sparse_areas) = self.get_region_info(index)?;
|
||||||
header: Header {
|
regions.push(Region {
|
||||||
message_id: self.next_message_id.0,
|
flags: region_info.flags,
|
||||||
command: Command::DeviceGetRegionInfo,
|
index: region_info.index,
|
||||||
flags: HeaderFlags::Command as u32,
|
size: region_info.size,
|
||||||
message_size: std::mem::size_of::<DeviceGetRegionInfo>() as u32,
|
file_offset: fd.map(|fd| FileOffset::new(fd, region_info.offset)),
|
||||||
..Default::default()
|
sparse_areas,
|
||||||
},
|
});
|
||||||
region_info: vfio_region_info {
|
}
|
||||||
argsz: 1024, // Arbitrary max size
|
|
||||||
index,
|
Ok(regions)
|
||||||
..Default::default()
|
}
|
||||||
},
|
|
||||||
};
|
fn get_region_info(
|
||||||
|
&mut self,
|
||||||
|
index: u32,
|
||||||
|
) -> Result<
|
||||||
|
(
|
||||||
|
vfio_region_info,
|
||||||
|
Option<File>,
|
||||||
|
Vec<vfio_region_sparse_mmap_area>,
|
||||||
|
),
|
||||||
|
Error,
|
||||||
|
> {
|
||||||
|
// Retrieve the region info without capability
|
||||||
|
let mut get_region_info = DeviceGetRegionInfo {
|
||||||
|
header: Header {
|
||||||
|
message_id: self.next_message_id.0,
|
||||||
|
command: Command::DeviceGetRegionInfo,
|
||||||
|
flags: HeaderFlags::Command as u32,
|
||||||
|
message_size: std::mem::size_of::<DeviceGetRegionInfo>() as u32,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
region_info: vfio_region_info {
|
||||||
|
argsz: size_of::<vfio_region_info>() as u32,
|
||||||
|
index,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
debug!("Command: {:?}", get_region_info);
|
||||||
|
self.next_message_id += Wrapping(1);
|
||||||
|
|
||||||
|
self.stream
|
||||||
|
.write_all(get_region_info.as_slice())
|
||||||
|
.map_err(Error::StreamWrite)?;
|
||||||
|
|
||||||
|
let mut reply = DeviceGetRegionInfo::default();
|
||||||
|
let (_, fd) = self
|
||||||
|
.stream
|
||||||
|
.recv_with_fd(reply.as_mut_slice())
|
||||||
|
.map_err(Error::ReceiveWithFd)?;
|
||||||
|
debug!("Reply: {:?}", reply);
|
||||||
|
|
||||||
|
// Retrieve the region info again with capabilities if needed
|
||||||
|
if reply.region_info.argsz > std::mem::size_of::<vfio_region_info>() as u32 {
|
||||||
|
get_region_info.region_info.argsz = reply.region_info.argsz;
|
||||||
debug!("Command: {:?}", get_region_info);
|
debug!("Command: {:?}", get_region_info);
|
||||||
self.next_message_id += Wrapping(1);
|
self.next_message_id += Wrapping(1);
|
||||||
|
|
||||||
@@ -502,24 +547,94 @@ impl Client {
|
|||||||
.map_err(Error::ReceiveWithFd)?;
|
.map_err(Error::ReceiveWithFd)?;
|
||||||
debug!("Reply: {:?}", reply);
|
debug!("Reply: {:?}", reply);
|
||||||
|
|
||||||
regions.push(Region {
|
let cap_size = reply.region_info.argsz - std::mem::size_of::<vfio_region_info>() as u32;
|
||||||
flags: reply.region_info.flags,
|
assert_eq!(
|
||||||
index: reply.region_info.index,
|
cap_size,
|
||||||
size: reply.region_info.size,
|
reply.header.message_size - size_of::<DeviceGetRegionInfo>() as u32
|
||||||
file_offset: fd.map(|fd| FileOffset::new(fd, reply.region_info.offset)),
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: Handle region with capabilities
|
|
||||||
let mut _cap_data = Vec::with_capacity(
|
|
||||||
reply.header.message_size as usize - std::mem::size_of::<DeviceGetRegionInfo>(),
|
|
||||||
);
|
);
|
||||||
_cap_data.resize(_cap_data.capacity(), 0u8);
|
let mut cap_data = Vec::with_capacity(cap_size as usize);
|
||||||
|
cap_data.resize(cap_data.capacity(), 0u8);
|
||||||
self.stream
|
self.stream
|
||||||
.read_exact(_cap_data.as_mut_slice())
|
.read_exact(cap_data.as_mut_slice())
|
||||||
.map_err(Error::StreamRead)?;
|
.map_err(Error::StreamRead)?;
|
||||||
|
|
||||||
|
let sparse_areas = Self::parse_region_caps(&cap_data, &reply.region_info)?;
|
||||||
|
|
||||||
|
Ok((reply.region_info, fd, sparse_areas))
|
||||||
|
} else {
|
||||||
|
Ok((reply.region_info, fd, Vec::new()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_region_caps(
|
||||||
|
cap_data: &[u8],
|
||||||
|
region_info: &vfio_region_info,
|
||||||
|
) -> Result<Vec<vfio_region_sparse_mmap_area>, Error> {
|
||||||
|
let mut sparse_areas: Vec<vfio_region_sparse_mmap_area> = Vec::new();
|
||||||
|
|
||||||
|
let cap_size = cap_data.len() as u32;
|
||||||
|
let cap_header_size = size_of::<vfio_info_cap_header>() as u32;
|
||||||
|
let mmap_cap_size = size_of::<vfio_region_info_cap_sparse_mmap>() as u32;
|
||||||
|
let mmap_area_size = size_of::<vfio_region_sparse_mmap_area>() as u32;
|
||||||
|
|
||||||
|
let cap_data_ptr = cap_data.as_ptr() as *const u8;
|
||||||
|
let mut region_info_offset = region_info.cap_offset;
|
||||||
|
while region_info_offset != 0 {
|
||||||
|
// calculate the offset from the begining of the cap_data based on the offset
|
||||||
|
// that is relative to the begining of the VFIO region info structure
|
||||||
|
let cap_offset = region_info_offset - size_of::<vfio_region_info>() as u32;
|
||||||
|
if cap_offset + cap_header_size > cap_size {
|
||||||
|
warn!(
|
||||||
|
"Unexpected end of cap data: 'cap_offset + cap_header_size > cap_size' \
|
||||||
|
cap_offset = {}, cap_header_size = {}, cap_size = {}",
|
||||||
|
cap_offset, cap_header_size, cap_size
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe because the `cap_data_ptr` is valid and the `cap_offset` is checked above
|
||||||
|
let cap_ptr = unsafe { cap_data_ptr.offset(cap_offset as isize) };
|
||||||
|
let cap_header = unsafe { &*(cap_ptr as *const vfio_info_cap_header) };
|
||||||
|
match cap_header.id as u32 {
|
||||||
|
VFIO_REGION_INFO_CAP_SPARSE_MMAP => {
|
||||||
|
if cap_offset + mmap_cap_size > cap_size {
|
||||||
|
warn!(
|
||||||
|
"Unexpected end of cap data: 'cap_offset + mmap_cap_size > cap_size' \
|
||||||
|
cap_offset = {}, mmap_cap_size = {}, cap_size = {}",
|
||||||
|
cap_offset, mmap_cap_size, cap_size
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Safe because the `cap_ptr` is valid and its size is also checked above
|
||||||
|
let sparse_mmap = unsafe {
|
||||||
|
&*(cap_ptr as *mut u8 as *const vfio_region_info_cap_sparse_mmap)
|
||||||
|
};
|
||||||
|
|
||||||
|
let area_num = sparse_mmap.nr_areas;
|
||||||
|
if cap_offset + mmap_cap_size + area_num * mmap_area_size > cap_size {
|
||||||
|
warn!("Unexpected end of cap data: 'cap_offset + mmap_cap_size + area_num * mmap_area_size > cap_size' \
|
||||||
|
cap_offset = {}, mmap_cap_size = {}, area_num = {}, mmap_area_size = {}, cap_size = {}",
|
||||||
|
cap_offset, mmap_cap_size, area_num, mmap_area_size, cap_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Safe because the `sparse_mmap` is valid and its size is also checked above
|
||||||
|
let areas =
|
||||||
|
unsafe { sparse_mmap.areas.as_slice(sparse_mmap.nr_areas as usize) };
|
||||||
|
for area in areas.iter() {
|
||||||
|
sparse_areas.push(*area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
warn!(
|
||||||
|
"Ignoring unsupported vfio region capability (id = '{}')",
|
||||||
|
cap_header.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
region_info_offset = cap_header.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(regions)
|
Ok(sparse_areas)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn region_read(&mut self, region: u32, offset: u64, data: &mut [u8]) -> Result<(), Error> {
|
pub fn region_read(&mut self, region: u32, offset: u64, data: &mut [u8]) -> Result<(), Error> {
|
||||||
@@ -528,7 +643,7 @@ impl Client {
|
|||||||
message_id: self.next_message_id.0,
|
message_id: self.next_message_id.0,
|
||||||
command: Command::RegionRead,
|
command: Command::RegionRead,
|
||||||
flags: HeaderFlags::Command as u32,
|
flags: HeaderFlags::Command as u32,
|
||||||
message_size: std::mem::size_of::<RegionAccess>() as u32,
|
message_size: size_of::<RegionAccess>() as u32,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
offset,
|
offset,
|
||||||
@@ -556,7 +671,7 @@ impl Client {
|
|||||||
message_id: self.next_message_id.0,
|
message_id: self.next_message_id.0,
|
||||||
command: Command::RegionWrite,
|
command: Command::RegionWrite,
|
||||||
flags: HeaderFlags::Command as u32,
|
flags: HeaderFlags::Command as u32,
|
||||||
message_size: (std::mem::size_of::<RegionAccess>() + data.len()) as u32,
|
message_size: (size_of::<RegionAccess>() + data.len()) as u32,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
offset,
|
offset,
|
||||||
@@ -588,10 +703,10 @@ impl Client {
|
|||||||
message_id: self.next_message_id.0,
|
message_id: self.next_message_id.0,
|
||||||
command: Command::GetIrqInfo,
|
command: Command::GetIrqInfo,
|
||||||
flags: HeaderFlags::Command as u32,
|
flags: HeaderFlags::Command as u32,
|
||||||
message_size: std::mem::size_of::<GetIrqInfo>() as u32,
|
message_size: size_of::<GetIrqInfo>() as u32,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
argsz: (std::mem::size_of::<GetIrqInfo>() - std::mem::size_of::<Header>()) as u32,
|
argsz: (size_of::<GetIrqInfo>() - size_of::<Header>()) as u32,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
index,
|
index,
|
||||||
count: 0,
|
count: 0,
|
||||||
@@ -629,10 +744,10 @@ impl Client {
|
|||||||
message_id: self.next_message_id.0,
|
message_id: self.next_message_id.0,
|
||||||
command: Command::SetIrqs,
|
command: Command::SetIrqs,
|
||||||
flags: HeaderFlags::Command as u32,
|
flags: HeaderFlags::Command as u32,
|
||||||
message_size: std::mem::size_of::<SetIrqs>() as u32,
|
message_size: size_of::<SetIrqs>() as u32,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
argsz: (std::mem::size_of::<SetIrqs>() - std::mem::size_of::<Header>()) as u32,
|
argsz: (size_of::<SetIrqs>() - size_of::<Header>()) as u32,
|
||||||
flags,
|
flags,
|
||||||
start,
|
start,
|
||||||
index,
|
index,
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ license = "Apache-2.0"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
crc32c = "0.6.3"
|
crc32c = "0.6.3"
|
||||||
libc = "0.2.123"
|
libc = "0.2.126"
|
||||||
log = "0.4.16"
|
log = "0.4.17"
|
||||||
remain = "0.2.2"
|
remain = "0.2.3"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
uuid = { version = "0.8.2", features = ["v4"] }
|
uuid = { version = "1.1.2", features = ["v4"] }
|
||||||
vmm-sys-util = ">=0.3.1"
|
vmm-sys-util = ">=0.3.1"
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user