mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
407 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
977a893d86 | ||
|
|
2c4f8d2218 | ||
|
|
4f37a273d9 | ||
|
|
d64a77a5c6 | ||
|
|
e0d05683ab | ||
|
|
387753ae1d | ||
|
|
951ad3495e | ||
|
|
0dbb2683e3 | ||
|
|
579710d3e0 | ||
|
|
4d8a73735b | ||
|
|
687d646c60 | ||
|
|
54e523c302 | ||
|
|
4737679661 | ||
|
|
9c5b404415 | ||
|
|
6e9d3eccd6 | ||
|
|
10b954e954 | ||
|
|
e4abf2ce6c | ||
|
|
ad07a275c5 | ||
|
|
a20041ba68 | ||
|
|
eed0c927fd | ||
|
|
fb5cbd966e | ||
|
|
25798a97b3 | ||
|
|
2752b07762 | ||
|
|
a2e72774a9 | ||
|
|
584d5c5596 | ||
|
|
828dbd5227 | ||
|
|
b2e88967e4 | ||
|
|
ea396afdfa | ||
|
|
bfe0e90671 | ||
|
|
282484120d | ||
|
|
4d52a84ef7 | ||
|
|
1bf083bf00 | ||
|
|
c50051a686 | ||
|
|
e475b12cf7 | ||
|
|
64e217cf39 | ||
|
|
968902dfec | ||
|
|
df3b20f472 | ||
|
|
6c142e35f7 | ||
|
|
32da33eacd | ||
|
|
5d53648762 | ||
|
|
7549149bb5 | ||
|
|
c2144b5690 | ||
|
|
0d01eac1d4 | ||
|
|
46c60183cd | ||
|
|
7b80709595 | ||
|
|
a1a0bc8592 | ||
|
|
92a506fb06 | ||
|
|
72eb533f56 | ||
|
|
66f0b5b2b6 | ||
|
|
d92707afc5 | ||
|
|
9a634f07cb | ||
|
|
d475b953b8 | ||
|
|
c331d6b8cd | ||
|
|
4ef4a22e02 | ||
|
|
ae1ffeacec | ||
|
|
79486d1964 | ||
|
|
19ed8b329a | ||
|
|
b30a95f69a | ||
|
|
63637eba31 | ||
|
|
d74a219add | ||
|
|
4e5cbd27bb | ||
|
|
bc7ffdce95 | ||
|
|
22d7398139 | ||
|
|
a90260ffb6 | ||
|
|
f3793c08b5 | ||
|
|
8841e63e2d | ||
|
|
4d673de0fb | ||
|
|
e877718b29 | ||
|
|
744b5799a3 | ||
|
|
b0d8b50b36 | ||
|
|
2349b7e753 | ||
|
|
45d698ae72 | ||
|
|
f9098af4e4 | ||
|
|
47091bd02c | ||
|
|
8fae21c10c | ||
|
|
0bd0a65b3a | ||
|
|
b82bb55927 | ||
|
|
e89345c2c2 | ||
|
|
2b513ece00 | ||
|
|
e1f35628e2 | ||
|
|
001ee6794c | ||
|
|
f840335922 | ||
|
|
183605f9e1 | ||
|
|
e9a1b75ee6 | ||
|
|
e3487c0146 | ||
|
|
b075aada8c | ||
|
|
4d2a4e2805 | ||
|
|
6233f6f68e | ||
|
|
c913f7da2f | ||
|
|
760031103e | ||
|
|
25ed8722c7 | ||
|
|
8f6a5f979d | ||
|
|
b8b16c6eec | ||
|
|
a969d5016c | ||
|
|
c8df576933 | ||
|
|
f3035a0f7a | ||
|
|
6c00f5514f | ||
|
|
8f31688fa3 | ||
|
|
756dd236b9 | ||
|
|
780e606f12 | ||
|
|
db557916a5 | ||
|
|
722523f925 | ||
|
|
16f52914e0 | ||
|
|
b347e192d3 | ||
|
|
ddf5a848d8 | ||
|
|
d3170a926f | ||
|
|
2f2e870ad1 | ||
|
|
a37424c011 | ||
|
|
02aa95a098 | ||
|
|
2a470d9a30 | ||
|
|
e965007514 | ||
|
|
98fc38c465 | ||
|
|
1fa3a60b35 | ||
|
|
5db4dede28 | ||
|
|
452af9b17c | ||
|
|
fc24f39507 | ||
|
|
3778bf8a8e | ||
|
|
9aba1fdee6 | ||
|
|
864a5e4fe0 | ||
|
|
7d38a1848b | ||
|
|
2d2463ce04 | ||
|
|
08ac3405f5 | ||
|
|
c7f75f9d59 | ||
|
|
620aaf234e | ||
|
|
86b2c17135 | ||
|
|
ce52fc97b9 | ||
|
|
754ce37031 | ||
|
|
8f7ed5fed7 | ||
|
|
af3bdb452a | ||
|
|
9d35a10fd4 | ||
|
|
ea5a050341 | ||
|
|
0bad764462 | ||
|
|
e7893b9a97 | ||
|
|
d13eea3ba1 | ||
|
|
1240ef3261 | ||
|
|
ed53c74ca9 | ||
|
|
0b5c680d15 | ||
|
|
6f436f02dc | ||
|
|
53b2e19934 | ||
|
|
f99462add4 | ||
|
|
1d403ea5d6 | ||
|
|
c9cc97e9a0 | ||
|
|
bcae6c41e3 | ||
|
|
f3197c3833 | ||
|
|
5a0a4bc505 | ||
|
|
165364e08b | ||
|
|
20aa811de7 | ||
|
|
ba8d3f2c1c | ||
|
|
6d34ed03f7 | ||
|
|
4918c1ca7f | ||
|
|
d278e9f39b | ||
|
|
7e06d36dee | ||
|
|
4735cb8563 | ||
|
|
a636411522 | ||
|
|
71c7dff32b | ||
|
|
db444715fd | ||
|
|
c85aa6dfae | ||
|
|
5a83ebce64 | ||
|
|
f65538b08f | ||
|
|
152a3b98c9 | ||
|
|
a738808604 | ||
|
|
06729bb3ba | ||
|
|
2c54c30435 | ||
|
|
adae986233 | ||
|
|
1c3f8236e7 | ||
|
|
204be8611c | ||
|
|
5e74848ab4 | ||
|
|
7935430f6b | ||
|
|
d3b32b3d6d | ||
|
|
3efccd0fef | ||
|
|
b28063a7b4 | ||
|
|
9254b74c6d | ||
|
|
7fbec7113e | ||
|
|
2e236c53c8 | ||
|
|
77e147f333 | ||
|
|
980c1f7b19 | ||
|
|
db2159b563 | ||
|
|
5b0d4bb398 | ||
|
|
f7f2f25a57 | ||
|
|
b4f887ea80 | ||
|
|
91b05b6186 | ||
|
|
ed1b12f9d0 | ||
|
|
c6dd9918d5 | ||
|
|
db102a2547 | ||
|
|
27a285257e | ||
|
|
447c986916 | ||
|
|
7fb980f17b | ||
|
|
5c6139bbff | ||
|
|
0411064271 | ||
|
|
e9637d3733 | ||
|
|
9d88e0b417 | ||
|
|
b3f5630c27 | ||
|
|
61994cdb14 | ||
|
|
c1b962048c | ||
|
|
79425b6aa8 | ||
|
|
2a1e33ee35 | ||
|
|
b02df13af9 | ||
|
|
b2cc45e0a3 | ||
|
|
deb4ad5e23 | ||
|
|
3dff598fa2 | ||
|
|
cdfc177347 | ||
|
|
51ceae9131 | ||
|
|
1997152ee1 | ||
|
|
a5f4d79547 | ||
|
|
2ff193456d | ||
|
|
ecc8382ff0 | ||
|
|
521a11a110 | ||
|
|
60d054519e | ||
|
|
dc35dac306 | ||
|
|
ec1f7189da | ||
|
|
f5353c5b08 | ||
|
|
2a76a589c3 | ||
|
|
22275c3462 | ||
|
|
d27ea34a2d | ||
|
|
a0e48a87b8 | ||
|
|
349dbb9aac | ||
|
|
9e0f402e27 | ||
|
|
673c539f40 | ||
|
|
504ccc32a0 | ||
|
|
8fb53eb167 | ||
|
|
c7d3992bbc | ||
|
|
83c44a2411 | ||
|
|
c597655d06 | ||
|
|
902fe20d41 | ||
|
|
eabcbb5159 | ||
|
|
e51e410e04 | ||
|
|
8363a44b51 | ||
|
|
edc9f25efa | ||
|
|
62b8955245 | ||
|
|
461e6da1dc | ||
|
|
4993a1653b | ||
|
|
73eb1b1ba1 | ||
|
|
3baa0c3721 | ||
|
|
81895b9b40 | ||
|
|
6492496cc2 | ||
|
|
fdecba6958 | ||
|
|
4abcb0a33c | ||
|
|
ccafab6983 | ||
|
|
382b37f8d1 | ||
|
|
d4b8c8308c | ||
|
|
1da37c7bb4 | ||
|
|
12db6e5068 | ||
|
|
0852287fee | ||
|
|
dcc646f5b1 | ||
|
|
91bd4ee8cc | ||
|
|
6761868a69 | ||
|
|
9ccd23ebb0 | ||
|
|
b00a6a8519 | ||
|
|
e7c9954dc1 | ||
|
|
2723995cfa | ||
|
|
ca09638491 | ||
|
|
0835198ddd | ||
|
|
6d9c1eb638 | ||
|
|
b4c2772031 | ||
|
|
9106afae38 | ||
|
|
f063346de3 | ||
|
|
5e0d498582 | ||
|
|
a33280b8ad | ||
|
|
ec0a0adaab | ||
|
|
49c72beda5 | ||
|
|
bcd45efdd3 | ||
|
|
1b2e51d4d9 | ||
|
|
5bcbd5607e | ||
|
|
02f2ecee61 | ||
|
|
4c840f04e1 | ||
|
|
e6db599907 | ||
|
|
72092a9733 | ||
|
|
624af4f9af | ||
|
|
2b7b26374a | ||
|
|
48d1a31e08 | ||
|
|
2ecced376e | ||
|
|
da4cde70c3 | ||
|
|
9af2968a7d | ||
|
|
0ac4545c5b | ||
|
|
2aa43d3554 | ||
|
|
3e482c9c74 | ||
|
|
05f7651cf5 | ||
|
|
569be6e706 | ||
|
|
972e96ea68 | ||
|
|
d4316d0228 | ||
|
|
e481f97550 | ||
|
|
3937e03c02 | ||
|
|
d68c388cac | ||
|
|
e60078d939 | ||
|
|
39bc444db4 | ||
|
|
e8bafd8caa | ||
|
|
50e0869a17 | ||
|
|
867016757e | ||
|
|
1365388f0b | ||
|
|
73cc443213 | ||
|
|
4e759ab437 | ||
|
|
8c0f2ae87c | ||
|
|
2b1173acc3 | ||
|
|
26b46ec435 | ||
|
|
2100f97cbc | ||
|
|
607fd3a8e5 | ||
|
|
429928057d | ||
|
|
7f507dd77d | ||
|
|
ea0918e5e8 | ||
|
|
6b710209b1 | ||
|
|
3987026997 | ||
|
|
9aedabe11e | ||
|
|
4a3cec8c1f | ||
|
|
3229fcc900 | ||
|
|
910313cfde | ||
|
|
5b8eed0e8c | ||
|
|
6cd6bb2755 | ||
|
|
613f74ca1e | ||
|
|
5effa20a5b | ||
|
|
17c99ae00a | ||
|
|
9ec0c981f8 | ||
|
|
3d4e27fa0a | ||
|
|
c46441c937 | ||
|
|
5b6d424a77 | ||
|
|
76ac0f1555 | ||
|
|
74950d07dd | ||
|
|
894a46f30c | ||
|
|
8744162a0e | ||
|
|
4da3bdcd6e | ||
|
|
95ca4fb15e | ||
|
|
6dcf9f6588 | ||
|
|
4440671739 | ||
|
|
957d3deeea | ||
|
|
6e63df98ba | ||
|
|
1f2915bff0 | ||
|
|
63b8d2eb58 | ||
|
|
71bbaf556f | ||
|
|
8819bb0f21 | ||
|
|
215372fd78 | ||
|
|
97b3c9b7b6 | ||
|
|
43f1a32859 | ||
|
|
b45264af75 | ||
|
|
d9680c4c51 | ||
|
|
28b80ba42a | ||
|
|
f40e8ce6b7 | ||
|
|
d494d6b837 | ||
|
|
48326ce731 | ||
|
|
054c036e81 | ||
|
|
5e42e0f1f7 | ||
|
|
81ec47b283 | ||
|
|
c101b1f558 | ||
|
|
efb0e5a49f | ||
|
|
e214bb9eed | ||
|
|
5cd82cb2e2 | ||
|
|
cff190fa5f | ||
|
|
7ba3eeda98 | ||
|
|
239e39ddbc | ||
|
|
5768dcc320 | ||
|
|
1075209e2a | ||
|
|
54c552f90d | ||
|
|
d330d91e1a | ||
|
|
3613b4c096 | ||
|
|
45c4d1a06e | ||
|
|
d4d62fc9dc | ||
|
|
c4be0f4235 | ||
|
|
5825ab2dd4 | ||
|
|
585269ecb9 | ||
|
|
5432cbfaad | ||
|
|
4d25eaa24a | ||
|
|
58461ce250 | ||
|
|
57762d4328 | ||
|
|
652e30c97d | ||
|
|
49e061d15b | ||
|
|
28ad84c207 | ||
|
|
b546afd196 | ||
|
|
6974b378f3 | ||
|
|
4d36ecef9e | ||
|
|
8a02cb3378 | ||
|
|
15112ae1b6 | ||
|
|
c93b7037b4 | ||
|
|
56c3073da4 | ||
|
|
cee5508e9b | ||
|
|
b56e1217b6 | ||
|
|
fb2e8b6817 | ||
|
|
a94fa77621 | ||
|
|
f0af934891 | ||
|
|
dc15e44e2a | ||
|
|
a36ac96444 | ||
|
|
09c3ddd47d | ||
|
|
07f3075773 | ||
|
|
acc71c4eda | ||
|
|
4c22592c6f | ||
|
|
9708019312 | ||
|
|
14c0e8424b | ||
|
|
3c0f06c09c | ||
|
|
2c576ab312 | ||
|
|
3fed07419a | ||
|
|
aa27f0e743 | ||
|
|
a6fe4aa7e9 | ||
|
|
de7cfd61a0 | ||
|
|
1ff4d4e3ae | ||
|
|
744e9d06e5 | ||
|
|
428c637506 | ||
|
|
f67ae9b47e | ||
|
|
251708b908 | ||
|
|
40f73e4fa1 | ||
|
|
62e1721c52 | ||
|
|
57f70c0761 | ||
|
|
0699dc1000 | ||
|
|
2e3e64a4cf | ||
|
|
36d336841c | ||
|
|
bfd4aa2fed | ||
|
|
f060ecd705 | ||
|
|
5363cee847 | ||
|
|
31e4d80caf | ||
|
|
c7f69cc0df | ||
|
|
ee118152ff |
11
.github/workflows/build.yaml
vendored
11
.github/workflows/build.yaml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
|
||||
- name: Debug Check (default features)
|
||||
run: |
|
||||
git rev-list origin/master..$GITHUB_SHA | xargs -t -I % sh -c 'git checkout %; cargo check --all --target=${{ matrix.target }}'
|
||||
git rev-list origin/main..$GITHUB_SHA | xargs -t -I % sh -c 'git checkout %; cargo check --all --target=${{ matrix.target }}'
|
||||
git checkout $GITHUB_SHA
|
||||
|
||||
- name: Build (acpi,kvm)
|
||||
@@ -39,6 +39,15 @@ jobs:
|
||||
|
||||
- name: Build (kvm)
|
||||
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "kvm" -- -D warnings
|
||||
|
||||
- name: Build (acpi,mshv)
|
||||
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "acpi,mshv" -- -D warnings
|
||||
|
||||
- name: Build (mshv)
|
||||
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "mshv" -- -D warnings
|
||||
|
||||
- name: Release Build (default features)
|
||||
run: cargo build --all --release --target=${{ matrix.target }}
|
||||
|
||||
- name: Check build did not modify any files
|
||||
run: test -z "$(git status --porcelain)"
|
||||
|
||||
2
.github/workflows/docker-image.yaml
vendored
2
.github/workflows/docker-image.yaml
vendored
@@ -2,7 +2,7 @@ name: Cloud-Hypervisor's Docker image update
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: master
|
||||
branches: main
|
||||
paths: resources/Dockerfile
|
||||
|
||||
jobs:
|
||||
|
||||
24
.github/workflows/quality-aarch64.yaml
vendored
24
.github/workflows/quality-aarch64.yaml
vendored
@@ -31,9 +31,31 @@ jobs:
|
||||
components: rustfmt, clippy
|
||||
- name: Formatting (rustfmt)
|
||||
run: cargo fmt -- --check
|
||||
|
||||
- name: Clippy (kvm)
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: true
|
||||
command: clippy
|
||||
args: --target=${{ matrix.target }} --no-default-features --features "kvm" -- -D warnings
|
||||
args: --target=${{ matrix.target }} --all --no-default-features --features "kvm" -- -D warnings
|
||||
|
||||
- name: Clippy (kvm,acpi)
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: true
|
||||
command: clippy
|
||||
args: --target=${{ matrix.target }} --all --no-default-features --features "kvm,acpi" -- -D warnings
|
||||
|
||||
- name: Clippy (all features,kvm)
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: true
|
||||
command: clippy
|
||||
args: --target=${{ matrix.target }} --all --no-default-features --features "common,kvm" -- -D warnings
|
||||
|
||||
- name: Clippy (default)
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: true
|
||||
command: clippy
|
||||
args: --target=${{ matrix.target }} --all -- -D warnings
|
||||
|
||||
3
.github/workflows/quality.yaml
vendored
3
.github/workflows/quality.yaml
vendored
@@ -56,3 +56,6 @@ jobs:
|
||||
|
||||
- name: Clippy (integration tests)
|
||||
run: cargo clippy --all --all-targets --tests --features "integration_tests" -- -D warnings
|
||||
|
||||
- name: Check build did not modify any files
|
||||
run: test -z "$(git status --porcelain)"
|
||||
|
||||
32
.github/workflows/release.yaml
vendored
32
.github/workflows/release.yaml
vendored
@@ -25,6 +25,18 @@ jobs:
|
||||
run: cargo build --all --release --target=x86_64-unknown-linux-musl
|
||||
- name: Strip cloud-hypervisor binaries
|
||||
run: strip target/*/release/cloud-hypervisor
|
||||
- name: Install Rust toolchain (aarch64-unknown-linux-musl)
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
target: aarch64-unknown-linux-musl
|
||||
override: true
|
||||
- name: Static Build (AArch64)
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: true
|
||||
command: build
|
||||
args: --all --release --target=aarch64-unknown-linux-musl
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
@@ -65,3 +77,23 @@ jobs:
|
||||
asset_path: target/x86_64-unknown-linux-gnu/release/ch-remote
|
||||
asset_name: ch-remote
|
||||
asset_content_type: application/octet-stream
|
||||
- name: Upload static AArch64 cloud-hypervisor
|
||||
id: upload-release-static-aarch64-cloud-hypervisor
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: target/aarch64-unknown-linux-musl/release/cloud-hypervisor
|
||||
asset_name: cloud-hypervisor-static-aarch64
|
||||
asset_content_type: application/octet-stream
|
||||
- name: Upload static AArch64 ch-remote
|
||||
id: upload-release-static-aarch64-ch-remote
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: target/aarch64-unknown-linux-musl/release/ch-remote
|
||||
asset_name: ch-remote-static-aarch64
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
@@ -55,7 +55,7 @@ you want to merge your changes to `cloud-hypervisor`:
|
||||
into your github organization.
|
||||
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/)
|
||||
against the master 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
|
||||
any comments and obtain minimum of 2 [maintainers](MAINTAINERS.md) approvals.
|
||||
To update your pull request amend existing commits whenever applicable and
|
||||
|
||||
240
Cargo.lock
generated
240
Cargo.lock
generated
@@ -11,9 +11,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.15.2"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a"
|
||||
checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
@@ -44,19 +44,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.40"
|
||||
version = "1.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
|
||||
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
|
||||
|
||||
[[package]]
|
||||
name = "api_client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.3.0"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e906254e445520903e7fc9da4f709886c84ae4bc4ddaf0e093188d66df4dc820"
|
||||
checksum = "b5ab7d9e73059c86c36473f459b52adbd99c3554a4fec492caef460806006f00"
|
||||
|
||||
[[package]]
|
||||
name = "arch"
|
||||
@@ -65,6 +68,7 @@ dependencies = [
|
||||
"acpi_tables",
|
||||
"anyhow",
|
||||
"byteorder",
|
||||
"fdt",
|
||||
"hypervisor",
|
||||
"libc",
|
||||
"linux-loader",
|
||||
@@ -76,6 +80,7 @@ dependencies = [
|
||||
"vm-fdt",
|
||||
"vm-memory",
|
||||
"vm-migration",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -97,9 +102,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.60"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7815ea54e4d821e791162e078acbebfd6d8c8939cd559c9335dceb1c8ca7282"
|
||||
checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
@@ -121,9 +126,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "block_util"
|
||||
@@ -136,6 +141,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"vhdx",
|
||||
"virtio-bindings",
|
||||
"vm-memory",
|
||||
"vm-virtio",
|
||||
@@ -150,9 +156,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.68"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
|
||||
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -184,7 +190,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cloud-hypervisor"
|
||||
version = "16.0.0"
|
||||
version = "18.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"api_client",
|
||||
@@ -199,7 +205,7 @@ dependencies = [
|
||||
"log",
|
||||
"net_util",
|
||||
"option_parser",
|
||||
"seccomp",
|
||||
"seccompiler",
|
||||
"serde_json",
|
||||
"signal-hook",
|
||||
"test_infra",
|
||||
@@ -219,6 +225,15 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32c"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "210cdf933e6a81212bfabf90cd8762f471b5922e5f6b709547673ad8e04b9448"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc64"
|
||||
version = "1.0.0"
|
||||
@@ -277,9 +292,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.8.3"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f"
|
||||
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
@@ -330,6 +345,12 @@ dependencies = [
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fdt"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.3"
|
||||
@@ -343,9 +364,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.24.0"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189"
|
||||
checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
@@ -355,9 +376,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.18"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -392,9 +413,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iced-x86"
|
||||
version = "1.11.3"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d907dfc273d9ed0da940e8145ceb77759056a1fb2110b44b83d1b203cddb906"
|
||||
checksum = "7383772b06135cede839b7270023b46403656a9148024886e721e82639d3f90e"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"static_assertions",
|
||||
@@ -402,9 +423,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "io-uring"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb82832e05cc4ca298f198a8db108837b4f7b7b1248e3cba8e48f151aece80cf"
|
||||
checksum = "8d75829ed9377bab6c90039fe47b9d84caceb4b5063266142e21bcce6550cda8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@@ -421,9 +442,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.7"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "kvm-bindings"
|
||||
@@ -454,9 +475,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.96"
|
||||
version = "0.2.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5600b4e6efc5421841a2138a6b082e07fe12f9aaa12783d50e5d13325b26b4fc"
|
||||
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
|
||||
|
||||
[[package]]
|
||||
name = "libssh2-sys"
|
||||
@@ -513,14 +534,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "micro_http"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#9b605a8b61df602cda62076d30d9f70307ea336f"
|
||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#36e59a083e76a2449e0f58e4283d201bc72fdf13"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"vmm-sys-util",
|
||||
@@ -539,7 +560,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mshv-bindings"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/cloud-hypervisor/mshv?branch=master#1024e9a821d33079452c20477b6ecb976ff795ad"
|
||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#0d6e4e82b9b575798de333e362129515e81049cb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"serde",
|
||||
@@ -551,7 +572,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mshv-ioctls"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/cloud-hypervisor/mshv?branch=master#1024e9a821d33079452c20477b6ecb976ff795ad"
|
||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#0d6e4e82b9b575798de333e362129515e81049cb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mshv-bindings",
|
||||
@@ -588,18 +609,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.25.2"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8bc1d42047cf336f0f939c99e97183cf31551bf0f2865a2ec9c8d91fd4ffb5e"
|
||||
checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.63"
|
||||
version = "0.9.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6b0d6fb7d80f877617dfcb014e605e2b5ab2fb0afdf27935219bb6bd984cb98"
|
||||
checksum = "1996d2d305e561b70d1ee0c53f1542833f4e1ac6ce9a6708b6ff2738ca67dc82"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
@@ -645,10 +666,12 @@ dependencies = [
|
||||
"hypervisor",
|
||||
"libc",
|
||||
"log",
|
||||
"thiserror",
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"vfio-bindings",
|
||||
"vfio-ioctls",
|
||||
"vfio_user",
|
||||
"vm-allocator",
|
||||
"vm-device",
|
||||
"vm-memory",
|
||||
@@ -752,9 +775,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.27"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
|
||||
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
@@ -796,9 +819,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.8"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@@ -810,7 +833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall 0.2.8",
|
||||
"redox_syscall 0.2.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -843,9 +866,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.19"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce"
|
||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
@@ -860,24 +892,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "seccomp"
|
||||
name = "seccompiler"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/firecracker-microvm/firecracker?tag=v0.24.4#8f44986a0e956a77f2b2324c12f73bec16130c82"
|
||||
source = "git+https://github.com/rust-vmm/seccompiler#da5788d52f1ae8886d8ed4624199b7e9fa64ac04"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.126"
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
|
||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.126"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
|
||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -886,9 +933,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.64"
|
||||
version = "1.0.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
||||
checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -897,9 +944,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.9"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "470c5a6397076fae0094aaf06a08e6ba6f37acb77d3b1b91ea92b4d6c8650c39"
|
||||
checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
@@ -946,9 +993,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.73"
|
||||
version = "1.0.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
|
||||
checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -957,9 +1004,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.4"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
|
||||
checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1010,18 +1057,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.25"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6"
|
||||
checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.25"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d"
|
||||
checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1045,12 +1092,15 @@ name = "uuid"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.13"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "025ce40a007e1907e58d5bc1a594def78e5573bb0b1160bc389634e8f12e4faa"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
@@ -1097,24 +1147,58 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio-ioctls"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=master#0f7eb6f855b80d60a7e09ac6df43b46ba69f9e9e"
|
||||
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=main#a8ee64b978ccd000df88732814d626651a091891"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"kvm-bindings",
|
||||
"kvm-ioctls",
|
||||
"log",
|
||||
"mshv-bindings",
|
||||
"mshv-ioctls",
|
||||
"vfio-bindings",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vfio_user"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"libc",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"vfio-bindings",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vhdx"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crc32c",
|
||||
"libc",
|
||||
"log",
|
||||
"remain",
|
||||
"thiserror",
|
||||
"uuid",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vhost"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vhost?branch=master#30ba3e7bbe9e0542cf480f44bc6845a8dbd2a6ba"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a6b90237e10f1a61b35fba73885c3567e1a5a8c40d44daae335f7710210a7dc"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
@@ -1138,6 +1222,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"block_util",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"epoll",
|
||||
"libc",
|
||||
"log",
|
||||
@@ -1155,6 +1240,7 @@ name = "vhost_user_net"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"env_logger",
|
||||
"epoll",
|
||||
"libc",
|
||||
"log",
|
||||
@@ -1190,7 +1276,7 @@ dependencies = [
|
||||
"net_util",
|
||||
"pci",
|
||||
"rate_limiter",
|
||||
"seccomp",
|
||||
"seccompiler",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
@@ -1232,12 +1318,13 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vm-fdt"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vm-fdt?branch=master#2e4ebdeb27be5b450b51b79fdeeeee3750d42182"
|
||||
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#06cbff3a0248ec654467a87b1be7c0bcf78a41a8"
|
||||
|
||||
[[package]]
|
||||
name = "vm-memory"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/rust-vmm/vm-memory?rev=5bd7138758183a73ac0da27ce40c004d95f1a7e9#5bd7138758183a73ac0da27ce40c004d95f1a7e9"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a8ebcb86ca457f9d6e14cf97009f679952eba42f0113de5db596e514cd0e43b"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"libc",
|
||||
@@ -1292,7 +1379,7 @@ dependencies = [
|
||||
"option_parser",
|
||||
"pci",
|
||||
"qcow",
|
||||
"seccomp",
|
||||
"seccompiler",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
@@ -1302,6 +1389,7 @@ dependencies = [
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"vfio-ioctls",
|
||||
"vhdx",
|
||||
"virtio-devices",
|
||||
"vm-allocator",
|
||||
"vm-device",
|
||||
@@ -1371,9 +1459,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.3.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6580539ad917b7c026220c4b3f2c08d52ce54d6ce0dc491e66002e35388fab46"
|
||||
checksum = "5e59ec1d2457bd6c0dd89b50e7d9d6b0b647809bf3f0a59ac85557046950b7b2"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
@@ -1381,9 +1469,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb"
|
||||
checksum = "0af017aca1fa6181f5dd7a802456fe6f7666ecdcc18d0910431f0fc89d474e51"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
|
||||
21
Cargo.toml
21
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cloud-hypervisor"
|
||||
version = "16.0.0"
|
||||
version = "18.0.0"
|
||||
authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
default-run = "cloud-hypervisor"
|
||||
@@ -13,22 +13,22 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.40"
|
||||
anyhow = "1.0.43"
|
||||
api_client = { path = "api_client" }
|
||||
clap = { version = "2.33.3", features = ["wrap_help"] }
|
||||
epoll = "4.3.1"
|
||||
event_monitor = { path = "event_monitor" }
|
||||
hypervisor = { path = "hypervisor" }
|
||||
libc = "0.2.96"
|
||||
libc = "0.2.101"
|
||||
log = { version = "0.4.14", features = ["std"] }
|
||||
option_parser = { path = "option_parser" }
|
||||
seccomp = { git = "https://github.com/firecracker-microvm/firecracker", tag = "v0.24.4" }
|
||||
serde_json = "1.0.64"
|
||||
signal-hook = "0.3.9"
|
||||
thiserror = "1.0.25"
|
||||
seccompiler = { git = "https://github.com/rust-vmm/seccompiler"}
|
||||
serde_json = "1.0.67"
|
||||
signal-hook = "0.3.10"
|
||||
thiserror = "1.0.29"
|
||||
vmm = { path = "vmm" }
|
||||
vmm-sys-util = "0.8.0"
|
||||
vm-memory = "0.5.0"
|
||||
vm-memory = "0.6.0"
|
||||
|
||||
[build-dependencies]
|
||||
clap = { version = "2.33.3", features = ["wrap_help"] }
|
||||
@@ -37,14 +37,13 @@ clap = { version = "2.33.3", features = ["wrap_help"] }
|
||||
[patch.crates-io]
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.4.0", features = ["with-serde", "fam-wrappers"] }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||
vm-memory = { git = "https://github.com/rust-vmm/vm-memory", rev = "5bd7138758183a73ac0da27ce40c004d95f1a7e9"}
|
||||
|
||||
[dev-dependencies]
|
||||
credibility = "0.1.3"
|
||||
dirs = "3.0.2"
|
||||
lazy_static= "1.4.0"
|
||||
net_util = { path = "net_util" }
|
||||
serde_json = "1.0.64"
|
||||
serde_json = "1.0.67"
|
||||
test_infra = { path = "test_infra" }
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
@@ -78,6 +77,8 @@ members = [
|
||||
"pci",
|
||||
"qcow",
|
||||
"rate_limiter",
|
||||
"vfio_user",
|
||||
"vhdx",
|
||||
"vhost_user_backend",
|
||||
"vhost_user_block",
|
||||
"vhost_user_net",
|
||||
|
||||
64
Jenkinsfile
vendored
64
Jenkinsfile
vendored
@@ -2,7 +2,7 @@ pipeline{
|
||||
agent none
|
||||
stages {
|
||||
stage ('Early checks') {
|
||||
agent { node { label 'master' } }
|
||||
agent { node { label 'built-in' } }
|
||||
stages {
|
||||
stage ('Check for RFC/WIP builds') {
|
||||
when {
|
||||
@@ -14,7 +14,7 @@ pipeline{
|
||||
}
|
||||
}
|
||||
stage ('Cancel older builds') {
|
||||
when { not { branch 'master' } }
|
||||
when { not { branch 'main' } }
|
||||
steps {
|
||||
cancelPreviousBuilds()
|
||||
}
|
||||
@@ -24,7 +24,7 @@ pipeline{
|
||||
stage ('Build') {
|
||||
parallel {
|
||||
stage ('Worker build') {
|
||||
agent { node { label 'groovy' } }
|
||||
agent { node { label 'hirsute' } }
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
steps {
|
||||
@@ -83,7 +83,7 @@ pipeline{
|
||||
}
|
||||
}
|
||||
stage ('Worker build (musl)') {
|
||||
agent { node { label 'groovy' } }
|
||||
agent { node { label 'hirsute' } }
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
steps {
|
||||
@@ -110,7 +110,7 @@ pipeline{
|
||||
agent { node { label 'bionic-sgx' } }
|
||||
when {
|
||||
beforeAgent true
|
||||
branch 'master'
|
||||
branch 'main'
|
||||
}
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
@@ -146,7 +146,7 @@ pipeline{
|
||||
agent { node { label 'bionic-vfio' } }
|
||||
when {
|
||||
beforeAgent true
|
||||
branch 'master'
|
||||
branch 'main'
|
||||
}
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
@@ -179,7 +179,10 @@ pipeline{
|
||||
}
|
||||
}
|
||||
stage ('Worker build - Windows guest') {
|
||||
agent { node { label 'groovy' } }
|
||||
agent { node { label 'hirsute' } }
|
||||
environment {
|
||||
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
|
||||
}
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
steps {
|
||||
@@ -188,17 +191,10 @@ pipeline{
|
||||
}
|
||||
stage ('Download assets') {
|
||||
steps {
|
||||
sh "sudo apt install -y azure-cli"
|
||||
sh "mkdir ${env.HOME}/workloads"
|
||||
azureDownload(storageCredentialId: 'ch-image-store',
|
||||
containerName: 'private-images',
|
||||
includeFilesPattern: 'OVMF-4b47d0c6c8.fd',
|
||||
downloadType: 'container',
|
||||
downloadDirLoc: "${env.HOME}/workloads")
|
||||
azureDownload(storageCredentialId: 'ch-image-store',
|
||||
containerName: 'private-images',
|
||||
includeFilesPattern: 'windows-server-2019.raw',
|
||||
downloadType: 'container',
|
||||
downloadDirLoc: "${env.HOME}/workloads")
|
||||
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/OVMF-4b47d0c6c8.fd" --name OVMF-4b47d0c6c8.fd --connection-string "$AZURE_CONNECTION_STRING"'
|
||||
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/windows-server-2019.raw" --name windows-server-2019.raw --connection-string "$AZURE_CONNECTION_STRING"'
|
||||
}
|
||||
}
|
||||
stage ('Run Windows guest integration tests') {
|
||||
@@ -219,21 +215,47 @@ pipeline{
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ('Worker build - Live Migration') {
|
||||
agent { node { label 'hirsute-small' } }
|
||||
stages {
|
||||
stage ('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage ('Run live-migration integration tests') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh "scripts/dev_cli.sh tests --integration-live-migration"
|
||||
}
|
||||
}
|
||||
stage ('Run live-migration integration tests for musl') {
|
||||
options {
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh "scripts/dev_cli.sh tests --integration-live-migration --libc musl"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
regression {
|
||||
script {
|
||||
if (env.BRANCH_NAME == 'master') {
|
||||
slackSend (color: '#ff0000', message: '"master" branch build is now failing')
|
||||
if (env.BRANCH_NAME == 'main') {
|
||||
slackSend (color: '#ff0000', message: '"main" branch build is now failing')
|
||||
}
|
||||
}
|
||||
}
|
||||
fixed {
|
||||
script {
|
||||
if (env.BRANCH_NAME == 'master') {
|
||||
slackSend (color: '#00ff00', message: '"master" branch build is now fixed')
|
||||
if (env.BRANCH_NAME == 'main') {
|
||||
slackSend (color: '#00ff00', message: '"main" branch build is now fixed')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Maintainers
|
||||
|
||||
- Sebastien Boeuf <sebastien.boeuf@intel.com> @sboeuf
|
||||
- Robert Bradford <robert.bradford@intel.com> @rbradford
|
||||
- Samuel Ortiz <sameo@linux.intel.com> @sameo
|
||||
- Chao P Peng <chao.p.peng@linux.intel.com> @chao-p
|
||||
- Sebastien Boeuf - @sboeuf
|
||||
- Robert Bradford - @rbradford
|
||||
- Samuel Ortiz - @sameo
|
||||
- Wei Liu - @liuw
|
||||
- Michael Zhao - @michael2012z
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
[](https://travis-ci.com/cloud-hypervisor/cloud-hypervisor)
|
||||
|
||||
- [1. What is Cloud Hypervisor?](#1-what-is-cloud-hypervisor)
|
||||
- [Objectives](#objectives)
|
||||
- [High Level](#high-level)
|
||||
- [Architectures](#architectures)
|
||||
- [Guest OS](#guest-os)
|
||||
- [2. Getting Started](#2-getting-started)
|
||||
- [Install prerequisites](#install-prerequisites)
|
||||
- [Clone and build](#clone-and-build)
|
||||
- [Containerized builds and tests](#containerized-builds-and-tests)
|
||||
- [Run](#run)
|
||||
@@ -23,6 +22,7 @@
|
||||
- [5. Community](#5-community)
|
||||
- [Contribute](#contribute)
|
||||
- [Join us](#join-us)
|
||||
- [Security issues](#security-issues)
|
||||
|
||||
# 1. What is Cloud Hypervisor?
|
||||
|
||||
@@ -149,7 +149,7 @@ We need to get the latest `rust-hypervisor-firmware` release and also a working
|
||||
$ pushd $CLOUDH
|
||||
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
|
||||
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-server-cloudimg-amd64.raw
|
||||
$ wget https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/download/0.3.1/hypervisor-fw
|
||||
$ wget https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/download/0.3.2/hypervisor-fw
|
||||
$ popd
|
||||
```
|
||||
|
||||
@@ -180,7 +180,7 @@ To build the kernel:
|
||||
|
||||
# Clone the Cloud Hypervisor Linux branch
|
||||
$ pushd $CLOUDH
|
||||
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-5.12 linux-cloud-hypervisor
|
||||
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-5.14 linux-cloud-hypervisor
|
||||
$ pushd linux-cloud-hypervisor
|
||||
|
||||
# Use the cloud-hypervisor kernel config to build your kernel
|
||||
|
||||
@@ -5,4 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
vm-memory = "0.5.0"
|
||||
vm-memory = "0.6.0"
|
||||
|
||||
@@ -36,7 +36,7 @@ impl Rsdp {
|
||||
};
|
||||
|
||||
rsdp.checksum = super::generate_checksum(&rsdp.as_slice()[0..19]);
|
||||
rsdp.extended_checksum = super::generate_checksum(&rsdp.as_slice());
|
||||
rsdp.extended_checksum = super::generate_checksum(rsdp.as_slice());
|
||||
rsdp
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ impl Sdt {
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
&self.data.as_slice()
|
||||
self.data.as_slice()
|
||||
}
|
||||
|
||||
pub fn append<T>(&mut self, value: T) {
|
||||
|
||||
@@ -3,3 +3,6 @@ name = "api_client"
|
||||
version = "0.1.0"
|
||||
authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
vmm-sys-util = "0.8.0"
|
||||
|
||||
@@ -5,10 +5,13 @@
|
||||
|
||||
use std::fmt;
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::io::RawFd;
|
||||
use vmm_sys_util::sock_ctrl_msg::ScmSocket;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Socket(std::io::Error),
|
||||
SocketSendFds(vmm_sys_util::errno::Error),
|
||||
StatusCodeParsing(std::num::ParseIntError),
|
||||
MissingProtocol,
|
||||
ContentLengthParsing(std::num::ParseIntError),
|
||||
@@ -20,6 +23,7 @@ impl fmt::Display for Error {
|
||||
use Error::*;
|
||||
match self {
|
||||
Socket(e) => write!(f, "Error writing to or reading from HTTP socket: {}", e),
|
||||
SocketSendFds(e) => write!(f, "Error writing to or reading from HTTP socket: {}", e),
|
||||
StatusCodeParsing(e) => write!(f, "Error parsing HTTP status code: {}", e),
|
||||
MissingProtocol => write!(f, "HTTP output is missing protocol statement"),
|
||||
ContentLengthParsing(e) => write!(f, "Error parsing HTTP Content-Length field: {}", e),
|
||||
@@ -133,21 +137,23 @@ fn parse_http_response(socket: &mut dyn Read) -> Result<Option<String>, Error> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn simple_api_command<T: Read + Write>(
|
||||
pub fn simple_api_command_with_fds<T: Read + Write + ScmSocket>(
|
||||
socket: &mut T,
|
||||
method: &str,
|
||||
c: &str,
|
||||
request_body: Option<&str>,
|
||||
request_fds: Vec<RawFd>,
|
||||
) -> Result<(), Error> {
|
||||
socket
|
||||
.write_all(
|
||||
format!(
|
||||
.send_with_fds(
|
||||
&[format!(
|
||||
"{} /api/v1/vm.{} HTTP/1.1\r\nHost: localhost\r\nAccept: */*\r\n",
|
||||
method, c
|
||||
)
|
||||
.as_bytes(),
|
||||
.as_bytes()],
|
||||
&request_fds,
|
||||
)
|
||||
.map_err(Error::Socket)?;
|
||||
.map_err(Error::SocketSendFds)?;
|
||||
|
||||
if let Some(request_body) = request_body {
|
||||
socket
|
||||
@@ -170,3 +176,12 @@ pub fn simple_api_command<T: Read + Write>(
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn simple_api_command<T: Read + Write + ScmSocket>(
|
||||
socket: &mut T,
|
||||
method: &str,
|
||||
c: &str,
|
||||
request_body: Option<&str>,
|
||||
) -> Result<(), Error> {
|
||||
simple_api_command_with_fds(socket, method, c, request_body, Vec::new())
|
||||
}
|
||||
|
||||
@@ -11,17 +11,20 @@ tdx = []
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { path = "../acpi_tables", optional = true }
|
||||
anyhow = "1.0"
|
||||
anyhow = "1.0.43"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.96"
|
||||
libc = "0.2.101"
|
||||
linux-loader = { version = "0.3.0", features = ["elf", "bzimage", "pe"] }
|
||||
log = "0.4.14"
|
||||
serde = {version = ">=1.0.27", features = ["rc"] }
|
||||
thiserror = "1.0"
|
||||
serde = { version = "1.0.130", features = ["rc"] }
|
||||
thiserror = "1.0.29"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-fdt = { git = "https://github.com/rust-vmm/vm-fdt", branch = "master" }
|
||||
vm-memory = { version = "0.5.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = { version = "0.8.0", features = ["with-serde"] }
|
||||
|
||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||
fdt_parser = { version = "0.1.3", package = 'fdt'}
|
||||
vm-fdt = { git = "https://github.com/rust-vmm/vm-fdt", branch = "main" }
|
||||
|
||||
@@ -6,10 +6,14 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the THIRD-PARTY file.
|
||||
|
||||
use crate::NumaNodes;
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CStr;
|
||||
use std::fmt::Debug;
|
||||
use std::result;
|
||||
use std::str;
|
||||
|
||||
use super::super::DeviceType;
|
||||
use super::super::GuestMemoryMmap;
|
||||
@@ -21,7 +25,7 @@ use super::layout::{
|
||||
PCI_HIGH_BASE, PCI_MMCONFIG_SIZE, PCI_MMCONFIG_START,
|
||||
};
|
||||
use vm_fdt::{FdtWriter, FdtWriterResult};
|
||||
use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryError};
|
||||
use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryRegion};
|
||||
|
||||
// This is a value for uniquely identifying the FDT node declaring the interrupt controller.
|
||||
const GIC_PHANDLE: u32 = 1;
|
||||
@@ -31,6 +35,9 @@ const MSI_PHANDLE: u32 = 2;
|
||||
const CLOCK_PHANDLE: u32 = 3;
|
||||
// This is a value for uniquely identifying the FDT node containing the gpio controller.
|
||||
const GPIO_PHANDLE: u32 = 4;
|
||||
// This is a value for uniquely identifying the FDT node containing the first vCPU.
|
||||
// The last number of vCPU phandle depends on the number of vCPUs.
|
||||
const FIRST_VCPU_PHANDLE: u32 = 5;
|
||||
|
||||
// Read the documentation specified when appending the root node to the FDT.
|
||||
const ADDRESS_CELLS: u32 = 0x2;
|
||||
@@ -69,17 +76,20 @@ pub enum Error {
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
||||
/// Creates the flattened device tree for this aarch64 VM.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
|
||||
guest_mem: &GuestMemoryMmap,
|
||||
cmdline: &CStr,
|
||||
vcpu_mpidr: Vec<u64>,
|
||||
vcpu_topology: Option<(u8, u8, u8)>,
|
||||
device_info: &HashMap<(DeviceType, String), T, S>,
|
||||
gic_device: &dyn GicDevice,
|
||||
initrd: &Option<InitramfsConfig>,
|
||||
pci_space_address: &(u64, u64),
|
||||
numa_nodes: &NumaNodes,
|
||||
) -> FdtWriterResult<Vec<u8>> {
|
||||
// Allocate stuff necessary for the holding the blob.
|
||||
let mut fdt = FdtWriter::new(&[]).unwrap();
|
||||
let mut fdt = FdtWriter::new().unwrap();
|
||||
|
||||
// For an explanation why these nodes were introduced in the blob take a look at
|
||||
// https://github.com/torvalds/linux/blob/master/Documentation/devicetree/booting-without-of.txt#L845
|
||||
@@ -95,8 +105,8 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
|
||||
// This is not mandatory but we use it to point the root node to the node
|
||||
// containing description of the interrupt controller for this VM.
|
||||
fdt.property_u32("interrupt-parent", GIC_PHANDLE)?;
|
||||
create_cpu_nodes(&mut fdt, &vcpu_mpidr)?;
|
||||
create_memory_node(&mut fdt, guest_mem)?;
|
||||
create_cpu_nodes(&mut fdt, &vcpu_mpidr, vcpu_topology, numa_nodes)?;
|
||||
create_memory_node(&mut fdt, guest_mem, numa_nodes)?;
|
||||
create_chosen_node(&mut fdt, cmdline.to_str().unwrap(), initrd)?;
|
||||
create_gic_node(&mut fdt, gic_device)?;
|
||||
create_timer_node(&mut fdt)?;
|
||||
@@ -104,6 +114,9 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
|
||||
create_psci_node(&mut fdt)?;
|
||||
create_devices_node(&mut fdt, device_info)?;
|
||||
create_pci_nodes(&mut fdt, pci_space_address.0, pci_space_address.1)?;
|
||||
if numa_nodes.len() > 1 {
|
||||
create_distance_map_node(&mut fdt, numa_nodes)?;
|
||||
}
|
||||
|
||||
// End Header node.
|
||||
fdt.end_node(root_node)?;
|
||||
@@ -123,14 +136,23 @@ pub fn write_fdt_to_memory(fdt_final: Vec<u8>, guest_mem: &GuestMemoryMmap) -> R
|
||||
}
|
||||
|
||||
// Following are the auxiliary function for creating the different nodes that we append to our FDT.
|
||||
fn create_cpu_nodes(fdt: &mut FdtWriter, vcpu_mpidr: &[u64]) -> FdtWriterResult<()> {
|
||||
fn create_cpu_nodes(
|
||||
fdt: &mut FdtWriter,
|
||||
vcpu_mpidr: &[u64],
|
||||
vcpu_topology: Option<(u8, u8, u8)>,
|
||||
numa_nodes: &NumaNodes,
|
||||
) -> FdtWriterResult<()> {
|
||||
// See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/arm/cpus.yaml.
|
||||
let cpus_node = fdt.begin_node("cpus")?;
|
||||
fdt.property_u32("#address-cells", 0x1)?;
|
||||
fdt.property_u32("#size-cells", 0x0)?;
|
||||
let num_cpus = vcpu_mpidr.len();
|
||||
|
||||
for cpu_id in 0..num_cpus {
|
||||
let num_cpus = vcpu_mpidr.len();
|
||||
let threads_per_core = vcpu_topology.unwrap_or_default().0 as u8;
|
||||
let cores_per_package = vcpu_topology.unwrap_or_default().1 as u8;
|
||||
let packages = vcpu_topology.unwrap_or_default().2 as u8;
|
||||
|
||||
for (cpu_id, mpidr) in vcpu_mpidr.iter().enumerate().take(num_cpus) {
|
||||
let cpu_name = format!("cpu@{:x}", cpu_id);
|
||||
let cpu_node = fdt.begin_node(&cpu_name)?;
|
||||
fdt.property_string("device_type", "cpu")?;
|
||||
@@ -139,23 +161,132 @@ fn create_cpu_nodes(fdt: &mut FdtWriter, vcpu_mpidr: &[u64]) -> FdtWriterResult<
|
||||
// This is required on armv8 64-bit. See aforementioned documentation.
|
||||
fdt.property_string("enable-method", "psci")?;
|
||||
}
|
||||
fdt.property_u32("reg", cpu_id as u32)?;
|
||||
// Set the field to first 24 bits of the MPIDR - Multiprocessor Affinity Register.
|
||||
// See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488c/BABHBJCI.html.
|
||||
fdt.property_u32("reg", (mpidr & 0x7FFFFF) as u32)?;
|
||||
fdt.property_u32("phandle", cpu_id as u32 + FIRST_VCPU_PHANDLE)?;
|
||||
|
||||
// Add `numa-node-id` property if there is any numa config.
|
||||
if numa_nodes.len() > 1 {
|
||||
for numa_node_idx in 0..numa_nodes.len() {
|
||||
let numa_node = numa_nodes.get(&(numa_node_idx as u32));
|
||||
if numa_node.unwrap().cpus.contains(&(cpu_id as u8)) {
|
||||
fdt.property_u32("numa-node-id", numa_node_idx as u32)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fdt.end_node(cpu_node)?;
|
||||
}
|
||||
|
||||
// If there is a valid cpu topology config, create the cpu-map node.
|
||||
if (threads_per_core > 0)
|
||||
&& (cores_per_package > 0)
|
||||
&& (packages > 0)
|
||||
&& (num_cpus as u8 == threads_per_core * cores_per_package * packages)
|
||||
{
|
||||
let cpu_map_node = fdt.begin_node("cpu-map")?;
|
||||
// Create mappings between CPU index and cluster,core, and thread.
|
||||
let mut cluster_core_thread_to_cpuidx = HashMap::new();
|
||||
for cpu_idx in 0..num_cpus as u8 {
|
||||
if threads_per_core > 1 {
|
||||
cluster_core_thread_to_cpuidx.insert(
|
||||
(
|
||||
cpu_idx / (cores_per_package * threads_per_core),
|
||||
(cpu_idx / threads_per_core) % cores_per_package,
|
||||
cpu_idx % threads_per_core,
|
||||
),
|
||||
cpu_idx,
|
||||
);
|
||||
} else {
|
||||
cluster_core_thread_to_cpuidx.insert(
|
||||
(cpu_idx / cores_per_package, cpu_idx % cores_per_package, 0),
|
||||
cpu_idx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Create device tree nodes with regard of above mapping.
|
||||
for cluster_idx in 0..packages {
|
||||
let cluster_name = format!("cluster{:x}", cluster_idx);
|
||||
let cluster_node = fdt.begin_node(&cluster_name)?;
|
||||
|
||||
for core_idx in 0..cores_per_package {
|
||||
let core_name = format!("core{:x}", core_idx);
|
||||
let core_node = fdt.begin_node(&core_name)?;
|
||||
|
||||
if threads_per_core > 1 {
|
||||
for thread_idx in 0..threads_per_core {
|
||||
let thread_name = format!("thread{:x}", thread_idx);
|
||||
let thread_node = fdt.begin_node(&thread_name)?;
|
||||
let cpu_idx = cluster_core_thread_to_cpuidx
|
||||
.get(&(cluster_idx, core_idx, thread_idx))
|
||||
.unwrap();
|
||||
|
||||
fdt.property_u32("cpu", *cpu_idx as u32 + FIRST_VCPU_PHANDLE)?;
|
||||
fdt.end_node(thread_node)?;
|
||||
}
|
||||
} else {
|
||||
let cpu_idx = cluster_core_thread_to_cpuidx
|
||||
.get(&(cluster_idx, core_idx, 0))
|
||||
.unwrap();
|
||||
|
||||
fdt.property_u32("cpu", *cpu_idx as u32 + FIRST_VCPU_PHANDLE)?;
|
||||
}
|
||||
fdt.end_node(core_node)?;
|
||||
}
|
||||
fdt.end_node(cluster_node)?;
|
||||
}
|
||||
fdt.end_node(cpu_map_node)?;
|
||||
} else {
|
||||
debug!("Boot using device tree, CPU topology is not (correctly) specified");
|
||||
}
|
||||
|
||||
fdt.end_node(cpus_node)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemoryMmap) -> FdtWriterResult<()> {
|
||||
let mem_size = guest_mem.last_addr().raw_value() - super::layout::RAM_64BIT_START + 1;
|
||||
// See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/booting-without-of.txt#L960
|
||||
// for an explanation of this.
|
||||
let mem_reg_prop = [super::layout::RAM_64BIT_START as u64, mem_size as u64];
|
||||
fn create_memory_node(
|
||||
fdt: &mut FdtWriter,
|
||||
guest_mem: &GuestMemoryMmap,
|
||||
numa_nodes: &NumaNodes,
|
||||
) -> FdtWriterResult<()> {
|
||||
if numa_nodes.len() > 1 {
|
||||
for numa_node_idx in 0..numa_nodes.len() {
|
||||
let numa_node = numa_nodes.get(&(numa_node_idx as u32));
|
||||
// Each memory zone of numa will have its own memory node, but
|
||||
// different numa nodes should not share same memory zones.
|
||||
for memory_region in numa_node.unwrap().memory_regions.iter() {
|
||||
let memory_region_start_addr: u64 = memory_region.start_addr().raw_value();
|
||||
let memory_region_size: u64 = memory_region.size() as u64;
|
||||
let mem_reg_prop = [memory_region_start_addr, memory_region_size];
|
||||
// With feature `acpi` enabled, RAM at 0-4M is for edk2 only
|
||||
// and should be hidden to the guest.
|
||||
#[cfg(feature = "acpi")]
|
||||
if memory_region_start_addr == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let memory_node = fdt.begin_node("memory")?;
|
||||
fdt.property_string("device_type", "memory")?;
|
||||
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
||||
fdt.end_node(memory_node)?;
|
||||
let memory_node_name = format!("memory@{:x}", memory_region_start_addr);
|
||||
let memory_node = fdt.begin_node(&memory_node_name)?;
|
||||
fdt.property_string("device_type", "memory")?;
|
||||
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
||||
fdt.property_u32("numa-node-id", numa_node_idx as u32)?;
|
||||
fdt.end_node(memory_node)?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let mem_size = guest_mem.last_addr().raw_value() - super::layout::RAM_64BIT_START + 1;
|
||||
// See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/booting-without-of.txt#L960
|
||||
// for an explanation of this.
|
||||
let mem_reg_prop = [super::layout::RAM_64BIT_START as u64, mem_size as u64];
|
||||
let memory_node = fdt.begin_node("memory")?;
|
||||
|
||||
fdt.property_string("device_type", "memory")?;
|
||||
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
||||
fdt.end_node(memory_node)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -191,7 +322,7 @@ fn create_gic_node(fdt: &mut FdtWriter, gic_device: &dyn GicDevice) -> FdtWriter
|
||||
// interrupt source. The type shall be a <u32> and the value shall be 3 if no PPI affinity description
|
||||
// is required.
|
||||
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("#address-cells", 2)?;
|
||||
fdt.property_u32("#size-cells", 2)?;
|
||||
@@ -210,7 +341,7 @@ fn create_gic_node(fdt: &mut FdtWriter, gic_device: &dyn GicDevice) -> FdtWriter
|
||||
fdt.property_null("msi-controller")?;
|
||||
fdt.property_u32("phandle", MSI_PHANDLE)?;
|
||||
let msi_reg_prop = gic_device.msi_properties();
|
||||
fdt.property_array_u64("reg", &msi_reg_prop)?;
|
||||
fdt.property_array_u64("reg", msi_reg_prop)?;
|
||||
fdt.end_node(msic_node)?;
|
||||
}
|
||||
|
||||
@@ -476,3 +607,124 @@ fn create_pci_nodes(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_distance_map_node(fdt: &mut FdtWriter, numa_nodes: &NumaNodes) -> FdtWriterResult<()> {
|
||||
let distance_map_node = fdt.begin_node("distance-map")?;
|
||||
fdt.property_string("compatible", "numa-distance-map-v1")?;
|
||||
// Construct the distance matrix.
|
||||
// 1. We use the word entry to describe a distance from a node to
|
||||
// its destination, e.g. 0 -> 1 = 20 is described as <0 1 20>.
|
||||
// 2. Each entry represents distance from first node to second node.
|
||||
// The distances are equal in either direction.
|
||||
// 3. The distance from a node to self (local distance) is represented
|
||||
// with value 10 and all internode distance should be represented with
|
||||
// a value greater than 10.
|
||||
// 4. distance-matrix should have entries in lexicographical ascending
|
||||
// order of nodes.
|
||||
let mut distance_matrix = Vec::new();
|
||||
for numa_node_idx in 0..numa_nodes.len() {
|
||||
let numa_node = numa_nodes.get(&(numa_node_idx as u32));
|
||||
for dest_numa_node in 0..numa_node.unwrap().distances.len() + 1 {
|
||||
if numa_node_idx == dest_numa_node {
|
||||
distance_matrix.push(numa_node_idx as u32);
|
||||
distance_matrix.push(dest_numa_node as u32);
|
||||
distance_matrix.push(10_u32);
|
||||
continue;
|
||||
}
|
||||
|
||||
distance_matrix.push(numa_node_idx as u32);
|
||||
distance_matrix.push(dest_numa_node as u32);
|
||||
distance_matrix.push(
|
||||
*numa_node
|
||||
.unwrap()
|
||||
.distances
|
||||
.get(&(dest_numa_node as u32))
|
||||
.unwrap() as u32,
|
||||
);
|
||||
}
|
||||
}
|
||||
fdt.property_array_u32("distance-matrix", distance_matrix.as_ref())?;
|
||||
fdt.end_node(distance_map_node)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Parse the DTB binary and print for debugging
|
||||
pub fn print_fdt(dtb: &[u8]) {
|
||||
match fdt_parser::Fdt::new(dtb) {
|
||||
Ok(fdt) => {
|
||||
if let Some(root) = fdt.find_node("/") {
|
||||
debug!("Printing the FDT:");
|
||||
print_node(root, 0);
|
||||
} else {
|
||||
debug!("Failed to find root node in FDT for debugging.");
|
||||
}
|
||||
}
|
||||
Err(_) => debug!("Failed to parse FDT for debugging."),
|
||||
}
|
||||
}
|
||||
|
||||
fn print_node(node: fdt_parser::node::FdtNode<'_, '_>, n_spaces: usize) {
|
||||
debug!("{:indent$}{}/", "", node.name, indent = n_spaces);
|
||||
for property in node.properties() {
|
||||
let name = property.name;
|
||||
|
||||
// If the property is 'compatible', its value requires special handling.
|
||||
// The u8 array could contain multiple null-terminated strings.
|
||||
// We copy the original array and simply replace all 'null' characters with spaces.
|
||||
let value = if name == "compatible" {
|
||||
let mut compatible = vec![0u8; 256];
|
||||
let handled_value = property
|
||||
.value
|
||||
.iter()
|
||||
.map(|&c| if c == 0 { b' ' } else { c })
|
||||
.collect::<Vec<_>>();
|
||||
let len = cmp::min(255, handled_value.len());
|
||||
compatible[..len].copy_from_slice(&handled_value[..len]);
|
||||
compatible[..(len + 1)].to_vec()
|
||||
} else {
|
||||
property.value.to_vec()
|
||||
};
|
||||
let value = &value;
|
||||
|
||||
// Now the value can be either:
|
||||
// - A null-terminated C string, or
|
||||
// - Binary data
|
||||
// We follow a very simple logic to present the value:
|
||||
// - At first, try to convert it to CStr and print,
|
||||
// - If failed, print it as u32 array.
|
||||
let value_result = match CStr::from_bytes_with_nul(value) {
|
||||
Ok(value_cstr) => match value_cstr.to_str() {
|
||||
Ok(value_str) => Some(value_str),
|
||||
Err(_e) => None,
|
||||
},
|
||||
Err(_e) => None,
|
||||
};
|
||||
|
||||
if let Some(value_str) = value_result {
|
||||
debug!(
|
||||
"{:indent$}{} : {:#?}",
|
||||
"",
|
||||
name,
|
||||
value_str,
|
||||
indent = (n_spaces + 2)
|
||||
);
|
||||
} else {
|
||||
let mut array = Vec::with_capacity(256);
|
||||
array.resize(value.len() / 4, 0u32);
|
||||
BigEndian::read_u32_into(value, &mut array);
|
||||
debug!(
|
||||
"{:indent$}{} : {:X?}",
|
||||
"",
|
||||
name,
|
||||
array,
|
||||
indent = (n_spaces + 2)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
// Print children nodes if there is any
|
||||
for child in node.children() {
|
||||
print_node(child, n_spaces + 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ pub fn set_dist_regs(gic: &Arc<dyn hypervisor::Device>, state: &[u32]) -> Result
|
||||
|
||||
for dreg in VGIC_DIST_REGS {
|
||||
let mut base = dreg.base + REG_SIZE as u32 * dreg.bpi as u32;
|
||||
let end = compute_reg_len(gic, &dreg, base)?;
|
||||
let end = compute_reg_len(gic, dreg, base)?;
|
||||
|
||||
while base < end {
|
||||
let val = state[idx];
|
||||
@@ -169,7 +169,7 @@ pub fn get_dist_regs(gic: &Arc<dyn hypervisor::Device>) -> Result<Vec<u32>> {
|
||||
|
||||
for dreg in VGIC_DIST_REGS {
|
||||
let mut base = dreg.base + REG_SIZE as u32 * dreg.bpi as u32;
|
||||
let end = compute_reg_len(gic, &dreg, base)?;
|
||||
let end = compute_reg_len(gic, dreg, base)?;
|
||||
|
||||
while base < end {
|
||||
let val: u32 = 0;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// 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};
|
||||
@@ -50,7 +53,7 @@ pub mod kvm {
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
||||
pub struct KvmGicV3 {
|
||||
/// The hypervisor agnostic device
|
||||
/// The hypervisor agnostic device for the GicV3
|
||||
device: Arc<dyn hypervisor::Device>,
|
||||
|
||||
/// Vector holding values of GICR_TYPER for each vCPU
|
||||
@@ -106,20 +109,17 @@ pub mod kvm {
|
||||
|
||||
/// Save the state of GIC.
|
||||
fn state(&self, gicr_typers: &[u64]) -> Result<Gicv3State> {
|
||||
// Flush redistributors pending tables to guest RAM.
|
||||
save_pending_tables(&self.device()).map_err(Error::SavePendingTables)?;
|
||||
|
||||
let gicd_ctlr =
|
||||
read_ctlr(&self.device()).map_err(Error::SaveDistributorCtrlRegisters)?;
|
||||
read_ctlr(self.device()).map_err(Error::SaveDistributorCtrlRegisters)?;
|
||||
|
||||
let dist_state =
|
||||
get_dist_regs(&self.device()).map_err(Error::SaveDistributorRegisters)?;
|
||||
get_dist_regs(self.device()).map_err(Error::SaveDistributorRegisters)?;
|
||||
|
||||
let rdist_state = get_redist_regs(&self.device(), &gicr_typers)
|
||||
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)?;
|
||||
get_icc_regs(self.device(), gicr_typers).map_err(Error::SaveIccRegisters)?;
|
||||
|
||||
Ok(Gicv3State {
|
||||
dist: dist_state,
|
||||
@@ -131,16 +131,16 @@ pub mod kvm {
|
||||
|
||||
/// Restore the state of GIC.
|
||||
fn set_state(&mut self, gicr_typers: &[u64], state: &Gicv3State) -> Result<()> {
|
||||
write_ctlr(&self.device(), state.gicd_ctlr)
|
||||
write_ctlr(self.device(), state.gicd_ctlr)
|
||||
.map_err(Error::RestoreDistributorCtrlRegisters)?;
|
||||
|
||||
set_dist_regs(&self.device(), &state.dist)
|
||||
set_dist_regs(self.device(), &state.dist)
|
||||
.map_err(Error::RestoreDistributorRegisters)?;
|
||||
|
||||
set_redist_regs(&self.device(), gicr_typers, &state.rdist)
|
||||
set_redist_regs(self.device(), gicr_typers, &state.rdist)
|
||||
.map_err(Error::RestoreRedistributorRegisters)?;
|
||||
|
||||
set_icc_regs(&self.device(), &gicr_typers, &state.icc)
|
||||
set_icc_regs(self.device(), gicr_typers, &state.icc)
|
||||
.map_err(Error::RestoreIccRegisters)?;
|
||||
|
||||
Ok(())
|
||||
@@ -168,6 +168,8 @@ pub mod kvm {
|
||||
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;
|
||||
@@ -202,7 +204,7 @@ pub mod kvm {
|
||||
|
||||
fn init_device_attributes(
|
||||
_vm: &Arc<dyn hypervisor::Vm>,
|
||||
gic_device: &dyn GicDevice,
|
||||
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.
|
||||
@@ -250,7 +252,16 @@ pub mod kvm {
|
||||
}
|
||||
}
|
||||
|
||||
impl Pausable for KvmGicV3 {}
|
||||
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,21 +1,156 @@
|
||||
// Copyright 2020 ARM Limited
|
||||
// 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 std::any::Any;
|
||||
use std::sync::Arc;
|
||||
use std::{boxed::Box, result};
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
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::KvmGicDevice;
|
||||
use crate::aarch64::gic::{Error, GicDevice};
|
||||
use crate::aarch64::gic::kvm::{save_pending_tables, KvmGicDevice};
|
||||
use crate::aarch64::gic::GicDevice;
|
||||
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: u64;
|
||||
if save {
|
||||
attr = u64::from(kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES);
|
||||
} else {
|
||||
attr = 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
|
||||
/// 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],
|
||||
|
||||
@@ -26,6 +161,23 @@ pub mod kvm {
|
||||
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 {
|
||||
const KVM_VGIC_V3_ITS_SIZE: u64 = (2 * KvmGicV3::SZ_64K);
|
||||
|
||||
@@ -36,6 +188,174 @@ pub mod kvm {
|
||||
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 {
|
||||
@@ -43,6 +363,10 @@ pub mod kvm {
|
||||
&self.device
|
||||
}
|
||||
|
||||
fn its_device(&self) -> Option<&Arc<dyn hypervisor::Device>> {
|
||||
self.its_device.as_ref()
|
||||
}
|
||||
|
||||
fn fdt_compatibility(&self) -> &str {
|
||||
"arm,gic-v3"
|
||||
}
|
||||
@@ -71,7 +395,14 @@ pub mod kvm {
|
||||
self.vcpu_count
|
||||
}
|
||||
|
||||
fn set_gicr_typers(&mut self, _vcpu_states: &[CpuState]) {}
|
||||
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
|
||||
@@ -89,6 +420,8 @@ pub mod kvm {
|
||||
) -> 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(),
|
||||
@@ -105,8 +438,8 @@ pub mod kvm {
|
||||
|
||||
fn init_device_attributes(
|
||||
vm: &Arc<dyn hypervisor::Vm>,
|
||||
gic_device: &dyn GicDevice,
|
||||
) -> Result<()> {
|
||||
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 {
|
||||
@@ -117,7 +450,7 @@ pub mod kvm {
|
||||
|
||||
let its_fd = vm
|
||||
.create_device(&mut its_device)
|
||||
.map_err(Error::CreateGic)?;
|
||||
.map_err(crate::aarch64::gic::Error::CreateGic)?;
|
||||
|
||||
Self::set_device_attribute(
|
||||
&its_fd,
|
||||
@@ -135,7 +468,49 @@ pub mod kvm {
|
||||
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,3 +1,4 @@
|
||||
// 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
|
||||
|
||||
@@ -31,6 +32,11 @@ 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;
|
||||
|
||||
@@ -58,6 +64,8 @@ pub trait GicDevice: Send {
|
||||
&[]
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
@@ -88,7 +96,7 @@ pub mod kvm {
|
||||
/// Setup the device-specific attributes
|
||||
fn init_device_attributes(
|
||||
vm: &Arc<dyn hypervisor::Vm>,
|
||||
gic_device: &dyn GicDevice,
|
||||
gic_device: &mut dyn GicDevice,
|
||||
) -> Result<()>;
|
||||
|
||||
/// Initialize a GIC device
|
||||
@@ -179,9 +187,9 @@ pub mod kvm {
|
||||
fn new(vm: &Arc<dyn hypervisor::Vm>, vcpu_count: u64) -> Result<Box<dyn GicDevice>> {
|
||||
let vgic_fd = Self::init_device(vm)?;
|
||||
|
||||
let device = Self::create_device(vgic_fd, vcpu_count);
|
||||
let mut device = Self::create_device(vgic_fd, vcpu_count);
|
||||
|
||||
Self::init_device_attributes(vm, &*device)?;
|
||||
Self::init_device_attributes(vm, &mut *device)?;
|
||||
|
||||
Self::finalize_device(&*device)?;
|
||||
|
||||
|
||||
@@ -62,11 +62,11 @@ macro_rules! VGIC_RDIST_REG {
|
||||
|
||||
// List with relevant distributor registers that we will be restoring.
|
||||
static VGIC_RDIST_REGS: &'static [RdistReg] = &[
|
||||
VGIC_RDIST_REG!(GICR_CTLR, 4),
|
||||
VGIC_RDIST_REG!(GICR_STATUSR, 4),
|
||||
VGIC_RDIST_REG!(GICR_WAKER, 4),
|
||||
VGIC_RDIST_REG!(GICR_PROPBASER, 8),
|
||||
VGIC_RDIST_REG!(GICR_PENDBASER, 8),
|
||||
VGIC_RDIST_REG!(GICR_CTLR, 4),
|
||||
];
|
||||
|
||||
// List with relevant distributor registers that we will be restoring.
|
||||
@@ -142,14 +142,14 @@ pub fn get_redist_regs(gic: &Arc<dyn hypervisor::Device>, gicr_typer: &[u64]) ->
|
||||
let mut idx: usize = 0;
|
||||
access_redists_aux(
|
||||
gic,
|
||||
&gicr_typer,
|
||||
gicr_typer,
|
||||
&mut state,
|
||||
VGIC_RDIST_REGS,
|
||||
&mut idx,
|
||||
false,
|
||||
)?;
|
||||
|
||||
access_redists_aux(gic, &gicr_typer, &mut state, VGIC_SGI_REGS, &mut idx, false)?;
|
||||
access_redists_aux(gic, gicr_typer, &mut state, VGIC_SGI_REGS, &mut idx, false)?;
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
|
||||
@@ -46,10 +46,11 @@
|
||||
|
||||
use vm_memory::GuestAddress;
|
||||
|
||||
/// 0x0 ~ 0x400_0000 is reserved to uefi
|
||||
/// 0x0 ~ 0x40_0000 (4 MiB) is reserved to UEFI
|
||||
/// UEFI binary size is required less than 3 MiB, reserving 4 MiB is enough.
|
||||
pub const UEFI_START: u64 = 0x0;
|
||||
pub const MEM_UEFI_START: GuestAddress = GuestAddress(0);
|
||||
pub const UEFI_SIZE: u64 = 0x0400_0000;
|
||||
pub const UEFI_SIZE: u64 = 0x040_0000;
|
||||
|
||||
/// Below this address will reside the GIC, above this address will reside the MMIO devices.
|
||||
pub const MAPPED_IO_START: u64 = 0x0900_0000;
|
||||
|
||||
@@ -14,10 +14,9 @@ pub mod regs;
|
||||
pub mod uefi;
|
||||
|
||||
pub use self::fdt::DeviceInfoForFdt;
|
||||
use crate::DeviceType;
|
||||
use crate::GuestMemoryMmap;
|
||||
use crate::RegionType;
|
||||
use crate::{DeviceType, GuestMemoryMmap, NumaNodes, RegionType};
|
||||
use gic::GicDevice;
|
||||
use log::{log_enabled, Level};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::CStr;
|
||||
@@ -87,7 +86,7 @@ pub fn configure_vcpu(
|
||||
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
|
||||
// Normally UEFI should be loaded to a flash area at the beginning of memory.
|
||||
// But now flash memory type is not supported.
|
||||
// As a workaround, we take 64 MiB memory from the main RAM for UEFI.
|
||||
// As a workaround, we take 4 MiB memory from the main RAM for UEFI.
|
||||
// As a result, the RAM that the guest can see is less than what has been
|
||||
// assigned in command line, when ACPI and UEFI is enabled.
|
||||
let ram_deduction = if cfg!(feature = "acpi") {
|
||||
@@ -97,7 +96,7 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
|
||||
};
|
||||
|
||||
vec![
|
||||
// 0 ~ 64 MiB: Reserved for UEFI space
|
||||
// 0 ~ 4 MiB: Reserved for UEFI space
|
||||
#[cfg(feature = "acpi")]
|
||||
(GuestAddress(0), layout::UEFI_SIZE as usize, RegionType::Ram),
|
||||
#[cfg(not(feature = "acpi"))]
|
||||
@@ -106,7 +105,7 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
|
||||
layout::UEFI_SIZE as usize,
|
||||
RegionType::Reserved,
|
||||
),
|
||||
// 64 MiB ~ 256 MiB: Gic and legacy devices
|
||||
// 4 MiB ~ 256 MiB: Gic and legacy devices
|
||||
(
|
||||
GuestAddress(layout::UEFI_SIZE),
|
||||
(layout::MEM_32BIT_DEVICES_START.0 - layout::UEFI_SIZE) as usize,
|
||||
@@ -134,26 +133,35 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
|
||||
}
|
||||
|
||||
/// Configures the system and should be called once per vm before starting vcpu threads.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
|
||||
guest_mem: &GuestMemoryMmap,
|
||||
cmdline_cstring: &CStr,
|
||||
vcpu_mpidr: Vec<u64>,
|
||||
vcpu_topology: Option<(u8, u8, u8)>,
|
||||
device_info: &HashMap<(DeviceType, String), T, S>,
|
||||
initrd: &Option<super::InitramfsConfig>,
|
||||
pci_space_address: &(u64, u64),
|
||||
gic_device: &dyn GicDevice,
|
||||
numa_nodes: &NumaNodes,
|
||||
) -> super::Result<()> {
|
||||
let fdt_final = fdt::create_fdt(
|
||||
guest_mem,
|
||||
cmdline_cstring,
|
||||
vcpu_mpidr,
|
||||
vcpu_topology,
|
||||
device_info,
|
||||
gic_device,
|
||||
initrd,
|
||||
pci_space_address,
|
||||
numa_nodes,
|
||||
)
|
||||
.map_err(|_| Error::SetupFdt)?;
|
||||
|
||||
if log_enabled!(Level::Debug) {
|
||||
fdt::print_fdt(&fdt_final);
|
||||
}
|
||||
|
||||
fdt::write_fdt_to_memory(fdt_final, guest_mem).map_err(Error::WriteFdtToMemory)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -11,10 +11,15 @@
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::x86_64::SgxEpcSection;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
use std::result;
|
||||
use std::sync::Arc;
|
||||
|
||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<vm_memory::bitmap::AtomicBitmap>;
|
||||
type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitmap>;
|
||||
|
||||
/// Type for returning error code.
|
||||
#[derive(Debug)]
|
||||
@@ -83,9 +88,9 @@ pub mod x86_64;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use x86_64::{
|
||||
arch_memory_regions, configure_system, configure_vcpu, get_host_cpu_phys_bits,
|
||||
initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE, layout::CMDLINE_START, regs, CpuidPatch,
|
||||
CpuidReg, EntryPoint,
|
||||
arch_memory_regions, configure_system, configure_vcpu, generate_common_cpuid,
|
||||
get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
|
||||
layout::CMDLINE_START, regs, CpuidFeatureEntry, EntryPoint,
|
||||
};
|
||||
|
||||
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
|
||||
@@ -96,6 +101,19 @@ fn pagesize() -> usize {
|
||||
unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct NumaNode {
|
||||
pub memory_regions: Vec<Arc<GuestRegionMmap>>,
|
||||
pub hotplug_regions: Vec<Arc<GuestRegionMmap>>,
|
||||
pub cpus: Vec<u8>,
|
||||
pub distances: BTreeMap<u32, u8>,
|
||||
pub memory_zones: Vec<String>,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub sgx_epc_sections: Vec<SgxEpcSection>,
|
||||
}
|
||||
|
||||
pub type NumaNodes = BTreeMap<u32, NumaNode>;
|
||||
|
||||
/// Type for passing information about the initramfs in the guest memory.
|
||||
pub struct InitramfsConfig {
|
||||
/// Load address of initramfs in guest memory
|
||||
|
||||
@@ -15,11 +15,12 @@ pub mod regs;
|
||||
use crate::GuestMemoryMmap;
|
||||
use crate::InitramfsConfig;
|
||||
use crate::RegionType;
|
||||
use hypervisor::{CpuId, CpuIdEntry, CPUID_FLAG_VALID_INDEX};
|
||||
use hypervisor::{CpuId, CpuIdEntry, HypervisorError, CPUID_FLAG_VALID_INDEX};
|
||||
use linux_loader::loader::bootparam::boot_params;
|
||||
use linux_loader::loader::elf::start_info::{
|
||||
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
|
||||
};
|
||||
use std::collections::BTreeMap;
|
||||
use std::mem;
|
||||
use vm_memory::{
|
||||
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
||||
@@ -30,6 +31,26 @@ use std::arch::x86_64;
|
||||
#[cfg(feature = "tdx")]
|
||||
pub mod tdx;
|
||||
|
||||
// CPUID feature bits
|
||||
const TSC_DEADLINE_TIMER_ECX_BIT: u8 = 24; // tsc deadline timer ecx bit.
|
||||
const HYPERVISOR_ECX_BIT: u8 = 31; // Hypervisor ecx bit.
|
||||
const MTRR_EDX_BIT: u8 = 12; // Hypervisor ecx bit.
|
||||
|
||||
// KVM feature bits
|
||||
const KVM_FEATURE_ASYNC_PF_INT_BIT: u8 = 14;
|
||||
#[cfg(feature = "tdx")]
|
||||
const KVM_FEATURE_CLOCKSOURCE_BIT: u8 = 0;
|
||||
#[cfg(feature = "tdx")]
|
||||
const KVM_FEATURE_CLOCKSOURCE2_BIT: u8 = 3;
|
||||
#[cfg(feature = "tdx")]
|
||||
const KVM_FEATURE_CLOCKSOURCE_STABLE_BIT: u8 = 24;
|
||||
#[cfg(feature = "tdx")]
|
||||
const KVM_FEATURE_ASYNC_PF_BIT: u8 = 4;
|
||||
#[cfg(feature = "tdx")]
|
||||
const KVM_FEATURE_ASYNC_PF_VMEXIT_BIT: u8 = 10;
|
||||
#[cfg(feature = "tdx")]
|
||||
const KVM_FEATURE_STEAL_TIME_BIT: u8 = 5;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
/// Specifies the entry point address where the guest must start
|
||||
/// executing code, as well as which of the supported boot protocols
|
||||
@@ -64,7 +85,7 @@ impl SgxEpcSection {
|
||||
pub struct SgxEpcRegion {
|
||||
start: GuestAddress,
|
||||
size: GuestUsize,
|
||||
epc_sections: Vec<SgxEpcSection>,
|
||||
epc_sections: BTreeMap<String, SgxEpcSection>,
|
||||
}
|
||||
|
||||
impl SgxEpcRegion {
|
||||
@@ -72,7 +93,7 @@ impl SgxEpcRegion {
|
||||
SgxEpcRegion {
|
||||
start,
|
||||
size,
|
||||
epc_sections: Vec::new(),
|
||||
epc_sections: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
pub fn start(&self) -> GuestAddress {
|
||||
@@ -81,11 +102,11 @@ impl SgxEpcRegion {
|
||||
pub fn size(&self) -> GuestUsize {
|
||||
self.size
|
||||
}
|
||||
pub fn epc_sections(&self) -> &Vec<SgxEpcSection> {
|
||||
pub fn epc_sections(&self) -> &BTreeMap<String, SgxEpcSection> {
|
||||
&self.epc_sections
|
||||
}
|
||||
pub fn push(&mut self, epc_section: SgxEpcSection) {
|
||||
self.epc_sections.push(epc_section);
|
||||
pub fn insert(&mut self, id: String, epc_section: SgxEpcSection) {
|
||||
self.epc_sections.insert(id, epc_section);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +176,18 @@ pub enum Error {
|
||||
|
||||
/// Missing SGX_LC CPU feature
|
||||
MissingSgxLaunchControlFeature,
|
||||
|
||||
/// Error getting supported CPUID through the hypervisor (kvm/mshv) API
|
||||
CpuidGetSupported(HypervisorError),
|
||||
|
||||
/// Error populating CPUID with KVM HyperV emulation details
|
||||
CpuidKvmHyperV(vmm_sys_util::fam::Error),
|
||||
|
||||
/// Error populating CPUID with CPU identification
|
||||
CpuidIdentification(vmm_sys_util::fam::Error),
|
||||
|
||||
/// Error checking CPUID compatibility
|
||||
CpuidCheckCompatibility,
|
||||
}
|
||||
|
||||
impl From<Error> for super::Error {
|
||||
@@ -164,7 +197,7 @@ impl From<Error> for super::Error {
|
||||
}
|
||||
|
||||
#[allow(dead_code, clippy::upper_case_acronyms)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum CpuidReg {
|
||||
EAX,
|
||||
EBX,
|
||||
@@ -308,6 +341,386 @@ impl CpuidPatch {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum CpuidCompatibleCheck {
|
||||
BitwiseSubset, // bitwise subset
|
||||
Equal, // equal in value
|
||||
NumNotGreater, // smaller or equal as a number
|
||||
}
|
||||
|
||||
pub struct CpuidFeatureEntry {
|
||||
function: u32,
|
||||
index: u32,
|
||||
feature_reg: CpuidReg,
|
||||
compatible_check: CpuidCompatibleCheck,
|
||||
}
|
||||
|
||||
impl CpuidFeatureEntry {
|
||||
fn checked_feature_entry_list() -> Vec<CpuidFeatureEntry> {
|
||||
vec![
|
||||
// The following list includes all hardware features bits from
|
||||
// the CPUID Wiki Page: https://en.wikipedia.org/wiki/CPUID
|
||||
// Leaf 0x1, ECX/EDX, feature bits
|
||||
CpuidFeatureEntry {
|
||||
function: 1,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::ECX,
|
||||
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||
},
|
||||
CpuidFeatureEntry {
|
||||
function: 1,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::EDX,
|
||||
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||
},
|
||||
// Leaf 0x7, EAX/EBX/ECX/EDX, extended features
|
||||
CpuidFeatureEntry {
|
||||
function: 7,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::EAX,
|
||||
compatible_check: CpuidCompatibleCheck::NumNotGreater,
|
||||
},
|
||||
CpuidFeatureEntry {
|
||||
function: 7,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::EBX,
|
||||
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||
},
|
||||
CpuidFeatureEntry {
|
||||
function: 7,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::ECX,
|
||||
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||
},
|
||||
CpuidFeatureEntry {
|
||||
function: 7,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::EDX,
|
||||
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||
},
|
||||
// Leaf 0x7 subleaf 0x1, EAX, extended features
|
||||
CpuidFeatureEntry {
|
||||
function: 7,
|
||||
index: 1,
|
||||
feature_reg: CpuidReg::EAX,
|
||||
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||
},
|
||||
// Leaf 0x8000_0001, ECX/EDX, CPUID features bits
|
||||
CpuidFeatureEntry {
|
||||
function: 0x8000_0001,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::ECX,
|
||||
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||
},
|
||||
CpuidFeatureEntry {
|
||||
function: 0x8000_0001,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::EDX,
|
||||
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||
},
|
||||
// KVM CPUID bits: https://www.kernel.org/doc/html/latest/virt/kvm/cpuid.html
|
||||
// Leaf 0x4000_0000, EAX/EBX/ECX/EDX, KVM CPUID SIGNATURE
|
||||
CpuidFeatureEntry {
|
||||
function: 0x4000_0000,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::EAX,
|
||||
compatible_check: CpuidCompatibleCheck::NumNotGreater,
|
||||
},
|
||||
CpuidFeatureEntry {
|
||||
function: 0x4000_0000,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::EBX,
|
||||
compatible_check: CpuidCompatibleCheck::Equal,
|
||||
},
|
||||
CpuidFeatureEntry {
|
||||
function: 0x4000_0000,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::ECX,
|
||||
compatible_check: CpuidCompatibleCheck::Equal,
|
||||
},
|
||||
CpuidFeatureEntry {
|
||||
function: 0x4000_0000,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::EDX,
|
||||
compatible_check: CpuidCompatibleCheck::Equal,
|
||||
},
|
||||
// Leaf 0x4000_0001, EAX/EBX/ECX/EDX, KVM CPUID features
|
||||
CpuidFeatureEntry {
|
||||
function: 0x4000_0001,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::EAX,
|
||||
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||
},
|
||||
CpuidFeatureEntry {
|
||||
function: 0x4000_0001,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::EBX,
|
||||
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||
},
|
||||
CpuidFeatureEntry {
|
||||
function: 0x4000_0001,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::ECX,
|
||||
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||
},
|
||||
CpuidFeatureEntry {
|
||||
function: 0x4000_0001,
|
||||
index: 0,
|
||||
feature_reg: CpuidReg::EDX,
|
||||
compatible_check: CpuidCompatibleCheck::BitwiseSubset,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn get_features_from_cpuid(
|
||||
cpuid: &CpuId,
|
||||
feature_entry_list: &[CpuidFeatureEntry],
|
||||
) -> Vec<u32> {
|
||||
let mut features = vec![0; feature_entry_list.len()];
|
||||
for (i, feature_entry) in feature_entry_list.iter().enumerate() {
|
||||
for cpuid_entry in cpuid.as_slice().iter() {
|
||||
if cpuid_entry.function == feature_entry.function
|
||||
&& cpuid_entry.index == feature_entry.index
|
||||
{
|
||||
match feature_entry.feature_reg {
|
||||
CpuidReg::EAX => {
|
||||
features[i] = cpuid_entry.eax;
|
||||
}
|
||||
CpuidReg::EBX => {
|
||||
features[i] = cpuid_entry.ebx;
|
||||
}
|
||||
CpuidReg::ECX => {
|
||||
features[i] = cpuid_entry.ecx;
|
||||
}
|
||||
CpuidReg::EDX => {
|
||||
features[i] = cpuid_entry.edx;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
features
|
||||
}
|
||||
|
||||
// The function returns `Error` (a.k.a. "incompatible"), when the CPUID features from `src_vm_cpuid`
|
||||
// is not a subset of those of the `dest_vm_cpuid`.
|
||||
pub fn check_cpuid_compatibility(
|
||||
src_vm_cpuid: &CpuId,
|
||||
dest_vm_cpuid: &CpuId,
|
||||
) -> Result<(), Error> {
|
||||
let feature_entry_list = &Self::checked_feature_entry_list();
|
||||
let src_vm_features = Self::get_features_from_cpuid(src_vm_cpuid, feature_entry_list);
|
||||
let dest_vm_features = Self::get_features_from_cpuid(dest_vm_cpuid, feature_entry_list);
|
||||
|
||||
// Loop on feature bit and check if the 'source vm' feature is a subset
|
||||
// of those of the 'destination vm' feature
|
||||
let mut compatible = true;
|
||||
for (i, (src_vm_feature, dest_vm_feature)) in src_vm_features
|
||||
.iter()
|
||||
.zip(dest_vm_features.iter())
|
||||
.enumerate()
|
||||
{
|
||||
let entry = &feature_entry_list[i];
|
||||
let entry_compatible;
|
||||
match entry.compatible_check {
|
||||
CpuidCompatibleCheck::BitwiseSubset => {
|
||||
let different_feature_bits = src_vm_feature ^ dest_vm_feature;
|
||||
let src_vm_feature_bits_only = different_feature_bits & src_vm_feature;
|
||||
entry_compatible = src_vm_feature_bits_only == 0;
|
||||
}
|
||||
CpuidCompatibleCheck::Equal => {
|
||||
entry_compatible = src_vm_feature == dest_vm_feature;
|
||||
}
|
||||
CpuidCompatibleCheck::NumNotGreater => {
|
||||
entry_compatible = src_vm_feature <= dest_vm_feature;
|
||||
}
|
||||
};
|
||||
if !entry_compatible {
|
||||
error!(
|
||||
"Detected incompatible CPUID entry: leaf={:#02x} (subleaf={:#02x}), register='{:?}', \
|
||||
compatilbe_check='{:?}', source VM feature='{:#04x}', destination VM feature'{:#04x}'.",
|
||||
entry.function, entry.index, entry.feature_reg,
|
||||
entry.compatible_check, src_vm_feature, dest_vm_feature
|
||||
);
|
||||
|
||||
compatible = false;
|
||||
}
|
||||
}
|
||||
|
||||
if compatible {
|
||||
info!("No CPU incompatibility detected.");
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::CpuidCheckCompatibility)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_common_cpuid(
|
||||
hypervisor: Arc<dyn hypervisor::Hypervisor>,
|
||||
topology: Option<(u8, u8, u8)>,
|
||||
sgx_epc_sections: Option<Vec<SgxEpcSection>>,
|
||||
phys_bits: u8,
|
||||
kvm_hyperv: bool,
|
||||
#[cfg(feature = "tdx")] tdx_enabled: bool,
|
||||
) -> super::Result<CpuId> {
|
||||
let cpuid_patches = vec![
|
||||
// Patch tsc deadline timer bit
|
||||
CpuidPatch {
|
||||
function: 1,
|
||||
index: 0,
|
||||
flags_bit: None,
|
||||
eax_bit: None,
|
||||
ebx_bit: None,
|
||||
ecx_bit: Some(TSC_DEADLINE_TIMER_ECX_BIT),
|
||||
edx_bit: None,
|
||||
},
|
||||
// Patch hypervisor bit
|
||||
CpuidPatch {
|
||||
function: 1,
|
||||
index: 0,
|
||||
flags_bit: None,
|
||||
eax_bit: None,
|
||||
ebx_bit: None,
|
||||
ecx_bit: Some(HYPERVISOR_ECX_BIT),
|
||||
edx_bit: None,
|
||||
},
|
||||
// Enable MTRR feature
|
||||
CpuidPatch {
|
||||
function: 1,
|
||||
index: 0,
|
||||
flags_bit: None,
|
||||
eax_bit: None,
|
||||
ebx_bit: None,
|
||||
ecx_bit: None,
|
||||
edx_bit: Some(MTRR_EDX_BIT),
|
||||
},
|
||||
];
|
||||
|
||||
// Supported CPUID
|
||||
let mut cpuid = hypervisor.get_cpuid().map_err(Error::CpuidGetSupported)?;
|
||||
|
||||
CpuidPatch::patch_cpuid(&mut cpuid, cpuid_patches);
|
||||
|
||||
if let Some(t) = topology {
|
||||
update_cpuid_topology(&mut cpuid, t.0, t.1, t.2);
|
||||
}
|
||||
|
||||
if let Some(sgx_epc_sections) = sgx_epc_sections {
|
||||
update_cpuid_sgx(&mut cpuid, sgx_epc_sections)?;
|
||||
}
|
||||
|
||||
// Update some existing CPUID
|
||||
for entry in cpuid.as_mut_slice().iter_mut() {
|
||||
match entry.function {
|
||||
// Set CPU physical bits
|
||||
0x8000_0008 => {
|
||||
entry.eax = (entry.eax & 0xffff_ff00) | (phys_bits as u32 & 0xff);
|
||||
}
|
||||
// Disable KVM_FEATURE_ASYNC_PF_INT
|
||||
// This is required until we find out why the asynchronous page
|
||||
// fault is generating unexpected behavior when using interrupt
|
||||
// mechanism.
|
||||
// TODO: Re-enable KVM_FEATURE_ASYNC_PF_INT (#2277)
|
||||
0x4000_0001 => {
|
||||
entry.eax &= !(1 << KVM_FEATURE_ASYNC_PF_INT_BIT);
|
||||
|
||||
// These features are not supported by TDX
|
||||
#[cfg(feature = "tdx")]
|
||||
if tdx_enabled {
|
||||
entry.eax &= !(1 << KVM_FEATURE_CLOCKSOURCE_BIT
|
||||
| 1 << KVM_FEATURE_CLOCKSOURCE2_BIT
|
||||
| 1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT
|
||||
| 1 << KVM_FEATURE_ASYNC_PF_BIT
|
||||
| 1 << KVM_FEATURE_ASYNC_PF_VMEXIT_BIT
|
||||
| 1 << KVM_FEATURE_STEAL_TIME_BIT)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy CPU identification string
|
||||
for i in 0x8000_0002..=0x8000_0004 {
|
||||
cpuid.retain(|c| c.function != i);
|
||||
let leaf = unsafe { std::arch::x86_64::__cpuid(i) };
|
||||
cpuid
|
||||
.push(CpuIdEntry {
|
||||
function: i,
|
||||
eax: leaf.eax,
|
||||
ebx: leaf.ebx,
|
||||
ecx: leaf.ecx,
|
||||
edx: leaf.edx,
|
||||
..Default::default()
|
||||
})
|
||||
.map_err(Error::CpuidIdentification)?;
|
||||
}
|
||||
|
||||
if kvm_hyperv {
|
||||
// Remove conflicting entries
|
||||
cpuid.retain(|c| c.function != 0x4000_0000);
|
||||
cpuid.retain(|c| c.function != 0x4000_0001);
|
||||
// See "Hypervisor Top Level Functional Specification" for details
|
||||
// Compliance with "Hv#1" requires leaves up to 0x4000_000a
|
||||
cpuid
|
||||
.push(CpuIdEntry {
|
||||
function: 0x40000000,
|
||||
eax: 0x4000000a, // Maximum cpuid leaf
|
||||
ebx: 0x756e694c, // "Linu"
|
||||
ecx: 0x564b2078, // "x KV"
|
||||
edx: 0x7648204d, // "M Hv"
|
||||
..Default::default()
|
||||
})
|
||||
.map_err(Error::CpuidKvmHyperV)?;
|
||||
cpuid
|
||||
.push(CpuIdEntry {
|
||||
function: 0x40000001,
|
||||
eax: 0x31237648, // "Hv#1"
|
||||
..Default::default()
|
||||
})
|
||||
.map_err(Error::CpuidKvmHyperV)?;
|
||||
cpuid
|
||||
.push(CpuIdEntry {
|
||||
function: 0x40000002,
|
||||
eax: 0x3839, // "Build number"
|
||||
ebx: 0xa0000, // "Version"
|
||||
..Default::default()
|
||||
})
|
||||
.map_err(Error::CpuidKvmHyperV)?;
|
||||
cpuid
|
||||
.push(CpuIdEntry {
|
||||
function: 0x4000_0003,
|
||||
eax: 1 << 1 // AccessPartitionReferenceCounter
|
||||
| 1 << 2 // AccessSynicRegs
|
||||
| 1 << 3 // AccessSyntheticTimerRegs
|
||||
| 1 << 9, // AccessPartitionReferenceTsc
|
||||
edx: 1 << 3, // CPU dynamic partitioning
|
||||
..Default::default()
|
||||
})
|
||||
.map_err(Error::CpuidKvmHyperV)?;
|
||||
cpuid
|
||||
.push(CpuIdEntry {
|
||||
function: 0x4000_0004,
|
||||
eax: 1 << 5, // Recommend relaxed timing
|
||||
..Default::default()
|
||||
})
|
||||
.map_err(Error::CpuidKvmHyperV)?;
|
||||
for i in 0x4000_0005..=0x4000_000a {
|
||||
cpuid
|
||||
.push(CpuIdEntry {
|
||||
function: i,
|
||||
..Default::default()
|
||||
})
|
||||
.map_err(Error::CpuidKvmHyperV)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(cpuid)
|
||||
}
|
||||
|
||||
pub fn configure_vcpu(
|
||||
fd: &Arc<dyn hypervisor::Vcpu>,
|
||||
id: u8,
|
||||
@@ -316,7 +729,7 @@ pub fn configure_vcpu(
|
||||
cpuid: CpuId,
|
||||
kvm_hyperv: bool,
|
||||
) -> super::Result<()> {
|
||||
// Per vCPU CPUID changes; common are handled via CpuManager::generate_common_cpuid()
|
||||
// Per vCPU CPUID changes; common are handled via generate_common_cpuid()
|
||||
let mut cpuid = cpuid;
|
||||
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));
|
||||
@@ -613,7 +1026,7 @@ pub fn get_host_cpu_phys_bits() -> u8 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_cpuid_topology(
|
||||
fn update_cpuid_topology(
|
||||
cpuid: &mut CpuId,
|
||||
threads_per_core: u8,
|
||||
cores_per_die: u8,
|
||||
@@ -678,7 +1091,7 @@ pub fn update_cpuid_topology(
|
||||
|
||||
// The goal is to update the CPUID sub-leaves to reflect the number of EPC
|
||||
// sections exposed to the guest.
|
||||
pub fn update_cpuid_sgx(cpuid: &mut CpuId, epc_sections: Vec<SgxEpcSection>) -> Result<(), Error> {
|
||||
fn update_cpuid_sgx(cpuid: &mut CpuId, epc_sections: Vec<SgxEpcSection>) -> Result<(), Error> {
|
||||
// Something's wrong if there's no EPC section.
|
||||
if epc_sections.is_empty() {
|
||||
return Err(Error::NoSgxEpcSection);
|
||||
|
||||
@@ -144,6 +144,7 @@ unsafe impl ByteValued for HobHeader {}
|
||||
struct HobHandoffInfoTable {
|
||||
header: HobHeader,
|
||||
version: u32,
|
||||
boot_mode: u32,
|
||||
efi_memory_top: u64,
|
||||
efi_memory_bottom: u64,
|
||||
efi_free_memory_top: u64,
|
||||
@@ -218,6 +219,7 @@ impl TdHob {
|
||||
reserved: 0,
|
||||
},
|
||||
version: 0x9,
|
||||
boot_mode: 0,
|
||||
efi_memory_top: 0,
|
||||
efi_memory_bottom: 0,
|
||||
efi_free_memory_top: 0,
|
||||
@@ -277,10 +279,10 @@ impl TdHob {
|
||||
},
|
||||
/* TODO:
|
||||
* QEMU currently fills it in like this:
|
||||
* EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED
|
||||
* EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_ENCRYPTED | EFI_RESOURCE_ATTRIBUTE_TESTED
|
||||
* which differs from the spec (due to TDVF implementation issue?)
|
||||
*/
|
||||
0x7,
|
||||
0x04000007,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,15 +9,16 @@ default = []
|
||||
io_uring = []
|
||||
|
||||
[dependencies]
|
||||
io-uring = ">=0.4.0"
|
||||
libc = "0.2.96"
|
||||
io-uring = "0.5.2"
|
||||
libc = "0.2.101"
|
||||
log = "0.4.14"
|
||||
qcow = { path = "../qcow" }
|
||||
thiserror = "1.0"
|
||||
thiserror = "1.0.29"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
virtio-bindings = { version = "0.1", features = ["virtio-v5_0_0"]}
|
||||
vm-memory = { version = "0.5.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = ">=0.3.1"
|
||||
vmm-sys-util = "0.8.0"
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ pub mod qcow_sync;
|
||||
pub mod raw_async;
|
||||
pub mod raw_sync;
|
||||
pub mod vhd;
|
||||
pub mod vhdx_sync;
|
||||
|
||||
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult, DiskFileError, DiskFileResult};
|
||||
#[cfg(feature = "io_uring")]
|
||||
@@ -187,8 +188,8 @@ impl Request {
|
||||
}
|
||||
|
||||
let mut req = Request {
|
||||
request_type: request_type(&mem, avail_desc.addr)?,
|
||||
sector: sector(&mem, avail_desc.addr)?,
|
||||
request_type: request_type(mem, avail_desc.addr)?,
|
||||
sector: sector(mem, avail_desc.addr)?,
|
||||
data_descriptors: Vec::new(),
|
||||
status_addr: GuestAddress(0),
|
||||
writeback: true,
|
||||
@@ -288,7 +289,7 @@ impl Request {
|
||||
if (*data_len as usize) < disk_id.len() {
|
||||
return Err(ExecuteError::BadRequest(Error::InvalidOffset));
|
||||
}
|
||||
mem.write_slice(&disk_id.as_slice(), *data_addr)
|
||||
mem.write_slice(disk_id.as_slice(), *data_addr)
|
||||
.map_err(ExecuteError::Write)?;
|
||||
}
|
||||
RequestType::Unsupported(t) => return Err(ExecuteError::Unsupported(t)),
|
||||
@@ -602,9 +603,11 @@ pub enum ImageType {
|
||||
FixedVhd,
|
||||
Qcow2,
|
||||
Raw,
|
||||
Vhdx,
|
||||
}
|
||||
|
||||
const QCOW_MAGIC: u32 = 0x5146_49fb;
|
||||
const VHDX_SIGN: u64 = 0x656C_6966_7864_6876;
|
||||
|
||||
/// Determine image type through file parsing.
|
||||
pub fn detect_image_type(f: &mut File) -> std::io::Result<ImageType> {
|
||||
@@ -623,6 +626,8 @@ pub fn detect_image_type(f: &mut File) -> std::io::Result<ImageType> {
|
||||
ImageType::Qcow2
|
||||
} else if vhd::is_fixed_vhd(f)? {
|
||||
ImageType::FixedVhd
|
||||
} else if u64::from_le_bytes(s.data[0..8].try_into().unwrap()) == VHDX_SIGN {
|
||||
ImageType::Vhdx
|
||||
} else {
|
||||
ImageType::Raw
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileResult};
|
||||
use crate::{disk_size, fsync_sync, read_vectored_sync, write_vectored_sync};
|
||||
use qcow::{QcowFile, RawFile};
|
||||
use qcow::{QcowFile, RawFile, Result as QcowResult};
|
||||
use std::fs::File;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@@ -15,12 +15,11 @@ pub struct QcowDiskSync {
|
||||
}
|
||||
|
||||
impl QcowDiskSync {
|
||||
pub fn new(file: File, direct_io: bool) -> Self {
|
||||
QcowDiskSync {
|
||||
qcow_file: QcowFile::from(RawFile::new(file, direct_io))
|
||||
.expect("Failed creating QcowFile"),
|
||||
pub fn new(file: File, direct_io: bool) -> QcowResult<Self> {
|
||||
Ok(QcowDiskSync {
|
||||
qcow_file: QcowFile::from(RawFile::new(file, direct_io))?,
|
||||
semaphore: Arc::new(Mutex::new(())),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ mod tests {
|
||||
let mut disk_file: File = TempFile::new().unwrap().into_file();
|
||||
disk_file.set_len(0x1000_0200).unwrap();
|
||||
disk_file.seek(SeekFrom::Start(0x1000_0000)).unwrap();
|
||||
disk_file.write_all(&footer).unwrap();
|
||||
disk_file.write_all(footer).unwrap();
|
||||
|
||||
testfn(disk_file); // File closed when the function exits.
|
||||
}
|
||||
|
||||
113
block_util/src/vhdx_sync.rs
Normal file
113
block_util/src/vhdx_sync.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright © 2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
|
||||
use crate::{fsync_sync, read_vectored_sync, write_vectored_sync};
|
||||
use std::fs::File;
|
||||
use std::ops::DerefMut;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use vhdx::vhdx::{Result as VhdxResult, Vhdx};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
pub struct VhdxDiskSync {
|
||||
vhdx_file: Arc<Mutex<Vhdx>>,
|
||||
semaphore: Arc<Mutex<()>>,
|
||||
}
|
||||
|
||||
impl VhdxDiskSync {
|
||||
pub fn new(f: File) -> VhdxResult<Self> {
|
||||
let vhdx = Vhdx::new(f)?;
|
||||
let vhdx_file = Arc::new(Mutex::new(vhdx));
|
||||
|
||||
Ok(VhdxDiskSync {
|
||||
vhdx_file,
|
||||
semaphore: Arc::new(Mutex::new(())),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl DiskFile for VhdxDiskSync {
|
||||
fn size(&mut self) -> DiskFileResult<u64> {
|
||||
Ok(self.vhdx_file.lock().unwrap().virtual_disk_size())
|
||||
}
|
||||
|
||||
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||
Ok(Box::new(
|
||||
VhdxSync::new(self.vhdx_file.clone(), self.semaphore.clone())
|
||||
.map_err(DiskFileError::NewAsyncIo)?,
|
||||
) as Box<dyn AsyncIo>)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VhdxSync {
|
||||
vhdx_file: Arc<Mutex<Vhdx>>,
|
||||
eventfd: EventFd,
|
||||
completion_list: Vec<(u64, i32)>,
|
||||
semaphore: Arc<Mutex<()>>,
|
||||
}
|
||||
|
||||
impl VhdxSync {
|
||||
pub fn new(vhdx_file: Arc<Mutex<Vhdx>>, semaphore: Arc<Mutex<()>>) -> std::io::Result<Self> {
|
||||
Ok(VhdxSync {
|
||||
vhdx_file,
|
||||
eventfd: EventFd::new(libc::EFD_NONBLOCK)?,
|
||||
completion_list: Vec::new(),
|
||||
semaphore,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncIo for VhdxSync {
|
||||
fn notifier(&self) -> &EventFd {
|
||||
&self.eventfd
|
||||
}
|
||||
|
||||
fn read_vectored(
|
||||
&mut self,
|
||||
offset: libc::off_t,
|
||||
iovecs: Vec<libc::iovec>,
|
||||
user_data: u64,
|
||||
) -> AsyncIoResult<()> {
|
||||
read_vectored_sync(
|
||||
offset,
|
||||
iovecs,
|
||||
user_data,
|
||||
self.vhdx_file.lock().unwrap().deref_mut(),
|
||||
&self.eventfd,
|
||||
&mut self.completion_list,
|
||||
&mut self.semaphore,
|
||||
)
|
||||
}
|
||||
|
||||
fn write_vectored(
|
||||
&mut self,
|
||||
offset: libc::off_t,
|
||||
iovecs: Vec<libc::iovec>,
|
||||
user_data: u64,
|
||||
) -> AsyncIoResult<()> {
|
||||
write_vectored_sync(
|
||||
offset,
|
||||
iovecs,
|
||||
user_data,
|
||||
self.vhdx_file.lock().unwrap().deref_mut(),
|
||||
&self.eventfd,
|
||||
&mut self.completion_list,
|
||||
&mut self.semaphore,
|
||||
)
|
||||
}
|
||||
|
||||
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
|
||||
fsync_sync(
|
||||
user_data,
|
||||
self.vhdx_file.lock().unwrap().deref_mut(),
|
||||
&self.eventfd,
|
||||
&mut self.completion_list,
|
||||
&mut self.semaphore,
|
||||
)
|
||||
}
|
||||
|
||||
fn complete(&mut self) -> Vec<(u64, i32)> {
|
||||
self.completion_list.drain(..).collect()
|
||||
}
|
||||
}
|
||||
@@ -6,19 +6,19 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { path = "../acpi_tables", optional = true }
|
||||
anyhow = "1.0"
|
||||
anyhow = "1.0.43"
|
||||
arch = { path = "../arch" }
|
||||
bitflags = ">=1.2.1"
|
||||
bitflags = "1.3.2"
|
||||
byteorder = "1.4.3"
|
||||
epoll = ">=4.0.1"
|
||||
libc = "0.2.96"
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.101"
|
||||
log = "0.4.14"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = "0.5.0"
|
||||
vm-memory = "0.6.0"
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = ">=0.3.1"
|
||||
vmm-sys-util = "0.8.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -41,7 +41,7 @@ impl BusDevice for AcpiShutdownDevice {
|
||||
|
||||
fn write(&mut self, _base: u64, _offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||
if data[0] == 1 {
|
||||
debug!("ACPI Reboot signalled");
|
||||
info!("ACPI Reboot signalled");
|
||||
if let Err(e) = self.reset_evt.write(1) {
|
||||
error!("Error triggering ACPI reset event: {}", e);
|
||||
}
|
||||
@@ -51,7 +51,7 @@ impl BusDevice for AcpiShutdownDevice {
|
||||
const SLEEP_STATUS_EN_BIT: u8 = 5;
|
||||
const SLEEP_VALUE_BIT: u8 = 2;
|
||||
if data[0] == (S5_SLEEP_VALUE << SLEEP_VALUE_BIT) | (1 << SLEEP_STATUS_EN_BIT) {
|
||||
debug!("ACPI Shutdown signalled");
|
||||
info!("ACPI Shutdown signalled");
|
||||
if let Err(e) = self.exit_evt.write(1) {
|
||||
error!("Error triggering ACPI shutdown event: {}", e);
|
||||
}
|
||||
@@ -62,7 +62,7 @@ impl BusDevice for AcpiShutdownDevice {
|
||||
|
||||
/// A device for handling ACPI GED event generation
|
||||
pub struct AcpiGedDevice {
|
||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||
notification_type: AcpiNotificationFlags,
|
||||
ged_irq: u32,
|
||||
address: GuestAddress,
|
||||
@@ -70,7 +70,7 @@ pub struct AcpiGedDevice {
|
||||
|
||||
impl AcpiGedDevice {
|
||||
pub fn new(
|
||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||
ged_irq: u32,
|
||||
address: GuestAddress,
|
||||
) -> AcpiGedDevice {
|
||||
|
||||
@@ -26,7 +26,7 @@ pub const IRQ_LEGACY_COUNT: usize = 32;
|
||||
// 1. Move Gic*.rs from arch/ folder here.
|
||||
// 2. Move this file and ioapic.rs to arch/, as they are architecture specific.
|
||||
pub struct Gic {
|
||||
interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||
gic_device: Option<Arc<Mutex<Box<dyn GicDevice>>>>,
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ pub struct Ioapic {
|
||||
reg_entries: [RedirectionTableEntry; NUM_IOAPIC_PINS],
|
||||
used_entries: [bool; NUM_IOAPIC_PINS],
|
||||
apic_address: GuestAddress,
|
||||
interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||
}
|
||||
|
||||
#[derive(Versionize)]
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use libc::{clock_gettime, gmtime_r, time_t, timespec, tm, CLOCK_REALTIME};
|
||||
use libc::{clock_gettime, gmtime_r, timespec, tm, CLOCK_REALTIME};
|
||||
use std::cmp::min;
|
||||
use std::mem;
|
||||
use std::sync::{Arc, Barrier};
|
||||
use vm_device::BusDevice;
|
||||
|
||||
// https://github.com/rust-lang/libc/issues/1848
|
||||
#[cfg_attr(target_env = "musl", allow(deprecated))]
|
||||
use libc::time_t;
|
||||
|
||||
const INDEX_MASK: u8 = 0x7f;
|
||||
const INDEX_OFFSET: u64 = 0x0;
|
||||
const DATA_OFFSET: u64 = 0x1;
|
||||
@@ -85,6 +89,8 @@ impl BusDevice for Cmos {
|
||||
let mut timespec: timespec = mem::zeroed();
|
||||
clock_gettime(CLOCK_REALTIME, &mut timespec as *mut _);
|
||||
|
||||
// https://github.com/rust-lang/libc/issues/1848
|
||||
#[cfg_attr(target_env = "musl", allow(deprecated))]
|
||||
let now: time_t = timespec.tv_sec;
|
||||
let mut tm: tm = mem::zeroed();
|
||||
gmtime_r(&now, &mut tm as *mut _);
|
||||
|
||||
@@ -86,7 +86,7 @@ pub struct Gpio {
|
||||
// Mode Control Select Register
|
||||
afsel: u32,
|
||||
// GPIO irq_field
|
||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||
}
|
||||
|
||||
#[derive(Versionize)]
|
||||
@@ -106,7 +106,7 @@ impl VersionMapped for GpioState {}
|
||||
|
||||
impl Gpio {
|
||||
/// Constructs an PL061 GPIO device.
|
||||
pub fn new(id: String, interrupt: Arc<Box<dyn InterruptSourceGroup>>) -> Self {
|
||||
pub fn new(id: String, interrupt: Arc<dyn InterruptSourceGroup>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
data: 0,
|
||||
@@ -297,7 +297,7 @@ impl BusDevice for Gpio {
|
||||
|
||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||
if data.len() <= 4 {
|
||||
let value = read_le_u32(&data);
|
||||
let value = read_le_u32(data);
|
||||
if let Err(e) = self.handle_write(offset, value) {
|
||||
warn!("Failed to write to GPIO PL061 device: {}", e);
|
||||
}
|
||||
@@ -376,14 +376,14 @@ mod tests {
|
||||
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
|
||||
let mut gpio = Gpio::new(
|
||||
String::from(GPIO_NAME),
|
||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
||||
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||
);
|
||||
let mut data = [0; 4];
|
||||
|
||||
// Read and write to the GPIODIR register.
|
||||
// Set pin 0 output pin.
|
||||
write_le_u32(&mut data, 1);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIODIR, &mut data);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIODIR, &data);
|
||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIODIR, &mut data);
|
||||
let v = read_le_u32(&data);
|
||||
assert_eq!(v, 1);
|
||||
@@ -391,8 +391,8 @@ mod tests {
|
||||
// Read and write to the GPIODATA register.
|
||||
write_le_u32(&mut data, 1);
|
||||
// Set pin 0 high.
|
||||
let offset = 0x00000004 as u64;
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, offset, &mut data);
|
||||
let offset = 0x00000004_u64;
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, offset, &data);
|
||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, offset, &mut data);
|
||||
let v = read_le_u32(&data);
|
||||
assert_eq!(v, 1);
|
||||
@@ -400,7 +400,7 @@ mod tests {
|
||||
// Read and write to the GPIOIS register.
|
||||
// Configure pin 0 detecting level interrupt.
|
||||
write_le_u32(&mut data, 1);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIS, &mut data);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIS, &data);
|
||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIS, &mut data);
|
||||
let v = read_le_u32(&data);
|
||||
assert_eq!(v, 1);
|
||||
@@ -408,7 +408,7 @@ mod tests {
|
||||
// Read and write to the GPIOIBE register.
|
||||
// Configure pin 1 detecting both falling and rising edges.
|
||||
write_le_u32(&mut data, 2);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIBE, &mut data);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIBE, &data);
|
||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIBE, &mut data);
|
||||
let v = read_le_u32(&data);
|
||||
assert_eq!(v, 2);
|
||||
@@ -416,7 +416,7 @@ mod tests {
|
||||
// Read and write to the GPIOIEV register.
|
||||
// Configure pin 2 detecting both falling and rising edges.
|
||||
write_le_u32(&mut data, 4);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIEV, &mut data);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIEV, &data);
|
||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIEV, &mut data);
|
||||
let v = read_le_u32(&data);
|
||||
assert_eq!(v, 4);
|
||||
@@ -425,12 +425,12 @@ mod tests {
|
||||
// Configure pin 0...2 capable of triggering their individual interrupts
|
||||
// and then the combined GPIOINTR line.
|
||||
write_le_u32(&mut data, 7);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIE, &mut data);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIE, &data);
|
||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIE, &mut data);
|
||||
let v = read_le_u32(&data);
|
||||
assert_eq!(v, 7);
|
||||
|
||||
let mask = 0x00000002 as u32;
|
||||
let mask = 0x00000002_u32;
|
||||
// emulate an rising pulse in pin 1.
|
||||
gpio.data |= !(gpio.data & mask) & mask;
|
||||
gpio.pl061_internal_update();
|
||||
@@ -443,14 +443,14 @@ mod tests {
|
||||
// Read and Write to the GPIOIC register.
|
||||
// clear interrupt in pin 1.
|
||||
write_le_u32(&mut data, 2);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIC, &mut data);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIC, &data);
|
||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIC, &mut data);
|
||||
let v = read_le_u32(&data);
|
||||
assert_eq!(v, 2);
|
||||
|
||||
// Attempts to write beyond the writable space.
|
||||
write_le_u32(&mut data, 0);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIO_ID_LOW, &mut data);
|
||||
gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIO_ID_LOW, &data);
|
||||
|
||||
let mut data = [0; 4];
|
||||
gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIO_ID_LOW, &mut data);
|
||||
|
||||
@@ -34,7 +34,7 @@ impl BusDevice for I8042Device {
|
||||
|
||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||
if data.len() == 1 && data[0] == 0xfe && offset == 3 {
|
||||
debug!("i8042 reset signalled");
|
||||
info!("i8042 reset signalled");
|
||||
if let Err(e) = self.reset_evt.write(1) {
|
||||
error!("Error triggering i8042 reset event: {}", e);
|
||||
}
|
||||
|
||||
@@ -224,12 +224,12 @@ pub struct Rtc {
|
||||
load: u32,
|
||||
imsc: u32,
|
||||
ris: u32,
|
||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||
}
|
||||
|
||||
impl Rtc {
|
||||
/// Constructs an AMBA PL031 RTC device.
|
||||
pub fn new(interrupt: Arc<Box<dyn InterruptSourceGroup>>) -> Self {
|
||||
pub fn new(interrupt: Arc<dyn InterruptSourceGroup>) -> Self {
|
||||
Self {
|
||||
// This is used only for duration measuring purposes.
|
||||
previous_now: Instant::now(),
|
||||
@@ -328,7 +328,7 @@ impl BusDevice for Rtc {
|
||||
|
||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||
if data.len() <= 4 {
|
||||
let v = read_le_u32(&data);
|
||||
let v = read_le_u32(data);
|
||||
if let Err(e) = self.handle_write(offset, v) {
|
||||
warn!("Failed to write to RTC PL031 device: {}", e);
|
||||
}
|
||||
@@ -450,14 +450,12 @@ mod tests {
|
||||
fn test_rtc_read_write_and_event() {
|
||||
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
|
||||
|
||||
let mut rtc = Rtc::new(Arc::new(Box::new(TestInterrupt::new(
|
||||
intr_evt.try_clone().unwrap(),
|
||||
))));
|
||||
let mut rtc = Rtc::new(Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())));
|
||||
let mut data = [0; 4];
|
||||
|
||||
// Read and write to the MR register.
|
||||
write_le_u32(&mut data, 123);
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCMR, &mut data);
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCMR, &data);
|
||||
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCMR, &mut data);
|
||||
let v = read_le_u32(&data);
|
||||
assert_eq!(v, 123);
|
||||
@@ -466,7 +464,7 @@ mod tests {
|
||||
let v = get_time(ClockType::Real);
|
||||
write_le_u32(&mut data, (v / NANOS_PER_SECOND) as u32);
|
||||
let previous_now_before = rtc.previous_now;
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCLR, &mut data);
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCLR, &data);
|
||||
|
||||
assert!(rtc.previous_now > previous_now_before);
|
||||
|
||||
@@ -478,7 +476,7 @@ mod tests {
|
||||
// Test with non zero value.
|
||||
let non_zero = 1;
|
||||
write_le_u32(&mut data, non_zero);
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &data);
|
||||
// The interrupt line should be on.
|
||||
assert!(rtc.interrupt.notifier(0).unwrap().read().unwrap() == 1);
|
||||
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
|
||||
@@ -487,14 +485,14 @@ mod tests {
|
||||
|
||||
// Now test with 0.
|
||||
write_le_u32(&mut data, 0);
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &data);
|
||||
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
|
||||
let v = read_le_u32(&data);
|
||||
assert_eq!(0, v);
|
||||
|
||||
// Read and write to the ICR register.
|
||||
write_le_u32(&mut data, 1);
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCICR, &mut data);
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCICR, &data);
|
||||
// The interrupt line should be on.
|
||||
assert!(rtc.interrupt.notifier(0).unwrap().read().unwrap() > 1);
|
||||
let v_before = read_le_u32(&data);
|
||||
@@ -506,7 +504,7 @@ mod tests {
|
||||
|
||||
// Attempts to turn off the RTC should not go through.
|
||||
write_le_u32(&mut data, 0);
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCCR, &mut data);
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCCR, &data);
|
||||
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCCR, &mut data);
|
||||
let v = read_le_u32(&data);
|
||||
assert_eq!(v, 1);
|
||||
@@ -514,7 +512,7 @@ mod tests {
|
||||
// Attempts to write beyond the writable space. Using here the space used to read
|
||||
// the CID and PID from.
|
||||
write_le_u32(&mut data, 0);
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, AMBA_ID_LOW, &mut data);
|
||||
rtc.write(LEGACY_RTC_MAPPED_IO_START, AMBA_ID_LOW, &data);
|
||||
// However, reading from the AMBA_ID_LOW should succeed upon read.
|
||||
|
||||
let mut data = [0; 4];
|
||||
|
||||
@@ -63,7 +63,7 @@ pub struct Serial {
|
||||
id: String,
|
||||
interrupt_enable: u8,
|
||||
interrupt_identification: u8,
|
||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||
line_control: u8,
|
||||
line_status: u8,
|
||||
modem_control: u8,
|
||||
@@ -91,7 +91,7 @@ impl VersionMapped for SerialState {}
|
||||
impl Serial {
|
||||
pub fn new(
|
||||
id: String,
|
||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||
out: Option<Box<dyn io::Write + Send>>,
|
||||
) -> Serial {
|
||||
Serial {
|
||||
@@ -113,14 +113,14 @@ impl Serial {
|
||||
/// Constructs a Serial port ready for output.
|
||||
pub fn new_out(
|
||||
id: String,
|
||||
interrupt: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||
out: Box<dyn io::Write + Send>,
|
||||
) -> Serial {
|
||||
Self::new(id, interrupt, Some(out))
|
||||
}
|
||||
|
||||
/// Constructs a Serial port with no connected output.
|
||||
pub fn new_sink(id: String, interrupt: Arc<Box<dyn InterruptSourceGroup>>) -> Serial {
|
||||
pub fn new_sink(id: String, interrupt: Arc<dyn InterruptSourceGroup>) -> Serial {
|
||||
Self::new(id, interrupt, None)
|
||||
}
|
||||
|
||||
@@ -370,7 +370,7 @@ mod tests {
|
||||
let serial_out = SharedBuffer::new();
|
||||
let mut serial = Serial::new_out(
|
||||
String::from(SERIAL_NAME),
|
||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
||||
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||
Box::new(serial_out.clone()),
|
||||
);
|
||||
|
||||
@@ -390,7 +390,7 @@ mod tests {
|
||||
let serial_out = SharedBuffer::new();
|
||||
let mut serial = Serial::new_out(
|
||||
String::from(SERIAL_NAME),
|
||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
||||
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||
Box::new(serial_out),
|
||||
);
|
||||
|
||||
@@ -427,7 +427,7 @@ mod tests {
|
||||
let intr_evt = EventFd::new(0).unwrap();
|
||||
let mut serial = Serial::new_sink(
|
||||
String::from(SERIAL_NAME),
|
||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
||||
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||
);
|
||||
|
||||
// write 1 to the interrupt event fd, so that read doesn't block in case the event fd
|
||||
@@ -449,7 +449,7 @@ mod tests {
|
||||
let intr_evt = EventFd::new(0).unwrap();
|
||||
let mut serial = Serial::new_sink(
|
||||
String::from(SERIAL_NAME),
|
||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
||||
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||
);
|
||||
|
||||
serial.write(0, LCR as u64, &[LCR_DLAB_BIT]);
|
||||
@@ -470,7 +470,7 @@ mod tests {
|
||||
let intr_evt = EventFd::new(0).unwrap();
|
||||
let mut serial = Serial::new_sink(
|
||||
String::from(SERIAL_NAME),
|
||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
||||
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||
);
|
||||
|
||||
serial.write(0, MCR as u64, &[MCR_LOOP_BIT]);
|
||||
@@ -496,7 +496,7 @@ mod tests {
|
||||
let intr_evt = EventFd::new(0).unwrap();
|
||||
let mut serial = Serial::new_sink(
|
||||
String::from(SERIAL_NAME),
|
||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
||||
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||
);
|
||||
|
||||
serial.write(0, SCR as u64, &[0x12]);
|
||||
|
||||
@@ -86,7 +86,7 @@ pub struct Pl011 {
|
||||
ifl: u32,
|
||||
read_count: u32,
|
||||
read_trigger: u32,
|
||||
irq: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
irq: Arc<dyn InterruptSourceGroup>,
|
||||
out: Option<Box<dyn io::Write + Send>>,
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ impl Pl011 {
|
||||
/// Constructs an AMBA PL011 UART device.
|
||||
pub fn new(
|
||||
id: String,
|
||||
irq: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
irq: Arc<dyn InterruptSourceGroup>,
|
||||
out: Option<Box<dyn io::Write + Send>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
@@ -341,7 +341,7 @@ impl BusDevice for Pl011 {
|
||||
|
||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||
if data.len() <= 4 {
|
||||
let v = read_le_u32(&data);
|
||||
let v = read_le_u32(data);
|
||||
if let Err(e) = self.handle_write(offset, v) {
|
||||
warn!("Failed to write to PL011 device: {}", e);
|
||||
}
|
||||
@@ -440,7 +440,7 @@ mod tests {
|
||||
let pl011_out = SharedBuffer::new();
|
||||
let mut pl011 = Pl011::new(
|
||||
String::from(SERIAL_NAME),
|
||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
||||
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||
Some(Box::new(pl011_out.clone())),
|
||||
);
|
||||
|
||||
@@ -460,7 +460,7 @@ mod tests {
|
||||
let pl011_out = SharedBuffer::new();
|
||||
let mut pl011 = Pl011::new(
|
||||
String::from(SERIAL_NAME),
|
||||
Arc::new(Box::new(TestInterrupt::new(intr_evt.try_clone().unwrap()))),
|
||||
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
|
||||
Some(Box::new(pl011_out)),
|
||||
);
|
||||
|
||||
|
||||
44
docs/api.md
44
docs/api.md
@@ -78,27 +78,29 @@ Shut the VMM down | `/vmm.shutdown` | N/A | N/A
|
||||
|
||||
#### Virtual Machine (VM) Actions
|
||||
|
||||
Action | Endpoint | Request Body | Response Body | Prerequisites
|
||||
-----------------------------------|---------------------|---------------------------|--------------------------|---------------------------
|
||||
Create the VM | `/vm.create` | `/schemas/VmConfig` | N/A | The VM is not created yet
|
||||
Delete the VM | `/vm.delete` | N/A | N/A | N/A
|
||||
Boot the VM | `/vm.boot` | N/A | N/A | The VM is created but not booted
|
||||
Shut the VM down | `/vm.shutdown` | N/A | N/A | The VM is booted
|
||||
Reboot the VM | `/vm.reboot` | 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
|
||||
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 a zone | `/vm.resize-zone` | `/schemas/VmResizeZone` | N/A | The VM is booted
|
||||
Dump the VM information | `/vm.info` | N/A | `/schemas/VmInfo` | The VM is created
|
||||
Add VFIO PCI device to the VM | `/vm.add-device` | `/schemas/VmAddDevice` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||
Add disk device to the VM | `/vm.add-disk` | `/schemas/DiskConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||
Add fs device to the VM | `/vm.add-fs` | `/schemas/FsConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||
Add pmem device to the VM | `/vm.add-pmem` | `/schemas/PmemConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||
Add network device to the VM | `/vm.add-net` | `/schemas/NetConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||
Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||
Remove device from the VM | `/vm.remove-device` | `/schemas/VmRemoveDevice` | N/A | The VM is booted
|
||||
Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted
|
||||
Action | Endpoint | Request Body | Response Body | Prerequisites
|
||||
-----------------------------------|----------------------|---------------------------|--------------------------|---------------------------
|
||||
Create the VM | `/vm.create` | `/schemas/VmConfig` | N/A | The VM is not created yet
|
||||
Delete the VM | `/vm.delete` | N/A | N/A | N/A
|
||||
Boot the VM | `/vm.boot` | N/A | N/A | The VM is created but not booted
|
||||
Shut the VM down | `/vm.shutdown` | N/A | N/A | The VM is booted
|
||||
Reboot the VM | `/vm.reboot` | N/A | N/A | The VM is booted
|
||||
Trigger power button of the VM | `/vm.power-button` | 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
|
||||
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 a zone | `/vm.resize-zone` | `/schemas/VmResizeZone` | N/A | The VM is booted
|
||||
Dump the VM information | `/vm.info` | N/A | `/schemas/VmInfo` | The VM is created
|
||||
Add VFIO PCI device to the VM | `/vm.add-device` | `/schemas/VmAddDevice` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||
Add disk device to the VM | `/vm.add-disk` | `/schemas/DiskConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||
Add fs device to the VM | `/vm.add-fs` | `/schemas/FsConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||
Add pmem device to the VM | `/vm.add-pmem` | `/schemas/PmemConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||
Add network device to the VM | `/vm.add-net` | `/schemas/NetConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||
Add userspace PCI device to the VM | `/vm.add-user-device`| `/schemas/VmAddUserDevice`| `/schemas/PciDeviceInfo` | The VM is booted
|
||||
Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||
Remove device from the VM | `/vm.remove-device` | `/schemas/VmRemoveDevice` | N/A | The VM is booted
|
||||
Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted
|
||||
|
||||
### REST API Examples
|
||||
|
||||
|
||||
108
docs/arm64.md
108
docs/arm64.md
@@ -1,58 +1,116 @@
|
||||
# How to build and run Cloud-hypervisor on AArch64
|
||||
# How to build and test Cloud Hypervisor on AArch64
|
||||
|
||||
Cloud-hypervisor is partially enabled on AArch64 architecture.
|
||||
Although all features are not ready yet, you can begin to test Cloud-hypervisor on a AArch64 host by following this guide.
|
||||
This document introduces how to build and test Cloud Hypervisor on AArch64 servers. Currently Cloud Hypervisor cannot be tested on Raspberry PI. Because on AArch64, Cloud Hypervisor requires GICv3-ITS device for PCIe MSI interrupt handling. But GICv3-ITS has not been equipped on any Raspberry PI product so far.
|
||||
|
||||
Now Cloud Hypervisor supports 2 ways of booting on AArch64: UEFI booting and direct-kernel booting. The document covers both of the ways.
|
||||
|
||||
All the steps are based on Ubuntu. We use the Ubuntu cloud image for guest VM disk.
|
||||
|
||||
## Getting started
|
||||
|
||||
We create a folder to build and run Cloud Hypervisor at `$HOME/cloud-hypervisor`
|
||||
|
||||
```shell
|
||||
$ export CLOUDH=$HOME/cloud-hypervisor
|
||||
$ mkdir $CLOUDH
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
On AArch64 machines, Cloud-hypervisor depends on an external library `libfdt-dev` for generating Flattened Device Tree (FDT).
|
||||
You need to install some prerequisite packages to build and test Cloud Hypervisor.
|
||||
|
||||
The long-term plan is to replace `libfdt-dev` with some pure-Rust component to get rid of such dependency.
|
||||
### Tools
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install libfdt-dev
|
||||
# Install rust tool chain
|
||||
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
# Install the tools used for building guest kernel, EDK2 and converting guest disk
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get install git build-essential m4 bison flex uuid-dev qemu-utils
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
Using PCI devices requires GICv3-ITS for MSI messaging. GICv3-ITS is very common in modern servers.
|
||||
### Building Cloud Hypervisor
|
||||
|
||||
```bash
|
||||
cargo build --no-default-features --features kvm
|
||||
$ pushd $CLOUDH
|
||||
$ git clone https://github.com/cloud-hypervisor/cloud-hypervisor.git
|
||||
$ cd cloud-hypervisor
|
||||
$ cargo build
|
||||
$ popd
|
||||
```
|
||||
|
||||
## Image
|
||||
### Disk image
|
||||
|
||||
Download kernel binary and rootfs image from AWS.
|
||||
Download the Ubuntu cloud image and convert the image type.
|
||||
|
||||
```bash
|
||||
wget https://s3.amazonaws.com/spec.ccfc.min/img/aarch64/ubuntu_with_ssh/fsfiles/xenial.rootfs.ext4 -O rootfs.ext4
|
||||
wget https://s3.amazonaws.com/spec.ccfc.min/img/aarch64/ubuntu_with_ssh/kernel/vmlinux.bin -O kernel.bin
|
||||
$ pushd $CLOUDH
|
||||
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-arm64.img
|
||||
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-arm64.img focal-server-cloudimg-arm64.raw
|
||||
$ popd
|
||||
```
|
||||
|
||||
## Containerized build
|
||||
## UEFI booting
|
||||
|
||||
If you want to build and test Cloud Hypervisor without having to install all the required dependencies, you can also turn to the development script: dev_cli.sh.
|
||||
This part introduces how to build EDK2 firmware and boot Cloud Hypervisor with it.
|
||||
|
||||
To build the development container:
|
||||
### Building EDK2
|
||||
|
||||
```bash
|
||||
./scripts/dev_cli.sh build-container
|
||||
$ pushd $CLOUDH
|
||||
|
||||
# Clone source code repos
|
||||
$ git clone --depth 1 https://github.com/tianocore/edk2.git -b master
|
||||
$ cd edk2
|
||||
$ git submodule update --init
|
||||
$ cd ..
|
||||
$ git clone --depth 1 https://github.com/tianocore/edk2-platforms.git -b master
|
||||
$ git clone --depth 1 https://github.com/acpica/acpica.git -b master
|
||||
|
||||
# Build tools
|
||||
$ export PACKAGES_PATH="$PWD/edk2:$PWD/edk2-platforms"
|
||||
$ export IASL_PREFIX="$PWD/acpica/generate/unix/bin/"
|
||||
$ make -C acpica
|
||||
$ cd edk2/
|
||||
$ . edksetup.sh
|
||||
$ cd ..
|
||||
$ make -C edk2/BaseTools
|
||||
|
||||
# Build EDK2
|
||||
$ build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtCloudHv.dsc -b RELEASE
|
||||
|
||||
$ popd
|
||||
```
|
||||
|
||||
To build Cloud-hypervisor in the container:
|
||||
If the build goes well, the EDK2 binary is available at `edk2/Build/ArmVirtCloudHv-AARCH64/RELEASE_GCC5/FV/CLOUDHV_EFI.fd`.
|
||||
|
||||
### Booting the guest VM
|
||||
|
||||
```bash
|
||||
./scripts/dev_cli.sh build
|
||||
$ pushd $CLOUDH
|
||||
$ sudo RUST_BACKTRACE=1 $CLOUDH/cloud-hypervisor/target/debug/cloud-hypervisor --api-socket /tmp/cloud-hypervisor.sock --kernel $CLOUDH/edk2/edk2/Build/ArmVirtCloudHv-AARCH64/RELEASE_GCC5/FV/CLOUDHV_EFI.fd --disk path=$CLOUDH/focal-server-cloudimg-arm64.raw --cpus boot=4 --memory size=4096M --serial tty --console off --log-file log.log -vvv --net tap=,mac=12:34:56:78:90:01,ip=192.168.1.1,mask=255.255.255.0
|
||||
$ popd
|
||||
```
|
||||
|
||||
## Run
|
||||
## Direct-kernel booting
|
||||
|
||||
Assuming you have built Cloud-hypervisor with the development container, a VM can be started with command:
|
||||
Alternativelly, you can build your own kernel for guest VM. This way, UEFI is not involved and ACPI cannot be enabled.
|
||||
|
||||
### Building kernel
|
||||
|
||||
```bash
|
||||
sudo build/cargo_target/aarch64-unknown-linux-gnu/debug/cloud-hypervisor --kernel kernel.bin --disk path=rootfs.ext4 --cmdline "keep_bootcon console=hvc0 reboot=k panic=1 root=/dev/vda rw" --cpus boot=4 --memory size=512M --serial file=serial.log --log-file log.log -vvv
|
||||
$ pushd $CLOUDH
|
||||
$ git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b ch-5.12
|
||||
$ cd linux
|
||||
$ cp $CLOUDH/cloud-hypervisor/resources/linux-config-aarch64 .config
|
||||
$ make -j `nproc`
|
||||
$ popd
|
||||
```
|
||||
|
||||
If the build was done out of the container, replace the binary path with `target/debug/cloud-hypervisor`.
|
||||
### Booting the guest VM
|
||||
|
||||
```bash
|
||||
$ pushd $CLOUDH
|
||||
$ sudo $CLOUDH/cloud-hypervisor/target/debug/cloud-hypervisor --api-socket /tmp/cloud-hypervisor.sock --kernel $CLOUDH/linux/arch/arm64/boot/Image --disk path=focal-server-cloudimg-arm64.raw --cmdline "keep_bootcon console=ttyAMA0 reboot=k panic=1 root=/dev/vda1 rw" --cpus boot=4 --memory size=4096M --serial tty --console off --log-file log.log -vvv --net "tap=,mac=,ip=,mask="
|
||||
$ popd
|
||||
```
|
||||
|
||||
@@ -20,10 +20,10 @@ cargo install cargo-fuzz
|
||||
|
||||
## Running the fuzzers
|
||||
|
||||
e.g. To run the `qcow` fuzzer using all available CPUs:
|
||||
e.g. To run the `block` fuzzer using all available CPUs:
|
||||
|
||||
```
|
||||
cargo fuzz run qcow -j `nproc`
|
||||
cargo fuzz run block -j `nproc`
|
||||
```
|
||||
|
||||
## Adding a new fuzzer
|
||||
@@ -32,4 +32,4 @@ cargo fuzz run qcow -j `nproc`
|
||||
cargo fuzz add <new_fuzzer>
|
||||
```
|
||||
|
||||
Inspiration for fuzzers can be found in [crosvm](https://chromium.googlesource.com/chromiumos/platform/crosvm/+/refs/heads/master/fuzz/)
|
||||
Inspiration for fuzzers can be found in [crosvm](https://chromium.googlesource.com/chromiumos/platform/crosvm/+/refs/heads/master/fuzz/)
|
||||
|
||||
@@ -34,7 +34,7 @@ memory, the second one being 32MiB with no pre-allocated memory.
|
||||
--disk path=focal-server-cloudimg-amd64.raw \
|
||||
--kernel vmlinux \
|
||||
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
|
||||
--sgx-epc size=64M,prefault=on size=32M,prefault=off
|
||||
--sgx-epc id=epc0,size=64M,prefault=on id=epc1,size=32M,prefault=off
|
||||
```
|
||||
|
||||
Once booted, and assuming your guest kernel contains the patches from the
|
||||
|
||||
@@ -36,7 +36,7 @@ $ target/release/ch-remote --api-socket=/tmp/api1 send-migration unix:/tmp/sock
|
||||
|
||||
When the above commands completed, the source VM should be successfully
|
||||
migrated to the destination VM. Now the destination VM is running while
|
||||
the source VM is paused.
|
||||
the source VM is terminated gracefully.
|
||||
|
||||
## Nested-VM Migration
|
||||
|
||||
@@ -136,4 +136,4 @@ vm-1:~$ sudo ./ch-remote --api-socket=/tmp/api1 send-migration unix:/tmp/sock1
|
||||
When the above commands completed, the source VM should be successfully
|
||||
migrated to the destination VM without interrupting our testing guest
|
||||
workload. Now the destination VM is running the testing guest workload
|
||||
while the source VM is paused.
|
||||
while the source VM is terminated gracefully.
|
||||
|
||||
@@ -24,7 +24,7 @@ struct MemoryConfig {
|
||||
```
|
||||
|
||||
```
|
||||
--memory <memory> Memory parameters "size=<guest_memory_size>,mergeable=on|off,shared=on|off,hugepages=on|off,hotplug_method=acpi|virtio-mem,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>"
|
||||
--memory <memory> Memory parameters "size=<guest_memory_size>,mergeable=on|off,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,hotplug_method=acpi|virtio-mem,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>"
|
||||
```
|
||||
|
||||
### `size`
|
||||
@@ -87,7 +87,9 @@ the guest will allocate hugepages as well. Another interesting use case is VFIO
|
||||
as it speeds up the VM's boot time since the amount of IOMMU mappings are
|
||||
reduced.
|
||||
|
||||
The user is responsible for ensuring there are sufficient huge pages of the specified size for the VMM to use. Failure to do so may result in strange VMM behaviour.
|
||||
The user is responsible for ensuring there are sufficient huge pages of the specified size for the VMM to use.
|
||||
Failure to do so may result in strange VMM behaviour, e.g. error with `ReadKernelImage` is common.
|
||||
If there is a strange error with `hugepages` enabled, just disable it or check whether there are enough huge pages.
|
||||
|
||||
By default this option is turned off.
|
||||
|
||||
@@ -343,15 +345,16 @@ it allows for specifying the distance between each NUMA node.
|
||||
|
||||
```rust
|
||||
struct NumaConfig {
|
||||
id: u32,
|
||||
guest_numa_id: u32,
|
||||
cpus: Option<Vec<u8>>,
|
||||
distances: Option<Vec<NumaDistance>>,
|
||||
memory_zones: Option<Vec<String>>,
|
||||
sgx_epc_sections: Option<Vec<String>>,
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
--numa <numa> Settings related to a given NUMA node "id=<node_id>,cpus=<cpus_id>,distances=<list_of_distances_to_destination_nodes>,memory_zones=<list_of_memory_zones>"
|
||||
--numa <numa> Settings related to a given NUMA node "guest_numa_id=<node_id>,cpus=<cpus_id>,distances=<list_of_distances_to_destination_nodes>,memory_zones=<list_of_memory_zones>,sgx_epc_sections=<list_of_sgx_epc_sections>"
|
||||
```
|
||||
|
||||
### `guest_numa_id`
|
||||
@@ -394,8 +397,7 @@ _Example_
|
||||
|
||||
```
|
||||
--cpus boot=8
|
||||
--numa guest_numa_id=0,cpus=1-3:7
|
||||
--numa guest_numa_id=1,cpus=0:4-6
|
||||
--numa guest_numa_id=0,cpus=1-3:7 guest_numa_id=1,cpus=0:4-6
|
||||
```
|
||||
|
||||
### `distances`
|
||||
@@ -420,9 +422,7 @@ different distances, it can be described with the following example.
|
||||
_Example_
|
||||
|
||||
```
|
||||
--numa guest_numa_id=0,distances=1@15:2@25
|
||||
--numa guest_numa_id=1,distances=0@15:2@20
|
||||
--numa guest_numa_id=2,distances=0@25:1@20
|
||||
--numa guest_numa_id=0,distances=1@15:2@25 guest_numa_id=1,distances=0@15:2@20 guest_numa_id=2,distances=0@25:1@20
|
||||
```
|
||||
|
||||
### `memory_zones`
|
||||
@@ -441,13 +441,38 @@ Multiple values can be provided to define the list. Each value is a string
|
||||
referring to an existing memory zone identifier. Values are separated from
|
||||
each other with the `:` separator.
|
||||
|
||||
Note that a memory zone must belong to a single NUMA node. The following
|
||||
configuration is incorrect, therefore not allowed:
|
||||
`--numa guest_numa_id=0,memory_zones=mem0 guest_numa_id=1,memory_zones=mem0`
|
||||
|
||||
_Example_
|
||||
|
||||
```
|
||||
--memory size=0
|
||||
--memory-zone id=mem0,size=1G
|
||||
--memory-zone id=mem1,size=1G
|
||||
--memory-zone id=mem2,size=1G
|
||||
--numa guest_numa_id=0,memory_zones=mem0:mem2
|
||||
--numa guest_numa_id=1,memory_zones=mem1
|
||||
--memory-zone id=mem0,size=1G id=mem1,size=1G id=mem2,size=1G
|
||||
--numa guest_numa_id=0,memory_zones=mem0:mem2 guest_numa_id=1,memory_zones=mem1
|
||||
```
|
||||
|
||||
### `sgx_epc_sections`
|
||||
|
||||
List of SGX EPC sections attached to the guest NUMA node identified by the
|
||||
`guest_numa_id` option. This allows for describing a list of SGX EPC sections
|
||||
which must be seen by the guest as belonging to the NUMA node `guest_numa_id`.
|
||||
|
||||
Multiple values can be provided to define the list. Each value is a string
|
||||
referring to an existing SGX EPC section identifier. Values are separated from
|
||||
each other with the `:` separator.
|
||||
|
||||
_Example_
|
||||
|
||||
```
|
||||
--sgx-epc id=epc0,size=32M id=epc1,size=64M id=epc2,size=32M
|
||||
--numa guest_numa_id=0,sgx_epc_sections=epc1 guest_numa_id=1,sgx_epc_sections=epc0:epc2
|
||||
```
|
||||
|
||||
### PCI bus
|
||||
|
||||
Cloud Hypervisor supports only one PCI bus, which is why it has been tied to
|
||||
the NUMA node 0 by default. It is the user responsibility to organize the NUMA
|
||||
nodes correctly so that vCPUs and guest RAM which should be located on the same
|
||||
NUMA node as the PCI bus end up on the NUMA node 0.
|
||||
|
||||
@@ -41,19 +41,20 @@ CSM is a module that allows to boot legacy operating systems using the OVMF firm
|
||||
|
||||
```shell
|
||||
sudo apt-get update
|
||||
sudo apt-get install uuid-dev nasm iasl build-essential python3-distutils git
|
||||
sudo apt-get install uuid-dev nasm iasl build-essential python3-distutils git libncurses-dev
|
||||
|
||||
git checkout https://github.com/cloud-hypervisor/seabios -b ch
|
||||
git clone https://github.com/cloud-hypervisor/seabios -b ch
|
||||
cd seabios
|
||||
make menuconfig
|
||||
# Enable `CONFIG_CSM` and `CONFIG_QEMU_HARDWARE`
|
||||
# Please make sure `python` is in your path
|
||||
make CONFIG_CSM=y CONFIG_QEMU_HARDWARE=y
|
||||
cd ..
|
||||
|
||||
git clone https://github.com/cloud-hypervisor/edk2 -b ch
|
||||
cd edk2
|
||||
. edksetup.sh
|
||||
git submodule update --init
|
||||
git submodule update --init --recursive
|
||||
cp ../seabios/out/Csm16.bin OvmfPkg/Csm/Csm16/
|
||||
|
||||
echo "ACTIVE_PLATFORM=OvmfPkg/OvmfCh.dsc" >> Conf/target.txt
|
||||
@@ -61,7 +62,7 @@ echo "TARGET_ARCH=X64" >> Conf/target.txt
|
||||
echo "TOOL_CHAIN_TAG=GCC5" >> Conf/target.txt
|
||||
|
||||
make -C ./BaseTools
|
||||
build
|
||||
build -DCSM_ENABLE
|
||||
|
||||
```
|
||||
|
||||
|
||||
77
docs/vfio-user.md
Normal file
77
docs/vfio-user.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Cloud Hypervisor VFIO-user HOWTO
|
||||
|
||||
VFIO-user is an *experimental* protocol for allowing devices to be implemented in another process and communicate over a socket; ie.e VFIO-user is to VFIO as virtio is to vhost-user.
|
||||
|
||||
The protocol is documented here: https://github.com/nutanix/libvfio-user/blob/master/docs/vfio-user.rst
|
||||
|
||||
The Cloud Hypervisor support for such devices is *experimental*. Not all Cloud Hypervisor functionality is supported in particular: virtio-mem and iommu are not supported.
|
||||
|
||||
## Usage
|
||||
|
||||
The `--user-device socket=<path>` parameter is used to create a vfio-user device when creating the VM specifying the socket to connect to. The device can also be hotplugged with `ch-remote add-user-device socket=<path>`.
|
||||
|
||||
## Example (GPIO device)
|
||||
|
||||
There is a simple GPIO device included in the libvfio-user repository: https://github.com/nutanix/libvfio-user#gpio
|
||||
|
||||
Run the example from the libvfio-user repository:
|
||||
|
||||
```sh
|
||||
rm /tmp/vfio-user.sock
|
||||
./build/dbg/samples/gpio-pci-idio-16 -v /tmp/vfio-user.sock &
|
||||
```
|
||||
|
||||
Start Cloud Hypervisor:
|
||||
|
||||
```sh
|
||||
target/debug/cloud-hypervisor \
|
||||
--memory size=1G,shared=on \
|
||||
--disk path=~/images/focal-server-cloudimg-amd64.raw \
|
||||
--kernel ~/src/linux/vmlinux \
|
||||
--cmdline "root=/dev/vda1 console=hvc0" \
|
||||
--user-device socket=/tmp/vfio-user.sock
|
||||
```
|
||||
|
||||
Inside the VM you can test the device with:
|
||||
|
||||
```sh
|
||||
cat /sys/class/gpio/gpiochip480/base > /sys/class/gpio/export
|
||||
for ((i=0;i<12;i++)); do cat /sys/class/gpio/OUT0/value; done
|
||||
```
|
||||
|
||||
## Example (NVMe device)
|
||||
|
||||
Use SPDK: https://github.com/spdk/spdk
|
||||
|
||||
Compile with `./configure --with-vfio-user`
|
||||
|
||||
Create an NVMe controller listening on a vfio-user socket with a simple block device:
|
||||
|
||||
```sh
|
||||
sudo scripts/setup.sh
|
||||
rm ~/images/test-disk.raw
|
||||
truncate ~/images/test-disk.raw -s 128M
|
||||
mkfs.ext4 ~/images/test-disk.raw
|
||||
sudo killall ./build/bin/nvmf_tgt
|
||||
sudo ./build/bin/nvmf_tgt -i 0 -e 0xFFFF -m 0x1 &
|
||||
sleep 2
|
||||
sudo ./scripts/rpc.py nvmf_create_transport -t VFIOUSER
|
||||
sudo rm -rf /tmp/nvme-vfio-user
|
||||
sudo mkdir -p /tmp/nvme-vfio-user
|
||||
sudo ./scripts/rpc.py bdev_aio_create ~/images/test-disk.raw test 512
|
||||
sudo ./scripts/rpc.py nvmf_create_subsystem nqn.2019-07.io.spdk:cnode -a -s test
|
||||
sudo ./scripts/rpc.py nvmf_subsystem_add_ns nqn.2019-07.io.spdk:cnode test
|
||||
sudo ./scripts/rpc.py nvmf_subsystem_add_listener nqn.2019-07.io.spdk:cnode -t VFIOUSER -a /tmp/nvme-vfio-user -s 0
|
||||
sudo chown $USER.$USER -R /tmp/nvme-vfio-user
|
||||
```
|
||||
|
||||
Start Cloud Hypervisor:
|
||||
|
||||
```sh
|
||||
target/debug/cloud-hypervisor \
|
||||
--memory size=1G,shared=on \
|
||||
--disk path=~/images/focal-server-cloudimg-amd64.raw \
|
||||
--kernel ~/src/linux/vmlinux \
|
||||
--cmdline "root=/dev/vda1 console=hvc0" \
|
||||
--user-device socket=/tmp/nvme-vfio-user/cntrl
|
||||
```
|
||||
@@ -30,15 +30,15 @@ This step currently requires QEMU to install Windows onto the guest. QEMU is onl
|
||||
Preparing several command parts as these will be used in the follow up sections as well.
|
||||
|
||||
```shell
|
||||
IMG_FILE=windows-disk.qcow
|
||||
IMG_FILE=windows-disk.raw
|
||||
WIN_ISO_FILE=en_windows_server_version_2004_updated_may_2020_x64_dvd_1e7f1cfa.iso
|
||||
VIRTIO_ISO_FILE=virtio-win-0.1.185.iso
|
||||
OVMF_DIR=./FV
|
||||
```
|
||||
|
||||
Create an empty image file, `qcow` or `raw` is supported.
|
||||
Create an empty image file, `raw` is supported.
|
||||
```shell
|
||||
qemu-img create -f qcow2 $IMG_FILE 30G
|
||||
qemu-img create -f raw $IMG_FILE 30G
|
||||
```
|
||||
|
||||
Begin the Windows installation process under QEMU
|
||||
@@ -221,7 +221,7 @@ qemu-system-x86_64 \
|
||||
-m 4G \
|
||||
-cdrom ./$WIN_ISO_FILE \
|
||||
-drive file=./$VIRTIO_ISO_FILE,index=0,media=cdrom
|
||||
-drive if=none,id=root,file=./windbg-disk.qcow \
|
||||
-drive if=none,id=root,file=./windbg-disk.raw \
|
||||
-device virtio-blk-pci,drive=root,disable-legacy=on \
|
||||
-device virtio-net-pci,netdev=mynet0,disable-legacy=on \
|
||||
-netdev user,id=mynet0,net=192.168.178.0/24,host=192.168.178.1,dhcpstart=192.168.178.64,hostname=windbg-host \
|
||||
@@ -280,7 +280,7 @@ qemu-system-x86_64 \
|
||||
-cpu host \
|
||||
-smp 1 \
|
||||
-m 4G \
|
||||
-drive if=none,id=root,file=./windbg-disk.qcow \
|
||||
-drive if=none,id=root,file=./windbg-disk.raw \
|
||||
-device virtio-blk-pci,drive=root,disable-legacy=on \
|
||||
-serial tcp::4445,server,nowait \
|
||||
-device virtio-net-pci,netdev=mynet0,disable-legacy=on \
|
||||
|
||||
@@ -5,7 +5,7 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.96"
|
||||
serde = {version = ">=1.0.27", features = ["rc"] }
|
||||
serde_derive = ">=1.0.27"
|
||||
serde_json = ">=1.0.9"
|
||||
libc = "0.2.101"
|
||||
serde = { version = "1.0.130", features = ["rc"] }
|
||||
serde_derive = "1.0.130"
|
||||
serde_json = "1.0.67"
|
||||
|
||||
216
fuzz/Cargo.lock
generated
216
fuzz/Cargo.lock
generated
@@ -20,25 +20,28 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.40"
|
||||
version = "1.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
|
||||
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
|
||||
|
||||
[[package]]
|
||||
name = "api_client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "237430fd6ed3740afe94eefcc278ae21e050285be882804e0d6e8695f0c94691"
|
||||
checksum = "577b08a4acd7b99869f863c50011b01eb73424ccc798ecd996f2e24817adfca7"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.3.0"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e906254e445520903e7fc9da4f709886c84ae4bc4ddaf0e093188d66df4dc820"
|
||||
checksum = "b5ab7d9e73059c86c36473f459b52adbd99c3554a4fec492caef460806006f00"
|
||||
|
||||
[[package]]
|
||||
name = "arch"
|
||||
@@ -47,6 +50,7 @@ dependencies = [
|
||||
"acpi_tables",
|
||||
"anyhow",
|
||||
"byteorder",
|
||||
"fdt",
|
||||
"hypervisor",
|
||||
"libc",
|
||||
"linux-loader",
|
||||
@@ -58,6 +62,7 @@ dependencies = [
|
||||
"vm-fdt",
|
||||
"vm-memory",
|
||||
"vm-migration",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -82,9 +87,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "block_util"
|
||||
@@ -97,6 +102,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"vhdx",
|
||||
"virtio-bindings",
|
||||
"vm-memory",
|
||||
"vm-virtio",
|
||||
@@ -111,9 +117,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.68"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
|
||||
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -139,7 +145,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cloud-hypervisor"
|
||||
version = "15.0.0"
|
||||
version = "17.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"api_client",
|
||||
@@ -150,7 +156,7 @@ dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"option_parser",
|
||||
"seccomp",
|
||||
"seccompiler",
|
||||
"serde_json",
|
||||
"signal-hook",
|
||||
"thiserror",
|
||||
@@ -168,13 +174,23 @@ dependencies = [
|
||||
"libc",
|
||||
"libfuzzer-sys",
|
||||
"qcow",
|
||||
"seccomp",
|
||||
"seccompiler",
|
||||
"vhdx",
|
||||
"virtio-devices",
|
||||
"vm-memory",
|
||||
"vm-virtio",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32c"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "210cdf933e6a81212bfabf90cd8762f471b5922e5f6b709547673ad8e04b9448"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc64"
|
||||
version = "1.0.0"
|
||||
@@ -222,10 +238,27 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.18"
|
||||
name = "fdt"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
|
||||
checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -251,9 +284,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iced-x86"
|
||||
version = "1.11.3"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d907dfc273d9ed0da940e8145ceb77759056a1fb2110b44b83d1b203cddb906"
|
||||
checksum = "7383772b06135cede839b7270023b46403656a9148024886e721e82639d3f90e"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"static_assertions",
|
||||
@@ -261,9 +294,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "io-uring"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb82832e05cc4ca298f198a8db108837b4f7b7b1248e3cba8e48f151aece80cf"
|
||||
checksum = "8d75829ed9377bab6c90039fe47b9d84caceb4b5063266142e21bcce6550cda8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@@ -271,9 +304,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.7"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "kvm-bindings"
|
||||
@@ -304,9 +337,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.96"
|
||||
version = "0.2.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5600b4e6efc5421841a2138a6b082e07fe12f9aaa12783d50e5d13325b26b4fc"
|
||||
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
@@ -340,7 +373,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "micro_http"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#9b605a8b61df602cda62076d30d9f70307ea336f"
|
||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#9517a300370a158a7af0996b7eebf040d171e1a4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"vmm-sys-util",
|
||||
@@ -373,9 +406,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.7.2"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
|
||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||
|
||||
[[package]]
|
||||
name = "option_parser"
|
||||
@@ -390,10 +423,12 @@ dependencies = [
|
||||
"hypervisor",
|
||||
"libc",
|
||||
"log",
|
||||
"thiserror",
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"vfio-bindings",
|
||||
"vfio-ioctls",
|
||||
"vfio_user",
|
||||
"vm-allocator",
|
||||
"vm-device",
|
||||
"vm-memory",
|
||||
@@ -403,9 +438,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.27"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
|
||||
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
@@ -450,6 +485,15 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
@@ -457,24 +501,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "seccomp"
|
||||
name = "seccompiler"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/firecracker-microvm/firecracker?tag=v0.24.4#8f44986a0e956a77f2b2324c12f73bec16130c82"
|
||||
source = "git+https://github.com/rust-vmm/seccompiler#da5788d52f1ae8886d8ed4624199b7e9fa64ac04"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.126"
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
|
||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.126"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
|
||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -483,9 +542,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.64"
|
||||
version = "1.0.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
||||
checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -494,9 +553,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.9"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "470c5a6397076fae0094aaf06a08e6ba6f37acb77d3b1b91ea92b4d6c8650c39"
|
||||
checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
@@ -525,9 +584,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.73"
|
||||
version = "1.0.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
|
||||
checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -556,18 +615,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.25"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6"
|
||||
checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.25"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d"
|
||||
checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -591,6 +650,9 @@ name = "uuid"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
@@ -618,8 +680,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "versionize_derive"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "140aa9fd298f667ea50fa1cb0d8530076924079285c623b18b8f8a1c28386b4a"
|
||||
source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch#ae35ef7a3ddabd3371ab8ac0193a383aff6e4b1b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -638,7 +699,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio-ioctls"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=master#5cb8550556620546e74b9fe6d1174e0d1fc83888"
|
||||
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=main#a8ee64b978ccd000df88732814d626651a091891"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"kvm-bindings",
|
||||
@@ -649,13 +710,45 @@ dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vfio_user"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"libc",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"vfio-bindings",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vhdx"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crc32c",
|
||||
"libc",
|
||||
"log",
|
||||
"remain",
|
||||
"thiserror",
|
||||
"uuid",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vhost"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vhost?branch=master#e5b930b73a47cbdd79858e2e68bcb57123d1c1f3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a6b90237e10f1a61b35fba73885c3567e1a5a8c40d44daae335f7710210a7dc"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
@@ -682,7 +775,7 @@ dependencies = [
|
||||
"net_util",
|
||||
"pci",
|
||||
"rate_limiter",
|
||||
"seccomp",
|
||||
"seccompiler",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
@@ -724,12 +817,13 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vm-fdt"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vm-fdt?branch=master#13ab882e2f8387753064351c69fbe35c422b448b"
|
||||
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#720e48e435b791ec6cbe8d2b229448b71dcb1ab9"
|
||||
|
||||
[[package]]
|
||||
name = "vm-memory"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/rust-vmm/vm-memory?rev=5bd7138758183a73ac0da27ce40c004d95f1a7e9#5bd7138758183a73ac0da27ce40c004d95f1a7e9"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a8ebcb86ca457f9d6e14cf97009f679952eba42f0113de5db596e514cd0e43b"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"libc",
|
||||
@@ -783,7 +877,7 @@ dependencies = [
|
||||
"option_parser",
|
||||
"pci",
|
||||
"qcow",
|
||||
"seccomp",
|
||||
"seccompiler",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
@@ -793,6 +887,7 @@ dependencies = [
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"vfio-ioctls",
|
||||
"vhdx",
|
||||
"virtio-devices",
|
||||
"vm-allocator",
|
||||
"vm-device",
|
||||
@@ -814,6 +909,12 @@ dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@@ -835,3 +936,8 @@ name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[patch.unused]]
|
||||
name = "vm-memory"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/rust-vmm/vm-memory?rev=5bd7138758183a73ac0da27ce40c004d95f1a7e9#5bd7138758183a73ac0da27ce40c004d95f1a7e9"
|
||||
|
||||
@@ -10,14 +10,15 @@ cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
block_util = { path = "../block_util" }
|
||||
libc = "0.2.96"
|
||||
libc = "0.2.101"
|
||||
libfuzzer-sys = "0.4.2"
|
||||
qcow = { path = "../qcow" }
|
||||
seccomp = { git = "https://github.com/firecracker-microvm/firecracker", tag = "v0.24.4" }
|
||||
seccompiler = { git = "https://github.com/rust-vmm/seccompiler"}
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-devices = { path = "../virtio-devices" }
|
||||
vmm-sys-util = "0.8.0"
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vm-memory = "0.5.0"
|
||||
vm-memory = "0.6.0"
|
||||
|
||||
[dependencies.cloud-hypervisor]
|
||||
path = ".."
|
||||
@@ -25,6 +26,7 @@ path = ".."
|
||||
[patch.crates-io]
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.4.0", features = ["with-serde", "fam-wrappers"] }
|
||||
vm-memory = { git = "https://github.com/rust-vmm/vm-memory", rev = "5bd7138758183a73ac0da27ce40c004d95f1a7e9"}
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||
|
||||
# Prevent this from interfering with workspaces
|
||||
[workspace]
|
||||
@@ -41,3 +43,9 @@ name = "block"
|
||||
path = "fuzz_targets/block.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "vhdx"
|
||||
path = "fuzz_targets/vhdx.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#![no_main]
|
||||
|
||||
use block_util::{async_io::DiskFile, qcow_sync::QcowDiskSync};
|
||||
use block_util::{async_io::DiskFile, raw_sync::RawFileDiskSync};
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use seccomp::SeccompAction;
|
||||
use seccompiler::SeccompAction;
|
||||
use std::ffi;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Cursor, Read, Seek, SeekFrom};
|
||||
@@ -17,7 +17,7 @@ use std::sync::Arc;
|
||||
use virtio_devices::{Block, VirtioDevice, VirtioInterrupt, VirtioInterruptType};
|
||||
use vm_memory::{Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryMmap};
|
||||
use vm_virtio::Queue;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
|
||||
|
||||
const MEM_SIZE: u64 = 256 * 1024 * 1024;
|
||||
const DESC_SIZE: u64 = 16; // Bytes in one virtio descriptor.
|
||||
@@ -84,7 +84,7 @@ fuzz_target!(|bytes| {
|
||||
|
||||
let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap();
|
||||
let disk_file: File = unsafe { File::from_raw_fd(shm) };
|
||||
let qcow_disk = Box::new(QcowDiskSync::new(disk_file, false)) as Box<dyn DiskFile>;
|
||||
let qcow_disk = Box::new(RawFileDiskSync::new(disk_file)) as Box<dyn DiskFile>;
|
||||
|
||||
let mut block = Block::new(
|
||||
"tmp".to_owned(),
|
||||
@@ -96,6 +96,7 @@ fuzz_target!(|bytes| {
|
||||
256,
|
||||
SeccompAction::Allow,
|
||||
None,
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
53
fuzz/fuzz_targets/vhdx.rs
Normal file
53
fuzz/fuzz_targets/vhdx.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright © 2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#![no_main]
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use std::ffi;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read, Seek, SeekFrom, Write};
|
||||
use std::os::unix::io::{FromRawFd, RawFd};
|
||||
use vhdx::vhdx::Vhdx;
|
||||
|
||||
// Populate the corpus directory with a test file:
|
||||
// truncate -s 16M /tmp/source
|
||||
// qemu-img convert -O vhdx /tmp/source fuzz/corpus/vhdx/test.vhdx
|
||||
// Run with:
|
||||
// cargo fuzz run vhdx -j 32 -- -max_len=16777216
|
||||
fuzz_target!(|bytes| {
|
||||
let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap();
|
||||
let mut disk_file: File = unsafe { File::from_raw_fd(shm) };
|
||||
disk_file.write_all(&bytes[..]).unwrap();
|
||||
disk_file.seek(SeekFrom::Start(0)).unwrap();
|
||||
|
||||
if let Ok(mut vhdx) = Vhdx::new(disk_file) {
|
||||
if vhdx.seek(SeekFrom::Start(0)).is_ok() {
|
||||
let mut offset = 0;
|
||||
while offset < bytes.len() {
|
||||
let mut data = vec![0; 8192];
|
||||
vhdx.read_exact(&mut data).ok();
|
||||
offset += data.len();
|
||||
}
|
||||
}
|
||||
|
||||
if vhdx.seek(SeekFrom::Start(0)).is_ok() {
|
||||
let mut offset = 0;
|
||||
while offset < bytes.len() {
|
||||
let data = vec![0; 8192];
|
||||
vhdx.write_all(&data).ok();
|
||||
offset += data.len();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
fn memfd_create(name: &ffi::CStr, flags: u32) -> Result<RawFd, io::Error> {
|
||||
let res = unsafe { libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags) };
|
||||
|
||||
if res < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(res as RawFd)
|
||||
}
|
||||
}
|
||||
@@ -11,25 +11,25 @@ mshv = ["mshv-ioctls", "mshv-bindings"]
|
||||
tdx = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
epoll = ">=4.0.1"
|
||||
thiserror = "1.0"
|
||||
libc = "0.2.96"
|
||||
anyhow = "1.0.43"
|
||||
epoll = "4.3.1"
|
||||
thiserror = "1.0.29"
|
||||
libc = "0.2.101"
|
||||
log = "0.4.14"
|
||||
kvm-ioctls = { version = "0.9.0", optional = true }
|
||||
kvm-ioctls = { version = "0.9.0", optional = true }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.4.0", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-bindings = {git = "https://github.com/cloud-hypervisor/mshv", branch = "master", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-ioctls = { git = "https://github.com/cloud-hypervisor/mshv", branch = "master", optional = true}
|
||||
serde = {version = ">=1.0.27", features = ["rc"] }
|
||||
serde_derive = ">=1.0.27"
|
||||
serde_json = ">=1.0.9"
|
||||
vm-memory = { version = "0.5.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = { version = ">=0.5.0", features = ["with-serde"] }
|
||||
mshv-bindings = {git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
||||
serde = { version = "1.0.130", features = ["rc"] }
|
||||
serde_derive = "1.0.130"
|
||||
serde_json = "1.0.67"
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = { version = "0.8.0", features = ["with-serde"] }
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
||||
version = "1.11"
|
||||
version = "1.14.0"
|
||||
default-features = false
|
||||
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.8.3"
|
||||
env_logger = "0.9.0"
|
||||
|
||||
@@ -678,7 +678,7 @@ mod mock_vmm {
|
||||
};
|
||||
|
||||
if let Some(mem) = memory {
|
||||
vmm.write_memory(mem.0, &mem.1).unwrap();
|
||||
vmm.write_memory(mem.0, mem.1).unwrap();
|
||||
}
|
||||
|
||||
vmm
|
||||
@@ -693,7 +693,7 @@ mod mock_vmm {
|
||||
let ip = self.cpu_state(cpu_id).unwrap().ip();
|
||||
let mut emulator = Emulator::new(self);
|
||||
|
||||
let new_state = emulator.emulate_insn_stream(cpu_id, &insn, num_insn)?;
|
||||
let new_state = emulator.emulate_insn_stream(cpu_id, insn, num_insn)?;
|
||||
if num_insn.is_none() {
|
||||
assert_eq!(ip + insn.len() as u64, new_state.ip());
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ use crate::x86_64::{
|
||||
use crate::CpuState;
|
||||
#[cfg(feature = "kvm")]
|
||||
use crate::MpState;
|
||||
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
||||
use crate::SuspendRegisters;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::Xsave;
|
||||
#[cfg(feature = "mshv")]
|
||||
@@ -42,6 +44,11 @@ pub enum HypervisorCpuError {
|
||||
#[error("Failed to get standard registers: {0}")]
|
||||
GetStandardRegs(#[source] anyhow::Error),
|
||||
///
|
||||
/// Getting suspend registers error
|
||||
///
|
||||
#[error("Failed to get suspend registers: {0}")]
|
||||
GetSuspendRegs(#[source] anyhow::Error),
|
||||
///
|
||||
/// Setting special register error
|
||||
///
|
||||
#[error("Failed to set special registers: {0}")]
|
||||
@@ -421,4 +428,9 @@ pub trait Vcpu: Send + Sync {
|
||||
///
|
||||
#[cfg(feature = "tdx")]
|
||||
fn tdx_init(&self, hob_address: u64) -> Result<()>;
|
||||
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
||||
///
|
||||
/// Return suspend registers(explicit and intercept suspend registers)
|
||||
///
|
||||
fn get_suspend_regs(&self) -> Result<SuspendRegisters>;
|
||||
}
|
||||
|
||||
@@ -22,13 +22,16 @@ use crate::vm::{self, VmmOps};
|
||||
use crate::{arm64_core_reg_id, offset__of};
|
||||
use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use std::convert::TryInto;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::fs::File;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use std::result;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, RwLock};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use vm_memory::Address;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@@ -87,6 +90,9 @@ pub use {
|
||||
kvm_ioctls::VcpuExit,
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
const KVM_CAP_SGX_ATTRIBUTE: u32 = 196;
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
ioctl_iowr_nr!(KVM_MEMORY_ENCRYPT_OP, KVMIO, 0xba, std::os::raw::c_ulong);
|
||||
|
||||
@@ -105,12 +111,21 @@ enum TdxCommand {
|
||||
pub struct KvmVmState {}
|
||||
|
||||
pub use KvmVmState as VmState;
|
||||
|
||||
struct KvmDirtyLogSlot {
|
||||
slot: u32,
|
||||
guest_phys_addr: u64,
|
||||
memory_size: u64,
|
||||
userspace_addr: u64,
|
||||
}
|
||||
|
||||
/// Wrapper over KVM VM ioctls.
|
||||
pub struct KvmVm {
|
||||
fd: Arc<VmFd>,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
msrs: MsrEntries,
|
||||
state: KvmVmState,
|
||||
dirty_log_slots: Arc<RwLock<HashMap<u32, KvmDirtyLogSlot>>>,
|
||||
}
|
||||
|
||||
///
|
||||
@@ -163,7 +178,7 @@ impl vm::Vm for KvmVm {
|
||||
fn create_vcpu(
|
||||
&self,
|
||||
id: u8,
|
||||
vmmops: Option<Arc<Box<dyn VmmOps>>>,
|
||||
vmmops: Option<Arc<dyn VmmOps>>,
|
||||
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
|
||||
let vc = self
|
||||
.fd
|
||||
@@ -226,7 +241,7 @@ impl vm::Vm for KvmVm {
|
||||
unsafe {
|
||||
let entries_slice: &mut [kvm_irq_routing_entry] =
|
||||
irq_routing[0].entries.as_mut_slice(entries.len());
|
||||
entries_slice.copy_from_slice(&entries);
|
||||
entries_slice.copy_from_slice(entries);
|
||||
}
|
||||
|
||||
self.fd
|
||||
@@ -234,7 +249,7 @@ impl vm::Vm for KvmVm {
|
||||
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
|
||||
}
|
||||
///
|
||||
/// Creates a memory region structure that can be used with set_user_memory_region
|
||||
/// Creates a memory region structure that can be used with {create/remove}_user_memory_region
|
||||
///
|
||||
fn make_user_memory_region(
|
||||
&self,
|
||||
@@ -259,14 +274,57 @@ impl vm::Vm for KvmVm {
|
||||
}
|
||||
}
|
||||
///
|
||||
/// Creates/modifies a guest physical memory slot.
|
||||
/// Creates a guest physical memory region.
|
||||
///
|
||||
fn set_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
|
||||
fn create_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
|
||||
let mut region = user_memory_region;
|
||||
|
||||
if (region.flags & KVM_MEM_LOG_DIRTY_PAGES) != 0 {
|
||||
if (region.flags & KVM_MEM_READONLY) != 0 {
|
||||
return Err(vm::HypervisorVmError::CreateUserMemory(anyhow!(
|
||||
"Error creating regions with both 'dirty-pages-log' and 'read-only'."
|
||||
)));
|
||||
}
|
||||
|
||||
// Keep track of the regions that need dirty pages log
|
||||
self.dirty_log_slots.write().unwrap().insert(
|
||||
region.slot,
|
||||
KvmDirtyLogSlot {
|
||||
slot: region.slot,
|
||||
guest_phys_addr: region.guest_phys_addr,
|
||||
memory_size: region.memory_size,
|
||||
userspace_addr: region.userspace_addr,
|
||||
},
|
||||
);
|
||||
|
||||
// Always create guest physical memory region without `KVM_MEM_LOG_DIRTY_PAGES`.
|
||||
// For regions that need this flag, dirty pages log will be turned on in `start_dirty_log`.
|
||||
region.flags = 0;
|
||||
}
|
||||
|
||||
// Safe because guest regions are guaranteed not to overlap.
|
||||
unsafe {
|
||||
self.fd
|
||||
.set_user_memory_region(user_memory_region)
|
||||
.map_err(|e| vm::HypervisorVmError::SetUserMemory(e.into()))
|
||||
.set_user_memory_region(region)
|
||||
.map_err(|e| vm::HypervisorVmError::CreateUserMemory(e.into()))
|
||||
}
|
||||
}
|
||||
///
|
||||
/// Removes a guest physical memory region.
|
||||
///
|
||||
fn remove_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
|
||||
let mut region = user_memory_region;
|
||||
|
||||
// Remove the corresponding entry from "self.dirty_log_slots" if needed
|
||||
self.dirty_log_slots.write().unwrap().remove(®ion.slot);
|
||||
|
||||
// Setting the size to 0 means "remove"
|
||||
region.memory_size = 0;
|
||||
// Safe because guest regions are guaranteed not to overlap.
|
||||
unsafe {
|
||||
self.fd
|
||||
.set_user_memory_region(region)
|
||||
.map_err(|e| vm::HypervisorVmError::RemoveUserMemory(e.into()))
|
||||
}
|
||||
}
|
||||
///
|
||||
@@ -309,6 +367,18 @@ impl vm::Vm for KvmVm {
|
||||
.map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?;
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn enable_sgx_attribute(&self, file: File) -> vm::Result<()> {
|
||||
let mut cap = kvm_enable_cap {
|
||||
cap: KVM_CAP_SGX_ATTRIBUTE,
|
||||
..Default::default()
|
||||
};
|
||||
cap.args[0] = file.as_raw_fd() as u64;
|
||||
self.fd
|
||||
.enable_cap(&cap)
|
||||
.map_err(|e| vm::HypervisorVmError::EnableSgxAttribute(e.into()))?;
|
||||
Ok(())
|
||||
}
|
||||
/// Retrieve guest clock.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn get_clock(&self) -> vm::Result<ClockData> {
|
||||
@@ -351,10 +421,58 @@ impl vm::Vm for KvmVm {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Start logging dirty pages
|
||||
///
|
||||
fn start_dirty_log(&self) -> vm::Result<()> {
|
||||
let dirty_log_slots = self.dirty_log_slots.read().unwrap();
|
||||
for (_, s) in dirty_log_slots.iter() {
|
||||
let region = MemoryRegion {
|
||||
slot: s.slot,
|
||||
guest_phys_addr: s.guest_phys_addr,
|
||||
memory_size: s.memory_size,
|
||||
userspace_addr: s.userspace_addr,
|
||||
flags: KVM_MEM_LOG_DIRTY_PAGES,
|
||||
};
|
||||
// Safe because guest regions are guaranteed not to overlap.
|
||||
unsafe {
|
||||
self.fd
|
||||
.set_user_memory_region(region)
|
||||
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Stop logging dirty pages
|
||||
///
|
||||
fn stop_dirty_log(&self) -> vm::Result<()> {
|
||||
let dirty_log_slots = self.dirty_log_slots.read().unwrap();
|
||||
for (_, s) in dirty_log_slots.iter() {
|
||||
let region = MemoryRegion {
|
||||
slot: s.slot,
|
||||
guest_phys_addr: s.guest_phys_addr,
|
||||
memory_size: s.memory_size,
|
||||
userspace_addr: s.userspace_addr,
|
||||
flags: 0,
|
||||
};
|
||||
// Safe because guest regions are guaranteed not to overlap.
|
||||
unsafe {
|
||||
self.fd
|
||||
.set_user_memory_region(region)
|
||||
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Get dirty pages bitmap (one bit per page)
|
||||
///
|
||||
fn get_dirty_log(&self, slot: u32, memory_size: u64) -> vm::Result<Vec<u64>> {
|
||||
fn get_dirty_log(&self, slot: u32, _base_gpa: u64, memory_size: u64) -> vm::Result<Vec<u64>> {
|
||||
self.fd
|
||||
.get_dirty_log(slot, memory_size as usize)
|
||||
.map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into()))
|
||||
@@ -368,15 +486,23 @@ impl vm::Vm for KvmVm {
|
||||
#[repr(C)]
|
||||
struct TdxInitVm {
|
||||
max_vcpus: u32,
|
||||
reserved: u32,
|
||||
tsc_khz: u32,
|
||||
attributes: u64,
|
||||
cpuid: u64,
|
||||
mrconfigid: [u64; 6],
|
||||
mrowner: [u64; 6],
|
||||
mrownerconfig: [u64; 6],
|
||||
reserved: [u64; 43],
|
||||
}
|
||||
let data = TdxInitVm {
|
||||
max_vcpus,
|
||||
reserved: 0,
|
||||
tsc_khz: 0,
|
||||
attributes: 1, // TDX1_TD_ATTRIBUTE_DEBUG,
|
||||
cpuid: cpuid.as_fam_struct_ptr() as u64,
|
||||
mrconfigid: [0; 6],
|
||||
mrowner: [0; 6],
|
||||
mrownerconfig: [0; 6],
|
||||
reserved: [0; 43],
|
||||
};
|
||||
|
||||
tdx_command(
|
||||
@@ -539,6 +665,7 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
||||
fd: vm_fd,
|
||||
msrs,
|
||||
state: VmState {},
|
||||
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -547,6 +674,7 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
||||
Ok(Arc::new(KvmVm {
|
||||
fd: vm_fd,
|
||||
state: VmState {},
|
||||
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -611,7 +739,7 @@ pub struct KvmVcpu {
|
||||
fd: VcpuFd,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
msrs: MsrEntries,
|
||||
vmmops: Option<Arc<Box<dyn vm::VmmOps>>>,
|
||||
vmmops: Option<Arc<dyn vm::VmmOps>>,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
hyperv_synic: AtomicBool,
|
||||
}
|
||||
@@ -801,7 +929,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
///
|
||||
fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> {
|
||||
self.fd
|
||||
.set_xcrs(&xcrs)
|
||||
.set_xcrs(xcrs)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
|
||||
}
|
||||
///
|
||||
@@ -1145,19 +1273,12 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
// call KVM_GET_ONE_REG on each id in order to save all of them. We carve out from the list
|
||||
// the core registers which are represented in the kernel by kvm_regs structure and for which
|
||||
// we can calculate the id based on the offset in the structure.
|
||||
|
||||
reg_list.retain(|regid| *regid != 0);
|
||||
reg_list.as_slice().to_vec().sort_unstable();
|
||||
|
||||
reg_list.retain(|regid| is_system_register(*regid));
|
||||
|
||||
// Now, for the rest of the registers left in the previously fetched register list, we are
|
||||
// simply calling KVM_GET_ONE_REG.
|
||||
let indices = reg_list.as_slice();
|
||||
for (_pos, index) in indices.iter().enumerate() {
|
||||
if _pos > 230 {
|
||||
break;
|
||||
}
|
||||
for index in indices.iter() {
|
||||
state.push(kvm_bindings::kvm_one_reg {
|
||||
id: *index,
|
||||
addr: self
|
||||
|
||||
@@ -16,7 +16,8 @@ pub use mshv_bindings::*;
|
||||
pub use mshv_ioctls::IoEventAddress;
|
||||
use mshv_ioctls::{set_registers_64, Mshv, NoDatamatch, VcpuFd, VmFd};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use vm::DataMatch;
|
||||
// x86_64 dependencies
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@@ -28,8 +29,21 @@ pub use x86_64::VcpuMshvState as CpuState;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use x86_64::*;
|
||||
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::sync::RwLock;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::fs::File;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
|
||||
const DIRTY_BITMAP_CLEAR_DIRTY: u64 = 0x4;
|
||||
const DIRTY_BITMAP_SET_DIRTY: u64 = 0x8;
|
||||
|
||||
///
|
||||
/// Export generically-named wrappers of mshv-bindings for Unix-based platforms
|
||||
///
|
||||
pub use {
|
||||
mshv_bindings::mshv_create_device as CreateDevice,
|
||||
mshv_bindings::mshv_device_attr as DeviceAttr,
|
||||
mshv_bindings::mshv_msi_routing_entry as IrqRoutingEntry, mshv_ioctls::DeviceFd,
|
||||
};
|
||||
|
||||
pub const PAGE_SHIFT: usize = 12;
|
||||
|
||||
@@ -40,6 +54,11 @@ pub struct HvState {
|
||||
|
||||
pub use HvState as VmState;
|
||||
|
||||
struct MshvDirtyLogSlot {
|
||||
guest_pfn: u64,
|
||||
memory_size: u64,
|
||||
}
|
||||
|
||||
/// Wrapper over mshv system ioctls.
|
||||
pub struct MshvHypervisor {
|
||||
mshv: Mshv,
|
||||
@@ -104,6 +123,7 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
||||
msrs,
|
||||
hv_state: hv_state_init(),
|
||||
vmmops: None,
|
||||
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
|
||||
}))
|
||||
}
|
||||
///
|
||||
@@ -131,7 +151,7 @@ pub struct MshvVcpu {
|
||||
cpuid: CpuId,
|
||||
msrs: MsrEntries,
|
||||
hv_state: Arc<RwLock<HvState>>, // Mshv State
|
||||
vmmops: Option<Arc<Box<dyn vm::VmmOps>>>,
|
||||
vmmops: Option<Arc<dyn vm::VmmOps>>,
|
||||
}
|
||||
|
||||
/// Implementation of Vcpu trait for Microsoft Hypervisor
|
||||
@@ -235,7 +255,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
///
|
||||
fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> {
|
||||
self.fd
|
||||
.set_xcrs(&xcrs)
|
||||
.set_xcrs(xcrs)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@@ -393,22 +413,22 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
}
|
||||
hv_message_type_HVMSG_X64_CPUID_INTERCEPT => {
|
||||
let info = x.to_cpuid_info().unwrap();
|
||||
debug!("cpuid eax: {:x}", info.rax);
|
||||
debug!("cpuid eax: {:x}", { info.rax });
|
||||
Ok(cpu::VmExit::Ignore)
|
||||
}
|
||||
hv_message_type_HVMSG_X64_MSR_INTERCEPT => {
|
||||
let info = x.to_msr_info().unwrap();
|
||||
if info.header.intercept_access_type == 0 {
|
||||
debug!("msr read: {:x}", info.msr_number);
|
||||
debug!("msr read: {:x}", { info.msr_number });
|
||||
} else {
|
||||
debug!("msr write: {:x}", info.msr_number);
|
||||
debug!("msr write: {:x}", { info.msr_number });
|
||||
}
|
||||
Ok(cpu::VmExit::Ignore)
|
||||
}
|
||||
hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT => {
|
||||
//TODO: Handler for VMCALL here.
|
||||
let info = x.to_exception_info().unwrap();
|
||||
debug!("Exception Info {:?}", info.exception_vector);
|
||||
debug!("Exception Info {:?}", { info.exception_vector });
|
||||
Ok(cpu::VmExit::Ignore)
|
||||
}
|
||||
exit => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
||||
@@ -534,6 +554,45 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
|
||||
Ok(r)
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// X86 specific call that returns the vcpu's current "suspend registers".
|
||||
///
|
||||
fn get_suspend_regs(&self) -> cpu::Result<SuspendRegisters> {
|
||||
self.fd
|
||||
.get_suspend_regs()
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetSuspendRegs(e.into()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Device struct for MSHV
|
||||
pub struct MshvDevice {
|
||||
fd: DeviceFd,
|
||||
}
|
||||
|
||||
impl device::Device for MshvDevice {
|
||||
///
|
||||
/// Set device attribute
|
||||
///
|
||||
fn set_device_attr(&self, attr: &DeviceAttr) -> device::Result<()> {
|
||||
self.fd
|
||||
.set_device_attr(attr)
|
||||
.map_err(|e| device::HypervisorDeviceError::SetDeviceAttribute(e.into()))
|
||||
}
|
||||
///
|
||||
/// Get device attribute
|
||||
///
|
||||
fn get_device_attr(&self, attr: &mut DeviceAttr) -> device::Result<()> {
|
||||
self.fd
|
||||
.get_device_attr(attr)
|
||||
.map_err(|e| device::HypervisorDeviceError::GetDeviceAttribute(e.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for MshvDevice {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
struct MshvEmulatorContext<'a> {
|
||||
@@ -559,7 +618,7 @@ impl<'a> MshvEmulatorContext<'a> {
|
||||
|
||||
let result_code = unsafe { r.1.__bindgen_anon_1.result_code };
|
||||
match result_code {
|
||||
hv_translate_gva_result_code_HvTranslateGvaSuccess => Ok(r.0),
|
||||
hv_translate_gva_result_code_HV_TRANSLATE_GVA_SUCCESS => Ok(r.0),
|
||||
_ => Err(PlatformError::TranslateVirtualAddress(anyhow!(result_code))),
|
||||
}
|
||||
}
|
||||
@@ -669,7 +728,8 @@ pub struct MshvVm {
|
||||
msrs: MsrEntries,
|
||||
// Hypervisor State
|
||||
hv_state: Arc<RwLock<HvState>>,
|
||||
vmmops: Option<Arc<Box<dyn vm::VmmOps>>>,
|
||||
vmmops: Option<Arc<dyn vm::VmmOps>>,
|
||||
dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>,
|
||||
}
|
||||
|
||||
fn hv_state_init() -> Arc<RwLock<HvState>> {
|
||||
@@ -708,7 +768,7 @@ impl vm::Vm for MshvVm {
|
||||
debug!("register_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi);
|
||||
|
||||
self.fd
|
||||
.register_irqfd(&fd, gsi)
|
||||
.register_irqfd(fd, gsi)
|
||||
.map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))?;
|
||||
|
||||
Ok(())
|
||||
@@ -720,7 +780,7 @@ impl vm::Vm for MshvVm {
|
||||
debug!("unregister_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi);
|
||||
|
||||
self.fd
|
||||
.unregister_irqfd(&fd, gsi)
|
||||
.unregister_irqfd(fd, gsi)
|
||||
.map_err(|e| vm::HypervisorVmError::UnregisterIrqFd(e.into()))?;
|
||||
|
||||
Ok(())
|
||||
@@ -731,7 +791,7 @@ impl vm::Vm for MshvVm {
|
||||
fn create_vcpu(
|
||||
&self,
|
||||
id: u8,
|
||||
vmmops: Option<Arc<Box<dyn VmmOps>>>,
|
||||
vmmops: Option<Arc<dyn VmmOps>>,
|
||||
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
|
||||
let vcpu_fd = self
|
||||
.fd
|
||||
@@ -751,6 +811,10 @@ impl vm::Vm for MshvVm {
|
||||
fn enable_split_irq(&self) -> vm::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn enable_sgx_attribute(&self, _file: File) -> vm::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn register_ioevent(
|
||||
&self,
|
||||
fd: &EventFd,
|
||||
@@ -789,11 +853,36 @@ impl vm::Vm for MshvVm {
|
||||
.map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into()))
|
||||
}
|
||||
|
||||
/// Creates/modifies a guest physical memory slot.
|
||||
fn set_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
|
||||
/// Creates a guest physical memory region.
|
||||
fn create_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
|
||||
// No matter read only or not we keep track the slots.
|
||||
// For readonly hypervisor can enable the dirty bits,
|
||||
// but a VM exit happens before setting the dirty bits
|
||||
self.dirty_log_slots.write().unwrap().insert(
|
||||
user_memory_region.guest_pfn,
|
||||
MshvDirtyLogSlot {
|
||||
guest_pfn: user_memory_region.guest_pfn,
|
||||
memory_size: user_memory_region.size,
|
||||
},
|
||||
);
|
||||
|
||||
self.fd
|
||||
.map_user_memory(user_memory_region)
|
||||
.map_err(|e| vm::HypervisorVmError::SetUserMemory(e.into()))?;
|
||||
.map_err(|e| vm::HypervisorVmError::CreateUserMemory(e.into()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes a guest physical memory region.
|
||||
fn remove_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
|
||||
// Remove the corresponding entry from "self.dirty_log_slots" if needed
|
||||
self.dirty_log_slots
|
||||
.write()
|
||||
.unwrap()
|
||||
.remove(&user_memory_region.guest_pfn);
|
||||
|
||||
self.fd
|
||||
.unmap_user_memory(user_memory_region)
|
||||
.map_err(|e| vm::HypervisorVmError::RemoveUserMemory(e.into()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -819,10 +908,28 @@ impl vm::Vm for MshvVm {
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates an in-kernel device.
|
||||
///
|
||||
/// See the documentation for `MSHV_CREATE_DEVICE`.
|
||||
fn create_device(&self, device: &mut CreateDevice) -> vm::Result<Arc<dyn device::Device>> {
|
||||
let fd = self
|
||||
.fd
|
||||
.create_device(device)
|
||||
.map_err(|e| vm::HypervisorVmError::CreateDevice(e.into()))?;
|
||||
let device = MshvDevice { fd };
|
||||
Ok(Arc::new(device))
|
||||
}
|
||||
|
||||
fn create_passthrough_device(&self) -> vm::Result<Arc<dyn device::Device>> {
|
||||
Err(vm::HypervisorVmError::CreatePassthroughDevice(anyhow!(
|
||||
"No passthrough support"
|
||||
)))
|
||||
let mut vfio_dev = mshv_create_device {
|
||||
type_: mshv_device_type_MSHV_DEV_TYPE_VFIO,
|
||||
fd: 0,
|
||||
flags: 0,
|
||||
};
|
||||
|
||||
self.create_device(&mut vfio_dev)
|
||||
.map_err(|e| vm::HypervisorVmError::CreatePassthroughDevice(e.into()))
|
||||
}
|
||||
|
||||
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
|
||||
@@ -833,7 +940,7 @@ impl vm::Vm for MshvVm {
|
||||
unsafe {
|
||||
let entries_slice: &mut [mshv_msi_routing_entry] =
|
||||
msi_routing[0].entries.as_mut_slice(entries.len());
|
||||
entries_slice.copy_from_slice(&entries);
|
||||
entries_slice.copy_from_slice(entries);
|
||||
}
|
||||
|
||||
self.fd
|
||||
@@ -854,16 +961,44 @@ impl vm::Vm for MshvVm {
|
||||
Ok(())
|
||||
}
|
||||
///
|
||||
/// Start logging dirty pages
|
||||
///
|
||||
fn start_dirty_log(&self) -> vm::Result<()> {
|
||||
self.fd
|
||||
.enable_dirty_page_tracking()
|
||||
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))
|
||||
}
|
||||
///
|
||||
/// Stop logging dirty pages
|
||||
///
|
||||
fn stop_dirty_log(&self) -> vm::Result<()> {
|
||||
let dirty_log_slots = self.dirty_log_slots.read().unwrap();
|
||||
// Before disabling the dirty page tracking we need
|
||||
// to set the dirty bits in the Hypervisor
|
||||
// This is a requirement from Microsoft Hypervisor
|
||||
for (_, s) in dirty_log_slots.iter() {
|
||||
self.fd
|
||||
.get_dirty_log(s.guest_pfn, s.memory_size as usize, DIRTY_BITMAP_SET_DIRTY)
|
||||
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?;
|
||||
}
|
||||
self.fd
|
||||
.disable_dirty_page_tracking()
|
||||
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?;
|
||||
Ok(())
|
||||
}
|
||||
///
|
||||
/// Get dirty pages bitmap (one bit per page)
|
||||
///
|
||||
fn get_dirty_log(&self, _slot: u32, _memory_size: u64) -> vm::Result<Vec<u64>> {
|
||||
Err(vm::HypervisorVmError::GetDirtyLog(anyhow!(
|
||||
"get_dirty_log not implemented"
|
||||
)))
|
||||
fn get_dirty_log(&self, _slot: u32, base_gpa: u64, memory_size: u64) -> vm::Result<Vec<u64>> {
|
||||
self.fd
|
||||
.get_dirty_log(
|
||||
base_gpa >> PAGE_SHIFT,
|
||||
memory_size as usize,
|
||||
DIRTY_BITMAP_CLEAR_DIRTY,
|
||||
)
|
||||
.map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into()))
|
||||
}
|
||||
}
|
||||
pub use hv_cpuid_entry as CpuIdEntry;
|
||||
|
||||
pub type IrqRoutingEntry = mshv_msi_routing_entry;
|
||||
|
||||
pub const CPUID_FLAG_VALID_INDEX: u32 = 0;
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
// Copyright 2018-2019 CrowdStrike, Inc.
|
||||
//
|
||||
//
|
||||
|
||||
use crate::arch::x86::{msr_index, SegmentRegisterOps};
|
||||
use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
///
|
||||
/// Export generically-named wrappers of mshv_bindings for Unix-based platforms
|
||||
///
|
||||
@@ -19,8 +20,8 @@ pub use {
|
||||
mshv_bindings::FloatingPointUnit as FpuState, mshv_bindings::LapicState,
|
||||
mshv_bindings::MsrList, mshv_bindings::Msrs as MsrEntries, mshv_bindings::Msrs,
|
||||
mshv_bindings::SegmentRegister, mshv_bindings::SpecialRegisters,
|
||||
mshv_bindings::StandardRegisters, mshv_bindings::VcpuEvents, mshv_bindings::XSave as Xsave,
|
||||
mshv_bindings::Xcrs as ExtendedControlRegisters,
|
||||
mshv_bindings::StandardRegisters, mshv_bindings::SuspendRegisters, mshv_bindings::VcpuEvents,
|
||||
mshv_bindings::XSave as Xsave, mshv_bindings::Xcrs as ExtendedControlRegisters,
|
||||
};
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
@@ -36,8 +37,30 @@ pub struct VcpuMshvState {
|
||||
pub xsave: Xsave,
|
||||
}
|
||||
|
||||
pub struct CreateDevice {}
|
||||
pub struct DeviceAttr {}
|
||||
impl fmt::Display for VcpuMshvState {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let expected_num_msrs = self.msrs.as_fam_struct_ref().nmsrs as usize;
|
||||
let mut msr_entries = vec![vec![0; 2]; expected_num_msrs];
|
||||
|
||||
for (i, entry) in self.msrs.as_slice().iter().enumerate() {
|
||||
msr_entries[i][1] = entry.data;
|
||||
msr_entries[i][0] = entry.index as u64;
|
||||
}
|
||||
write!(f, "Number of MSRs: {}: MSRs: {:#010X?}, -- VCPU Events: {:?} -- Standard registers: {:?} Special Registers: {:?} ---- Floating Point Unit: {:?} --- Extended Control Register: {:?} --- Local APIC: {:?} --- DBG: {:?} --- Xsave: {:?}",
|
||||
msr_entries.len(),
|
||||
msr_entries,
|
||||
self.vcpu_events,
|
||||
self.regs,
|
||||
self.sregs,
|
||||
self.fpu,
|
||||
self.xcrs,
|
||||
self.lapic,
|
||||
self.dbg,
|
||||
self.xsave,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IrqRouting {}
|
||||
pub enum VcpuExit {}
|
||||
pub struct MpState {}
|
||||
@@ -118,6 +141,7 @@ pub fn boot_msr_entries() -> MsrEntries {
|
||||
msr!(msr_index::MSR_KERNEL_GS_BASE),
|
||||
msr!(msr_index::MSR_SYSCALL_MASK),
|
||||
msr!(msr_index::MSR_IA32_TSC),
|
||||
msr_data!(msr_index::MSR_MTRRdefType, MTRR_ENABLE | MTRR_MEM_TYPE_WB),
|
||||
])
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ use crate::device::Device;
|
||||
use crate::x86_64::CpuId;
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
use crate::ClockData;
|
||||
#[cfg(feature = "kvm")]
|
||||
use crate::CreateDevice;
|
||||
#[cfg(feature = "mshv")]
|
||||
use crate::HvState as VmState;
|
||||
@@ -25,6 +24,8 @@ use crate::KvmVmState as VmState;
|
||||
use crate::{IoEventAddress, IrqRoutingEntry, MemoryRegion};
|
||||
#[cfg(feature = "kvm")]
|
||||
use kvm_ioctls::Cap;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::fs::File;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@@ -92,10 +93,15 @@ pub enum HypervisorVmError {
|
||||
#[error("Failed to set GSI routing: {0}")]
|
||||
SetGsiRouting(#[source] anyhow::Error),
|
||||
///
|
||||
/// Set user memory error
|
||||
/// Create user memory error
|
||||
///
|
||||
#[error("Failed to set user memory: {0}")]
|
||||
SetUserMemory(#[source] anyhow::Error),
|
||||
#[error("Failed to create user memory: {0}")]
|
||||
CreateUserMemory(#[source] anyhow::Error),
|
||||
///
|
||||
/// Remove user memory region error
|
||||
///
|
||||
#[error("Failed to remove user memory: {0}")]
|
||||
RemoveUserMemory(#[source] anyhow::Error),
|
||||
///
|
||||
/// Create device error
|
||||
///
|
||||
@@ -112,6 +118,11 @@ pub enum HypervisorVmError {
|
||||
#[error("Failed to enable split Irq: {0}")]
|
||||
EnableSplitIrq(#[source] anyhow::Error),
|
||||
///
|
||||
/// Enable SGX attribute error
|
||||
///
|
||||
#[error("Failed to enable SGX attribute: {0}")]
|
||||
EnableSgxAttribute(#[source] anyhow::Error),
|
||||
///
|
||||
/// Get clock error
|
||||
///
|
||||
#[error("Failed to get clock: {0}")]
|
||||
@@ -156,6 +167,16 @@ pub enum HypervisorVmError {
|
||||
#[error("Failed to write to IO Bus: {0}")]
|
||||
IoBusWrite(#[source] anyhow::Error),
|
||||
///
|
||||
/// Start dirty log error
|
||||
///
|
||||
#[error("Failed to get dirty log: {0}")]
|
||||
StartDirtyLog(#[source] anyhow::Error),
|
||||
///
|
||||
/// Stop dirty log error
|
||||
///
|
||||
#[error("Failed to get dirty log: {0}")]
|
||||
StopDirtyLog(#[source] anyhow::Error),
|
||||
///
|
||||
/// Get dirty log error
|
||||
///
|
||||
#[error("Failed to get dirty log: {0}")]
|
||||
@@ -206,7 +227,7 @@ pub trait Vm: Send + Sync {
|
||||
/// Unregister an event that will, when signaled, trigger the `gsi` IRQ.
|
||||
fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()>;
|
||||
/// Creates a new KVM vCPU file descriptor and maps the memory corresponding
|
||||
fn create_vcpu(&self, id: u8, vmmops: Option<Arc<Box<dyn VmmOps>>>) -> Result<Arc<dyn Vcpu>>;
|
||||
fn create_vcpu(&self, id: u8, vmmops: Option<Arc<dyn VmmOps>>) -> Result<Arc<dyn Vcpu>>;
|
||||
/// Registers an event to be signaled whenever a certain address is written to.
|
||||
fn register_ioevent(
|
||||
&self,
|
||||
@@ -218,7 +239,7 @@ pub trait Vm: Send + Sync {
|
||||
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>;
|
||||
/// Sets the GSI routing table entries, overwriting any previously set
|
||||
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> Result<()>;
|
||||
/// Creates a memory region structure that can be used with set_user_memory_region
|
||||
/// Creates a memory region structure that can be used with {create/remove}_user_memory_region
|
||||
fn make_user_memory_region(
|
||||
&self,
|
||||
slot: u32,
|
||||
@@ -228,9 +249,10 @@ pub trait Vm: Send + Sync {
|
||||
readonly: bool,
|
||||
log_dirty_pages: bool,
|
||||
) -> MemoryRegion;
|
||||
/// Creates/modifies a guest physical memory slot.
|
||||
fn set_user_memory_region(&self, user_memory_region: MemoryRegion) -> Result<()>;
|
||||
#[cfg(feature = "kvm")]
|
||||
/// Creates a guest physical memory slot.
|
||||
fn create_user_memory_region(&self, user_memory_region: MemoryRegion) -> Result<()>;
|
||||
/// Removes a guest physical memory slot.
|
||||
fn remove_user_memory_region(&self, user_memory_region: MemoryRegion) -> Result<()>;
|
||||
/// Creates an emulated device in the kernel.
|
||||
fn create_device(&self, device: &mut CreateDevice) -> Result<Arc<dyn Device>>;
|
||||
/// Returns the preferred CPU target type which can be emulated by KVM on underlying host.
|
||||
@@ -239,6 +261,8 @@ pub trait Vm: Send + Sync {
|
||||
/// Enable split Irq capability
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn enable_split_irq(&self) -> Result<()>;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn enable_sgx_attribute(&self, file: File) -> Result<()>;
|
||||
/// Retrieve guest clock.
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
fn get_clock(&self) -> Result<ClockData>;
|
||||
@@ -254,8 +278,12 @@ pub trait Vm: Send + Sync {
|
||||
fn state(&self) -> Result<VmState>;
|
||||
/// Set the VM state
|
||||
fn set_state(&self, state: VmState) -> Result<()>;
|
||||
/// Start logging dirty pages
|
||||
fn start_dirty_log(&self) -> Result<()>;
|
||||
/// Stop logging dirty pages
|
||||
fn stop_dirty_log(&self) -> Result<()>;
|
||||
/// Get dirty pages bitmap
|
||||
fn get_dirty_log(&self, slot: u32, memory_size: u64) -> Result<Vec<u64>>;
|
||||
fn get_dirty_log(&self, slot: u32, base_gpa: u64, memory_size: u64) -> Result<Vec<u64>>;
|
||||
#[cfg(feature = "tdx")]
|
||||
/// Initalize TDX on this VM
|
||||
fn tdx_init(&self, cpuid: &CpuId, max_vcpus: u32) -> Result<()>;
|
||||
|
||||
@@ -5,4 +5,4 @@ authors = ["The Chromium OS Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
vmm-sys-util = ">=0.3.1"
|
||||
vmm-sys-util = "0.8.0"
|
||||
|
||||
@@ -5,20 +5,20 @@ authors = ["The Chromium OS Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
epoll = ">=4.0.1"
|
||||
libc = "0.2.96"
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.101"
|
||||
log = "0.4.14"
|
||||
net_gen = { path = "../net_gen" }
|
||||
rate_limiter = { path = "../rate_limiter" }
|
||||
serde = "1.0.126"
|
||||
serde = "1.0.130"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
virtio-bindings = "0.1.0"
|
||||
vm-memory = { version = "0.5.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = ">=0.3.1"
|
||||
vmm-sys-util = "0.8.0"
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.3.0"
|
||||
lazy_static = "1.4.0"
|
||||
pnet = "0.28.0"
|
||||
serde_json = "1.0.64"
|
||||
serde_json = "1.0.67"
|
||||
|
||||
@@ -47,7 +47,7 @@ impl CtrlQueue {
|
||||
|
||||
pub fn process(&mut self, mem: &GuestMemoryMmap, queue: &mut Queue) -> Result<bool> {
|
||||
let mut used_desc_heads = Vec::new();
|
||||
for avail_desc in queue.iter(&mem) {
|
||||
for avail_desc in queue.iter(mem) {
|
||||
let ctrl_hdr: ControlHeader =
|
||||
mem.read_obj(avail_desc.addr).map_err(Error::GuestMemory)?;
|
||||
let data_desc = avail_desc
|
||||
@@ -111,8 +111,8 @@ impl CtrlQueue {
|
||||
}
|
||||
|
||||
for (desc_index, len) in used_desc_heads.iter() {
|
||||
queue.add_used(&mem, *desc_index, *len);
|
||||
queue.update_avail_event(&mem);
|
||||
queue.add_used(mem, *desc_index, *len);
|
||||
queue.update_avail_event(mem);
|
||||
}
|
||||
|
||||
Ok(!used_desc_heads.is_empty())
|
||||
|
||||
@@ -57,7 +57,7 @@ impl MacAddr {
|
||||
// TODO: using something like std::mem::uninitialized could avoid the extra initialization,
|
||||
// if this ever becomes a performance bottleneck.
|
||||
let mut bytes = [0u8; MAC_ADDR_LEN];
|
||||
bytes[..].copy_from_slice(&src);
|
||||
bytes[..].copy_from_slice(src);
|
||||
|
||||
MacAddr { bytes }
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
|
||||
use super::{unregister_listener, vnet_hdr_len, Tap};
|
||||
use super::{register_listener, unregister_listener, vnet_hdr_len, Tap};
|
||||
use crate::GuestMemoryMmap;
|
||||
use rate_limiter::{RateLimiter, TokenType};
|
||||
use std::io;
|
||||
@@ -39,34 +39,18 @@ impl TxVirtio {
|
||||
tap: &mut Tap,
|
||||
queue: &mut Queue,
|
||||
rate_limiter: &mut Option<RateLimiter>,
|
||||
) -> Result<(), NetQueuePairError> {
|
||||
while let Some(avail_desc) = queue.iter(&mem).next() {
|
||||
) -> Result<bool, NetQueuePairError> {
|
||||
let mut retry_write = false;
|
||||
let mut rate_limit_reached = false;
|
||||
while let Some(avail_desc) = queue.iter(mem).next() {
|
||||
if rate_limit_reached {
|
||||
queue.go_to_previous_position();
|
||||
break;
|
||||
}
|
||||
|
||||
let head_index = avail_desc.index;
|
||||
let mut next_desc = Some(avail_desc);
|
||||
|
||||
if let Some(rate_limiter) = rate_limiter {
|
||||
if !rate_limiter.consume(1, TokenType::Ops) {
|
||||
queue.go_to_previous_position();
|
||||
break;
|
||||
}
|
||||
|
||||
let mut bytes = Wrapping(0);
|
||||
let mut tmp_next_desc = next_desc.clone();
|
||||
while let Some(desc) = tmp_next_desc {
|
||||
if !desc.is_write_only() {
|
||||
bytes += Wrapping(desc.len as u64);
|
||||
}
|
||||
tmp_next_desc = desc.next_descriptor();
|
||||
}
|
||||
bytes -= Wrapping(vnet_hdr_len() as u64);
|
||||
if !rate_limiter.consume(bytes.0, TokenType::Bytes) {
|
||||
// Revert the OPS consume().
|
||||
rate_limiter.manual_replenish(1, TokenType::Ops);
|
||||
queue.go_to_previous_position();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let mut iovecs = Vec::new();
|
||||
while let Some(desc) = next_desc {
|
||||
if !desc.is_write_only() && desc.len > 0 {
|
||||
@@ -83,7 +67,7 @@ impl TxVirtio {
|
||||
next_desc = desc.next_descriptor();
|
||||
}
|
||||
|
||||
if !iovecs.is_empty() {
|
||||
let len = if !iovecs.is_empty() {
|
||||
let result = unsafe {
|
||||
libc::writev(
|
||||
tap.as_raw_fd() as libc::c_int,
|
||||
@@ -91,13 +75,14 @@ impl TxVirtio {
|
||||
iovecs.len() as libc::c_int,
|
||||
)
|
||||
};
|
||||
|
||||
if result < 0 {
|
||||
let e = std::io::Error::last_os_error();
|
||||
queue.go_to_previous_position();
|
||||
|
||||
/* EAGAIN */
|
||||
if e.kind() == std::io::ErrorKind::WouldBlock {
|
||||
warn!("net: tx: (recoverable) failed writing to tap: {}", e);
|
||||
queue.go_to_previous_position();
|
||||
retry_write = true;
|
||||
break;
|
||||
}
|
||||
error!("net: tx: failed writing to tap: {}", e);
|
||||
@@ -106,13 +91,25 @@ impl TxVirtio {
|
||||
|
||||
self.counter_bytes += Wrapping(result as u64 - vnet_hdr_len() as u64);
|
||||
self.counter_frames += Wrapping(1);
|
||||
}
|
||||
|
||||
queue.add_used(&mem, head_index, 0);
|
||||
queue.update_avail_event(&mem);
|
||||
result as u32
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
queue.add_used(mem, head_index, 0);
|
||||
queue.update_avail_event(mem);
|
||||
|
||||
// For the sake of simplicity (similar to the RX rate limiting), we always
|
||||
// let the 'last' descriptor chain go-through even if it was over the rate
|
||||
// limit, and simply stop processing oncoming `avail_desc` if any.
|
||||
if let Some(rate_limiter) = rate_limiter {
|
||||
rate_limit_reached = !rate_limiter.consume(1, TokenType::Ops)
|
||||
|| !rate_limiter.consume(len as u64, TokenType::Bytes);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(retry_write)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +143,7 @@ impl RxVirtio {
|
||||
let mut exhausted_descs = true;
|
||||
let mut rate_limit_reached = false;
|
||||
|
||||
while let Some(avail_desc) = queue.iter(&mem).next() {
|
||||
while let Some(avail_desc) = queue.iter(mem).next() {
|
||||
if rate_limit_reached {
|
||||
exhausted_descs = false;
|
||||
queue.go_to_previous_position();
|
||||
@@ -208,8 +205,8 @@ impl RxVirtio {
|
||||
0
|
||||
};
|
||||
|
||||
queue.add_used(&mem, head_index, len);
|
||||
queue.update_avail_event(&mem);
|
||||
queue.add_used(mem, head_index, len);
|
||||
queue.update_avail_event(mem);
|
||||
|
||||
// For the sake of simplicity (keeping the handling of RX_QUEUE_EVENT and
|
||||
// RX_TAP_EVENT totally asynchronous), we always let the 'last' descriptor
|
||||
@@ -252,12 +249,19 @@ pub enum NetQueuePairError {
|
||||
pub struct NetQueuePair {
|
||||
pub mem: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
pub tap: Tap,
|
||||
// With epoll each FD must be unique. So in order to filter the
|
||||
// events we need to get a second FD responding to the original
|
||||
// device so that we can send EPOLLOUT and EPOLLIN to separate
|
||||
// events.
|
||||
pub tap_for_write_epoll: Tap,
|
||||
pub rx: RxVirtio,
|
||||
pub tx: TxVirtio,
|
||||
pub epoll_fd: Option<RawFd>,
|
||||
pub rx_tap_listening: bool,
|
||||
pub tx_tap_listening: bool,
|
||||
pub counters: NetCounters,
|
||||
pub tap_event_id: u16,
|
||||
pub tap_rx_event_id: u16,
|
||||
pub tap_tx_event_id: u16,
|
||||
pub rx_desc_avail: bool,
|
||||
pub rx_rate_limiter: Option<RateLimiter>,
|
||||
pub tx_rate_limiter: Option<RateLimiter>,
|
||||
@@ -271,8 +275,35 @@ impl NetQueuePair {
|
||||
.ok_or(NetQueuePairError::NoMemoryConfigured)
|
||||
.map(|m| m.memory())?;
|
||||
|
||||
self.tx
|
||||
.process_desc_chain(&mem, &mut self.tap, &mut queue, &mut self.tx_rate_limiter)?;
|
||||
let tx_tap_retry = self.tx.process_desc_chain(
|
||||
&mem,
|
||||
&mut self.tap,
|
||||
&mut queue,
|
||||
&mut self.tx_rate_limiter,
|
||||
)?;
|
||||
|
||||
// We got told to try again when writing to the tap. Wait for the TAP to be writable
|
||||
if tx_tap_retry && !self.tx_tap_listening {
|
||||
register_listener(
|
||||
self.epoll_fd.unwrap(),
|
||||
self.tap_for_write_epoll.as_raw_fd(),
|
||||
epoll::Events::EPOLLOUT,
|
||||
u64::from(self.tap_tx_event_id),
|
||||
)
|
||||
.map_err(NetQueuePairError::RegisterListener)?;
|
||||
self.tx_tap_listening = true;
|
||||
info!("Writing to TAP returned EAGAIN. Listening for TAP to become writable.");
|
||||
} else if !tx_tap_retry && self.tx_tap_listening {
|
||||
unregister_listener(
|
||||
self.epoll_fd.unwrap(),
|
||||
self.tap_for_write_epoll.as_raw_fd(),
|
||||
epoll::Events::EPOLLOUT,
|
||||
u64::from(self.tap_tx_event_id),
|
||||
)
|
||||
.map_err(NetQueuePairError::UnregisterListener)?;
|
||||
self.tx_tap_listening = false;
|
||||
info!("Writing to TAP succeeded. No longer listening for TAP to become writable.");
|
||||
}
|
||||
|
||||
self.counters
|
||||
.tx_bytes
|
||||
@@ -312,7 +343,7 @@ impl NetQueuePair {
|
||||
self.epoll_fd.unwrap(),
|
||||
self.tap.as_raw_fd(),
|
||||
epoll::Events::EPOLLIN,
|
||||
u64::from(self.tap_event_id),
|
||||
u64::from(self.tap_rx_event_id),
|
||||
)
|
||||
.map_err(NetQueuePairError::UnregisterListener)?;
|
||||
self.rx_tap_listening = false;
|
||||
|
||||
@@ -384,7 +384,7 @@ impl Read for Tap {
|
||||
|
||||
impl Write for Tap {
|
||||
fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
|
||||
self.tap_file.write(&buf)
|
||||
self.tap_file.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> IoResult<()> {
|
||||
|
||||
@@ -4,19 +4,26 @@ version = "0.1.0"
|
||||
authors = ["Samuel Ortiz <sameo@linux.intel.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
kvm = ["vfio-ioctls/kvm"]
|
||||
mshv = ["vfio-ioctls/mshv"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
anyhow = "1.0.43"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio-ioctls", branch = "master" }
|
||||
vmm-sys-util = ">=0.3.1"
|
||||
libc = "0.2.96"
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio-ioctls", branch = "main", default-features = false }
|
||||
vfio_user = { path = "../vfio_user" }
|
||||
vmm-sys-util = "0.8.0"
|
||||
libc = "0.2.101"
|
||||
log = "0.4.14"
|
||||
thiserror = "1.0.29"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = "0.5.0"
|
||||
vm-memory = "0.6.0"
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
|
||||
[dependencies.vfio-bindings]
|
||||
|
||||
@@ -317,7 +317,7 @@ pub struct PciConfiguration {
|
||||
}
|
||||
|
||||
/// See pci_regs.h in kernel
|
||||
#[derive(Copy, Clone, PartialEq, Versionize)]
|
||||
#[derive(Copy, Clone, PartialEq, Versionize, Debug)]
|
||||
pub enum PciBarRegionType {
|
||||
Memory32BitRegion = 0,
|
||||
IoRegion = 0x01,
|
||||
@@ -794,9 +794,9 @@ impl PciConfiguration {
|
||||
return None;
|
||||
}
|
||||
|
||||
debug!(
|
||||
"DETECT BAR REPROG: current 0x{:x}, new 0x{:x}",
|
||||
self.registers[reg_idx], value
|
||||
info!(
|
||||
"Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
|
||||
reg_idx, self.registers[reg_idx], value
|
||||
);
|
||||
let old_base = u64::from(self.bars[bar_idx].addr & mask);
|
||||
let new_base = u64::from(value & mask);
|
||||
@@ -820,9 +820,9 @@ impl PciConfiguration {
|
||||
!= (self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1])
|
||||
|| (value & mask) != (self.bars[bar_idx].addr & mask))
|
||||
{
|
||||
debug!(
|
||||
"DETECT BAR REPROG: current 0x{:x}, new 0x{:x}",
|
||||
self.registers[reg_idx], value
|
||||
info!(
|
||||
"Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
|
||||
reg_idx, self.registers[reg_idx], value
|
||||
);
|
||||
let old_base = u64::from(self.bars[bar_idx].addr & mask) << 32
|
||||
| u64::from(self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1]);
|
||||
@@ -850,9 +850,9 @@ impl PciConfiguration {
|
||||
return None;
|
||||
}
|
||||
|
||||
debug!(
|
||||
"DETECT ROM BAR REPROG: current 0x{:x}, new 0x{:x}",
|
||||
self.registers[reg_idx], value
|
||||
info!(
|
||||
"Detected ROM BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
|
||||
reg_idx, self.registers[reg_idx], value
|
||||
);
|
||||
let old_base = u64::from(self.rom_bar_addr & mask);
|
||||
let new_base = u64::from(value & mask);
|
||||
|
||||
@@ -12,6 +12,7 @@ mod device;
|
||||
mod msi;
|
||||
mod msix;
|
||||
mod vfio;
|
||||
mod vfio_user;
|
||||
|
||||
pub use self::bus::{PciBus, PciConfigIo, PciConfigMmio, PciRoot, PciRootError};
|
||||
pub use self::configuration::{
|
||||
@@ -25,6 +26,7 @@ pub use self::device::{
|
||||
pub use self::msi::{msi_num_enabled_vectors, MsiCap, MsiConfig};
|
||||
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_TABLE_ENTRY_SIZE};
|
||||
pub use self::vfio::{VfioPciDevice, VfioPciError};
|
||||
pub use self::vfio_user::{VfioUserPciDevice, VfioUserPciDeviceError};
|
||||
|
||||
/// PCI has four interrupt pins A->D.
|
||||
#[derive(Copy, Clone)]
|
||||
|
||||
@@ -159,11 +159,11 @@ impl MsiCap {
|
||||
|
||||
pub struct MsiConfig {
|
||||
cap: MsiCap,
|
||||
interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||
}
|
||||
|
||||
impl MsiConfig {
|
||||
pub fn new(msg_ctl: u16, interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>) -> Self {
|
||||
pub fn new(msg_ctl: u16, interrupt_source_group: Arc<dyn InterruptSourceGroup>) -> Self {
|
||||
let cap = MsiCap {
|
||||
msg_ctl,
|
||||
..Default::default()
|
||||
|
||||
@@ -74,7 +74,7 @@ pub struct MsixConfig {
|
||||
pub table_entries: Vec<MsixTableEntry>,
|
||||
pub pba_entries: Vec<u64>,
|
||||
pub devid: u32,
|
||||
interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||
masked: bool,
|
||||
enabled: bool,
|
||||
}
|
||||
@@ -82,7 +82,7 @@ pub struct MsixConfig {
|
||||
impl MsixConfig {
|
||||
pub fn new(
|
||||
msix_vectors: u16,
|
||||
interrupt_source_group: Arc<Box<dyn InterruptSourceGroup>>,
|
||||
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||
devid: u32,
|
||||
) -> Self {
|
||||
assert!(msix_vectors <= MAX_MSIX_VECTORS_PER_DEVICE);
|
||||
|
||||
1281
pci/src/vfio.rs
1281
pci/src/vfio.rs
File diff suppressed because it is too large
Load Diff
485
pci/src/vfio_user.rs
Normal file
485
pci/src/vfio_user.rs
Normal file
@@ -0,0 +1,485 @@
|
||||
// Copyright © 2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use crate::vfio::{Interrupt, Vfio, VfioCommon, VfioError};
|
||||
use crate::{BarReprogrammingParams, PciBarRegionType, VfioPciError};
|
||||
use crate::{
|
||||
PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
|
||||
};
|
||||
use hypervisor::HypervisorVmError;
|
||||
use std::any::Any;
|
||||
use std::os::unix::prelude::AsRawFd;
|
||||
use std::path::Path;
|
||||
use std::ptr::null_mut;
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use std::u32;
|
||||
use thiserror::Error;
|
||||
use vfio_bindings::bindings::vfio::*;
|
||||
use vfio_ioctls::VfioIrq;
|
||||
use vfio_user::{Client, Error as VfioUserError};
|
||||
use vm_allocator::SystemAllocator;
|
||||
use vm_device::interrupt::{InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig};
|
||||
use vm_device::BusDevice;
|
||||
use vm_memory::bitmap::AtomicBitmap;
|
||||
use vm_memory::{Address, GuestAddress, GuestMemoryRegion, GuestRegionMmap, GuestUsize};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
pub struct VfioUserPciDevice {
|
||||
vm: Arc<dyn hypervisor::Vm>,
|
||||
client: Arc<Mutex<Client>>,
|
||||
vfio_wrapper: VfioUserClientWrapper,
|
||||
common: VfioCommon,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum VfioUserPciDeviceError {
|
||||
#[error("Client error: {0}")]
|
||||
Client(#[source] VfioUserError),
|
||||
#[error("Failed to map VFIO PCI region into guest: {0}")]
|
||||
MapRegionGuest(#[source] HypervisorVmError),
|
||||
#[error("Failed to DMA map: {0}")]
|
||||
DmaMap(#[source] VfioUserError),
|
||||
#[error("Failed to DMA unmap: {0}")]
|
||||
DmaUnmap(#[source] VfioUserError),
|
||||
#[error("Failed to initialize legacy interrupts: {0}")]
|
||||
InitializeLegacyInterrupts(#[source] VfioPciError),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum PciVfioUserSubclass {
|
||||
VfioUserSubclass = 0xff,
|
||||
}
|
||||
|
||||
impl PciSubclass for PciVfioUserSubclass {
|
||||
fn get_register_value(&self) -> u8 {
|
||||
*self as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl VfioUserPciDevice {
|
||||
pub fn new(
|
||||
vm: &Arc<dyn hypervisor::Vm>,
|
||||
path: &Path,
|
||||
msi_interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
|
||||
) -> Result<Self, VfioUserPciDeviceError> {
|
||||
let mut client = Client::new(path).map_err(VfioUserPciDeviceError::Client)?;
|
||||
|
||||
// This is used for the BAR and capabilities only
|
||||
let configuration = PciConfiguration::new(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
PciClassCode::Other,
|
||||
&PciVfioUserSubclass::VfioUserSubclass,
|
||||
None,
|
||||
PciHeaderType::Device,
|
||||
0,
|
||||
0,
|
||||
None,
|
||||
);
|
||||
if client.resettable() {
|
||||
client.reset().map_err(VfioUserPciDeviceError::Client)?;
|
||||
}
|
||||
|
||||
let client = Arc::new(Mutex::new(client));
|
||||
|
||||
let vfio_wrapper = VfioUserClientWrapper {
|
||||
client: client.clone(),
|
||||
};
|
||||
|
||||
let mut common = VfioCommon {
|
||||
mmio_regions: Vec::new(),
|
||||
configuration,
|
||||
interrupt: Interrupt {
|
||||
intx: None,
|
||||
msi: None,
|
||||
msix: None,
|
||||
},
|
||||
};
|
||||
|
||||
common.parse_capabilities(msi_interrupt_manager, &vfio_wrapper);
|
||||
common
|
||||
.initialize_legacy_interrupt(legacy_interrupt_group, &vfio_wrapper)
|
||||
.map_err(VfioUserPciDeviceError::InitializeLegacyInterrupts)?;
|
||||
|
||||
Ok(Self {
|
||||
vm: vm.clone(),
|
||||
client,
|
||||
vfio_wrapper,
|
||||
common,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl BusDevice for VfioUserPciDevice {
|
||||
fn read(&mut self, base: u64, offset: u64, data: &mut [u8]) {
|
||||
self.read_bar(base, offset, data)
|
||||
}
|
||||
|
||||
fn write(&mut self, base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||
self.write_bar(base, offset, data)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[allow(dead_code)]
|
||||
enum Regions {
|
||||
Bar0,
|
||||
Bar1,
|
||||
Bar2,
|
||||
Bar3,
|
||||
Bar4,
|
||||
Bar5,
|
||||
Rom,
|
||||
Config,
|
||||
Vga,
|
||||
Migration,
|
||||
}
|
||||
|
||||
struct VfioUserClientWrapper {
|
||||
client: Arc<Mutex<Client>>,
|
||||
}
|
||||
|
||||
impl Vfio for VfioUserClientWrapper {
|
||||
fn region_read(&self, index: u32, offset: u64, data: &mut [u8]) {
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.region_read(index, offset, data)
|
||||
.ok();
|
||||
}
|
||||
|
||||
fn region_write(&self, index: u32, offset: u64, data: &[u8]) {
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.region_write(index, offset, data)
|
||||
.ok();
|
||||
}
|
||||
|
||||
fn get_irq_info(&self, irq_index: u32) -> Option<VfioIrq> {
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get_irq_info(irq_index)
|
||||
.ok()
|
||||
.map(|i| VfioIrq {
|
||||
index: i.index,
|
||||
flags: i.flags,
|
||||
count: i.count,
|
||||
})
|
||||
}
|
||||
|
||||
fn enable_irq(&self, irq_index: u32, event_fds: Vec<&EventFd>) -> Result<(), VfioError> {
|
||||
info!(
|
||||
"Enabling IRQ {:x} number of fds = {:?}",
|
||||
irq_index,
|
||||
event_fds.len()
|
||||
);
|
||||
let fds: Vec<i32> = event_fds.iter().map(|e| e.as_raw_fd()).collect();
|
||||
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_irqs(
|
||||
irq_index,
|
||||
VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER,
|
||||
0,
|
||||
event_fds.len() as u32,
|
||||
&fds,
|
||||
)
|
||||
.map_err(VfioError::VfioUser)
|
||||
}
|
||||
|
||||
fn disable_irq(&self, irq_index: u32) -> Result<(), VfioError> {
|
||||
info!("Disabling IRQ {:x}", irq_index);
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_irqs(
|
||||
irq_index,
|
||||
VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER,
|
||||
0,
|
||||
0,
|
||||
&[],
|
||||
)
|
||||
.map_err(VfioError::VfioUser)
|
||||
}
|
||||
|
||||
fn unmask_irq(&self, irq_index: u32) -> Result<(), VfioError> {
|
||||
info!("Unmasking IRQ {:x}", irq_index);
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_irqs(
|
||||
irq_index,
|
||||
VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
|
||||
0,
|
||||
1,
|
||||
&[],
|
||||
)
|
||||
.map_err(VfioError::VfioUser)
|
||||
}
|
||||
}
|
||||
|
||||
impl PciDevice for VfioUserPciDevice {
|
||||
fn allocate_bars(
|
||||
&mut self,
|
||||
allocator: &mut SystemAllocator,
|
||||
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
|
||||
self.common.allocate_bars(allocator, &self.vfio_wrapper)
|
||||
}
|
||||
|
||||
fn free_bars(&mut self, allocator: &mut SystemAllocator) -> Result<(), PciDeviceError> {
|
||||
self.common.free_bars(allocator)
|
||||
}
|
||||
|
||||
fn as_any(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn detect_bar_reprogramming(
|
||||
&mut self,
|
||||
reg_idx: usize,
|
||||
data: &[u8],
|
||||
) -> Option<BarReprogrammingParams> {
|
||||
self.common
|
||||
.configuration
|
||||
.detect_bar_reprogramming(reg_idx, data)
|
||||
}
|
||||
|
||||
fn write_config_register(
|
||||
&mut self,
|
||||
reg_idx: usize,
|
||||
offset: u64,
|
||||
data: &[u8],
|
||||
) -> Option<Arc<Barrier>> {
|
||||
self.common
|
||||
.write_config_register(reg_idx, offset, data, &self.vfio_wrapper)
|
||||
}
|
||||
|
||||
fn read_config_register(&mut self, reg_idx: usize) -> u32 {
|
||||
self.common
|
||||
.read_config_register(reg_idx, &self.vfio_wrapper)
|
||||
}
|
||||
|
||||
fn read_bar(&mut self, base: u64, offset: u64, data: &mut [u8]) {
|
||||
self.common.read_bar(base, offset, data, &self.vfio_wrapper)
|
||||
}
|
||||
|
||||
fn write_bar(&mut self, base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||
self.common
|
||||
.write_bar(base, offset, data, &self.vfio_wrapper)
|
||||
}
|
||||
|
||||
fn move_bar(&mut self, old_base: u64, new_base: u64) -> Result<(), std::io::Error> {
|
||||
info!("Moving BAR 0x{:x} -> 0x{:x}", old_base, new_base);
|
||||
for mmio_region in self.common.mmio_regions.iter_mut() {
|
||||
if mmio_region.start.raw_value() == old_base {
|
||||
mmio_region.start = GuestAddress(new_base);
|
||||
|
||||
if let Some(mem_slot) = mmio_region.mem_slot {
|
||||
if let Some(host_addr) = mmio_region.host_addr {
|
||||
// Remove original region
|
||||
let old_region = self.vm.make_user_memory_region(
|
||||
mem_slot,
|
||||
old_base,
|
||||
mmio_region.length as u64,
|
||||
host_addr as u64,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
|
||||
self.vm
|
||||
.remove_user_memory_region(old_region)
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
|
||||
|
||||
let new_region = self.vm.make_user_memory_region(
|
||||
mem_slot,
|
||||
new_base,
|
||||
mmio_region.length as u64,
|
||||
host_addr as u64,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl VfioUserPciDevice {
|
||||
pub fn map_mmio_regions<F>(
|
||||
&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 {
|
||||
let region_flags = self
|
||||
.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.region(mmio_region.index)
|
||||
.unwrap()
|
||||
.flags;
|
||||
let file_offset = self
|
||||
.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.region(mmio_region.index)
|
||||
.unwrap()
|
||||
.file_offset
|
||||
.clone();
|
||||
|
||||
if region_flags & VFIO_REGION_INFO_FLAG_MMAP != 0 {
|
||||
let mut prot = 0;
|
||||
if region_flags & VFIO_REGION_INFO_FLAG_READ != 0 {
|
||||
prot |= libc::PROT_READ;
|
||||
}
|
||||
if region_flags & VFIO_REGION_INFO_FLAG_WRITE != 0 {
|
||||
prot |= libc::PROT_WRITE;
|
||||
}
|
||||
|
||||
let host_addr = unsafe {
|
||||
libc::mmap(
|
||||
null_mut(),
|
||||
mmio_region.length 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,
|
||||
)
|
||||
};
|
||||
|
||||
if host_addr == libc::MAP_FAILED {
|
||||
error!(
|
||||
"Could not mmap regions, error:{}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unmap_mmio_regions(&mut self) {
|
||||
for mmio_region in self.common.mmio_regions.iter() {
|
||||
if let (Some(host_addr), Some(mmap_size), Some(mem_slot)) = (
|
||||
mmio_region.host_addr,
|
||||
mmio_region.mmap_size,
|
||||
mmio_region.mem_slot,
|
||||
) {
|
||||
// Remove region
|
||||
let r = self.vm.make_user_memory_region(
|
||||
mem_slot,
|
||||
mmio_region.start.raw_value(),
|
||||
mmap_size as u64,
|
||||
host_addr as u64,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
|
||||
if let Err(e) = self.vm.remove_user_memory_region(r) {
|
||||
error!("Could not remove the userspace memory region: {}", e);
|
||||
}
|
||||
|
||||
let ret = unsafe { libc::munmap(host_addr as *mut libc::c_void, mmap_size) };
|
||||
if ret != 0 {
|
||||
error!(
|
||||
"Could not unmap region {}, error:{}",
|
||||
mmio_region.index,
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dma_map(
|
||||
&mut self,
|
||||
region: &GuestRegionMmap<AtomicBitmap>,
|
||||
) -> Result<(), VfioUserPciDeviceError> {
|
||||
let (fd, offset) = match region.file_offset() {
|
||||
Some(_file_offset) => (_file_offset.file().as_raw_fd(), _file_offset.start()),
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.dma_map(
|
||||
offset,
|
||||
region.start_addr().raw_value(),
|
||||
region.len() as u64,
|
||||
fd,
|
||||
)
|
||||
.map_err(VfioUserPciDeviceError::DmaMap)
|
||||
}
|
||||
|
||||
pub fn dma_unmap(
|
||||
&mut self,
|
||||
region: &GuestRegionMmap<AtomicBitmap>,
|
||||
) -> Result<(), VfioUserPciDeviceError> {
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.dma_unmap(region.start_addr().raw_value(), region.len() as u64)
|
||||
.map_err(VfioUserPciDeviceError::DmaUnmap)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VfioUserPciDevice {
|
||||
fn drop(&mut self) {
|
||||
self.unmap_mmio_regions();
|
||||
|
||||
if let Some(msix) = &self.common.interrupt.msix {
|
||||
if msix.bar.enabled() {
|
||||
self.common.disable_msix(&self.vfio_wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(msi) = &self.common.interrupt.msi {
|
||||
if msi.cfg.enabled() {
|
||||
self.common.disable_msi(&self.vfio_wrapper)
|
||||
}
|
||||
}
|
||||
|
||||
if self.common.interrupt.intx_in_use() {
|
||||
self.common.disable_intx(&self.vfio_wrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ path = "src/qcow.rs"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.4.3"
|
||||
libc = "0.2.96"
|
||||
libc = "0.2.101"
|
||||
log = "0.4.14"
|
||||
remain = "0.2.2"
|
||||
vmm-sys-util = ">=0.3.1"
|
||||
vmm-sys-util = "0.8.0"
|
||||
|
||||
@@ -576,7 +576,7 @@ impl QcowFile {
|
||||
|
||||
/// Returns the L1 lookup table for this file. This is only useful for debugging.
|
||||
pub fn l1_table(&self) -> &[u64] {
|
||||
&self.l1_table.get_values()
|
||||
self.l1_table.get_values()
|
||||
}
|
||||
|
||||
/// Returns an L2_table of cluster addresses, only used for debugging.
|
||||
@@ -613,7 +613,7 @@ impl QcowFile {
|
||||
|
||||
/// Returns the refcount table for this file. This is only useful for debugging.
|
||||
pub fn ref_table(&self) -> &[u64] {
|
||||
&self.refcounts.ref_table()
|
||||
self.refcounts.ref_table()
|
||||
}
|
||||
|
||||
/// Returns the `index`th refcount block from the file.
|
||||
@@ -831,7 +831,7 @@ impl QcowFile {
|
||||
|
||||
// Rewrite the top-level refcount table.
|
||||
raw_file
|
||||
.write_pointer_table(header.refcount_table_offset, &ref_table, 0)
|
||||
.write_pointer_table(header.refcount_table_offset, ref_table, 0)
|
||||
.map_err(Error::WritingHeader)?;
|
||||
|
||||
// Rewrite the header again, now with lazy refcounts disabled.
|
||||
@@ -1379,7 +1379,7 @@ impl QcowFile {
|
||||
let mut sync_required = if self.l1_table.dirty() {
|
||||
self.raw_file.write_pointer_table(
|
||||
self.header.l1_table_offset,
|
||||
&self.l1_table.get_values(),
|
||||
self.l1_table.get_values(),
|
||||
0,
|
||||
)?;
|
||||
self.l1_table.mark_clean();
|
||||
@@ -1783,7 +1783,7 @@ mod tests {
|
||||
F: FnMut(RawFile),
|
||||
{
|
||||
let mut disk_file: RawFile = RawFile::new(TempFile::new().unwrap().into_file(), false);
|
||||
disk_file.write_all(&header).unwrap();
|
||||
disk_file.write_all(header).unwrap();
|
||||
disk_file.set_len(0x1_0000_0000).unwrap();
|
||||
disk_file.seek(SeekFrom::Start(0)).unwrap();
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ impl RefCount {
|
||||
if self.ref_table.dirty() {
|
||||
raw_file.write_pointer_table(
|
||||
self.refcount_table_offset,
|
||||
&self.ref_table.get_values(),
|
||||
self.ref_table.get_values(),
|
||||
0,
|
||||
)?;
|
||||
self.ref_table.mark_clean();
|
||||
@@ -210,7 +210,7 @@ impl RefCount {
|
||||
|
||||
/// Returns the refcount table for this file. This is only useful for debugging.
|
||||
pub fn ref_table(&self) -> &[u64] {
|
||||
&self.ref_table.get_values()
|
||||
self.ref_table.get_values()
|
||||
}
|
||||
|
||||
/// Returns the refcounts stored in the given block.
|
||||
|
||||
@@ -4,6 +4,6 @@ version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.96"
|
||||
libc = "0.2.101"
|
||||
log = "0.4.14"
|
||||
vmm-sys-util = "0.8.0"
|
||||
|
||||
186
release-notes.md
186
release-notes.md
@@ -1,10 +1,29 @@
|
||||
- [v18.0](#v180)
|
||||
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
|
||||
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
|
||||
- [VHDX disk image support](#vhdx-disk-image-support)
|
||||
- [Device pass through on MSHV hypervisor](#device-pass-through-on-mshv-hypervisor)
|
||||
- [AArch64 for support `virtio-mem`](#aarch64-for-support-virtio-mem)
|
||||
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
||||
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
||||
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
||||
- [Notable bug fixes](#notable-bug-fixes)
|
||||
- [Contributors](#contributors)
|
||||
- [v17.0](#v170)
|
||||
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
|
||||
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
|
||||
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
|
||||
- [Improved SGX support](#improved-sgx-support)
|
||||
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
|
||||
- [Notable bug fixes](#notable-bug-fixes-1)
|
||||
- [Contributors](#contributors-1)
|
||||
- [v16.0](#v160)
|
||||
- [Improved live migration support](#improved-live-migration-support)
|
||||
- [Improved `vhost-user` support](#improved-vhost-user-support)
|
||||
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
|
||||
- [Notable bug fixes](#notable-bug-fixes)
|
||||
- [Notable bug fixes](#notable-bug-fixes-2)
|
||||
- [Removed functionality](#removed-functionality)
|
||||
- [Contributors](#contributors)
|
||||
- [Contributors](#contributors-2)
|
||||
- [v15.0](#v150)
|
||||
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
||||
- [Network device rate limiting](#network-device-rate-limiting)
|
||||
@@ -12,7 +31,7 @@
|
||||
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
||||
- [Bug fixes](#bug-fixes)
|
||||
- [Deprecations](#deprecations)
|
||||
- [Contributors](#contributors-1)
|
||||
- [Contributors](#contributors-3)
|
||||
- [v0.14.1](#v0141)
|
||||
- [v0.14.0](#v0140)
|
||||
- [Structured event monitoring](#structured-event-monitoring)
|
||||
@@ -22,7 +41,7 @@
|
||||
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
|
||||
- [Block device rate limiting](#block-device-rate-limiting)
|
||||
- [Deprecations](#deprecations-1)
|
||||
- [Contributors](#contributors-2)
|
||||
- [Contributors](#contributors-4)
|
||||
- [v0.13.0](#v0130)
|
||||
- [Wider VFIO device support](#wider-vfio-device-support)
|
||||
- [Improved huge page support](#improved-huge-page-support)
|
||||
@@ -30,13 +49,13 @@
|
||||
- [VHD disk image support](#vhd-disk-image-support)
|
||||
- [Improved Virtio device threading](#improved-virtio-device-threading)
|
||||
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
|
||||
- [Contributors](#contributors-3)
|
||||
- [Contributors](#contributors-5)
|
||||
- [v0.12.0](#v0120)
|
||||
- [ARM64 enhancements](#arm64-enhancements)
|
||||
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
|
||||
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
|
||||
- [Enhanced "info" API](#enhanced-info-api)
|
||||
- [Contributors](#contributors-4)
|
||||
- [Contributors](#contributors-6)
|
||||
- [v0.11.0](#v0110)
|
||||
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
|
||||
- [Windows Guest Support](#windows-guest-support)
|
||||
@@ -48,15 +67,15 @@
|
||||
- [Default Log Level Changed](#default-log-level-changed)
|
||||
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
|
||||
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
||||
- [Contributors](#contributors-5)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||
- [Contributors](#contributors-7)
|
||||
- [v0.10.0](#v0100)
|
||||
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
|
||||
- [Memory Zones](#memory-zones)
|
||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
|
||||
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
||||
- [Contributors](#contributors-6)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Contributors](#contributors-8)
|
||||
- [v0.9.0](#v090)
|
||||
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
|
||||
- [Block and Network Device Statistics](#block-and-network-device-statistics)
|
||||
@@ -69,17 +88,17 @@
|
||||
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
|
||||
- [Intel SGX Support](#intel-sgx-support)
|
||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||
- [Contributors](#contributors-7)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Contributors](#contributors-9)
|
||||
- [v0.8.0](#v080)
|
||||
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
|
||||
- [Experimental ARM64 Support](#experimental-arm64-support)
|
||||
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
|
||||
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
|
||||
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes)
|
||||
- [Contributors](#contributors-8)
|
||||
- [Contributors](#contributors-10)
|
||||
- [v0.7.0](#v070)
|
||||
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
|
||||
- [Alternative `libc` Support](#alternative-libc-support)
|
||||
@@ -89,14 +108,14 @@
|
||||
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
||||
- [Updated Distribution Support](#updated-distribution-support)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
||||
- [Contributors](#contributors-9)
|
||||
- [Contributors](#contributors-11)
|
||||
- [v0.6.0](#v060)
|
||||
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
|
||||
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
|
||||
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
|
||||
- [Command Line Interface](#command-line-interface)
|
||||
- [PVH Boot](#pvh-boot)
|
||||
- [Contributors](#contributors-10)
|
||||
- [Contributors](#contributors-12)
|
||||
- [v0.5.1](#v051)
|
||||
- [v0.5.0](#v050)
|
||||
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
||||
@@ -104,7 +123,7 @@
|
||||
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
||||
- [Development Tools](#development-tools)
|
||||
- [Kata Containers Integration](#kata-containers-integration)
|
||||
- [Contributors](#contributors-11)
|
||||
- [Contributors](#contributors-13)
|
||||
- [v0.4.0](#v040)
|
||||
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
||||
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
||||
@@ -113,7 +132,7 @@
|
||||
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
|
||||
- [PCI BAR reprogramming](#pci-bar-reprogramming)
|
||||
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
|
||||
- [Contributors](#contributors-12)
|
||||
- [Contributors](#contributors-14)
|
||||
- [v0.3.0](#v030)
|
||||
- [Block device offloading](#block-device-offloading)
|
||||
- [Network device backend](#network-device-backend)
|
||||
@@ -140,6 +159,137 @@
|
||||
- [Unit testing](#unit-testing)
|
||||
- [Integration tests parallelization](#integration-tests-parallelization)
|
||||
|
||||
# v18.0
|
||||
|
||||
This release has been tracked through the [v18.0
|
||||
project](https://github.com/cloud-hypervisor/cloud-hypervisor/projects/21).
|
||||
|
||||
### Experimental User Device (`vfio-user`) support
|
||||
|
||||
Experimental support for running PCI devices in userspace via `vfio-user`
|
||||
has been included. This allows the use of the SPDK NVMe `vfio-user` controller
|
||||
with Cloud Hypervisor. This is enabled by `--user-device` on the command line.
|
||||
|
||||
### Migration support for `vhost-user` devices
|
||||
|
||||
Devices exposed into the VM via `vhost-user` can now be migrated using the live
|
||||
migration support. This requires support from the backend however the commonly
|
||||
used DPDK `vhost-user` backend does support this.
|
||||
|
||||
### VHDX disk image support
|
||||
|
||||
Images using the VHDX disk image format can now be used with Cloud Hypervisor.
|
||||
|
||||
### Device pass through on MSHV hypervisor
|
||||
|
||||
When running on the MSHV hypervisor it is possible to pass through devices from
|
||||
the host through to the guest (e.g with `--device`)
|
||||
|
||||
### AArch64 for support `virtio-mem`
|
||||
|
||||
The reference Linux kernel we recommend for using with Cloud Hypervisor now supports `virtio-mem` on AArch64.
|
||||
|
||||
### Live migration on MSHV hypervisor
|
||||
|
||||
Live migration is now supported when running on the MSHV hypervisor including
|
||||
efficient tracking of dirty pages.
|
||||
|
||||
### AArch64 CPU topology support
|
||||
|
||||
The CPU topology (as configured through `--cpu topology=`) can now be
|
||||
configured on AArch64 platforms and is conveyed through either ACPI or device
|
||||
tree.
|
||||
|
||||
### Power button support on AArch64
|
||||
|
||||
Use of the ACPI power button (e.g `ch-remote --api-socket=<API socket> power-button`)
|
||||
is now supported when running on AArch64.
|
||||
|
||||
### Notable bug fixes
|
||||
|
||||
* Using two PTY outputs e.g. `--serial pty --console pty` now works correctly (#3012)
|
||||
* TTY input is now always sent to the correct destination (#3005)
|
||||
* The boot is no longer blocked when using a unattached PTY on the serial console (#3004)
|
||||
* Live migration is now supported on AArch64 (#3049)
|
||||
* Ensure signal handlers are run on the correct thread (#3069)
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Alyssa Ross <hi@alyssa.is>
|
||||
* Anatol Belski <anbelski@linux.microsoft.com>
|
||||
* Arafatms <arafatms@outlook.com>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Fazla Mehrab <akm.fazla.mehrab@vt.edu>
|
||||
* Henry Wang <Henry.Wang@arm.com>
|
||||
* Jianyong Wu <jianyong.wu@arm.com>
|
||||
* Jiaqi Gao <jiaqi.gao@intel.com>
|
||||
* Markus Theil <markus.theil@tu-ilmenau.de>
|
||||
* Muminul Islam <muislam@microsoft.com>
|
||||
* Rob Bradford <robert.bradford@intel.com>
|
||||
* Sebastien Boeuf <sebastien.boeuf@intel.com>
|
||||
* Wei Liu <liuwe@microsoft.com>
|
||||
* Yu Li <liyu.yukiteru@bytedance.com>
|
||||
|
||||
# v17.0
|
||||
|
||||
This release has been tracked through the [v17.0
|
||||
project](https://github.com/cloud-hypervisor/cloud-hypervisor/projects/20).
|
||||
|
||||
### ARM64 NUMA support using ACPI
|
||||
|
||||
The support for ACPI on ARM64 has been enhanced to include support for
|
||||
specifying a NUMA configuration using the existing control options.
|
||||
|
||||
### `Seccomp` support for MSHV backend
|
||||
|
||||
The `seccomp` rules have now been extended to support running against the MSHV
|
||||
hypervisor backend.
|
||||
|
||||
### Hotplug of `macvtap` devices
|
||||
|
||||
Hotplug of `macvtap` devices is now supported with the file descriptor for the
|
||||
network device if opened by the user and passed to the VMM. The `ch-remote`
|
||||
tool supports this functionality when adding a network device.
|
||||
|
||||
### Improved SGX support
|
||||
|
||||
The SGX support has been updated to match the latest Linux kernel support and
|
||||
now supports SGX provisioning and associating EPC sections to NUMA nodes.
|
||||
|
||||
### Inflight tracking for `vhost-user` devices
|
||||
|
||||
Support for handling inflight tracking of I/O requests has been added to the
|
||||
`vhost-user` devices allowing recovery after device reconnection.
|
||||
|
||||
### Notable bug fixes
|
||||
|
||||
* VFIO PCI BAR calculation code now correctly handles I/O BARs (#2821).
|
||||
* The VMM side of `vhost-user` devices no longer advertise the
|
||||
`VIRTIO_F_RING_PACKED` feature as they are not yet supported in the VMM
|
||||
(#2833).
|
||||
* On ARM64 VMs can be created with more than 16 vCPUs (#2763).
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Anatol Belski <anbelski@linux.microsoft.com>
|
||||
* Arafatms <arafatms@outlook.com>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Fei Li <lifei.shirley@bytedance.com>
|
||||
* Henry Wang <Henry.Wang@arm.com>
|
||||
* Jiachen Zhang <zhangjiachen.jaycee@bytedance.com>
|
||||
* Jianyong Wu <jianyong.wu@arm.com>
|
||||
* Li Hangjing <lihangjing@bytedance.com>
|
||||
* Michael Zhao <michael.zhao@arm.com>
|
||||
* Muminul Islam <muislam@microsoft.com>
|
||||
* Rob Bradford <robert.bradford@intel.com>
|
||||
* Sebastien Boeuf <sebastien.boeuf@intel.com>
|
||||
* Wei Liu <liuwe@microsoft.com>
|
||||
* Yukiteru <wfly1998@sina.com>
|
||||
|
||||
# v16.0
|
||||
|
||||
This release has been tracked through the [v16.0 project](https://github.com/cloud-hypervisor/cloud-hypervisor/projects/19).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FROM ubuntu:20.04 as dev
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG RUST_TOOLCHAIN="1.52.1"
|
||||
ARG RUST_TOOLCHAIN="1.54.0"
|
||||
ARG CLH_SRC_DIR="/cloud-hypervisor"
|
||||
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
|
||||
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/arm64 5.12.0 Kernel Configuration
|
||||
# Linux/arm64 5.14.0 Kernel Configuration
|
||||
#
|
||||
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0"
|
||||
CONFIG_CC_IS_GCC=y
|
||||
CONFIG_GCC_VERSION=90300
|
||||
CONFIG_CLANG_VERSION=0
|
||||
CONFIG_AS_IS_GNU=y
|
||||
CONFIG_AS_VERSION=23400
|
||||
CONFIG_LD_IS_BFD=y
|
||||
CONFIG_LD_VERSION=23400
|
||||
CONFIG_LLD_VERSION=0
|
||||
@@ -13,6 +15,7 @@ CONFIG_CC_CAN_LINK=y
|
||||
CONFIG_CC_CAN_LINK_STATIC=y
|
||||
CONFIG_CC_HAS_ASM_GOTO=y
|
||||
CONFIG_CC_HAS_ASM_INLINE=y
|
||||
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
|
||||
CONFIG_IRQ_WORK=y
|
||||
CONFIG_BUILDTIME_TABLE_SORT=y
|
||||
CONFIG_THREAD_INFO_IN_TASK=y
|
||||
@@ -60,7 +63,6 @@ CONFIG_SPARSE_IRQ=y
|
||||
# CONFIG_GENERIC_IRQ_DEBUGFS is not set
|
||||
# end of IRQ subsystem
|
||||
|
||||
CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
|
||||
CONFIG_GENERIC_TIME_VSYSCALL=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS=y
|
||||
CONFIG_ARCH_HAS_TICK_BROADCAST=y
|
||||
@@ -78,9 +80,22 @@ CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
# end of Timers subsystem
|
||||
|
||||
CONFIG_BPF=y
|
||||
CONFIG_HAVE_EBPF_JIT=y
|
||||
CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y
|
||||
|
||||
#
|
||||
# BPF subsystem
|
||||
#
|
||||
CONFIG_BPF_SYSCALL=y
|
||||
# CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set
|
||||
# CONFIG_BPF_PRELOAD is not set
|
||||
# end of BPF subsystem
|
||||
|
||||
CONFIG_PREEMPT_NONE=y
|
||||
# CONFIG_PREEMPT_VOLUNTARY is not set
|
||||
# CONFIG_PREEMPT is not set
|
||||
# CONFIG_SCHED_CORE is not set
|
||||
|
||||
#
|
||||
# CPU/Task time and stats accounting
|
||||
@@ -151,6 +166,7 @@ CONFIG_CGROUP_DEVICE=y
|
||||
CONFIG_CGROUP_CPUACCT=y
|
||||
CONFIG_CGROUP_PERF=y
|
||||
CONFIG_CGROUP_BPF=y
|
||||
# CONFIG_CGROUP_MISC is not set
|
||||
# CONFIG_CGROUP_DEBUG is not set
|
||||
CONFIG_SOCK_CGROUP_DATA=y
|
||||
CONFIG_NAMESPACES=y
|
||||
@@ -179,7 +195,6 @@ CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
|
||||
CONFIG_LD_ORPHAN_WARN=y
|
||||
CONFIG_SYSCTL=y
|
||||
CONFIG_SYSCTL_EXCEPTION_TRACE=y
|
||||
CONFIG_BPF=y
|
||||
CONFIG_EXPERT=y
|
||||
CONFIG_MULTIUSER=y
|
||||
CONFIG_SGETMASK_SYSCALL=y
|
||||
@@ -202,13 +217,11 @@ CONFIG_SHMEM=y
|
||||
CONFIG_AIO=y
|
||||
CONFIG_IO_URING=y
|
||||
CONFIG_ADVISE_SYSCALLS=y
|
||||
CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y
|
||||
CONFIG_MEMBARRIER=y
|
||||
CONFIG_KALLSYMS=y
|
||||
# CONFIG_KALLSYMS_ALL is not set
|
||||
CONFIG_KALLSYMS_BASE_RELATIVE=y
|
||||
CONFIG_BPF_SYSCALL=y
|
||||
CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y
|
||||
# CONFIG_BPF_PRELOAD is not set
|
||||
CONFIG_USERFAULTFD=y
|
||||
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
|
||||
# CONFIG_KCMP is not set
|
||||
@@ -258,10 +271,7 @@ CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
|
||||
CONFIG_GENERIC_HWEIGHT=y
|
||||
CONFIG_GENERIC_CSUM=y
|
||||
CONFIG_GENERIC_CALIBRATE_DELAY=y
|
||||
CONFIG_ZONE_DMA=y
|
||||
CONFIG_ZONE_DMA32=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
|
||||
CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_KERNEL_MODE_NEON=y
|
||||
CONFIG_FIX_EARLYCON_MEM=y
|
||||
@@ -273,10 +283,9 @@ CONFIG_ARCH_PROC_KCORE_TEXT=y
|
||||
# Platform selection
|
||||
#
|
||||
# CONFIG_ARCH_ACTIONS is not set
|
||||
# CONFIG_ARCH_AGILEX is not set
|
||||
# CONFIG_ARCH_N5X is not set
|
||||
# CONFIG_ARCH_SUNXI is not set
|
||||
# CONFIG_ARCH_ALPINE is not set
|
||||
# CONFIG_ARCH_APPLE is not set
|
||||
# CONFIG_ARCH_BCM2835 is not set
|
||||
# CONFIG_ARCH_BCM4908 is not set
|
||||
# CONFIG_ARCH_BCM_IPROC is not set
|
||||
@@ -300,7 +309,7 @@ CONFIG_ARCH_PROC_KCORE_TEXT=y
|
||||
# CONFIG_ARCH_ROCKCHIP is not set
|
||||
# CONFIG_ARCH_S32 is not set
|
||||
# CONFIG_ARCH_SEATTLE is not set
|
||||
# CONFIG_ARCH_STRATIX10 is not set
|
||||
# CONFIG_ARCH_INTEL_SOCFPGA is not set
|
||||
# CONFIG_ARCH_SYNQUACER is not set
|
||||
# CONFIG_ARCH_TEGRA is not set
|
||||
# CONFIG_ARCH_SPRD is not set
|
||||
@@ -328,6 +337,7 @@ CONFIG_ARM64_ERRATUM_819472=y
|
||||
CONFIG_ARM64_ERRATUM_832075=y
|
||||
CONFIG_ARM64_ERRATUM_834220=y
|
||||
CONFIG_ARM64_ERRATUM_843419=y
|
||||
CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y
|
||||
CONFIG_ARM64_ERRATUM_1024718=y
|
||||
CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT=y
|
||||
CONFIG_ARM64_ERRATUM_1165522=y
|
||||
@@ -373,7 +383,6 @@ CONFIG_NODES_SHIFT=10
|
||||
CONFIG_USE_PERCPU_NUMA_NODE_ID=y
|
||||
CONFIG_HAVE_SETUP_PER_CPU_AREA=y
|
||||
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
|
||||
CONFIG_HOLES_IN_ZONE=y
|
||||
# CONFIG_HZ_100 is not set
|
||||
CONFIG_HZ_250=y
|
||||
# CONFIG_HZ_300 is not set
|
||||
@@ -381,12 +390,8 @@ CONFIG_HZ_250=y
|
||||
CONFIG_HZ=250
|
||||
CONFIG_SCHED_HRTICK=y
|
||||
CONFIG_ARCH_SPARSEMEM_ENABLE=y
|
||||
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
|
||||
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
|
||||
CONFIG_HW_PERF_EVENTS=y
|
||||
CONFIG_SYS_SUPPORTS_HUGETLBFS=y
|
||||
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
|
||||
CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
|
||||
CONFIG_ARCH_HAS_FILTER_PGPROT=y
|
||||
CONFIG_PARAVIRT=y
|
||||
CONFIG_PARAVIRT_TIME_ACCOUNTING=y
|
||||
# CONFIG_KEXEC is not set
|
||||
@@ -411,7 +416,6 @@ CONFIG_AS_HAS_LDAPR=y
|
||||
CONFIG_AS_HAS_LSE_ATOMICS=y
|
||||
CONFIG_ARM64_LSE_ATOMICS=y
|
||||
CONFIG_ARM64_USE_LSE_ATOMICS=y
|
||||
CONFIG_ARM64_VHE=y
|
||||
# end of ARMv8.1 architectural features
|
||||
|
||||
#
|
||||
@@ -426,10 +430,9 @@ CONFIG_ARM64_CNP=y
|
||||
# ARMv8.3 architectural features
|
||||
#
|
||||
CONFIG_ARM64_PTR_AUTH=y
|
||||
CONFIG_CC_HAS_BRANCH_PROT_PAC_RET=y
|
||||
CONFIG_ARM64_PTR_AUTH_KERNEL=y
|
||||
CONFIG_CC_HAS_SIGN_RETURN_ADDRESS=y
|
||||
CONFIG_AS_HAS_PAC=y
|
||||
CONFIG_AS_HAS_CFI_NEGATE_RA_STATE=y
|
||||
# end of ARMv8.3 architectural features
|
||||
|
||||
#
|
||||
@@ -443,22 +446,22 @@ CONFIG_ARM64_TLB_RANGE=y
|
||||
#
|
||||
# ARMv8.5 architectural features
|
||||
#
|
||||
CONFIG_AS_HAS_ARMV8_5=y
|
||||
CONFIG_ARM64_BTI=y
|
||||
CONFIG_CC_HAS_BRANCH_PROT_PAC_RET_BTI=y
|
||||
CONFIG_ARM64_E0PD=y
|
||||
CONFIG_ARCH_RANDOM=y
|
||||
CONFIG_ARM64_AS_HAS_MTE=y
|
||||
CONFIG_ARM64_MTE=y
|
||||
# end of ARMv8.5 architectural features
|
||||
|
||||
#
|
||||
# ARMv8.7 architectural features
|
||||
#
|
||||
CONFIG_ARM64_EPAN=y
|
||||
# end of ARMv8.7 architectural features
|
||||
|
||||
CONFIG_ARM64_SVE=y
|
||||
# CONFIG_ARM64_PSEUDO_NMI is not set
|
||||
CONFIG_RELOCATABLE=y
|
||||
CONFIG_RANDOMIZE_BASE=y
|
||||
CONFIG_RANDOMIZE_MODULE_REGION_FULL=y
|
||||
CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
|
||||
CONFIG_STACKPROTECTOR_PER_TASK=y
|
||||
# end of Kernel Features
|
||||
|
||||
#
|
||||
@@ -471,9 +474,6 @@ CONFIG_EFI=y
|
||||
CONFIG_DMI=y
|
||||
# end of Boot options
|
||||
|
||||
CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
|
||||
CONFIG_ARCH_ENABLE_THP_MIGRATION=y
|
||||
|
||||
#
|
||||
# Power management options
|
||||
#
|
||||
@@ -553,6 +553,7 @@ CONFIG_FIRMWARE_MEMMAP=y
|
||||
CONFIG_DMIID=y
|
||||
CONFIG_DMI_SYSFS=y
|
||||
# CONFIG_FW_CFG_SYSFS is not set
|
||||
# CONFIG_ARM_FFA_TRANSPORT is not set
|
||||
# CONFIG_GOOGLE_FIRMWARE is not set
|
||||
|
||||
#
|
||||
@@ -623,6 +624,7 @@ CONFIG_ACPI_IORT=y
|
||||
CONFIG_ACPI_GTDT=y
|
||||
CONFIG_ACPI_PPTT=y
|
||||
# CONFIG_PMIC_OPREGION is not set
|
||||
CONFIG_ACPI_VIOT=y
|
||||
CONFIG_IRQ_BYPASS_MANAGER=y
|
||||
CONFIG_VIRTUALIZATION=y
|
||||
CONFIG_KVM=y
|
||||
@@ -661,6 +663,7 @@ CONFIG_ARCH_HAS_KEEPINITRD=y
|
||||
CONFIG_ARCH_HAS_SET_MEMORY=y
|
||||
CONFIG_ARCH_HAS_SET_DIRECT_MAP=y
|
||||
CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
|
||||
CONFIG_ARCH_WANTS_NO_INSTR=y
|
||||
CONFIG_HAVE_ASM_MODVERSIONS=y
|
||||
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
|
||||
CONFIG_HAVE_RSEQ=y
|
||||
@@ -688,6 +691,7 @@ CONFIG_STACKPROTECTOR_STRONG=y
|
||||
CONFIG_ARCH_SUPPORTS_LTO_CLANG=y
|
||||
CONFIG_ARCH_SUPPORTS_LTO_CLANG_THIN=y
|
||||
CONFIG_LTO_NONE=y
|
||||
CONFIG_ARCH_SUPPORTS_CFI_CLANG=y
|
||||
CONFIG_HAVE_CONTEXT_TRACKING=y
|
||||
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
|
||||
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
|
||||
@@ -705,6 +709,8 @@ CONFIG_CLONE_BACKWARDS=y
|
||||
# CONFIG_COMPAT_32BIT_TIME is not set
|
||||
CONFIG_HAVE_ARCH_VMAP_STACK=y
|
||||
CONFIG_VMAP_STACK=y
|
||||
CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET=y
|
||||
# CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT is not set
|
||||
CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
|
||||
CONFIG_STRICT_KERNEL_RWX=y
|
||||
CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
|
||||
@@ -742,9 +748,10 @@ CONFIG_BLK_DEV_THROTTLING=y
|
||||
# CONFIG_BLK_DEV_THROTTLING_LOW is not set
|
||||
CONFIG_BLK_CMDLINE_PARSER=y
|
||||
CONFIG_BLK_WBT=y
|
||||
CONFIG_BLK_WBT_MQ=y
|
||||
# CONFIG_BLK_CGROUP_IOLATENCY is not set
|
||||
# CONFIG_BLK_CGROUP_IOCOST is not set
|
||||
CONFIG_BLK_WBT_MQ=y
|
||||
# CONFIG_BLK_CGROUP_IOPRIO is not set
|
||||
CONFIG_BLK_DEBUG_FS=y
|
||||
# CONFIG_BLK_SED_OPAL is not set
|
||||
# CONFIG_BLK_INLINE_ENCRYPTION is not set
|
||||
@@ -863,10 +870,7 @@ CONFIG_COREDUMP=y
|
||||
#
|
||||
# Memory Management options
|
||||
#
|
||||
CONFIG_SELECT_MEMORY_MODEL=y
|
||||
CONFIG_SPARSEMEM_MANUAL=y
|
||||
CONFIG_SPARSEMEM=y
|
||||
CONFIG_NEED_MULTIPLE_NODES=y
|
||||
CONFIG_SPARSEMEM_EXTREME=y
|
||||
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
|
||||
CONFIG_SPARSEMEM_VMEMMAP=y
|
||||
@@ -874,19 +878,24 @@ CONFIG_HAVE_FAST_GUP=y
|
||||
CONFIG_ARCH_KEEP_MEMBLOCK=y
|
||||
CONFIG_NUMA_KEEP_MEMINFO=y
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
|
||||
CONFIG_MEMORY_HOTPLUG=y
|
||||
CONFIG_MEMORY_HOTPLUG_SPARSE=y
|
||||
# CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE is not set
|
||||
CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
|
||||
CONFIG_MEMORY_HOTREMOVE=y
|
||||
CONFIG_MHP_MEMMAP_ON_MEMORY=y
|
||||
CONFIG_SPLIT_PTLOCK_CPUS=4
|
||||
CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
|
||||
CONFIG_MEMORY_BALLOON=y
|
||||
CONFIG_BALLOON_COMPACTION=y
|
||||
CONFIG_COMPACTION=y
|
||||
CONFIG_PAGE_REPORTING=y
|
||||
CONFIG_MIGRATION=y
|
||||
CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
|
||||
CONFIG_ARCH_ENABLE_THP_MIGRATION=y
|
||||
CONFIG_CONTIG_ALLOC=y
|
||||
CONFIG_PHYS_ADDR_T_64BIT=y
|
||||
CONFIG_BOUNCE=y
|
||||
CONFIG_MMU_NOTIFIER=y
|
||||
CONFIG_KSM=y
|
||||
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
|
||||
@@ -919,15 +928,19 @@ CONFIG_ZSMALLOC_STAT=y
|
||||
CONFIG_GENERIC_EARLY_IOREMAP=y
|
||||
# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set
|
||||
# CONFIG_IDLE_PAGE_TRACKING is not set
|
||||
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
|
||||
CONFIG_ARCH_HAS_PTE_DEVMAP=y
|
||||
CONFIG_ARCH_HAS_ZONE_DMA_SET=y
|
||||
CONFIG_ZONE_DMA=y
|
||||
CONFIG_ZONE_DMA32=y
|
||||
CONFIG_ZONE_DEVICE=y
|
||||
CONFIG_DEV_PAGEMAP_OPS=y
|
||||
# CONFIG_DEVICE_PRIVATE is not set
|
||||
CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
|
||||
CONFIG_PERCPU_STATS=y
|
||||
# CONFIG_GUP_TEST is not set
|
||||
# CONFIG_READ_ONLY_THP_FOR_FS is not set
|
||||
CONFIG_ARCH_HAS_PTE_SPECIAL=y
|
||||
CONFIG_SECRETMEM=y
|
||||
# end of Memory Management options
|
||||
|
||||
CONFIG_NET=y
|
||||
@@ -991,7 +1004,6 @@ CONFIG_NET_PTP_CLASSIFY=y
|
||||
# CONFIG_ATM is not set
|
||||
# CONFIG_L2TP is not set
|
||||
# CONFIG_BRIDGE is not set
|
||||
CONFIG_HAVE_NET_DSA=y
|
||||
# CONFIG_NET_DSA is not set
|
||||
# CONFIG_VLAN_8021Q is not set
|
||||
# CONFIG_DECNET is not set
|
||||
@@ -1019,6 +1031,7 @@ CONFIG_VIRTIO_VSOCKETS_COMMON=y
|
||||
# CONFIG_NET_L3_MASTER_DEV is not set
|
||||
# CONFIG_QRTR is not set
|
||||
# CONFIG_NET_NCSI is not set
|
||||
CONFIG_PCPU_DEV_REFCNT=y
|
||||
CONFIG_RPS=y
|
||||
CONFIG_RFS_ACCEL=y
|
||||
CONFIG_SOCK_RX_QUEUE_MAPPING=y
|
||||
@@ -1056,7 +1069,6 @@ CONFIG_GRO_CELLS=y
|
||||
CONFIG_NET_SOCK_MSG=y
|
||||
CONFIG_FAILOVER=y
|
||||
# CONFIG_ETHTOOL_NETLINK is not set
|
||||
CONFIG_HAVE_EBPF_JIT=y
|
||||
|
||||
#
|
||||
# Device Drivers
|
||||
@@ -1128,7 +1140,6 @@ CONFIG_PCI_HOST_GENERIC=y
|
||||
#
|
||||
# Mobiveil PCIe Core Support
|
||||
#
|
||||
# CONFIG_PCIE_LAYERSCAPE_GEN4 is not set
|
||||
# end of Mobiveil PCIe Core Support
|
||||
|
||||
#
|
||||
@@ -1229,7 +1240,6 @@ CONFIG_ZRAM_DEF_COMP_LZORLE=y
|
||||
CONFIG_ZRAM_DEF_COMP="lzo-rle"
|
||||
# CONFIG_ZRAM_WRITEBACK is not set
|
||||
# CONFIG_ZRAM_MEMORY_TRACKING is not set
|
||||
# CONFIG_BLK_DEV_UMEM is not set
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
|
||||
CONFIG_BLK_DEV_CRYPTOLOOP=y
|
||||
@@ -1250,6 +1260,7 @@ CONFIG_VIRTIO_BLK=y
|
||||
#
|
||||
# CONFIG_BLK_DEV_NVME is not set
|
||||
# CONFIG_NVME_FC is not set
|
||||
# CONFIG_NVME_TCP is not set
|
||||
# CONFIG_NVME_TARGET is not set
|
||||
# end of NVME Support
|
||||
|
||||
@@ -1262,9 +1273,9 @@ CONFIG_VIRTIO_BLK=y
|
||||
# CONFIG_ENCLOSURE_SERVICES is not set
|
||||
# CONFIG_HP_ILO is not set
|
||||
# CONFIG_SRAM is not set
|
||||
# CONFIG_DW_XDATA_PCIE is not set
|
||||
# CONFIG_PCI_ENDPOINT_TEST is not set
|
||||
# CONFIG_XILINX_SDFEC is not set
|
||||
# CONFIG_PVPANIC is not set
|
||||
# CONFIG_C2PORT is not set
|
||||
|
||||
#
|
||||
@@ -1291,6 +1302,7 @@ CONFIG_VIRTIO_BLK=y
|
||||
# CONFIG_MISC_RTSX_PCI is not set
|
||||
# CONFIG_HABANA_AI is not set
|
||||
# CONFIG_UACCE is not set
|
||||
# CONFIG_PVPANIC is not set
|
||||
# end of Misc devices
|
||||
|
||||
#
|
||||
@@ -1335,13 +1347,6 @@ CONFIG_VETH=y
|
||||
CONFIG_VIRTIO_NET=y
|
||||
# CONFIG_NLMON is not set
|
||||
# CONFIG_ARCNET is not set
|
||||
|
||||
#
|
||||
# Distributed Switch Architecture drivers
|
||||
#
|
||||
# CONFIG_NET_DSA_MV88E6XXX_PTP is not set
|
||||
# end of Distributed Switch Architecture drivers
|
||||
|
||||
# CONFIG_ETHERNET is not set
|
||||
# CONFIG_FDDI is not set
|
||||
# CONFIG_HIPPI is not set
|
||||
@@ -1362,6 +1367,13 @@ CONFIG_VIRTIO_NET=y
|
||||
#
|
||||
# CONFIG_WLAN is not set
|
||||
# CONFIG_WAN is not set
|
||||
|
||||
#
|
||||
# Wireless WAN
|
||||
#
|
||||
# CONFIG_WWAN is not set
|
||||
# end of Wireless WAN
|
||||
|
||||
# CONFIG_VMXNET3 is not set
|
||||
# CONFIG_FUJITSU_ES is not set
|
||||
# CONFIG_NETDEVSIM is not set
|
||||
@@ -1497,7 +1509,6 @@ CONFIG_SERIAL_MCTRL_GPIO=y
|
||||
# CONFIG_N_GSM is not set
|
||||
# CONFIG_NOZOMI is not set
|
||||
# CONFIG_NULL_TTY is not set
|
||||
# CONFIG_TRACE_SINK is not set
|
||||
CONFIG_HVC_DRIVER=y
|
||||
# CONFIG_HVC_DCC is not set
|
||||
CONFIG_SERIAL_DEV_BUS=y
|
||||
@@ -1514,8 +1525,6 @@ CONFIG_HW_RANDOM_CAVIUM=y
|
||||
# CONFIG_HW_RANDOM_XIPHERA is not set
|
||||
# CONFIG_APPLICOM is not set
|
||||
CONFIG_DEVMEM=y
|
||||
CONFIG_RAW_DRIVER=y
|
||||
CONFIG_MAX_RAW_DEVS=256
|
||||
CONFIG_DEVPORT=y
|
||||
# CONFIG_TCG_TPM is not set
|
||||
# CONFIG_XILLYBUS is not set
|
||||
@@ -1556,6 +1565,7 @@ CONFIG_PTP_1588_CLOCK=y
|
||||
#
|
||||
# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
|
||||
#
|
||||
CONFIG_PTP_1588_CLOCK_KVM=y
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# end of PTP clock support
|
||||
|
||||
@@ -1632,6 +1642,7 @@ CONFIG_POWER_SUPPLY=y
|
||||
# CONFIG_CHARGER_MAX8903 is not set
|
||||
# CONFIG_CHARGER_GPIO is not set
|
||||
# CONFIG_CHARGER_LT3651 is not set
|
||||
# CONFIG_BATTERY_GOLDFISH is not set
|
||||
# CONFIG_HWMON is not set
|
||||
CONFIG_THERMAL=y
|
||||
# CONFIG_THERMAL_NETLINK is not set
|
||||
@@ -1655,6 +1666,7 @@ CONFIG_WATCHDOG_CORE=y
|
||||
CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y
|
||||
CONFIG_WATCHDOG_OPEN_TIMEOUT=0
|
||||
# CONFIG_WATCHDOG_SYSFS is not set
|
||||
# CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT is not set
|
||||
|
||||
#
|
||||
# Watchdog Pretimeout Governors
|
||||
@@ -1705,7 +1717,6 @@ CONFIG_BCMA_POSSIBLE=y
|
||||
# CONFIG_MFD_MT6397 is not set
|
||||
# CONFIG_MFD_RDC321X is not set
|
||||
# CONFIG_MFD_SM501 is not set
|
||||
# CONFIG_ABX500_CORE is not set
|
||||
# CONFIG_MFD_SYSCON is not set
|
||||
# CONFIG_MFD_TI_AM335X_TSCADC is not set
|
||||
# CONFIG_MFD_TQMX86 is not set
|
||||
@@ -1869,6 +1880,7 @@ CONFIG_HID_REDRAGON=y
|
||||
# CONFIG_HID_PRIMAX is not set
|
||||
# CONFIG_HID_SAITEK is not set
|
||||
# CONFIG_HID_SAMSUNG is not set
|
||||
# CONFIG_HID_SEMITEK is not set
|
||||
# CONFIG_HID_SPEEDLINK is not set
|
||||
# CONFIG_HID_STEAM is not set
|
||||
# CONFIG_HID_STEELSERIES is not set
|
||||
@@ -1878,7 +1890,6 @@ CONFIG_HID_REDRAGON=y
|
||||
# CONFIG_HID_SMARTJOYPLUS is not set
|
||||
# CONFIG_HID_TIVO is not set
|
||||
# CONFIG_HID_TOPSEED is not set
|
||||
# CONFIG_HID_THRUSTMASTER is not set
|
||||
# CONFIG_HID_UDRAW_PS3 is not set
|
||||
# CONFIG_HID_XINMO is not set
|
||||
# CONFIG_HID_ZEROPLUS is not set
|
||||
@@ -2033,6 +2044,7 @@ CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_VIRTIO_PCI_LEGACY=y
|
||||
CONFIG_VIRTIO_PMEM=y
|
||||
CONFIG_VIRTIO_BALLOON=y
|
||||
CONFIG_VIRTIO_MEM=y
|
||||
CONFIG_VIRTIO_INPUT=y
|
||||
CONFIG_VIRTIO_MMIO=y
|
||||
CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
|
||||
@@ -2048,15 +2060,23 @@ CONFIG_VHOST_MENU=y
|
||||
# end of Microsoft Hyper-V guest support
|
||||
|
||||
# CONFIG_GREYBUS is not set
|
||||
# CONFIG_COMEDI is not set
|
||||
# CONFIG_STAGING is not set
|
||||
# CONFIG_GOLDFISH is not set
|
||||
# CONFIG_CHROME_PLATFORMS is not set
|
||||
# CONFIG_MELLANOX_PLATFORM is not set
|
||||
# CONFIG_SURFACE_PLATFORMS is not set
|
||||
CONFIG_HAVE_CLK=y
|
||||
CONFIG_CLKDEV_LOOKUP=y
|
||||
CONFIG_HAVE_CLK_PREPARE=y
|
||||
CONFIG_COMMON_CLK=y
|
||||
|
||||
#
|
||||
# Clock driver for ARM Reference designs
|
||||
#
|
||||
# CONFIG_ICST is not set
|
||||
# CONFIG_CLK_SP810 is not set
|
||||
# end of Clock driver for ARM Reference designs
|
||||
|
||||
# CONFIG_COMMON_CLK_AXI_CLKGEN is not set
|
||||
# CONFIG_COMMON_CLK_XGENE is not set
|
||||
# CONFIG_COMMON_CLK_FIXED_MMIO is not set
|
||||
@@ -2104,9 +2124,6 @@ CONFIG_IOMMU_DMA=y
|
||||
# CONFIG_ARM_SMMU is not set
|
||||
# CONFIG_ARM_SMMU_V3 is not set
|
||||
CONFIG_VIRTIO_IOMMU=y
|
||||
CONFIG_VIRTIO_IOMMU_TOPOLOGY_HELPERS=y
|
||||
CONFIG_VIRTIO_IOMMU_TOPOLOGY=y
|
||||
CONFIG_ACPI_VIOT=y
|
||||
|
||||
#
|
||||
# Remoteproc drivers
|
||||
@@ -2199,6 +2216,7 @@ CONFIG_PARTITION_PERCPU=y
|
||||
#
|
||||
# CONFIG_GENERIC_PHY is not set
|
||||
# CONFIG_PHY_XGENE is not set
|
||||
# CONFIG_PHY_CAN_TRANSCEIVER is not set
|
||||
# CONFIG_BCM_KONA_USB2_PHY is not set
|
||||
# CONFIG_PHY_CADENCE_TORRENT is not set
|
||||
# CONFIG_PHY_CADENCE_DPHY is not set
|
||||
@@ -2327,6 +2345,8 @@ CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y
|
||||
#
|
||||
# Caches
|
||||
#
|
||||
CONFIG_NETFS_SUPPORT=y
|
||||
# CONFIG_NETFS_STATS is not set
|
||||
CONFIG_FSCACHE=y
|
||||
# CONFIG_FSCACHE_STATS is not set
|
||||
# CONFIG_FSCACHE_HISTOGRAM is not set
|
||||
@@ -2371,6 +2391,7 @@ CONFIG_TMPFS=y
|
||||
CONFIG_TMPFS_POSIX_ACL=y
|
||||
CONFIG_TMPFS_XATTR=y
|
||||
# CONFIG_TMPFS_INODE64 is not set
|
||||
CONFIG_ARCH_SUPPORTS_HUGETLBFS=y
|
||||
CONFIG_HUGETLBFS=y
|
||||
CONFIG_HUGETLB_PAGE=y
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
@@ -2545,6 +2566,7 @@ CONFIG_CRYPTO_CRYPTD=y
|
||||
# CONFIG_CRYPTO_RSA is not set
|
||||
# CONFIG_CRYPTO_DH is not set
|
||||
# CONFIG_CRYPTO_ECDH is not set
|
||||
# CONFIG_CRYPTO_ECDSA is not set
|
||||
# CONFIG_CRYPTO_ECRDSA is not set
|
||||
# CONFIG_CRYPTO_SM2 is not set
|
||||
# CONFIG_CRYPTO_CURVE25519 is not set
|
||||
@@ -2673,6 +2695,8 @@ CONFIG_SYSTEM_BLACKLIST_KEYRING=y
|
||||
CONFIG_SYSTEM_BLACKLIST_HASH_LIST=""
|
||||
# end of Certificates for signature checking
|
||||
|
||||
CONFIG_BINARY_PRINTF=y
|
||||
|
||||
#
|
||||
# Library routines
|
||||
#
|
||||
@@ -2682,6 +2706,7 @@ CONFIG_HAVE_ARCH_BITREVERSE=y
|
||||
CONFIG_GENERIC_STRNCPY_FROM_USER=y
|
||||
CONFIG_GENERIC_STRNLEN_USER=y
|
||||
CONFIG_GENERIC_NET_UTILS=y
|
||||
CONFIG_GENERIC_FIND_FIRST_BIT=y
|
||||
# CONFIG_CORDIC is not set
|
||||
# CONFIG_PRIME_NUMBERS is not set
|
||||
CONFIG_RATIONAL=y
|
||||
@@ -2770,7 +2795,6 @@ CONFIG_FONT_8x16=y
|
||||
CONFIG_MEMREGION=y
|
||||
CONFIG_ARCH_STACKWALK=y
|
||||
CONFIG_SBITMAP=y
|
||||
# CONFIG_STRING_SELFTEST is not set
|
||||
# end of Library routines
|
||||
|
||||
CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
|
||||
@@ -2784,6 +2808,7 @@ CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
|
||||
#
|
||||
CONFIG_PRINTK_TIME=y
|
||||
# CONFIG_PRINTK_CALLER is not set
|
||||
# CONFIG_STACKTRACE_BUILD_ID is not set
|
||||
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
|
||||
CONFIG_CONSOLE_LOGLEVEL_QUIET=4
|
||||
CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
|
||||
@@ -2804,9 +2829,10 @@ CONFIG_STRIP_ASM_SYMS=y
|
||||
# CONFIG_HEADERS_INSTALL is not set
|
||||
CONFIG_DEBUG_SECTION_MISMATCH=y
|
||||
CONFIG_SECTION_MISMATCH_WARN_ONLY=y
|
||||
# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set
|
||||
# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set
|
||||
CONFIG_ARCH_WANT_FRAME_POINTERS=y
|
||||
CONFIG_FRAME_POINTER=y
|
||||
# CONFIG_VMLINUX_MAP is not set
|
||||
# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
|
||||
# end of Compile-time checks and compiler options
|
||||
|
||||
@@ -2858,10 +2884,8 @@ CONFIG_DEBUG_MEMORY_INIT=y
|
||||
# CONFIG_DEBUG_PER_CPU_MAPS is not set
|
||||
CONFIG_HAVE_ARCH_KASAN=y
|
||||
CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y
|
||||
CONFIG_HAVE_ARCH_KASAN_HW_TAGS=y
|
||||
CONFIG_HAVE_ARCH_KASAN_VMALLOC=y
|
||||
CONFIG_CC_HAS_KASAN_GENERIC=y
|
||||
CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y
|
||||
# CONFIG_KASAN is not set
|
||||
CONFIG_HAVE_ARCH_KFENCE=y
|
||||
# CONFIG_KFENCE is not set
|
||||
# end of Memory Debugging
|
||||
@@ -2913,7 +2937,6 @@ CONFIG_LOCK_DEBUGGING_SUPPORT=y
|
||||
CONFIG_STACKTRACE=y
|
||||
# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set
|
||||
# CONFIG_DEBUG_KOBJECT is not set
|
||||
CONFIG_HAVE_DEBUG_BUGVERBOSE=y
|
||||
|
||||
#
|
||||
# Debug kernel data structures
|
||||
@@ -2945,7 +2968,6 @@ CONFIG_RCU_CPU_STALL_TIMEOUT=59
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
||||
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||
@@ -2973,19 +2995,21 @@ CONFIG_CC_HAS_SANCOV_TRACE_PC=y
|
||||
# CONFIG_KCOV is not set
|
||||
CONFIG_RUNTIME_TESTING_MENU=y
|
||||
# CONFIG_LKDTM is not set
|
||||
# CONFIG_TEST_LIST_SORT is not set
|
||||
# CONFIG_TEST_MIN_HEAP is not set
|
||||
# CONFIG_TEST_SORT is not set
|
||||
# CONFIG_TEST_DIV64 is not set
|
||||
# CONFIG_BACKTRACE_SELF_TEST is not set
|
||||
# CONFIG_RBTREE_TEST is not set
|
||||
# CONFIG_REED_SOLOMON_TEST is not set
|
||||
# CONFIG_INTERVAL_TREE_TEST is not set
|
||||
# CONFIG_ATOMIC64_SELFTEST is not set
|
||||
# CONFIG_TEST_HEXDUMP is not set
|
||||
# CONFIG_STRING_SELFTEST is not set
|
||||
# CONFIG_TEST_STRING_HELPERS is not set
|
||||
# CONFIG_TEST_STRSCPY is not set
|
||||
# CONFIG_TEST_KSTRTOX is not set
|
||||
# CONFIG_TEST_PRINTF is not set
|
||||
# CONFIG_TEST_SCANF is not set
|
||||
# CONFIG_TEST_BITMAP is not set
|
||||
# CONFIG_TEST_UUID is not set
|
||||
# CONFIG_TEST_XARRAY is not set
|
||||
@@ -3001,6 +3025,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
|
||||
# CONFIG_TEST_STACKINIT is not set
|
||||
# CONFIG_TEST_MEMINIT is not set
|
||||
# CONFIG_TEST_FREE_PAGES is not set
|
||||
CONFIG_ARCH_USE_MEMTEST=y
|
||||
# CONFIG_MEMTEST is not set
|
||||
# end of Kernel Testing and Coverage
|
||||
# end of Kernel hacking
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/x86 5.12.0 Kernel Configuration
|
||||
# Linux/x86 5.14.0 Kernel Configuration
|
||||
#
|
||||
CONFIG_CC_VERSION_TEXT="gcc (GCC) 10.2.1 20201125 (Red Hat 10.2.1-9)"
|
||||
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 10.3.0-1ubuntu1) 10.3.0"
|
||||
CONFIG_CC_IS_GCC=y
|
||||
CONFIG_GCC_VERSION=100201
|
||||
CONFIG_GCC_VERSION=100300
|
||||
CONFIG_CLANG_VERSION=0
|
||||
CONFIG_AS_IS_GNU=y
|
||||
CONFIG_AS_VERSION=23500
|
||||
CONFIG_LD_IS_BFD=y
|
||||
CONFIG_LD_VERSION=23500
|
||||
CONFIG_LLD_VERSION=0
|
||||
@@ -13,6 +15,7 @@ CONFIG_CC_CAN_LINK=y
|
||||
CONFIG_CC_CAN_LINK_STATIC=y
|
||||
CONFIG_CC_HAS_ASM_GOTO=y
|
||||
CONFIG_CC_HAS_ASM_INLINE=y
|
||||
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
|
||||
CONFIG_IRQ_WORK=y
|
||||
CONFIG_BUILDTIME_TABLE_SORT=y
|
||||
CONFIG_THREAD_INFO_IN_TASK=y
|
||||
@@ -97,9 +100,22 @@ CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
# end of Timers subsystem
|
||||
|
||||
CONFIG_BPF=y
|
||||
CONFIG_HAVE_EBPF_JIT=y
|
||||
CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y
|
||||
|
||||
#
|
||||
# BPF subsystem
|
||||
#
|
||||
CONFIG_BPF_SYSCALL=y
|
||||
# CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set
|
||||
# CONFIG_BPF_PRELOAD is not set
|
||||
# end of BPF subsystem
|
||||
|
||||
CONFIG_PREEMPT_NONE=y
|
||||
# CONFIG_PREEMPT_VOLUNTARY is not set
|
||||
# CONFIG_PREEMPT is not set
|
||||
# CONFIG_SCHED_CORE is not set
|
||||
|
||||
#
|
||||
# CPU/Task time and stats accounting
|
||||
@@ -173,6 +189,7 @@ CONFIG_CGROUP_DEVICE=y
|
||||
CONFIG_CGROUP_CPUACCT=y
|
||||
CONFIG_CGROUP_PERF=y
|
||||
CONFIG_CGROUP_BPF=y
|
||||
# CONFIG_CGROUP_MISC is not set
|
||||
# CONFIG_CGROUP_DEBUG is not set
|
||||
CONFIG_SOCK_CGROUP_DATA=y
|
||||
CONFIG_NAMESPACES=y
|
||||
@@ -202,7 +219,6 @@ CONFIG_LD_ORPHAN_WARN=y
|
||||
CONFIG_SYSCTL=y
|
||||
CONFIG_SYSCTL_EXCEPTION_TRACE=y
|
||||
CONFIG_HAVE_PCSPKR_PLATFORM=y
|
||||
CONFIG_BPF=y
|
||||
CONFIG_EXPERT=y
|
||||
CONFIG_MULTIUSER=y
|
||||
CONFIG_SGETMASK_SYSCALL=y
|
||||
@@ -226,14 +242,12 @@ CONFIG_AIO=y
|
||||
CONFIG_IO_URING=y
|
||||
CONFIG_ADVISE_SYSCALLS=y
|
||||
CONFIG_HAVE_ARCH_USERFAULTFD_WP=y
|
||||
CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y
|
||||
CONFIG_MEMBARRIER=y
|
||||
CONFIG_KALLSYMS=y
|
||||
# CONFIG_KALLSYMS_ALL is not set
|
||||
CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y
|
||||
CONFIG_KALLSYMS_BASE_RELATIVE=y
|
||||
CONFIG_BPF_SYSCALL=y
|
||||
CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y
|
||||
# CONFIG_BPF_PRELOAD is not set
|
||||
CONFIG_USERFAULTFD=y
|
||||
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
|
||||
# CONFIG_KCMP is not set
|
||||
@@ -280,7 +294,6 @@ CONFIG_GENERIC_BUG=y
|
||||
CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
|
||||
CONFIG_GENERIC_CALIBRATE_DELAY=y
|
||||
CONFIG_ARCH_HAS_CPU_RELAX=y
|
||||
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
|
||||
CONFIG_ARCH_HAS_FILTER_PGPROT=y
|
||||
CONFIG_HAVE_SETUP_PER_CPU_AREA=y
|
||||
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
|
||||
@@ -288,7 +301,6 @@ CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
|
||||
CONFIG_ZONE_DMA32=y
|
||||
CONFIG_AUDIT_ARCH=y
|
||||
CONFIG_X86_64_SMP=y
|
||||
CONFIG_ARCH_SUPPORTS_UPROBES=y
|
||||
@@ -300,7 +312,6 @@ CONFIG_CC_HAS_SANE_STACKPROTECTOR=y
|
||||
#
|
||||
# Processor type and features
|
||||
#
|
||||
CONFIG_ZONE_DMA=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_X86_FEATURE_NAMES=y
|
||||
CONFIG_X86_X2APIC=y
|
||||
@@ -398,7 +409,6 @@ CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
|
||||
# CONFIG_X86_PMEM_LEGACY is not set
|
||||
CONFIG_X86_CHECK_BIOS_CORRUPTION=y
|
||||
CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y
|
||||
CONFIG_X86_RESERVE_LOW=64
|
||||
CONFIG_MTRR=y
|
||||
CONFIG_MTRR_SANITIZER=y
|
||||
CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=0
|
||||
@@ -447,12 +457,8 @@ CONFIG_HAVE_LIVEPATCH=y
|
||||
# end of Processor type and features
|
||||
|
||||
CONFIG_ARCH_HAS_ADD_PAGES=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
|
||||
CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y
|
||||
CONFIG_USE_PERCPU_NUMA_NODE_ID=y
|
||||
CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
|
||||
CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
|
||||
CONFIG_ARCH_ENABLE_THP_MIGRATION=y
|
||||
|
||||
#
|
||||
# Power management and ACPI options
|
||||
@@ -520,7 +526,9 @@ CONFIG_HAVE_ACPI_APEI_NMI=y
|
||||
# CONFIG_ACPI_DPTF is not set
|
||||
# CONFIG_ACPI_CONFIGFS is not set
|
||||
# CONFIG_PMIC_OPREGION is not set
|
||||
CONFIG_ACPI_VIOT=y
|
||||
CONFIG_X86_PM_TIMER=y
|
||||
# CONFIG_ACPI_PRMT is not set
|
||||
|
||||
#
|
||||
# CPU Frequency scaling
|
||||
@@ -639,6 +647,7 @@ CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
|
||||
CONFIG_HAVE_KVM_IRQ_BYPASS=y
|
||||
CONFIG_HAVE_KVM_NO_POLL=y
|
||||
CONFIG_KVM_XFER_TO_GUEST_WORK=y
|
||||
CONFIG_HAVE_KVM_PM_NOTIFIER=y
|
||||
CONFIG_VIRTUALIZATION=y
|
||||
CONFIG_KVM=y
|
||||
# CONFIG_KVM_WERROR is not set
|
||||
@@ -678,6 +687,7 @@ CONFIG_ARCH_HAS_SET_MEMORY=y
|
||||
CONFIG_ARCH_HAS_SET_DIRECT_MAP=y
|
||||
CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
|
||||
CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y
|
||||
CONFIG_ARCH_WANTS_NO_INSTR=y
|
||||
CONFIG_HAVE_ASM_MODVERSIONS=y
|
||||
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
|
||||
CONFIG_HAVE_RSEQ=y
|
||||
@@ -734,6 +744,8 @@ CONFIG_HAVE_RELIABLE_STACKTRACE=y
|
||||
# CONFIG_COMPAT_32BIT_TIME is not set
|
||||
CONFIG_HAVE_ARCH_VMAP_STACK=y
|
||||
CONFIG_VMAP_STACK=y
|
||||
CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET=y
|
||||
# CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT is not set
|
||||
CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
|
||||
CONFIG_STRICT_KERNEL_RWX=y
|
||||
CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
|
||||
@@ -768,14 +780,16 @@ CONFIG_BLK_CGROUP_RWSTAT=y
|
||||
CONFIG_BLK_DEV_BSG=y
|
||||
CONFIG_BLK_DEV_BSGLIB=y
|
||||
CONFIG_BLK_DEV_INTEGRITY=y
|
||||
CONFIG_BLK_DEV_INTEGRITY_T10=y
|
||||
# CONFIG_BLK_DEV_ZONED is not set
|
||||
CONFIG_BLK_DEV_THROTTLING=y
|
||||
# CONFIG_BLK_DEV_THROTTLING_LOW is not set
|
||||
CONFIG_BLK_CMDLINE_PARSER=y
|
||||
CONFIG_BLK_WBT=y
|
||||
CONFIG_BLK_WBT_MQ=y
|
||||
# CONFIG_BLK_CGROUP_IOLATENCY is not set
|
||||
# CONFIG_BLK_CGROUP_IOCOST is not set
|
||||
CONFIG_BLK_WBT_MQ=y
|
||||
# CONFIG_BLK_CGROUP_IOPRIO is not set
|
||||
CONFIG_BLK_DEBUG_FS=y
|
||||
# CONFIG_BLK_SED_OPAL is not set
|
||||
# CONFIG_BLK_INLINE_ENCRYPTION is not set
|
||||
@@ -849,7 +863,6 @@ CONFIG_COREDUMP=y
|
||||
CONFIG_SELECT_MEMORY_MODEL=y
|
||||
CONFIG_SPARSEMEM_MANUAL=y
|
||||
CONFIG_SPARSEMEM=y
|
||||
CONFIG_NEED_MULTIPLE_NODES=y
|
||||
CONFIG_SPARSEMEM_EXTREME=y
|
||||
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
|
||||
CONFIG_SPARSEMEM_VMEMMAP=y
|
||||
@@ -857,19 +870,24 @@ CONFIG_HAVE_FAST_GUP=y
|
||||
CONFIG_NUMA_KEEP_MEMINFO=y
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_HAVE_BOOTMEM_INFO_NODE=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
|
||||
CONFIG_MEMORY_HOTPLUG=y
|
||||
CONFIG_MEMORY_HOTPLUG_SPARSE=y
|
||||
CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
|
||||
CONFIG_MEMORY_HOTREMOVE=y
|
||||
CONFIG_MHP_MEMMAP_ON_MEMORY=y
|
||||
CONFIG_SPLIT_PTLOCK_CPUS=4
|
||||
CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
|
||||
CONFIG_MEMORY_BALLOON=y
|
||||
CONFIG_BALLOON_COMPACTION=y
|
||||
CONFIG_COMPACTION=y
|
||||
CONFIG_PAGE_REPORTING=y
|
||||
CONFIG_MIGRATION=y
|
||||
CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
|
||||
CONFIG_ARCH_ENABLE_THP_MIGRATION=y
|
||||
CONFIG_CONTIG_ALLOC=y
|
||||
CONFIG_PHYS_ADDR_T_64BIT=y
|
||||
CONFIG_BOUNCE=y
|
||||
CONFIG_VIRT_TO_BUS=y
|
||||
CONFIG_MMU_NOTIFIER=y
|
||||
CONFIG_KSM=y
|
||||
@@ -903,7 +921,11 @@ CONFIG_ZSMALLOC_STAT=y
|
||||
CONFIG_GENERIC_EARLY_IOREMAP=y
|
||||
# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set
|
||||
# CONFIG_IDLE_PAGE_TRACKING is not set
|
||||
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
|
||||
CONFIG_ARCH_HAS_PTE_DEVMAP=y
|
||||
CONFIG_ARCH_HAS_ZONE_DMA_SET=y
|
||||
CONFIG_ZONE_DMA=y
|
||||
CONFIG_ZONE_DMA32=y
|
||||
CONFIG_ZONE_DEVICE=y
|
||||
CONFIG_DEV_PAGEMAP_OPS=y
|
||||
# CONFIG_DEVICE_PRIVATE is not set
|
||||
@@ -911,6 +933,7 @@ CONFIG_PERCPU_STATS=y
|
||||
# CONFIG_GUP_TEST is not set
|
||||
# CONFIG_READ_ONLY_THP_FOR_FS is not set
|
||||
CONFIG_ARCH_HAS_PTE_SPECIAL=y
|
||||
CONFIG_SECRETMEM=y
|
||||
# end of Memory Management options
|
||||
|
||||
CONFIG_NET=y
|
||||
@@ -974,7 +997,6 @@ CONFIG_NET_PTP_CLASSIFY=y
|
||||
# CONFIG_ATM is not set
|
||||
# CONFIG_L2TP is not set
|
||||
# CONFIG_BRIDGE is not set
|
||||
CONFIG_HAVE_NET_DSA=y
|
||||
# CONFIG_NET_DSA is not set
|
||||
# CONFIG_VLAN_8021Q is not set
|
||||
# CONFIG_DECNET is not set
|
||||
@@ -994,6 +1016,7 @@ CONFIG_VSOCKETS_DIAG=y
|
||||
# CONFIG_VSOCKETS_LOOPBACK is not set
|
||||
CONFIG_VIRTIO_VSOCKETS=y
|
||||
CONFIG_VIRTIO_VSOCKETS_COMMON=y
|
||||
# CONFIG_HYPERV_VSOCKETS is not set
|
||||
# CONFIG_NETLINK_DIAG is not set
|
||||
# CONFIG_MPLS is not set
|
||||
# CONFIG_NET_NSH is not set
|
||||
@@ -1002,6 +1025,7 @@ CONFIG_VIRTIO_VSOCKETS_COMMON=y
|
||||
# CONFIG_NET_L3_MASTER_DEV is not set
|
||||
# CONFIG_QRTR is not set
|
||||
# CONFIG_NET_NCSI is not set
|
||||
CONFIG_PCPU_DEV_REFCNT=y
|
||||
CONFIG_RPS=y
|
||||
CONFIG_RFS_ACCEL=y
|
||||
CONFIG_SOCK_RX_QUEUE_MAPPING=y
|
||||
@@ -1039,7 +1063,6 @@ CONFIG_GRO_CELLS=y
|
||||
CONFIG_NET_SOCK_MSG=y
|
||||
CONFIG_FAILOVER=y
|
||||
# CONFIG_ETHTOOL_NETLINK is not set
|
||||
CONFIG_HAVE_EBPF_JIT=y
|
||||
|
||||
#
|
||||
# Device Drivers
|
||||
@@ -1073,6 +1096,7 @@ CONFIG_PCI_LOCKLESS_CONFIG=y
|
||||
# CONFIG_PCI_PASID is not set
|
||||
# CONFIG_PCI_P2PDMA is not set
|
||||
CONFIG_PCI_LABEL=y
|
||||
# CONFIG_PCI_HYPERV is not set
|
||||
# CONFIG_PCIE_BUS_TUNE_OFF is not set
|
||||
CONFIG_PCIE_BUS_DEFAULT=y
|
||||
# CONFIG_PCIE_BUS_SAFE is not set
|
||||
@@ -1088,6 +1112,7 @@ CONFIG_HOTPLUG_PCI_ACPI=y
|
||||
# PCI controller drivers
|
||||
#
|
||||
# CONFIG_VMD is not set
|
||||
# CONFIG_PCI_HYPERV_INTERFACE is not set
|
||||
|
||||
#
|
||||
# DesignWare PCI Core Support
|
||||
@@ -1182,7 +1207,6 @@ CONFIG_ZRAM_DEF_COMP_LZORLE=y
|
||||
CONFIG_ZRAM_DEF_COMP="lzo-rle"
|
||||
# CONFIG_ZRAM_WRITEBACK is not set
|
||||
# CONFIG_ZRAM_MEMORY_TRACKING is not set
|
||||
# CONFIG_BLK_DEV_UMEM is not set
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
|
||||
CONFIG_BLK_DEV_CRYPTOLOOP=y
|
||||
@@ -1201,8 +1225,11 @@ CONFIG_VIRTIO_BLK=y
|
||||
#
|
||||
# NVME Support
|
||||
#
|
||||
# CONFIG_BLK_DEV_NVME is not set
|
||||
CONFIG_NVME_CORE=y
|
||||
CONFIG_BLK_DEV_NVME=y
|
||||
# CONFIG_NVME_MULTIPATH is not set
|
||||
# CONFIG_NVME_FC is not set
|
||||
# CONFIG_NVME_TCP is not set
|
||||
# CONFIG_NVME_TARGET is not set
|
||||
# end of NVME Support
|
||||
|
||||
@@ -1216,9 +1243,9 @@ CONFIG_VIRTIO_BLK=y
|
||||
# CONFIG_ENCLOSURE_SERVICES is not set
|
||||
# CONFIG_HP_ILO is not set
|
||||
# CONFIG_SRAM is not set
|
||||
# CONFIG_DW_XDATA_PCIE is not set
|
||||
# CONFIG_PCI_ENDPOINT_TEST is not set
|
||||
# CONFIG_XILINX_SDFEC is not set
|
||||
# CONFIG_PVPANIC is not set
|
||||
# CONFIG_C2PORT is not set
|
||||
|
||||
#
|
||||
@@ -1232,6 +1259,7 @@ CONFIG_VIRTIO_BLK=y
|
||||
#
|
||||
# Texas Instruments shared transport line discipline
|
||||
#
|
||||
# CONFIG_TI_ST is not set
|
||||
# end of Texas Instruments shared transport line discipline
|
||||
|
||||
#
|
||||
@@ -1248,11 +1276,9 @@ CONFIG_VIRTIO_BLK=y
|
||||
# CONFIG_MISC_RTSX_PCI is not set
|
||||
# CONFIG_HABANA_AI is not set
|
||||
# CONFIG_UACCE is not set
|
||||
# CONFIG_PVPANIC is not set
|
||||
# end of Misc devices
|
||||
|
||||
CONFIG_HAVE_IDE=y
|
||||
# CONFIG_IDE is not set
|
||||
|
||||
#
|
||||
# SCSI device support
|
||||
#
|
||||
@@ -1295,13 +1321,6 @@ CONFIG_VETH=y
|
||||
CONFIG_VIRTIO_NET=y
|
||||
# CONFIG_NLMON is not set
|
||||
# CONFIG_ARCNET is not set
|
||||
|
||||
#
|
||||
# Distributed Switch Architecture drivers
|
||||
#
|
||||
# CONFIG_NET_DSA_MV88E6XXX_PTP is not set
|
||||
# end of Distributed Switch Architecture drivers
|
||||
|
||||
# CONFIG_ETHERNET is not set
|
||||
# CONFIG_FDDI is not set
|
||||
# CONFIG_HIPPI is not set
|
||||
@@ -1322,8 +1341,16 @@ CONFIG_VIRTIO_NET=y
|
||||
#
|
||||
# CONFIG_WLAN is not set
|
||||
# CONFIG_WAN is not set
|
||||
|
||||
#
|
||||
# Wireless WAN
|
||||
#
|
||||
# CONFIG_WWAN is not set
|
||||
# end of Wireless WAN
|
||||
|
||||
# CONFIG_VMXNET3 is not set
|
||||
# CONFIG_FUJITSU_ES is not set
|
||||
# CONFIG_HYPERV_NET is not set
|
||||
# CONFIG_NETDEVSIM is not set
|
||||
CONFIG_NET_FAILOVER=y
|
||||
# CONFIG_ISDN is not set
|
||||
@@ -1354,6 +1381,9 @@ CONFIG_INPUT_EVDEV=y
|
||||
CONFIG_INPUT_KEYBOARD=y
|
||||
# CONFIG_KEYBOARD_ATKBD is not set
|
||||
# CONFIG_KEYBOARD_LKKBD is not set
|
||||
# CONFIG_KEYBOARD_GPIO is not set
|
||||
# CONFIG_KEYBOARD_GPIO_POLLED is not set
|
||||
# CONFIG_KEYBOARD_MATRIX is not set
|
||||
# CONFIG_KEYBOARD_NEWTON is not set
|
||||
# CONFIG_KEYBOARD_OPENCORES is not set
|
||||
# CONFIG_KEYBOARD_SAMSUNG is not set
|
||||
@@ -1368,8 +1398,12 @@ CONFIG_INPUT_MISC=y
|
||||
# CONFIG_INPUT_AD714X is not set
|
||||
# CONFIG_INPUT_E3X0_BUTTON is not set
|
||||
# CONFIG_INPUT_PCSPKR is not set
|
||||
# CONFIG_INPUT_GPIO_BEEPER is not set
|
||||
# CONFIG_INPUT_GPIO_DECODER is not set
|
||||
# CONFIG_INPUT_GPIO_VIBRA is not set
|
||||
# CONFIG_INPUT_ATLAS_BTNS is not set
|
||||
CONFIG_INPUT_UINPUT=y
|
||||
# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
|
||||
# CONFIG_INPUT_ADXL34X is not set
|
||||
# CONFIG_INPUT_CMA3000 is not set
|
||||
# CONFIG_RMI4_CORE is not set
|
||||
@@ -1440,11 +1474,11 @@ CONFIG_SERIAL_ARC_NR_PORTS=1
|
||||
# CONFIG_SERIAL_SPRD is not set
|
||||
# end of Serial drivers
|
||||
|
||||
CONFIG_SERIAL_MCTRL_GPIO=y
|
||||
# CONFIG_SERIAL_NONSTANDARD is not set
|
||||
# CONFIG_N_GSM is not set
|
||||
# CONFIG_NOZOMI is not set
|
||||
# CONFIG_NULL_TTY is not set
|
||||
# CONFIG_TRACE_SINK is not set
|
||||
CONFIG_HVC_DRIVER=y
|
||||
CONFIG_SERIAL_DEV_BUS=y
|
||||
CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
|
||||
@@ -1462,10 +1496,7 @@ CONFIG_HW_RANDOM_VIRTIO=y
|
||||
# CONFIG_APPLICOM is not set
|
||||
# CONFIG_MWAVE is not set
|
||||
CONFIG_DEVMEM=y
|
||||
# CONFIG_DEVKMEM is not set
|
||||
CONFIG_NVRAM=y
|
||||
CONFIG_RAW_DRIVER=y
|
||||
CONFIG_MAX_RAW_DEVS=256
|
||||
CONFIG_DEVPORT=y
|
||||
# CONFIG_HPET is not set
|
||||
CONFIG_HANGCHECK_TIMER=y
|
||||
@@ -1515,7 +1546,60 @@ CONFIG_PTP_1588_CLOCK_KVM=y
|
||||
# end of PTP clock support
|
||||
|
||||
# CONFIG_PINCTRL is not set
|
||||
# CONFIG_GPIOLIB is not set
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIOLIB_FASTPATH_LIMIT=512
|
||||
CONFIG_GPIO_ACPI=y
|
||||
CONFIG_GPIOLIB_IRQCHIP=y
|
||||
# CONFIG_DEBUG_GPIO is not set
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
CONFIG_GPIO_CDEV=y
|
||||
CONFIG_GPIO_CDEV_V1=y
|
||||
|
||||
#
|
||||
# Memory mapped GPIO drivers
|
||||
#
|
||||
# CONFIG_GPIO_AMDPT is not set
|
||||
# CONFIG_GPIO_DWAPB is not set
|
||||
# CONFIG_GPIO_EXAR is not set
|
||||
# CONFIG_GPIO_GENERIC_PLATFORM is not set
|
||||
# CONFIG_GPIO_MB86S7X is not set
|
||||
# CONFIG_GPIO_VX855 is not set
|
||||
# CONFIG_GPIO_AMD_FCH is not set
|
||||
# end of Memory mapped GPIO drivers
|
||||
|
||||
#
|
||||
# Port-mapped I/O GPIO drivers
|
||||
#
|
||||
# CONFIG_GPIO_F7188X is not set
|
||||
# CONFIG_GPIO_IT87 is not set
|
||||
# CONFIG_GPIO_SCH311X is not set
|
||||
# CONFIG_GPIO_WINBOND is not set
|
||||
# CONFIG_GPIO_WS16C48 is not set
|
||||
# end of Port-mapped I/O GPIO drivers
|
||||
|
||||
#
|
||||
# MFD GPIO expanders
|
||||
#
|
||||
# end of MFD GPIO expanders
|
||||
|
||||
#
|
||||
# PCI GPIO expanders
|
||||
#
|
||||
# CONFIG_GPIO_AMD8111 is not set
|
||||
# CONFIG_GPIO_BT8XX is not set
|
||||
# CONFIG_GPIO_ML_IOH is not set
|
||||
CONFIG_GPIO_PCI_IDIO_16=y
|
||||
# CONFIG_GPIO_PCIE_IDIO_24 is not set
|
||||
# CONFIG_GPIO_RDC321X is not set
|
||||
# end of PCI GPIO expanders
|
||||
|
||||
#
|
||||
# Virtual GPIO drivers
|
||||
#
|
||||
# CONFIG_GPIO_AGGREGATOR is not set
|
||||
# CONFIG_GPIO_MOCKUP is not set
|
||||
# end of Virtual GPIO drivers
|
||||
|
||||
# CONFIG_W1 is not set
|
||||
# CONFIG_POWER_RESET is not set
|
||||
# CONFIG_POWER_SUPPLY is not set
|
||||
@@ -1549,6 +1633,7 @@ CONFIG_X86_THERMAL_VECTOR=y
|
||||
# end of ACPI INT340X thermal drivers
|
||||
|
||||
# CONFIG_INTEL_PCH_THERMAL is not set
|
||||
# CONFIG_INTEL_TCC_COOLING is not set
|
||||
# end of Intel thermal drivers
|
||||
|
||||
CONFIG_WATCHDOG=y
|
||||
@@ -1557,6 +1642,7 @@ CONFIG_WATCHDOG_CORE=y
|
||||
CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y
|
||||
CONFIG_WATCHDOG_OPEN_TIMEOUT=0
|
||||
# CONFIG_WATCHDOG_SYSFS is not set
|
||||
# CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT is not set
|
||||
|
||||
#
|
||||
# Watchdog Pretimeout Governors
|
||||
@@ -1606,6 +1692,7 @@ CONFIG_WATCHDOG_OPEN_TIMEOUT=0
|
||||
# CONFIG_SBC_EPX_C3_WATCHDOG is not set
|
||||
# CONFIG_NI903X_WDT is not set
|
||||
# CONFIG_NIC7018_WDT is not set
|
||||
# CONFIG_MEN_A21_WDT is not set
|
||||
CONFIG_VIRTIO_WDT=y
|
||||
|
||||
#
|
||||
@@ -1634,7 +1721,6 @@ CONFIG_BCMA_POSSIBLE=y
|
||||
# CONFIG_MFD_MT6397 is not set
|
||||
# CONFIG_MFD_RDC321X is not set
|
||||
# CONFIG_MFD_SM501 is not set
|
||||
# CONFIG_ABX500_CORE is not set
|
||||
# CONFIG_MFD_SYSCON is not set
|
||||
# CONFIG_MFD_TI_AM335X_TSCADC is not set
|
||||
# CONFIG_MFD_TQMX86 is not set
|
||||
@@ -1713,6 +1799,7 @@ CONFIG_FB=y
|
||||
# CONFIG_FB_VIRTUAL is not set
|
||||
# CONFIG_FB_METRONOME is not set
|
||||
# CONFIG_FB_MB862XX is not set
|
||||
# CONFIG_FB_HYPERV is not set
|
||||
# CONFIG_FB_SIMPLE is not set
|
||||
# CONFIG_FB_SM712 is not set
|
||||
# end of Frame buffer Devices
|
||||
@@ -1723,9 +1810,11 @@ CONFIG_FB=y
|
||||
CONFIG_LCD_CLASS_DEVICE=y
|
||||
# CONFIG_LCD_PLATFORM is not set
|
||||
CONFIG_BACKLIGHT_CLASS_DEVICE=y
|
||||
# CONFIG_BACKLIGHT_KTD253 is not set
|
||||
# CONFIG_BACKLIGHT_APPLE is not set
|
||||
# CONFIG_BACKLIGHT_QCOM_WLED is not set
|
||||
# CONFIG_BACKLIGHT_SAHARA is not set
|
||||
# CONFIG_BACKLIGHT_GPIO is not set
|
||||
# end of Backlight & LCD device support
|
||||
|
||||
#
|
||||
@@ -1806,16 +1895,17 @@ CONFIG_HID_REDRAGON=y
|
||||
# CONFIG_HID_PRIMAX is not set
|
||||
# CONFIG_HID_SAITEK is not set
|
||||
# CONFIG_HID_SAMSUNG is not set
|
||||
# CONFIG_HID_SEMITEK is not set
|
||||
# CONFIG_HID_SPEEDLINK is not set
|
||||
# CONFIG_HID_STEAM is not set
|
||||
# CONFIG_HID_STEELSERIES is not set
|
||||
# CONFIG_HID_SUNPLUS is not set
|
||||
# CONFIG_HID_RMI is not set
|
||||
# CONFIG_HID_GREENASIA is not set
|
||||
# CONFIG_HID_HYPERV_MOUSE is not set
|
||||
# CONFIG_HID_SMARTJOYPLUS is not set
|
||||
# CONFIG_HID_TIVO is not set
|
||||
# CONFIG_HID_TOPSEED is not set
|
||||
# CONFIG_HID_THRUSTMASTER is not set
|
||||
# CONFIG_HID_UDRAW_PS3 is not set
|
||||
# CONFIG_HID_XINMO is not set
|
||||
# CONFIG_HID_ZEROPLUS is not set
|
||||
@@ -1864,7 +1954,6 @@ CONFIG_DMA_ACPI=y
|
||||
# CONFIG_INTEL_IDXD is not set
|
||||
# CONFIG_INTEL_IOATDMA is not set
|
||||
# CONFIG_PLX_DMA is not set
|
||||
# CONFIG_XILINX_ZYNQMP_DPDMA is not set
|
||||
# CONFIG_QCOM_HIDMA_MGMT is not set
|
||||
# CONFIG_QCOM_HIDMA is not set
|
||||
CONFIG_DW_DMAC_CORE=y
|
||||
@@ -1902,6 +1991,7 @@ CONFIG_UIO_DMEM_GENIRQ=y
|
||||
# CONFIG_UIO_NETX is not set
|
||||
# CONFIG_UIO_PRUSS is not set
|
||||
# CONFIG_UIO_MF624 is not set
|
||||
# CONFIG_UIO_HV_GENERIC is not set
|
||||
CONFIG_VFIO_IOMMU_TYPE1=y
|
||||
CONFIG_VFIO_VIRQFD=y
|
||||
CONFIG_VFIO=y
|
||||
@@ -1915,6 +2005,7 @@ CONFIG_VFIO_PCI_INTX=y
|
||||
CONFIG_IRQ_BYPASS_MANAGER=y
|
||||
# CONFIG_VIRT_DRIVERS is not set
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_ARCH_HAS_RESTRICTED_VIRTIO_MEMORY_ACCESS=y
|
||||
CONFIG_VIRTIO_PCI_LIB=y
|
||||
CONFIG_VIRTIO_MENU=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
@@ -1931,10 +2022,14 @@ CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
|
||||
#
|
||||
# Microsoft Hyper-V guest support
|
||||
#
|
||||
# CONFIG_HYPERV is not set
|
||||
CONFIG_HYPERV=y
|
||||
CONFIG_HYPERV_TIMER=y
|
||||
# CONFIG_HYPERV_UTILS is not set
|
||||
# CONFIG_HYPERV_BALLOON is not set
|
||||
# end of Microsoft Hyper-V guest support
|
||||
|
||||
# CONFIG_GREYBUS is not set
|
||||
# CONFIG_COMEDI is not set
|
||||
# CONFIG_STAGING is not set
|
||||
# CONFIG_X86_PLATFORM_DEVICES is not set
|
||||
CONFIG_PMC_ATOM=y
|
||||
@@ -1942,9 +2037,16 @@ CONFIG_PMC_ATOM=y
|
||||
# CONFIG_MELLANOX_PLATFORM is not set
|
||||
# CONFIG_SURFACE_PLATFORMS is not set
|
||||
CONFIG_HAVE_CLK=y
|
||||
CONFIG_CLKDEV_LOOKUP=y
|
||||
CONFIG_HAVE_CLK_PREPARE=y
|
||||
CONFIG_COMMON_CLK=y
|
||||
|
||||
#
|
||||
# Clock driver for ARM Reference designs
|
||||
#
|
||||
# CONFIG_ICST is not set
|
||||
# CONFIG_CLK_SP810 is not set
|
||||
# end of Clock driver for ARM Reference designs
|
||||
|
||||
# CONFIG_XILINX_VCU is not set
|
||||
# CONFIG_HWSPINLOCK is not set
|
||||
|
||||
@@ -1974,10 +2076,8 @@ CONFIG_IOMMU_DMA=y
|
||||
# CONFIG_AMD_IOMMU is not set
|
||||
# CONFIG_INTEL_IOMMU is not set
|
||||
# CONFIG_IRQ_REMAP is not set
|
||||
CONFIG_HYPERV_IOMMU=y
|
||||
CONFIG_VIRTIO_IOMMU=y
|
||||
CONFIG_VIRTIO_IOMMU_TOPOLOGY_HELPERS=y
|
||||
CONFIG_VIRTIO_IOMMU_TOPOLOGY=y
|
||||
CONFIG_ACPI_VIOT=y
|
||||
|
||||
#
|
||||
# Remoteproc drivers
|
||||
@@ -2056,6 +2156,7 @@ CONFIG_ACPI_VIOT=y
|
||||
# PHY Subsystem
|
||||
#
|
||||
# CONFIG_GENERIC_PHY is not set
|
||||
# CONFIG_PHY_CAN_TRANSCEIVER is not set
|
||||
# CONFIG_BCM_KONA_USB2_PHY is not set
|
||||
# CONFIG_PHY_PXA_28NM_HSIC is not set
|
||||
# CONFIG_PHY_PXA_28NM_USB2 is not set
|
||||
@@ -2165,6 +2266,8 @@ CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y
|
||||
#
|
||||
# Caches
|
||||
#
|
||||
CONFIG_NETFS_SUPPORT=y
|
||||
# CONFIG_NETFS_STATS is not set
|
||||
CONFIG_FSCACHE=y
|
||||
# CONFIG_FSCACHE_STATS is not set
|
||||
# CONFIG_FSCACHE_HISTOGRAM is not set
|
||||
@@ -2212,6 +2315,8 @@ CONFIG_TMPFS_XATTR=y
|
||||
# CONFIG_TMPFS_INODE64 is not set
|
||||
CONFIG_HUGETLBFS=y
|
||||
CONFIG_HUGETLB_PAGE=y
|
||||
CONFIG_HUGETLB_PAGE_FREE_VMEMMAP=y
|
||||
# CONFIG_HUGETLB_PAGE_FREE_VMEMMAP_DEFAULT_ON is not set
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
|
||||
CONFIG_CONFIGFS_FS=y
|
||||
@@ -2350,6 +2455,7 @@ CONFIG_CRYPTO_SIMD=y
|
||||
# CONFIG_CRYPTO_RSA is not set
|
||||
# CONFIG_CRYPTO_DH is not set
|
||||
# CONFIG_CRYPTO_ECDH is not set
|
||||
# CONFIG_CRYPTO_ECDSA is not set
|
||||
# CONFIG_CRYPTO_ECRDSA is not set
|
||||
# CONFIG_CRYPTO_SM2 is not set
|
||||
# CONFIG_CRYPTO_CURVE25519 is not set
|
||||
@@ -2507,6 +2613,8 @@ CONFIG_SYSTEM_BLACKLIST_KEYRING=y
|
||||
CONFIG_SYSTEM_BLACKLIST_HASH_LIST=""
|
||||
# end of Certificates for signature checking
|
||||
|
||||
CONFIG_BINARY_PRINTF=y
|
||||
|
||||
#
|
||||
# Library routines
|
||||
#
|
||||
@@ -2598,7 +2706,6 @@ CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y
|
||||
CONFIG_ARCH_HAS_COPY_MC=y
|
||||
CONFIG_ARCH_STACKWALK=y
|
||||
CONFIG_SBITMAP=y
|
||||
# CONFIG_STRING_SELFTEST is not set
|
||||
# end of Library routines
|
||||
|
||||
#
|
||||
@@ -2610,6 +2717,7 @@ CONFIG_SBITMAP=y
|
||||
#
|
||||
CONFIG_PRINTK_TIME=y
|
||||
# CONFIG_PRINTK_CALLER is not set
|
||||
# CONFIG_STACKTRACE_BUILD_ID is not set
|
||||
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
|
||||
CONFIG_CONSOLE_LOGLEVEL_QUIET=4
|
||||
CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
|
||||
@@ -2630,9 +2738,10 @@ CONFIG_STRIP_ASM_SYMS=y
|
||||
# CONFIG_HEADERS_INSTALL is not set
|
||||
CONFIG_DEBUG_SECTION_MISMATCH=y
|
||||
CONFIG_SECTION_MISMATCH_WARN_ONLY=y
|
||||
# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set
|
||||
# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set
|
||||
CONFIG_FRAME_POINTER=y
|
||||
CONFIG_STACK_VALIDATION=y
|
||||
# CONFIG_VMLINUX_MAP is not set
|
||||
# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
|
||||
# end of Compile-time checks and compiler options
|
||||
|
||||
@@ -2830,19 +2939,21 @@ CONFIG_CC_HAS_SANCOV_TRACE_PC=y
|
||||
# CONFIG_KCOV is not set
|
||||
CONFIG_RUNTIME_TESTING_MENU=y
|
||||
# CONFIG_LKDTM is not set
|
||||
# CONFIG_TEST_LIST_SORT is not set
|
||||
# CONFIG_TEST_MIN_HEAP is not set
|
||||
# CONFIG_TEST_SORT is not set
|
||||
# CONFIG_TEST_DIV64 is not set
|
||||
# CONFIG_BACKTRACE_SELF_TEST is not set
|
||||
# CONFIG_RBTREE_TEST is not set
|
||||
# CONFIG_REED_SOLOMON_TEST is not set
|
||||
# CONFIG_INTERVAL_TREE_TEST is not set
|
||||
# CONFIG_ATOMIC64_SELFTEST is not set
|
||||
# CONFIG_TEST_HEXDUMP is not set
|
||||
# CONFIG_STRING_SELFTEST is not set
|
||||
# CONFIG_TEST_STRING_HELPERS is not set
|
||||
# CONFIG_TEST_STRSCPY is not set
|
||||
# CONFIG_TEST_KSTRTOX is not set
|
||||
# CONFIG_TEST_PRINTF is not set
|
||||
# CONFIG_TEST_SCANF is not set
|
||||
# CONFIG_TEST_BITMAP is not set
|
||||
# CONFIG_TEST_UUID is not set
|
||||
# CONFIG_TEST_XARRAY is not set
|
||||
@@ -2859,6 +2970,9 @@ CONFIG_RUNTIME_TESTING_MENU=y
|
||||
# CONFIG_TEST_MEMINIT is not set
|
||||
# CONFIG_TEST_FREE_PAGES is not set
|
||||
# CONFIG_TEST_FPU is not set
|
||||
# CONFIG_TEST_CLOCKSOURCE_WATCHDOG is not set
|
||||
CONFIG_ARCH_USE_MEMTEST=y
|
||||
# CONFIG_MEMTEST is not set
|
||||
# CONFIG_HYPERV_TESTING is not set
|
||||
# end of Kernel Testing and Coverage
|
||||
# end of Kernel hacking
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Name: cloud-hypervisor
|
||||
Summary: Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM.
|
||||
Version: 15.0
|
||||
Version: 18.0
|
||||
Release: 0%{?dist}
|
||||
License: ASL 2.0 or BSD-3-clause
|
||||
Group: Applications/System
|
||||
|
||||
@@ -178,16 +178,17 @@ cmd_help() {
|
||||
echo ""
|
||||
echo " tests [--unit|--cargo|--all] [--libc musl|gnu] [-- [<cargo test args>]]"
|
||||
echo " Run the Cloud Hypervisor tests."
|
||||
echo " --unit Run the unit tests."
|
||||
echo " --cargo Run the cargo tests."
|
||||
echo " --integration Run the integration tests."
|
||||
echo " --integration-sgx Run the SGX integration tests."
|
||||
echo " --integration-vfio Run the VFIO integration tests."
|
||||
echo " --integration-windows Run the Windows guest integration tests."
|
||||
echo " --libc Select the C library Cloud Hypervisor will be built against. Default is gnu"
|
||||
echo " --volumes Hash separated volumes to be exported. Example --volumes /mnt:/mnt#/myvol:/myvol"
|
||||
echo " --hypervisor Underlying hypervisor. Options kvm, mshv"
|
||||
echo " --all Run all tests."
|
||||
echo " --unit Run the unit tests."
|
||||
echo " --cargo Run the cargo tests."
|
||||
echo " --integration Run the integration tests."
|
||||
echo " --integration-sgx Run the SGX integration tests."
|
||||
echo " --integration-vfio Run the VFIO integration tests."
|
||||
echo " --integration-windows Run the Windows guest integration tests."
|
||||
echo " --integration-live-migration Run the live-migration integration tests."
|
||||
echo " --libc Select the C library Cloud Hypervisor will be built against. Default is gnu"
|
||||
echo " --volumes Hash separated volumes to be exported. Example --volumes /mnt:/mnt#/myvol:/myvol"
|
||||
echo " --hypervisor Underlying hypervisor. Options kvm, mshv"
|
||||
echo " --all Run all tests."
|
||||
echo ""
|
||||
echo " build-container [--type]"
|
||||
echo " Build the Cloud Hypervisor container."
|
||||
@@ -198,6 +199,7 @@ cmd_help() {
|
||||
echo ""
|
||||
echo " shell"
|
||||
echo " Run the development container into an interactive, privileged BASH shell."
|
||||
echo " --volumes Hash separated volumes to be exported. Example --volumes /mnt:/mnt#/myvol:/myvol"
|
||||
echo ""
|
||||
echo " help"
|
||||
echo " Display this help message."
|
||||
@@ -238,9 +240,7 @@ cmd_build() {
|
||||
done
|
||||
|
||||
ensure_build_dir
|
||||
if [ $(uname -m) = "x86_64" ]; then
|
||||
ensure_latest_ctr
|
||||
fi
|
||||
ensure_latest_ctr
|
||||
|
||||
process_volumes_args
|
||||
if [[ "$hypervisor" != "kvm" ]]; then
|
||||
@@ -279,9 +279,7 @@ cmd_clean() {
|
||||
cargo_args=("$@")
|
||||
|
||||
ensure_build_dir
|
||||
if [ $(uname -m) = "x86_64" ]; then
|
||||
ensure_latest_ctr
|
||||
fi
|
||||
ensure_latest_ctr
|
||||
|
||||
$DOCKER_RUNTIME run \
|
||||
--user "$(id -u):$(id -g)" \
|
||||
@@ -301,19 +299,21 @@ cmd_tests() {
|
||||
integration_sgx=false
|
||||
integration_vfio=false
|
||||
integration_windows=false
|
||||
integration_live_migration=false
|
||||
libc="gnu"
|
||||
arg_vols=""
|
||||
hypervisor="kvm"
|
||||
exported_device="/dev/kvm"
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
"-h"|"--help") { cmd_help; exit 1; } ;;
|
||||
"--unit") { unit=true; } ;;
|
||||
"--cargo") { cargo=true; } ;;
|
||||
"--integration") { integration=true; } ;;
|
||||
"--integration-sgx") { integration_sgx=true; } ;;
|
||||
"--integration-vfio") { integration_vfio=true; } ;;
|
||||
"--integration-windows") { integration_windows=true; } ;;
|
||||
"-h"|"--help") { cmd_help; exit 1; } ;;
|
||||
"--unit") { unit=true; } ;;
|
||||
"--cargo") { cargo=true; } ;;
|
||||
"--integration") { integration=true; } ;;
|
||||
"--integration-sgx") { integration_sgx=true; } ;;
|
||||
"--integration-vfio") { integration_vfio=true; } ;;
|
||||
"--integration-windows") { integration_windows=true; } ;;
|
||||
"--integration-live-migration") { integration_live_migration=true; } ;;
|
||||
"--libc")
|
||||
shift
|
||||
[[ "$1" =~ ^(musl|gnu)$ ]] || \
|
||||
@@ -345,9 +345,7 @@ cmd_tests() {
|
||||
set -- "$@" '--hypervisor' $hypervisor
|
||||
|
||||
ensure_build_dir
|
||||
if [ $(uname -m) = "x86_64" ]; then
|
||||
ensure_latest_ctr
|
||||
fi
|
||||
ensure_latest_ctr
|
||||
|
||||
process_volumes_args
|
||||
target="$(uname -m)-unknown-linux-${libc}"
|
||||
@@ -459,6 +457,25 @@ cmd_tests() {
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_windows.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
|
||||
if [ "$integration_live_migration" = true ] ; then
|
||||
say "Running 'live migration' integration tests for $target..."
|
||||
$DOCKER_RUNTIME run \
|
||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||
--rm \
|
||||
--privileged \
|
||||
--security-opt seccomp=unconfined \
|
||||
--ipc=host \
|
||||
--net="$CTR_CLH_NET" \
|
||||
--mount type=tmpfs,destination=/tmp \
|
||||
--volume /dev:/dev \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_live_migration.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
fix_dir_perms $?
|
||||
}
|
||||
|
||||
@@ -478,9 +495,7 @@ cmd_build-container() {
|
||||
done
|
||||
|
||||
ensure_build_dir
|
||||
if [ $(uname -m) = "x86_64" ]; then
|
||||
ensure_latest_ctr
|
||||
fi
|
||||
ensure_latest_ctr
|
||||
|
||||
BUILD_DIR=/tmp/cloud-hypervisor/container/
|
||||
|
||||
@@ -499,10 +514,22 @@ cmd_build-container() {
|
||||
}
|
||||
|
||||
cmd_shell() {
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
"-h"|"--help") { cmd_help; exit 1; } ;;
|
||||
"--volumes")
|
||||
shift
|
||||
arg_vols="$1"
|
||||
;;
|
||||
"--") { shift; break; } ;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
ensure_build_dir
|
||||
if [ $(uname -m) = "x86_64" ]; then
|
||||
ensure_latest_ctr
|
||||
fi
|
||||
ensure_latest_ctr
|
||||
process_volumes_args
|
||||
say_warn "Starting a privileged shell prompt as root ..."
|
||||
say_warn "WARNING: Your $CLH_ROOT_DIR folder will be bind-mounted in the container under $CTR_CLH_ROOT_DIR"
|
||||
$DOCKER_RUNTIME run \
|
||||
|
||||
@@ -13,9 +13,9 @@ EDK2_BUILD_DIR="$WORKLOADS_DIR/edk2_build"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
|
||||
build_edk2() {
|
||||
EDK2_REPO="https://github.com/cloud-hypervisor/edk2.git"
|
||||
EDK2_REPO="https://github.com/tianocore/edk2.git"
|
||||
EDK2_DIR="edk2"
|
||||
EDK2_BRANCH="ch-aarch64"
|
||||
EDK2_BRANCH="master"
|
||||
EDK2_PLAT_REPO="https://github.com/tianocore/edk2-platforms.git"
|
||||
EDK2_PLAT_DIR="edk2-platforms"
|
||||
ACPICA_REPO="https://github.com/acpica/acpica.git"
|
||||
@@ -79,7 +79,7 @@ update_workloads() {
|
||||
cp scripts/sha1sums-aarch64 $WORKLOADS_DIR
|
||||
|
||||
BIONIC_OS_IMAGE_DOWNLOAD_NAME="bionic-server-cloudimg-arm64.img"
|
||||
BIONIC_OS_IMAGE_DOWNLOAD_URL="https://cloudhypervisorstorage.blob.core.windows.net/images/$BIONIC_OS_IMAGE_DOWNLOAD_NAME"
|
||||
BIONIC_OS_IMAGE_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$BIONIC_OS_IMAGE_DOWNLOAD_NAME"
|
||||
BIONIC_OS_DOWNLOAD_IMAGE="$WORKLOADS_DIR/$BIONIC_OS_IMAGE_DOWNLOAD_NAME"
|
||||
if [ ! -f "$BIONIC_OS_DOWNLOAD_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
@@ -106,7 +106,7 @@ update_workloads() {
|
||||
fi
|
||||
|
||||
FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-arm64-custom.raw"
|
||||
FOCAL_OS_RAW_IMAGE_DOWNLOAD_URL="https://cloudhypervisorstorage.blob.core.windows.net/images/$FOCAL_OS_RAW_IMAGE_NAME"
|
||||
FOCAL_OS_RAW_IMAGE_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_RAW_IMAGE_NAME"
|
||||
FOCAL_OS_RAW_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_NAME"
|
||||
if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
@@ -117,7 +117,7 @@ update_workloads() {
|
||||
# Convert the raw image to qcow2 image to remove compressed blocks from the disk. Therefore letting the
|
||||
# qcow2 format image can be directly used in the integration test.
|
||||
FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME="focal-server-cloudimg-arm64-custom.qcow2"
|
||||
FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_DOWNLOAD_URL="https://cloudhypervisorstorage.blob.core.windows.net/images/$FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
|
||||
FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
|
||||
FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
|
||||
if [ ! -f "$FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
@@ -171,7 +171,7 @@ update_workloads() {
|
||||
}
|
||||
|
||||
SRCDIR=$PWD
|
||||
LINUX_CUSTOM_BRANCH="ch-5.12"
|
||||
LINUX_CUSTOM_BRANCH="ch-5.14"
|
||||
|
||||
# Check whether the local HEAD commit same as the remote HEAD or not. Remove the folder if they are different.
|
||||
if [ -d "$LINUX_CUSTOM_DIR" ]; then
|
||||
@@ -249,14 +249,12 @@ process_common_args "$@"
|
||||
|
||||
# aarch64 not supported for MSHV
|
||||
if [[ "$hypervisor" = "mshv" ]]; then
|
||||
echo "Aarch64 is not supported in Microsoft Hypervisor"
|
||||
echo "AArch64 is not supported in Microsoft Hypervisor"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
features_build_fdt="--no-default-features --features $hypervisor"
|
||||
features_build_acpi="--no-default-features --features $hypervisor,acpi"
|
||||
features_test_fdt="--no-default-features --features integration_tests,$hypervisor"
|
||||
features_test_acpi="--no-default-features --features integration_tests,$hypervisor,acpi"
|
||||
features_build=""
|
||||
features_test="--features integration_tests"
|
||||
|
||||
# lock the workloads folder to avoid parallel updating by different containers
|
||||
(
|
||||
@@ -283,7 +281,7 @@ fi
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
# Test without ACPI
|
||||
cargo build --all --release $features_build_fdt --target $BUILD_TARGET
|
||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||
strip target/$BUILD_TARGET/release/vhost_user_net
|
||||
strip target/$BUILD_TARGET/release/ch-remote
|
||||
@@ -301,20 +299,33 @@ ovs-vsctl init
|
||||
ovs-vsctl set Open_vSwitch . other_config:dpdk-init=true
|
||||
service openvswitch-switch restart
|
||||
|
||||
time cargo test $features_test_fdt "tests::parallel::$test_filter"
|
||||
# Run all direct kernel boot (Device Tree) test cases in mod `parallel`
|
||||
time cargo test $features_test "tests::parallel::$test_filter"
|
||||
RES=$?
|
||||
echo "Integration test on FDT finished with result $RES."
|
||||
|
||||
# Run some tests in sequence since the result could be affected by other tests
|
||||
# running in parallel.
|
||||
if [ $RES -eq 0 ]; then
|
||||
# Test with EDK2 + ACPI
|
||||
cargo build --all --release $features_build_acpi --target $BUILD_TARGET
|
||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||
strip target/$BUILD_TARGET/release/vhost_user_net
|
||||
strip target/$BUILD_TARGET/release/ch-remote
|
||||
|
||||
time cargo test $features_test_acpi "tests::parallel::test_edk2_acpi_launch"
|
||||
time cargo test $features_test "tests::sequential::$test_filter" -- --test-threads=1
|
||||
RES=$?
|
||||
echo "Integration test on UEFI & ACPI finished with result $RES."
|
||||
else
|
||||
exit $RES
|
||||
fi
|
||||
|
||||
# Run all ACPI test cases
|
||||
if [ $RES -eq 0 ]; then
|
||||
time cargo test $features_test "tests::aarch64_acpi::$test_filter"
|
||||
RES=$?
|
||||
else
|
||||
exit $RES
|
||||
fi
|
||||
|
||||
# Run all test cases related to live migration
|
||||
if [ $RES -eq 0 ]; then
|
||||
time cargo test $features_test "tests::live_migration::$test_filter" -- --test-threads=1
|
||||
RES=$?
|
||||
else
|
||||
exit $RES
|
||||
fi
|
||||
|
||||
exit $RES
|
||||
|
||||
87
scripts/run_integration_tests_live_migration.sh
Executable file
87
scripts/run_integration_tests_live_migration.sh
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
|
||||
export BUILD_TARGET=${BUILD_TARGET-x86_64-unknown-linux-gnu}
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
|
||||
process_common_args "$@"
|
||||
|
||||
# For now these values are deafult for kvm
|
||||
features_build=""
|
||||
features_test="--features integration_tests"
|
||||
|
||||
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||
|
||||
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
|
||||
FOCAL_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_IMAGE_NAME"
|
||||
FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
|
||||
if [ ! -f "$FOCAL_OS_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $FOCAL_OS_IMAGE_URL || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.raw"
|
||||
FOCAL_OS_RAW_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_NAME"
|
||||
if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time qemu-img convert -p -f qcow2 -O raw $FOCAL_OS_IMAGE_NAME $FOCAL_OS_RAW_IMAGE_NAME || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
pushd $WORKLOADS_DIR
|
||||
grep focal sha1sums-x86_64 | sha1sum --check
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "sha1sum validation of images failed, remove invalid images to fix the issue."
|
||||
exit 1
|
||||
fi
|
||||
popd
|
||||
|
||||
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
||||
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
|
||||
|
||||
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
||||
|
||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||
SRCDIR=$PWD
|
||||
pushd $WORKLOADS_DIR
|
||||
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-5.14" $LINUX_CUSTOM_DIR
|
||||
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
|
||||
popd
|
||||
fi
|
||||
|
||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||
pushd $LINUX_CUSTOM_DIR
|
||||
time make bzImage -j `nproc`
|
||||
cp vmlinux $VMLINUX_IMAGE || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
if [ -d "$LINUX_CUSTOM_DIR" ]; then
|
||||
rm -rf $LINUX_CUSTOM_DIR
|
||||
fi
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||
strip target/$BUILD_TARGET/release/vhost_user_net
|
||||
strip target/$BUILD_TARGET/release/ch-remote
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
time cargo test $features_test "tests::live_migration::$test_filter" -- --test-threads=1
|
||||
RES=$?
|
||||
|
||||
exit $RES
|
||||
@@ -26,7 +26,7 @@ if [ ! -f "$FW" ]; then
|
||||
fi
|
||||
|
||||
BIONIC_OS_IMAGE_NAME="bionic-server-cloudimg-amd64.qcow2"
|
||||
BIONIC_OS_IMAGE_URL="https://cloudhypervisorstorage.blob.core.windows.net/images/$BIONIC_OS_IMAGE_NAME"
|
||||
BIONIC_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$BIONIC_OS_IMAGE_NAME"
|
||||
BIONIC_OS_IMAGE="$WORKLOADS_DIR/$BIONIC_OS_IMAGE_NAME"
|
||||
if [ ! -f "$BIONIC_OS_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
@@ -44,7 +44,7 @@ fi
|
||||
|
||||
|
||||
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
|
||||
FOCAL_OS_IMAGE_URL="https://cloudhypervisorstorage.blob.core.windows.net/images/$FOCAL_OS_IMAGE_NAME"
|
||||
FOCAL_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_IMAGE_NAME"
|
||||
FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
|
||||
if [ ! -f "$FOCAL_OS_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
@@ -102,7 +102,7 @@ LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||
SRCDIR=$PWD
|
||||
pushd $WORKLOADS_DIR
|
||||
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-5.12" $LINUX_CUSTOM_DIR
|
||||
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-5.14" $LINUX_CUSTOM_DIR
|
||||
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
|
||||
popd
|
||||
fi
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
extern crate clap;
|
||||
|
||||
use api_client::simple_api_command;
|
||||
use api_client::simple_api_command_with_fds;
|
||||
use api_client::Error as ApiClientError;
|
||||
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||
use option_parser::{ByteSized, ByteSizedParseError};
|
||||
@@ -26,6 +27,7 @@ enum Error {
|
||||
AddFsConfig(vmm::config::Error),
|
||||
AddPmemConfig(vmm::config::Error),
|
||||
AddNetConfig(vmm::config::Error),
|
||||
AddUserDeviceConfig(vmm::config::Error),
|
||||
AddVsockConfig(vmm::config::Error),
|
||||
Restore(vmm::config::Error),
|
||||
}
|
||||
@@ -44,6 +46,7 @@ impl fmt::Display for Error {
|
||||
AddFsConfig(e) => write!(f, "Error parsing filesystem syntax: {}", e),
|
||||
AddPmemConfig(e) => write!(f, "Error parsing persistent memory syntax: {}", e),
|
||||
AddNetConfig(e) => write!(f, "Error parsing network syntax: {}", e),
|
||||
AddUserDeviceConfig(e) => write!(f, "Error parsing user device syntax: {}", e),
|
||||
AddVsockConfig(e) => write!(f, "Error parsing vsock syntax: {}", e),
|
||||
Restore(e) => write!(f, "Error parsing restore syntax: {}", e),
|
||||
}
|
||||
@@ -129,6 +132,19 @@ fn add_device_api_command(socket: &mut UnixStream, config: &str) -> Result<(), E
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn add_user_device_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
let device_config =
|
||||
vmm::config::UserDeviceConfig::parse(config).map_err(Error::AddUserDeviceConfig)?;
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-user-device",
|
||||
Some(&serde_json::to_string(&device_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn remove_device_api_command(socket: &mut UnixStream, id: &str) -> Result<(), Error> {
|
||||
let remove_device_data = vmm::api::VmRemoveDeviceData { id: id.to_owned() };
|
||||
|
||||
@@ -178,13 +194,20 @@ fn add_pmem_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Err
|
||||
}
|
||||
|
||||
fn add_net_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
let net_config = vmm::config::NetConfig::parse(config).map_err(Error::AddNetConfig)?;
|
||||
let mut net_config = vmm::config::NetConfig::parse(config).map_err(Error::AddNetConfig)?;
|
||||
|
||||
simple_api_command(
|
||||
// NetConfig is modified on purpose here by taking the list of file
|
||||
// descriptors out. Keeping the list and send it to the server side
|
||||
// process would not make any sense since the file descriptor may be
|
||||
// represented with different values.
|
||||
let fds = net_config.fds.take().unwrap_or_default();
|
||||
|
||||
simple_api_command_with_fds(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-net",
|
||||
Some(&serde_json::to_string(&net_config).unwrap()),
|
||||
fds,
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
@@ -340,6 +363,14 @@ fn do_command(matches: &ArgMatches) -> Result<(), Error> {
|
||||
.value_of("net_config")
|
||||
.unwrap(),
|
||||
),
|
||||
Some("add-user-device") => add_user_device_api_command(
|
||||
&mut socket,
|
||||
matches
|
||||
.subcommand_matches("add-user-device")
|
||||
.unwrap()
|
||||
.value_of("device_config")
|
||||
.unwrap(),
|
||||
),
|
||||
Some("add-vsock") => add_vsock_api_command(
|
||||
&mut socket,
|
||||
matches
|
||||
@@ -443,6 +474,15 @@ fn main() {
|
||||
.help(vmm::config::NetConfig::SYNTAX),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("add-user-device")
|
||||
.about("Add userspace device")
|
||||
.arg(
|
||||
Arg::with_name("device_config")
|
||||
.index(1)
|
||||
.help(vmm::config::UserDeviceConfig::SYNTAX),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("add-vsock")
|
||||
.about("Add vsock device")
|
||||
|
||||
29
src/main.rs
29
src/main.rs
@@ -12,7 +12,7 @@ use clap::{App, Arg, ArgGroup, ArgMatches};
|
||||
use libc::EFD_NONBLOCK;
|
||||
use log::LevelFilter;
|
||||
use option_parser::OptionParser;
|
||||
use seccomp::SeccompAction;
|
||||
use seccompiler::SeccompAction;
|
||||
use signal_hook::{
|
||||
consts::SIGSYS,
|
||||
iterator::{exfiltrator::WithRawSiginfo, SignalsInfo},
|
||||
@@ -26,6 +26,7 @@ use std::thread;
|
||||
use thiserror::Error;
|
||||
use vmm::config;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::signal::block_signal;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
enum Error {
|
||||
@@ -150,7 +151,7 @@ fn create_app<'a, 'b>(
|
||||
topology=<threads_per_core>:<cores_per_die>:<dies_per_package>:<packages>,\
|
||||
kvm_hyperv=on|off,max_phys_bits=<maximum_number_of_physical_bits>",
|
||||
)
|
||||
.default_value(&default_vcpus)
|
||||
.default_value(default_vcpus)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
@@ -159,12 +160,12 @@ fn create_app<'a, 'b>(
|
||||
.help(
|
||||
"Memory parameters \
|
||||
\"size=<guest_memory_size>,mergeable=on|off,shared=on|off,\
|
||||
hugepages=on|off,hugepage_size=<hugepage_size>\
|
||||
hugepages=on|off,hugepage_size=<hugepage_size>,\
|
||||
hotplug_method=acpi|virtio-mem,\
|
||||
hotplug_size=<hotpluggable_memory_size>,\
|
||||
hotplugged_size=<hotplugged_memory_size>\"",
|
||||
)
|
||||
.default_value(&default_memory)
|
||||
.default_value(default_memory)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
@@ -174,7 +175,7 @@ fn create_app<'a, 'b>(
|
||||
"User defined memory zone parameters \
|
||||
\"size=<guest_memory_region_size>,file=<backing_file>,\
|
||||
shared=on|off,\
|
||||
hugepages=on|off,hugepage_size=<hugepage_size>\
|
||||
hugepages=on|off,hugepage_size=<hugepage_size>,\
|
||||
host_numa_node=<node_id>,\
|
||||
id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,\
|
||||
hotplugged_size=<hotplugged_memory_size>\"",
|
||||
@@ -229,7 +230,7 @@ fn create_app<'a, 'b>(
|
||||
.help(
|
||||
"Random number generator parameters \"src=<entropy_source_path>,iommu=on|off\"",
|
||||
)
|
||||
.default_value(&default_rng)
|
||||
.default_value(default_rng)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
@@ -279,6 +280,14 @@ fn create_app<'a, 'b>(
|
||||
.min_values(1)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("user-device")
|
||||
.long("user-device")
|
||||
.help(config::UserDeviceConfig::SYNTAX)
|
||||
.takes_value(true)
|
||||
.min_values(1)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("vsock")
|
||||
.long("vsock")
|
||||
@@ -488,6 +497,13 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// Before we start any threads, mask the signals we'll be
|
||||
// installing handlers for, to make sure they only ever run on the
|
||||
// dedicated signal handling thread we'll start in a bit.
|
||||
for sig in vmm::vm::HANDLED_SIGNALS {
|
||||
block_signal(sig).unwrap();
|
||||
}
|
||||
|
||||
event!("vmm", "starting");
|
||||
|
||||
let hypervisor = hypervisor::new().map_err(Error::CreateHypervisor)?;
|
||||
@@ -656,6 +672,7 @@ mod unit_tests {
|
||||
iommu: false,
|
||||
},
|
||||
devices: None,
|
||||
user_devices: None,
|
||||
vsock: None,
|
||||
iommu: false,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
||||
@@ -36,15 +36,18 @@ write_files:
|
||||
#!/bin/bash
|
||||
|
||||
mount /dev/vdc /mnt
|
||||
bash -c "echo 1af4 1042 > /sys/bus/pci/drivers/vfio-pci/new_id"
|
||||
bash -c "echo 0000:00:05.0 > /sys/bus/pci/devices/0000\:00\:05.0/driver/unbind"
|
||||
bash -c "echo 0000:00:05.0 > /sys/bus/pci/drivers/vfio-pci/bind"
|
||||
bash -c "echo 1af4 1041 > /sys/bus/pci/drivers/vfio-pci/new_id"
|
||||
bash -c "echo 0000:00:06.0 > /sys/bus/pci/devices/0000\:00\:06.0/driver/unbind"
|
||||
bash -c "echo 0000:00:06.0 > /sys/bus/pci/drivers/vfio-pci/bind"
|
||||
bash -c "echo 0000:00:07.0 > /sys/bus/pci/devices/0000\:00\:07.0/driver/unbind"
|
||||
bash -c "echo 0000:00:07.0 > /sys/bus/pci/drivers/vfio-pci/bind"
|
||||
bash -c "echo 0000:00:08.0 > /sys/bus/pci/devices/0000\:00\:08.0/driver/unbind"
|
||||
bash -c "echo 0000:00:08.0 > /sys/bus/pci/drivers/vfio-pci/bind"
|
||||
# 1G ram requires 512 pages
|
||||
echo 512 | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
/mnt/cloud-hypervisor --kernel /mnt/vmlinux --cmdline "console=hvc0 reboot=k panic=1 nomodules root=/dev/vda1 VFIOTAG" --disk path=/mnt/focal-server-cloudimg-amd64-custom-20210609-0.qcow2 path=/mnt/cloudinit.img --cpus boot=1 --memory size=512M,hotplug_size=1G,hugepages=on --device path=/sys/bus/pci/devices/0000:00:06.0/ path=/sys/bus/pci/devices/0000:00:07.0/ --api-socket /tmp/ch_api.sock
|
||||
/mnt/cloud-hypervisor --kernel /mnt/vmlinux --cmdline "console=hvc0 reboot=k panic=1 nomodules root=/dev/vda1 VFIOTAG" --disk path=/mnt/focal-server-cloudimg-amd64-custom-20210609-0.qcow2 path=/mnt/cloudinit.img --cpus boot=1 --memory size=512M,hotplug_size=1G,hugepages=on --device path=/sys/bus/pci/devices/0000:00:05.0/ path=/sys/bus/pci/devices/0000:00:07.0/ path=/sys/bus/pci/devices/0000:00:08.0/ --api-socket /tmp/ch_api.sock
|
||||
|
||||
-
|
||||
path: /etc/systemd/system/notify-booted.service
|
||||
|
||||
@@ -226,7 +226,7 @@ impl DiskConfig for UbuntuDiskConfig {
|
||||
.expect("Expected reading user-data file in to succeed");
|
||||
user_data_string = user_data_string.replace(
|
||||
"@DEFAULT_TCP_LISTENER_MESSAGE",
|
||||
&DEFAULT_TCP_LISTENER_MESSAGE,
|
||||
DEFAULT_TCP_LISTENER_MESSAGE,
|
||||
);
|
||||
user_data_string = user_data_string.replace("@HOST_IP", &network.host_ip);
|
||||
user_data_string =
|
||||
@@ -234,7 +234,7 @@ impl DiskConfig for UbuntuDiskConfig {
|
||||
|
||||
fs::File::create(cloud_init_directory.join("user-data"))
|
||||
.unwrap()
|
||||
.write_all(&user_data_string.as_bytes())
|
||||
.write_all(user_data_string.as_bytes())
|
||||
.expect("Expected writing out user-data to succeed");
|
||||
|
||||
let mut network_config_string = String::new();
|
||||
@@ -260,7 +260,7 @@ impl DiskConfig for UbuntuDiskConfig {
|
||||
|
||||
fs::File::create(cloud_init_directory.join("network-config"))
|
||||
.unwrap()
|
||||
.write_all(&network_config_string.as_bytes())
|
||||
.write_all(network_config_string.as_bytes())
|
||||
.expect("Expected writing out network-config to succeed");
|
||||
|
||||
std::process::Command::new("mkdosfs")
|
||||
@@ -595,12 +595,12 @@ pub fn exec_host_command_status(command: &str) -> ExitStatus {
|
||||
std::process::Command::new("bash")
|
||||
.args(&["-c", command])
|
||||
.status()
|
||||
.expect(&format!("Expected '{}' to run", command))
|
||||
.unwrap_or_else(|_| panic!("Expected '{}' to run", command))
|
||||
}
|
||||
|
||||
pub fn exec_host_command_output(command: &str) -> Output {
|
||||
std::process::Command::new("bash")
|
||||
.args(&["-c", command])
|
||||
.output()
|
||||
.expect(&format!("Expected '{}' to run", command))
|
||||
.unwrap_or_else(|_| panic!("Expected '{}' to run", command))
|
||||
}
|
||||
|
||||
1636
tests/integration.rs
1636
tests/integration.rs
File diff suppressed because it is too large
Load Diff
20
vfio_user/Cargo.toml
Normal file
20
vfio_user/Cargo.toml
Normal file
@@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "vfio_user"
|
||||
version = "0.1.0"
|
||||
authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.43"
|
||||
libc = "0.2.101"
|
||||
log = "0.4.14"
|
||||
serde = {version = ">=1.0.27", features = ["rc"] }
|
||||
serde_derive = ">=1.0.27"
|
||||
serde_json = ">=1.0.9"
|
||||
thiserror = "1.0.29"
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = ">=0.3.1"
|
||||
|
||||
[dependencies.vfio-bindings]
|
||||
version = "0.2.0"
|
||||
features = ["fam-wrappers"]
|
||||
675
vfio_user/src/lib.rs
Normal file
675
vfio_user/src/lib.rs
Normal file
@@ -0,0 +1,675 @@
|
||||
// Copyright © 2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::io::{IoSlice, Read, Write};
|
||||
use std::num::Wrapping;
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::os::unix::prelude::RawFd;
|
||||
use std::path::Path;
|
||||
use thiserror::Error;
|
||||
use vfio_bindings::bindings::vfio::*;
|
||||
use vm_memory::{ByteValued, FileOffset};
|
||||
use vmm_sys_util::sock_ctrl_msg::ScmSocket;
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(u16)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum Command {
|
||||
Unknown = 0,
|
||||
Version = 1,
|
||||
DmaMap = 2,
|
||||
DmaUnmap = 3,
|
||||
DeviceGetInfo = 4,
|
||||
DeviceGetRegionInfo = 5,
|
||||
GetRegionIoFds = 6,
|
||||
GetIrqInfo = 7,
|
||||
SetIrqs = 8,
|
||||
RegionRead = 9,
|
||||
RegionWrite = 10,
|
||||
DmaRead = 11,
|
||||
DmaWrite = 12,
|
||||
DeviceReset = 13,
|
||||
UserDirtyPages = 14,
|
||||
}
|
||||
|
||||
impl Default for Command {
|
||||
fn default() -> Self {
|
||||
Command::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum HeaderFlags {
|
||||
Command = 0,
|
||||
Reply = 1,
|
||||
NoReply = 1 << 4,
|
||||
Error = 1 << 5,
|
||||
}
|
||||
|
||||
impl Default for HeaderFlags {
|
||||
fn default() -> Self {
|
||||
HeaderFlags::Command
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
struct Header {
|
||||
message_id: u16,
|
||||
command: Command,
|
||||
message_size: u32,
|
||||
flags: u32,
|
||||
error: u32,
|
||||
}
|
||||
|
||||
unsafe impl ByteValued for Header {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
struct Version {
|
||||
header: Header,
|
||||
major: u16,
|
||||
minor: u16,
|
||||
}
|
||||
unsafe impl ByteValued for Version {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct MigrationCapabilities {
|
||||
pgsize: u32,
|
||||
}
|
||||
|
||||
const fn default_max_msg_fds() -> u32 {
|
||||
1
|
||||
}
|
||||
|
||||
const fn default_max_data_xfer_size() -> u32 {
|
||||
1048576
|
||||
}
|
||||
|
||||
const fn default_migration_capabilities() -> MigrationCapabilities {
|
||||
MigrationCapabilities { pgsize: 4096 }
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[allow(dead_code)]
|
||||
enum DmaMapFlags {
|
||||
Unknown = 0,
|
||||
ReadOnly = 1,
|
||||
WriteOnly = 2,
|
||||
ReadWrite = 3,
|
||||
}
|
||||
|
||||
impl Default for DmaMapFlags {
|
||||
fn default() -> Self {
|
||||
Self::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
struct DmaMap {
|
||||
header: Header,
|
||||
argsz: u32,
|
||||
flags: DmaMapFlags,
|
||||
offset: u64,
|
||||
address: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
unsafe impl ByteValued for DmaMap {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
struct DmaUnmap {
|
||||
header: Header,
|
||||
argsz: u32,
|
||||
flags: u32,
|
||||
address: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
unsafe impl ByteValued for DmaUnmap {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
struct DeviceGetInfo {
|
||||
header: Header,
|
||||
argsz: u32,
|
||||
flags: u32,
|
||||
num_regions: u32,
|
||||
num_irqs: u32,
|
||||
}
|
||||
|
||||
unsafe impl ByteValued for DeviceGetInfo {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
struct DeviceGetRegionInfo {
|
||||
header: Header,
|
||||
region_info: vfio_region_info,
|
||||
}
|
||||
|
||||
unsafe impl ByteValued for DeviceGetRegionInfo {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
struct RegionAccess {
|
||||
header: Header,
|
||||
offset: u64,
|
||||
region: u32,
|
||||
count: u32,
|
||||
}
|
||||
|
||||
unsafe impl ByteValued for RegionAccess {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
struct GetIrqInfo {
|
||||
header: Header,
|
||||
argsz: u32,
|
||||
flags: u32,
|
||||
index: u32,
|
||||
count: u32,
|
||||
}
|
||||
|
||||
unsafe impl ByteValued for GetIrqInfo {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
struct SetIrqs {
|
||||
header: Header,
|
||||
argsz: u32,
|
||||
flags: u32,
|
||||
index: u32,
|
||||
start: u32,
|
||||
count: u32,
|
||||
}
|
||||
|
||||
unsafe impl ByteValued for SetIrqs {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
struct DeviceReset {
|
||||
header: Header,
|
||||
}
|
||||
|
||||
unsafe impl ByteValued for DeviceReset {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct Capabilities {
|
||||
#[serde(default = "default_max_msg_fds")]
|
||||
max_msg_fds: u32,
|
||||
#[serde(default = "default_max_data_xfer_size")]
|
||||
max_data_xfer_size: u32,
|
||||
#[serde(default = "default_migration_capabilities")]
|
||||
migration: MigrationCapabilities,
|
||||
}
|
||||
|
||||
impl Default for Capabilities {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
max_msg_fds: default_max_msg_fds(),
|
||||
max_data_xfer_size: default_max_data_xfer_size(),
|
||||
migration: default_migration_capabilities(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
stream: UnixStream,
|
||||
next_message_id: Wrapping<u16>,
|
||||
num_irqs: u32,
|
||||
resettable: bool,
|
||||
regions: Vec<Region>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Region {
|
||||
pub flags: u32,
|
||||
pub index: u32,
|
||||
pub size: u64,
|
||||
pub file_offset: Option<FileOffset>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IrqInfo {
|
||||
pub index: u32,
|
||||
pub flags: u32,
|
||||
pub count: u32,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Error connecting: {0}")]
|
||||
Connect(#[source] std::io::Error),
|
||||
#[error("Error serializing capabilities: {0}")]
|
||||
SerializeCapabilites(#[source] serde_json::Error),
|
||||
#[error("Error deserializing capabilities: {0}")]
|
||||
DeserializeCapabilites(#[source] serde_json::Error),
|
||||
#[error("Error writing to stream: {0}")]
|
||||
StreamWrite(#[source] std::io::Error),
|
||||
#[error("Error reading from stream: {0}")]
|
||||
StreamRead(#[source] std::io::Error),
|
||||
#[error("Error writing with file descriptors: {0}")]
|
||||
SendWithFd(#[source] vmm_sys_util::errno::Error),
|
||||
#[error("Error reading with file descriptors: {0}")]
|
||||
ReceiveWithFd(#[source] vmm_sys_util::errno::Error),
|
||||
#[error("Not a PCI device")]
|
||||
NotPciDevice,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(path: &Path) -> Result<Client, Error> {
|
||||
let stream = UnixStream::connect(path).map_err(Error::Connect)?;
|
||||
|
||||
let mut client = Client {
|
||||
next_message_id: Wrapping(0),
|
||||
stream,
|
||||
num_irqs: 0,
|
||||
resettable: false,
|
||||
regions: Vec::new(),
|
||||
};
|
||||
|
||||
client.negotiate_version()?;
|
||||
|
||||
client.regions = client.get_regions()?;
|
||||
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
fn negotiate_version(&mut self) -> Result<(), Error> {
|
||||
let caps = Capabilities::default();
|
||||
|
||||
let version_data = serde_json::to_string(&caps).map_err(Error::SerializeCapabilites)?;
|
||||
|
||||
let version = Version {
|
||||
header: Header {
|
||||
message_id: self.next_message_id.0,
|
||||
command: Command::Version,
|
||||
flags: HeaderFlags::Command as u32,
|
||||
message_size: (std::mem::size_of::<Version>() + version_data.len() + 1) as u32,
|
||||
..Default::default()
|
||||
},
|
||||
major: 0,
|
||||
minor: 1,
|
||||
};
|
||||
info!("Command: {:?}", version);
|
||||
|
||||
let version_data = CString::new(version_data.as_bytes()).unwrap();
|
||||
let bufs = vec![
|
||||
IoSlice::new(version.as_slice()),
|
||||
IoSlice::new(version_data.as_bytes_with_nul()),
|
||||
];
|
||||
|
||||
// TODO: Use write_all_vectored() when ready
|
||||
let _ = self
|
||||
.stream
|
||||
.write_vectored(&bufs)
|
||||
.map_err(Error::StreamWrite)?;
|
||||
|
||||
info!(
|
||||
"Sent client version information: major = {} minor = {} capabilities = {:?}",
|
||||
version.major, version.minor, &caps
|
||||
);
|
||||
|
||||
self.next_message_id += Wrapping(1);
|
||||
|
||||
let mut server_version: Version = Version::default();
|
||||
self.stream
|
||||
.read_exact(server_version.as_mut_slice())
|
||||
.map_err(Error::StreamRead)?;
|
||||
|
||||
info!("Reply: {:?}", server_version);
|
||||
|
||||
let mut server_version_data = Vec::new();
|
||||
server_version_data.resize(
|
||||
server_version.header.message_size as usize - std::mem::size_of::<Version>(),
|
||||
0,
|
||||
);
|
||||
self.stream
|
||||
.read_exact(server_version_data.as_mut_slice())
|
||||
.map_err(Error::StreamRead)?;
|
||||
|
||||
let server_caps: Capabilities =
|
||||
serde_json::from_slice(&server_version_data[0..server_version_data.len() - 1])
|
||||
.map_err(Error::DeserializeCapabilites)?;
|
||||
|
||||
info!(
|
||||
"Received server version information: major = {} minor = {} capabilities = {:?}",
|
||||
server_version.major, server_version.minor, &server_caps
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn dma_map(
|
||||
&mut self,
|
||||
offset: u64,
|
||||
address: u64,
|
||||
size: u64,
|
||||
fd: RawFd,
|
||||
) -> Result<(), Error> {
|
||||
let dma_map = DmaMap {
|
||||
header: Header {
|
||||
message_id: self.next_message_id.0,
|
||||
command: Command::DmaMap,
|
||||
flags: HeaderFlags::Command as u32,
|
||||
message_size: std::mem::size_of::<DmaMap>() as u32,
|
||||
..Default::default()
|
||||
},
|
||||
argsz: (std::mem::size_of::<DmaMap>() - std::mem::size_of::<Header>()) as u32,
|
||||
flags: DmaMapFlags::ReadWrite,
|
||||
offset,
|
||||
address,
|
||||
size,
|
||||
};
|
||||
info!("Command: {:?}", dma_map);
|
||||
self.next_message_id += Wrapping(1);
|
||||
self.stream
|
||||
.send_with_fd(dma_map.as_slice(), fd)
|
||||
.map_err(Error::SendWithFd)?;
|
||||
|
||||
let mut reply = Header::default();
|
||||
self.stream
|
||||
.read_exact(reply.as_mut_slice())
|
||||
.map_err(Error::StreamRead)?;
|
||||
info!("Reply: {:?}", reply);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn dma_unmap(&mut self, address: u64, size: u64) -> Result<(), Error> {
|
||||
let dma_unmap = DmaUnmap {
|
||||
header: Header {
|
||||
message_id: self.next_message_id.0,
|
||||
command: Command::DmaUnmap,
|
||||
flags: HeaderFlags::Command as u32,
|
||||
message_size: std::mem::size_of::<DmaUnmap>() as u32,
|
||||
..Default::default()
|
||||
},
|
||||
argsz: (std::mem::size_of::<DmaUnmap>() - std::mem::size_of::<Header>()) as u32,
|
||||
flags: 0,
|
||||
address,
|
||||
size,
|
||||
};
|
||||
info!("Command: {:?}", dma_unmap);
|
||||
self.next_message_id += Wrapping(1);
|
||||
self.stream
|
||||
.write_all(dma_unmap.as_slice())
|
||||
.map_err(Error::StreamWrite)?;
|
||||
|
||||
let mut reply = DmaUnmap::default();
|
||||
self.stream
|
||||
.read_exact(reply.as_mut_slice())
|
||||
.map_err(Error::StreamRead)?;
|
||||
info!("Reply: {:?}", reply);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) -> Result<(), Error> {
|
||||
let reset = DeviceReset {
|
||||
header: Header {
|
||||
message_id: self.next_message_id.0,
|
||||
command: Command::DeviceReset,
|
||||
flags: HeaderFlags::Command as u32,
|
||||
message_size: std::mem::size_of::<DeviceReset>() as u32,
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
info!("Command: {:?}", reset);
|
||||
self.next_message_id += Wrapping(1);
|
||||
self.stream
|
||||
.write_all(reset.as_slice())
|
||||
.map_err(Error::StreamWrite)?;
|
||||
|
||||
let mut reply = Header::default();
|
||||
self.stream
|
||||
.read_exact(reply.as_mut_slice())
|
||||
.map_err(Error::StreamRead)?;
|
||||
info!("Reply: {:?}", reply);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_regions(&mut self) -> Result<Vec<Region>, Error> {
|
||||
let get_info = DeviceGetInfo {
|
||||
header: Header {
|
||||
message_id: self.next_message_id.0,
|
||||
command: Command::DeviceGetInfo,
|
||||
flags: HeaderFlags::Command as u32,
|
||||
message_size: std::mem::size_of::<DeviceGetInfo>() as u32,
|
||||
..Default::default()
|
||||
},
|
||||
argsz: std::mem::size_of::<DeviceGetInfo>() as u32,
|
||||
..Default::default()
|
||||
};
|
||||
info!("Command: {:?}", get_info);
|
||||
self.next_message_id += Wrapping(1);
|
||||
|
||||
self.stream
|
||||
.write_all(get_info.as_slice())
|
||||
.map_err(Error::StreamWrite)?;
|
||||
|
||||
let mut reply = DeviceGetInfo::default();
|
||||
self.stream
|
||||
.read_exact(reply.as_mut_slice())
|
||||
.map_err(Error::StreamRead)?;
|
||||
info!("Reply: {:?}", reply);
|
||||
self.num_irqs = reply.num_irqs;
|
||||
|
||||
if reply.flags & VFIO_DEVICE_FLAGS_PCI != VFIO_DEVICE_FLAGS_PCI {
|
||||
return Err(Error::NotPciDevice);
|
||||
}
|
||||
|
||||
self.resettable = reply.flags & VFIO_DEVICE_FLAGS_RESET != VFIO_DEVICE_FLAGS_RESET;
|
||||
|
||||
let num_regions = reply.num_regions;
|
||||
let mut regions = Vec::new();
|
||||
for index in 0..num_regions {
|
||||
let 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: 1024, // Arbitrary max size
|
||||
index,
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
info!("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)?;
|
||||
info!("Reply: {:?}", reply);
|
||||
|
||||
regions.push(Region {
|
||||
flags: reply.region_info.flags,
|
||||
index: reply.region_info.index,
|
||||
size: reply.region_info.size,
|
||||
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);
|
||||
self.stream
|
||||
.read_exact(_cap_data.as_mut_slice())
|
||||
.map_err(Error::StreamRead)?;
|
||||
}
|
||||
|
||||
Ok(regions)
|
||||
}
|
||||
|
||||
pub fn region_read(&mut self, region: u32, offset: u64, data: &mut [u8]) -> Result<(), Error> {
|
||||
let region_read = RegionAccess {
|
||||
header: Header {
|
||||
message_id: self.next_message_id.0,
|
||||
command: Command::RegionRead,
|
||||
flags: HeaderFlags::Command as u32,
|
||||
message_size: std::mem::size_of::<RegionAccess>() as u32,
|
||||
..Default::default()
|
||||
},
|
||||
offset,
|
||||
count: data.len() as u32,
|
||||
region,
|
||||
};
|
||||
info!("Command: {:?}", region_read);
|
||||
self.next_message_id += Wrapping(1);
|
||||
self.stream
|
||||
.write_all(region_read.as_slice())
|
||||
.map_err(Error::StreamWrite)?;
|
||||
|
||||
let mut reply = RegionAccess::default();
|
||||
self.stream
|
||||
.read_exact(reply.as_mut_slice())
|
||||
.map_err(Error::StreamRead)?;
|
||||
info!("Reply: {:?}", reply);
|
||||
self.stream.read_exact(data).map_err(Error::StreamRead)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn region_write(&mut self, region: u32, offset: u64, data: &[u8]) -> Result<(), Error> {
|
||||
let region_write = RegionAccess {
|
||||
header: Header {
|
||||
message_id: self.next_message_id.0,
|
||||
command: Command::RegionWrite,
|
||||
flags: HeaderFlags::Command as u32,
|
||||
message_size: (std::mem::size_of::<RegionAccess>() + data.len()) as u32,
|
||||
..Default::default()
|
||||
},
|
||||
offset,
|
||||
count: data.len() as u32,
|
||||
region,
|
||||
};
|
||||
info!("Command: {:?}", region_write);
|
||||
self.next_message_id += Wrapping(1);
|
||||
|
||||
let bufs = vec![IoSlice::new(region_write.as_slice()), IoSlice::new(data)];
|
||||
|
||||
// TODO: Use write_all_vectored() when ready
|
||||
let _ = self
|
||||
.stream
|
||||
.write_vectored(&bufs)
|
||||
.map_err(Error::StreamWrite)?;
|
||||
|
||||
let mut reply = RegionAccess::default();
|
||||
self.stream
|
||||
.read_exact(reply.as_mut_slice())
|
||||
.map_err(Error::StreamRead)?;
|
||||
info!("Reply: {:?}", reply);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_irq_info(&mut self, index: u32) -> Result<IrqInfo, Error> {
|
||||
let get_irq_info = GetIrqInfo {
|
||||
header: Header {
|
||||
message_id: self.next_message_id.0,
|
||||
command: Command::GetIrqInfo,
|
||||
flags: HeaderFlags::Command as u32,
|
||||
message_size: std::mem::size_of::<GetIrqInfo>() as u32,
|
||||
..Default::default()
|
||||
},
|
||||
argsz: (std::mem::size_of::<GetIrqInfo>() - std::mem::size_of::<Header>()) as u32,
|
||||
flags: 0,
|
||||
index,
|
||||
count: 0,
|
||||
};
|
||||
info!("Command: {:?}", get_irq_info);
|
||||
self.next_message_id += Wrapping(1);
|
||||
|
||||
self.stream
|
||||
.write_all(get_irq_info.as_slice())
|
||||
.map_err(Error::StreamWrite)?;
|
||||
|
||||
let mut reply = GetIrqInfo::default();
|
||||
self.stream
|
||||
.read_exact(reply.as_mut_slice())
|
||||
.map_err(Error::StreamRead)?;
|
||||
info!("Reply: {:?}", reply);
|
||||
|
||||
Ok(IrqInfo {
|
||||
index: reply.index,
|
||||
flags: reply.flags,
|
||||
count: reply.count,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_irqs(
|
||||
&mut self,
|
||||
index: u32,
|
||||
flags: u32,
|
||||
start: u32,
|
||||
count: u32,
|
||||
fds: &[RawFd],
|
||||
) -> Result<(), Error> {
|
||||
let set_irqs = SetIrqs {
|
||||
header: Header {
|
||||
message_id: self.next_message_id.0,
|
||||
command: Command::SetIrqs,
|
||||
flags: HeaderFlags::Command as u32,
|
||||
message_size: std::mem::size_of::<SetIrqs>() as u32,
|
||||
..Default::default()
|
||||
},
|
||||
argsz: (std::mem::size_of::<SetIrqs>() - std::mem::size_of::<Header>()) as u32,
|
||||
flags,
|
||||
start,
|
||||
index,
|
||||
count,
|
||||
};
|
||||
info!("Command: {:?}", set_irqs);
|
||||
self.next_message_id += Wrapping(1);
|
||||
|
||||
self.stream
|
||||
.send_with_fds(&[set_irqs.as_slice()], fds)
|
||||
.map_err(Error::SendWithFd)?;
|
||||
|
||||
let mut reply = Header::default();
|
||||
self.stream
|
||||
.read_exact(reply.as_mut_slice())
|
||||
.map_err(Error::StreamRead)?;
|
||||
info!("Reply: {:?}", reply);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn region(&self, region_index: u32) -> Option<&Region> {
|
||||
for region in &self.regions {
|
||||
if region.index == region_index {
|
||||
return Some(region);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn resettable(&self) -> bool {
|
||||
self.resettable
|
||||
}
|
||||
}
|
||||
16
vhdx/Cargo.toml
Normal file
16
vhdx/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "vhdx"
|
||||
version = "0.1.0"
|
||||
authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.4.3"
|
||||
crc32c = "0.6.0"
|
||||
libc = "0.2.101"
|
||||
log = "0.4.14"
|
||||
remain = "0.2.2"
|
||||
thiserror = "1.0"
|
||||
uuid = { version = "0.8.2", features = ["v4"] }
|
||||
vmm-sys-util = ">=0.3.1"
|
||||
31
vhdx/src/lib.rs
Normal file
31
vhdx/src/lib.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright © 2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use std::result::Result;
|
||||
use uuid::Uuid;
|
||||
|
||||
macro_rules! div_round_up {
|
||||
($n:expr,$d:expr) => {
|
||||
($n + $d - 1) / $d
|
||||
};
|
||||
}
|
||||
|
||||
pub mod vhdx;
|
||||
mod vhdx_bat;
|
||||
mod vhdx_header;
|
||||
mod vhdx_io;
|
||||
mod vhdx_metadata;
|
||||
|
||||
pub(crate) fn uuid_from_guid(buf: &[u8]) -> Result<Uuid, uuid::Error> {
|
||||
// The first 3 fields of UUID are stored in Big Endian format, and
|
||||
// the last 8 bytes are stored as byte array. Therefore, we read the
|
||||
// first 3 fields in Big Endian format instead of Little Endian.
|
||||
Uuid::from_fields_le(
|
||||
BigEndian::read_u32(&buf[0..4]),
|
||||
BigEndian::read_u16(&buf[4..6]),
|
||||
BigEndian::read_u16(&buf[6..8]),
|
||||
&buf[8..16],
|
||||
)
|
||||
}
|
||||
212
vhdx/src/vhdx.rs
Normal file
212
vhdx/src/vhdx.rs
Normal file
@@ -0,0 +1,212 @@
|
||||
// Copyright © 2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::vhdx_bat::{BatEntry, VhdxBatError};
|
||||
use crate::vhdx_header::{self, RegionInfo, RegionTableEntry, VhdxHeader, VhdxHeaderError};
|
||||
use crate::vhdx_io::{self, VhdxIoError};
|
||||
use crate::vhdx_metadata::{DiskSpec, VhdxMetadataError};
|
||||
use remain::sorted;
|
||||
use std::collections::btree_map::BTreeMap;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use thiserror::Error;
|
||||
|
||||
#[sorted]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum VhdxError {
|
||||
#[error("Not a VHDx file {0}")]
|
||||
NotVhdx(#[source] VhdxHeaderError),
|
||||
#[error("Failed to parse VHDx header {0}")]
|
||||
ParseVhdxHeader(#[source] VhdxHeaderError),
|
||||
#[error("Failed to parse VHDx metadata {0}")]
|
||||
ParseVhdxMetadata(#[source] VhdxMetadataError),
|
||||
#[error("Failed to parse VHDx region entries {0}")]
|
||||
ParseVhdxRegionEntry(#[source] VhdxHeaderError),
|
||||
#[error("Failed reading metadata {0}")]
|
||||
ReadBatEntry(#[source] VhdxBatError),
|
||||
#[error("Failed reading sector from disk {0}")]
|
||||
ReadFailed(#[source] VhdxIoError),
|
||||
#[error("Failed writing to sector on disk {0}")]
|
||||
WriteFailed(#[source] VhdxIoError),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, VhdxError>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Vhdx {
|
||||
file: File,
|
||||
vhdx_header: VhdxHeader,
|
||||
region_entries: BTreeMap<u64, u64>,
|
||||
bat_entry: RegionTableEntry,
|
||||
mdr_entry: RegionTableEntry,
|
||||
disk_spec: DiskSpec,
|
||||
bat_entries: Vec<BatEntry>,
|
||||
current_offset: u64,
|
||||
first_write: bool,
|
||||
}
|
||||
|
||||
impl Vhdx {
|
||||
/// Parse the Vhdx header, BAT, and metadata from a file and store info
|
||||
// in Vhdx structure.
|
||||
pub fn new(mut file: File) -> Result<Vhdx> {
|
||||
let vhdx_header = VhdxHeader::new(&mut file).map_err(VhdxError::ParseVhdxHeader)?;
|
||||
|
||||
let collected_entries = RegionInfo::new(
|
||||
&mut file,
|
||||
vhdx_header::REGION_TABLE_1_START,
|
||||
vhdx_header.region_entry_count(),
|
||||
)
|
||||
.map_err(VhdxError::ParseVhdxRegionEntry)?;
|
||||
|
||||
let bat_entry = collected_entries.bat_entry;
|
||||
let mdr_entry = collected_entries.mdr_entry;
|
||||
|
||||
let disk_spec =
|
||||
DiskSpec::new(&mut file, &mdr_entry).map_err(VhdxError::ParseVhdxMetadata)?;
|
||||
let bat_entries = BatEntry::collect_bat_entries(&mut file, &disk_spec, &bat_entry)
|
||||
.map_err(VhdxError::ReadBatEntry)?;
|
||||
|
||||
Ok(Vhdx {
|
||||
file,
|
||||
vhdx_header,
|
||||
region_entries: collected_entries.region_entries,
|
||||
bat_entry,
|
||||
mdr_entry,
|
||||
disk_spec,
|
||||
bat_entries,
|
||||
current_offset: 0,
|
||||
first_write: true,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn virtual_disk_size(&self) -> u64 {
|
||||
self.disk_spec.virtual_disk_size
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Vhdx {
|
||||
/// Wrapper function to satisfy Read trait implementation for VHDx disk.
|
||||
/// Convert the offset to sector index and buffer length to sector count.
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
|
||||
let sector_count =
|
||||
div_round_up!(buf.len() as u64, self.disk_spec.logical_sector_size as u64);
|
||||
let sector_index = self.current_offset / self.disk_spec.logical_sector_size as u64;
|
||||
|
||||
vhdx_io::read(
|
||||
&mut self.file,
|
||||
buf,
|
||||
&self.disk_spec,
|
||||
&self.bat_entries,
|
||||
sector_index,
|
||||
sector_count,
|
||||
)
|
||||
.map_err(|e| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"Failed reading {} sectors from VHDx at index {}: {}",
|
||||
sector_count, sector_index, e
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Vhdx {
|
||||
fn flush(&mut self) -> std::result::Result<(), std::io::Error> {
|
||||
self.file.flush()
|
||||
}
|
||||
|
||||
/// Wrapper function to satisfy Write trait implementation for VHDx disk.
|
||||
/// Convert the offset to sector index and buffer length to sector count.
|
||||
fn write(&mut self, buf: &[u8]) -> std::result::Result<usize, std::io::Error> {
|
||||
let sector_count =
|
||||
div_round_up!(buf.len() as u64, self.disk_spec.logical_sector_size as u64);
|
||||
let sector_index = self.current_offset / self.disk_spec.logical_sector_size as u64;
|
||||
|
||||
if self.first_write {
|
||||
self.first_write = false;
|
||||
self.vhdx_header.update(&mut self.file).map_err(|e| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("Failed to update VHDx header: {}", e),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
||||
vhdx_io::write(
|
||||
&mut self.file,
|
||||
buf,
|
||||
&mut self.disk_spec,
|
||||
self.bat_entry.file_offset,
|
||||
&mut self.bat_entries,
|
||||
sector_index,
|
||||
sector_count,
|
||||
)
|
||||
.map_err(|e| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"Failed writing {} sectors on VHDx at index {}: {}",
|
||||
sector_count, sector_index, e
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Seek for Vhdx {
|
||||
/// Wrapper function to satisfy Seek trait implementation for VHDx disk.
|
||||
/// Updates the offset field in the Vhdx struct.
|
||||
fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
|
||||
let new_offset: Option<u64> = match pos {
|
||||
SeekFrom::Start(off) => Some(off),
|
||||
SeekFrom::End(off) => {
|
||||
if off < 0 {
|
||||
0i64.checked_sub(off).and_then(|increment| {
|
||||
self.virtual_disk_size().checked_sub(increment as u64)
|
||||
})
|
||||
} else {
|
||||
self.virtual_disk_size().checked_add(off as u64)
|
||||
}
|
||||
}
|
||||
SeekFrom::Current(off) => {
|
||||
if off < 0 {
|
||||
0i64.checked_sub(off)
|
||||
.and_then(|increment| self.current_offset.checked_sub(increment as u64))
|
||||
} else {
|
||||
self.current_offset.checked_add(off as u64)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(o) = new_offset {
|
||||
if o <= self.virtual_disk_size() {
|
||||
self.current_offset = o;
|
||||
return Ok(o);
|
||||
}
|
||||
}
|
||||
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"Failed seek operation",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Vhdx {
|
||||
fn clone(&self) -> Self {
|
||||
Vhdx {
|
||||
file: self.file.try_clone().unwrap(),
|
||||
vhdx_header: self.vhdx_header.clone(),
|
||||
region_entries: self.region_entries.clone(),
|
||||
bat_entry: self.bat_entry,
|
||||
mdr_entry: self.mdr_entry,
|
||||
disk_spec: self.disk_spec.clone(),
|
||||
bat_entries: self.bat_entries.clone(),
|
||||
current_offset: self.current_offset,
|
||||
first_write: self.first_write,
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user