mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
412 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e0e632361 | ||
|
|
1c9df58440 | ||
|
|
1917e86206 | ||
|
|
787f5085b6 | ||
|
|
fec39ccf51 | ||
|
|
115085eb9e | ||
|
|
802e9009b9 | ||
|
|
37fbece885 | ||
|
|
ec6e87479f | ||
|
|
5b51024ef7 | ||
|
|
99a98f270d | ||
|
|
c0af33a4c9 | ||
|
|
0cf868b5c1 | ||
|
|
3da60dfa5e | ||
|
|
1c8a91940e | ||
|
|
8c117a8117 | ||
|
|
7d0aa1fd02 | ||
|
|
a0190b16aa | ||
|
|
1bd8eb68ff | ||
|
|
8363eddd97 | ||
|
|
70aa5bc231 | ||
|
|
b8ce1816e9 | ||
|
|
43eed4861f | ||
|
|
268c4ea214 | ||
|
|
29a0ddc58e | ||
|
|
4079e4f1ad | ||
|
|
fba0b5f93c | ||
|
|
05cc5f596c | ||
|
|
c1b33329db | ||
|
|
402a24a688 | ||
|
|
0809e7f675 | ||
|
|
a718716831 | ||
|
|
5a9dd7489c | ||
|
|
dec8d619d4 | ||
|
|
c39cdb3c1f | ||
|
|
26ae8b6d5c | ||
|
|
de31b3fadc | ||
|
|
b06ad85604 | ||
|
|
8d89736c68 | ||
|
|
55ee8eb482 | ||
|
|
1017157bb6 | ||
|
|
499989fb17 | ||
|
|
ce0f30bb54 | ||
|
|
fce202a90c | ||
|
|
95626ae564 | ||
|
|
1e1012c31b | ||
|
|
56207dc3a0 | ||
|
|
57fdaa3a39 | ||
|
|
19c5c0af9f | ||
|
|
e26e7b4d72 | ||
|
|
e8d6c9ecb0 | ||
|
|
0712027eb1 | ||
|
|
7ea5d7a416 | ||
|
|
7023d4ff84 | ||
|
|
5f31ad319e | ||
|
|
5083549afe | ||
|
|
beed5e5d6d | ||
|
|
7feb25daf0 | ||
|
|
f2574897cd | ||
|
|
2698924c0d | ||
|
|
6bd4927d11 | ||
|
|
f485922b78 | ||
|
|
1faaa2cd0a | ||
|
|
6c630f4908 | ||
|
|
3b39c41a01 | ||
|
|
309e346c4c | ||
|
|
3f6833b315 | ||
|
|
a862c804ba | ||
|
|
83914d80a2 | ||
|
|
a7aecb5eee | ||
|
|
a64d27f841 | ||
|
|
7a458d85d1 | ||
|
|
a92d852848 | ||
|
|
0664647109 | ||
|
|
f2c813e1cf | ||
|
|
f00df25d40 | ||
|
|
c016a0d4d3 | ||
|
|
5c96fbb19b | ||
|
|
b955f09b80 | ||
|
|
79ad6f8536 | ||
|
|
be4f04a906 | ||
|
|
f8415debe9 | ||
|
|
9014a5e59c | ||
|
|
612621bb46 | ||
|
|
18e1d2caf5 | ||
|
|
4be406a308 | ||
|
|
7bf2a2c382 | ||
|
|
7df80220ec | ||
|
|
84d2511de0 | ||
|
|
374263ddac | ||
|
|
7b76b6b61e | ||
|
|
e06f12673b | ||
|
|
89e658d9ff | ||
|
|
5ac68534b1 | ||
|
|
6acceaa87c | ||
|
|
a3898fd8e1 | ||
|
|
7026622c24 | ||
|
|
41e5384f15 | ||
|
|
681a30bd15 | ||
|
|
1976157761 | ||
|
|
0b1e626fe3 | ||
|
|
79bc42f3c2 | ||
|
|
eca75dcfc9 | ||
|
|
600d1664ee | ||
|
|
e6208d1c0e | ||
|
|
cf635c64d7 | ||
|
|
42ca292dce | ||
|
|
b7338c96eb | ||
|
|
bf4af14e73 | ||
|
|
24a3505f0b | ||
|
|
20f3691474 | ||
|
|
c56a3ce59a | ||
|
|
18f7a37b48 | ||
|
|
98496434b9 | ||
|
|
0b2994a6e3 | ||
|
|
553e6857bd | ||
|
|
083ce323c0 | ||
|
|
8fff4c1af3 | ||
|
|
35ecfb6ec5 | ||
|
|
a61a013311 | ||
|
|
b509fd94cd | ||
|
|
631af8a4f7 | ||
|
|
aa14fe214a | ||
|
|
45e3f49bba | ||
|
|
03db406645 | ||
|
|
ba1e89139a | ||
|
|
21d40d7489 | ||
|
|
c90a0ffff6 | ||
|
|
dc7931f592 | ||
|
|
841627f10a | ||
|
|
97fdb65012 | ||
|
|
d17d70fae1 | ||
|
|
71d1296d09 | ||
|
|
0d58e51a3a | ||
|
|
97012c511d | ||
|
|
c10e2a79b1 | ||
|
|
f3870ae638 | ||
|
|
3c0b389c82 | ||
|
|
9881c94f84 | ||
|
|
ceb8151747 | ||
|
|
2554f2a8d4 | ||
|
|
036af673e6 | ||
|
|
990362e314 | ||
|
|
83d57d3cce | ||
|
|
a0babfb9c1 | ||
|
|
3394a59466 | ||
|
|
f8e0376f6d | ||
|
|
6379074264 | ||
|
|
5dbc72948f | ||
|
|
04d111ee15 | ||
|
|
a9623c7a28 | ||
|
|
4baf85857a | ||
|
|
e3d2917d5f | ||
|
|
a84b540b65 | ||
|
|
8eb162e3d7 | ||
|
|
2804608a1c | ||
|
|
e0125653b1 | ||
|
|
e431a48201 | ||
|
|
c143cb3af0 | ||
|
|
b6feae0ace | ||
|
|
520aff2efc | ||
|
|
41880919a0 | ||
|
|
865291d840 | ||
|
|
346ee09e6b | ||
|
|
59012ccc6e | ||
|
|
3f17f4657b | ||
|
|
086ca9b935 | ||
|
|
9b724303ac | ||
|
|
948573db0d | ||
|
|
0352846af2 | ||
|
|
8b3f0043b0 | ||
|
|
9d532acab6 | ||
|
|
df2a7c1764 | ||
|
|
3f5dac988f | ||
|
|
3096f1d42f | ||
|
|
42a4e593ce | ||
|
|
b56da6ee24 | ||
|
|
90dcbc3232 | ||
|
|
f3522e85fc | ||
|
|
d3ac6a85e0 | ||
|
|
38a1b45783 | ||
|
|
e9841db486 | ||
|
|
c1f555cde3 | ||
|
|
505f4dfa53 | ||
|
|
67ad3ff1ba | ||
|
|
755cabea4c | ||
|
|
1ed4898d28 | ||
|
|
a807b91f86 | ||
|
|
f6236087d8 | ||
|
|
95f83320b1 | ||
|
|
dcc858a403 | ||
|
|
57ea412c64 | ||
|
|
e32c9525c0 | ||
|
|
2b4f60e57b | ||
|
|
5736205cf0 | ||
|
|
a8d1849485 | ||
|
|
55937f63bc | ||
|
|
426d5d6dd0 | ||
|
|
3f3d07b3dc | ||
|
|
296cb909f4 | ||
|
|
e7d52fc736 | ||
|
|
a598b935f2 | ||
|
|
1c0b6f1090 | ||
|
|
1b12790c13 | ||
|
|
bd307dcab5 | ||
|
|
83d757d89a | ||
|
|
1b8e7ac06c | ||
|
|
389e4fe8be | ||
|
|
06a9c3b839 | ||
|
|
36cf46e381 | ||
|
|
1efdea7466 | ||
|
|
e662a2e12c | ||
|
|
5496bd5dfb | ||
|
|
e655de1e39 | ||
|
|
a55a642b70 | ||
|
|
ded8959b9a | ||
|
|
53e49636ca | ||
|
|
0b0f3c69f0 | ||
|
|
6650f553bd | ||
|
|
c5bca514b9 | ||
|
|
c4106c0592 | ||
|
|
61f89e7dcc | ||
|
|
7a4be1534f | ||
|
|
cf0c4e07b6 | ||
|
|
36ec53c4a0 | ||
|
|
c7997ea4e5 | ||
|
|
b2d3aba19c | ||
|
|
9cd97bb64e | ||
|
|
868fdf9dfe | ||
|
|
12729eb034 | ||
|
|
a062401be6 | ||
|
|
09cc139b53 | ||
|
|
4635ebd4b2 | ||
|
|
ca96ff601b | ||
|
|
feb523ef78 | ||
|
|
7e47464a48 | ||
|
|
4c4f79c831 | ||
|
|
0fd701ac75 | ||
|
|
64924d5c2b | ||
|
|
9c11927305 | ||
|
|
b13d0e53c5 | ||
|
|
6001240ca1 | ||
|
|
9534604ef3 | ||
|
|
c152f9f6bc | ||
|
|
325e62372d | ||
|
|
9421884334 | ||
|
|
fcd09946b7 | ||
|
|
a20e481abe | ||
|
|
6e4374c392 | ||
|
|
44452cbe22 | ||
|
|
7b2ebd2fa5 | ||
|
|
8a0f6014ce | ||
|
|
d78da5d252 | ||
|
|
b35a94d83c | ||
|
|
961319d8ad | ||
|
|
b97f929706 | ||
|
|
b71564f284 | ||
|
|
f2be30f699 | ||
|
|
b14216e854 | ||
|
|
3498e67bda | ||
|
|
24d163b244 | ||
|
|
90697d4ae0 | ||
|
|
73c4156775 | ||
|
|
02f774824b | ||
|
|
74cd3d0dc2 | ||
|
|
85962099c7 | ||
|
|
04ee1efa70 | ||
|
|
5258a870e0 | ||
|
|
76d6d28f3e | ||
|
|
5132e3b907 | ||
|
|
599c5280ed | ||
|
|
2f649bb6ad | ||
|
|
ece0e6fa92 | ||
|
|
2593b67864 | ||
|
|
191e865261 | ||
|
|
ca3a441c49 | ||
|
|
de3ca97095 | ||
|
|
74dcb37ec3 | ||
|
|
1d55de9c74 | ||
|
|
2e94a86b31 | ||
|
|
996bdc6e08 | ||
|
|
9d18012c52 | ||
|
|
6a8bd8e8c5 | ||
|
|
d9184e5256 | ||
|
|
5e475e70e6 | ||
|
|
bd1e1677bd | ||
|
|
595c9d13a9 | ||
|
|
c2616f3f4f | ||
|
|
7ceb126184 | ||
|
|
879411e70f | ||
|
|
1181fd21fd | ||
|
|
c8967fcc37 | ||
|
|
19e893fa53 | ||
|
|
aa502b3e41 | ||
|
|
10531f052b | ||
|
|
b072eb454e | ||
|
|
b7c2a0f23f | ||
|
|
874d524a13 | ||
|
|
91e2601523 | ||
|
|
01900e3c2b | ||
|
|
e35ef40029 | ||
|
|
aa0af5f8d7 | ||
|
|
46066d6ae1 | ||
|
|
51c1738d55 | ||
|
|
0567def931 | ||
|
|
0110fb4edc | ||
|
|
4f945743cb | ||
|
|
8f6afec520 | ||
|
|
b14427540b | ||
|
|
ea4a95c4f6 | ||
|
|
f5084f7c65 | ||
|
|
45ab9f77b7 | ||
|
|
f0ea8eb70b | ||
|
|
3377e0e983 | ||
|
|
e9435b1327 | ||
|
|
09fca4a5dd | ||
|
|
1143d54ee0 | ||
|
|
934b20a77a | ||
|
|
b54ce6c3db | ||
|
|
3dd01443d5 | ||
|
|
43227cd5c4 | ||
|
|
176e438d17 | ||
|
|
c22c4675b3 | ||
|
|
7ccf58a019 | ||
|
|
48e1af7d3c | ||
|
|
341a69c39c | ||
|
|
5d34d85b92 | ||
|
|
bcd46906ec | ||
|
|
bc59ca72f3 | ||
|
|
995945dd25 | ||
|
|
8edd81ec82 | ||
|
|
726cfa41f4 | ||
|
|
d19a5d5356 | ||
|
|
69e8f60b91 | ||
|
|
c6eb69caba | ||
|
|
e4ed9bc557 | ||
|
|
f4509c3611 | ||
|
|
ecbb8ab282 | ||
|
|
29ebecccb0 | ||
|
|
5646a917ff | ||
|
|
6e22f23831 | ||
|
|
8e996ff2fe | ||
|
|
2d2f356d94 | ||
|
|
938c16f2b2 | ||
|
|
105a7dd7aa | ||
|
|
11ef495e6b | ||
|
|
34b3170680 | ||
|
|
427a2bacf5 | ||
|
|
1325c76525 | ||
|
|
4a51a6615f | ||
|
|
d5ce855649 | ||
|
|
496f932276 | ||
|
|
c33efe294a | ||
|
|
2d022d0c85 | ||
|
|
5b31b19530 | ||
|
|
ad202f9b7a | ||
|
|
3a225aaa23 | ||
|
|
1bfa07f48e | ||
|
|
8e682bcb00 | ||
|
|
1ee2922dbc | ||
|
|
2ce503f457 | ||
|
|
574576c8e9 | ||
|
|
aaf67c9ae4 | ||
|
|
8b9da4e286 | ||
|
|
271f11d9ec | ||
|
|
e436b382cc | ||
|
|
1ce1fe7334 | ||
|
|
73af65f417 | ||
|
|
cffde0ff65 | ||
|
|
e41b7d90d5 | ||
|
|
60425471dd | ||
|
|
2b76e1d7ba | ||
|
|
15ace525be | ||
|
|
8db630763a | ||
|
|
cd1470e289 | ||
|
|
99d8c34861 | ||
|
|
6725771dc3 | ||
|
|
0e8fd0bc17 | ||
|
|
0ef1e668a5 | ||
|
|
477332a94a | ||
|
|
7b102c4fa3 | ||
|
|
1e159dbefb | ||
|
|
a4ef6e57a7 | ||
|
|
ec45daac19 | ||
|
|
c773330a65 | ||
|
|
e4ae668bcd | ||
|
|
f6c058da56 | ||
|
|
089dffcb49 | ||
|
|
9d7034b9c6 | ||
|
|
a86edd3032 | ||
|
|
7805fe58e2 | ||
|
|
e66ffffd43 | ||
|
|
843c8ad51c | ||
|
|
a334831d54 | ||
|
|
dab9f1cf30 | ||
|
|
3a81f9328f | ||
|
|
e2886a4b1f | ||
|
|
c6d3f61a42 | ||
|
|
4689abd9f4 | ||
|
|
f479f0605d | ||
|
|
5034bea8c4 | ||
|
|
b8172408f8 | ||
|
|
b0a2ce0598 | ||
|
|
a0922930b1 | ||
|
|
d1ec65873e | ||
|
|
54e9ed9932 | ||
|
|
111225a2a5 | ||
|
|
fe49056129 | ||
|
|
d5558aea2a | ||
|
|
1ba995d952 | ||
|
|
c6c081099f | ||
|
|
3a1254a9b2 |
5
.github/workflows/build.yaml
vendored
5
.github/workflows/build.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
- "1.60"
|
||||
- "1.64"
|
||||
target:
|
||||
- x86_64-unknown-linux-gnu
|
||||
- x86_64-unknown-linux-musl
|
||||
@@ -42,6 +42,9 @@ jobs:
|
||||
- name: Build (default features + tdx)
|
||||
run: cargo rustc --locked --bin cloud-hypervisor --features "tdx" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Build (default features + dbus_api)
|
||||
run: cargo rustc --locked --bin cloud-hypervisor --features "dbus_api" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Build (default features + guest_debug)
|
||||
run: cargo rustc --locked --bin cloud-hypervisor --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
|
||||
20
.github/workflows/docker-image.yaml
vendored
20
.github/workflows/docker-image.yaml
vendored
@@ -7,6 +7,10 @@ on:
|
||||
pull_request:
|
||||
paths: resources/Dockerfile
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -20,19 +24,19 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Login to DockerHub
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: docker/login-action@v1
|
||||
- name: Login to ghcr
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
# list of Docker images to use as base name for tags
|
||||
images: cloudhypervisor/dev
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
# generate Docker tags based on the following events/attributes
|
||||
tags: |
|
||||
type=raw,value={{date 'YYYYMMDD'}}-0
|
||||
|
||||
26
.github/workflows/hadolint.yaml
vendored
Normal file
26
.github/workflows/hadolint.yaml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Lint Dockerfile
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- resources/Dockerfile
|
||||
pull_request:
|
||||
paths:
|
||||
- resources/Dockerfile
|
||||
|
||||
jobs:
|
||||
hadolint:
|
||||
name: Run Hadolint Dockerfile Linter
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Lint Dockerfile
|
||||
uses: hadolint/hadolint-action@master
|
||||
with:
|
||||
dockerfile: ./resources/Dockerfile
|
||||
format: tty
|
||||
no-fail: false
|
||||
verbose: true
|
||||
failure-threshold: info
|
||||
16
.github/workflows/quality.yaml
vendored
16
.github/workflows/quality.yaml
vendored
@@ -51,7 +51,7 @@ jobs:
|
||||
run: |
|
||||
set -e
|
||||
commits=$(git rev-list origin/${{ github.base_ref }}..${{ github.sha }})
|
||||
for commit in $commits; do git checkout $commit; cargo check --tests --all --target=${{ matrix.target }}; done
|
||||
for commit in $commits; do git checkout $commit; cargo check --tests --examples --all --target=${{ matrix.target }}; done
|
||||
git checkout ${{ github.sha }}
|
||||
|
||||
- name: Formatting (rustfmt)
|
||||
@@ -62,28 +62,28 @@ jobs:
|
||||
with:
|
||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
||||
command: clippy
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Clippy (default features)
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
||||
command: clippy
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --tests -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --examples -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Clippy (default features + guest_debug)
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
||||
command: clippy
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --examples --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Clippy (default features + tracing)
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
||||
command: clippy
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --features "tracing" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --examples --features "tracing" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Clippy (mshv)
|
||||
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
with:
|
||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
||||
command: clippy
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --features "mshv" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "mshv" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Clippy (mshv + kvm)
|
||||
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
with:
|
||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
||||
command: clippy
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Clippy (kvm + tdx)
|
||||
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
with:
|
||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
||||
command: clippy
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --features "tdx,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "tdx,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Check build did not modify any files
|
||||
run: test -z "$(git status --porcelain)"
|
||||
|
||||
11
.github/workflows/release.yaml
vendored
11
.github/workflows/release.yaml
vendored
@@ -3,6 +3,7 @@ on: [pull_request, create]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: (github.event_name == 'create' && github.event.ref_type == 'tag') || github.event_name == 'pull_request'
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -15,29 +16,29 @@ jobs:
|
||||
- name: Install Rust toolchain (x86_64-unknown-linux-gnu)
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
toolchain: "1.67.1"
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- name: Install Rust toolchain (x86_64-unknown-linux-musl)
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
toolchain: "1.67.1"
|
||||
target: x86_64-unknown-linux-musl
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
toolchain: "1.67.1"
|
||||
command: build
|
||||
args: --all --release --no-default-features --features "kvm,mshv" --target=x86_64-unknown-linux-gnu
|
||||
- name: Static Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
toolchain: "1.67.1"
|
||||
command: build
|
||||
args: --all --release --no-default-features --features "kvm,mshv" --target=x86_64-unknown-linux-musl
|
||||
- name: Install Rust toolchain (aarch64-unknown-linux-musl)
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
toolchain: "1.67.1"
|
||||
target: aarch64-unknown-linux-musl
|
||||
override: true
|
||||
- name: Create Release
|
||||
|
||||
1527
Cargo.lock
generated
1527
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
37
Cargo.toml
37
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cloud-hypervisor"
|
||||
version = "29.0.0"
|
||||
version = "33.0.0"
|
||||
authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
default-run = "cloud-hypervisor"
|
||||
@@ -12,10 +12,10 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
||||
# Keep in sync with version in .github/workflows/build.yaml
|
||||
# Policy on MSRV (see #4318):
|
||||
# Can only be bumped by:
|
||||
# a.) A dependency requires it,
|
||||
# a.) A dependency requires it,
|
||||
# b.) If we want to use a new feature and that MSRV is at least 6 months old,
|
||||
# c.) There is a security issue that is addressed by the toolchain update.
|
||||
rust-version = "1.60"
|
||||
rust-version = "1.64"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
@@ -23,10 +23,16 @@ codegen-units = 1
|
||||
opt-level = "s"
|
||||
strip = true
|
||||
|
||||
[profile.profiling]
|
||||
inherits = "release"
|
||||
strip = false
|
||||
debug = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.68"
|
||||
anyhow = "1.0.71"
|
||||
api_client = { path = "api_client" }
|
||||
clap = { version = "4.0.32", features = ["wrap_help","cargo","string"] }
|
||||
argh = "0.1.9"
|
||||
dhat = { version = "0.3.2", optional = true }
|
||||
epoll = "4.3.1"
|
||||
event_monitor = { path = "event_monitor" }
|
||||
hypervisor = { path = "hypervisor" }
|
||||
@@ -34,30 +40,35 @@ libc = "0.2.139"
|
||||
log = { version = "0.4.17", features = ["std"] }
|
||||
option_parser = { path = "option_parser" }
|
||||
seccompiler = "0.3.0"
|
||||
serde_json = "1.0.89"
|
||||
signal-hook = "0.3.14"
|
||||
thiserror = "1.0.38"
|
||||
serde_json = "1.0.96"
|
||||
signal-hook = "0.3.15"
|
||||
thiserror = "1.0.40"
|
||||
tpm = { path = "tpm"}
|
||||
tracer = { path = "tracer" }
|
||||
vmm = { path = "vmm" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
vm-memory = "0.10.0"
|
||||
vm-memory = "0.11.0"
|
||||
zbus = { version = "3.11.1", optional = true }
|
||||
|
||||
# List of patched crates
|
||||
[patch.crates-io]
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" }
|
||||
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||
vhost = { git = "https://github.com/rust-vmm/vhost", branch = "main" }
|
||||
|
||||
[dev-dependencies]
|
||||
dirs = "4.0.0"
|
||||
dirs = "5.0.0"
|
||||
net_util = { path = "net_util" }
|
||||
once_cell = "1.16.0"
|
||||
serde_json = "1.0.89"
|
||||
once_cell = "1.17.1"
|
||||
serde_json = "1.0.96"
|
||||
test_infra = { path = "test_infra" }
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
[features]
|
||||
default = ["kvm"]
|
||||
dbus_api = ["zbus", "vmm/dbus_api"]
|
||||
dhat-heap = ["dhat"] # For heap profiling
|
||||
guest_debug = ["vmm/guest_debug"]
|
||||
kvm = ["vmm/kvm"]
|
||||
mshv = ["vmm/mshv"]
|
||||
@@ -66,7 +77,6 @@ tracing = ["vmm/tracing", "tracer/tracing"]
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"acpi_tables",
|
||||
"api_client",
|
||||
"arch",
|
||||
"block_util",
|
||||
@@ -83,7 +93,6 @@ members = [
|
||||
"serial_buffer",
|
||||
"test_infra",
|
||||
"tracer",
|
||||
"vfio_user",
|
||||
"vhdx",
|
||||
"vhost_user_block",
|
||||
"vhost_user_net",
|
||||
|
||||
5
Jenkinsfile
vendored
5
Jenkinsfile
vendored
@@ -1,6 +1,9 @@
|
||||
def runWorkers = true
|
||||
pipeline {
|
||||
agent none
|
||||
options {
|
||||
timeout(time: 4, unit: 'HOURS')
|
||||
}
|
||||
stages {
|
||||
stage('Early checks') {
|
||||
agent { node { label 'built-in' } }
|
||||
@@ -214,7 +217,7 @@ pipeline {
|
||||
stage('Download assets') {
|
||||
steps {
|
||||
sh "mkdir ${env.HOME}/workloads"
|
||||
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/windows-server-2019.raw" --name windows-server-2019.raw --connection-string "$AZURE_CONNECTION_STRING"'
|
||||
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/windows-server-2022-amd64-2.raw" --name windows-server-2022-amd64-2.raw --connection-string "$AZURE_CONNECTION_STRING"'
|
||||
}
|
||||
}
|
||||
stage('Run Windows guest integration tests') {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
- Sebastien Boeuf - @sboeuf
|
||||
- Robert Bradford - @rbradford
|
||||
- Bo Chen - @likebreath
|
||||
- Samuel Ortiz - @sameo
|
||||
- Wei Liu - @liuw
|
||||
- Michael Zhao - @michael2012z
|
||||
|
||||
23
README.md
23
README.md
@@ -113,7 +113,7 @@ Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) or an
|
||||
edk2 UEFI firmware called `CLOUDHV` / `CLOUDHV_EFI`.)
|
||||
|
||||
Binary builds of the firmware files are available for the latest release of
|
||||
[Rust Hyperivor
|
||||
[Rust Hypervisor
|
||||
Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/latest)
|
||||
and [our edk2
|
||||
repository](https://github.com/cloud-hypervisor/edk2/releases/latest)
|
||||
@@ -124,7 +124,7 @@ may be required.
|
||||
### Firmware Booting
|
||||
|
||||
Cloud Hypervisor supports booting disk images containing all needed components
|
||||
to run cloud workloads, a.k.a. cloud images.
|
||||
to run cloud workloads, a.k.a. cloud images.
|
||||
|
||||
The following sample commands will download an Ubuntu Cloud image, converting
|
||||
it into a format that Cloud Hypervisor can use and a firmware to boot the image
|
||||
@@ -140,14 +140,17 @@ The Ubuntu cloud images do not ship with a default password so it necessary to
|
||||
use a `cloud-init` disk image to customise the image on the first boot. A basic
|
||||
`cloud-init` image is generated by this [script](scripts/create-cloud-init.sh).
|
||||
This seeds the image with a default username/password of `cloud/cloud123`. It
|
||||
is only necessary to add this disk image on the first boot.
|
||||
is only necessary to add this disk image on the first boot. Script also assigns
|
||||
default IP address using `test_data/cloud-init/ubuntu/local/network-config` details
|
||||
with `--net "mac=12:34:56:78:90:ab,tap="` option. Then the matching mac address
|
||||
interface will be enabled as per `network-config` details.
|
||||
|
||||
```shell
|
||||
$ sudo setcap cap_net_admin+ep ./cloud-hypervisor
|
||||
$ ./create-cloud-init.sh
|
||||
$ ./cloud-hypervisor \
|
||||
--kernel ./hypervisor-fw \
|
||||
--disk path=focal-server-cloudimg-amd64.raw path=/tmp/ubuntu-cloudinit.img \
|
||||
--disk path=focal-server-cloudimg-amd64.raw --disk path=/tmp/ubuntu-cloudinit.img \
|
||||
--cpus boot=4 \
|
||||
--memory size=1024M \
|
||||
--net "tap=,mac=,ip=,mask="
|
||||
@@ -160,7 +163,7 @@ GRUB) is required then it necessary to switch to the serial console instead of
|
||||
```shell
|
||||
$ ./cloud-hypervisor \
|
||||
--kernel ./hypervisor-fw \
|
||||
--disk path=focal-server-cloudimg-amd64.raw path=/tmp/ubuntu-cloudinit.img \
|
||||
--disk path=focal-server-cloudimg-amd64.raw --disk path=/tmp/ubuntu-cloudinit.img \
|
||||
--cpus boot=4 \
|
||||
--memory size=1024M \
|
||||
--net "tap=,mac=,ip=,mask=" \
|
||||
@@ -178,7 +181,7 @@ To build the kernel:
|
||||
|
||||
```shell
|
||||
# Clone the Cloud Hypervisor Linux branch
|
||||
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-5.15.12 linux-cloud-hypervisor
|
||||
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-6.2 linux-cloud-hypervisor
|
||||
$ pushd linux-cloud-hypervisor
|
||||
# Use the x86-64 cloud-hypervisor kernel config to build your kernel for x86-64
|
||||
$ wget https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/main/resources/linux-config-x86_64
|
||||
@@ -222,7 +225,7 @@ $ sudo setcap cap_net_admin+ep ./cloud-hypervisor
|
||||
$ ./create-cloud-init.sh
|
||||
$ ./cloud-hypervisor \
|
||||
--kernel ./linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin \
|
||||
--disk path=focal-server-cloudimg-amd64.raw path=/tmp/ubuntu-cloudinit.img \
|
||||
--disk path=focal-server-cloudimg-amd64.raw --disk path=/tmp/ubuntu-cloudinit.img \
|
||||
--cmdline "console=hvc0 root=/dev/vda1 rw" \
|
||||
--cpus boot=4 \
|
||||
--memory size=1024M \
|
||||
@@ -236,7 +239,7 @@ $ sudo setcap cap_net_admin+ep ./cloud-hypervisor
|
||||
$ ./create-cloud-init.sh
|
||||
$ ./cloud-hypervisor \
|
||||
--kernel ./linux-cloud-hypervisor/arch/arm64/boot/Image \
|
||||
--disk path=focal-server-cloudimg-arm64.raw path=/tmp/ubuntu-cloudinit.img \
|
||||
--disk path=focal-server-cloudimg-arm64.raw --disk path=/tmp/ubuntu-cloudinit.img \
|
||||
--cmdline "console=hvc0 root=/dev/vda1 rw" \
|
||||
--cpus boot=4 \
|
||||
--memory size=1024M \
|
||||
@@ -372,8 +375,8 @@ are all equal and welcome means of contribution. See the
|
||||
|
||||
## Slack
|
||||
|
||||
Get an [invite to our Slack channel](https://join.slack.com/t/cloud-hypervisor/shared_invite/enQtNjY3MTE3MDkwNDQ4LWQ1MTA1ZDVmODkwMWQ1MTRhYzk4ZGNlN2UwNTI3ZmFlODU0OTcwOWZjMTkwZDExYWE3YjFmNzgzY2FmNDAyMjI)
|
||||
and [join us on Slack](https://cloud-hypervisor.slack.com/).
|
||||
Get an [invite to our Slack channel](https://join.slack.com/t/cloud-hypervisor/shared_invite/enQtNjY3MTE3MDkwNDQ4LWQ1MTA1ZDVmODkwMWQ1MTRhYzk4ZGNlN2UwNTI3ZmFlODU0OTcwOWZjMTkwZDExYWE3YjFmNzgzY2FmNDAyMjI),
|
||||
[join us on Slack](https://cloud-hypervisor.slack.com/), and [participate in our community activities](https://cloud-hypervisor.slack.com/archives/C04R5DUQVBN).
|
||||
|
||||
## Mailing list
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "acpi_tables"
|
||||
version = "0.1.0"
|
||||
authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
vm-memory = "0.10.0"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +0,0 @@
|
||||
// Copyright © 2019 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
pub mod aml;
|
||||
pub mod rsdp;
|
||||
pub mod sdt;
|
||||
|
||||
fn generate_checksum(data: &[u8]) -> u8 {
|
||||
(255 - data.iter().fold(0u8, |acc, x| acc.wrapping_add(*x))).wrapping_add(1)
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
// Copyright © 2019 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use vm_memory::ByteValued;
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub struct Rsdp {
|
||||
pub signature: [u8; 8],
|
||||
pub checksum: u8,
|
||||
pub oem_id: [u8; 6],
|
||||
pub revision: u8,
|
||||
_rsdt_addr: u32,
|
||||
pub length: u32,
|
||||
pub xsdt_addr: u64,
|
||||
pub extended_checksum: u8,
|
||||
_reserved: [u8; 3],
|
||||
}
|
||||
|
||||
// SAFETY: Rsdp only contains a series of integers
|
||||
unsafe impl ByteValued for Rsdp {}
|
||||
|
||||
impl Rsdp {
|
||||
pub fn new(oem_id: [u8; 6], xsdt_addr: u64) -> Self {
|
||||
let mut rsdp = Rsdp {
|
||||
signature: *b"RSD PTR ",
|
||||
checksum: 0,
|
||||
oem_id,
|
||||
revision: 2,
|
||||
_rsdt_addr: 0,
|
||||
length: std::mem::size_of::<Rsdp>() as u32,
|
||||
xsdt_addr,
|
||||
extended_checksum: 0,
|
||||
_reserved: [0; 3],
|
||||
};
|
||||
|
||||
rsdp.checksum = super::generate_checksum(&rsdp.as_slice()[0..19]);
|
||||
rsdp.extended_checksum = super::generate_checksum(rsdp.as_slice());
|
||||
rsdp
|
||||
}
|
||||
|
||||
pub fn len() -> usize {
|
||||
std::mem::size_of::<Rsdp>()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Rsdp;
|
||||
use vm_memory::bytes::ByteValued;
|
||||
|
||||
#[test]
|
||||
fn test_rsdp() {
|
||||
let rsdp = Rsdp::new(*b"CHYPER", 0xdead_beef);
|
||||
let sum = rsdp
|
||||
.as_slice()
|
||||
.iter()
|
||||
.fold(0u8, |acc, x| acc.wrapping_add(*x));
|
||||
assert_eq!(sum, 0);
|
||||
let sum: u8 = rsdp
|
||||
.as_slice()
|
||||
.iter()
|
||||
.fold(0u8, |acc, x| acc.wrapping_add(*x));
|
||||
assert_eq!(sum, 0);
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
// Copyright © 2019 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct GenericAddress {
|
||||
pub address_space_id: u8,
|
||||
pub register_bit_width: u8,
|
||||
pub register_bit_offset: u8,
|
||||
pub access_size: u8,
|
||||
pub address: u64,
|
||||
}
|
||||
|
||||
impl GenericAddress {
|
||||
pub fn io_port_address<T>(address: u16) -> Self {
|
||||
GenericAddress {
|
||||
address_space_id: 1,
|
||||
register_bit_width: 8 * std::mem::size_of::<T>() as u8,
|
||||
register_bit_offset: 0,
|
||||
access_size: std::mem::size_of::<T>() as u8,
|
||||
address: u64::from(address),
|
||||
}
|
||||
}
|
||||
pub fn mmio_address<T>(address: u64) -> Self {
|
||||
GenericAddress {
|
||||
address_space_id: 0,
|
||||
register_bit_width: 8 * std::mem::size_of::<T>() as u8,
|
||||
register_bit_offset: 0,
|
||||
access_size: std::mem::size_of::<T>() as u8,
|
||||
address,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Sdt {
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Sdt {
|
||||
pub fn new(
|
||||
signature: [u8; 4],
|
||||
length: u32,
|
||||
revision: u8,
|
||||
oem_id: [u8; 6],
|
||||
oem_table: [u8; 8],
|
||||
oem_revision: u32,
|
||||
) -> Self {
|
||||
assert!(length >= 36);
|
||||
|
||||
let mut data = Vec::with_capacity(length as usize);
|
||||
data.extend_from_slice(&signature);
|
||||
data.extend_from_slice(&length.to_le_bytes());
|
||||
data.push(revision);
|
||||
data.push(0); // checksum
|
||||
data.extend_from_slice(&oem_id);
|
||||
data.extend_from_slice(&oem_table);
|
||||
data.extend_from_slice(&oem_revision.to_le_bytes());
|
||||
data.extend_from_slice(b"CLDH");
|
||||
data.extend_from_slice(&0u32.to_le_bytes());
|
||||
assert_eq!(data.len(), 36);
|
||||
|
||||
data.resize(length as usize, 0);
|
||||
let mut sdt = Sdt { data };
|
||||
|
||||
sdt.update_checksum();
|
||||
sdt
|
||||
}
|
||||
|
||||
pub fn update_checksum(&mut self) {
|
||||
self.data[9] = 0;
|
||||
let checksum = super::generate_checksum(self.data.as_slice());
|
||||
self.data[9] = checksum
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
self.data.as_slice()
|
||||
}
|
||||
|
||||
pub fn append<T>(&mut self, value: T) {
|
||||
let orig_length = self.data.len();
|
||||
let new_length = orig_length + std::mem::size_of::<T>();
|
||||
self.data.resize(new_length, 0);
|
||||
self.write_u32(4, new_length as u32);
|
||||
self.write(orig_length, value);
|
||||
}
|
||||
|
||||
pub fn append_slice(&mut self, data: &[u8]) {
|
||||
let orig_length = self.data.len();
|
||||
let new_length = orig_length + data.len();
|
||||
self.write_u32(4, new_length as u32);
|
||||
self.data.extend_from_slice(data);
|
||||
self.update_checksum();
|
||||
}
|
||||
|
||||
/// Write a value at the given offset
|
||||
pub fn write<T>(&mut self, offset: usize, value: T) {
|
||||
assert!((offset + (std::mem::size_of::<T>() - 1)) < self.data.len());
|
||||
// SAFETY: The assertion above makes sure we don't do out of bounds write.
|
||||
unsafe {
|
||||
*(((self.data.as_mut_ptr() as usize) + offset) as *mut T) = value;
|
||||
}
|
||||
self.update_checksum();
|
||||
}
|
||||
|
||||
pub fn write_u8(&mut self, offset: usize, val: u8) {
|
||||
self.write(offset, val);
|
||||
}
|
||||
|
||||
pub fn write_u16(&mut self, offset: usize, val: u16) {
|
||||
self.write(offset, val);
|
||||
}
|
||||
|
||||
pub fn write_u32(&mut self, offset: usize, val: u32) {
|
||||
self.write(offset, val);
|
||||
}
|
||||
|
||||
pub fn write_u64(&mut self, offset: usize, val: u64) {
|
||||
self.write(offset, val);
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.data.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Sdt;
|
||||
|
||||
#[test]
|
||||
fn test_sdt() {
|
||||
let mut sdt = Sdt::new(*b"TEST", 40, 1, *b"CLOUDH", *b"TESTTEST", 1);
|
||||
let sum: u8 = sdt
|
||||
.as_slice()
|
||||
.iter()
|
||||
.fold(0u8, |acc, x| acc.wrapping_add(*x));
|
||||
assert_eq!(sum, 0);
|
||||
sdt.write_u32(36, 0x12345678);
|
||||
let sum: u8 = sdt
|
||||
.as_slice()
|
||||
.iter()
|
||||
.fold(0u8, |acc, x| acc.wrapping_add(*x));
|
||||
assert_eq!(sum, 0);
|
||||
}
|
||||
}
|
||||
@@ -9,18 +9,18 @@ default = []
|
||||
tdx = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.68"
|
||||
anyhow = "1.0.71"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.139"
|
||||
linux-loader = { version = "0.8.1", features = ["elf", "bzimage", "pe"] }
|
||||
linux-loader = { version = "0.9.0", features = ["elf", "bzimage", "pe"] }
|
||||
log = "0.4.17"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
thiserror = "1.0.38"
|
||||
uuid = "1.2.2"
|
||||
versionize = "0.1.9"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
thiserror = "1.0.40"
|
||||
uuid = "1.3.4"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ use super::layout::{
|
||||
IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START,
|
||||
PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
|
||||
};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use vm_fdt::{FdtWriter, FdtWriterResult};
|
||||
use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError, GuestMemoryRegion};
|
||||
|
||||
@@ -40,8 +42,12 @@ const VIRTIO_IOMMU_PHANDLE: u32 = 5;
|
||||
// NOTE: Keep FIRST_VCPU_PHANDLE the last PHANDLE defined.
|
||||
// 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 = 6;
|
||||
const FIRST_VCPU_PHANDLE: u32 = 8;
|
||||
|
||||
// This is a value for uniquely identifying the FDT node containing the L2 cache info
|
||||
const L2_CACHE_PHANDLE: u32 = 6;
|
||||
// This is a value for uniquely identifying the FDT node containing the L3 cache info
|
||||
const L3_CACHE_PHANDLE: u32 = 7;
|
||||
// Read the documentation specified when appending the root node to the FDT.
|
||||
const ADDRESS_CELLS: u32 = 0x2;
|
||||
const SIZE_CELLS: u32 = 0x2;
|
||||
@@ -81,6 +87,97 @@ pub enum Error {
|
||||
}
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
||||
pub enum CacheLevel {
|
||||
/// L1 data cache
|
||||
L1D = 0,
|
||||
/// L1 instruction cache
|
||||
L1I = 1,
|
||||
/// L2 cache
|
||||
L2 = 2,
|
||||
/// L3 cache
|
||||
L3 = 3,
|
||||
}
|
||||
|
||||
/// NOTE: CACHE SIZE file directory example,
|
||||
/// "/sys/devices/system/cpu/cpu0/cache/index0/size".
|
||||
pub fn get_cache_size(cache_level: CacheLevel) -> u32 {
|
||||
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
|
||||
match cache_level {
|
||||
CacheLevel::L1D => file_directory += "/index0/size",
|
||||
CacheLevel::L1I => file_directory += "/index1/size",
|
||||
CacheLevel::L2 => file_directory += "/index2/size",
|
||||
CacheLevel::L3 => file_directory += "/index3/size",
|
||||
}
|
||||
|
||||
let file_path = Path::new(&file_directory);
|
||||
if !file_path.exists() {
|
||||
error!("File: {} not exist.", file_directory);
|
||||
0
|
||||
} else {
|
||||
info!("File: {} exist.", file_directory);
|
||||
|
||||
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
|
||||
// The content of the file is as simple as a size, like: "32K"
|
||||
let src = src.trim();
|
||||
let src_digits: u32 = src[0..src.len() - 1].parse().unwrap();
|
||||
let src_unit = &src[src.len() - 1..];
|
||||
|
||||
src_digits
|
||||
* match src_unit {
|
||||
"K" => 1024,
|
||||
"M" => 1024u32.pow(2),
|
||||
"G" => 1024u32.pow(3),
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// NOTE: CACHE COHERENCY LINE SIZE file directory example,
|
||||
/// "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size".
|
||||
pub fn get_cache_coherency_line_size(cache_level: CacheLevel) -> u32 {
|
||||
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
|
||||
match cache_level {
|
||||
CacheLevel::L1D => file_directory += "/index0/coherency_line_size",
|
||||
CacheLevel::L1I => file_directory += "/index1/coherency_line_size",
|
||||
CacheLevel::L2 => file_directory += "/index2/coherency_line_size",
|
||||
CacheLevel::L3 => file_directory += "/index3/coherency_line_size",
|
||||
}
|
||||
|
||||
let file_path = Path::new(&file_directory);
|
||||
if !file_path.exists() {
|
||||
error!("File: {} not exist.", file_directory);
|
||||
0
|
||||
} else {
|
||||
info!("File: {} exist.", file_directory);
|
||||
|
||||
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
|
||||
src.trim().parse::<u32>().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// NOTE: CACHE NUMBER OF SETS file directory example,
|
||||
/// "/sys/devices/system/cpu/cpu0/cache/index0/number_of_sets".
|
||||
pub fn get_cache_number_of_sets(cache_level: CacheLevel) -> u32 {
|
||||
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
|
||||
match cache_level {
|
||||
CacheLevel::L1D => file_directory += "/index0/number_of_sets",
|
||||
CacheLevel::L1I => file_directory += "/index1/number_of_sets",
|
||||
CacheLevel::L2 => file_directory += "/index2/number_of_sets",
|
||||
CacheLevel::L3 => file_directory += "/index3/number_of_sets",
|
||||
}
|
||||
|
||||
let file_path = Path::new(&file_directory);
|
||||
if !file_path.exists() {
|
||||
error!("File: {} not exist.", file_directory);
|
||||
0
|
||||
} else {
|
||||
info!("File: {} exist.", file_directory);
|
||||
|
||||
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
|
||||
src.trim().parse::<u32>().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// 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>(
|
||||
@@ -159,6 +256,54 @@ fn create_cpu_nodes(
|
||||
|
||||
let num_cpus = vcpu_mpidr.len();
|
||||
|
||||
// Add cache info.
|
||||
// L1 Data Cache Info.
|
||||
let mut l1_d_cache_size: u32 = 0;
|
||||
let mut l1_d_cache_line_size: u32 = 0;
|
||||
let mut l1_d_cache_sets: u32 = 0;
|
||||
|
||||
// L1 Instruction Cache Info.
|
||||
let mut l1_i_cache_size: u32 = 0;
|
||||
let mut l1_i_cache_line_size: u32 = 0;
|
||||
let mut l1_i_cache_sets: u32 = 0;
|
||||
|
||||
// L2 Cache Info.
|
||||
let mut l2_cache_size: u32 = 0;
|
||||
let mut l2_cache_line_size: u32 = 0;
|
||||
let mut l2_cache_sets: u32 = 0;
|
||||
|
||||
// L3 Cache Info.
|
||||
let mut l3_cache_size: u32 = 0;
|
||||
let mut l3_cache_line_size: u32 = 0;
|
||||
let mut l3_cache_sets: u32 = 0;
|
||||
|
||||
let cache_path = Path::new("/sys/devices/system/cpu/cpu0/cache");
|
||||
let cache_exist: bool = cache_path.exists();
|
||||
if !cache_exist {
|
||||
error!("cache sysfs system does not exist.");
|
||||
} else {
|
||||
info!("cache sysfs system exists.");
|
||||
// L1 Data Cache Info.
|
||||
l1_d_cache_size = get_cache_size(CacheLevel::L1D);
|
||||
l1_d_cache_line_size = get_cache_coherency_line_size(CacheLevel::L1D);
|
||||
l1_d_cache_sets = get_cache_number_of_sets(CacheLevel::L1D);
|
||||
|
||||
// L1 Instruction Cache Info.
|
||||
l1_i_cache_size = get_cache_size(CacheLevel::L1I);
|
||||
l1_i_cache_line_size = get_cache_coherency_line_size(CacheLevel::L1I);
|
||||
l1_i_cache_sets = get_cache_number_of_sets(CacheLevel::L1I);
|
||||
|
||||
// L2 Cache Info.
|
||||
l2_cache_size = get_cache_size(CacheLevel::L2);
|
||||
l2_cache_line_size = get_cache_coherency_line_size(CacheLevel::L2);
|
||||
l2_cache_sets = get_cache_number_of_sets(CacheLevel::L2);
|
||||
|
||||
// L3 Cache Info.
|
||||
l3_cache_size = get_cache_size(CacheLevel::L3);
|
||||
l3_cache_line_size = get_cache_coherency_line_size(CacheLevel::L3);
|
||||
l3_cache_sets = get_cache_number_of_sets(CacheLevel::L3);
|
||||
}
|
||||
|
||||
for (cpu_id, mpidr) in vcpu_mpidr.iter().enumerate().take(num_cpus) {
|
||||
let cpu_name = format!("cpu@{cpu_id:x}");
|
||||
let cpu_node = fdt.begin_node(&cpu_name)?;
|
||||
@@ -173,6 +318,21 @@ fn create_cpu_nodes(
|
||||
fdt.property_u32("reg", (mpidr & 0x7FFFFF) as u32)?;
|
||||
fdt.property_u32("phandle", cpu_id as u32 + FIRST_VCPU_PHANDLE)?;
|
||||
|
||||
if cache_exist && l1_d_cache_size != 0 && l1_i_cache_size != 0 {
|
||||
// Add cache info.
|
||||
fdt.property_u32("d-cache-size", l1_d_cache_size)?;
|
||||
fdt.property_u32("d-cache-line-size", l1_d_cache_line_size)?;
|
||||
fdt.property_u32("d-cache-sets", l1_d_cache_sets)?;
|
||||
|
||||
fdt.property_u32("i-cache-size", l1_i_cache_size)?;
|
||||
fdt.property_u32("i-cache-line-size", l1_i_cache_line_size)?;
|
||||
fdt.property_u32("i-cache-sets", l1_i_cache_sets)?;
|
||||
|
||||
if l2_cache_size != 0 {
|
||||
fdt.property_u32("next-level-cache", L2_CACHE_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() {
|
||||
@@ -186,14 +346,48 @@ fn create_cpu_nodes(
|
||||
fdt.end_node(cpu_node)?;
|
||||
}
|
||||
|
||||
if cache_exist && l2_cache_size != 0 {
|
||||
let l2_cache_name = "l2-cache0";
|
||||
let l2_cache_node = fdt.begin_node(l2_cache_name)?;
|
||||
fdt.property_u32("phandle", L2_CACHE_PHANDLE)?;
|
||||
fdt.property_string("compatible", "cache")?;
|
||||
fdt.property_u32("cache-size", l2_cache_size)?;
|
||||
fdt.property_u32("cache-line-size", l2_cache_line_size)?;
|
||||
fdt.property_u32("cache-sets", l2_cache_sets)?;
|
||||
fdt.property_u32("cache-level", 2)?;
|
||||
|
||||
if l3_cache_size != 0 {
|
||||
fdt.property_u32("next-level-cache", L3_CACHE_PHANDLE)?;
|
||||
}
|
||||
|
||||
fdt.end_node(l2_cache_node)?;
|
||||
}
|
||||
|
||||
if cache_exist && l3_cache_size != 0 {
|
||||
let l3_cache_name = "l3-cache0";
|
||||
let l3_cache_node = fdt.begin_node(l3_cache_name)?;
|
||||
fdt.property_u32("phandle", L3_CACHE_PHANDLE)?;
|
||||
fdt.property_string("compatible", "cache")?;
|
||||
fdt.property_null("cache-unified")?;
|
||||
fdt.property_u32("cache-size", l3_cache_size)?;
|
||||
fdt.property_u32("cache-line-size", l3_cache_line_size)?;
|
||||
fdt.property_u32("cache-sets", l3_cache_sets)?;
|
||||
fdt.property_u32("cache-level", 3)?;
|
||||
fdt.end_node(l3_cache_node)?;
|
||||
}
|
||||
|
||||
if let Some(topology) = vcpu_topology {
|
||||
let (threads_per_core, cores_per_package, packages) = topology;
|
||||
let cpu_map_node = fdt.begin_node("cpu-map")?;
|
||||
|
||||
// Create device tree nodes with regard of above mapping.
|
||||
for cluster_idx in 0..packages {
|
||||
let cluster_name = format!("cluster{cluster_idx:x}");
|
||||
let cluster_node = fdt.begin_node(&cluster_name)?;
|
||||
for package_idx in 0..packages {
|
||||
let package_name = format!("socket{package_idx:x}");
|
||||
let package_node = fdt.begin_node(&package_name)?;
|
||||
|
||||
// Cluster is the container of cores, and it is mandatory in the CPU topology.
|
||||
// Add a default "cluster0" in each socket/package.
|
||||
let cluster_node = fdt.begin_node("cluster0")?;
|
||||
|
||||
for core_idx in 0..cores_per_package {
|
||||
let core_name = format!("core{core_idx:x}");
|
||||
@@ -202,7 +396,7 @@ fn create_cpu_nodes(
|
||||
for thread_idx in 0..threads_per_core {
|
||||
let thread_name = format!("thread{thread_idx:x}");
|
||||
let thread_node = fdt.begin_node(&thread_name)?;
|
||||
let cpu_idx = threads_per_core * cores_per_package * cluster_idx
|
||||
let cpu_idx = threads_per_core * cores_per_package * package_idx
|
||||
+ threads_per_core * core_idx
|
||||
+ thread_idx;
|
||||
fdt.property_u32("cpu", cpu_idx as u32 + FIRST_VCPU_PHANDLE)?;
|
||||
@@ -212,6 +406,7 @@ fn create_cpu_nodes(
|
||||
fdt.end_node(core_node)?;
|
||||
}
|
||||
fdt.end_node(cluster_node)?;
|
||||
fdt.end_node(package_node)?;
|
||||
}
|
||||
fdt.end_node(cpu_map_node)?;
|
||||
} else {
|
||||
@@ -255,32 +450,86 @@ fn create_memory_node(
|
||||
fdt.end_node(memory_node)?;
|
||||
}
|
||||
} else {
|
||||
let last_addr = guest_mem.last_addr().raw_value();
|
||||
if last_addr < super::layout::MEM_32BIT_RESERVED_START.raw_value() {
|
||||
// Case 1: all RAM is under the hole
|
||||
let mem_size = last_addr - super::layout::RAM_START.raw_value() + 1;
|
||||
let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
|
||||
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)?;
|
||||
} else {
|
||||
// Case 2: RAM is split by the hole
|
||||
// Region 1: RAM before the hole
|
||||
let mem_size = super::layout::MEM_32BIT_RESERVED_START.raw_value()
|
||||
- super::layout::RAM_START.raw_value();
|
||||
let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
|
||||
let memory_node_name = format!("memory@{:x}", super::layout::RAM_START.raw_value());
|
||||
// Note: memory regions from "GuestMemory" are sorted and non-zero sized.
|
||||
let ram_regions = {
|
||||
let mut ram_regions = Vec::new();
|
||||
let mut current_start = guest_mem
|
||||
.iter()
|
||||
.next()
|
||||
.map(GuestMemoryRegion::start_addr)
|
||||
.expect("GuestMemory must have one memory region at least")
|
||||
.raw_value();
|
||||
let mut current_end = current_start;
|
||||
|
||||
for (start, size) in guest_mem
|
||||
.iter()
|
||||
.map(|m| (m.start_addr().raw_value(), m.len()))
|
||||
{
|
||||
if current_end == start {
|
||||
// This zone is continuous with the previous one.
|
||||
current_end += size;
|
||||
} else {
|
||||
ram_regions.push((current_start, current_end));
|
||||
|
||||
current_start = start;
|
||||
current_end = start + size;
|
||||
}
|
||||
}
|
||||
|
||||
ram_regions.push((current_start, current_end));
|
||||
|
||||
ram_regions
|
||||
};
|
||||
|
||||
if ram_regions.len() > 2 {
|
||||
panic!(
|
||||
"There should be up to two non-continuous regions, devidided by the
|
||||
gap at the end of 32bit address space."
|
||||
);
|
||||
}
|
||||
|
||||
// Create the memory node for memory region before the gap
|
||||
{
|
||||
let (first_region_start, first_region_end) = ram_regions
|
||||
.first()
|
||||
.expect("There should be at last one memory region");
|
||||
let ram_start = super::layout::RAM_START.raw_value();
|
||||
let mem_32bit_reserved_start = super::layout::MEM_32BIT_RESERVED_START.raw_value();
|
||||
|
||||
if !((first_region_start <= &ram_start)
|
||||
&& (first_region_end > &ram_start)
|
||||
&& (first_region_end <= &mem_32bit_reserved_start))
|
||||
{
|
||||
panic!(
|
||||
"Unexpected first memory region layout: (start: 0x{:08x}, end: 0x{:08x}).
|
||||
ram_start: 0x{:08x}, mem_32bit_reserved_start: 0x{:08x}",
|
||||
first_region_start, first_region_end, ram_start, mem_32bit_reserved_start
|
||||
);
|
||||
}
|
||||
|
||||
let mem_size = first_region_end - ram_start;
|
||||
let mem_reg_prop = [ram_start, mem_size];
|
||||
let memory_node_name = format!("memory@{:x}", ram_start);
|
||||
let memory_node = fdt.begin_node(&memory_node_name)?;
|
||||
fdt.property_string("device_type", "memory")?;
|
||||
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
||||
fdt.end_node(memory_node)?;
|
||||
}
|
||||
|
||||
// Region 2: RAM after the hole
|
||||
let mem_size = last_addr - super::layout::RAM_64BIT_START.raw_value() + 1;
|
||||
let mem_reg_prop = [super::layout::RAM_64BIT_START.raw_value(), mem_size];
|
||||
let memory_node_name =
|
||||
format!("memory@{:x}", super::layout::RAM_64BIT_START.raw_value());
|
||||
// Create the memory map entry for memory region after the gap if any
|
||||
if let Some((second_region_start, second_region_end)) = ram_regions.get(1) {
|
||||
let ram_64bit_start = super::layout::RAM_64BIT_START.raw_value();
|
||||
|
||||
if second_region_start != &ram_64bit_start {
|
||||
panic!(
|
||||
"Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
|
||||
second_region_start, ram_64bit_start
|
||||
);
|
||||
}
|
||||
|
||||
let mem_size = second_region_end - ram_64bit_start;
|
||||
let mem_reg_prop = [ram_64bit_start, mem_size];
|
||||
let memory_node_name = format!("memory@{:x}", ram_64bit_start);
|
||||
let memory_node = fdt.begin_node(&memory_node_name)?;
|
||||
fdt.property_string("device_type", "memory")?;
|
||||
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
||||
|
||||
@@ -19,7 +19,9 @@ use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic, GuestUsize};
|
||||
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic};
|
||||
|
||||
pub const _NSIG: i32 = 65;
|
||||
|
||||
/// Errors thrown while configuring aarch64 system.
|
||||
#[derive(Debug)]
|
||||
@@ -81,8 +83,8 @@ pub fn configure_vcpu(
|
||||
Ok(mpidr)
|
||||
}
|
||||
|
||||
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
|
||||
let mut regions = vec![
|
||||
pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
|
||||
vec![
|
||||
// 0 MiB ~ 256 MiB: UEFI, GIC and legacy devices
|
||||
(
|
||||
GuestAddress(0),
|
||||
@@ -101,39 +103,21 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
|
||||
layout::PCI_MMCONFIG_SIZE as usize,
|
||||
RegionType::Reserved,
|
||||
),
|
||||
];
|
||||
|
||||
let ram_32bit_space_size =
|
||||
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START);
|
||||
|
||||
// RAM space
|
||||
// Case1: guest memory fits before the gap
|
||||
if size <= ram_32bit_space_size {
|
||||
regions.push((layout::RAM_START, size as usize, RegionType::Ram));
|
||||
// Case2: guest memory extends beyond the gap
|
||||
} else {
|
||||
// Push memory before the gap
|
||||
regions.push((
|
||||
// 1GiB ~ 4032 MiB: RAM before the gap
|
||||
(
|
||||
layout::RAM_START,
|
||||
ram_32bit_space_size as usize,
|
||||
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize,
|
||||
RegionType::Ram,
|
||||
));
|
||||
// Other memory is placed after 4GiB
|
||||
regions.push((
|
||||
layout::RAM_64BIT_START,
|
||||
(size - ram_32bit_space_size) as usize,
|
||||
RegionType::Ram,
|
||||
));
|
||||
}
|
||||
|
||||
// Add the 32-bit reserved memory hole as a reserved region
|
||||
regions.push((
|
||||
layout::MEM_32BIT_RESERVED_START,
|
||||
layout::MEM_32BIT_RESERVED_SIZE as usize,
|
||||
RegionType::Reserved,
|
||||
));
|
||||
|
||||
regions
|
||||
),
|
||||
// 4GiB ~ inf: RAM after the gap
|
||||
(layout::RAM_64BIT_START, usize::MAX, RegionType::Ram),
|
||||
// Add the 32-bit reserved memory hole as a reserved region
|
||||
(
|
||||
layout::MEM_32BIT_RESERVED_START,
|
||||
layout::MEM_32BIT_RESERVED_SIZE as usize,
|
||||
RegionType::Reserved,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
/// Configures the system and should be called once per vm before starting vcpu threads.
|
||||
@@ -196,11 +180,8 @@ pub fn initramfs_load_addr(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_host_cpu_phys_bits() -> u8 {
|
||||
// A dummy hypervisor created only for querying the host IPA size and will
|
||||
// be freed after the query.
|
||||
let hv = hypervisor::new().unwrap();
|
||||
let host_cpu_phys_bits = hv.get_host_ipa_limit().try_into().unwrap();
|
||||
pub fn get_host_cpu_phys_bits(hypervisor: &Arc<dyn hypervisor::Hypervisor>) -> u8 {
|
||||
let host_cpu_phys_bits = hypervisor.get_host_ipa_limit().try_into().unwrap();
|
||||
if host_cpu_phys_bits == 0 {
|
||||
// Host kernel does not support `get_host_ipa_limit`,
|
||||
// we return the default value 40 here.
|
||||
@@ -215,26 +196,12 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_arch_memory_regions_dram_2gb() {
|
||||
let regions = arch_memory_regions((1usize << 31) as u64); //2GB
|
||||
assert_eq!(5, regions.len());
|
||||
assert_eq!(layout::RAM_START, regions[3].0);
|
||||
assert_eq!((1usize << 31), regions[3].1);
|
||||
assert_eq!(RegionType::Ram, regions[3].2);
|
||||
assert_eq!(RegionType::Reserved, regions[4].2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arch_memory_regions_dram_4gb() {
|
||||
let regions = arch_memory_regions((1usize << 32) as u64); //4GB
|
||||
let ram_32bit_space_size =
|
||||
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize;
|
||||
fn test_arch_memory_regions_dram() {
|
||||
let regions = arch_memory_regions();
|
||||
assert_eq!(6, regions.len());
|
||||
assert_eq!(layout::RAM_START, regions[3].0);
|
||||
assert_eq!(ram_32bit_space_size, regions[3].1);
|
||||
assert_eq!(RegionType::Ram, regions[3].2);
|
||||
assert_eq!(RegionType::Reserved, regions[5].2);
|
||||
assert_eq!(RegionType::Ram, regions[4].2);
|
||||
assert_eq!(((1usize << 32) - ram_32bit_space_size), regions[4].1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
///
|
||||
/// AArch64 system register encoding:
|
||||
/// See https://developer.arm.com/documentation/ddi0487 (chapter D12)
|
||||
///
|
||||
/// 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
|
||||
/// +----------+---+-----+-----+-----+-----+-----+----+
|
||||
/// |1101010100| L | op0 | op1 | CRn | CRm | op2 | Rt |
|
||||
/// +----------+---+-----+-----+-----+-----+-----+----+
|
||||
///
|
||||
/// Notes:
|
||||
/// - L and Rt are reserved as implementation defined fields, ignored.
|
||||
///
|
||||
// AArch64 system register encoding:
|
||||
// See https://developer.arm.com/documentation/ddi0487 (chapter D12)
|
||||
//
|
||||
// 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
|
||||
// +----------+---+-----+-----+-----+-----+-----+----+
|
||||
// |1101010100| L | op0 | op1 | CRn | CRm | op2 | Rt |
|
||||
// +----------+---+-----+-----+-----+-----+-----+----+
|
||||
//
|
||||
// Notes:
|
||||
// - L and Rt are reserved as implementation defined fields, ignored.
|
||||
|
||||
const SYSREG_HEAD: u32 = 0b1101010100u32 << 22;
|
||||
const SYSREG_OP0_SHIFT: u32 = 19;
|
||||
const SYSREG_OP0_MASK: u32 = 0b11u32 << 19;
|
||||
|
||||
@@ -82,7 +82,7 @@ pub mod aarch64;
|
||||
pub use aarch64::{
|
||||
arch_memory_regions, configure_system, configure_vcpu, fdt::DeviceInfoForFdt,
|
||||
get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
|
||||
layout::IRQ_BASE, uefi, EntryPoint,
|
||||
layout::IRQ_BASE, uefi, EntryPoint, _NSIG,
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@@ -92,7 +92,7 @@ pub mod x86_64;
|
||||
pub use x86_64::{
|
||||
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,
|
||||
layout::CMDLINE_START, regs, CpuidFeatureEntry, EntryPoint, _NSIG,
|
||||
};
|
||||
|
||||
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::GuestMemoryMmap;
|
||||
use crate::InitramfsConfig;
|
||||
use crate::RegionType;
|
||||
use hypervisor::arch::x86::{CpuIdEntry, CPUID_FLAG_VALID_INDEX};
|
||||
use hypervisor::HypervisorError;
|
||||
use hypervisor::{CpuVendor, HypervisorCpuError, HypervisorError};
|
||||
use linux_loader::loader::bootparam::boot_params;
|
||||
use linux_loader::loader::elf::start_info::{
|
||||
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
|
||||
@@ -36,6 +36,7 @@ pub mod tdx;
|
||||
const TSC_DEADLINE_TIMER_ECX_BIT: u8 = 24; // tsc deadline timer ecx bit.
|
||||
const HYPERVISOR_ECX_BIT: u8 = 31; // Hypervisor ecx bit.
|
||||
const MTRR_EDX_BIT: u8 = 12; // Hypervisor ecx bit.
|
||||
const INVARIANT_TSC_EDX_BIT: u8 = 8; // Invariant TSC bit on 0x8000_0007 EDX
|
||||
|
||||
// KVM feature bits
|
||||
const KVM_FEATURE_ASYNC_PF_INT_BIT: u8 = 14;
|
||||
@@ -52,6 +53,8 @@ const KVM_FEATURE_ASYNC_PF_VMEXIT_BIT: u8 = 10;
|
||||
#[cfg(feature = "tdx")]
|
||||
const KVM_FEATURE_STEAL_TIME_BIT: u8 = 5;
|
||||
|
||||
pub const _NSIG: i32 = 65;
|
||||
|
||||
#[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
|
||||
@@ -193,6 +196,9 @@ pub enum Error {
|
||||
// Error writing EBDA address
|
||||
EbdaSetup(vm_memory::GuestMemoryError),
|
||||
|
||||
// Error getting CPU TSC frequency
|
||||
GetTscFrequency(HypervisorCpuError),
|
||||
|
||||
/// Error retrieving TDX capabilities through the hypervisor (kvm/mshv) API
|
||||
#[cfg(feature = "tdx")]
|
||||
TdxCapabilities(HypervisorError),
|
||||
@@ -204,7 +210,6 @@ impl From<Error> for super::Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum CpuidReg {
|
||||
EAX,
|
||||
@@ -605,7 +610,9 @@ pub fn generate_common_cpuid(
|
||||
];
|
||||
|
||||
// Supported CPUID
|
||||
let mut cpuid = hypervisor.get_cpuid().map_err(Error::CpuidGetSupported)?;
|
||||
let mut cpuid = hypervisor
|
||||
.get_supported_cpuid()
|
||||
.map_err(Error::CpuidGetSupported)?;
|
||||
|
||||
CpuidPatch::patch_cpuid(&mut cpuid, cpuid_patches);
|
||||
|
||||
@@ -768,6 +775,41 @@ pub fn configure_vcpu(
|
||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
|
||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
|
||||
|
||||
// Set ApicId in cpuid for each vcpu
|
||||
// SAFETY: get host cpuid when eax=1
|
||||
let mut cpu_ebx = unsafe { core::arch::x86_64::__cpuid(1) }.ebx;
|
||||
cpu_ebx &= 0xffffff;
|
||||
cpu_ebx |= (id as u32) << 24;
|
||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
|
||||
|
||||
// The TSC frequency CPUID leaf should not be included when running with HyperV emulation
|
||||
if !kvm_hyperv {
|
||||
if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? {
|
||||
// Need to check that the TSC doesn't vary with dynamic frequency
|
||||
// SAFETY: cpuid called with valid leaves
|
||||
if unsafe { std::arch::x86_64::__cpuid(0x8000_0007) }.edx
|
||||
& (1u32 << INVARIANT_TSC_EDX_BIT)
|
||||
> 0
|
||||
{
|
||||
CpuidPatch::set_cpuid_reg(
|
||||
&mut cpuid,
|
||||
0x4000_0000,
|
||||
None,
|
||||
CpuidReg::EAX,
|
||||
0x4000_0010,
|
||||
);
|
||||
cpuid.retain(|c| c.function != 0x4000_0010);
|
||||
cpuid.push(CpuIdEntry {
|
||||
function: 0x4000_0010,
|
||||
eax: tsc_khz,
|
||||
ebx: 1000000, /* LAPIC resolution of 1ns (freq: 1GHz) is hardcoded in KVM's
|
||||
* APIC_BUS_CYCLE_NS */
|
||||
..Default::default()
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
vcpu.set_cpuid2(&cpuid)
|
||||
.map_err(|e| Error::SetSupportedCpusFailed(e.into()))?;
|
||||
|
||||
@@ -792,47 +834,29 @@ pub fn configure_vcpu(
|
||||
/// These should be used to configure the GuestMemory structure for the platform.
|
||||
/// For x86_64 all addresses are valid from the start of the kernel except a
|
||||
/// carve out at the end of 32bit address space.
|
||||
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
|
||||
let reserved_memory_gap_start = layout::MEM_32BIT_RESERVED_START
|
||||
.checked_add(layout::MEM_32BIT_DEVICES_SIZE)
|
||||
.expect("32-bit reserved region is too large");
|
||||
|
||||
let requested_memory_size = GuestAddress(size);
|
||||
let mut regions = Vec::new();
|
||||
|
||||
// case1: guest memory fits before the gap
|
||||
if size <= layout::MEM_32BIT_RESERVED_START.raw_value() {
|
||||
regions.push((GuestAddress(0), size as usize, RegionType::Ram));
|
||||
// case2: guest memory extends beyond the gap
|
||||
} else {
|
||||
// push memory before the gap
|
||||
regions.push((
|
||||
pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
|
||||
vec![
|
||||
// 0 GiB ~ 3GiB: memory before the gap
|
||||
(
|
||||
GuestAddress(0),
|
||||
layout::MEM_32BIT_RESERVED_START.raw_value() as usize,
|
||||
RegionType::Ram,
|
||||
));
|
||||
regions.push((
|
||||
layout::RAM_64BIT_START,
|
||||
requested_memory_size.unchecked_offset_from(layout::MEM_32BIT_RESERVED_START) as usize,
|
||||
RegionType::Ram,
|
||||
));
|
||||
}
|
||||
|
||||
// Add the 32-bit device memory hole as a sub region.
|
||||
regions.push((
|
||||
layout::MEM_32BIT_RESERVED_START,
|
||||
layout::MEM_32BIT_DEVICES_SIZE as usize,
|
||||
RegionType::SubRegion,
|
||||
));
|
||||
|
||||
// Add the 32-bit reserved memory hole as a sub region.
|
||||
regions.push((
|
||||
reserved_memory_gap_start,
|
||||
(layout::MEM_32BIT_RESERVED_SIZE - layout::MEM_32BIT_DEVICES_SIZE) as usize,
|
||||
RegionType::Reserved,
|
||||
));
|
||||
|
||||
regions
|
||||
),
|
||||
// 4 GiB ~ inf: memory after the gap
|
||||
(layout::RAM_64BIT_START, usize::MAX, RegionType::Ram),
|
||||
// 3 GiB ~ 3712 MiB: 32-bit device memory hole
|
||||
(
|
||||
layout::MEM_32BIT_RESERVED_START,
|
||||
layout::MEM_32BIT_DEVICES_SIZE as usize,
|
||||
RegionType::SubRegion,
|
||||
),
|
||||
// 3712 MiB ~ 3968 MiB: 32-bit reserved memory hole
|
||||
(
|
||||
layout::MEM_32BIT_RESERVED_START.unchecked_add(layout::MEM_32BIT_DEVICES_SIZE),
|
||||
(layout::MEM_32BIT_RESERVED_SIZE - layout::MEM_32BIT_DEVICES_SIZE) as usize,
|
||||
RegionType::Reserved,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
/// Configures the system and should be called once per vm before starting vcpu threads.
|
||||
@@ -930,30 +954,102 @@ fn configure_pvh(
|
||||
// Create the memory map entries.
|
||||
add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM);
|
||||
|
||||
let mem_end = guest_mem.last_addr();
|
||||
// Merge continuous memory regions into one region.
|
||||
// Note: memory regions from "GuestMemory" are sorted and non-zero sized.
|
||||
let ram_regions = {
|
||||
let mut ram_regions = Vec::new();
|
||||
let mut current_start = guest_mem
|
||||
.iter()
|
||||
.next()
|
||||
.map(GuestMemoryRegion::start_addr)
|
||||
.expect("GuestMemory must have one memory region at least")
|
||||
.raw_value();
|
||||
let mut current_end = current_start;
|
||||
|
||||
if mem_end < layout::MEM_32BIT_RESERVED_START {
|
||||
add_memmap_entry(
|
||||
&mut memmap,
|
||||
layout::HIGH_RAM_START.raw_value(),
|
||||
mem_end.unchecked_offset_from(layout::HIGH_RAM_START) + 1,
|
||||
E820_RAM,
|
||||
);
|
||||
} else {
|
||||
add_memmap_entry(
|
||||
&mut memmap,
|
||||
layout::HIGH_RAM_START.raw_value(),
|
||||
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::HIGH_RAM_START),
|
||||
E820_RAM,
|
||||
);
|
||||
if mem_end > layout::RAM_64BIT_START {
|
||||
add_memmap_entry(
|
||||
&mut memmap,
|
||||
layout::RAM_64BIT_START.raw_value(),
|
||||
mem_end.unchecked_offset_from(layout::RAM_64BIT_START) + 1,
|
||||
E820_RAM,
|
||||
);
|
||||
for (start, size) in guest_mem
|
||||
.iter()
|
||||
.map(|m| (m.start_addr().raw_value(), m.len()))
|
||||
{
|
||||
if current_end == start {
|
||||
// This zone is continuous with the previous one.
|
||||
current_end += size;
|
||||
} else {
|
||||
ram_regions.push((current_start, current_end));
|
||||
|
||||
current_start = start;
|
||||
current_end = start + size;
|
||||
}
|
||||
}
|
||||
|
||||
ram_regions.push((current_start, current_end));
|
||||
|
||||
ram_regions
|
||||
};
|
||||
|
||||
if ram_regions.len() > 2 {
|
||||
error!(
|
||||
"There should be up to two non-continuous regions, devidided by the
|
||||
gap at the end of 32bit address space (e.g. between 3G and 4G)."
|
||||
);
|
||||
return Err(super::Error::MemmapTableSetup);
|
||||
}
|
||||
|
||||
// Create the memory map entry for memory region before the gap
|
||||
{
|
||||
let (first_region_start, first_region_end) =
|
||||
ram_regions.first().ok_or(super::Error::MemmapTableSetup)?;
|
||||
let high_ram_start = layout::HIGH_RAM_START.raw_value();
|
||||
let mem_32bit_reserved_start = layout::MEM_32BIT_RESERVED_START.raw_value();
|
||||
|
||||
if !((first_region_start <= &high_ram_start)
|
||||
&& (first_region_end > &high_ram_start)
|
||||
&& (first_region_end <= &mem_32bit_reserved_start))
|
||||
{
|
||||
error!(
|
||||
"Unexpected first memory region layout: (start: 0x{:08x}, end: 0x{:08x}).
|
||||
high_ram_start: 0x{:08x}, mem_32bit_reserved_start: 0x{:08x}",
|
||||
first_region_start, first_region_end, high_ram_start, mem_32bit_reserved_start
|
||||
);
|
||||
|
||||
return Err(super::Error::MemmapTableSetup);
|
||||
}
|
||||
|
||||
info!(
|
||||
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x})",
|
||||
high_ram_start, first_region_end
|
||||
);
|
||||
|
||||
add_memmap_entry(
|
||||
&mut memmap,
|
||||
high_ram_start,
|
||||
first_region_end - high_ram_start,
|
||||
E820_RAM,
|
||||
);
|
||||
}
|
||||
|
||||
// Create the memory map entry for memory region after the gap if any
|
||||
if let Some((second_region_start, second_region_end)) = ram_regions.get(1) {
|
||||
let ram_64bit_start = layout::RAM_64BIT_START.raw_value();
|
||||
|
||||
if second_region_start != &ram_64bit_start {
|
||||
error!(
|
||||
"Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
|
||||
second_region_start, ram_64bit_start
|
||||
);
|
||||
|
||||
return Err(super::Error::MemmapTableSetup);
|
||||
}
|
||||
|
||||
info!(
|
||||
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x})",
|
||||
ram_64bit_start, second_region_end
|
||||
);
|
||||
add_memmap_entry(
|
||||
&mut memmap,
|
||||
ram_64bit_start,
|
||||
second_region_end - ram_64bit_start,
|
||||
E820_RAM,
|
||||
);
|
||||
}
|
||||
|
||||
add_memmap_entry(
|
||||
@@ -1043,7 +1139,7 @@ pub fn initramfs_load_addr(
|
||||
Ok(aligned_addr)
|
||||
}
|
||||
|
||||
pub fn get_host_cpu_phys_bits() -> u8 {
|
||||
pub fn get_host_cpu_phys_bits(hypervisor: &Arc<dyn hypervisor::Hypervisor>) -> u8 {
|
||||
// SAFETY: call cpuid with valid leaves
|
||||
unsafe {
|
||||
let leaf = x86_64::__cpuid(0x8000_0000);
|
||||
@@ -1052,9 +1148,7 @@ pub fn get_host_cpu_phys_bits() -> u8 {
|
||||
// Some physical address bits may become reserved when the feature is enabled.
|
||||
// See AMD64 Architecture Programmer's Manual Volume 2, Section 7.10.1
|
||||
let reduced = if leaf.eax >= 0x8000_001f
|
||||
&& leaf.ebx == 0x6874_7541 // Vendor ID: AuthenticAMD
|
||||
&& leaf.ecx == 0x444d_4163
|
||||
&& leaf.edx == 0x6974_6e65
|
||||
&& matches!(hypervisor.get_cpu_vendor(), CpuVendor::AMD)
|
||||
&& x86_64::__cpuid(0x8000_001f).eax & 0x1 != 0
|
||||
{
|
||||
(x86_64::__cpuid(0x8000_001f).ebx >> 6) & 0x3f
|
||||
@@ -1189,16 +1283,8 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn regions_lt_4gb() {
|
||||
let regions = arch_memory_regions(1 << 29);
|
||||
assert_eq!(3, regions.len());
|
||||
assert_eq!(GuestAddress(0), regions[0].0);
|
||||
assert_eq!(1usize << 29, regions[0].1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regions_gt_4gb() {
|
||||
let regions = arch_memory_regions((1 << 32) + 0x8000);
|
||||
fn regions_base_addr() {
|
||||
let regions = arch_memory_regions();
|
||||
assert_eq!(4, regions.len());
|
||||
assert_eq!(GuestAddress(0), regions[0].0);
|
||||
assert_eq!(GuestAddress(1 << 32), regions[1].0);
|
||||
@@ -1222,11 +1308,10 @@ mod tests {
|
||||
assert!(config_err.is_err());
|
||||
|
||||
// Now assigning some memory that falls before the 32bit memory hole.
|
||||
let mem_size = 128 << 20;
|
||||
let arch_mem_regions = arch_memory_regions(mem_size);
|
||||
let arch_mem_regions = arch_memory_regions();
|
||||
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
||||
.iter()
|
||||
.filter(|r| r.2 == RegionType::Ram)
|
||||
.filter(|r| r.2 == RegionType::Ram && r.1 != usize::MAX)
|
||||
.map(|r| (r.0, r.1))
|
||||
.collect();
|
||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||
@@ -1244,48 +1329,18 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Now assigning some memory that is equal to the start of the 32bit memory hole.
|
||||
let mem_size = 3328 << 20;
|
||||
let arch_mem_regions = arch_memory_regions(mem_size);
|
||||
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
||||
.iter()
|
||||
.filter(|r| r.2 == RegionType::Ram)
|
||||
.map(|r| (r.0, r.1))
|
||||
.collect();
|
||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||
configure_system(
|
||||
&gm,
|
||||
GuestAddress(0),
|
||||
&None,
|
||||
no_vcpus,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
configure_system(
|
||||
&gm,
|
||||
GuestAddress(0),
|
||||
&None,
|
||||
no_vcpus,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Now assigning some memory that falls after the 32bit memory hole.
|
||||
let mem_size = 3330 << 20;
|
||||
let arch_mem_regions = arch_memory_regions(mem_size);
|
||||
let arch_mem_regions = arch_memory_regions();
|
||||
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
||||
.iter()
|
||||
.filter(|r| r.2 == RegionType::Ram)
|
||||
.map(|r| (r.0, r.1))
|
||||
.map(|r| {
|
||||
if r.1 == usize::MAX {
|
||||
(r.0, 128 << 20)
|
||||
} else {
|
||||
(r.0, r.1)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||
configure_system(
|
||||
|
||||
@@ -55,7 +55,7 @@ pub struct TdvfSection {
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub enum TdvfSectionType {
|
||||
Bfv,
|
||||
Cfv,
|
||||
@@ -64,15 +64,10 @@ pub enum TdvfSectionType {
|
||||
PermMem,
|
||||
Payload,
|
||||
PayloadParam,
|
||||
#[default]
|
||||
Reserved = 0xffffffff,
|
||||
}
|
||||
|
||||
impl Default for TdvfSectionType {
|
||||
fn default() -> Self {
|
||||
TdvfSectionType::Reserved
|
||||
}
|
||||
}
|
||||
|
||||
fn tdvf_descriptor_offset(file: &mut File) -> Result<(SeekFrom, bool), TdvfError> {
|
||||
// Let's first try to identify the presence of the table footer GUID
|
||||
file.seek(SeekFrom::End(-0x30))
|
||||
@@ -202,21 +197,16 @@ pub fn parse_tdvf_sections(file: &mut File) -> Result<(Vec<TdvfSection>, bool),
|
||||
}
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
enum HobType {
|
||||
Handoff = 0x1,
|
||||
ResourceDescriptor = 0x3,
|
||||
GuidExtension = 0x4,
|
||||
#[default]
|
||||
Unused = 0xfffe,
|
||||
EndOfHobList = 0xffff,
|
||||
}
|
||||
|
||||
impl Default for HobType {
|
||||
fn default() -> Self {
|
||||
HobType::Unused
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
struct HobHeader {
|
||||
@@ -266,19 +256,14 @@ struct HobGuidType {
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub enum PayloadImageType {
|
||||
#[default]
|
||||
ExecutablePayload,
|
||||
BzImage,
|
||||
RawVmLinux,
|
||||
}
|
||||
|
||||
impl Default for PayloadImageType {
|
||||
fn default() -> Self {
|
||||
PayloadImageType::ExecutablePayload
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
pub struct PayloadInfo {
|
||||
|
||||
@@ -8,18 +8,18 @@ edition = "2021"
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
io-uring = "0.5.11"
|
||||
io-uring = "0.5.13"
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
qcow = { path = "../qcow" }
|
||||
smallvec = "1.10.0"
|
||||
thiserror = "1.0.38"
|
||||
versionize = "0.1.9"
|
||||
thiserror = "1.0.40"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
|
||||
virtio-queue = "0.7.0"
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
|
||||
virtio-queue = "0.8.0"
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ use std::time::Instant;
|
||||
use thiserror::Error;
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use virtio_bindings::bindings::virtio_blk::*;
|
||||
use virtio_bindings::virtio_blk::*;
|
||||
use virtio_queue::DescriptorChain;
|
||||
use vm_memory::{
|
||||
bitmap::AtomicBitmap, bitmap::Bitmap, ByteValued, Bytes, GuestAddress, GuestMemory,
|
||||
@@ -201,7 +201,7 @@ pub struct Request {
|
||||
pub data_descriptors: SmallVec<[(GuestAddress, u32); 1]>,
|
||||
pub status_addr: GuestAddress,
|
||||
pub writeback: bool,
|
||||
pub aligned_operations: Vec<AlignedOperation>,
|
||||
pub aligned_operations: SmallVec<[AlignedOperation; 1]>,
|
||||
pub start: Instant,
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ impl Request {
|
||||
data_descriptors: SmallVec::with_capacity(1),
|
||||
status_addr: GuestAddress(0),
|
||||
writeback: true,
|
||||
aligned_operations: Vec::new(),
|
||||
aligned_operations: SmallVec::with_capacity(1),
|
||||
start: Instant::now(),
|
||||
};
|
||||
|
||||
@@ -602,7 +602,7 @@ where
|
||||
completion_list: &mut VecDeque<(u64, i32)>,
|
||||
) -> AsyncIoResult<()> {
|
||||
// Convert libc::iovec into IoSliceMut
|
||||
let mut slices = Vec::new();
|
||||
let mut slices: SmallVec<[IoSliceMut; 1]> = SmallVec::with_capacity(iovecs.len());
|
||||
for iovec in iovecs.iter() {
|
||||
// SAFETY: on Linux IoSliceMut wraps around libc::iovec
|
||||
slices.push(IoSliceMut::new(unsafe { std::mem::transmute(*iovec) }));
|
||||
@@ -635,9 +635,9 @@ where
|
||||
completion_list: &mut VecDeque<(u64, i32)>,
|
||||
) -> AsyncIoResult<()> {
|
||||
// Convert libc::iovec into IoSlice
|
||||
let mut slices = Vec::new();
|
||||
let mut slices: SmallVec<[IoSlice; 1]> = SmallVec::with_capacity(iovecs.len());
|
||||
for iovec in iovecs.iter() {
|
||||
// SAFETY: on Linux IoSliceMut wraps around libc::iovec
|
||||
// SAFETY: on Linux IoSlice wraps around libc::iovec
|
||||
slices.push(IoSlice::new(unsafe { std::mem::transmute(*iovec) }));
|
||||
}
|
||||
|
||||
|
||||
4
build.rs
4
build.rs
@@ -17,8 +17,8 @@ fn main() {
|
||||
}
|
||||
|
||||
// This println!() has a special behavior, as it will set the environment
|
||||
// variable BUILT_VERSION, so that it can be reused from the binary.
|
||||
// variable BUILD_VERSION, so that it can be reused from the binary.
|
||||
// Particularly, this is used from src/main.rs to display the exact
|
||||
// version.
|
||||
println!("cargo:rustc-env=BUILT_VERSION={version}");
|
||||
println!("cargo:rustc-env=BUILD_VERSION={version}");
|
||||
}
|
||||
|
||||
@@ -5,21 +5,20 @@ authors = ["The Chromium OS Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { path = "../acpi_tables" }
|
||||
anyhow = "1.0.68"
|
||||
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
|
||||
anyhow = "1.0.71"
|
||||
arch = { path = "../arch" }
|
||||
bitflags = "1.3.2"
|
||||
bitflags = "2.3.3"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
phf = { version = "0.11.1", features = ["macros"] }
|
||||
thiserror = "1.0.38"
|
||||
thiserror = "1.0.40"
|
||||
tpm = { path = "../tpm" }
|
||||
versionize = "0.1.9"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = "0.10.0"
|
||||
vm-memory = "0.11.0"
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//
|
||||
|
||||
use super::AcpiNotificationFlags;
|
||||
use acpi_tables::{aml, aml::Aml};
|
||||
use acpi_tables::{aml, Aml, AmlSink};
|
||||
use std::sync::{Arc, Barrier};
|
||||
use std::time::Instant;
|
||||
use vm_device::interrupt::InterruptSourceGroup;
|
||||
@@ -103,11 +103,11 @@ impl BusDevice for AcpiGedDevice {
|
||||
}
|
||||
|
||||
impl Aml for AcpiGedDevice {
|
||||
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
|
||||
fn to_aml_bytes(&self, sink: &mut dyn AmlSink) {
|
||||
aml::Device::new(
|
||||
"_SB_.GEC_".into(),
|
||||
vec![
|
||||
&aml::Name::new("_HID".into(), &aml::EisaName::new("PNP0A06")),
|
||||
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A06")),
|
||||
&aml::Name::new("_UID".into(), &"Generic Event Controller"),
|
||||
&aml::Name::new(
|
||||
"_CRS".into(),
|
||||
@@ -116,17 +116,19 @@ impl Aml for AcpiGedDevice {
|
||||
true,
|
||||
self.address.0,
|
||||
self.address.0 + GED_DEVICE_ACPI_SIZE as u64 - 1,
|
||||
None,
|
||||
)]),
|
||||
),
|
||||
&aml::OpRegion::new(
|
||||
"GDST".into(),
|
||||
aml::OpRegionSpace::SystemMemory,
|
||||
self.address.0 as usize,
|
||||
GED_DEVICE_ACPI_SIZE,
|
||||
&(self.address.0 as usize),
|
||||
&GED_DEVICE_ACPI_SIZE,
|
||||
),
|
||||
&aml::Field::new(
|
||||
"GDST".into(),
|
||||
aml::FieldAccessType::Byte,
|
||||
aml::FieldLockRule::NoLock,
|
||||
aml::FieldUpdateRule::WriteAsZeroes,
|
||||
vec![aml::FieldEntry::Named(*b"GDAT", 8)],
|
||||
),
|
||||
@@ -163,7 +165,7 @@ impl Aml for AcpiGedDevice {
|
||||
),
|
||||
],
|
||||
)
|
||||
.append_aml_bytes(bytes);
|
||||
.to_aml_bytes(sink);
|
||||
aml::Device::new(
|
||||
"_SB_.GED_".into(),
|
||||
vec![
|
||||
@@ -187,7 +189,7 @@ impl Aml for AcpiGedDevice {
|
||||
),
|
||||
],
|
||||
)
|
||||
.append_aml_bytes(bytes)
|
||||
.to_aml_bytes(sink)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,13 +8,11 @@ use anyhow::anyhow;
|
||||
use arch::aarch64::layout::{TPM_SIZE, TPM_START};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use arch::x86_64::layout::{TPM_SIZE, TPM_START};
|
||||
use phf::phf_map;
|
||||
use std::cmp;
|
||||
use std::sync::{Arc, Barrier};
|
||||
use thiserror::Error;
|
||||
use tpm::emulator::{BackendCmd, Emulator};
|
||||
use tpm::TPM_CRB_BUFFER_MAX;
|
||||
use tpm::TPM_SUCCESS;
|
||||
use vm_device::BusDevice;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@@ -23,62 +21,135 @@ pub enum Error {
|
||||
CheckCaps(#[source] anyhow::Error),
|
||||
#[error("Failed to initialize tpm: {0}")]
|
||||
Init(#[source] anyhow::Error),
|
||||
#[error("Failed to deliver tpm Command: {0}")]
|
||||
DeliverRequest(#[source] anyhow::Error),
|
||||
}
|
||||
type Result<T> = anyhow::Result<T, Error>;
|
||||
|
||||
#[allow(dead_code)]
|
||||
enum LocStateFields {
|
||||
TpmEstablished,
|
||||
LocAssigned,
|
||||
ActiveLocality,
|
||||
Reserved,
|
||||
TpmRegValidSts,
|
||||
}
|
||||
|
||||
enum LocStsFields {
|
||||
Granted,
|
||||
BeenSeized,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
enum IntfIdFields {
|
||||
InterfaceType,
|
||||
InterfaceVersion,
|
||||
CapLocality,
|
||||
CapCRBIdleBypass,
|
||||
Reserved1,
|
||||
CapDataXferSizeSupport,
|
||||
CapFIFO,
|
||||
CapCRB,
|
||||
CapIFRes,
|
||||
InterfaceSelector,
|
||||
IntfSelLock,
|
||||
Reserved2,
|
||||
Rid,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
enum IntfId2Fields {
|
||||
Vid,
|
||||
Did,
|
||||
}
|
||||
|
||||
enum CtrlStsFields {
|
||||
TpmSts,
|
||||
TpmIdle,
|
||||
}
|
||||
|
||||
enum CrbRegister {
|
||||
LocState(LocStateFields),
|
||||
LocSts(LocStsFields),
|
||||
IntfId(IntfIdFields),
|
||||
IntfId2(IntfId2Fields),
|
||||
CtrlSts(CtrlStsFields),
|
||||
}
|
||||
|
||||
/* crb 32-bit registers */
|
||||
const CRB_LOC_STATE: u32 = 0x0;
|
||||
//Register Fields
|
||||
// Field => (start, length)
|
||||
// start: lowest bit in the bit field numbered from 0
|
||||
// Field => (base, offset, length)
|
||||
// base: starting position of the register
|
||||
// offset: lowest bit in the bit field numbered from 0
|
||||
// length: length of the bit field
|
||||
const CRB_LOC_STATE_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
|
||||
"tpmEstablished" => [0, 1],
|
||||
"locAssigned" => [1,1],
|
||||
"activeLocality"=> [2, 3],
|
||||
"reserved" => [5, 2],
|
||||
"tpmRegValidSts" => [7, 1]
|
||||
};
|
||||
const fn get_crb_loc_state_field(f: LocStateFields) -> (u32, u32, u32) {
|
||||
let (offset, len) = match f {
|
||||
LocStateFields::TpmEstablished => (0, 1),
|
||||
LocStateFields::LocAssigned => (1, 1),
|
||||
LocStateFields::ActiveLocality => (2, 3),
|
||||
LocStateFields::Reserved => (5, 2),
|
||||
LocStateFields::TpmRegValidSts => (7, 1),
|
||||
};
|
||||
|
||||
(CRB_LOC_STATE, offset, len)
|
||||
}
|
||||
|
||||
const CRB_LOC_CTRL: u32 = 0x08;
|
||||
const CRB_LOC_CTRL_REQUEST_ACCESS: u32 = 1 << 0;
|
||||
const CRB_LOC_CTRL_RELINQUISH: u32 = 1 << 1;
|
||||
const CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT: u32 = 1 << 3;
|
||||
const CRB_LOC_STS: u32 = 0x0C;
|
||||
const CRB_LOC_STS_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
|
||||
"Granted" => [0, 1],
|
||||
"beenSeized" => [1,1]
|
||||
};
|
||||
const fn get_crb_loc_sts_field(f: LocStsFields) -> (u32, u32, u32) {
|
||||
let (offset, len) = match f {
|
||||
LocStsFields::Granted => (0, 1),
|
||||
LocStsFields::BeenSeized => (1, 1),
|
||||
};
|
||||
|
||||
(CRB_LOC_STS, offset, len)
|
||||
}
|
||||
|
||||
const CRB_INTF_ID: u32 = 0x30;
|
||||
const CRB_INTF_ID_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
|
||||
"InterfaceType" => [0, 4],
|
||||
"InterfaceVersion" => [4, 4],
|
||||
"CapLocality" => [8, 1],
|
||||
"CapCRBIdleBypass" => [9, 1],
|
||||
"Reserved1" => [10, 1],
|
||||
"CapDataXferSizeSupport" => [11, 2],
|
||||
"CapFIFO" => [13, 1],
|
||||
"CapCRB" => [14, 1],
|
||||
"CapIFRes" => [15, 2],
|
||||
"InterfaceSelector" => [17, 2],
|
||||
"IntfSelLock" => [19, 1],
|
||||
"Reserved2" => [20, 4],
|
||||
"RID" => [24, 8]
|
||||
};
|
||||
const fn get_crb_intf_id_field(f: IntfIdFields) -> (u32, u32, u32) {
|
||||
let (offset, len) = match f {
|
||||
IntfIdFields::InterfaceType => (0, 4),
|
||||
IntfIdFields::InterfaceVersion => (4, 4),
|
||||
IntfIdFields::CapLocality => (8, 1),
|
||||
IntfIdFields::CapCRBIdleBypass => (9, 1),
|
||||
IntfIdFields::Reserved1 => (10, 1),
|
||||
IntfIdFields::CapDataXferSizeSupport => (11, 2),
|
||||
IntfIdFields::CapFIFO => (13, 1),
|
||||
IntfIdFields::CapCRB => (14, 1),
|
||||
IntfIdFields::CapIFRes => (15, 2),
|
||||
IntfIdFields::InterfaceSelector => (17, 2),
|
||||
IntfIdFields::IntfSelLock => (19, 1),
|
||||
IntfIdFields::Reserved2 => (20, 4),
|
||||
IntfIdFields::Rid => (24, 8),
|
||||
};
|
||||
|
||||
(CRB_INTF_ID, offset, len)
|
||||
}
|
||||
|
||||
const CRB_INTF_ID2: u32 = 0x34;
|
||||
const CRB_INTF_ID2_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
|
||||
"VID" => [0, 16],
|
||||
"DID" => [16, 16]
|
||||
};
|
||||
const fn get_crb_intf_id2_field(f: IntfId2Fields) -> (u32, u32, u32) {
|
||||
let (offset, len) = match f {
|
||||
IntfId2Fields::Vid => (0, 16),
|
||||
IntfId2Fields::Did => (16, 16),
|
||||
};
|
||||
|
||||
(CRB_INTF_ID2, offset, len)
|
||||
}
|
||||
|
||||
const CRB_CTRL_REQ: u32 = 0x40;
|
||||
const CRB_CTRL_REQ_CMD_READY: u32 = 1 << 0;
|
||||
const CRB_CTRL_REQ_GO_IDLE: u32 = 1 << 1;
|
||||
const CRB_CTRL_STS: u32 = 0x44;
|
||||
const CRB_CTRL_STS_FIELDS: phf::Map<&str, [u32; 2]> = phf_map! {
|
||||
"tpmSts" => [0, 1],
|
||||
"tpmIdle" => [1, 1]
|
||||
};
|
||||
const fn get_crb_ctrl_sts_field(f: CtrlStsFields) -> (u32, u32, u32) {
|
||||
let (offset, len) = match f {
|
||||
CtrlStsFields::TpmSts => (0, 1),
|
||||
CtrlStsFields::TpmIdle => (1, 1),
|
||||
};
|
||||
|
||||
(CRB_CTRL_STS, offset, len)
|
||||
}
|
||||
const CRB_CTRL_CANCEL: u32 = 0x48;
|
||||
const CRB_CANCEL_INVOKE: u32 = 1 << 0;
|
||||
const CRB_CTRL_START: u32 = 0x4C;
|
||||
@@ -94,7 +165,7 @@ const TPM_CRB_NO_LOCALITY: u32 = 0xff;
|
||||
const TPM_CRB_ADDR_BASE: u32 = TPM_START.0 as u32;
|
||||
const TPM_CRB_ADDR_SIZE: usize = TPM_SIZE as usize;
|
||||
|
||||
const TPM_CRB_R_MAX: u32 = CRB_DATA_BUFFER;
|
||||
const TPM_CRB_R_MAX: usize = CRB_DATA_BUFFER as usize;
|
||||
|
||||
// CRB Protocol details
|
||||
const CRB_INTF_TYPE_CRB_ACTIVE: u32 = 0b1;
|
||||
@@ -109,47 +180,29 @@ const PCI_VENDOR_ID_IBM: u32 = 0x1014;
|
||||
const CRB_CTRL_CMD_SIZE_REG: u32 = 0x58;
|
||||
const CRB_CTRL_CMD_SIZE: usize = TPM_CRB_ADDR_SIZE - CRB_DATA_BUFFER as usize;
|
||||
|
||||
fn get_fields_map(reg: u32) -> phf::Map<&'static str, [u32; 2]> {
|
||||
// Returns (register base, offset, len)
|
||||
const fn get_field(reg: CrbRegister) -> (u32, u32, u32) {
|
||||
match reg {
|
||||
CRB_LOC_STATE => CRB_LOC_STATE_FIELDS,
|
||||
CRB_LOC_STS => CRB_LOC_STS_FIELDS,
|
||||
CRB_INTF_ID => CRB_INTF_ID_FIELDS,
|
||||
CRB_INTF_ID2 => CRB_INTF_ID2_FIELDS,
|
||||
CRB_CTRL_STS => CRB_CTRL_STS_FIELDS,
|
||||
_ => {
|
||||
panic!("Fields in '{reg:?}' register were accessed which are Invalid");
|
||||
}
|
||||
CrbRegister::LocState(f) => get_crb_loc_state_field(f),
|
||||
CrbRegister::LocSts(f) => get_crb_loc_sts_field(f),
|
||||
CrbRegister::IntfId(f) => get_crb_intf_id_field(f),
|
||||
CrbRegister::IntfId2(f) => get_crb_intf_id2_field(f),
|
||||
CrbRegister::CtrlSts(f) => get_crb_ctrl_sts_field(f),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a particular field in a Register
|
||||
fn set_reg_field(regs: &mut [u32; TPM_CRB_R_MAX as usize], reg: u32, field: &str, value: u32) {
|
||||
let reg_fields = get_fields_map(reg);
|
||||
if reg_fields.contains_key(field) {
|
||||
let start = reg_fields.get(field).unwrap()[0];
|
||||
let len = reg_fields.get(field).unwrap()[1];
|
||||
let mask = (!(0_u32) >> (32 - len)) << start;
|
||||
regs[reg as usize] = (regs[reg as usize] & !mask) | ((value << start) & mask);
|
||||
} else {
|
||||
error!(
|
||||
"Failed to tpm Register. {:?} is not a valid field in Reg {:#X}",
|
||||
field, reg
|
||||
)
|
||||
}
|
||||
// Set a particular field in a Register
|
||||
fn set_reg_field(regs: &mut [u32; TPM_CRB_R_MAX], reg: CrbRegister, value: u32) {
|
||||
let (base, offset, len) = get_field(reg);
|
||||
let mask = (!(0_u32) >> (32 - len)) << offset;
|
||||
regs[base as usize] = (regs[base as usize] & !mask) | ((value << offset) & mask);
|
||||
}
|
||||
|
||||
/// Get the value of a particular field in a Register
|
||||
fn get_reg_field(regs: &[u32; TPM_CRB_R_MAX as usize], reg: u32, field: &str) -> u32 {
|
||||
let reg_fields = get_fields_map(reg);
|
||||
if reg_fields.contains_key(field) {
|
||||
let start = reg_fields.get(field).unwrap()[0];
|
||||
let len = reg_fields.get(field).unwrap()[1];
|
||||
let mask = (!(0_u32) >> (32 - len)) << start;
|
||||
(regs[reg as usize] & mask) >> start
|
||||
} else {
|
||||
// TODO: Sensible return value if fields do not exist
|
||||
0x0
|
||||
}
|
||||
// Get the value of a particular field in a Register
|
||||
const fn get_reg_field(regs: &[u32; TPM_CRB_R_MAX], reg: CrbRegister) -> u32 {
|
||||
let (base, offset, len) = get_field(reg);
|
||||
let mask = (!(0_u32) >> (32 - len)) << offset;
|
||||
(regs[base as usize] & mask) >> offset
|
||||
}
|
||||
|
||||
fn locality_from_addr(addr: u32) -> u8 {
|
||||
@@ -158,8 +211,7 @@ fn locality_from_addr(addr: u32) -> u8 {
|
||||
|
||||
pub struct Tpm {
|
||||
emulator: Emulator,
|
||||
cmd: Option<BackendCmd>,
|
||||
regs: [u32; TPM_CRB_R_MAX as usize],
|
||||
regs: [u32; TPM_CRB_R_MAX],
|
||||
backend_buff_size: usize,
|
||||
data_buff: [u8; TPM_CRB_BUFFER_MAX],
|
||||
data_buff_len: usize,
|
||||
@@ -171,8 +223,7 @@ impl Tpm {
|
||||
.map_err(|e| Error::Init(anyhow!("Failed while initializing tpm Emulator: {:?}", e)))?;
|
||||
let mut tpm = Tpm {
|
||||
emulator,
|
||||
cmd: None,
|
||||
regs: [0; TPM_CRB_R_MAX as usize],
|
||||
regs: [0; TPM_CRB_R_MAX],
|
||||
backend_buff_size: TPM_CRB_BUFFER_MAX,
|
||||
data_buff: [0; TPM_CRB_BUFFER_MAX],
|
||||
data_buff_len: 0,
|
||||
@@ -182,74 +233,93 @@ impl Tpm {
|
||||
}
|
||||
|
||||
fn get_active_locality(&mut self) -> u32 {
|
||||
if get_reg_field(&self.regs, CRB_LOC_STATE, "locAssigned") == 0 {
|
||||
if get_reg_field(
|
||||
&self.regs,
|
||||
CrbRegister::LocState(LocStateFields::LocAssigned),
|
||||
) == 0
|
||||
{
|
||||
return TPM_CRB_NO_LOCALITY;
|
||||
}
|
||||
get_reg_field(&self.regs, CRB_LOC_STATE, "activeLocality")
|
||||
get_reg_field(
|
||||
&self.regs,
|
||||
CrbRegister::LocState(LocStateFields::ActiveLocality),
|
||||
)
|
||||
}
|
||||
|
||||
fn request_completed(&mut self, result: isize) {
|
||||
fn request_completed(&mut self, success: bool) {
|
||||
self.regs[CRB_CTRL_START as usize] = !CRB_START_INVOKE;
|
||||
if result != 0 {
|
||||
set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmSts", 1);
|
||||
if !success {
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CrbRegister::CtrlSts(CtrlStsFields::TpmSts),
|
||||
1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> Result<()> {
|
||||
let cur_buff_size = self.emulator.get_buffer_size().unwrap();
|
||||
self.regs = [0; TPM_CRB_R_MAX as usize];
|
||||
set_reg_field(&mut self.regs, CRB_LOC_STATE, "tpmRegValidSts", 1);
|
||||
set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 1);
|
||||
let cur_buff_size = self.emulator.get_buffer_size();
|
||||
self.regs = [0; TPM_CRB_R_MAX];
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"InterfaceType",
|
||||
CrbRegister::LocState(LocStateFields::TpmRegValidSts),
|
||||
1,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CrbRegister::CtrlSts(CtrlStsFields::TpmIdle),
|
||||
1,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CrbRegister::IntfId(IntfIdFields::InterfaceType),
|
||||
CRB_INTF_TYPE_CRB_ACTIVE,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"InterfaceVersion",
|
||||
CrbRegister::IntfId(IntfIdFields::InterfaceVersion),
|
||||
CRB_INTF_VERSION_CRB,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"CapLocality",
|
||||
CrbRegister::IntfId(IntfIdFields::CapLocality),
|
||||
CRB_INTF_CAP_LOCALITY_0_ONLY,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"CapCRBIdleBypass",
|
||||
CrbRegister::IntfId(IntfIdFields::CapCRBIdleBypass),
|
||||
CRB_INTF_CAP_IDLE_FAST,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"CapDataXferSizeSupport",
|
||||
CrbRegister::IntfId(IntfIdFields::CapDataXferSizeSupport),
|
||||
CRB_INTF_CAP_XFER_SIZE_64,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"CapFIFO",
|
||||
CrbRegister::IntfId(IntfIdFields::CapFIFO),
|
||||
CRB_INTF_CAP_FIFO_NOT_SUPPORTED,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"CapCRB",
|
||||
CrbRegister::IntfId(IntfIdFields::CapCRB),
|
||||
CRB_INTF_CAP_CRB_SUPPORTED,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CRB_INTF_ID,
|
||||
"InterfaceSelector",
|
||||
CrbRegister::IntfId(IntfIdFields::InterfaceSelector),
|
||||
CRB_INTF_IF_SELECTOR_CRB,
|
||||
);
|
||||
set_reg_field(&mut self.regs, CRB_INTF_ID, "RID", 0b0000);
|
||||
set_reg_field(&mut self.regs, CRB_INTF_ID2, "VID", PCI_VENDOR_ID_IBM);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CrbRegister::IntfId(IntfIdFields::Rid),
|
||||
0b0000,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CrbRegister::IntfId2(IntfId2Fields::Vid),
|
||||
PCI_VENDOR_ID_IBM,
|
||||
);
|
||||
|
||||
self.regs[CRB_CTRL_CMD_SIZE_REG as usize] = CRB_CTRL_CMD_SIZE as u32;
|
||||
self.regs[CRB_CTRL_CMD_LADDR as usize] = TPM_CRB_ADDR_BASE + CRB_DATA_BUFFER;
|
||||
@@ -268,7 +338,6 @@ impl Tpm {
|
||||
}
|
||||
}
|
||||
|
||||
//impl BusDevice for TPM
|
||||
impl BusDevice for Tpm {
|
||||
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
||||
let mut offset: u32 = offset as u32;
|
||||
@@ -367,10 +436,18 @@ impl BusDevice for Tpm {
|
||||
}
|
||||
CRB_CTRL_REQ => match v {
|
||||
CRB_CTRL_REQ_CMD_READY => {
|
||||
set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 0);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CrbRegister::CtrlSts(CtrlStsFields::TpmIdle),
|
||||
0,
|
||||
);
|
||||
}
|
||||
CRB_CTRL_REQ_GO_IDLE => {
|
||||
set_reg_field(&mut self.regs, CRB_CTRL_STS, "tpmIdle", 1);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CrbRegister::CtrlSts(CtrlStsFields::TpmIdle),
|
||||
1,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
error!("Invalid value passed to CRTL_REQ register");
|
||||
@@ -393,27 +470,14 @@ impl BusDevice for Tpm {
|
||||
{
|
||||
self.regs[CRB_CTRL_START as usize] |= CRB_START_INVOKE;
|
||||
|
||||
self.cmd = Some(BackendCmd {
|
||||
locality: locality as u8,
|
||||
input: self.data_buff[0..self.data_buff_len].to_vec(),
|
||||
let mut cmd = BackendCmd {
|
||||
buffer: &mut self.data_buff,
|
||||
input_len: cmp::min(self.data_buff_len, TPM_CRB_BUFFER_MAX),
|
||||
output: self.data_buff.to_vec(),
|
||||
output_len: TPM_CRB_BUFFER_MAX,
|
||||
selftest_done: false,
|
||||
});
|
||||
};
|
||||
|
||||
let mut cmd = self.cmd.as_ref().unwrap().clone();
|
||||
let output = self.emulator.deliver_request(&mut cmd).map_err(|e| {
|
||||
Error::DeliverRequest(anyhow!(
|
||||
"Failed to deliver tpm request. Error :{:?}",
|
||||
e
|
||||
))
|
||||
});
|
||||
//TODO: drop the copy here
|
||||
self.data_buff.fill(0);
|
||||
self.data_buff.clone_from_slice(output.unwrap().as_slice());
|
||||
let status = self.emulator.deliver_request(&mut cmd).is_ok();
|
||||
|
||||
self.request_completed(TPM_SUCCESS as isize);
|
||||
self.request_completed(status);
|
||||
}
|
||||
}
|
||||
CRB_LOC_CTRL => {
|
||||
@@ -424,13 +488,33 @@ impl BusDevice for Tpm {
|
||||
match v {
|
||||
CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT => {}
|
||||
CRB_LOC_CTRL_RELINQUISH => {
|
||||
set_reg_field(&mut self.regs, CRB_LOC_STATE, "locAssigned", 0);
|
||||
set_reg_field(&mut self.regs, CRB_LOC_STS, "Granted", 0);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CrbRegister::LocState(LocStateFields::LocAssigned),
|
||||
0,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CrbRegister::LocSts(LocStsFields::Granted),
|
||||
0,
|
||||
);
|
||||
}
|
||||
CRB_LOC_CTRL_REQUEST_ACCESS => {
|
||||
set_reg_field(&mut self.regs, CRB_LOC_STS, "Granted", 1);
|
||||
set_reg_field(&mut self.regs, CRB_LOC_STS, "beenSeized", 0);
|
||||
set_reg_field(&mut self.regs, CRB_LOC_STATE, "locAssigned", 1);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CrbRegister::LocSts(LocStsFields::Granted),
|
||||
1,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CrbRegister::LocSts(LocStsFields::BeenSeized),
|
||||
0,
|
||||
);
|
||||
set_reg_field(
|
||||
&mut self.regs,
|
||||
CrbRegister::LocState(LocStateFields::LocAssigned),
|
||||
1,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
error!("Invalid value to write in CRB_LOC_CTRL {:#X} ", v);
|
||||
@@ -456,10 +540,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_set_get_reg_field() {
|
||||
let mut regs: [u32; TPM_CRB_R_MAX as usize] = [0; TPM_CRB_R_MAX as usize];
|
||||
set_reg_field(&mut regs, CRB_INTF_ID, "RID", 0xAC);
|
||||
let mut regs: [u32; TPM_CRB_R_MAX] = [0; TPM_CRB_R_MAX];
|
||||
set_reg_field(&mut regs, CrbRegister::IntfId(IntfIdFields::Rid), 0xAC);
|
||||
assert_eq!(
|
||||
get_reg_field(®s, CRB_INTF_ID, "RID"),
|
||||
get_reg_field(®s, CrbRegister::IntfId(IntfIdFields::Rid)),
|
||||
0xAC,
|
||||
concat!("Test: ", stringify!(set_get_reg_field))
|
||||
);
|
||||
|
||||
223
docs/api.md
223
docs/api.md
@@ -1,18 +1,21 @@
|
||||
- [Cloud Hypervisor API](#cloud-hypervisor-api)
|
||||
- [External API](#external-api)
|
||||
- [REST API](#rest-api)
|
||||
- [Location and availability](#location-and-availability)
|
||||
- [Endpoints](#endpoints)
|
||||
- [Virtual Machine Manager (VMM) Actions](#virtual-machine-manager-vmm-actions)
|
||||
- [Virtual Machine (VM) Actions](#virtual-machine-vm-actions)
|
||||
- [REST API Examples](#rest-api-examples)
|
||||
- [Create a Virtual Machine](#create-a-virtual-machine)
|
||||
- [Boot a Virtual Machine](#boot-a-virtual-machine)
|
||||
- [Dump a Virtual Machine Information](#dump-a-virtual-machine-information)
|
||||
- [Reboot a Virtual Machine](#reboot-a-virtual-machine)
|
||||
- [Shut a Virtual Machine Down](#shut-a-virtual-machine-down)
|
||||
- [REST API Location and availability](#rest-api-location-and-availability)
|
||||
- [REST API Endpoints](#rest-api-endpoints)
|
||||
- [Virtual Machine Manager (VMM) Actions](#virtual-machine-manager-vmm-actions)
|
||||
- [Virtual Machine (VM) Actions](#virtual-machine-vm-actions)
|
||||
- [REST API Examples](#rest-api-examples)
|
||||
- [Create a Virtual Machine](#create-a-virtual-machine)
|
||||
- [Boot a Virtual Machine](#boot-a-virtual-machine)
|
||||
- [Dump a Virtual Machine Information](#dump-a-virtual-machine-information)
|
||||
- [Reboot a Virtual Machine](#reboot-a-virtual-machine)
|
||||
- [Shut a Virtual Machine Down](#shut-a-virtual-machine-down)
|
||||
- [D-Bus API](#d-bus-api)
|
||||
- [D-Bus API Location and availability](#d-bus-api-location-and-availability)
|
||||
- [D-Bus API Interface](#d-bus-api-interface)
|
||||
- [Command Line Interface](#command-line-interface)
|
||||
- [REST API and CLI Architectural Relationship](#rest-api-and-cli-architectural-relationship)
|
||||
- [REST API, D-Bus API and CLI Architectural Relationship](#rest-api-and-cli-architectural-relationship)
|
||||
- [Internal API](#internal-api)
|
||||
- [Goals and Design](#goals-and-design)
|
||||
- [End to End Example](#end-to-end-example)
|
||||
@@ -21,9 +24,11 @@
|
||||
|
||||
The Cloud Hypervisor API is made of 2 distinct interfaces:
|
||||
|
||||
1. **The external API**. This is the user facing API. Users and operators can
|
||||
control and manage Cloud Hypervisor through either a REST API or a Command
|
||||
Line Interface (CLI).
|
||||
1. **The External API** This is the user facing API. Users and operators
|
||||
can control and manage the Cloud Hypervisor through various options
|
||||
including a REST API, a Command Line Interface (CLI) or a D-Bus based API,
|
||||
which is not compiled into Cloud Hypervisor by default.
|
||||
|
||||
1. **The internal API**, based on [rust's Multi-Producer, Single-Consumer (MPSC)](https://doc.rust-lang.org/std/sync/mpsc/)
|
||||
module. This API is used internally by the Cloud Hypervisor threads to
|
||||
communicate between each others.
|
||||
@@ -40,10 +45,10 @@ API triggers VM and VMM specific actions, and as such it is designed as a
|
||||
collection of RPC-style, static methods.
|
||||
|
||||
The API is [OpenAPI 3.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md)
|
||||
compliant. Please consult the [Cloud Hypervisor API](https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/master/vmm/src/api/openapi/cloud-hypervisor.yaml)
|
||||
document for more details about the API payloads and responses.
|
||||
compliant. Please consult the [Cloud Hypervisor OpenAPI Document](https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/master/vmm/src/api/openapi/cloud-hypervisor.yaml)
|
||||
for more details about the API payloads and responses.
|
||||
|
||||
### Location and availability
|
||||
#### REST API Location and availability
|
||||
|
||||
The REST API is available as soon as the Cloud Hypervisor binary is started,
|
||||
through a local UNIX socket.
|
||||
@@ -65,48 +70,55 @@ Cloud Hypervisor Guest
|
||||
Disk(s): None
|
||||
```
|
||||
|
||||
### Endpoints
|
||||
#### REST API Endpoints
|
||||
|
||||
The Cloud Hypervisor API exposes the following actions through its endpoints:
|
||||
|
||||
#### Virtual Machine Manager (VMM) Actions
|
||||
##### Virtual Machine Manager (VMM) Actions
|
||||
|
||||
| Action | Endpoint | Request Body | Response Body | Prerequisites |
|
||||
| ----------------------------------- | --------------- | ------------ | -------------------------- | ------------------ |
|
||||
| Check for the REST API availability | `/vmm.ping` | N/A | `/schemas/VmmPingResponse` | N/A |
|
||||
| Shut the VMM down | `/vmm.shutdown` | N/A | N/A | The VMM is running |
|
||||
|
||||
#### Virtual Machine (VM) Actions
|
||||
##### 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 |
|
||||
| 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 |
|
||||
| Task a snapshot of the VM | `/vm.snapshot` | `/schemas/VmSnapshotConfig` | N/A | The VM is paused |
|
||||
| Perform a coredump of the VM | `/vm.coredump` | `/schemas/VmCoredumpData` | N/A | The VM is paused |
|
||||
| Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted |
|
||||
| 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 vdpa device to the VM | `/vm.add-vdpa` | `/schemas/VdpaConfig` | `/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 |
|
||||
| Task a snapshot of the VM | `/vm.snapshot` | `/schemas/VmSnapshotConfig` | N/A | The VM is paused |
|
||||
| Perform a coredump of the VM* | `/vm.coredump` | `/schemas/VmCoredumpData` | N/A | The VM is paused |
|
||||
| Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted |
|
||||
| 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 vdpa device to the VM | `/vm.add-vdpa` | `/schemas/VdpaConfig` | `/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 |
|
||||
| Prepare to receive a migration | `/vm.receive-migration` | `/schemas/ReceiveMigrationData` | N/A | N/A |
|
||||
| Start to send migration to target | `/vm.send-migration` | `/schemas/SendMigrationData` | N/A | The VM is booted and (shared mem or hugepages enabled) |
|
||||
|
||||
### REST API Examples
|
||||
* The `vmcoredump` action is available exclusively for the `x86_64`
|
||||
architecture and can be executed only when the `guest_debug` feature is
|
||||
enabled. Without this feature, the corresponding [REST API](#rest-api) or
|
||||
[D-Bus API](#d-bus-api) endpoints are not available.
|
||||
|
||||
#### REST API Examples
|
||||
|
||||
For the following set of examples, we assume Cloud Hypervisor is started with
|
||||
the REST API available at `/tmp/cloud-hypervisor.sock`:
|
||||
@@ -122,7 +134,7 @@ Cloud Hypervisor Guest
|
||||
Disk(s): None
|
||||
```
|
||||
|
||||
#### Create a Virtual Machine
|
||||
##### Create a Virtual Machine
|
||||
|
||||
We want to create a virtual machine with the following characteristics:
|
||||
|
||||
@@ -150,7 +162,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||
}'
|
||||
```
|
||||
|
||||
#### Boot a Virtual Machine
|
||||
##### Boot a Virtual Machine
|
||||
|
||||
Once the VM is created, we can boot it:
|
||||
|
||||
@@ -160,7 +172,7 @@ Once the VM is created, we can boot it:
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.boot'
|
||||
```
|
||||
|
||||
#### Dump a Virtual Machine Information
|
||||
##### Dump a Virtual Machine Information
|
||||
|
||||
We can fetch information about any VM, as soon as it's created:
|
||||
|
||||
@@ -172,7 +184,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||
-H 'Accept: application/json'
|
||||
```
|
||||
|
||||
#### Reboot a Virtual Machine
|
||||
##### Reboot a Virtual Machine
|
||||
|
||||
We can reboot a VM that's already booted:
|
||||
|
||||
@@ -182,7 +194,7 @@ We can reboot a VM that's already booted:
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.reboot'
|
||||
```
|
||||
|
||||
#### Shut a Virtual Machine Down
|
||||
##### Shut a Virtual Machine Down
|
||||
|
||||
Once booted, we can shut a VM down from the REST API:
|
||||
|
||||
@@ -192,6 +204,50 @@ Once booted, we can shut a VM down from the REST API:
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.shutdown'
|
||||
```
|
||||
|
||||
### D-Bus API
|
||||
|
||||
Cloud Hypervisor offers a D-Bus API as an alternative to its REST API. As of
|
||||
writing this document, the D-Bus API mirrors the functionality of the REST
|
||||
API and shares the same set of endpoints, meaning that it supports every call
|
||||
that is supported by the REST API and can be a drop-in replacement since it
|
||||
also consumes/produces JSON.
|
||||
|
||||
#### D-Bus API Location and availability
|
||||
|
||||
This feature is not compiled into Cloud Hypervisor by default. Users who
|
||||
wish to use the D-Bus API, must explicitly enable it with the `dbus_api`
|
||||
feature flag when compiling Cloud Hypervisor.
|
||||
|
||||
```sh
|
||||
$ ./scripts/dev_cli.sh build --release --libc musl -- --features dbus_api
|
||||
```
|
||||
|
||||
Once this feature is enabled, it can be configured with the following
|
||||
CLI options:
|
||||
|
||||
```
|
||||
--dbus-service-name
|
||||
well known name of the service
|
||||
--dbus-object-path
|
||||
object path to serve the dbus interface
|
||||
--dbus-system-bus use the system bus instead of a session bus
|
||||
```
|
||||
|
||||
Example invocation:
|
||||
|
||||
```sh
|
||||
$ ./cloud-hypervisor --dbus-service-name "org.cloudhypervisor.DBusApi" \
|
||||
--dbus-object-path "/org/cloudhypervisor/DBusApi"
|
||||
```
|
||||
|
||||
This will start serving a service with the name `org.cloudhypervisor.DBusApi1`
|
||||
which in turn can be used to control and manage Cloud Hypervisor.
|
||||
|
||||
#### D-Bus API Interface
|
||||
|
||||
Please refer to the [REST API](#rest-api) documentation. As previously
|
||||
mentioned, the D-Bus API currently mirrors the behaviour of the REST API.
|
||||
|
||||
### Command Line Interface
|
||||
|
||||
The Cloud Hypervisor Command Line Interface (CLI) can only be used for launching
|
||||
@@ -199,33 +255,41 @@ the Cloud Hypervisor binary, i.e. it can not be used for controlling the VMM or
|
||||
the launched VM once they're up and running.
|
||||
|
||||
If you want to inspect the VMM, or control the VM after launching Cloud
|
||||
Hypervisor from the CLI, you must use the [REST API](#rest-api).
|
||||
Hypervisor from the CLI, you must use either the [REST API](#rest-api)
|
||||
or the [D-Bus API](#d-bus-api).
|
||||
|
||||
From the CLI, one can either:
|
||||
From the CLI, one can:
|
||||
|
||||
1. Create and boot a complete virtual machine by using the CLI options to build
|
||||
the VM config. Run `cloud-hypervisor --help` for a complete list of CLI
|
||||
options. As soon as the `cloud-hypervisor` binary is launched, the
|
||||
[REST API](#rest-api) is available for controlling and managing the VM.
|
||||
1. Start the [REST API](#rest-api) server only, by not passing any VM
|
||||
configuration options. The VM can then be asynchronously created and booted
|
||||
by sending HTTP commands to the [REST API](#rest-api). Check the
|
||||
[REST API examples](#rest-api-examples) section for more details.
|
||||
options. As soon as the `cloud-hypervisor` binary is launched, contrary
|
||||
to the [D-Bus API](#d-bus-api), the [REST API](#rest-api) is available
|
||||
for controlling and managing the VM. The [D-Bus API](#d-bus-api) doesn't start
|
||||
automatically and needs to be explicitly configured in order to be run.
|
||||
1. Start either the REST API, D-Bus API or both simultaneously without passing
|
||||
any VM configuration options. The VM can then be asynchronously created and
|
||||
booted by calling API methods of choice. It should be noted that one external
|
||||
API does not exclude another; it is possible to have both the REST and D-Bus
|
||||
APIs running simultaneously.
|
||||
|
||||
### REST API and CLI Architectural Relationship
|
||||
### REST API, D-Bus API and CLI Architectural Relationship
|
||||
|
||||
The REST API and the CLI both rely on a common, [internal API](#internal-api).
|
||||
The REST API, D-Bus API and the CLI all rely on a common, [internal API](#internal-api).
|
||||
|
||||
The CLI options are parsed by the
|
||||
[clap crate](https://docs.rs/clap/2.33.0/clap/) and then translated into
|
||||
[argh crate](https://docs.rs/argh/latest/argh/) and then translated into
|
||||
[internal API](#internal-api) commands.
|
||||
|
||||
The REST API is processed by an HTTP thread using the
|
||||
[Firecracker's `micro_http`](https://github.com/firecracker-microvm/firecracker/tree/master/src/micro_http)
|
||||
[Firecracker's `micro_http`](https://github.com/firecracker-microvm/micro-http)
|
||||
crate. As with the CLI, the HTTP requests eventually get translated into
|
||||
[internal API](#internal-api) commands.
|
||||
|
||||
As a summary, the REST API and the CLI are essentially frontends for the
|
||||
The D-Bus API is implemented using the [zbus](https://github.com/dbus2/zbus)
|
||||
crate and runs in its own thread. Whenever it needs to call the [internal API](#internal-api),
|
||||
the [blocking](https://github.com/smol-rs/blocking) crate is used perform the call in zbus' async context.
|
||||
|
||||
As a summary, the REST API, the D-Bus API and the CLI are essentially frontends for the
|
||||
[internal API](#internal-api):
|
||||
|
||||
```
|
||||
@@ -236,16 +300,16 @@ As a summary, the REST API and the CLI are essentially frontends for the
|
||||
| +------------------+ |
|
||||
| | +------------------------+
|
||||
| | | |
|
||||
+------------+ | | | |
|
||||
| | | | | +--------------+ |
|
||||
| User +---------+ +------> | Internal API | |
|
||||
| | | | | +--------------+ |
|
||||
+------------+ | | | |
|
||||
+------------+ | +----------+ | | |
|
||||
| | | D-Bus API | | | | +--------------+ |
|
||||
| User +---------+----------->+ zbus +--------------+------> | Internal API | |
|
||||
| | | | | | | +--------------+ |
|
||||
+------------+ | +----------+ | | |
|
||||
| | | |
|
||||
| | +------------------------+
|
||||
| +----------+ | VMM
|
||||
| CLI | | |
|
||||
+----------->+ clap +--------------+
|
||||
+----------->+ argh +--------------+
|
||||
| |
|
||||
+----------+
|
||||
|
||||
@@ -255,22 +319,23 @@ As a summary, the REST API and the CLI are essentially frontends for the
|
||||
## Internal API
|
||||
|
||||
The Cloud Hypervisor internal API, as its name suggests, is used internally
|
||||
by the different Cloud Hypervisor threads (VMM, HTTP, control loop, etc) to
|
||||
send commands and responses to each others.
|
||||
by the different Cloud Hypervisor threads (VMM, HTTP, D-Bus, control loop,
|
||||
etc) to send commands and responses to each others.
|
||||
|
||||
It is based on [rust's Multi-Producer, Single-Consumer (MPSC)](https://doc.rust-lang.org/std/sync/mpsc/),
|
||||
and the single consumer (a.k.a. the API receiver) is the Cloud Hypervisor
|
||||
control loop.
|
||||
|
||||
API producers are the HTTP thread handling the [REST API](#rest-api) and the
|
||||
main thread that initially parses the [CLI](#command-line-interface).
|
||||
API producers are the HTTP thread handling the [REST API](#rest-api), the
|
||||
D-Bus thread handling the [D-Bus API](#d-bus-api) and the main thread that
|
||||
initially parses the [CLI](#command-line-interface).
|
||||
|
||||
### Goals and Design
|
||||
|
||||
The internal API is designed for controlling, managing and inspecting a Cloud
|
||||
Hypervisor VMM and its guest. It is a backend for handling external, user
|
||||
visible requests through either the [REST API](#rest-api) or the
|
||||
[CLI](#command-line-interface) interfaces.
|
||||
visible requests through the [REST API](#rest-api), the [D-Bus API](#d-bus-api)
|
||||
or the [CLI](#command-line-interface) interfaces.
|
||||
|
||||
The API follows a command-response scheme that closely maps the [REST API](#rest-api).
|
||||
Any command must be replied to with a response.
|
||||
@@ -379,5 +444,5 @@ APIs work together, let's look at a complete VM creation flow, from the
|
||||
```
|
||||
1. The Cloud Hypervisor HTTP thread sends the formed HTTP response back to the
|
||||
user. This is abstracted by the
|
||||
[micro_http](https://github.com/firecracker-microvm/firecracker/tree/master/src/micro_http)
|
||||
[micro_http](https://github.com/firecracker-microvm/micro-http)
|
||||
crate.
|
||||
|
||||
@@ -27,7 +27,7 @@ distributions please replace the package manager and package name.
|
||||
# Install basic packages needed. For a package list targeting for more
|
||||
# functionalities for example the test, please see resources/Dockerfile.
|
||||
$ sudo apt-get update
|
||||
$ sudo apt install git build-essential m4 bison flex uuid-dev qemu-utils
|
||||
$ sudo apt install git build-essential m4 bison flex uuid-dev qemu-utils musl-tools
|
||||
# Install rust tool chain
|
||||
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
# If you want to build statically linked binary please add musl target
|
||||
|
||||
@@ -88,7 +88,7 @@ Ubuntu distributions.
|
||||
|
||||
```bash
|
||||
apt update
|
||||
apt install fio iperf iperf3 socat stress cpuid
|
||||
apt install fio iperf iperf3 socat stress cpuid tpm2-tools
|
||||
```
|
||||
|
||||
### Remove counterproductive packages
|
||||
@@ -170,8 +170,8 @@ We usually start from one of the custom cloud image we have previously created
|
||||
but we can use a stock cloud image as well.
|
||||
|
||||
```bash
|
||||
wget https://cloud-hypervisor.azureedge.net/jammy-server-cloudimg-amd64-custom-20221118-1.raw
|
||||
mv jammy-server-cloudimg-amd64-custom-20221118-1.raw jammy-server-cloudimg-amd64-nvidia.raw
|
||||
wget https://cloud-hypervisor.azureedge.net/jammy-server-cloudimg-amd64-custom-20230119-0.raw
|
||||
mv jammy-server-cloudimg-amd64-custom-20230119-0.raw jammy-server-cloudimg-amd64-nvidia.raw
|
||||
```
|
||||
|
||||
### Extend the image size
|
||||
@@ -225,7 +225,7 @@ Number Start End Size File system Name Flags
|
||||
|
||||
### Create a macvtap interface
|
||||
|
||||
Rely on the following [documentation](docs/macvtap-bridge.md) to set up a
|
||||
Rely on the following [documentation](macvtap-bridge.md) to set up a
|
||||
macvtap interface to provide your VM with proper connectivity.
|
||||
|
||||
### Boot the image
|
||||
|
||||
@@ -36,7 +36,7 @@ Assuming parts of the guest software stack have been instrumented to use the
|
||||
`cloud-hypervisor` debug I/O port, we may want to gather the related logs.
|
||||
|
||||
To do so we need to start `cloud-hypervisor` with the right debug level
|
||||
(`-vvv`). It is also recommended to have it log into a dedicated file in order
|
||||
(`-v -v -v`). It is also recommended to have it log into a dedicated file in order
|
||||
to easily grep for the tracing logs (e.g.
|
||||
`--log-file /tmp/cloud-hypervisor.log`):
|
||||
|
||||
@@ -48,7 +48,7 @@ to easily grep for the tracing logs (e.g.
|
||||
--memory size=1024M \
|
||||
--rng \
|
||||
--log-file /tmp/ch-fw.log \
|
||||
-vvv
|
||||
-v -v -v
|
||||
```
|
||||
|
||||
After booting the guest, we then have to grep for the debug I/O port traces in
|
||||
|
||||
@@ -8,7 +8,7 @@ To enable debugging with GDB, build with the `guest_debug` feature enabled:
|
||||
cargo build --features guest_debug
|
||||
```
|
||||
|
||||
To use the `--gdb` option, specify the Unix Domain Socket with `--path` that Cloud Hypervisor will use to communicate with the host's GDB:
|
||||
To use the `--gdb` option, specify the Unix Domain Socket with `path` that Cloud Hypervisor will use to communicate with the host's GDB:
|
||||
|
||||
```bash
|
||||
./cloud-hypervisor \
|
||||
|
||||
41
docs/heap-profiling.md
Normal file
41
docs/heap-profiling.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Heap profiling
|
||||
|
||||
Cloud Hypervisor supports generating a profile using
|
||||
[dhat](https://docs.rs/dhat/latest/dhat/) of the heap allocations made during
|
||||
the runtime of the process.
|
||||
|
||||
## Building a suitable binary
|
||||
|
||||
This adds the symbol information to the release binary but does not otherwise
|
||||
affect the performance.
|
||||
|
||||
```
|
||||
$ cargo build --profile profiling --features "dhat-heap"
|
||||
```
|
||||
|
||||
## Generating output
|
||||
|
||||
Cloud Hypervisor can then be run as usual. However it is necessary to run with `--seccomp false` as the profiling requires extra syscalls.
|
||||
|
||||
```
|
||||
$ target/profiling/cloud-hypervisor \
|
||||
--kernel ~/src/linux/vmlinux \
|
||||
--pmem file=~/workloads/focal.raw \
|
||||
--cpus boot=1 --memory size=1G \
|
||||
--cmdline "root=/dev/pmem0p1 console=ttyS0" \
|
||||
--serial tty --console off \
|
||||
--api-socket /tmp/api1 \
|
||||
--seccomp false
|
||||
```
|
||||
|
||||
When the VMM exits a message like the following will be shown:
|
||||
|
||||
```
|
||||
dhat: Total: 384,582 bytes in 3,512 blocks
|
||||
dhat: At t-gmax: 133,885 bytes in 379 blocks
|
||||
dhat: At t-end: 12,160 bytes in 20 blocks
|
||||
dhat: The data has been saved to dhat-heap.json, and is viewable with dhat/dh_view.html
|
||||
```
|
||||
|
||||
The JSON output can then be uploaded to [the dh_view tool](https://nnethercote.github.io/dh_view/dh_view.html) for analysis.
|
||||
|
||||
@@ -4,7 +4,7 @@ Currently Cloud Hypervisor supports hot plugging of CPUs devices (x86 only), PCI
|
||||
|
||||
## Kernel support
|
||||
|
||||
For hotplug on Cloud Hypervisor ACPI GED support is needed. This can either be achieved by turning on `CONFIG_ACPI_REDUCED_HARDWARE_ONLY`
|
||||
For hotplug on Cloud Hypervisor ACPI GED support is needed. This can either be achieved by turning on `CONFIG_ACPI_REDUCED_HARDWARE_ONLY`
|
||||
or by using this kernel patch (available in 5.5-rc1 and later): https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/patch/drivers/acpi/Makefile?id=ac36d37e943635fc072e9d4f47e40a48fbcdb3f0
|
||||
|
||||
## CPU Hot Plug
|
||||
@@ -27,16 +27,16 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
||||
--memory size=1024M \
|
||||
--net "tap=,mac=,ip=,mask=" \
|
||||
--rng \
|
||||
--api-socket=/tmp/ch-socket
|
||||
--api-socket /tmp/ch-socket
|
||||
$ popd
|
||||
```
|
||||
|
||||
Notice the addition of `--api-socket=/tmp/ch-socket` and a `max` parameter on `--cpus boot=4,max=8`.
|
||||
Notice the addition of `--api-socket /tmp/ch-socket` and a `max` parameter on `--cpus boot=4,max=8`.
|
||||
|
||||
To ask the VMM to add additional vCPUs then use the resize API:
|
||||
|
||||
```shell
|
||||
./ch-remote --api-socket=/tmp/ch-socket resize --cpus 8
|
||||
./ch-remote --api-socket /tmp/ch-socket resize --cpus 8
|
||||
```
|
||||
|
||||
The extra vCPU threads will be created and advertised to the running kernel. The kernel does not bring up the CPUs immediately and instead the user must "online" them from inside the VM:
|
||||
@@ -56,7 +56,7 @@ After a reboot the added CPUs will remain.
|
||||
Removing CPUs works similarly by reducing the number in the "desired_vcpus" field of the reisze API. The CPUs will be automatically offlined inside the guest so there is no need to run any commands inside the guest:
|
||||
|
||||
```shell
|
||||
./ch-remote --api-socket=/tmp/ch-socket resize --cpus 2
|
||||
./ch-remote --api-socket /tmp/ch-socket resize --cpus 2
|
||||
```
|
||||
|
||||
As per adding CPUs to the guest, after a reboot the VM will be running with the reduced number of vCPUs.
|
||||
@@ -85,7 +85,7 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
||||
--memory size=1024M,hotplug_size=8192M \
|
||||
--net "tap=,mac=,ip=,mask=" \
|
||||
--rng \
|
||||
--api-socket=/tmp/ch-socket
|
||||
--api-socket /tmp/ch-socket
|
||||
$ popd
|
||||
```
|
||||
|
||||
@@ -98,7 +98,7 @@ root@ch-guest ~ # echo online | sudo tee /sys/devices/system/memory/auto_online_
|
||||
To ask the VMM to expand the RAM for the VM:
|
||||
|
||||
```shell
|
||||
./ch-remote --api-socket=/tmp/ch-socket resize --memory 3G
|
||||
./ch-remote --api-socket /tmp/ch-socket resize --memory 3G
|
||||
```
|
||||
|
||||
The new memory is now available to use inside the VM:
|
||||
@@ -134,14 +134,14 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
||||
--disk path=focal-server-cloudimg-amd64.raw \
|
||||
--memory size=1024M,hotplug_size=8192M,hotplug_method=virtio-mem \
|
||||
--net "tap=,mac=,ip=,mask=" \
|
||||
--api-socket=/tmp/ch-socket
|
||||
--api-socket /tmp/ch-socket
|
||||
$ popd
|
||||
```
|
||||
|
||||
To ask the VMM to expand the RAM for the VM (request is in bytes):
|
||||
|
||||
```shell
|
||||
./ch-remote --api-socket=/tmp/ch-socket resize --memory 3G
|
||||
./ch-remote --api-socket /tmp/ch-socket resize --memory 3G
|
||||
```
|
||||
|
||||
The new memory is now available to use inside the VM:
|
||||
@@ -159,7 +159,7 @@ The same API can also be used to reduce the desired RAM for a VM. It is importan
|
||||
|
||||
Extra PCI devices can be added and removed from a running `cloud-hypervisor` instance. This is controlled by making a HTTP API request to the VMM to ask for the additional device to be added, or for the existing device to be removed.
|
||||
|
||||
Note: On AArch64 platform, PCI device hotplug can only be achieved using ACPI. Please refer to the [documentation](arm64.md#uefi-booting) for more information.
|
||||
Note: On AArch64 platform, PCI device hotplug can only be achieved using ACPI. Please refer to the [documentation](uefi.md#building-uefi-firmware-for-aarch64) for more information.
|
||||
|
||||
To use PCI device hotplug start the VM with the HTTP server.
|
||||
|
||||
@@ -172,17 +172,17 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
||||
--cpus boot=4 \
|
||||
--memory size=1024M \
|
||||
--net "tap=,mac=,ip=,mask=" \
|
||||
--api-socket=/tmp/ch-socket
|
||||
--api-socket /tmp/ch-socket
|
||||
```
|
||||
|
||||
Notice the addition of `--api-socket=/tmp/ch-socket`.
|
||||
Notice the addition of `--api-socket /tmp/ch-socket`.
|
||||
|
||||
### Add VFIO Device
|
||||
|
||||
To ask the VMM to add additional VFIO device then use the `add-device` API.
|
||||
|
||||
```shell
|
||||
./ch-remote --api-socket=/tmp/ch-socket add-device path=/sys/bus/pci/devices/0000:01:00.0/
|
||||
./ch-remote --api-socket /tmp/ch-socket add-device path=/sys/bus/pci/devices/0000:01:00.0/
|
||||
```
|
||||
|
||||
### Add Disk Device
|
||||
@@ -190,7 +190,7 @@ To ask the VMM to add additional VFIO device then use the `add-device` API.
|
||||
To ask the VMM to add additional disk device then use the `add-disk` API.
|
||||
|
||||
```shell
|
||||
./ch-remote --api-socket=/tmp/ch-socket add-disk path=/foo/bar/cloud.img
|
||||
./ch-remote --api-socket /tmp/ch-socket add-disk path=/foo/bar/cloud.img
|
||||
```
|
||||
|
||||
### Add Fs Device
|
||||
@@ -198,7 +198,7 @@ To ask the VMM to add additional disk device then use the `add-disk` API.
|
||||
To ask the VMM to add additional fs device then use the `add-fs` API.
|
||||
|
||||
```shell
|
||||
./ch-remote --api-socket=/tmp/ch-socket add-fs tag=myfs,socket=/foo/bar/virtiofs.sock
|
||||
./ch-remote --api-socket /tmp/ch-socket add-fs tag=myfs,socket=/foo/bar/virtiofs.sock
|
||||
```
|
||||
|
||||
### Add Net Device
|
||||
@@ -206,7 +206,7 @@ To ask the VMM to add additional fs device then use the `add-fs` API.
|
||||
To ask the VMM to add additional network device then use the `add-net` API.
|
||||
|
||||
```shell
|
||||
./ch-remote --api-socket=/tmp/ch-socket add-net tap=chtap0
|
||||
./ch-remote --api-socket /tmp/ch-socket add-net tap=chtap0
|
||||
```
|
||||
|
||||
### Add Pmem Device
|
||||
@@ -214,7 +214,7 @@ To ask the VMM to add additional network device then use the `add-net` API.
|
||||
To ask the VMM to add additional PMEM device then use the `add-pmem` API.
|
||||
|
||||
```shell
|
||||
./ch-remote --api-socket=/tmp/ch-socket add-pmem file=/foo/bar.cloud.img
|
||||
./ch-remote --api-socket /tmp/ch-socket add-pmem file=/foo/bar.cloud.img
|
||||
```
|
||||
|
||||
### Add Vsock Device
|
||||
@@ -222,7 +222,7 @@ To ask the VMM to add additional PMEM device then use the `add-pmem` API.
|
||||
To ask the VMM to add additional vsock device then use the `add-vsock` API.
|
||||
|
||||
```shell
|
||||
./ch-remote --api-socket=/tmp/ch-socket add-vsock cid=3,socket=/foo/bar/vsock.sock
|
||||
./ch-remote --api-socket /tmp/ch-socket add-vsock cid=3,socket=/foo/bar/vsock.sock
|
||||
```
|
||||
|
||||
### Common Across All PCI Devices
|
||||
@@ -244,7 +244,7 @@ After a reboot the added PCI device will remain.
|
||||
Removing a PCI device works the same way for all kind of PCI devices. The unique identifier related to the device must be provided. This identifier can be provided by the user when adding the new device, or by default Cloud Hypervisor will assign one.
|
||||
|
||||
```shell
|
||||
./ch-remote --api-socket=/tmp/ch-socket remove-device _disk0
|
||||
./ch-remote --api-socket /tmp/ch-socket remove-device _disk0
|
||||
```
|
||||
|
||||
As per adding a PCI device to the guest, after a reboot the VM will be running without the removed PCI device.
|
||||
|
||||
@@ -2,49 +2,64 @@
|
||||
|
||||
Intel® Trust Domain Extensions (Intel® TDX) is an Intel technology designed to
|
||||
isolate virtual machines from the VMM, hypervisor and any other software on the
|
||||
host platform.
|
||||
host platform. Here are some useful links:
|
||||
|
||||
For more information about TDX technical aspects, design and specification
|
||||
please refer to the
|
||||
[TDX Homepage](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-trust-domain-extensions.html).
|
||||
* [TDX Homepage](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-trust-domain-extensions.html):
|
||||
more information about TDX technical aspects, design and specification
|
||||
|
||||
The required Linux changes for the host side can be found in the
|
||||
[KVM TDX tree](https://github.com/intel/tdx/tree/kvm) while the changes for
|
||||
the guest side can be found in the [Guest TDX tree](https://github.com/intel/tdx/tree/guest).
|
||||
* [KVM TDX tree](https://github.com/intel/tdx/tree/kvm): the required
|
||||
Linux kernel changes for the host side
|
||||
|
||||
The TDVF firmware can be found in the
|
||||
[EDK2 staging project](https://github.com/tianocore/edk2-staging/tree/TDVF).
|
||||
* [Guest TDX tree](https://github.com/intel/tdx/tree/guest): the Linux
|
||||
kernel changes for the guest side
|
||||
|
||||
The TDShim firmware can be found in the
|
||||
[Confidential Containers project](https://github.com/confidential-containers/td-shim).
|
||||
* [EDK2 project](https://github.com/tianocore/edk2): the TDVF firmware
|
||||
|
||||
* [Confidential Containers project](https://github.com/confidential-containers/td-shim):
|
||||
the TDShim firmware
|
||||
|
||||
* [TDX Tools](https://github.com/intel/tdx-tools): a collection of tools
|
||||
and scripts to setup TDX environment for testing purpose (such as
|
||||
installing required packages on the host, creating guest images, and
|
||||
building the custom Linux kernel for TDX host and guest)
|
||||
|
||||
## Cloud Hypervisor support
|
||||
|
||||
First, you must be running on a machine with TDX enabled in hardware, and
|
||||
It is required to use a machine with TDX enabled in hardware and
|
||||
with the host OS compiled from the [KVM TDX tree](https://github.com/intel/tdx/tree/kvm).
|
||||
The host environment can also be setup with the [TDX Tools](https://github.com/intel/tdx-tools).
|
||||
|
||||
Cloud Hypervisor can run TDX VM (Trust Domain) by loading a TD firmware,
|
||||
Cloud Hypervisor can run TDX VM (Trust Domain) by loading a TD firmware ([TDVF](https://github.com/tianocore/edk2)),
|
||||
which will then load the guest kernel from the image. The image must be custom
|
||||
as it must include a kernel built from the [Guest TDX tree](https://github.com/intel/tdx/tree/guest).
|
||||
Cloud Hypervisor can also boot a TDX VM with direct kernel boot using [TDshim](https://github.com/confidential-containers/td-shim).
|
||||
The custom Linux kernel for the guest can be built with the [TDX Tools](https://github.com/intel/tdx-tools).
|
||||
|
||||
> **Note**
|
||||
> The latest version of custom host and guest kernel being tested is
|
||||
> from [TDX Tools - 2023ww01](https://github.com/intel/tdx-tools/commits/2023ww01).
|
||||
|
||||
### TDVF
|
||||
|
||||
> **Note**
|
||||
> The latest version of TDVF being tested is [_13b9773_](https://github.com/tianocore/edk2/commit/13b97736c876919b9786055829caaa4fa46984b7).
|
||||
|
||||
The firmware can be built as follows:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/tianocore/edk2-staging.git
|
||||
cd edk2-staging
|
||||
git checkout origin/TDVF
|
||||
git clone https://github.com/tianocore/edk2.git
|
||||
cd edk2
|
||||
git checkout 13b97736c876919b9786055829caaa4fa46984b7
|
||||
git submodule update --init --recursive
|
||||
make -C BaseTools
|
||||
source ./edksetup.sh
|
||||
build -p OvmfPkg/OvmfCh.dsc -a X64 -t GCC5 -b RELEASE
|
||||
build -p OvmfPkg/IntelTdx/IntelTdxX64.dsc -a X64 -t GCC5 -b RELEASE
|
||||
```
|
||||
|
||||
If debug logs are needed, here is the alternative command:
|
||||
|
||||
```bash
|
||||
build -p OvmfPkg/OvmfCh.dsc -a X64 -t GCC5 -D DEBUG_ON_SERIAL_PORT=TRUE
|
||||
build -p OvmfPkg/IntelTdx/IntelTdxX64.dsc -a X64 -t GCC5 -D DEBUG_ON_SERIAL_PORT=TRUE
|
||||
```
|
||||
|
||||
On the Cloud Hypervisor side, all you need is to build the project with the
|
||||
@@ -62,7 +77,7 @@ meaning it will be printing guest kernel logs to the `virtio-console` device.
|
||||
```bash
|
||||
./cloud-hypervisor \
|
||||
--platform tdx=on
|
||||
--firmware edk2-staging/Build/OvmfCh/RELEASE_GCC5/FV/OVMF.fd \
|
||||
--firmware edk2/Build/IntelTdx/RELEASE_GCC5/FV/OVMF.fd \
|
||||
--cpus boot=1 \
|
||||
--memory size=1G \
|
||||
--disk path=tdx_guest_img
|
||||
@@ -74,7 +89,7 @@ firmware:
|
||||
```bash
|
||||
./cloud-hypervisor \
|
||||
--platform tdx=on
|
||||
--firmware edk2-staging/Build/OvmfCh/DEBUG_GCC5/FV/OVMF.fd \
|
||||
--firmware edk2/Build/IntelTdx/DEBUG_GCC5/FV/OVMF.fd \
|
||||
--cpus boot=1 \
|
||||
--memory size=1G \
|
||||
--disk path=tdx_guest_img \
|
||||
@@ -84,21 +99,60 @@ firmware:
|
||||
|
||||
### TDShim
|
||||
|
||||
> **Note**
|
||||
> The latest version of TDShim being tested is [_66bb334_](https://github.com/confidential-containers/td-shim/tree/66bb33451befbf1291abe3cfea7ee9e99d922b0d).
|
||||
|
||||
This is a lightweight version of the TDVF, written in Rust and designed for
|
||||
direct kernel boot, which is useful for containers use cases.
|
||||
|
||||
You can find the instructions for building the firmware directly from the
|
||||
project [documentation](https://github.com/confidential-containers/td-shim/tree/staging#how-to-build).
|
||||
To build TDShim from source, it is required to install `Rust`, `NASM`,
|
||||
and `LLVM` first. The TDshim can be build as follows:
|
||||
```bash
|
||||
git clone https://github.com/confidential-containers/td-shim
|
||||
cd td-shim
|
||||
git checkout 66bb33451befbf1291abe3cfea7ee9e99d922b0d
|
||||
cargo install cargo-xbuild
|
||||
export CC=clang
|
||||
export AR=llvm-ar
|
||||
export CC_x86_64_unknown_none=clang
|
||||
export AR_x86_64_unknown_none=llvm-ar
|
||||
git submodule update --init --recursive
|
||||
./sh_script/preparation.sh
|
||||
cargo xbuild -p td-shim --target x86_64-unknown-none --release --features=main,tdx
|
||||
cargo run -p td-shim-tools --bin td-shim-ld --features=linker -- target/x86_64-unknown-none/release/ResetVector.bin target/x86_64-unknown-none/release/td-shim -o target/release/final.bin
|
||||
```
|
||||
|
||||
If debug logs from the TDShim is needed, here are the alternative
|
||||
commands:
|
||||
```bash
|
||||
cargo xbuild -p td-shim --target x86_64-unknown-none --features=main,tdx
|
||||
cargo run -p td-shim-tools --bin td-shim-ld --features=linker -- target/x86_64-unknown-none/debug/ResetVector.bin target/x86_64-unknown-none/debug/td-shim -o target/debug/final.bin
|
||||
```
|
||||
|
||||
And run a TDX VM by providing the firmware previously built, along with a guest
|
||||
kernel built from the [Guest TDX tree](https://github.com/intel/tdx/tree/guest).
|
||||
kernel built from the [Guest TDX tree](https://github.com/intel/tdx/tree/guest)
|
||||
or the [TDX Tools](https://github.com/intel/tdx-tools).
|
||||
The appropriate kernel boot options must be provided through the `--cmdline`
|
||||
option as well.
|
||||
|
||||
```bash
|
||||
./cloud-hypervisor \
|
||||
--platform tdx=on
|
||||
--firmware tdshim \
|
||||
--firmware td-shim/target/release/final.bin \
|
||||
--kernel bzImage \
|
||||
--cmdline "root=/dev/vda3 console=hvc0 rw"
|
||||
--cpus boot=1 \
|
||||
--memory size=1G \
|
||||
--disk path=tdx_guest_img
|
||||
```
|
||||
|
||||
And here is the alternative command when looking for debug logs from the
|
||||
TDShim:
|
||||
|
||||
```bash
|
||||
./cloud-hypervisor \
|
||||
--platform tdx=on
|
||||
--firmware td-shim/target/debug/final.bin \
|
||||
--kernel bzImage \
|
||||
--cmdline "root=/dev/vda3 console=hvc0 rw"
|
||||
--cpus boot=1 \
|
||||
|
||||
@@ -245,7 +245,7 @@ e.g.
|
||||
|
||||
```bash
|
||||
./cloud-hypervisor \
|
||||
--api-socket=/tmp/api \
|
||||
--api-socket /tmp/api \
|
||||
--cpus boot=1 \
|
||||
--memory size=4G,hugepages=on \
|
||||
--disk path=focal-server-cloudimg-amd64.raw \
|
||||
@@ -260,7 +260,7 @@ requiring the IOMMU then may be hotplugged:
|
||||
e.g.
|
||||
|
||||
```bash
|
||||
./ch-remote --api-socket=/tmp/api add-device path=/sys/bus/pci/devices/0000:00:04.0,iommu=on,pci_segment=1
|
||||
./ch-remote --api-socket /tmp/api add-device path=/sys/bus/pci/devices/0000:00:04.0,iommu=on,pci_segment=1
|
||||
```
|
||||
|
||||
Devices that cannot be placed behind an IOMMU (e.g. lacking an `iommu=` option)
|
||||
|
||||
@@ -16,22 +16,22 @@ $ target/release/cloud-hypervisor
|
||||
--disk path=~/workloads/focal.raw \
|
||||
--cpus boot=1 --memory size=1G,shared=on \
|
||||
--cmdline "root=/dev/vda1 console=ttyS0" \
|
||||
--serial tty --console off --api-socket=/tmp/api1
|
||||
--serial tty --console off --api-socket /tmp/api1
|
||||
```
|
||||
|
||||
Launch the destination VM from the same directory (on the host machine):
|
||||
```bash
|
||||
$ target/release/cloud-hypervisor --api-socket=/tmp/api2
|
||||
$ target/release/cloud-hypervisor --api-socket /tmp/api2
|
||||
```
|
||||
|
||||
Get ready for receiving migration for the destination VM (on the host machine):
|
||||
```bash
|
||||
$ target/release/ch-remote --api-socket=/tmp/api2 receive-migration unix:/tmp/sock
|
||||
$ target/release/ch-remote --api-socket /tmp/api2 receive-migration unix:/tmp/sock
|
||||
```
|
||||
|
||||
Start to send migration for the source VM (on the host machine):
|
||||
```bash
|
||||
$ target/release/ch-remote --api-socket=/tmp/api1 send-migration --local unix:/tmp/sock
|
||||
$ target/release/ch-remote --api-socket /tmp/api1 send-migration --local unix:/tmp/sock
|
||||
```
|
||||
|
||||
When the above commands completed, the source VM should be successfully
|
||||
@@ -51,7 +51,7 @@ $ sudo /target/release/cloud-hypervisor \
|
||||
--cpus boot=1 --memory size=512M \
|
||||
--kernel vmlinux \
|
||||
--cmdline "root=/dev/vda1 console=ttyS0" \
|
||||
--disk path=focal-1.raw path=focal-nested.raw path=tmp.img\
|
||||
--disk path=focal-1.raw path=focal-nested.raw --disk path=tmp.img\
|
||||
--net ip=192.168.101.1
|
||||
```
|
||||
|
||||
@@ -63,7 +63,7 @@ $ sudo /target/release/cloud-hypervisor \
|
||||
--cpus boot=1 --memory size=512M \
|
||||
--kernel vmlinux \
|
||||
--cmdline "root=/dev/vda1 console=ttyS0" \
|
||||
--disk path=focal-2.raw path=focal-nested.raw path=tmp.img\
|
||||
--disk path=focal-2.raw path=focal-nested.raw --disk path=tmp.img\
|
||||
--net ip=192.168.102.1
|
||||
```
|
||||
|
||||
@@ -74,8 +74,8 @@ vm-1:~$ sudo ./cloud-hypervisor \
|
||||
--memory size=128M \
|
||||
--kernel vmlinux \
|
||||
--cmdline "console=ttyS0 root=/dev/vda1" \
|
||||
--disk path=/dev/vdb path=/dev/vdc \
|
||||
--api-socket=/tmp/api1 \
|
||||
--disk path=/dev/vdb --disk path=/dev/vdc \
|
||||
--api-socket /tmp/api1 \
|
||||
--net ip=192.168.100.1
|
||||
vm-1:~$ # setup the guest network if needed
|
||||
vm-1:~$ sudo ip addr add 192.168.101.2/24 dev ens4
|
||||
@@ -108,7 +108,7 @@ echo "tmp = $tmp"
|
||||
|
||||
Launch the nested destination VM (inside the guest OS of the VM 2):
|
||||
```bash
|
||||
vm-2:~$ sudo ./cloud-hypervisor --api-socket=/tmp/api2
|
||||
vm-2:~$ sudo ./cloud-hypervisor --api-socket /tmp/api2
|
||||
vm-2:~$ # setup the guest network with the following commands if needed
|
||||
vm-2:~$ sudo ip addr add 192.168.102.2/24 dev ens4
|
||||
vm-2:~$ sudo ip link set up dev ens4
|
||||
@@ -122,7 +122,7 @@ vm-2:~$ ping 192.168.101.2 # This should succeed
|
||||
Get ready for receiving migration for the nested destination VM (inside
|
||||
the guest OS of the VM 2):
|
||||
```bash
|
||||
vm-2:~$ sudo ./ch-remote --api-socket=/tmp/api2 receive-migration unix:/tmp/sock2
|
||||
vm-2:~$ sudo ./ch-remote --api-socket /tmp/api2 receive-migration unix:/tmp/sock2
|
||||
vm-2:~$ sudo socat TCP-LISTEN:6000,reuseaddr UNIX-CLIENT:/tmp/sock2
|
||||
```
|
||||
|
||||
@@ -130,7 +130,7 @@ Start to send migration for the nested source VM (inside the guest OS of
|
||||
the VM 1):
|
||||
```bash
|
||||
vm-1:~$ sudo socat UNIX-LISTEN:/tmp/sock1,reuseaddr TCP:192.168.102.2:6000
|
||||
vm-1:~$ sudo ./ch-remote --api-socket=/tmp/api1 send-migration unix:/tmp/sock1
|
||||
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
|
||||
|
||||
@@ -38,6 +38,6 @@ This level is for the benefit of developers. It should be used for sporadic and
|
||||
|
||||
### `debug!()`
|
||||
|
||||
Use `-vv` to enable.
|
||||
Use `-v -v` to enable.
|
||||
|
||||
For the most verbose of logging messages. It is acceptable to "spam" the log with repeated invocations of the same message. This level of logging would be combined with `--log-file`.
|
||||
For the most verbose of logging messages. It is acceptable to "spam" the log with repeated invocations of the same message. This level of logging would be combined with `--log-file`.
|
||||
|
||||
@@ -266,11 +266,8 @@ _Example_
|
||||
|
||||
### `file`
|
||||
|
||||
Path to the file backing the memory zone. This can be either a file or a
|
||||
directory. In case of a file, it will be opened and used as the backing file
|
||||
for the `mmap(2)` operation. In case of a directory, a temporary file with no
|
||||
hard link on the filesystem will be created. This file will be used as the
|
||||
backing file for the `mmap(2)` operation.
|
||||
Path to the file backing the memory zone. The file will be opened and used as
|
||||
the backing file for the `mmap(2)` operation.
|
||||
|
||||
This option can be particularly useful when trying to back a part of the guest
|
||||
RAM with a well known file. In the context of the snapshot/restore feature, and
|
||||
@@ -519,7 +516,7 @@ different distances, it can be described with the following example.
|
||||
_Example_
|
||||
|
||||
```
|
||||
--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]
|
||||
--numa guest_numa_id=0,distances=[1@15,2@25] --numa guest_numa_id=1,distances=[0@15,2@20] guest_numa_id=2,distances=[0@25,1@20]
|
||||
```
|
||||
|
||||
### `memory_zones`
|
||||
@@ -543,14 +540,14 @@ demarcate the list.
|
||||
|
||||
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`
|
||||
`--numa guest_numa_id=0,memory_zones=mem0 --numa guest_numa_id=1,memory_zones=mem0`
|
||||
|
||||
_Example_
|
||||
|
||||
```
|
||||
--memory size=0
|
||||
--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
|
||||
--memory-zone id=mem0,size=1G 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
|
||||
```
|
||||
|
||||
### `sgx_epc_sections`
|
||||
@@ -570,7 +567,7 @@ _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]
|
||||
--numa guest_numa_id=0,sgx_epc_sections=epc1 --numa guest_numa_id=1,sgx_epc_sections=[epc0,epc2]
|
||||
```
|
||||
|
||||
### PCI bus
|
||||
|
||||
@@ -4,20 +4,12 @@
|
||||
|
||||
## Building a suitable binary
|
||||
|
||||
Modify the `Cargo.toml` file to add `debug = 1` to the `[profile.release]` block. It should look like this:
|
||||
|
||||
```
|
||||
[profile.release]
|
||||
lto = true
|
||||
debug = 1
|
||||
```
|
||||
|
||||
This adds the symbol information to the release binary but does not otherwise affect the performance.
|
||||
|
||||
The binary must also be built with frame pointers included so that the call graph can be captured by the profiler.
|
||||
|
||||
```
|
||||
$ cargo clean && RUSTFLAGS='-C force-frame-pointers=y' cargo build --release
|
||||
$ cargo clean && RUSTFLAGS='-C force-frame-pointers=y' cargo build --profile profiling
|
||||
```
|
||||
|
||||
## Profiling
|
||||
@@ -27,13 +19,13 @@ $ cargo clean && RUSTFLAGS='-C force-frame-pointers=y' cargo build --release
|
||||
e.g.
|
||||
|
||||
```
|
||||
$ perf record -g target/release/cloud-hypervisor \
|
||||
$ perf record -g target/profiling/cloud-hypervisor \
|
||||
--kernel ~/src/linux/vmlinux \
|
||||
--pmem file=~/workloads/focal.raw \
|
||||
--cpus boot=1 --memory size=1G \
|
||||
--cmdline "root=/dev/pmem0p1 console=ttyS0" \
|
||||
--serial tty --console off \
|
||||
--api-socket=/tmp/api1
|
||||
--api-socket /tmp/api1
|
||||
```
|
||||
|
||||
For analysing the samples:
|
||||
@@ -60,5 +52,5 @@ $ perf record --call-graph lbr --all-user --user-callchains -g target/release/cl
|
||||
--cpus boot=1 --memory size=1G \
|
||||
--cmdline "root=/dev/pmem0p1 console=ttyS0" \
|
||||
--serial tty --console off \
|
||||
--api-socket=/tmp/api1
|
||||
--api-socket /tmp/api1
|
||||
```
|
||||
|
||||
@@ -25,14 +25,14 @@ First thing, we must run a Cloud Hypervisor VM:
|
||||
At any point in time when the VM is running, one might choose to pause it:
|
||||
|
||||
```bash
|
||||
./ch-remote --api-socket=/tmp/cloud-hypervisor.sock pause
|
||||
./ch-remote --api-socket /tmp/cloud-hypervisor.sock pause
|
||||
```
|
||||
|
||||
Once paused, the VM can be safely snapshot into the specified directory and
|
||||
using the following command:
|
||||
|
||||
```bash
|
||||
./ch-remote --api-socket=/tmp/cloud-hypervisor.sock snapshot file:///home/foo/snapshot
|
||||
./ch-remote --api-socket /tmp/cloud-hypervisor.sock snapshot file:///home/foo/snapshot
|
||||
```
|
||||
|
||||
Given the directory was present on the system, the snapshot will succeed and
|
||||
@@ -79,7 +79,7 @@ Or using two different commands from two terminals:
|
||||
./cloud-hypervisor --api-socket /tmp/cloud-hypervisor.sock
|
||||
|
||||
# Second terminal
|
||||
./ch-remote --api-socket=/tmp/cloud-hypervisor.sock restore source_url=file:///home/foo/snapshot
|
||||
./ch-remote --api-socket /tmp/cloud-hypervisor.sock restore source_url=file:///home/foo/snapshot
|
||||
```
|
||||
|
||||
Remember the VM is restored in a `paused` state, which was the VM's state when
|
||||
@@ -87,7 +87,7 @@ it was snapshot. For this reason, one must explicitly `resume` the VM before to
|
||||
start using it.
|
||||
|
||||
```bash
|
||||
./ch-remote --api-socket=/tmp/cloud-hypervisor.sock resume
|
||||
./ch-remote --api-socket /tmp/cloud-hypervisor.sock resume
|
||||
```
|
||||
|
||||
At this point, the VM is fully restored and is identical to the VM which was
|
||||
|
||||
@@ -94,7 +94,7 @@ VMs run in client mode. They connect to the socket created by the `dpdkvhostuser
|
||||
--memory size=1024M,hugepages=on,shared=true \
|
||||
--kernel linux/arch/x86/boot/compressed/vmlinux.bin \
|
||||
--cmdline "console=ttyS0 root=/dev/vda1 rw iommu=off" \
|
||||
--disk path=images/focal-server-cloudimg-amd64.raw vhost_user=true,socket=/var/tmp/vhost.1,num_queues=4,queue_size=128 \
|
||||
--disk path=images/focal-server-cloudimg-amd64.raw --disk vhost_user=true,socket=/var/tmp/vhost.1,num_queues=4,queue_size=128 \
|
||||
--console off \
|
||||
--serial tty \
|
||||
--rng
|
||||
|
||||
@@ -6,5 +6,5 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.139"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.89"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
|
||||
510
fuzz/Cargo.lock
generated
510
fuzz/Cargo.lock
generated
@@ -5,15 +5,16 @@ version = 3
|
||||
[[package]]
|
||||
name = "acpi_tables"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#05a609136387cc1cc9b499cee4320020325c263f"
|
||||
dependencies = [
|
||||
"vm-memory",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.68"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
|
||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
|
||||
[[package]]
|
||||
name = "api_client"
|
||||
@@ -24,15 +25,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.2.0"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29d47fbf90d5149a107494b15a7dc8d69b351be2db3bb9691740e88ec17fd880"
|
||||
checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.5.1"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "983cd8b9d4b02a6dc6ffa557262eb5858a27a0038ffffe21a0f133eaa819a164"
|
||||
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
|
||||
|
||||
[[package]]
|
||||
name = "arch"
|
||||
@@ -56,6 +57,34 @@ dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argh"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab257697eb9496bf75526f0217b5ed64636a9cfafa78b8365c71bd283fcef93e"
|
||||
dependencies = [
|
||||
"argh_derive",
|
||||
"argh_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argh_derive"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b382dbd3288e053331f03399e1db106c9fb0d8562ad62cb04859ae926f324fa6"
|
||||
dependencies = [
|
||||
"argh_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argh_shared"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64cb94155d965e3d37ffbbe7cc5b82c3dd79dd33bd48e536f73d2cfb8d85506f"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
@@ -71,6 +100,12 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded"
|
||||
|
||||
[[package]]
|
||||
name = "block_util"
|
||||
version = "0.1.0"
|
||||
@@ -99,9 +134,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.78"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
]
|
||||
@@ -112,37 +147,13 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap_lex",
|
||||
"is-terminal",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloud-hypervisor"
|
||||
version = "28.0.0"
|
||||
version = "32.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"api_client",
|
||||
"clap",
|
||||
"argh",
|
||||
"epoll",
|
||||
"event_monitor",
|
||||
"hypervisor",
|
||||
@@ -203,9 +214,9 @@ checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.14.2"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa"
|
||||
checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
@@ -213,27 +224,27 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.14.2"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f"
|
||||
checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.14.2"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e"
|
||||
checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -243,12 +254,11 @@ dependencies = [
|
||||
"acpi_tables",
|
||||
"anyhow",
|
||||
"arch",
|
||||
"bitflags",
|
||||
"bitflags 2.3.2",
|
||||
"byteorder",
|
||||
"hypervisor",
|
||||
"libc",
|
||||
"log",
|
||||
"phf",
|
||||
"thiserror",
|
||||
"tpm",
|
||||
"versionize",
|
||||
@@ -265,28 +275,7 @@ version = "4.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20df693c700404f7e19d4d6fae6b15215d2913c27955d2b9d6f2c0f537511cd0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -301,9 +290,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fdt"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "964f5becd44d069dca0beea2b4bc05639ae7bf3b3f5369c295aff360bb57cca2"
|
||||
checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
@@ -313,24 +302,15 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.8"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hypervisor"
|
||||
version = "0.1.0"
|
||||
@@ -352,9 +332,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iced-x86"
|
||||
version = "1.18.0"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dd04b950d75b3498320253b17fb92745b2cc79ead8814aede2f7c1bab858bec"
|
||||
checksum = "b7cc8d38244d84278262c8ebe6930cc44283d194cbabae2651f6112103802fb5"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
@@ -365,49 +345,27 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-uring"
|
||||
version = "0.5.11"
|
||||
version = "0.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9ddf18110cedc09617f5a965bdb51adb0c0fb02c791e4ab22f7a21bb25269b0"
|
||||
checksum = "dd1e1a01cfb924fd8c5c43b6827965db394f5a3a16c599ce03452266e1cf984c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"io-lifetimes",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
|
||||
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.25"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
|
||||
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -424,9 +382,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kvm-ioctls"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3a321cabd827642499c77e27314f388dd83a717a5ca716b86476fb947f73ae4"
|
||||
checksum = "b8f8dc9c1896e5f144ec5d07169bc29f39a047686d29585a91f30489abfaeb6b"
|
||||
dependencies = [
|
||||
"kvm-bindings",
|
||||
"libc",
|
||||
@@ -441,15 +399,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.139"
|
||||
version = "0.2.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
version = "0.4.5"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8fff891139ee62800da71b7fd5b508d570b9ad95e614a53c6f453ca08366038"
|
||||
checksum = "beb09950ae85a0a94b27676cccf37da5ff13f27076aa1adbc6545dd0d0e1bd4e"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"cc",
|
||||
@@ -458,32 +416,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-loader"
|
||||
version = "0.8.1"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9259ddbfbb52cc918f6bbc60390004ddd0228cf1d85f402009ff2b3d95de83f"
|
||||
checksum = "8d3adb7b28e189741eca3b1a4a27de0bf15e0907c9d4b0c74bd2d7d84ef72e08"
|
||||
dependencies = [
|
||||
"vm-memory",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
||||
|
||||
[[package]]
|
||||
name = "micro_http"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#fbef706e28c7ca7cce8dfec7ca073f3b359879d3"
|
||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#b538bf89e50be83b6fa9ab1896727ff61e02fa13"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"vmm-sys-util",
|
||||
@@ -519,20 +468,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.0"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "option_parser"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
||||
|
||||
[[package]]
|
||||
name = "pci"
|
||||
version = "0.1.0"
|
||||
@@ -556,53 +499,11 @@ dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c"
|
||||
dependencies = [
|
||||
"phf_macros",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.49"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
|
||||
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -620,28 +521,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.21"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "rate_limiter"
|
||||
version = "0.1.0"
|
||||
@@ -653,13 +539,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "remain"
|
||||
version = "0.2.6"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5704e2cda92fd54202f05430725317ba0ea7d0c96b246ca0a92e45177127ba3b"
|
||||
checksum = "e13cca257d068dd3a390d04b2c3009a3fad2ee5048dfa8f239d048372810470c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -671,25 +557,11 @@ dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.36.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.12"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
|
||||
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
||||
|
||||
[[package]]
|
||||
name = "seccompiler"
|
||||
@@ -702,35 +574,35 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.16"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
|
||||
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.152"
|
||||
version = "1.0.164"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.152"
|
||||
version = "1.0.164"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.91"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
|
||||
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -739,9 +611,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "2.1.0"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25bf4a5a814902cd1014dbccfa4d4560fb8432c779471e96e035602519f82eef"
|
||||
checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_with_macros",
|
||||
@@ -749,14 +621,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with_macros"
|
||||
version = "2.2.0"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1966009f3c05f095697c537312f5415d1e3ed31ce0a56942bac4c771c5c335e"
|
||||
checksum = "edc7d5d3932fb12ce722ee5e64dd38c504efba37567f0c402f6ca728c3b8b070"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -765,9 +637,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.14"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
|
||||
checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
@@ -775,19 +647,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
@@ -802,9 +668,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.107"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -812,42 +678,34 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
name = "syn"
|
||||
version = "2.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.37"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
|
||||
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.37"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
|
||||
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -858,6 +716,7 @@ dependencies = [
|
||||
"byteorder",
|
||||
"libc",
|
||||
"log",
|
||||
"net_gen",
|
||||
"thiserror",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
@@ -875,24 +734,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.6"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.2.2"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
|
||||
checksum = "0fa2982af2eec27de306107c027578ff7f423d65f7250e40ce0fea8f45248b81"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "versionize"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6e2495726cf917e7ba7ec8bf0f0fceab543dd38d0a4195ed6bef331e38a290f"
|
||||
checksum = "dca4b7062e7e6d685901e815c35f9671e059de97c1c0905eeff8592f3fff442f"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"crc64",
|
||||
@@ -900,7 +759,7 @@ dependencies = [
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"versionize_derive",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
@@ -908,17 +767,17 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "versionize_derive"
|
||||
version = "0.1.4"
|
||||
source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch#ae35ef7a3ddabd3371ab8ac0193a383aff6e4b1b"
|
||||
source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch#e502b1d4aabab342386f0c53780d49f21a6a1df6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vfio-bindings"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#7ef33f6759ae6d37a54cd66f749aa47c1c81509c"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#89f8e77dd1a2829197ecde65b686bafcc8a1def4"
|
||||
dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
@@ -926,7 +785,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio-ioctls"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#7ef33f6759ae6d37a54cd66f749aa47c1c81509c"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#89f8e77dd1a2829197ecde65b686bafcc8a1def4"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"kvm-bindings",
|
||||
@@ -942,7 +801,9 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio_user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#eef6bec4d421f08ed1688fe67c5ea33aabbf5069"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"log",
|
||||
"serde",
|
||||
@@ -969,11 +830,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vhost"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9b791c5b0717a0558888a4cf7240cea836f39a99cb342e12ce633dcaa078072"
|
||||
checksum = "84f81f436bca4541f4d33172e1202882c9d437db34ed17fc6d84c8ff2bde21f5"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
@@ -981,9 +842,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "virtio-bindings"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ff512178285488516ed85f15b5d0113a7cdb89e9e8a760b269ae4f02b84bd6b"
|
||||
checksum = "0b9084faf91b9aa9676ae2cac8f1432df2839d9566e6f19f29dbc13a8b831dff"
|
||||
|
||||
[[package]]
|
||||
name = "virtio-devices"
|
||||
@@ -1022,9 +883,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "virtio-queue"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19e927d93d54c365034fd7f31a5f458a1f540de4a37c52e892670dad9692173c"
|
||||
checksum = "91aebb1df33db33cbf04d4c2445e4f78d0b0c8e65acfd16a4ee95ef63ca252f8"
|
||||
dependencies = [
|
||||
"log",
|
||||
"virtio-bindings",
|
||||
@@ -1061,9 +922,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#c5a99ab71b130435927
|
||||
|
||||
[[package]]
|
||||
name = "vm-memory"
|
||||
version = "0.10.0"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "688a70366615b45575a424d9c665561c1b5ab2224d494f706b6a6812911a827c"
|
||||
checksum = "9d6ea57fe00f9086c59eeeb68e102dd611686bc3c28520fa465996d4d4bdce07"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"libc",
|
||||
@@ -1100,9 +961,8 @@ dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
"arch",
|
||||
"bitflags",
|
||||
"bitflags 2.3.2",
|
||||
"block_util",
|
||||
"clap",
|
||||
"devices",
|
||||
"epoll",
|
||||
"event_monitor",
|
||||
@@ -1137,15 +997,16 @@ dependencies = [
|
||||
"vm-migration",
|
||||
"vm-virtio",
|
||||
"vmm-sys-util",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vmm-sys-util"
|
||||
version = "0.11.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc06a16ee8ebf0d9269aed304030b0d20a866b8b3dd3d4ce532596ac567a0d24"
|
||||
checksum = "dd64fe09d8e880e600c324e7d664760a17f56e9672b7495a86381b49e4f72f46"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
@@ -1173,15 +1034,6 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
@@ -1189,58 +1041,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
name = "zerocopy"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.0"
|
||||
name = "zerocopy-derive"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
||||
checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
@@ -12,20 +12,20 @@ cargo-fuzz = true
|
||||
block_util = { path = "../block_util" }
|
||||
devices = { path = "../devices" }
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.138"
|
||||
libfuzzer-sys = "0.4.5"
|
||||
linux-loader = { version = "0.8.1", features = ["elf", "bzimage", "pe"] }
|
||||
libc = "0.2.147"
|
||||
libfuzzer-sys = "0.4.6"
|
||||
linux-loader = { version = "0.9.0", features = ["elf", "bzimage", "pe"] }
|
||||
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
|
||||
net_util = { path = "../net_util" }
|
||||
once_cell = "1.17.0"
|
||||
once_cell = "1.18.0"
|
||||
qcow = { path = "../qcow" }
|
||||
seccompiler = "0.3.0"
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-devices = { path = "../virtio-devices" }
|
||||
virtio-queue = "0.7.0"
|
||||
virtio-queue = "0.8.0"
|
||||
vmm = { path = "../vmm" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
vm-memory = "0.10.0"
|
||||
vmm-sys-util = "0.11.1"
|
||||
vm-memory = "0.11.0"
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
|
||||
|
||||
@@ -6,28 +6,28 @@ edition = "2021"
|
||||
license = "Apache-2.0 OR BSD-3-Clause"
|
||||
|
||||
[features]
|
||||
kvm = ["kvm-ioctls", "kvm-bindings"]
|
||||
mshv = ["mshv-ioctls", "mshv-bindings"]
|
||||
kvm = ["kvm-ioctls", "kvm-bindings", "vfio-ioctls/kvm"]
|
||||
mshv = ["mshv-ioctls", "mshv-bindings", "vfio-ioctls/mshv"]
|
||||
tdx = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.68"
|
||||
anyhow = "1.0.71"
|
||||
byteorder = "1.4.3"
|
||||
thiserror = "1.0.38"
|
||||
thiserror = "1.0.40"
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
kvm-ioctls = { version = "0.12.0", optional = true }
|
||||
kvm-ioctls = { version = "0.13.0", optional = true }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_with = { version = "2.1.0", default-features = false, features = ["macros"] }
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_with = { version = "3.0.0", default-features = false, features = ["macros"] }
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
||||
version = "1.18.0"
|
||||
version = "1.19.0"
|
||||
default-features = false
|
||||
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
|
||||
|
||||
|
||||
@@ -15,73 +15,89 @@ use crate::arch::x86::emulator::instructions::*;
|
||||
use crate::arch::x86::regs::DF;
|
||||
use crate::arch::x86::Exception;
|
||||
|
||||
macro_rules! movs {
|
||||
($bound:ty) => {
|
||||
fn emulate(
|
||||
&self,
|
||||
insn: &Instruction,
|
||||
state: &mut T,
|
||||
platform: &mut dyn PlatformEmulator<CpuState = T>,
|
||||
) -> Result<(), EmulationError<Exception>> {
|
||||
let mut count: u64 = if insn.has_rep_prefix() {
|
||||
state
|
||||
.read_reg(Register::ECX)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
let mut rsi = state
|
||||
.read_reg(Register::RSI)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
let mut rdi = state
|
||||
.read_reg(Register::RDI)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
|
||||
let df = (state.flags() & DF) != 0;
|
||||
let len = std::mem::size_of::<$bound>();
|
||||
|
||||
while count > 0 {
|
||||
let mut memory: [u8; 4] = [0; 4];
|
||||
|
||||
let src = state
|
||||
.linearize(Register::DS, rsi, false)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
let dst = state
|
||||
.linearize(Register::ES, rdi, true)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
|
||||
platform
|
||||
.read_memory(src, &mut memory[0..len])
|
||||
.map_err(EmulationError::PlatformEmulationError)?;
|
||||
platform
|
||||
.write_memory(dst, &memory[0..len])
|
||||
.map_err(EmulationError::PlatformEmulationError)?;
|
||||
|
||||
if df {
|
||||
rsi = rsi.wrapping_sub(len as u64);
|
||||
rdi = rdi.wrapping_sub(len as u64);
|
||||
} else {
|
||||
rsi = rsi.wrapping_add(len as u64);
|
||||
rdi = rdi.wrapping_add(len as u64);
|
||||
}
|
||||
count -= 1;
|
||||
}
|
||||
|
||||
state
|
||||
.write_reg(Register::RSI, rsi)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
state
|
||||
.write_reg(Register::RDI, rdi)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
if insn.has_rep_prefix() {
|
||||
state
|
||||
.write_reg(Register::ECX, 0)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Movsd_m32_m32;
|
||||
impl<T: CpuStateManager> InstructionHandler<T> for Movsd_m32_m32 {
|
||||
fn emulate(
|
||||
&self,
|
||||
insn: &Instruction,
|
||||
state: &mut T,
|
||||
platform: &mut dyn PlatformEmulator<CpuState = T>,
|
||||
) -> Result<(), EmulationError<Exception>> {
|
||||
let mut count: u64 = if insn.has_rep_prefix() {
|
||||
state
|
||||
.read_reg(Register::ECX)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?
|
||||
} else {
|
||||
1
|
||||
};
|
||||
movs!(u32);
|
||||
}
|
||||
|
||||
let mut rsi = state
|
||||
.read_reg(Register::RSI)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
let mut rdi = state
|
||||
.read_reg(Register::RDI)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
pub struct Movsw_m16_m16;
|
||||
impl<T: CpuStateManager> InstructionHandler<T> for Movsw_m16_m16 {
|
||||
movs!(u16);
|
||||
}
|
||||
|
||||
let df = (state.flags() & DF) != 0;
|
||||
let len = std::mem::size_of::<u32>();
|
||||
|
||||
while count > 0 {
|
||||
let mut memory: [u8; 4] = [0; 4];
|
||||
|
||||
let src = state
|
||||
.linearize(Register::DS, rsi, false)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
let dst = state
|
||||
.linearize(Register::ES, rdi, true)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
|
||||
platform
|
||||
.read_memory(src, &mut memory[0..len])
|
||||
.map_err(EmulationError::PlatformEmulationError)?;
|
||||
platform
|
||||
.write_memory(dst, &memory[0..len])
|
||||
.map_err(EmulationError::PlatformEmulationError)?;
|
||||
|
||||
if df {
|
||||
rsi = rsi.wrapping_sub(len as u64);
|
||||
rdi = rdi.wrapping_sub(len as u64);
|
||||
} else {
|
||||
rsi = rsi.wrapping_add(len as u64);
|
||||
rdi = rdi.wrapping_add(len as u64);
|
||||
}
|
||||
count -= 1;
|
||||
}
|
||||
|
||||
state
|
||||
.write_reg(Register::RSI, rsi)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
state
|
||||
.write_reg(Register::RDI, rdi)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
if insn.has_rep_prefix() {
|
||||
state
|
||||
.write_reg(Register::ECX, 0)
|
||||
.map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub struct Movsb_m8_m8;
|
||||
impl<T: CpuStateManager> InstructionHandler<T> for Movsb_m8_m8 {
|
||||
movs!(u8);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -142,4 +158,127 @@ mod tests {
|
||||
vmm.read_memory(0x8 + 8, &mut data).unwrap();
|
||||
assert_eq!(0x0, <u32>::from_le_bytes(data));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rep_movsw_m16_m16() {
|
||||
let ip: u64 = 0x1000;
|
||||
let memory: [u8; 24] = [
|
||||
0x78, 0x56, 0x34, 0x12, // 0x12345678
|
||||
0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd
|
||||
0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5
|
||||
0x00, 0x00, 0x00, 0x00, // 0x00000000
|
||||
0x00, 0x00, 0x00, 0x00, // 0x00000000
|
||||
0x00, 0x00, 0x00, 0x00, // 0x00000000
|
||||
];
|
||||
let insn = [0x66, 0xf3, 0xa5]; // rep movsw
|
||||
let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0xc)];
|
||||
let mut data = [0u8; 2];
|
||||
|
||||
let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
|
||||
|
||||
assert!(vmm.emulate_first_insn(0, &insn).is_ok());
|
||||
|
||||
vmm.read_memory(0xc, &mut data).unwrap();
|
||||
assert_eq!(0x5678, <u16>::from_le_bytes(data));
|
||||
vmm.read_memory(0xc + 2, &mut data).unwrap();
|
||||
assert_eq!(0x1234, <u16>::from_le_bytes(data));
|
||||
vmm.read_memory(0xc + 4, &mut data).unwrap();
|
||||
assert_eq!(0xccdd, <u16>::from_le_bytes(data));
|
||||
vmm.read_memory(0xc + 6, &mut data).unwrap();
|
||||
assert_eq!(0xaabb, <u16>::from_le_bytes(data));
|
||||
vmm.read_memory(0xc + 8, &mut data).unwrap();
|
||||
assert_eq!(0x5aa5, <u16>::from_le_bytes(data));
|
||||
vmm.read_memory(0xc + 10, &mut data).unwrap();
|
||||
assert_eq!(0x5aa5, <u16>::from_le_bytes(data));
|
||||
// The rest should be default value 0 from MockVmm
|
||||
vmm.read_memory(0xc + 12, &mut data).unwrap();
|
||||
assert_eq!(0x0, <u16>::from_le_bytes(data));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_movsw_m16_m16() {
|
||||
let ip: u64 = 0x1000;
|
||||
let memory: [u8; 4] = [
|
||||
0x78, 0x56, 0x34, 0x12, // 0x12345678
|
||||
];
|
||||
let insn = [0x66, 0xa5]; // movsw
|
||||
let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)];
|
||||
let mut data = [0u8; 2];
|
||||
|
||||
let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
|
||||
|
||||
assert!(vmm.emulate_first_insn(0, &insn).is_ok());
|
||||
|
||||
vmm.read_memory(0x8, &mut data).unwrap();
|
||||
assert_eq!(0x5678, <u16>::from_le_bytes(data));
|
||||
// Only two bytes were copied, so the value at 0xa should be zero
|
||||
vmm.read_memory(0xa, &mut data).unwrap();
|
||||
assert_eq!(0x0, <u16>::from_le_bytes(data));
|
||||
// The rest should be default value 0 from MockVmm
|
||||
vmm.read_memory(0x4, &mut data).unwrap();
|
||||
assert_eq!(0x0, <u16>::from_le_bytes(data));
|
||||
vmm.read_memory(0x8 + 8, &mut data).unwrap();
|
||||
assert_eq!(0x0, <u16>::from_le_bytes(data));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_movsb_m8_m8() {
|
||||
let ip: u64 = 0x1000;
|
||||
let memory: [u8; 4] = [
|
||||
0x78, 0x56, 0x34, 0x12, // 0x12345678
|
||||
];
|
||||
let insn = [0x66, 0xa4]; // movsb
|
||||
let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)];
|
||||
let mut data = [0u8; 1];
|
||||
|
||||
let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
|
||||
|
||||
assert!(vmm.emulate_first_insn(0, &insn).is_ok());
|
||||
|
||||
vmm.read_memory(0x8, &mut data).unwrap();
|
||||
assert_eq!(0x78, data[0]);
|
||||
// Only one byte was copied, so the value at 0x9 should be zero
|
||||
vmm.read_memory(0x9, &mut data).unwrap();
|
||||
assert_eq!(0x0, data[0]);
|
||||
// The rest should be default value 0 from MockVmm
|
||||
vmm.read_memory(0x4, &mut data).unwrap();
|
||||
assert_eq!(0x0, data[0]);
|
||||
// the src value is left as is after movb
|
||||
vmm.read_memory(0x0, &mut data).unwrap();
|
||||
assert_eq!(0x78, data[0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rep_movsb_m8_m8() {
|
||||
let ip: u64 = 0x1000;
|
||||
let memory: [u8; 16] = [
|
||||
0x78, 0x56, 0x34, 0x12, // 0x12345678
|
||||
0xbb, 0xaa, 0x00, 0x00, // 0x0000aabb
|
||||
0x00, 0x00, 0x00, 0x00, // 0x00000000
|
||||
0x00, 0x00, 0x00, 0x00, // 0x00000000
|
||||
];
|
||||
let insn = [0x66, 0xf3, 0xa4]; // rep movsw
|
||||
let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0x8)];
|
||||
let mut data = [0u8; 1];
|
||||
|
||||
let mut vmm = MockVmm::new(ip, regs, Some((0, &memory)));
|
||||
|
||||
assert!(vmm.emulate_first_insn(0, &insn).is_ok());
|
||||
|
||||
vmm.read_memory(0x8, &mut data).unwrap();
|
||||
assert_eq!(0x78, data[0]);
|
||||
vmm.read_memory(0x8 + 1, &mut data).unwrap();
|
||||
assert_eq!(0x56, data[0]);
|
||||
vmm.read_memory(0x8 + 2, &mut data).unwrap();
|
||||
assert_eq!(0x34, data[0]);
|
||||
vmm.read_memory(0x8 + 3, &mut data).unwrap();
|
||||
assert_eq!(0x12, data[0]);
|
||||
vmm.read_memory(0x8 + 4, &mut data).unwrap();
|
||||
assert_eq!(0xbb, data[0]);
|
||||
vmm.read_memory(0x8 + 5, &mut data).unwrap();
|
||||
assert_eq!(0xaa, data[0]);
|
||||
// The rest should be default value 0 from MockVmm
|
||||
vmm.read_memory(0x8 + 6, &mut data).unwrap();
|
||||
assert_eq!(0x0, data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,6 +526,8 @@ impl<'a, T: CpuStateManager> Emulator<'a, T> {
|
||||
(mov, Movzx_r64_rm16),
|
||||
// MOVS
|
||||
(movs, Movsd_m32_m32),
|
||||
(movs, Movsw_m16_m16),
|
||||
(movs, Movsb_m8_m8),
|
||||
// OR
|
||||
(or, Or_rm8_r8)
|
||||
);
|
||||
|
||||
@@ -26,7 +26,6 @@ pub const MTRR_MEM_TYPE_WB: u64 = 0x6;
|
||||
pub const NUM_IOAPIC_PINS: usize = 24;
|
||||
|
||||
// X86 Exceptions
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Exception {
|
||||
DE = 0, // Divide Error
|
||||
|
||||
@@ -21,6 +21,15 @@ use crate::MpState;
|
||||
use thiserror::Error;
|
||||
use vm_memory::GuestAddress;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub enum CpuVendor {
|
||||
#[default]
|
||||
Unknown,
|
||||
Intel,
|
||||
AMD,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
///
|
||||
/// Enum for CPU error
|
||||
@@ -237,6 +246,12 @@ pub enum HypervisorCpuError {
|
||||
///
|
||||
#[error("Failed to initialize PMU")]
|
||||
InitializePmu,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Error getting TSC frequency
|
||||
///
|
||||
#[error("Failed to get TSC frequency: {0}")]
|
||||
GetTscKhz(#[source] anyhow::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -432,4 +447,11 @@ pub trait Vcpu: Send + Sync {
|
||||
/// Return the list of initial MSR entries for a VCPU
|
||||
///
|
||||
fn boot_msr_entries(&self) -> Vec<MsrEntry>;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Get the frequency of the TSC if available
|
||||
///
|
||||
fn tsc_khz(&self) -> Result<Option<u32>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,14 @@
|
||||
//
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::x86::CpuIdEntry;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::cpu::CpuVendor;
|
||||
#[cfg(feature = "tdx")]
|
||||
use crate::kvm::TdxCapabilities;
|
||||
use crate::vm::Vm;
|
||||
use crate::HypervisorType;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::arch::x86_64;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -75,6 +79,11 @@ pub enum HypervisorError {
|
||||
///
|
||||
#[error("Failed to set partition property:{0}")]
|
||||
SetPartitionProperty(#[source] anyhow::Error),
|
||||
///
|
||||
/// Running on an unsupported CPU
|
||||
///
|
||||
#[error("Unsupported CPU:{0}")]
|
||||
UnsupportedCpu(#[source] anyhow::Error),
|
||||
}
|
||||
|
||||
///
|
||||
@@ -108,7 +117,7 @@ pub trait Hypervisor: Send + Sync {
|
||||
///
|
||||
/// Get the supported CpuID
|
||||
///
|
||||
fn get_cpuid(&self) -> Result<Vec<CpuIdEntry>>;
|
||||
fn get_supported_cpuid(&self) -> Result<Vec<CpuIdEntry>>;
|
||||
///
|
||||
/// Check particular extensions if any
|
||||
///
|
||||
@@ -133,4 +142,30 @@ pub trait Hypervisor: Send + Sync {
|
||||
fn get_guest_debug_hw_bps(&self) -> usize {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Get maximum number of vCPUs
|
||||
fn get_max_vcpus(&self) -> u32;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Determine CPU vendor
|
||||
///
|
||||
fn get_cpu_vendor(&self) -> CpuVendor {
|
||||
// SAFETY: call cpuid with valid leaves
|
||||
unsafe {
|
||||
let leaf = x86_64::__cpuid(0x0);
|
||||
|
||||
if leaf.ebx == 0x756e_6547 && leaf.ecx == 0x6c65_746e && leaf.edx == 0x4965_6e69 {
|
||||
// Vendor string GenuineIntel
|
||||
CpuVendor::Intel
|
||||
} else if leaf.ebx == 0x6874_7541 && leaf.ecx == 0x444d_4163 && leaf.edx == 0x6974_6e65
|
||||
{
|
||||
// Vendor string AuthenticAMD
|
||||
CpuVendor::AMD
|
||||
} else {
|
||||
// Not known yet, the corresponding manufacturer manual should contain the
|
||||
// necesssary info. See also https://wiki.osdev.org/CPUID#CPU_Vendor_ID_String
|
||||
CpuVendor::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +243,6 @@ impl KvmGicV3Its {
|
||||
}
|
||||
|
||||
/// Method to initialize the GIC device
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(vm: &dyn Vm, config: VgicConfig) -> Result<KvmGicV3Its> {
|
||||
// This is inside KVM module
|
||||
let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?");
|
||||
|
||||
@@ -106,7 +106,7 @@ pub use {
|
||||
const KVM_CAP_SGX_ATTRIBUTE: u32 = 196;
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
const KVM_EXIT_TDX: u32 = 35;
|
||||
const KVM_EXIT_TDX: u32 = 50;
|
||||
#[cfg(feature = "tdx")]
|
||||
const TDG_VP_VMCALL_GET_QUOTE: u64 = 0x10002;
|
||||
#[cfg(feature = "tdx")]
|
||||
@@ -330,21 +330,22 @@ impl KvmVm {
|
||||
Ok(VfioDeviceFd::new_from_kvm(device_fd))
|
||||
}
|
||||
/// Checks if a particular `Cap` is available.
|
||||
fn check_extension(&self, c: Cap) -> bool {
|
||||
pub fn check_extension(&self, c: Cap) -> bool {
|
||||
self.fd.check_extension(c)
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Implementation of Vm trait for KVM
|
||||
/// Example:
|
||||
/// #[cfg(feature = "kvm")]
|
||||
/// extern crate hypervisor
|
||||
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
|
||||
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// vm.set/get().unwrap()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let kvm = KvmHypervisor::new().unwrap();
|
||||
/// let hypervisor = Arc::new(kvm);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// ```
|
||||
impl vm::Vm for KvmVm {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
@@ -746,36 +747,34 @@ impl vm::Vm for KvmVm {
|
||||
///
|
||||
#[cfg(feature = "tdx")]
|
||||
fn tdx_init(&self, cpuid: &[CpuIdEntry], max_vcpus: u32) -> vm::Result<()> {
|
||||
use std::io::{Error, ErrorKind};
|
||||
let cpuid: Vec<kvm_bindings::kvm_cpuid_entry2> =
|
||||
const TDX_ATTR_SEPT_VE_DISABLE: usize = 28;
|
||||
|
||||
let mut cpuid: Vec<kvm_bindings::kvm_cpuid_entry2> =
|
||||
cpuid.iter().map(|e| (*e).into()).collect();
|
||||
let kvm_cpuid = kvm_bindings::CpuId::from_entries(&cpuid).map_err(|_| {
|
||||
vm::HypervisorVmError::InitializeTdx(Error::new(
|
||||
ErrorKind::Other,
|
||||
"failed to allocate CpuId",
|
||||
))
|
||||
})?;
|
||||
cpuid.resize(256, kvm_bindings::kvm_cpuid_entry2::default());
|
||||
|
||||
#[repr(C)]
|
||||
struct TdxInitVm {
|
||||
max_vcpus: u32,
|
||||
tsc_khz: u32,
|
||||
attributes: u64,
|
||||
cpuid: u64,
|
||||
max_vcpus: u32,
|
||||
padding: u32,
|
||||
mrconfigid: [u64; 6],
|
||||
mrowner: [u64; 6],
|
||||
mrownerconfig: [u64; 6],
|
||||
reserved: [u64; 43],
|
||||
cpuid_nent: u32,
|
||||
cpuid_padding: u32,
|
||||
cpuid_entries: [kvm_bindings::kvm_cpuid_entry2; 256],
|
||||
}
|
||||
let data = TdxInitVm {
|
||||
attributes: 1 << TDX_ATTR_SEPT_VE_DISABLE,
|
||||
max_vcpus,
|
||||
tsc_khz: 0,
|
||||
attributes: 0,
|
||||
cpuid: kvm_cpuid.as_fam_struct_ptr() as u64,
|
||||
padding: 0,
|
||||
mrconfigid: [0; 6],
|
||||
mrowner: [0; 6],
|
||||
mrownerconfig: [0; 6],
|
||||
reserved: [0; 43],
|
||||
cpuid_nent: cpuid.len() as u32,
|
||||
cpuid_padding: 0,
|
||||
cpuid_entries: cpuid.as_slice().try_into().unwrap(),
|
||||
};
|
||||
|
||||
tdx_command(
|
||||
@@ -837,19 +836,23 @@ impl vm::Vm for KvmVm {
|
||||
fn tdx_command(
|
||||
fd: &RawFd,
|
||||
command: TdxCommand,
|
||||
metadata: u32,
|
||||
flags: u32,
|
||||
data: u64,
|
||||
) -> std::result::Result<(), std::io::Error> {
|
||||
#[repr(C)]
|
||||
struct TdxIoctlCmd {
|
||||
command: TdxCommand,
|
||||
metadata: u32,
|
||||
flags: u32,
|
||||
data: u64,
|
||||
error: u64,
|
||||
unused: u64,
|
||||
}
|
||||
let cmd = TdxIoctlCmd {
|
||||
command,
|
||||
metadata,
|
||||
flags,
|
||||
data,
|
||||
error: 0,
|
||||
unused: 0,
|
||||
};
|
||||
// SAFETY: FFI call. All input parameters are valid.
|
||||
let ret = unsafe {
|
||||
@@ -915,13 +918,16 @@ impl KvmHypervisor {
|
||||
}
|
||||
}
|
||||
/// Implementation of Hypervisor trait for KVM
|
||||
/// Example:
|
||||
/// #[cfg(feature = "kvm")]
|
||||
/// extern crate hypervisor
|
||||
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
|
||||
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let kvm = KvmHypervisor::new().unwrap();
|
||||
/// let hypervisor = Arc::new(kvm);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// ```
|
||||
impl hypervisor::Hypervisor for KvmHypervisor {
|
||||
///
|
||||
/// Returns the type of the hypervisor
|
||||
@@ -930,13 +936,15 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
||||
HypervisorType::Kvm
|
||||
}
|
||||
/// Create a KVM vm object of a specific VM type and return the object as Vm trait object
|
||||
/// Example
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::KvmHypervisor;
|
||||
/// use hypervisor::KvmVm;
|
||||
/// let hypervisor = KvmHypervisor::new().unwrap();
|
||||
/// let vm = hypervisor.create_vm_with_type(KvmVmType::LegacyVm).unwrap()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// use hypervisor::kvm::KvmVm;
|
||||
/// let hypervisor = KvmHypervisor::new().unwrap();
|
||||
/// let vm = hypervisor.create_vm_with_type(0).unwrap();
|
||||
/// ```
|
||||
fn create_vm_with_type(&self, vm_type: u64) -> hypervisor::Result<Arc<dyn vm::Vm>> {
|
||||
let fd: VmFd;
|
||||
loop {
|
||||
@@ -990,13 +998,15 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
||||
}
|
||||
|
||||
/// Create a KVM vm object and return the object as Vm trait object
|
||||
/// Example
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::KvmHypervisor;
|
||||
/// use hypervisor::KvmVm;
|
||||
/// let hypervisor = KvmHypervisor::new().unwrap();
|
||||
/// let vm = hypervisor.create_vm().unwrap()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// use hypervisor::kvm::KvmVm;
|
||||
/// let hypervisor = KvmHypervisor::new().unwrap();
|
||||
/// let vm = hypervisor.create_vm().unwrap();
|
||||
/// ```
|
||||
fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> {
|
||||
#[allow(unused_mut)]
|
||||
let mut vm_type: u64 = 0; // Create with default platform type
|
||||
@@ -1021,7 +1031,7 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
||||
///
|
||||
/// X86 specific call to get the system supported CPUID values.
|
||||
///
|
||||
fn get_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> {
|
||||
fn get_supported_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> {
|
||||
let kvm_cpuid = self
|
||||
.kvm
|
||||
.get_supported_cpuid(kvm_bindings::KVM_MAX_CPUID_ENTRIES)
|
||||
@@ -1074,6 +1084,11 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
||||
self.kvm.get_guest_debug_hw_bps() as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// Get maximum number of vCPUs
|
||||
fn get_max_vcpus(&self) -> u32 {
|
||||
self.kvm.get_max_vcpus().min(u32::MAX as usize) as u32
|
||||
}
|
||||
}
|
||||
/// Vcpu struct for KVM
|
||||
pub struct KvmVcpu {
|
||||
@@ -1085,15 +1100,17 @@ pub struct KvmVcpu {
|
||||
hyperv_synic: AtomicBool,
|
||||
}
|
||||
/// Implementation of Vcpu trait for KVM
|
||||
/// Example:
|
||||
/// #[cfg(feature = "kvm")]
|
||||
/// extern crate hypervisor
|
||||
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
|
||||
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let kvm = KvmHypervisor::new().unwrap();
|
||||
/// let hypervisor = Arc::new(kvm);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// let vcpu = vm.create_vcpu(0, None).unwrap();
|
||||
/// vcpu.get/set().unwrap()
|
||||
///
|
||||
/// ```
|
||||
impl cpu::Vcpu for KvmVcpu {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
@@ -1795,11 +1812,10 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::KvmHypervisor;
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
|
||||
/// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
|
||||
/// let kvm = KvmHypervisor::new().unwrap();
|
||||
/// let hv = Arc::new(kvm);
|
||||
/// let vm = hv.create_vm().expect("new VM fd creation failed");
|
||||
/// vm.enable_split_irq().unwrap();
|
||||
/// let vcpu = vm.create_vcpu(0, None).unwrap();
|
||||
@@ -1967,11 +1983,10 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::KvmHypervisor;
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
|
||||
/// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
|
||||
/// let kvm = KvmHypervisor::new().unwrap();
|
||||
/// let hv = Arc::new(kvm);
|
||||
/// let vm = hv.create_vm().expect("new VM fd creation failed");
|
||||
/// vm.enable_split_irq().unwrap();
|
||||
/// let vcpu = vm.create_vcpu(0, None).unwrap();
|
||||
@@ -2154,6 +2169,23 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.set_device_attr(&cpu_attr)
|
||||
.map_err(|_| cpu::HypervisorCpuError::InitializePmu)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Get the frequency of the TSC if available
|
||||
///
|
||||
fn tsc_khz(&self) -> cpu::Result<Option<u32>> {
|
||||
match self.fd.get_tsc_khz() {
|
||||
Err(e) => {
|
||||
if e.errno() == libc::EIO {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(cpu::HypervisorCpuError::GetTscKhz(e.into()))
|
||||
}
|
||||
}
|
||||
Ok(v) => Ok(Some(v)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KvmVcpu {
|
||||
|
||||
@@ -50,6 +50,9 @@ pub fn check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()> {
|
||||
if !kvm.check_extension(Cap::ImmediateExit) {
|
||||
return Err(KvmError::CapabilityMissing(Cap::ImmediateExit));
|
||||
}
|
||||
if !kvm.check_extension(Cap::GetTscKhz) {
|
||||
return Err(KvmError::CapabilityMissing(Cap::GetTscKhz));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
|
||||
@@ -48,9 +48,11 @@ mod cpu;
|
||||
/// Device related module
|
||||
mod device;
|
||||
|
||||
pub use crate::hypervisor::{Hypervisor, HypervisorError};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use cpu::CpuVendor;
|
||||
pub use cpu::{HypervisorCpuError, Vcpu, VmExit};
|
||||
pub use device::HypervisorDeviceError;
|
||||
pub use hypervisor::{Hypervisor, HypervisorError};
|
||||
#[cfg(all(feature = "kvm", target_arch = "aarch64"))]
|
||||
pub use kvm::{aarch64, GicState};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -195,13 +195,16 @@ impl MshvHypervisor {
|
||||
}
|
||||
}
|
||||
/// Implementation of Hypervisor trait for Mshv
|
||||
/// Example:
|
||||
/// #[cfg(feature = "mshv")]
|
||||
/// extern crate hypervisor
|
||||
/// let mshv = hypervisor::mshv::MshvHypervisor::new().unwrap();
|
||||
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::mshv::MshvHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let mshv = MshvHypervisor::new().unwrap();
|
||||
/// let hypervisor = Arc::new(mshv);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// ```
|
||||
impl hypervisor::Hypervisor for MshvHypervisor {
|
||||
///
|
||||
/// Returns the type of the hypervisor
|
||||
@@ -210,13 +213,16 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
||||
HypervisorType::Mshv
|
||||
}
|
||||
/// Create a mshv vm object and return the object as Vm trait object
|
||||
/// Example
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::MshvHypervisor;
|
||||
/// use hypervisor::MshvVm;
|
||||
/// let hypervisor = MshvHypervisor::new().unwrap();
|
||||
/// let vm = hypervisor.create_vm().unwrap()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::mshv::MshvHypervisor;
|
||||
/// use hypervisor::mshv::MshvVm;
|
||||
/// let hypervisor = MshvHypervisor::new().unwrap();
|
||||
/// let vm = hypervisor.create_vm().unwrap();
|
||||
/// ```
|
||||
fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> {
|
||||
let fd: VmFd;
|
||||
loop {
|
||||
@@ -270,9 +276,16 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
||||
///
|
||||
/// Get the supported CpuID
|
||||
///
|
||||
fn get_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> {
|
||||
fn get_supported_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
/// Get maximum number of vCPUs
|
||||
fn get_max_vcpus(&self) -> u32 {
|
||||
// TODO: Using HV_MAXIMUM_PROCESSORS would be better
|
||||
// but the ioctl API is limited to u8
|
||||
256
|
||||
}
|
||||
}
|
||||
|
||||
/// Vcpu struct for Microsoft Hypervisor
|
||||
@@ -285,15 +298,17 @@ pub struct MshvVcpu {
|
||||
}
|
||||
|
||||
/// Implementation of Vcpu trait for Microsoft Hypervisor
|
||||
/// Example:
|
||||
/// #[cfg(feature = "mshv")]
|
||||
/// extern crate hypervisor
|
||||
/// let mshv = hypervisor::mshv::MshvHypervisor::new().unwrap();
|
||||
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// let vcpu = vm.create_vcpu(0).unwrap();
|
||||
/// vcpu.get/set().unwrap()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::mshv::MshvHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let mshv = MshvHypervisor::new().unwrap();
|
||||
/// let hypervisor = Arc::new(mshv);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// let vcpu = vm.create_vcpu(0, None).unwrap();
|
||||
/// ```
|
||||
impl cpu::Vcpu for MshvVcpu {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
@@ -446,10 +461,10 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
/* Advance RIP and update RAX */
|
||||
let arr_reg_name_value = [
|
||||
(
|
||||
hv_x64_register_name_HV_X64_REGISTER_RIP,
|
||||
hv_register_name_HV_X64_REGISTER_RIP,
|
||||
info.header.rip + insn_len,
|
||||
),
|
||||
(hv_x64_register_name_HV_X64_REGISTER_RAX, ret_rax),
|
||||
(hv_register_name_HV_X64_REGISTER_RAX, ret_rax),
|
||||
];
|
||||
set_registers_64!(self.fd, arr_reg_name_value)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
|
||||
@@ -495,10 +510,10 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
/* Advance RIP and update RAX */
|
||||
let arr_reg_name_value = [
|
||||
(
|
||||
hv_x64_register_name_HV_X64_REGISTER_RIP,
|
||||
hv_register_name_HV_X64_REGISTER_RIP,
|
||||
info.header.rip + insn_len,
|
||||
),
|
||||
(hv_x64_register_name_HV_X64_REGISTER_RAX, ret_rax),
|
||||
(hv_register_name_HV_X64_REGISTER_RAX, ret_rax),
|
||||
];
|
||||
set_registers_64!(self.fd, arr_reg_name_value)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
|
||||
@@ -568,8 +583,14 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
///
|
||||
/// X86 specific call to setup the CPUID registers.
|
||||
///
|
||||
fn set_cpuid2(&self, _cpuid: &[CpuIdEntry]) -> cpu::Result<()> {
|
||||
Ok(())
|
||||
fn set_cpuid2(&self, cpuid: &[CpuIdEntry]) -> cpu::Result<()> {
|
||||
let cpuid: Vec<mshv_bindings::hv_cpuid_entry> = cpuid.iter().map(|e| (*e).into()).collect();
|
||||
let mshv_cpuid = <CpuId>::from_entries(&cpuid)
|
||||
.map_err(|_| cpu::HypervisorCpuError::SetCpuid(anyhow!("failed to create CpuId")))?;
|
||||
|
||||
self.fd
|
||||
.register_intercept_result_cpuid(&mshv_cpuid)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into()))
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
@@ -917,15 +938,17 @@ impl MshvVm {
|
||||
|
||||
///
|
||||
/// Implementation of Vm trait for Mshv
|
||||
/// Example:
|
||||
/// #[cfg(feature = "mshv")]
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::MshvHypervisor;
|
||||
/// let mshv = MshvHypervisor::new().unwrap();
|
||||
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// vm.set/get().unwrap()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::mshv::MshvHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let mshv = MshvHypervisor::new().unwrap();
|
||||
/// let hypervisor = Arc::new(mshv);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// ```
|
||||
impl vm::Vm for MshvVm {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
impl<T> __IncompleteArrayField<T> {
|
||||
#[inline]
|
||||
pub const fn new() -> Self {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
impl<T> __IncompleteArrayField<T> {
|
||||
#[inline]
|
||||
pub const fn new() -> Self {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the THIRD-PARTY file.
|
||||
|
||||
#![allow(clippy::all)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
@@ -28,10 +27,12 @@ pub mod inn;
|
||||
// generated with bindgen /usr/include/linux/sockios.h --no-unstable-rust
|
||||
// --constified-enum '*' --with-derive-default
|
||||
pub mod sockios;
|
||||
pub use if_tun::*;
|
||||
pub use iff::*;
|
||||
pub use inn::*;
|
||||
pub use sockios::*;
|
||||
pub use if_tun::{
|
||||
sock_fprog, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_TAP, IFF_VNET_HDR, TUN_F_CSUM, TUN_F_TSO4,
|
||||
TUN_F_TSO6, TUN_F_TSO_ECN, TUN_F_UFO,
|
||||
};
|
||||
pub use iff::{ifreq, net_device_flags_IFF_UP, setsockopt, sockaddr, AF_INET};
|
||||
pub use inn::sockaddr_in;
|
||||
|
||||
pub const TUNTAP: ::std::os::raw::c_uint = 84;
|
||||
|
||||
|
||||
@@ -11,18 +11,18 @@ libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
net_gen = { path = "../net_gen" }
|
||||
rate_limiter = { path = "../rate_limiter" }
|
||||
serde = "1.0.151"
|
||||
thiserror = "1.0.38"
|
||||
versionize = "0.1.9"
|
||||
serde = "1.0.164"
|
||||
thiserror = "1.0.40"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
virtio-bindings = "0.1.0"
|
||||
virtio-queue = "0.7.0"
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
virtio-bindings = "0.2.0"
|
||||
virtio-queue = "0.8.0"
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
[dev-dependencies]
|
||||
once_cell = "1.16.0"
|
||||
pnet = "0.31.0"
|
||||
pnet_datalink = "0.31.0"
|
||||
serde_json = "1.0.89"
|
||||
once_cell = "1.17.1"
|
||||
pnet = "0.33.0"
|
||||
pnet_datalink = "0.33.0"
|
||||
serde_json = "1.0.96"
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::GuestMemoryMmap;
|
||||
use crate::Tap;
|
||||
use libc::c_uint;
|
||||
use std::sync::Arc;
|
||||
use virtio_bindings::bindings::virtio_net::{
|
||||
use virtio_bindings::virtio_net::{
|
||||
VIRTIO_NET_CTRL_GUEST_OFFLOADS, VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, VIRTIO_NET_CTRL_MQ,
|
||||
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN,
|
||||
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, VIRTIO_NET_ERR, VIRTIO_NET_F_GUEST_CSUM,
|
||||
|
||||
@@ -21,7 +21,7 @@ use std::{io, mem, net};
|
||||
use thiserror::Error;
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use virtio_bindings::bindings::virtio_net::{
|
||||
use virtio_bindings::virtio_net::{
|
||||
virtio_net_hdr_v1, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN,
|
||||
VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_TSO4,
|
||||
VIRTIO_NET_F_GUEST_TSO6, VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_F_MAC, VIRTIO_NET_F_MQ,
|
||||
|
||||
@@ -10,20 +10,21 @@ kvm = ["vfio-ioctls/kvm"]
|
||||
mshv = ["vfio-ioctls/mshv"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.68"
|
||||
anyhow = "1.0.71"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main", features = ["fam-wrappers"] }
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||
vfio_user = { path = "../vfio_user" }
|
||||
vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" }
|
||||
|
||||
vmm-sys-util = "0.11.0"
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
serde = { version = "1.0.151", features = ["derive"] }
|
||||
thiserror = "1.0.38"
|
||||
versionize = "0.1.9"
|
||||
serde = { version = "1.0.164", features = ["derive"] }
|
||||
thiserror = "1.0.40"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = "0.10.0"
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
|
||||
@@ -452,10 +452,9 @@ impl From<PciBarType> for PciBarRegionType {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::from_over_into)]
|
||||
impl Into<PciBarType> for PciBarRegionType {
|
||||
fn into(self) -> PciBarType {
|
||||
match self {
|
||||
impl From<PciBarRegionType> for PciBarType {
|
||||
fn from(val: PciBarRegionType) -> Self {
|
||||
match val {
|
||||
PciBarRegionType::IoRegion => PciBarType::Io,
|
||||
PciBarRegionType::Memory32BitRegion => PciBarType::Mmio32,
|
||||
PciBarRegionType::Memory64BitRegion => PciBarType::Mmio64,
|
||||
@@ -469,10 +468,9 @@ pub enum PciBarPrefetchable {
|
||||
Prefetchable = 0x08,
|
||||
}
|
||||
|
||||
#[allow(clippy::from_over_into)]
|
||||
impl Into<bool> for PciBarPrefetchable {
|
||||
fn into(self) -> bool {
|
||||
match self {
|
||||
impl From<PciBarPrefetchable> for bool {
|
||||
fn from(val: PciBarPrefetchable) -> Self {
|
||||
match val {
|
||||
PciBarPrefetchable::NotPrefetchable => false,
|
||||
PciBarPrefetchable::Prefetchable => true,
|
||||
}
|
||||
|
||||
@@ -511,6 +511,16 @@ impl MsixCap {
|
||||
self.pba & 0xffff_fff8
|
||||
}
|
||||
|
||||
pub fn table_set_offset(&mut self, addr: u32) {
|
||||
self.table &= 0x7;
|
||||
self.table += addr;
|
||||
}
|
||||
|
||||
pub fn pba_set_offset(&mut self, addr: u32) {
|
||||
self.pba &= 0x7;
|
||||
self.pba += addr;
|
||||
}
|
||||
|
||||
pub fn table_bir(&self) -> u32 {
|
||||
self.table & 0x7
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use crate::{
|
||||
use anyhow::anyhow;
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use hypervisor::HypervisorVmError;
|
||||
use libc::{sysconf, _SC_PAGESIZE};
|
||||
use std::any::Any;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::io;
|
||||
@@ -27,6 +28,9 @@ use vfio_bindings::bindings::vfio::*;
|
||||
use vfio_ioctls::{
|
||||
VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap, VfioRegionSparseMmapArea,
|
||||
};
|
||||
use vm_allocator::page_size::{
|
||||
align_page_size_down, align_page_size_up, is_4k_aligned, is_4k_multiple, is_page_size_aligned,
|
||||
};
|
||||
use vm_allocator::{AddressAllocator, SystemAllocator};
|
||||
use vm_device::interrupt::{
|
||||
InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig,
|
||||
@@ -498,6 +502,29 @@ impl VfioCommon {
|
||||
Ok(vfio_common)
|
||||
}
|
||||
|
||||
/// In case msix table offset is not page size aligned, we need do some fixup to achive it.
|
||||
/// Becuse we don't want the MMIO RW region and trap region overlap each other.
|
||||
fn fixup_msix_region(&mut self, bar_id: u32, region_size: u64) -> u64 {
|
||||
let msix = self.interrupt.msix.as_mut().unwrap();
|
||||
let msix_cap = &mut msix.cap;
|
||||
|
||||
// Suppose table_bir equals to pba_bir here. Am I right?
|
||||
let (table_offset, table_size) = msix_cap.table_range();
|
||||
if is_page_size_aligned(table_offset) || msix_cap.table_bir() != bar_id {
|
||||
return region_size;
|
||||
}
|
||||
|
||||
let (pba_offset, pba_size) = msix_cap.pba_range();
|
||||
let msix_sz = align_page_size_up(table_size + pba_size);
|
||||
// Expand region to hold RW and trap region which both page size aligned
|
||||
let size = std::cmp::max(region_size * 2, msix_sz * 2);
|
||||
// let table starts from the middle of the region
|
||||
msix_cap.table_set_offset((size / 2) as u32);
|
||||
msix_cap.pba_set_offset((size / 2 + pba_offset - table_offset) as u32);
|
||||
|
||||
size
|
||||
}
|
||||
|
||||
pub(crate) fn allocate_bars(
|
||||
&mut self,
|
||||
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||
@@ -661,9 +688,16 @@ impl VfioCommon {
|
||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
|
||||
}
|
||||
PciBarRegionType::Memory64BitRegion => {
|
||||
// BAR allocation must be naturally aligned
|
||||
// We need do some fixup to keep MMIO RW region and msix cap region page size
|
||||
// aligned.
|
||||
region_size = self.fixup_msix_region(bar_id, region_size);
|
||||
mmio_allocator
|
||||
.allocate(restored_bar_addr, region_size, Some(region_size))
|
||||
.allocate(
|
||||
restored_bar_addr,
|
||||
region_size,
|
||||
// SAFETY: FFI call. Trivially safe.
|
||||
Some(unsafe { sysconf(_SC_PAGESIZE) as GuestUsize }),
|
||||
)
|
||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
|
||||
}
|
||||
};
|
||||
@@ -800,6 +834,23 @@ impl VfioCommon {
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn get_msix_cap_idx(&self) -> Option<usize> {
|
||||
let mut cap_next = self
|
||||
.vfio_wrapper
|
||||
.read_config_byte(PCI_CONFIG_CAPABILITY_OFFSET);
|
||||
|
||||
while cap_next != 0 {
|
||||
let cap_id = self.vfio_wrapper.read_config_byte(cap_next.into());
|
||||
if PciCapabilityId::from(cap_id) == PciCapabilityId::MsiX {
|
||||
return Some(cap_next as usize);
|
||||
} else {
|
||||
cap_next = self.vfio_wrapper.read_config_byte((cap_next + 1).into());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn parse_capabilities(&mut self, bdf: PciBdf) {
|
||||
let mut cap_next = self
|
||||
.vfio_wrapper
|
||||
@@ -1154,6 +1205,15 @@ impl VfioCommon {
|
||||
return self.configuration.read_reg(reg_idx);
|
||||
}
|
||||
|
||||
if let Some(id) = self.get_msix_cap_idx() {
|
||||
let msix = self.interrupt.msix.as_mut().unwrap();
|
||||
if reg_idx * 4 == id + 4 {
|
||||
return msix.cap.table;
|
||||
} else if reg_idx * 4 == id + 8 {
|
||||
return msix.cap.pba;
|
||||
}
|
||||
}
|
||||
|
||||
// Since we don't support passing multi-functions devices, we should
|
||||
// mask the multi-function bit, bit 7 of the Header Type byte on the
|
||||
// register 3.
|
||||
@@ -1316,18 +1376,6 @@ impl VfioPciDevice {
|
||||
self.iommu_attached
|
||||
}
|
||||
|
||||
fn align_4k(address: u64) -> u64 {
|
||||
(address + 0xfff) & 0xffff_ffff_ffff_f000
|
||||
}
|
||||
|
||||
fn is_4k_aligned(address: u64) -> bool {
|
||||
(address & 0xfff) == 0
|
||||
}
|
||||
|
||||
fn is_4k_multiple(size: u64) -> bool {
|
||||
(size & 0xfff) == 0
|
||||
}
|
||||
|
||||
fn generate_sparse_areas(
|
||||
caps: &[VfioRegionInfoCap],
|
||||
region_index: u32,
|
||||
@@ -1339,14 +1387,14 @@ impl VfioPciDevice {
|
||||
match cap {
|
||||
VfioRegionInfoCap::SparseMmap(sparse_mmap) => return Ok(sparse_mmap.areas.clone()),
|
||||
VfioRegionInfoCap::MsixMappable => {
|
||||
if !Self::is_4k_aligned(region_start) {
|
||||
if !is_4k_aligned(region_start) {
|
||||
error!(
|
||||
"Region start address 0x{:x} must be at least aligned on 4KiB",
|
||||
region_start
|
||||
);
|
||||
return Err(VfioPciError::RegionAlignment);
|
||||
}
|
||||
if !Self::is_4k_multiple(region_size) {
|
||||
if !is_4k_multiple(region_size) {
|
||||
error!(
|
||||
"Region size 0x{:x} must be at least a multiple of 4KiB",
|
||||
region_size
|
||||
@@ -1358,7 +1406,8 @@ impl VfioPciDevice {
|
||||
// the MSI-X PBA table, we must calculate the subregions
|
||||
// around them, leading to a list of sparse areas.
|
||||
// We want to make sure we will still trap MMIO accesses
|
||||
// to these MSI-X specific ranges.
|
||||
// to these MSI-X specific ranges. If these region don't align
|
||||
// with pagesize, we can achive it by enlarging its range.
|
||||
//
|
||||
// Using a BtreeMap as the list provided through the iterator is sorted
|
||||
// by key. This ensures proper split of the whole region.
|
||||
@@ -1366,10 +1415,14 @@ impl VfioPciDevice {
|
||||
if let Some(msix) = vfio_msix {
|
||||
if region_index == msix.cap.table_bir() {
|
||||
let (offset, size) = msix.cap.table_range();
|
||||
let offset = align_page_size_down(offset);
|
||||
let size = align_page_size_up(size);
|
||||
inter_ranges.insert(offset, size);
|
||||
}
|
||||
if region_index == msix.cap.pba_bir() {
|
||||
let (offset, size) = msix.cap.pba_range();
|
||||
let offset = align_page_size_down(offset);
|
||||
let size = align_page_size_up(size);
|
||||
inter_ranges.insert(offset, size);
|
||||
}
|
||||
}
|
||||
@@ -1383,8 +1436,7 @@ impl VfioPciDevice {
|
||||
size: range_offset - current_offset,
|
||||
});
|
||||
}
|
||||
|
||||
current_offset = Self::align_4k(range_offset + range_size);
|
||||
current_offset = align_page_size_down(range_offset + range_size);
|
||||
}
|
||||
|
||||
if region_size > current_offset {
|
||||
@@ -1482,6 +1534,15 @@ impl VfioPciDevice {
|
||||
return Err(VfioPciError::MmapArea);
|
||||
}
|
||||
|
||||
if !is_page_size_aligned(area.size) || !is_page_size_aligned(area.offset) {
|
||||
warn!(
|
||||
"Could not mmap sparse area that is not page size aligned (offset = 0x{:x}, size = 0x{:x})",
|
||||
area.offset,
|
||||
area.size,
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let user_memory_region = UserMemoryRegion {
|
||||
slot: (self.memory_slot)(),
|
||||
start: region.start.0 + area.offset,
|
||||
|
||||
@@ -3,13 +3,13 @@ name = "performance-metrics"
|
||||
version = "0.1.0"
|
||||
authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
build = "build.rs"
|
||||
build = "../build.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.0.32", features = ["wrap_help"] }
|
||||
dirs = "4.0.0"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.89"
|
||||
argh = "0.1.9"
|
||||
dirs = "5.0.0"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
test_infra = { path = "../test_infra" }
|
||||
thiserror = "1.0.38"
|
||||
thiserror = "1.0.40"
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright © 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
let mut git_human_readable = "v".to_owned() + env!("CARGO_PKG_VERSION");
|
||||
|
||||
if let Ok(git_out) = Command::new("git").args(["describe", "--dirty"]).output() {
|
||||
if git_out.status.success() {
|
||||
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
|
||||
git_human_readable = git_out_str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This println!() has a special behavior, as it will set the environment
|
||||
// variable GIT_HUMAN_READABLE, so that it can be reused from the binary.
|
||||
// Particularly, this is used from the main.rs to display the exact
|
||||
// version information.
|
||||
println!("cargo:rustc-env=GIT_HUMAN_READABLE={git_human_readable}");
|
||||
}
|
||||
@@ -8,11 +8,11 @@ extern crate test_infra;
|
||||
|
||||
mod performance_tests;
|
||||
|
||||
use clap::{Arg, ArgAction, Command as ClapCommand};
|
||||
use argh::FromArgs;
|
||||
use performance_tests::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
env, fmt,
|
||||
fmt,
|
||||
process::Command,
|
||||
sync::{mpsc::channel, Arc},
|
||||
thread,
|
||||
@@ -110,18 +110,23 @@ impl Default for MetricsReport {
|
||||
#[derive(Default)]
|
||||
pub struct PerformanceTestOverrides {
|
||||
test_iterations: Option<u32>,
|
||||
test_timeout: Option<u32>,
|
||||
}
|
||||
|
||||
impl fmt::Display for PerformanceTestOverrides {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(test_iterations) = self.test_iterations {
|
||||
write!(f, "test_iterations = {test_iterations}")?;
|
||||
write!(f, "test_iterations = {test_iterations}, ")?;
|
||||
}
|
||||
if let Some(test_timeout) = self.test_timeout {
|
||||
write!(f, "test_timeout = {test_timeout}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PerformanceTestControl {
|
||||
test_timeout: u32,
|
||||
test_iterations: u32,
|
||||
@@ -188,7 +193,14 @@ impl PerformanceTest {
|
||||
.test_iterations
|
||||
.unwrap_or(self.control.test_iterations)
|
||||
{
|
||||
metrics.push((self.func_ptr)(&self.control));
|
||||
// update the timeout in control if passed explicitly and run testcase with it
|
||||
if let Some(test_timeout) = overrides.test_timeout {
|
||||
let mut control: PerformanceTestControl = self.control.clone();
|
||||
control.test_timeout = test_timeout;
|
||||
metrics.push((self.func_ptr)(&control));
|
||||
} else {
|
||||
metrics.push((self.func_ptr)(&self.control));
|
||||
}
|
||||
}
|
||||
|
||||
let mean = (self.unit_adjuster)(mean(&metrics).unwrap());
|
||||
@@ -207,9 +219,9 @@ impl PerformanceTest {
|
||||
|
||||
// Calculate the timeout for each test
|
||||
// Note: To cover the setup/cleanup time, 20s is added for each iteration of the test
|
||||
pub fn calc_timeout(&self, test_iterations: &Option<u32>) -> u64 {
|
||||
((self.control.test_timeout + 20) * test_iterations.unwrap_or(self.control.test_iterations))
|
||||
as u64
|
||||
pub fn calc_timeout(&self, test_iterations: &Option<u32>, test_timeout: &Option<u32>) -> u64 {
|
||||
((test_timeout.unwrap_or(self.control.test_timeout) + 20)
|
||||
* test_iterations.unwrap_or(self.control.test_iterations)) as u64
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,6 +599,7 @@ fn run_test_with_timeout(
|
||||
) -> Result<PerformanceTestResult, Error> {
|
||||
let (sender, receiver) = channel::<Result<PerformanceTestResult, Error>>();
|
||||
let test_iterations = overrides.test_iterations;
|
||||
let test_timeout = overrides.test_timeout;
|
||||
let overrides = overrides.clone();
|
||||
thread::spawn(move || {
|
||||
println!(
|
||||
@@ -609,7 +622,7 @@ fn run_test_with_timeout(
|
||||
});
|
||||
|
||||
// Todo: Need to cleanup/kill all hanging child processes
|
||||
let test_timeout = test.calc_timeout(&test_iterations);
|
||||
let test_timeout = test.calc_timeout(&test_iterations, &test_timeout);
|
||||
receiver
|
||||
.recv_timeout(Duration::from_secs(test_timeout))
|
||||
.map_err(|_| {
|
||||
@@ -626,39 +639,41 @@ fn date() -> String {
|
||||
String::from_utf8_lossy(&output.stdout).trim().to_string()
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
/// Generate the performance metrics data for Cloud Hypervisor
|
||||
struct Options {
|
||||
#[argh(switch, long = "list-tests")]
|
||||
/// print the list of available metrics tests
|
||||
list_tests: bool,
|
||||
|
||||
#[argh(option, long = "test-filter")]
|
||||
/// filter metrics tests to run based on provided keywords
|
||||
keywords: Vec<String>,
|
||||
|
||||
#[argh(option, long = "report-file")]
|
||||
/// report file. Stderr is used if not specified
|
||||
report_file: Option<String>,
|
||||
|
||||
#[argh(option, long = "iterations")]
|
||||
/// override number of test iterations
|
||||
iterations: Option<u32>,
|
||||
|
||||
#[argh(option, long = "timeout")]
|
||||
/// override test timeout, Ex. --timeout 5
|
||||
timeout: Option<u32>,
|
||||
|
||||
#[argh(switch, short = 'V', long = "version")]
|
||||
/// print version information
|
||||
version: bool,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cmd_arguments = ClapCommand::new("performance-metrics")
|
||||
.version(env!("GIT_HUMAN_READABLE"))
|
||||
.author(env!("CARGO_PKG_AUTHORS"))
|
||||
.about("Generate the performance metrics data for Cloud Hypervisor")
|
||||
.arg(
|
||||
Arg::new("test-filter")
|
||||
.long("test-filter")
|
||||
.help("Filter metrics tests to run based on provided keywords")
|
||||
.num_args(1)
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("list-tests")
|
||||
.long("list-tests")
|
||||
.help("Print the list of availale metrics tests")
|
||||
.num_args(0)
|
||||
.action(ArgAction::SetTrue)
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("report-file")
|
||||
.long("report-file")
|
||||
.help("Report file. Standard error is used if not specified")
|
||||
.num_args(1),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("iterations")
|
||||
.long("iterations")
|
||||
.help("Override number of test iterations")
|
||||
.num_args(1),
|
||||
)
|
||||
.get_matches();
|
||||
let opts: Options = argh::from_env();
|
||||
|
||||
if opts.version {
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
|
||||
return;
|
||||
}
|
||||
|
||||
// It seems that the tool (ethr) used for testing the virtio-net latency
|
||||
// is not stable on AArch64, and therefore the latency test is currently
|
||||
@@ -668,7 +683,7 @@ fn main() {
|
||||
.filter(|t| !(cfg!(target_arch = "aarch64") && t.name == "virtio_net_latency_us"))
|
||||
.collect();
|
||||
|
||||
if cmd_arguments.get_flag("list-tests") {
|
||||
if opts.list_tests {
|
||||
for test in test_list.iter() {
|
||||
println!("\"{}\" ({})", test.name, test.control);
|
||||
}
|
||||
@@ -676,10 +691,7 @@ fn main() {
|
||||
return;
|
||||
}
|
||||
|
||||
let test_filter = match cmd_arguments.get_many::<String>("test-filter") {
|
||||
Some(s) => s.collect(),
|
||||
None => Vec::new(),
|
||||
};
|
||||
let test_filter = opts.keywords.iter().collect::<Vec<&String>>();
|
||||
|
||||
// Run performance tests sequentially and report results (in both readable/json format)
|
||||
let mut metrics_report: MetricsReport = Default::default();
|
||||
@@ -687,11 +699,8 @@ fn main() {
|
||||
init_tests();
|
||||
|
||||
let overrides = Arc::new(PerformanceTestOverrides {
|
||||
test_iterations: cmd_arguments
|
||||
.get_one::<String>("iterations")
|
||||
.map(|s| s.parse())
|
||||
.transpose()
|
||||
.unwrap_or_default(),
|
||||
test_iterations: opts.iterations,
|
||||
test_timeout: opts.timeout,
|
||||
});
|
||||
|
||||
for test in test_list.iter() {
|
||||
@@ -710,19 +719,18 @@ fn main() {
|
||||
|
||||
cleanup_tests();
|
||||
|
||||
let mut report_file: Box<dyn std::io::Write + Send> =
|
||||
if let Some(file) = cmd_arguments.get_one::<String>("report-file") {
|
||||
Box::new(
|
||||
std::fs::File::create(std::path::Path::new(file))
|
||||
.map_err(|e| {
|
||||
eprintln!("Error opening report file: {file}: {e}");
|
||||
std::process::exit(1);
|
||||
})
|
||||
.unwrap(),
|
||||
)
|
||||
} else {
|
||||
Box::new(std::io::stdout())
|
||||
};
|
||||
let mut report_file: Box<dyn std::io::Write + Send> = if let Some(ref file) = opts.report_file {
|
||||
Box::new(
|
||||
std::fs::File::create(std::path::Path::new(file))
|
||||
.map_err(|e| {
|
||||
eprintln!("Error opening report file: {file}: {e}");
|
||||
std::process::exit(1);
|
||||
})
|
||||
.unwrap(),
|
||||
)
|
||||
} else {
|
||||
Box::new(std::io::stdout())
|
||||
};
|
||||
|
||||
report_file
|
||||
.write_all(
|
||||
|
||||
@@ -168,7 +168,6 @@ fn parse_boot_time_output(output: &[u8]) -> Result<f64, Error> {
|
||||
std::panic::catch_unwind(|| {
|
||||
let l: Vec<String> = String::from_utf8_lossy(output)
|
||||
.lines()
|
||||
.into_iter()
|
||||
.filter(|l| l.contains("Debug I/O port: Kernel code"))
|
||||
.map(|l| l.to_string())
|
||||
.collect();
|
||||
@@ -359,11 +358,13 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
|
||||
guest.disk_config.disk(DiskType::OperatingSystem).unwrap()
|
||||
)
|
||||
.as_str(),
|
||||
"--disk",
|
||||
format!(
|
||||
"path={}",
|
||||
guest.disk_config.disk(DiskType::CloudInit).unwrap()
|
||||
)
|
||||
.as_str(),
|
||||
"--disk",
|
||||
format!("path={BLK_IO_TEST_IMG}").as_str(),
|
||||
])
|
||||
.default_net()
|
||||
|
||||
@@ -66,7 +66,7 @@ impl QcowRawFile {
|
||||
non_zero_flags: u64,
|
||||
) -> io::Result<()> {
|
||||
self.file.seek(SeekFrom::Start(offset))?;
|
||||
let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u64>(), &mut self.file);
|
||||
let mut buffer = BufWriter::with_capacity(std::mem::size_of_val(table), &mut self.file);
|
||||
for addr in table {
|
||||
let val = if *addr == 0 {
|
||||
0
|
||||
@@ -91,7 +91,8 @@ impl QcowRawFile {
|
||||
/// Writes a refcount block to the file.
|
||||
pub fn write_refcount_block(&mut self, offset: u64, table: &[u16]) -> io::Result<()> {
|
||||
self.file.seek(SeekFrom::Start(offset))?;
|
||||
let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u16>(), &mut self.file);
|
||||
let mut buffer = BufWriter::with_capacity(std::mem::size_of_val(table), &mut self.file);
|
||||
|
||||
for count in table {
|
||||
buffer.write_u16::<BigEndian>(*count)?;
|
||||
}
|
||||
|
||||
365
release-notes.md
365
release-notes.md
@@ -1,3 +1,30 @@
|
||||
- [v33.0](#v330)
|
||||
- [D-Bus based API](#d-bus-based-api)
|
||||
- [Passthrough CPU cache information for AArch64](#passthrough-cpu-cache-information-for-aarch64)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes)
|
||||
- [Contributors](#contributors)
|
||||
- [v32.0](#v320)
|
||||
- [Increased PCI Segment Limit](#increased-pci-segment-limit)
|
||||
- [API Changes](#api-changes)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
||||
- [Contributors](#contributors-1)
|
||||
- [v31.1](#v311)
|
||||
- [v31.0](#v310)
|
||||
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
|
||||
- [Update Reference Kernel to 6.2](#update-reference-kernel-to-62)
|
||||
- [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler)
|
||||
- [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile)
|
||||
- [Documentation Improvements](#documentation-improvements)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
||||
- [Contributors](#contributors-2)
|
||||
- [v30.0](#v300)
|
||||
- [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size)
|
||||
- [Basic vfio-user Server Support](#basic-vfio-user-server-support)
|
||||
- [Heap Profiling Support](#heap-profiling-support)
|
||||
- [Documentation Improvements](#documentation-improvements-1)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||
- [Contributors](#contributors-3)
|
||||
- [v28.2](#v282)
|
||||
- [v29.0](#v290)
|
||||
- [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm)
|
||||
- [Snapshot/Restore and Live Migration Improvements](#snapshotrestore-and-live-migration-improvements)
|
||||
@@ -6,10 +33,10 @@
|
||||
- [`AArch64` Documentation Integration](#aarch64-documentation-integration)
|
||||
- [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement)
|
||||
- [TCP Offload Control](#tcp-offload-control)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Removals](#removals)
|
||||
- [Deprecations](#deprecations)
|
||||
- [Contributors](#contributors)
|
||||
- [Contributors](#contributors-4)
|
||||
- [v28.1](#v281)
|
||||
- [v28.0](#v280)
|
||||
- [Community Engagement (Reminder)](#community-engagement-reminder)
|
||||
@@ -17,9 +44,9 @@
|
||||
- [Virtualised TPM Support](#virtualised-tpm-support)
|
||||
- [Transparent Huge Page Support](#transparent-huge-page-support)
|
||||
- [README Quick Start Improved](#readme-quick-start-improved)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Removals](#removals-1)
|
||||
- [Contributors](#contributors-1)
|
||||
- [Contributors](#contributors-5)
|
||||
- [v27.0](#v270)
|
||||
- [Community Engagement](#community-engagement)
|
||||
- [Prebuilt Packages](#prebuilt-packages)
|
||||
@@ -28,41 +55,41 @@
|
||||
- [Simplified Build Feature Flags](#simplified-build-feature-flags)
|
||||
- [Asynchronous Kernel Loading](#asynchronous-kernel-loading)
|
||||
- [GDB Support for AArch64](#gdb-support-for-aarch64)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||
- [Deprecations](#deprecations-1)
|
||||
- [Contributors](#contributors-2)
|
||||
- [Contributors](#contributors-6)
|
||||
- [v26.0](#v260)
|
||||
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform)
|
||||
- [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
||||
- [Deprecations](#deprecations-2)
|
||||
- [Removals](#removals-2)
|
||||
- [Contributors](#contributors-3)
|
||||
- [Contributors](#contributors-7)
|
||||
- [v25.0](#v250)
|
||||
- [`ch-remote` Improvements](#ch-remote-improvements-1)
|
||||
- [VM "Coredump" Support](#vm-coredump-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-8)
|
||||
- [Removals](#removals-3)
|
||||
- [Contributors](#contributors-4)
|
||||
- [Contributors](#contributors-8)
|
||||
- [v24.0](#v240)
|
||||
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
|
||||
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
|
||||
- [Sparse Mmap support](#sparse-mmap-support)
|
||||
- [Expose Platform Serial Number](#expose-platform-serial-number)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-9)
|
||||
- [Notable Improvements](#notable-improvements)
|
||||
- [Deprecations](#deprecations-3)
|
||||
- [New on the Website](#new-on-the-website)
|
||||
- [Contributors](#contributors-5)
|
||||
- [Contributors](#contributors-9)
|
||||
- [v23.1](#v231)
|
||||
- [v23.0](#v230)
|
||||
- [vDPA Support](#vdpa-support)
|
||||
- [Updated OS Support list](#updated-os-support-list)
|
||||
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
|
||||
- [`AMX` Support](#amx-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-10)
|
||||
- [Deprecations](#deprecations-4)
|
||||
- [Contributors](#contributors-6)
|
||||
- [Contributors](#contributors-10)
|
||||
- [v22.1](#v221)
|
||||
- [v22.0](#v220)
|
||||
- [GDB Debug Stub Support](#gdb-debug-stub-support)
|
||||
@@ -73,13 +100,13 @@
|
||||
- [PMU Support for AArch64](#pmu-support-for-aarch64)
|
||||
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
|
||||
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
||||
- [Contributors](#contributors-7)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-11)
|
||||
- [Contributors](#contributors-11)
|
||||
- [v21.0](#v210)
|
||||
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
|
||||
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
|
||||
- [Notable Bug fixes](#notable-bug-fixes-8)
|
||||
- [Contributors](#contributors-8)
|
||||
- [Notable Bug fixes](#notable-bug-fixes-12)
|
||||
- [Contributors](#contributors-12)
|
||||
- [v20.2](#v202)
|
||||
- [v20.1](#v201)
|
||||
- [v20.0](#v200)
|
||||
@@ -88,8 +115,8 @@
|
||||
- [Improved VFIO support](#improved-vfio-support)
|
||||
- [Safer code](#safer-code)
|
||||
- [Extended documentation](#extended-documentation)
|
||||
- [Notable bug fixes](#notable-bug-fixes-9)
|
||||
- [Contributors](#contributors-9)
|
||||
- [Notable bug fixes](#notable-bug-fixes-13)
|
||||
- [Contributors](#contributors-13)
|
||||
- [v19.0](#v190)
|
||||
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
|
||||
- [PCI boot time optimisations](#pci-boot-time-optimisations)
|
||||
@@ -97,8 +124,8 @@
|
||||
- [Live migration enhancements](#live-migration-enhancements)
|
||||
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
|
||||
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
|
||||
- [Notable bug fixes](#notable-bug-fixes-10)
|
||||
- [Contributors](#contributors-10)
|
||||
- [Notable bug fixes](#notable-bug-fixes-14)
|
||||
- [Contributors](#contributors-14)
|
||||
- [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)
|
||||
@@ -108,23 +135,23 @@
|
||||
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
||||
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
||||
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
||||
- [Notable bug fixes](#notable-bug-fixes-11)
|
||||
- [Contributors](#contributors-11)
|
||||
- [Notable bug fixes](#notable-bug-fixes-15)
|
||||
- [Contributors](#contributors-15)
|
||||
- [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-12)
|
||||
- [Contributors](#contributors-12)
|
||||
- [Notable bug fixes](#notable-bug-fixes-16)
|
||||
- [Contributors](#contributors-16)
|
||||
- [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-13)
|
||||
- [Notable bug fixes](#notable-bug-fixes-17)
|
||||
- [Removed functionality](#removed-functionality)
|
||||
- [Contributors](#contributors-13)
|
||||
- [Contributors](#contributors-17)
|
||||
- [v15.0](#v150)
|
||||
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
||||
- [Network device rate limiting](#network-device-rate-limiting)
|
||||
@@ -132,7 +159,7 @@
|
||||
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
||||
- [Bug fixes](#bug-fixes)
|
||||
- [Deprecations](#deprecations-5)
|
||||
- [Contributors](#contributors-14)
|
||||
- [Contributors](#contributors-18)
|
||||
- [v0.14.1](#v0141)
|
||||
- [v0.14.0](#v0140)
|
||||
- [Structured event monitoring](#structured-event-monitoring)
|
||||
@@ -142,7 +169,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-6)
|
||||
- [Contributors](#contributors-15)
|
||||
- [Contributors](#contributors-19)
|
||||
- [v0.13.0](#v0130)
|
||||
- [Wider VFIO device support](#wider-vfio-device-support)
|
||||
- [Improved huge page support](#improved-huge-page-support)
|
||||
@@ -150,13 +177,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-16)
|
||||
- [Contributors](#contributors-20)
|
||||
- [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-17)
|
||||
- [Contributors](#contributors-21)
|
||||
- [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)
|
||||
@@ -168,15 +195,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-14)
|
||||
- [Contributors](#contributors-18)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-18)
|
||||
- [Contributors](#contributors-22)
|
||||
- [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-15)
|
||||
- [Contributors](#contributors-19)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-19)
|
||||
- [Contributors](#contributors-23)
|
||||
- [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)
|
||||
@@ -189,17 +216,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-16)
|
||||
- [Contributors](#contributors-20)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-20)
|
||||
- [Contributors](#contributors-24)
|
||||
- [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-17)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-21)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes)
|
||||
- [Contributors](#contributors-21)
|
||||
- [Contributors](#contributors-25)
|
||||
- [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)
|
||||
@@ -209,14 +236,14 @@
|
||||
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
||||
- [Updated Distribution Support](#updated-distribution-support)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
||||
- [Contributors](#contributors-22)
|
||||
- [Contributors](#contributors-26)
|
||||
- [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-23)
|
||||
- [Contributors](#contributors-27)
|
||||
- [v0.5.1](#v051)
|
||||
- [v0.5.0](#v050)
|
||||
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
||||
@@ -224,7 +251,7 @@
|
||||
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
||||
- [Development Tools](#development-tools)
|
||||
- [Kata Containers Integration](#kata-containers-integration)
|
||||
- [Contributors](#contributors-24)
|
||||
- [Contributors](#contributors-28)
|
||||
- [v0.4.0](#v040)
|
||||
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
||||
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
||||
@@ -233,7 +260,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-25)
|
||||
- [Contributors](#contributors-29)
|
||||
- [v0.3.0](#v030)
|
||||
- [Block device offloading](#block-device-offloading)
|
||||
- [Network device backend](#network-device-backend)
|
||||
@@ -260,6 +287,242 @@
|
||||
- [Unit testing](#unit-testing)
|
||||
- [Integration tests parallelization](#integration-tests-parallelization)
|
||||
|
||||
# v33.0
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
|
||||
v33.0. The following user visible changes have been made:
|
||||
|
||||
### D-Bus based API
|
||||
|
||||
A D-Bus based API has been added as an alternative to the existing REST
|
||||
API. This feature is gated by the `dbus_api` feature. Details can be
|
||||
found in the [API documentation](docs/api.md).
|
||||
|
||||
### Expose Host CPU Cache Details for AArch64
|
||||
|
||||
Now the CPU cache information on the host is properly exposed to the
|
||||
guest on AArch64.
|
||||
|
||||
### Notable Bug Fixes
|
||||
|
||||
* Report errors explicitly to users when VM failed to boot (#5453)
|
||||
* Fix VFIO on platforms with non-4k page size (#5450, #5469)
|
||||
* Fix TDX initialization (#5454)
|
||||
* Ensure all guest memory regions are page-size aligned (#5496)
|
||||
* Fix seccomp filter lists related to virtio-console, serial and pty
|
||||
(#5506, #5524)
|
||||
* Populate APIC ID properly (#5512)
|
||||
* Ignore and warn TAP FDs in more situations (#5522)
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Alyssa Ross <hi@alyssa.is>
|
||||
* Anatol Belski <anbelski@linux.microsoft.com>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Jianyong Wu <jianyong.wu@arm.com>
|
||||
* Omer Faruk Bayram <omer.faruk@sartura.hr>
|
||||
* Rafael Mendonca <rafaelmendsr@gmail.com>
|
||||
* Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
|
||||
* Rob Bradford <rbradford@rivosinc.com>
|
||||
* Ruslan Mstoi <ruslan.mstoi@intel.com>
|
||||
* Yu Li <liyu.yukiteru@bytedance.com>
|
||||
* zhongbingnan <zhongbingnan@bytedance.com>
|
||||
|
||||
# v32.0
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
|
||||
v32.0. The following user visible changes have been made:
|
||||
|
||||
### Increased PCI Segment Limit
|
||||
|
||||
The maximum number of PCI segments that can be used is now 96 (up from 16).
|
||||
|
||||
### API Changes
|
||||
|
||||
* The VmmPingResponse now includes the PID as well as the build details.
|
||||
(#5348)
|
||||
|
||||
### Notable Bug Fixes
|
||||
|
||||
* Ignore and warn TAP FDs sent via the HTTP request body (#5350)
|
||||
* Properly preserve and close valid FDs for TAP devices (#5373)
|
||||
* Only use `KVM_ARM_VCPU_PMU_V3` if available (#5360)
|
||||
* Only touch the tty flags if it's being used (#5343)
|
||||
* Fix seccomp filter lists for vhost-user devices (#5361)
|
||||
* The number of vCPUs is capped at the hypervisor maximum (#5357)
|
||||
* Fixes for TTY reset (#5414)
|
||||
* CPU topology fixes on MSHV (#5325)
|
||||
* Seccomp fixes for older distributions (#5397)
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Alyssa Ross <hi@alyssa.is>
|
||||
* Anatol Belski <anbelski@linux.microsoft.com>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Hao Xu <howeyxu@tencent.com>
|
||||
* Muminul Islam <muislam@microsoft.com>
|
||||
* Omer Faruk Bayram <omer.faruk@sartura.hr>
|
||||
* Rafael Mendonca <rafaelmendsr@gmail.com>
|
||||
* Rob Bradford <rbradford@rivosinc.com>
|
||||
* Ruslan Mstoi <ruslan.mstoi@intel.com>
|
||||
* Smit Gardhariya <gardhariya.smit@gmail.com>
|
||||
* Wei Liu <liuwe@microsoft.com>
|
||||
|
||||
# v31.1
|
||||
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
|
||||
* Ignore and warn TAP FDs sent via the HTTP request body (#5350)
|
||||
* Properly preserve and close valid FDs for TAP devices (#5373)
|
||||
* Only use `KVM_ARM_VCPU_PMU_V3` if available (#5360)
|
||||
* Only touch the tty flags if it's being used (#5343)
|
||||
* Fix seccomp filter lists for vhost-user devices (#5361)
|
||||
|
||||
# v31.0
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
|
||||
v31.0. The following user visible changes have been made:
|
||||
|
||||
### Update to Latest `acpi_tables`
|
||||
|
||||
Adapted to the latest [acpi_tables](https://github.com/rust-vmm/acpi_tables).
|
||||
There has been significant API changes in the crate.
|
||||
|
||||
### Update Reference Kernel to 6.2
|
||||
|
||||
Updated the recommended guest kernel version from 6.1.6 to 6.2.
|
||||
|
||||
### Improvements on Console `SIGWINCH` Handler
|
||||
|
||||
A separate thread had been created to capture the `SIGWINCH` signal and resize
|
||||
the guest console. Now the thread is skipped if the console is not resizable.
|
||||
|
||||
Two completely different code paths existed for handling console resizing, one
|
||||
for `tty` and the other for `pty`. That makes the understanding of the console
|
||||
handling code unnecessarily complicated. Now the code paths are unified. Both
|
||||
`tty` and `pty` are supported in single `SIGWINCH` handler. And the new handler
|
||||
can works with kernel versions earlier than v5.5.
|
||||
|
||||
### Remove Directory Support from `MemoryZoneConfig::file`
|
||||
|
||||
Setting a directory to `MemoryZoneConfig::file` is no longer supported.
|
||||
|
||||
Before this change, user can set a directory to `file` of the `--memory-zone`
|
||||
option. In that case, a temporary file will be created as the backing file for
|
||||
the `mmap(2)` operation. This functionality has been unnecessary since we had
|
||||
the native support for hugepages and allocating anonymous shared memory.
|
||||
|
||||
### Documentation Improvements
|
||||
|
||||
* Various improvements in API document
|
||||
* Improvements in Doc comments
|
||||
* Updated Slack channel information in README
|
||||
|
||||
### Notable Bug Fixes
|
||||
|
||||
* Fixed the offset setting while removing the entire mapping of `vhost-user` FS
|
||||
client.
|
||||
* Fixed the `ShutdownVmm` and `Shutdown` commands to call the correct API
|
||||
endpoint.
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Alyssa Ross <hi@alyssa.is>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Daniel Farina <daniel@fdr.io>
|
||||
* Dom <peng6662001@163.com>
|
||||
* Hao Xu <howeyxu@tencent.com>
|
||||
* Muminul Islam <muislam@microsoft.com>
|
||||
* Omer Faruk Bayram <omer.faruk@sartura.hr>
|
||||
* Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
|
||||
* Rob Bradford <rbradford@rivosinc.com>
|
||||
* Ruslan Mstoi <ruslan.mstoi@intel.com>
|
||||
* Smit Gardhariya <gardhariya.smit@gmail.com>
|
||||
* Yang <ailin.yang@intel.com>
|
||||
* Yong He <alexyonghe@tencent.com>
|
||||
|
||||
# v30.0
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
|
||||
v30.0. The following user visible changes have been made:
|
||||
|
||||
### Command Line Changes for Reduced Binary Size
|
||||
|
||||
The `clap` crate was replaced by the `argh` crate to create our command
|
||||
line, which reduced our release binary size from 3.6MB to 3.3MB. There
|
||||
were several syntax changes:
|
||||
|
||||
* All `--option=value` commands now are `--option value`.
|
||||
* The `--disk DISK1 DISK2` command now is `--disk DISK1 --disk DISK2`.
|
||||
* The `-vvv` command now is `-v -v -v`
|
||||
|
||||
### Basic vfio-user Server Support
|
||||
|
||||
Our `vfio-user` crate is extended to provide basic server side support
|
||||
with an example of gpio vfio-user device. This crate now is moved to [its
|
||||
own repository](https://github.com/rust-vmm/vfio-user) under the
|
||||
`rust-vmm` organization.
|
||||
|
||||
### Heap Profiling Support
|
||||
|
||||
A new building target is added for profiling purposes with examples of
|
||||
heap profiling using `dhat` gated by the `dhat-heap` feature.
|
||||
|
||||
### Documentation Improvements
|
||||
|
||||
The documentation on Intel TDX is expanded with details of the building
|
||||
and using [TD-Shim](https://github.com/confidential-containers/td-shim),
|
||||
references to [TDX Tools](https://github.com/intel/tdx-tools), and
|
||||
version information of guest/host kernel/TDVF/TDShim being tested. Also,
|
||||
a new 'heap profiling' documentation is added with improvements on the
|
||||
existing 'profiling' documentation.
|
||||
|
||||
### Notable Bug Fixes
|
||||
|
||||
* Close FDs for TAP devices that are provided to VM (#5199, #5206)
|
||||
* Set vcpu thread status properly and signal `exit_evt` upon thread exit (#5211)
|
||||
* Populate CPUID leaf 0x4000_0010 (TSC frequency) (#5178, #5179)
|
||||
* Inform the TPM guest driver upon failed TPM requests on the host (#5151)
|
||||
* Bug fix to OpenAPI specification file (#5186)
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Anatol Belski <anbelski@linux.microsoft.com>
|
||||
* Anirudh Rayabharam <anrayabh@linux.microsoft.com>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Jinank Jain <jinankjain@microsoft.com>
|
||||
* Kaihang Zhang <kaihang.zhang@smartx.com>
|
||||
* Michael Zhao <michael.zhao@arm.com>
|
||||
* Muminul Islam <muislam@microsoft.com>
|
||||
* Philipp Schuster <philipp.schuster@cyberus-technology.de>
|
||||
* Praveen K Paladugu <prapal@linux.microsoft.com>
|
||||
* Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
|
||||
* Rob Bradford <robert.bradford@intel.com>
|
||||
* Ruslan Mstoi <ruslan.mstoi@intel.com>
|
||||
* Sebastien Boeuf <sebastien.boeuf@intel.com>
|
||||
* Wei Liu <liuwe@microsoft.com>
|
||||
* Yong He <alexyonghe@tencent.com>
|
||||
* Yu Li <liyu.yukiteru@bytedance.com>
|
||||
|
||||
# v28.2
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
|
||||
* Fix QCOW2 refcount table size (#5034)
|
||||
* Fix unpause support on MSHV in dual binary (#5037)
|
||||
* Threads inside `virtio` devices are now shutdown on reboot (#5095)
|
||||
|
||||
# v29.0
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
@@ -406,7 +669,7 @@ different firmware options and to recommend the use of pre-built binaries.
|
||||
newer Linux kernels (#4744)
|
||||
* Error on reboot from race to close TAP devices (#4871)
|
||||
* Non-spec compliant virtio-block read-only support (#4888)
|
||||
|
||||
|
||||
### Removals
|
||||
|
||||
The following functionality has been removed:
|
||||
@@ -414,7 +677,7 @@ The following functionality has been removed:
|
||||
* Support for non-PVH firmware booting has been removed (#4511)
|
||||
* I/O ports used for older versions of firmware have been removed (#3926)
|
||||
* Deprecated API options for kernel/cmdline/initramfs have been removed (#4737)
|
||||
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
@@ -921,7 +1184,7 @@ Many thanks to everyone who has contributed to our release:
|
||||
* Sebastien Boeuf <sebastien.boeuf@intel.com>
|
||||
* Wei Liu <liuwe@microsoft.com>
|
||||
* Ziye Yang <ziye.yang@intel.com>
|
||||
|
||||
|
||||
# v20.2
|
||||
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
@@ -1020,7 +1283,7 @@ significant improvements in the boot time of the guest.
|
||||
### Improved TDX support
|
||||
|
||||
When using the latest TDVF firmware the ACPI tables created by the VMM are now
|
||||
exposed via the firmware to the guest.
|
||||
exposed via the firmware to the guest.
|
||||
|
||||
### Live migration enhancements
|
||||
|
||||
@@ -1107,7 +1370,7 @@ tree.
|
||||
|
||||
### Power button support on AArch64
|
||||
|
||||
Use of the ACPI power button (e.g `ch-remote --api-socket=<API socket> power-button`)
|
||||
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
|
||||
@@ -1519,7 +1782,7 @@ Highlights for `cloud-hypervisor` version 0.11.0 include:
|
||||
### `io_uring` support by default for `virtio-block`
|
||||
|
||||
Provided that the host OS supports it (Linux kernel 5.8+) then `io_uring` will
|
||||
be used for a significantly higher performance block device.
|
||||
be used for a significantly higher performance block device.
|
||||
|
||||
### Windows Guest Support
|
||||
|
||||
@@ -1693,7 +1956,7 @@ A new abstraction has been introduced, in the form of a `hypervisor` crate so as
|
||||
Multiple improvements have been made to the VM snapshot/restore support that was added in the last release. This includes persisting more vCPU state and in particular preserving the guest paravirtualized clock in order to avoid vCPU hangs inside the guest when running with multiple vCPUs.
|
||||
|
||||
### Virtio Memory Ballooning Support
|
||||
|
||||
|
||||
A `virtio-balloon` device has been added, controlled through the `resize` control, which allows the reclamation of host memory by resizing a memory balloon inside the guest.
|
||||
|
||||
### Enhancements to ARM64 Support
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# When changing this file don't forget to update the tag name in the
|
||||
# .github/workflows/docker-image.yaml file if doing multiple per day
|
||||
|
||||
FROM ubuntu:20.04 as dev
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG RUST_TOOLCHAIN="1.62.0"
|
||||
ARG RUST_TOOLCHAIN="1.67.1"
|
||||
ARG CLH_SRC_DIR="/cloud-hypervisor"
|
||||
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
|
||||
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"
|
||||
@@ -13,55 +15,67 @@ ARG CARGO_GIT_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_git_registry"
|
||||
ENV CARGO_HOME=/usr/local/rust
|
||||
ENV RUSTUP_HOME=$CARGO_HOME
|
||||
ENV PATH="$PATH:$CARGO_HOME/bin"
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install all CI dependencies
|
||||
# DL3015 ignored cause not installing openvswitch-switch-dpdk recommended packages breaks ovs_dpdk test
|
||||
# hadolint ignore=DL3008,DL3015
|
||||
RUN apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
||||
build-essential \
|
||||
bc \
|
||||
curl \
|
||||
wget \
|
||||
sudo \
|
||||
mtools \
|
||||
musl-tools \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
flex \
|
||||
bison \
|
||||
libelf-dev \
|
||||
qemu-utils \
|
||||
libglib2.0-dev \
|
||||
libpixman-1-dev \
|
||||
libseccomp-dev \
|
||||
libcap-ng-dev \
|
||||
socat \
|
||||
dosfstools \
|
||||
cpio \
|
||||
python \
|
||||
python3 \
|
||||
python3-setuptools \
|
||||
ntfs-3g \
|
||||
openvswitch-switch-dpdk \
|
||||
python3-distutils \
|
||||
uuid-dev \
|
||||
iperf3 \
|
||||
zip \
|
||||
git-core \
|
||||
dnsmasq \
|
||||
dmsetup \
|
||||
&& apt-get -yq upgrade \
|
||||
&& apt-get install --no-install-recommends -yq \
|
||||
build-essential \
|
||||
bc \
|
||||
curl \
|
||||
wget \
|
||||
sudo \
|
||||
mtools \
|
||||
musl-tools \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
flex \
|
||||
bison \
|
||||
libelf-dev \
|
||||
qemu-utils \
|
||||
libglib2.0-dev \
|
||||
libpixman-1-dev \
|
||||
libseccomp-dev \
|
||||
libcap-ng-dev \
|
||||
socat \
|
||||
dosfstools \
|
||||
cpio \
|
||||
python \
|
||||
python3 \
|
||||
python3-setuptools \
|
||||
ntfs-3g \
|
||||
python3-distutils \
|
||||
uuid-dev \
|
||||
iperf3 \
|
||||
zip \
|
||||
git-core \
|
||||
dnsmasq \
|
||||
dmsetup \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
iproute2 \
|
||||
dbus \
|
||||
&& apt-get install openvswitch-switch-dpdk -yq \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
&& rm -rf /var/lib/apt/lists/* /var/log/*log /var/log/apt/* /var/lib/dpkg/*-old /var/cache/debconf/*-old
|
||||
|
||||
RUN update-alternatives --set ovs-vswitchd /usr/lib/openvswitch-switch-dpdk/ovs-vswitchd-dpdk
|
||||
|
||||
# hadolint ignore=DL3008
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq gcc-multilib \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*; fi
|
||||
apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& apt-get install --no-install-recommends -yq gcc-multilib gawk \
|
||||
libtool expect gnutls-dev gnutls-bin libfuse-dev \
|
||||
libjson-glib-dev libgmp-dev libtasn1-dev python3-twisted \
|
||||
net-tools softhsm2 \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /var/log/*log /var/log/apt/* /var/lib/dpkg/*-old /var/cache/debconf/*-old; fi
|
||||
|
||||
# hadolint ignore=DL3008
|
||||
RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
# On AArch64, `setcap` binary should be installed via `libcap2-bin`.
|
||||
# The `setcap` binary is used in integration tests.
|
||||
@@ -69,7 +83,7 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
# kernel (any version) image in `/boot` and modules in `/lib/modules`.
|
||||
apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
||||
&& apt-get install --no-install-recommends -yq \
|
||||
libcap2-bin \
|
||||
libguestfs-tools \
|
||||
linux-image-generic \
|
||||
@@ -79,11 +93,12 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
perl \
|
||||
texinfo \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*; fi
|
||||
&& rm -rf /var/lib/apt/lists/* /var/log/*log /var/log/apt/* /var/lib/dpkg/*-old /var/cache/debconf/*-old; fi
|
||||
|
||||
# Fix the libssl-dev install
|
||||
# hadolint ignore=SC2155
|
||||
RUN export ARCH="$(uname -m)" \
|
||||
&& cp /usr/include/$ARCH-linux-gnu/openssl/opensslconf.h /usr/include/openssl/
|
||||
&& cp /usr/include/"$ARCH"-linux-gnu/openssl/opensslconf.h /usr/include/openssl/
|
||||
ENV X86_64_UNKNOWN_LINUX_GNU_OPENSSL_LIB_DIR=/usr/lib/x86_64-linux-gnu/
|
||||
ENV X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR=/usr/lib/x86_64-linux-gnu/
|
||||
ENV AARCH64_UNKNOWN_LINUX_GNU_OPENSSL_LIB_DIR=/usr/lib/aarch64-linux-gnu/
|
||||
@@ -91,9 +106,10 @@ ENV AARCH64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR=/usr/lib/aarch64-linux-gnu/
|
||||
ENV OPENSSL_INCLUDE_DIR=/usr/include/
|
||||
|
||||
# Install the rust toolchain
|
||||
# hadolint ignore=DL4006,SC2155
|
||||
RUN export ARCH="$(uname -m)" \
|
||||
&& nohup curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain "$RUST_TOOLCHAIN" \
|
||||
&& rustup target add $ARCH-unknown-linux-musl --toolchain "$RUST_TOOLCHAIN" \
|
||||
&& rustup target add "$ARCH"-unknown-linux-musl --toolchain "$RUST_TOOLCHAIN" \
|
||||
&& if [ "$TARGETARCH" = "amd64" ]; then rustup toolchain add --profile minimal $RUST_TOOLCHAIN-x86_64-unknown-linux-musl; fi \
|
||||
&& if [ "$TARGETARCH" = "amd64" ]; then rustup component add rustfmt; fi \
|
||||
&& if [ "$TARGETARCH" = "amd64" ]; then rustup component add clippy; fi \
|
||||
@@ -103,12 +119,14 @@ RUN export ARCH="$(uname -m)" \
|
||||
&& ln -s "$CARGO_GIT_REGISTRY_DIR" "$CARGO_HOME/git"
|
||||
|
||||
# Set the rust environment
|
||||
RUN echo 'source $CARGO_HOME/env' >> $HOME/.bashrc \
|
||||
&& mkdir $HOME/.cargo \
|
||||
&& ln -s $CARGO_HOME/env $HOME/.cargo/env
|
||||
# hadolint ignore=SC2016
|
||||
RUN echo 'source $CARGO_HOME/env' >> "$HOME"/.bashrc \
|
||||
&& mkdir "$HOME"/.cargo \
|
||||
&& ln -s $CARGO_HOME/env "$HOME"/.cargo/env
|
||||
|
||||
# install SPDK NVMe
|
||||
# only for 'x86_64' platform images as 'docker buildx' can't build 'spdk'
|
||||
# hadolint ignore=DL3003,SC2046
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
git clone https://github.com/spdk/spdk \
|
||||
&& cd spdk \
|
||||
@@ -118,16 +136,36 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
&& ./scripts/pkgdep.sh \
|
||||
&& apt-get clean \
|
||||
&& ./configure --with-vfio-user \
|
||||
&& make -j `nproc` \
|
||||
&& make -j $(nproc) \
|
||||
&& mkdir /usr/local/bin/spdk-nvme \
|
||||
&& cp ./build/bin/nvmf_tgt /usr/local/bin/spdk-nvme \
|
||||
&& cp ./scripts/rpc.py /usr/local/bin/spdk-nvme \
|
||||
&& cp -r ./scripts/rpc /usr/local/bin/spdk-nvme \
|
||||
&& cd .. && rm -rf spdk; fi
|
||||
|
||||
# install swtpm only for x86_64 arch
|
||||
# hadolint ignore=DL3003
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
git clone https://github.com/stefanberger/libtpms libtpms_build \
|
||||
&& cd libtpms_build \
|
||||
&& git checkout v0.8.8 \
|
||||
&& ./autogen.sh \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& cd .. \
|
||||
&& git clone https://github.com/stefanberger/swtpm swtpm_build \
|
||||
&& cd swtpm_build \
|
||||
&& git checkout v0.8.0 \
|
||||
&& ./autogen.sh \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& cd .. \
|
||||
&& ldconfig \
|
||||
&& rm -rf swtpm_build libtpms_build; fi
|
||||
|
||||
# install ethr tool for performance tests
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
wget https://github.com/microsoft/ethr/releases/latest/download/ethr_linux.zip \
|
||||
wget -nv https://github.com/microsoft/ethr/releases/latest/download/ethr_linux.zip \
|
||||
&& unzip ethr_linux.zip \
|
||||
&& cp ethr /usr/local/bin \
|
||||
&& rm ethr_linux.zip; fi
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,6 @@
|
||||
|
||||
from colorsys import hsv_to_rgb
|
||||
from random import random
|
||||
import xml
|
||||
import json
|
||||
from sys import argv, stderr
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
set -x
|
||||
|
||||
rm -f /tmp/ubuntu-cloudinit.img
|
||||
mkdosfs -n cidata -C /tmp/ubuntu-cloudinit.img 8192
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/user-data ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/meta-data ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/network-config ::
|
||||
mkdosfs -n CIDATA -C /tmp/ubuntu-cloudinit.img 8192
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/local/user-data ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/local/meta-data ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/local/network-config ::
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
CLI_NAME="Cloud Hypervisor"
|
||||
|
||||
CTR_IMAGE_TAG="cloudhypervisor/dev"
|
||||
CTR_IMAGE_VERSION="20220705-0"
|
||||
CTR_IMAGE_TAG="ghcr.io/cloud-hypervisor/cloud-hypervisor"
|
||||
CTR_IMAGE_VERSION="20230620-0"
|
||||
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
|
||||
|
||||
DOCKER_RUNTIME="docker"
|
||||
@@ -168,10 +168,15 @@ process_volumes_args() {
|
||||
exported_volumes="$exported_volumes --volume $var"
|
||||
done
|
||||
}
|
||||
|
||||
cmd_help() {
|
||||
echo ""
|
||||
echo "Cloud Hypervisor $(basename "$0")"
|
||||
echo "Usage: $(basename "$0") <command> [<command args>]"
|
||||
echo "Usage: $(basename "$0") [flags] <command> [<command args>]"
|
||||
echo ""
|
||||
echo "Available flags":
|
||||
echo ""
|
||||
echo " --local Set the container image version being used to \"local\"."
|
||||
echo ""
|
||||
echo "Available commands:"
|
||||
echo ""
|
||||
@@ -379,6 +384,10 @@ cmd_tests() {
|
||||
exported_device="/dev/mshv"
|
||||
fi
|
||||
|
||||
if [ ! -e "${exported_device}" ] ; then
|
||||
die "${exported_device} does not exist on the system"
|
||||
fi
|
||||
|
||||
set -- '--hypervisor' "$hypervisor" "$@"
|
||||
|
||||
ensure_build_dir
|
||||
@@ -417,7 +426,7 @@ cmd_tests() {
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
|
||||
dbus-run-session ./scripts/run_integration_tests_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
|
||||
if [ "$integration_sgx" = true ]; then
|
||||
@@ -530,6 +539,7 @@ cmd_tests() {
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
--env RUST_BACKTRACE="${RUST_BACKTRACE}" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_metrics.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -621,6 +631,12 @@ cmd_shell() {
|
||||
fix_dir_perms $?
|
||||
}
|
||||
|
||||
if [ $# = 0 ]; then
|
||||
cmd_help
|
||||
say_err "Please specify command to run!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Parse main command line args.
|
||||
#
|
||||
while [ $# -gt 0 ]; do
|
||||
|
||||
@@ -148,7 +148,7 @@ update_workloads() {
|
||||
popd
|
||||
|
||||
# Download Cloud Hypervisor binary from its last stable release
|
||||
LAST_RELEASE_VERSION="v26.0"
|
||||
LAST_RELEASE_VERSION="v30.0"
|
||||
CH_RELEASE_URL="https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$LAST_RELEASE_VERSION/cloud-hypervisor-static-aarch64"
|
||||
CH_RELEASE_NAME="cloud-hypervisor-static-aarch64"
|
||||
pushd $WORKLOADS_DIR
|
||||
@@ -225,8 +225,8 @@ fi
|
||||
|
||||
BUILD_TARGET="aarch64-unknown-linux-${CH_LIBC}"
|
||||
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
fi
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
@@ -240,7 +240,9 @@ sudo bash -c "echo 10 > /sys/kernel/mm/ksm/sleep_millisecs"
|
||||
sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
|
||||
|
||||
# Both test_vfio and ovs-dpdk rely on hugepages
|
||||
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
||||
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
|
||||
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
|
||||
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
# Run all direct kernel boot (Device Tree) test cases in mod `parallel`
|
||||
@@ -279,4 +281,12 @@ else
|
||||
exit $RES
|
||||
fi
|
||||
|
||||
# Run tests on dbus_api
|
||||
if [ $RES -eq 0 ]; then
|
||||
cargo build --features "dbus_api" --all --release --target $BUILD_TARGET
|
||||
export RUST_BACKTRACE=1
|
||||
time cargo test "dbus_api::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
|
||||
RES=$?
|
||||
fi
|
||||
|
||||
exit $RES
|
||||
|
||||
@@ -46,7 +46,7 @@ fi
|
||||
popd
|
||||
|
||||
# Download Cloud Hypervisor binary from its last stable release
|
||||
LAST_RELEASE_VERSION="v26.0"
|
||||
LAST_RELEASE_VERSION="v30.0"
|
||||
CH_RELEASE_URL="https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$LAST_RELEASE_VERSION/cloud-hypervisor-static"
|
||||
CH_RELEASE_NAME="cloud-hypervisor-static"
|
||||
pushd $WORKLOADS_DIR
|
||||
@@ -56,26 +56,8 @@ 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.15.12" $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
|
||||
build_custom_linux
|
||||
fi
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
@@ -89,7 +71,9 @@ fi
|
||||
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
|
||||
|
||||
# Test ovs-dpdk relies on hugepages
|
||||
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
||||
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
|
||||
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
|
||||
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
@@ -45,29 +45,7 @@ if [ $? -ne 0 ]; then
|
||||
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.15.12" $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_custom_linux
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
|
||||
@@ -21,7 +21,7 @@ rm -f $FW
|
||||
time wget --quiet $FW_URL || exit 1
|
||||
popd
|
||||
|
||||
JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20221118-1.qcow2"
|
||||
JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.qcow2"
|
||||
JAMMY_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_IMAGE_NAME"
|
||||
JAMMY_OS_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_IMAGE_NAME"
|
||||
if [ ! -f "$JAMMY_OS_IMAGE" ]; then
|
||||
@@ -30,7 +30,7 @@ if [ ! -f "$JAMMY_OS_IMAGE" ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
JAMMY_OS_RAW_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20221118-1.raw"
|
||||
JAMMY_OS_RAW_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.raw"
|
||||
JAMMY_OS_RAW_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_RAW_IMAGE_NAME"
|
||||
if [ ! -f "$JAMMY_OS_RAW_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
@@ -42,8 +42,8 @@ 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/"
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
|
||||
|
||||
@@ -7,14 +7,45 @@ source $(dirname "$0")/test-util.sh
|
||||
process_common_args "$@"
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.raw"
|
||||
FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
|
||||
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||
|
||||
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
FW="$WORKLOADS_DIR/hypervisor-fw"
|
||||
if [ ! -f "$FW" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $FW_URL || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
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
|
||||
sha1sum sha1sums-x86_64 --check --ignore-missing
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "sha1sum validation of images failed, remove invalid images to fix the issue."
|
||||
exit 1
|
||||
fi
|
||||
popd
|
||||
|
||||
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
|
||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||
build_custom_linux
|
||||
fi
|
||||
build_custom_linux
|
||||
|
||||
BLK_IMAGE="$WORKLOADS_DIR/blk.img"
|
||||
MNT_DIR="mount_image"
|
||||
@@ -33,7 +64,7 @@ VFIO_DIR="$WORKLOADS_DIR/vfio"
|
||||
VFIO_DISK_IMAGE="$WORKLOADS_DIR/vfio.img"
|
||||
rm -rf $VFIO_DIR $VFIO_DISK_IMAGE
|
||||
mkdir -p $VFIO_DIR
|
||||
cp $FOCAL_OS_IMAGE $VFIO_DIR
|
||||
cp $FOCAL_OS_RAW_IMAGE $VFIO_DIR
|
||||
cp $FW $VFIO_DIR
|
||||
cp $VMLINUX_IMAGE $VFIO_DIR || exit 1
|
||||
|
||||
@@ -52,16 +83,13 @@ cp target/$BUILD_TARGET/release/cloud-hypervisor $VFIO_DIR
|
||||
cp target/$BUILD_TARGET/release/ch-remote $VFIO_DIR
|
||||
|
||||
# test_vfio rely on hugepages
|
||||
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
||||
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
|
||||
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
|
||||
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
time cargo test "vfio::test_vfio" -- ${test_binary_args[*]}
|
||||
time cargo test "vfio::test_nvidia" -- --test-threads=1 ${test_binary_args[*]}
|
||||
RES=$?
|
||||
|
||||
if [ $RES -eq 0 ]; then
|
||||
time cargo test "vfio::test_nvidia" -- --test-threads=1 ${test_binary_args[*]}
|
||||
RES=$?
|
||||
fi
|
||||
|
||||
exit $RES
|
||||
|
||||
@@ -24,8 +24,8 @@ BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
fi
|
||||
|
||||
# Check if the images are present
|
||||
|
||||
@@ -11,7 +11,7 @@ test_features=""
|
||||
if [ "$hypervisor" = "mshv" ] ; then
|
||||
test_features="--no-default-features --features mshv"
|
||||
fi
|
||||
WIN_IMAGE_FILE="/root/workloads/windows-server-2019.raw"
|
||||
WIN_IMAGE_FILE="/root/workloads/windows-server-2022-amd64-2.raw"
|
||||
|
||||
WORKLOADS_DIR="/root/workloads"
|
||||
OVMF_FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/edk2/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
@@ -26,8 +26,8 @@ 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/"
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
# Check if the images are present
|
||||
|
||||
@@ -53,7 +53,7 @@ if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20221118-1.qcow2"
|
||||
JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.qcow2"
|
||||
JAMMY_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_IMAGE_NAME"
|
||||
JAMMY_OS_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_IMAGE_NAME"
|
||||
if [ ! -f "$JAMMY_OS_IMAGE" ]; then
|
||||
@@ -62,7 +62,7 @@ if [ ! -f "$JAMMY_OS_IMAGE" ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
JAMMY_OS_RAW_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20221118-1.raw"
|
||||
JAMMY_OS_RAW_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.raw"
|
||||
JAMMY_OS_RAW_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_RAW_IMAGE_NAME"
|
||||
if [ ! -f "$JAMMY_OS_RAW_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
@@ -169,7 +169,9 @@ sudo bash -c "echo 10 > /sys/kernel/mm/ksm/sleep_millisecs"
|
||||
sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
|
||||
|
||||
# Both test_vfio, ovs-dpdk and vDPA tests rely on hugepages
|
||||
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
||||
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
|
||||
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
|
||||
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
# Update max locked memory to 'unlimited' to avoid issues with vDPA
|
||||
@@ -187,4 +189,13 @@ if [ $RES -eq 0 ]; then
|
||||
RES=$?
|
||||
fi
|
||||
|
||||
# Run tests on dbus_api
|
||||
if [ $RES -eq 0 ]; then
|
||||
cargo build --no-default-features --features "kvm,mshv,dbus_api" --all --release --target $BUILD_TARGET
|
||||
export RUST_BACKTRACE=1
|
||||
# integration tests now do not reply on build feature "dbus_api"
|
||||
time cargo test $test_features "dbus_api::$test_filter" -- ${test_binary_args[*]}
|
||||
RES=$?
|
||||
fi
|
||||
|
||||
exit $RES
|
||||
|
||||
@@ -95,7 +95,9 @@ fi
|
||||
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
|
||||
|
||||
# setup hugepages
|
||||
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
||||
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
|
||||
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
|
||||
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
if [ -n "$test_filter" ]; then
|
||||
@@ -105,7 +107,12 @@ fi
|
||||
# Ensure that git commands can be run in this directory (for metrics report)
|
||||
git config --global --add safe.directory $PWD
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
RUST_BACKTRACE_VALUE=`echo $RUST_BACKTRACE`
|
||||
if [ -z $RUST_BACKTRACE_VALUE ];then
|
||||
export RUST_BACKTRACE=1
|
||||
else
|
||||
echo "RUST_BACKTRACE is set to: $RUST_BACKTRACE_VALUE"
|
||||
fi
|
||||
time target/$BUILD_TARGET/release/performance-metrics ${test_binary_args[*]}
|
||||
RES=$?
|
||||
|
||||
|
||||
@@ -22,3 +22,4 @@ fi
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
cargo test --lib --bins --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1
|
||||
cargo test --doc --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
d4a44acc6014d5f83dea1c625c43d677a95fa75f alpine-minirootfs-x86_64.tar.gz
|
||||
f1eccdc5e1b515dbad294426ab081b47ebfb97c0 focal-server-cloudimg-amd64-custom-20210609-0.qcow2
|
||||
7f5a8358243a96adf61f5c20139b29f308f2c0e3 focal-server-cloudimg-amd64-custom-20210609-0.raw
|
||||
b12e52203bc78400b2f099420b411b49ef4be7b8 jammy-server-cloudimg-amd64-custom-20221118-1.qcow2
|
||||
d843d5b249e8db3c0158eaf56ade895ed10342b5 jammy-server-cloudimg-amd64-custom-20221118-1.raw
|
||||
864c074e2f1bd753667a35188b510d83a1d62793 jammy-server-cloudimg-amd64-custom-20230119-0.qcow2
|
||||
24358ee053f94e7f710ea4ce9e7a63eff2a1eb25 jammy-server-cloudimg-amd64-custom-20230119-0.raw
|
||||
|
||||
@@ -46,7 +46,7 @@ build_custom_linux() {
|
||||
ARCH=$(uname -m)
|
||||
SRCDIR=$PWD
|
||||
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
||||
LINUX_CUSTOM_BRANCH="ch-5.15.12"
|
||||
LINUX_CUSTOM_BRANCH="ch-6.2"
|
||||
LINUX_CUSTOM_URL="https://github.com/cloud-hypervisor/linux.git"
|
||||
|
||||
checkout_repo "$LINUX_CUSTOM_DIR" "$LINUX_CUSTOM_URL" "$LINUX_CUSTOM_BRANCH"
|
||||
|
||||
1322
src/bin/ch-remote.rs
1322
src/bin/ch-remote.rs
File diff suppressed because it is too large
Load Diff
788
src/main.rs
788
src/main.rs
@@ -6,9 +6,9 @@
|
||||
#[macro_use]
|
||||
extern crate event_monitor;
|
||||
|
||||
use clap::{Arg, ArgAction, ArgGroup, ArgMatches, Command};
|
||||
use argh::FromArgs;
|
||||
use libc::EFD_NONBLOCK;
|
||||
use log::LevelFilter;
|
||||
use log::{warn, LevelFilter};
|
||||
use option_parser::OptionParser;
|
||||
use seccompiler::SeccompAction;
|
||||
use signal_hook::consts::SIGSYS;
|
||||
@@ -18,10 +18,15 @@ use std::os::unix::io::{FromRawFd, RawFd};
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use thiserror::Error;
|
||||
#[cfg(feature = "dbus_api")]
|
||||
use vmm::api::dbus::{dbus_api_graceful_shutdown, DBusApiOptions};
|
||||
use vmm::config;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::signal::block_signal;
|
||||
use vmm_sys_util::terminal::Terminal;
|
||||
|
||||
#[cfg(feature = "dhat-heap")]
|
||||
#[global_allocator]
|
||||
static ALLOC: dhat::Alloc = dhat::Alloc;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
enum Error {
|
||||
@@ -30,6 +35,8 @@ enum Error {
|
||||
#[cfg(feature = "guest_debug")]
|
||||
#[error("Failed to create Debug EventFd: {0}")]
|
||||
CreateDebugEventFd(#[source] std::io::Error),
|
||||
#[error("Failed to create exit EventFd: {0}")]
|
||||
CreateExitEventFd(#[source] std::io::Error),
|
||||
#[error("Failed to open hypervisor interface (is hypervisor interface available?): {0}")]
|
||||
CreateHypervisor(#[source] hypervisor::HypervisorError),
|
||||
#[error("Failed to start the VMM thread: {0}")]
|
||||
@@ -52,6 +59,12 @@ enum Error {
|
||||
ParsingApiSocket(std::num::ParseIntError),
|
||||
#[error("Error parsing --event-monitor: {0}")]
|
||||
ParsingEventMonitor(option_parser::OptionParserError),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[error("`--dbus-object-path` option isn't provided")]
|
||||
MissingDBusObjectPath,
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[error("`--dbus-service-name` option isn't provided")]
|
||||
MissingDBusServiceName,
|
||||
#[error("Error parsing --event-monitor: path or fd required")]
|
||||
BareEventMonitor,
|
||||
#[error("Error doing event monitor I/O: {0}")]
|
||||
@@ -87,9 +100,9 @@ impl log::Log for Logger {
|
||||
let duration = now.duration_since(self.start);
|
||||
|
||||
if record.file().is_some() && record.line().is_some() {
|
||||
writeln!(
|
||||
write!(
|
||||
*(*(self.output.lock().unwrap())),
|
||||
"cloud-hypervisor: {:.6?}: <{}> {}:{}:{} -- {}",
|
||||
"cloud-hypervisor: {:.6?}: <{}> {}:{}:{} -- {}\r\n",
|
||||
duration,
|
||||
std::thread::current().name().unwrap_or("anonymous"),
|
||||
record.level(),
|
||||
@@ -98,9 +111,9 @@ impl log::Log for Logger {
|
||||
record.args()
|
||||
)
|
||||
} else {
|
||||
writeln!(
|
||||
write!(
|
||||
*(*(self.output.lock().unwrap())),
|
||||
"cloud-hypervisor: {:.6?}: <{}> {}:{} -- {}",
|
||||
"cloud-hypervisor: {:.6?}: <{}> {}:{} -- {}\r\n",
|
||||
duration,
|
||||
std::thread::current().name().unwrap_or("anonymous"),
|
||||
record.level(),
|
||||
@@ -113,296 +126,288 @@ impl log::Log for Logger {
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
fn prepare_default_values() -> (String, String, String) {
|
||||
let default_vcpus =
|
||||
format! {"boot={},max_phys_bits={}", config::DEFAULT_VCPUS,config::DEFAULT_MAX_PHYS_BITS};
|
||||
let default_memory = format! {"size={}M", config::DEFAULT_MEMORY_MB};
|
||||
let default_rng = format! {"src={}", config::DEFAULT_RNG_SOURCE};
|
||||
|
||||
(default_vcpus, default_memory, default_rng)
|
||||
fn default_vcpus() -> String {
|
||||
format!(
|
||||
"boot={},max_phys_bits={}",
|
||||
config::DEFAULT_VCPUS,
|
||||
config::DEFAULT_MAX_PHYS_BITS
|
||||
)
|
||||
}
|
||||
|
||||
fn create_app(default_vcpus: String, default_memory: String, default_rng: String) -> Command {
|
||||
#[allow(clippy::let_and_return)]
|
||||
let app = Command::new("cloud-hypervisor")
|
||||
// 'BUILT_VERSION' is set by the build script 'build.rs' at
|
||||
// compile time
|
||||
.version(env!("BUILT_VERSION"))
|
||||
.author(env!("CARGO_PKG_AUTHORS"))
|
||||
.about("Launch a cloud-hypervisor VMM.")
|
||||
.group(ArgGroup::new("vm-config").multiple(true))
|
||||
.group(ArgGroup::new("vmm-config").multiple(true))
|
||||
.group(ArgGroup::new("logging").multiple(true))
|
||||
.arg(
|
||||
Arg::new("cpus")
|
||||
.long("cpus")
|
||||
.help(
|
||||
"boot=<boot_vcpus>,max=<max_vcpus>,\
|
||||
topology=<threads_per_core>:<cores_per_die>:<dies_per_package>:<packages>,\
|
||||
kvm_hyperv=on|off,max_phys_bits=<maximum_number_of_physical_bits>,\
|
||||
affinity=<list_of_vcpus_with_their_associated_cpuset>,\
|
||||
features=<list_of_features_to_enable>",
|
||||
)
|
||||
.default_value(default_vcpus)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("platform")
|
||||
.long("platform")
|
||||
.help(
|
||||
"num_pci_segments=<num_pci_segments>,iommu_segments=<list_of_segments>,serial_number=<dmi_device_serial_number>,uuid=<dmi_device_uuid>,oem_strings=<list_of_strings>",
|
||||
)
|
||||
.num_args(1)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("memory")
|
||||
.long("memory")
|
||||
.help(
|
||||
"Memory parameters \
|
||||
\"size=<guest_memory_size>,mergeable=on|off,shared=on|off,\
|
||||
hugepages=on|off,hugepage_size=<hugepage_size>,\
|
||||
hotplug_method=acpi|virtio-mem,\
|
||||
hotplug_size=<hotpluggable_memory_size>,\
|
||||
hotplugged_size=<hotplugged_memory_size>,\
|
||||
prefault=on|off,thp=on|off\"",
|
||||
)
|
||||
.default_value(default_memory)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("memory-zone")
|
||||
.long("memory-zone")
|
||||
.help(
|
||||
"User defined memory zone parameters \
|
||||
\"size=<guest_memory_region_size>,file=<backing_file>,\
|
||||
shared=on|off,\
|
||||
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>,\
|
||||
prefault=on|off\"",
|
||||
)
|
||||
.num_args(1..)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("firmware")
|
||||
.long("firmware")
|
||||
.help("Path to firmware that is loaded in an architectural specific way")
|
||||
.num_args(1)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("kernel")
|
||||
.long("kernel")
|
||||
.help(
|
||||
"Path to kernel to load. This may be a kernel or firmware that supports a PVH \
|
||||
entry point (e.g. vmlinux) or architecture equivalent",
|
||||
)
|
||||
.num_args(1)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("initramfs")
|
||||
.long("initramfs")
|
||||
.help("Path to initramfs image")
|
||||
.num_args(1)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("cmdline")
|
||||
.long("cmdline")
|
||||
.help("Kernel command line")
|
||||
.num_args(1)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("disk")
|
||||
.long("disk")
|
||||
.help(config::DiskConfig::SYNTAX)
|
||||
.num_args(1..)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("net")
|
||||
.long("net")
|
||||
.help(config::NetConfig::SYNTAX)
|
||||
.num_args(1..)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("rng")
|
||||
.long("rng")
|
||||
.help(
|
||||
"Random number generator parameters \"src=<entropy_source_path>,iommu=on|off\"",
|
||||
)
|
||||
.default_value(default_rng)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("balloon")
|
||||
.long("balloon")
|
||||
.help(config::BalloonConfig::SYNTAX)
|
||||
.num_args(1)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("fs")
|
||||
.long("fs")
|
||||
.help(config::FsConfig::SYNTAX)
|
||||
.num_args(1..)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("pmem")
|
||||
.long("pmem")
|
||||
.help(config::PmemConfig::SYNTAX)
|
||||
.num_args(1..)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("serial")
|
||||
.long("serial")
|
||||
.help("Control serial port: off|null|pty|tty|file=/path/to/a/file")
|
||||
.default_value("null")
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("console")
|
||||
.long("console")
|
||||
.help(
|
||||
"Control (virtio) console: \"off|null|pty|tty|file=/path/to/a/file,iommu=on|off\"",
|
||||
)
|
||||
.default_value("tty")
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("device")
|
||||
.long("device")
|
||||
.help(config::DeviceConfig::SYNTAX)
|
||||
.num_args(1..)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("user-device")
|
||||
.long("user-device")
|
||||
.help(config::UserDeviceConfig::SYNTAX)
|
||||
.num_args(1..)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("vdpa")
|
||||
.long("vdpa")
|
||||
.help(config::VdpaConfig::SYNTAX)
|
||||
.num_args(1..)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("vsock")
|
||||
.long("vsock")
|
||||
.help(config::VsockConfig::SYNTAX)
|
||||
.num_args(1)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("numa")
|
||||
.long("numa")
|
||||
.help(config::NumaConfig::SYNTAX)
|
||||
.num_args(1..)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("watchdog")
|
||||
.long("watchdog")
|
||||
.help("Enable virtio-watchdog")
|
||||
.num_args(0)
|
||||
.action(ArgAction::SetTrue)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("v")
|
||||
.short('v')
|
||||
.action(ArgAction::Count)
|
||||
.help("Sets the level of debugging output")
|
||||
.group("logging"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("log-file")
|
||||
.long("log-file")
|
||||
.help("Log file. Standard error is used if not specified")
|
||||
.num_args(1)
|
||||
.group("logging"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("api-socket")
|
||||
.long("api-socket")
|
||||
.help("HTTP API socket (UNIX domain socket): path=</path/to/a/file> or fd=<fd>.")
|
||||
.num_args(1)
|
||||
.group("vmm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("event-monitor")
|
||||
.long("event-monitor")
|
||||
.help("File to report events on: path=</path/to/a/file> or fd=<fd>")
|
||||
.num_args(1)
|
||||
.group("vmm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("restore")
|
||||
.long("restore")
|
||||
.help(config::RestoreConfig::SYNTAX)
|
||||
.num_args(1)
|
||||
.group("vmm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("seccomp")
|
||||
.long("seccomp")
|
||||
.num_args(1)
|
||||
.value_parser(["true", "false", "log"])
|
||||
.default_value("true"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("tpm")
|
||||
.long("tpm")
|
||||
.num_args(1)
|
||||
.help(config::TpmConfig::SYNTAX)
|
||||
.group("vmm-config"),
|
||||
fn default_memory() -> String {
|
||||
format!("size={}M", config::DEFAULT_MEMORY_MB)
|
||||
}
|
||||
|
||||
);
|
||||
fn default_rng() -> String {
|
||||
format!("src={}", config::DEFAULT_RNG_SOURCE)
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
/// Launch a cloud-hypervisor VMM.
|
||||
pub struct TopLevel {
|
||||
#[argh(option, long = "cpus", default = "default_vcpus()")]
|
||||
/// boot=<boot_vcpus>, max=<max_vcpus>, topology=<threads_per_core>:<cores_per_die>:<dies_per_package>:<packages>, kvm_hyperv=on|off, max_phys_bits=<maximum_number_of_physical_bits>, affinity=<list_of_vcpus_with_their_associated_cpuset>, features=<list_of_features_to_enable>
|
||||
cpus: String,
|
||||
|
||||
#[argh(option, long = "platform")]
|
||||
/// num_pci_segments=<num_pci_segments>, iommu_segments=<list_of_segments>, serial_number=<dmi_device_serial_number>, uuid=<dmi_device_uuid>, oem_strings=<list_of_strings>
|
||||
platform: Option<String>,
|
||||
|
||||
#[argh(option, long = "memory", default = "default_memory()")]
|
||||
/// size=<guest_memory_size>, mergeable=on|off, shared=on|off, hugepages=on|off, hugepage_size=<hugepage_size>, hotplug_method=acpi|virtio-mem, hotplug_size=<hotpluggable_memory_size>, hotplugged_size=<hotplugged_memory_size>, prefault=on|off, thp=on|off
|
||||
memory: String,
|
||||
|
||||
#[argh(option, long = "memory-zone")]
|
||||
/// size=<guest_memory_region_size>, file=<backing_file>, shared=on|off, 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>, prefault=on|off
|
||||
memory_zone: Vec<String>,
|
||||
|
||||
#[argh(option, long = "firmware")]
|
||||
/// path to firmware that is loaded in an architectural specific way
|
||||
firmware: Option<String>,
|
||||
|
||||
#[argh(option, long = "kernel")]
|
||||
/// path to kernel or firmware that supports a PVH entry point or architecture equivalent
|
||||
kernel: Option<String>,
|
||||
|
||||
#[argh(option, long = "initramfs")]
|
||||
/// path to initramfs image
|
||||
initramfs: Option<String>,
|
||||
|
||||
#[argh(option, long = "cmdline")]
|
||||
/// kernel command line
|
||||
cmdline: Option<String>,
|
||||
|
||||
#[argh(option, long = "disk")]
|
||||
/// path=<disk_image_path>, readonly=on|off, direct=on|off, iommu=on|off, num_queues=<number_of_queues>, queue_size=<size_of_each_queue>, vhost_user=on|off, socket=<vhost_user_socket_path>, bw_size=<bytes>, bw_one_time_burst=<bytes>, bw_refill_time=<ms>, ops_size=<io_ops>, ops_one_time_burst=<io_ops>, ops_refill_time=<ms>, id=<device_id>, pci_segment=<segment_id>
|
||||
disk: Vec<String>,
|
||||
|
||||
#[argh(option, long = "net")]
|
||||
/// tap=<if_name>, ip=<ip_addr>, mask=<net_mask>, mac=<mac_addr>, fd=<fd1,fd2...>, iommu=on|off, num_queues=<number_of_queues>, queue_size=<size_of_each_queue>, id=<device_id>, vhost_user=<vhost_user_enable>, socket=<vhost_user_socket_path>, vhost_mode=client|server, bw_size=<bytes>, bw_one_time_burst=<bytes>, bw_refill_time=<ms>, ops_size=<io_ops>, ops_one_time_burst=<io_ops>, ops_refill_time=<ms>, pci_segment=<segment_id>offload_tso=on|off, offload_ufo=on|off, offload_csum=on|off
|
||||
net: Vec<String>,
|
||||
|
||||
#[argh(option, long = "rng", default = "default_rng()")]
|
||||
/// src=<entropy_source_path>, iommu=on|off
|
||||
rng: String,
|
||||
|
||||
#[argh(option, long = "balloon")]
|
||||
/// size=<balloon_size>, deflate_on_oom=on|off, free_page_reporting=on|off
|
||||
balloon: Option<String>,
|
||||
|
||||
#[argh(option, long = "fs")]
|
||||
/// tag=<tag_name>, socket=<socket_path>, num_queues=<number_of_queues>, queue_size=<size_of_each_queue>, id=<device_id>, pci_segment=<segment_id>
|
||||
fs: Vec<String>,
|
||||
|
||||
#[argh(option, long = "pmem")]
|
||||
/// file=<backing_file_path>, size=<persistent_memory_size>, iommu=on|off, discard_writes=on|off, id=<device_id>, pci_segment=<segment_id>
|
||||
pmem: Vec<String>,
|
||||
|
||||
#[argh(option, long = "serial", default = "String::from(\"null\")")]
|
||||
/// off|null|pty|tty|file=/path/to/a/file
|
||||
serial: String,
|
||||
|
||||
#[argh(option, long = "console", default = "String::from(\"tty\")")]
|
||||
/// off|null|pty|tty|file=/path/to/a/file, iommu=on|off
|
||||
console: String,
|
||||
|
||||
#[argh(option, long = "device")]
|
||||
/// path=<device_path>, iommu=on|off, id=<device_id>, pci_segment=<segment_id>
|
||||
device: Vec<String>,
|
||||
|
||||
#[argh(option, long = "user-device")]
|
||||
/// socket=<socket_path>, id=<device_id>, pci_segment=<segment_id>
|
||||
user_device: Vec<String>,
|
||||
|
||||
#[argh(option, long = "vdpa")]
|
||||
/// path=<device_path>, num_queues=<number_of_queues>, iommu=on|off, id=<device_id>, pci_segment=<segment_id>
|
||||
vdpa: Vec<String>,
|
||||
|
||||
#[argh(option, long = "vsock")]
|
||||
/// cid=<context_id>, socket=<socket_path>, iommu=on|off, id=<device_id>, pci_segment=<segment_id>
|
||||
vsock: Option<String>,
|
||||
|
||||
#[argh(option, long = "numa")]
|
||||
/// 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>
|
||||
numa: Vec<String>,
|
||||
|
||||
#[argh(switch, long = "watchdog")]
|
||||
/// enable virtio-watchdog
|
||||
watchdog: bool,
|
||||
|
||||
#[argh(switch, short = 'v')]
|
||||
/// set the level of debugging output
|
||||
verbosity: u8,
|
||||
|
||||
#[argh(option, long = "log-file")]
|
||||
/// path to log file
|
||||
log_file: Option<String>,
|
||||
|
||||
#[argh(option, long = "api-socket")]
|
||||
/// path=<path/to/a/file>|fd=<fd>
|
||||
api_socket: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(option, long = "dbus-service-name")]
|
||||
/// well known name of the service
|
||||
dbus_name: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(option, long = "dbus-object-path")]
|
||||
/// object path to serve the dbus interface
|
||||
dbus_path: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(switch, long = "dbus-system-bus")]
|
||||
/// use the system bus instead of a session bus
|
||||
dbus_system_bus: bool,
|
||||
|
||||
#[argh(option, long = "event-monitor")]
|
||||
/// path=<path/to/a/file>|fd=<fd>
|
||||
event_monitor: Option<String>,
|
||||
|
||||
#[argh(option, long = "restore")]
|
||||
/// source_url=<source_url>, prefault=on|off
|
||||
restore: Option<String>,
|
||||
|
||||
#[argh(option, long = "seccomp", default = "String::from(\"true\")")]
|
||||
/// seccomp configuration (true, false or log)
|
||||
seccomp: String,
|
||||
|
||||
#[argh(option, long = "tpm")]
|
||||
/// socket=<path/to/a/socket>
|
||||
tpm: Option<String>,
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let app = app.arg(
|
||||
Arg::new("sgx-epc")
|
||||
.long("sgx-epc")
|
||||
.help(config::SgxEpcConfig::SYNTAX)
|
||||
.num_args(1..)
|
||||
.group("vm-config"),
|
||||
);
|
||||
#[argh(option, long = "sgx-epc")]
|
||||
/// id=<epc_section_identifier>, size=<epc_section_size>, prefault=on|off
|
||||
sgx_epc: Vec<String>,
|
||||
|
||||
#[cfg(feature = "guest_debug")]
|
||||
let app = app.arg(
|
||||
Arg::new("gdb")
|
||||
.long("gdb")
|
||||
.help("GDB socket (UNIX domain socket): path=</path/to/a/file>")
|
||||
.num_args(1)
|
||||
.group("vmm-config"),
|
||||
);
|
||||
#[argh(option, long = "gdb")]
|
||||
/// path=<path/to/a/file>
|
||||
gdb: Option<String>,
|
||||
|
||||
app
|
||||
#[argh(switch, short = 'V', long = "version")]
|
||||
/// print version information
|
||||
version: bool,
|
||||
}
|
||||
|
||||
fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
||||
let log_level = match cmd_arguments.get_count("v") {
|
||||
impl TopLevel {
|
||||
fn to_vm_params(&self) -> config::VmParams<'_> {
|
||||
let cpus = &self.cpus;
|
||||
let memory = &self.memory;
|
||||
let memory_zones = if !self.memory_zone.is_empty() {
|
||||
Some(self.memory_zone.iter().map(|x| x.as_str()).collect())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let rng = &self.rng;
|
||||
let serial = &self.serial;
|
||||
let firmware = self.firmware.as_deref();
|
||||
let kernel = self.kernel.as_deref();
|
||||
let initramfs = self.initramfs.as_deref();
|
||||
let cmdline = self.cmdline.as_deref();
|
||||
|
||||
let disks = if !self.disk.is_empty() {
|
||||
Some(self.disk.iter().map(|x| x.as_str()).collect())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let net = if !self.net.is_empty() {
|
||||
Some(self.net.iter().map(|x| x.as_str()).collect())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let console = &self.console;
|
||||
let balloon = self.balloon.as_deref();
|
||||
let fs = if !self.fs.is_empty() {
|
||||
Some(self.fs.iter().map(|x| x.as_str()).collect())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let pmem = if !self.pmem.is_empty() {
|
||||
Some(self.pmem.iter().map(|x| x.as_str()).collect())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let devices = if !self.device.is_empty() {
|
||||
Some(self.device.iter().map(|x| x.as_str()).collect())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let user_devices = if !self.user_device.is_empty() {
|
||||
Some(self.user_device.iter().map(|x| x.as_str()).collect())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let vdpa = if !self.vdpa.is_empty() {
|
||||
Some(self.vdpa.iter().map(|x| x.as_str()).collect())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let vsock = self.vsock.as_deref();
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let sgx_epc = if !self.sgx_epc.is_empty() {
|
||||
Some(self.sgx_epc.iter().map(|x| x.as_str()).collect())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let numa = if !self.numa.is_empty() {
|
||||
Some(self.numa.iter().map(|x| x.as_str()).collect())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let watchdog = self.watchdog;
|
||||
let platform = self.platform.as_deref();
|
||||
#[cfg(feature = "guest_debug")]
|
||||
let gdb = self.gdb.is_some();
|
||||
let tpm = self.tpm.as_deref();
|
||||
|
||||
config::VmParams {
|
||||
cpus,
|
||||
memory,
|
||||
memory_zones,
|
||||
firmware,
|
||||
kernel,
|
||||
initramfs,
|
||||
cmdline,
|
||||
disks,
|
||||
net,
|
||||
rng,
|
||||
balloon,
|
||||
fs,
|
||||
pmem,
|
||||
serial,
|
||||
console,
|
||||
devices,
|
||||
user_devices,
|
||||
vdpa,
|
||||
vsock,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
sgx_epc,
|
||||
numa,
|
||||
watchdog,
|
||||
#[cfg(feature = "guest_debug")]
|
||||
gdb,
|
||||
platform,
|
||||
tpm,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
|
||||
let log_level = match toplevel.verbosity {
|
||||
0 => LevelFilter::Warn,
|
||||
1 => LevelFilter::Info,
|
||||
2 => LevelFilter::Debug,
|
||||
_ => LevelFilter::Trace,
|
||||
};
|
||||
|
||||
let log_file: Box<dyn std::io::Write + Send> = if let Some(file) =
|
||||
cmd_arguments.get_one::<String>("log-file")
|
||||
{
|
||||
let log_file: Box<dyn std::io::Write + Send> = if let Some(ref file) = toplevel.log_file {
|
||||
Box::new(std::fs::File::create(std::path::Path::new(file)).map_err(Error::LogFileCreation)?)
|
||||
} else {
|
||||
Box::new(std::io::stderr())
|
||||
@@ -415,32 +420,38 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
||||
.map(|()| log::set_max_level(log_level))
|
||||
.map_err(Error::LoggerSetup)?;
|
||||
|
||||
let (api_socket_path, api_socket_fd) =
|
||||
if let Some(socket_config) = cmd_arguments.get_one::<String>("api-socket") {
|
||||
let mut parser = OptionParser::new();
|
||||
parser.add("path").add("fd");
|
||||
parser.parse(socket_config).unwrap_or_default();
|
||||
let (api_socket_path, api_socket_fd) = if let Some(ref socket_config) = toplevel.api_socket {
|
||||
let mut parser = OptionParser::new();
|
||||
parser.add("path").add("fd");
|
||||
parser.parse(socket_config).unwrap_or_default();
|
||||
|
||||
if let Some(fd) = parser.get("fd") {
|
||||
(
|
||||
None,
|
||||
Some(fd.parse::<RawFd>().map_err(Error::ParsingApiSocket)?),
|
||||
)
|
||||
} else if let Some(path) = parser.get("path") {
|
||||
(Some(path), None)
|
||||
} else {
|
||||
(
|
||||
cmd_arguments
|
||||
.get_one::<String>("api-socket")
|
||||
.map(|s| s.to_string()),
|
||||
None,
|
||||
)
|
||||
}
|
||||
if let Some(fd) = parser.get("fd") {
|
||||
(
|
||||
None,
|
||||
Some(fd.parse::<RawFd>().map_err(Error::ParsingApiSocket)?),
|
||||
)
|
||||
} else if let Some(path) = parser.get("path") {
|
||||
(Some(path), None)
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
(toplevel.api_socket.as_ref().map(|s| s.to_string()), None)
|
||||
}
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
if let Some(monitor_config) = cmd_arguments.get_one::<String>("event-monitor") {
|
||||
#[cfg(feature = "dbus_api")]
|
||||
let dbus_options = match (&toplevel.dbus_name, &toplevel.dbus_path) {
|
||||
(Some(ref name), Some(ref path)) => Ok(Some(DBusApiOptions {
|
||||
service_name: name.to_owned(),
|
||||
object_path: path.to_owned(),
|
||||
system_bus: toplevel.dbus_system_bus,
|
||||
})),
|
||||
(Some(_), None) => Err(Error::MissingDBusObjectPath),
|
||||
(None, Some(_)) => Err(Error::MissingDBusServiceName),
|
||||
(None, None) => Ok(None),
|
||||
}?;
|
||||
|
||||
if let Some(ref monitor_config) = toplevel.event_monitor {
|
||||
let mut parser = OptionParser::new();
|
||||
parser.add("path").add("fd");
|
||||
parser
|
||||
@@ -469,19 +480,15 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
||||
let (api_request_sender, api_request_receiver) = channel();
|
||||
let api_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateApiEventFd)?;
|
||||
|
||||
let http_sender = api_request_sender.clone();
|
||||
let seccomp_action = if let Some(seccomp_value) = cmd_arguments.get_one::<String>("seccomp") {
|
||||
match seccomp_value as &str {
|
||||
"true" => SeccompAction::Trap,
|
||||
"false" => SeccompAction::Allow,
|
||||
"log" => SeccompAction::Log,
|
||||
_ => {
|
||||
// The user providing an invalid value will be rejected by clap
|
||||
panic!("Invalid parameter {seccomp_value} for \"--seccomp\" flag");
|
||||
}
|
||||
let api_request_sender_clone = api_request_sender.clone();
|
||||
let seccomp_action = match &toplevel.seccomp as &str {
|
||||
"true" => SeccompAction::Trap,
|
||||
"false" => SeccompAction::Allow,
|
||||
"log" => SeccompAction::Log,
|
||||
val => {
|
||||
// The user providing an invalid value will be rejected
|
||||
panic!("Invalid parameter {val} for \"--seccomp\" flag");
|
||||
}
|
||||
} else {
|
||||
SeccompAction::Trap
|
||||
};
|
||||
|
||||
if seccomp_action == SeccompAction::Trap {
|
||||
@@ -521,7 +528,7 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
||||
let hypervisor = hypervisor::new().map_err(Error::CreateHypervisor)?;
|
||||
|
||||
#[cfg(feature = "guest_debug")]
|
||||
let gdb_socket_path = if let Some(gdb_config) = cmd_arguments.get_one::<String>("gdb") {
|
||||
let gdb_socket_path = if let Some(ref gdb_config) = toplevel.gdb {
|
||||
let mut parser = OptionParser::new();
|
||||
parser.add("path");
|
||||
parser.parse(gdb_config).map_err(Error::ParsingGdb)?;
|
||||
@@ -539,12 +546,16 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
||||
#[cfg(feature = "guest_debug")]
|
||||
let vm_debug_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateDebugEventFd)?;
|
||||
|
||||
let vmm_thread = vmm::start_vmm_thread(
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateExitEventFd)?;
|
||||
|
||||
let vmm_thread_handle = vmm::start_vmm_thread(
|
||||
vmm::VmmVersionInfo::new(env!("BUILD_VERSION"), env!("CARGO_PKG_VERSION")),
|
||||
&api_socket_path,
|
||||
api_socket_fd,
|
||||
#[cfg(feature = "dbus_api")]
|
||||
dbus_options,
|
||||
api_evt.try_clone().unwrap(),
|
||||
http_sender,
|
||||
api_request_sender_clone,
|
||||
api_request_receiver,
|
||||
#[cfg(feature = "guest_debug")]
|
||||
gdb_socket_path,
|
||||
@@ -552,52 +563,78 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
||||
debug_evt.try_clone().unwrap(),
|
||||
#[cfg(feature = "guest_debug")]
|
||||
vm_debug_evt.try_clone().unwrap(),
|
||||
exit_evt.try_clone().unwrap(),
|
||||
&seccomp_action,
|
||||
hypervisor,
|
||||
)
|
||||
.map_err(Error::StartVmmThread)?;
|
||||
|
||||
let payload_present =
|
||||
cmd_arguments.contains_id("kernel") || cmd_arguments.contains_id("firmware");
|
||||
let r: Result<(), Error> = (|| {
|
||||
let payload_present = toplevel.kernel.is_some() || toplevel.firmware.is_some();
|
||||
|
||||
if payload_present {
|
||||
let vm_params = config::VmParams::from_arg_matches(&cmd_arguments);
|
||||
let vm_config = config::VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?;
|
||||
if payload_present {
|
||||
let vm_params = toplevel.to_vm_params();
|
||||
let vm_config = config::VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?;
|
||||
|
||||
// Create and boot the VM based off the VM config we just built.
|
||||
let sender = api_request_sender.clone();
|
||||
vmm::api::vm_create(
|
||||
api_evt.try_clone().unwrap(),
|
||||
api_request_sender,
|
||||
Arc::new(Mutex::new(vm_config)),
|
||||
)
|
||||
.map_err(Error::VmCreate)?;
|
||||
vmm::api::vm_boot(api_evt.try_clone().unwrap(), sender).map_err(Error::VmBoot)?;
|
||||
} else if let Some(restore_params) = cmd_arguments.get_one::<String>("restore") {
|
||||
vmm::api::vm_restore(
|
||||
api_evt.try_clone().unwrap(),
|
||||
api_request_sender,
|
||||
Arc::new(config::RestoreConfig::parse(restore_params).map_err(Error::ParsingRestore)?),
|
||||
)
|
||||
.map_err(Error::VmRestore)?;
|
||||
// Create and boot the VM based off the VM config we just built.
|
||||
let sender = api_request_sender.clone();
|
||||
vmm::api::vm_create(
|
||||
api_evt.try_clone().unwrap(),
|
||||
api_request_sender,
|
||||
Arc::new(Mutex::new(vm_config)),
|
||||
)
|
||||
.map_err(Error::VmCreate)?;
|
||||
vmm::api::vm_boot(api_evt.try_clone().unwrap(), sender).map_err(Error::VmBoot)?;
|
||||
} else if let Some(restore_params) = toplevel.restore {
|
||||
vmm::api::vm_restore(
|
||||
api_evt.try_clone().unwrap(),
|
||||
api_request_sender,
|
||||
Arc::new(
|
||||
config::RestoreConfig::parse(&restore_params).map_err(Error::ParsingRestore)?,
|
||||
),
|
||||
)
|
||||
.map_err(Error::VmRestore)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})();
|
||||
|
||||
if r.is_err() {
|
||||
if let Err(e) = exit_evt.write(1) {
|
||||
warn!("writing to exit EventFd: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
vmm_thread
|
||||
vmm_thread_handle
|
||||
.thread_handle
|
||||
.join()
|
||||
.map_err(Error::ThreadJoin)?
|
||||
.map_err(Error::VmmThread)?;
|
||||
|
||||
Ok(api_socket_path)
|
||||
#[cfg(feature = "dbus_api")]
|
||||
if let Some(chs) = vmm_thread_handle.dbus_shutdown_chs {
|
||||
dbus_api_graceful_shutdown(chs);
|
||||
}
|
||||
|
||||
r.map(|_| api_socket_path)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[cfg(feature = "dhat-heap")]
|
||||
let _profiler = dhat::Profiler::new_heap();
|
||||
|
||||
// Ensure all created files (.e.g sockets) are only accessible by this user
|
||||
// SAFETY: trivially safe
|
||||
let _ = unsafe { libc::umask(0o077) };
|
||||
|
||||
let (default_vcpus, default_memory, default_rng) = prepare_default_values();
|
||||
let cmd_arguments = create_app(default_vcpus, default_memory, default_rng).get_matches();
|
||||
let exit_code = match start_vmm(cmd_arguments) {
|
||||
let toplevel: TopLevel = argh::from_env();
|
||||
|
||||
if toplevel.version {
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
|
||||
return;
|
||||
}
|
||||
|
||||
let exit_code = match start_vmm(toplevel) {
|
||||
Ok(path) => {
|
||||
path.map(|s| std::fs::remove_file(s).ok());
|
||||
0
|
||||
@@ -608,13 +645,8 @@ fn main() {
|
||||
}
|
||||
};
|
||||
|
||||
// SAFETY: trivially safe
|
||||
let on_tty = unsafe { libc::isatty(libc::STDIN_FILENO) } != 0;
|
||||
if on_tty {
|
||||
// Don't forget to set the terminal in canonical mode
|
||||
// before to exit.
|
||||
std::io::stdin().lock().set_canon_mode().unwrap();
|
||||
}
|
||||
#[cfg(feature = "dhat-heap")]
|
||||
drop(_profiler);
|
||||
|
||||
std::process::exit(exit_code);
|
||||
}
|
||||
@@ -622,19 +654,45 @@ fn main() {
|
||||
#[cfg(test)]
|
||||
mod unit_tests {
|
||||
use crate::config::HotplugMethod;
|
||||
use crate::{create_app, prepare_default_values};
|
||||
use crate::TopLevel;
|
||||
use std::path::PathBuf;
|
||||
use vmm::config::{
|
||||
ConsoleConfig, ConsoleOutputMode, CpuFeatures, CpusConfig, MemoryConfig, PayloadConfig,
|
||||
RngConfig, VmConfig, VmParams,
|
||||
RngConfig, VmConfig,
|
||||
};
|
||||
|
||||
fn get_vm_config_from_vec(args: &[&str]) -> VmConfig {
|
||||
let (default_vcpus, default_memory, default_rng) = prepare_default_values();
|
||||
let cmd_arguments =
|
||||
create_app(default_vcpus, default_memory, default_rng).get_matches_from(args);
|
||||
// Taken from argh
|
||||
fn cmd<'a>(default: &'a str, path: &'a str) -> &'a str {
|
||||
std::path::Path::new(path)
|
||||
.file_name()
|
||||
.and_then(|s| s.to_str())
|
||||
.unwrap_or(default)
|
||||
}
|
||||
|
||||
let vm_params = VmParams::from_arg_matches(&cmd_arguments);
|
||||
// Some code taken from argh since it does not provide a helper to parse arbitrary strings
|
||||
fn get_vm_config_from_vec(args: &[&str]) -> VmConfig {
|
||||
let strings: Vec<String> = args.iter().map(|x| x.to_string()).collect();
|
||||
let cmd = cmd(&strings[0], &strings[0]);
|
||||
let strs: Vec<&str> = strings.iter().map(|s| s.as_str()).collect();
|
||||
let toplevel = <TopLevel as argh::FromArgs>::from_args(&[cmd], &strs[1..]).unwrap_or_else(
|
||||
|early_exit| {
|
||||
std::process::exit(match early_exit.status {
|
||||
Ok(()) => {
|
||||
println!("{}", early_exit.output);
|
||||
0
|
||||
}
|
||||
Err(()) => {
|
||||
eprintln!(
|
||||
"{}\nRun {} --help for more information.",
|
||||
early_exit.output, cmd
|
||||
);
|
||||
1
|
||||
}
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
let vm_params = toplevel.to_vm_params();
|
||||
|
||||
VmConfig::parse(vm_params).unwrap()
|
||||
}
|
||||
@@ -724,6 +782,7 @@ mod unit_tests {
|
||||
gdb: false,
|
||||
platform: None,
|
||||
tpm: None,
|
||||
preserved_fds: None,
|
||||
};
|
||||
|
||||
assert_eq!(expected_vm_config, result_vm_config);
|
||||
@@ -893,6 +952,7 @@ mod unit_tests {
|
||||
"/path/to/kernel",
|
||||
"--disk",
|
||||
"path=/path/to/disk/1",
|
||||
"--disk",
|
||||
"path=/path/to/disk/2",
|
||||
],
|
||||
r#"{
|
||||
@@ -911,6 +971,7 @@ mod unit_tests {
|
||||
"/path/to/kernel",
|
||||
"--disk",
|
||||
"path=/path/to/disk/1",
|
||||
"--disk",
|
||||
"path=/path/to/disk/2",
|
||||
],
|
||||
r#"{
|
||||
@@ -1186,6 +1247,7 @@ mod unit_tests {
|
||||
"--memory", "shared=true",
|
||||
"--fs",
|
||||
"tag=virtiofs1,socket=/path/to/sock1",
|
||||
"--fs",
|
||||
"tag=virtiofs2,socket=/path/to/sock2",
|
||||
],
|
||||
r#"{
|
||||
@@ -1204,6 +1266,7 @@ mod unit_tests {
|
||||
"--memory", "shared=true",
|
||||
"--fs",
|
||||
"tag=virtiofs1,socket=/path/to/sock1",
|
||||
"--fs",
|
||||
"tag=virtiofs2,socket=/path/to/sock2",
|
||||
],
|
||||
r#"{
|
||||
@@ -1266,6 +1329,7 @@ mod unit_tests {
|
||||
"/path/to/kernel",
|
||||
"--pmem",
|
||||
"file=/path/to/img/1,size=1G",
|
||||
"--pmem",
|
||||
"file=/path/to/img/2,size=2G",
|
||||
],
|
||||
r#"{
|
||||
@@ -1432,6 +1496,7 @@ mod unit_tests {
|
||||
"/path/to/kernel",
|
||||
"--device",
|
||||
"path=/path/to/device/1",
|
||||
"--device",
|
||||
"path=/path/to/device/2",
|
||||
],
|
||||
r#"{
|
||||
@@ -1450,6 +1515,7 @@ mod unit_tests {
|
||||
"/path/to/kernel",
|
||||
"--device",
|
||||
"path=/path/to/device/1",
|
||||
"--device",
|
||||
"path=/path/to/device/2",
|
||||
],
|
||||
r#"{
|
||||
@@ -1526,6 +1592,7 @@ mod unit_tests {
|
||||
"/path/to/kernel",
|
||||
"--vdpa",
|
||||
"path=/path/to/device/1",
|
||||
"--vdpa",
|
||||
"path=/path/to/device/2,num_queues=2",
|
||||
],
|
||||
r#"{
|
||||
@@ -1544,6 +1611,7 @@ mod unit_tests {
|
||||
"/path/to/kernel",
|
||||
"--vdpa",
|
||||
"path=/path/to/device/1",
|
||||
"--vdpa",
|
||||
"path=/path/to/device/2",
|
||||
],
|
||||
r#"{
|
||||
|
||||
2
test_data/cloud-init/ubuntu/local/meta-data
Normal file
2
test_data/cloud-init/ubuntu/local/meta-data
Normal file
@@ -0,0 +1,2 @@
|
||||
instance-id: cloud
|
||||
local-hostname: cloud
|
||||
7
test_data/cloud-init/ubuntu/local/network-config
Normal file
7
test_data/cloud-init/ubuntu/local/network-config
Normal file
@@ -0,0 +1,7 @@
|
||||
version: 2
|
||||
ethernets:
|
||||
ens4:
|
||||
match:
|
||||
macaddress: 12:34:56:78:90:ab
|
||||
addresses: [192.168.249.2/24]
|
||||
gateway4: 192.168.249.1
|
||||
10
test_data/cloud-init/ubuntu/local/user-data
Normal file
10
test_data/cloud-init/ubuntu/local/user-data
Normal file
@@ -0,0 +1,10 @@
|
||||
#cloud-config
|
||||
users:
|
||||
- name: cloud
|
||||
passwd: $6$7125787751a8d18a$sHwGySomUA1PawiNFWVCKYQN.Ec.Wzz0JtPPL1MvzFrkwmop2dq7.4CYf03A5oemPQ4pOFCCrtCelvFBEle/K.
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
lock_passwd: False
|
||||
inactive: False
|
||||
shell: /bin/bash
|
||||
|
||||
ssh_pwauth: True
|
||||
@@ -5,12 +5,12 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
dirs = "4.0.0"
|
||||
dirs = "5.0.0"
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.139"
|
||||
once_cell = "1.16.0"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.89"
|
||||
ssh2 = { version = "0.9.3", features = ["vendored-openssl"] }
|
||||
once_cell = "1.17.1"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
ssh2 = { version = "0.9.4", features = ["vendored-openssl"] }
|
||||
vmm-sys-util = "0.11.0"
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user