mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
370 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f96fa15a8 | ||
|
|
ed1f906d46 | ||
|
|
3b64b7723b | ||
|
|
6925750622 | ||
|
|
26808bfb71 | ||
|
|
b89657ea22 | ||
|
|
1ef2b488c7 | ||
|
|
7be69edf51 | ||
|
|
c022063ae8 | ||
|
|
e6aa57e3b9 | ||
|
|
512591ba1c | ||
|
|
e7e856d8ac | ||
|
|
a84bc06874 | ||
|
|
a750e6ec15 | ||
|
|
82d275ccaa | ||
|
|
10ab87d6a3 | ||
|
|
dad55fcef2 | ||
|
|
5e9886bba4 | ||
|
|
ce29afd0eb | ||
|
|
493178c972 | ||
|
|
533710f0cd | ||
|
|
2b82384a90 | ||
|
|
e7ee88e8ac | ||
|
|
6c4144e943 | ||
|
|
8a6add9c79 | ||
|
|
76e557814d | ||
|
|
a28ad40671 | ||
|
|
cb9726b4a4 | ||
|
|
b5c5e9b34b | ||
|
|
a5552b87f4 | ||
|
|
79021ebb16 | ||
|
|
00e05c0278 | ||
|
|
691dd926e4 | ||
|
|
b6783d4477 | ||
|
|
077970f99b | ||
|
|
f43df1d415 | ||
|
|
8a80bea4c5 | ||
|
|
108af5a293 | ||
|
|
c8f4fece1a | ||
|
|
549681de59 | ||
|
|
c4ad9b45d0 | ||
|
|
d485896edd | ||
|
|
e1bb5e71bf | ||
|
|
7966925c1c | ||
|
|
f409c4b63b | ||
|
|
d0cfa3a014 | ||
|
|
e99540e5e9 | ||
|
|
101cfb9650 | ||
|
|
11c593e3b9 | ||
|
|
f3b0f59646 | ||
|
|
f09f5af16a | ||
|
|
00684e6d19 | ||
|
|
fa7a000dbe | ||
|
|
85a3623b44 | ||
|
|
66add03d38 | ||
|
|
3fa02b34ca | ||
|
|
5668f02eb6 | ||
|
|
045964deee | ||
|
|
a5e2460d95 | ||
|
|
fd854c7339 | ||
|
|
2d15a2cd45 | ||
|
|
fbe3e4d642 | ||
|
|
28d4957ba5 | ||
|
|
f39d5eeaf0 | ||
|
|
639db35635 | ||
|
|
6482f7e8c3 | ||
|
|
3214dc6431 | ||
|
|
97686ef7a3 | ||
|
|
d3e4f9cc1b | ||
|
|
fcf229a33a | ||
|
|
310382a918 | ||
|
|
6d374d8805 | ||
|
|
11fa24cdcb | ||
|
|
f0be099461 | ||
|
|
3f95ada71e | ||
|
|
c6d5cd78a7 | ||
|
|
80dcb165ba | ||
|
|
6922e25e78 | ||
|
|
5997cfacbf | ||
|
|
55678b23ba | ||
|
|
b15e5923ab | ||
|
|
fd81a23fcc | ||
|
|
acc25def7d | ||
|
|
c3f1c3ee3d | ||
|
|
58e6a289ab | ||
|
|
7c6c45128d | ||
|
|
625b18d2a2 | ||
|
|
fbdc5d4487 | ||
|
|
6bee8ac702 | ||
|
|
749eb423cf | ||
|
|
44fbd60b7a | ||
|
|
98c48d40d2 | ||
|
|
fdcc8539cd | ||
|
|
f7b9a6e577 | ||
|
|
c9e989de6e | ||
|
|
2501426e47 | ||
|
|
dad1ab1227 | ||
|
|
97a1a70275 | ||
|
|
3a60c65369 | ||
|
|
719cae217e | ||
|
|
41bae9fe93 | ||
|
|
f093ffcbef | ||
|
|
2f5e48d295 | ||
|
|
4d52150b87 | ||
|
|
c721c0d88f | ||
|
|
b4b5f16268 | ||
|
|
b8e84f09be | ||
|
|
ab9fc3a8a0 | ||
|
|
1e3d21e504 | ||
|
|
72620295dc | ||
|
|
67054bf78b | ||
|
|
39ab482c47 | ||
|
|
521a0d1ade | ||
|
|
2529ffd593 | ||
|
|
f1856bb27c | ||
|
|
89ff0627e6 | ||
|
|
dd37f33a43 | ||
|
|
87f4399853 | ||
|
|
ec36113751 | ||
|
|
f6b5356dd2 | ||
|
|
0886eb4301 | ||
|
|
0e7c8a1d8a | ||
|
|
cb984e163c | ||
|
|
1363891df6 | ||
|
|
f898e660b6 | ||
|
|
d2c2054047 | ||
|
|
2d6287d159 | ||
|
|
61d9debb5e | ||
|
|
e50e5d8081 | ||
|
|
7ff5ebee1d | ||
|
|
6a446b6158 | ||
|
|
f9be73ae06 | ||
|
|
c85488f22e | ||
|
|
c420dcd41b | ||
|
|
dccc00f208 | ||
|
|
7e487dfa17 | ||
|
|
dcc2294949 | ||
|
|
8f0464b635 | ||
|
|
9c68e86f83 | ||
|
|
cd116cb24f | ||
|
|
da376a4b37 | ||
|
|
fbcf5fb37d | ||
|
|
23632b0bf4 | ||
|
|
d05b05b050 | ||
|
|
1811e24a4b | ||
|
|
d245e62427 | ||
|
|
f1e4a82fd3 | ||
|
|
5466e873c4 | ||
|
|
1708561c74 | ||
|
|
c72bf0b32d | ||
|
|
f40dd4a993 | ||
|
|
f8ac38d113 | ||
|
|
b072671e82 | ||
|
|
6f49d7f192 | ||
|
|
0f71956d6d | ||
|
|
46c9b9693c | ||
|
|
cdafe5344d | ||
|
|
f48942ce3f | ||
|
|
d3fade85a7 | ||
|
|
b65b866895 | ||
|
|
0718067851 | ||
|
|
7d60ab70e6 | ||
|
|
084eb0792d | ||
|
|
b8f5687707 | ||
|
|
1091494320 | ||
|
|
3f2ca5375e | ||
|
|
efc24119f3 | ||
|
|
b750c332aa | ||
|
|
05ec6190da | ||
|
|
1db30405e1 | ||
|
|
3e35529842 | ||
|
|
96cc1ba76c | ||
|
|
022f375ef8 | ||
|
|
81b95023c4 | ||
|
|
f15ca1aec3 | ||
|
|
cb8a728dfb | ||
|
|
80aa91f24c | ||
|
|
d9f48505fe | ||
|
|
1d098949b9 | ||
|
|
18a4d732b9 | ||
|
|
ba6bfee4ff | ||
|
|
eecd879b36 | ||
|
|
57fb97e41f | ||
|
|
97b23f1448 | ||
|
|
0310c5726f | ||
|
|
5627c26405 | ||
|
|
07560c596d | ||
|
|
1a4c890f83 | ||
|
|
e51fb0ee36 | ||
|
|
aa6c486a6b | ||
|
|
b765acd608 | ||
|
|
4fb86e9915 | ||
|
|
7d305c5bbf | ||
|
|
3c4fa14c3e | ||
|
|
b77f779c90 | ||
|
|
1fe2771a0d | ||
|
|
2e4079becb | ||
|
|
d32de07be7 | ||
|
|
6ec83c7d8e | ||
|
|
68dd467104 | ||
|
|
a9aed1a9bc | ||
|
|
84a6da5e93 | ||
|
|
6930370a03 | ||
|
|
89f2a4882e | ||
|
|
307a0166c5 | ||
|
|
845bdfb1b2 | ||
|
|
e136d343ab | ||
|
|
9b722bbcf6 | ||
|
|
927df4e643 | ||
|
|
8e46c03453 | ||
|
|
adb318f4cd | ||
|
|
09f3658999 | ||
|
|
6362b711c6 | ||
|
|
d8cd403c5d | ||
|
|
09cf8c3118 | ||
|
|
da3693f164 | ||
|
|
2b3e10ab88 | ||
|
|
3d5718bd87 | ||
|
|
ef4fbf086f | ||
|
|
9f8aeacd3d | ||
|
|
c9f94be7ab | ||
|
|
af49b10cf2 | ||
|
|
2fc2cabcbc | ||
|
|
ce7db3f7c3 | ||
|
|
bcdd23956f | ||
|
|
b1f3860d9a | ||
|
|
341152b4c7 | ||
|
|
e013fdd9d4 | ||
|
|
eee31f1d41 | ||
|
|
d0be450b1b | ||
|
|
3a683b54d5 | ||
|
|
af4a193b43 | ||
|
|
2b2d00653c | ||
|
|
318caeb9d8 | ||
|
|
612a8dfb1b | ||
|
|
321d6f47e6 | ||
|
|
035c4b20fb | ||
|
|
ee0cf3a715 | ||
|
|
ffef4ae5ac | ||
|
|
8f98240ed4 | ||
|
|
5b0de115f0 | ||
|
|
308b74f3a4 | ||
|
|
441b58437f | ||
|
|
829d310c57 | ||
|
|
9c7ee4ab3d | ||
|
|
ab5a731160 | ||
|
|
f0c1f8d079 | ||
|
|
56dbb8f0db | ||
|
|
66f8841ba1 | ||
|
|
5641e3a283 | ||
|
|
653d0548eb | ||
|
|
50241f94d9 | ||
|
|
7633d47293 | ||
|
|
939cc348ed | ||
|
|
744f2b011b | ||
|
|
08120b79fc | ||
|
|
9b0b881351 | ||
|
|
c1f4a7b295 | ||
|
|
36890373cd | ||
|
|
107f4bdc12 | ||
|
|
8899ebd63c | ||
|
|
c19c73cb99 | ||
|
|
4e0dc5203a | ||
|
|
61afd93a50 | ||
|
|
9dfc39d336 | ||
|
|
e70bf59809 | ||
|
|
d516374c39 | ||
|
|
9b84c6c3f5 | ||
|
|
9b54a8fb1c | ||
|
|
dd13fee3d7 | ||
|
|
3042a0baf3 | ||
|
|
dbda3ade92 | ||
|
|
6dc7e21327 | ||
|
|
166111a0d8 | ||
|
|
73bfaace83 | ||
|
|
95cd81073e | ||
|
|
3603c51f0b | ||
|
|
8c172e41c6 | ||
|
|
5ec47d4883 | ||
|
|
1617736937 | ||
|
|
a9340f5d9d | ||
|
|
82cac6f6ad | ||
|
|
c1206b604e | ||
|
|
0a32779506 | ||
|
|
4625f3ca3a | ||
|
|
3945253619 | ||
|
|
a5296a8147 | ||
|
|
7acfff5da7 | ||
|
|
026d8908fd | ||
|
|
c8ad2bfc05 | ||
|
|
e50a641126 | ||
|
|
8f90fba250 | ||
|
|
3ce0fef7fd | ||
|
|
6cb1d908bf | ||
|
|
51ebc3ac92 | ||
|
|
5368ff28da | ||
|
|
3993663e5c | ||
|
|
2c9cf8d8af | ||
|
|
b4eb2af1c6 | ||
|
|
7674196113 | ||
|
|
c71cb00a5a | ||
|
|
895dc12a74 | ||
|
|
9cb996db09 | ||
|
|
90245be978 | ||
|
|
15e2218c25 | ||
|
|
e33279471f | ||
|
|
993a8324e2 | ||
|
|
76dbe660f5 | ||
|
|
e61c6a1382 | ||
|
|
4ae5503b58 | ||
|
|
7ae46e9b61 | ||
|
|
33a05c7247 | ||
|
|
9b67bc5fe5 | ||
|
|
4ca18c082e | ||
|
|
6aa7afbb6f | ||
|
|
d3bc877a07 | ||
|
|
81bd07fc8b | ||
|
|
d5b813838c | ||
|
|
7bc764d4e0 | ||
|
|
34e965d775 | ||
|
|
7c4ca2bcf9 | ||
|
|
0fb44c074f | ||
|
|
451d3fb2f0 | ||
|
|
7d0b85d727 | ||
|
|
5857d8a7cc | ||
|
|
48de800756 | ||
|
|
dc68a6e30f | ||
|
|
cbcbf635ab | ||
|
|
433d4ddc0c | ||
|
|
9d2a939714 | ||
|
|
c97b56251d | ||
|
|
e041defa67 | ||
|
|
9d5dfa879b | ||
|
|
a511dd1b18 | ||
|
|
a5b6e2c5fd | ||
|
|
2da5763cac | ||
|
|
3e3bb64f4b | ||
|
|
61f0db7713 | ||
|
|
0eba2d1b81 | ||
|
|
9e9bcd24c6 | ||
|
|
c297d8d796 | ||
|
|
c71da496c0 | ||
|
|
d11480197e | ||
|
|
533de1b3c3 | ||
|
|
3d6594a594 | ||
|
|
ee2f0c3cb4 | ||
|
|
9c2d650cb8 | ||
|
|
5c0b66529a | ||
|
|
a2ceb00fbc | ||
|
|
48fc91467b | ||
|
|
c2b746fe15 | ||
|
|
27e8e4ece9 | ||
|
|
e03c0c12a7 | ||
|
|
f8195faaa1 | ||
|
|
accac17b22 | ||
|
|
580b45505b | ||
|
|
24f384d239 | ||
|
|
eaef2ed7de | ||
|
|
4995e8db35 | ||
|
|
16c3df6cad | ||
|
|
42477207e2 | ||
|
|
9b151d06ca | ||
|
|
91fe48d5f7 | ||
|
|
e0abeeb790 | ||
|
|
1302dfcafa | ||
|
|
6c9ed2a655 | ||
|
|
b5ea8b7b02 | ||
|
|
82a3664139 | ||
|
|
b2a78c6188 | ||
|
|
2b4e620813 |
3
.github/workflows/audit.yaml
vendored
3
.github/workflows/audit.yaml
vendored
@@ -4,12 +4,13 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- '**/Cargo.toml'
|
- '**/Cargo.toml'
|
||||||
- '**/Cargo.lock'
|
- '**/Cargo.lock'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
security_audit:
|
security_audit:
|
||||||
name: Audit
|
name: Audit
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions-rs/audit-check@v1
|
- uses: actions-rust-lang/audit@v1
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
11
.github/workflows/build.yaml
vendored
11
.github/workflows/build.yaml
vendored
@@ -1,9 +1,11 @@
|
|||||||
name: Cloud Hypervisor Build
|
name: Cloud Hypervisor Build
|
||||||
on: [pull_request, create]
|
on: [pull_request, merge_group]
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: github.event_name == 'pull_request'
|
|
||||||
name: Build
|
name: Build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -13,7 +15,7 @@ jobs:
|
|||||||
- stable
|
- stable
|
||||||
- beta
|
- beta
|
||||||
- nightly
|
- nightly
|
||||||
- "1.70"
|
- "1.74.1"
|
||||||
target:
|
target:
|
||||||
- x86_64-unknown-linux-gnu
|
- x86_64-unknown-linux-gnu
|
||||||
- x86_64-unknown-linux-musl
|
- x86_64-unknown-linux-musl
|
||||||
@@ -27,11 +29,10 @@ jobs:
|
|||||||
run: sudo apt install -y musl-tools
|
run: sudo apt install -y musl-tools
|
||||||
|
|
||||||
- name: Install Rust toolchain (${{ matrix.rust }})
|
- name: Install Rust toolchain (${{ matrix.rust }})
|
||||||
uses: actions-rs/toolchain@v1
|
uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
toolchain: ${{ matrix.rust }}
|
toolchain: ${{ matrix.rust }}
|
||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
override: true
|
|
||||||
|
|
||||||
- name: Build (default features)
|
- name: Build (default features)
|
||||||
run: cargo rustc --locked --bin cloud-hypervisor -- -D warnings -D clippy::undocumented_unsafe_blocks
|
run: cargo rustc --locked --bin cloud-hypervisor -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||||
|
|||||||
6
.github/workflows/dco.yaml
vendored
6
.github/workflows/dco.yaml
vendored
@@ -1,8 +1,9 @@
|
|||||||
name: DCO
|
name: DCO
|
||||||
on:
|
on: [pull_request, merge_group]
|
||||||
pull_request:
|
|
||||||
jobs:
|
jobs:
|
||||||
check:
|
check:
|
||||||
|
name: DCO Check ("Signed-Off-By")
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -11,6 +12,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: '3.x'
|
python-version: '3.x'
|
||||||
- name: Check DCO
|
- name: Check DCO
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
6
.github/workflows/docker-image.yaml
vendored
6
.github/workflows/docker-image.yaml
vendored
@@ -1,11 +1,13 @@
|
|||||||
name: Cloud Hypervisor's Docker image update
|
name: Cloud Hypervisor's Docker image update
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: main
|
branches: main
|
||||||
paths: resources/Dockerfile
|
paths: resources/Dockerfile
|
||||||
pull_request:
|
pull_request:
|
||||||
paths: resources/Dockerfile
|
paths: resources/Dockerfile
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: ghcr.io
|
REGISTRY: ghcr.io
|
||||||
@@ -39,7 +41,7 @@ jobs:
|
|||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
# generate Docker tags based on the following events/attributes
|
# generate Docker tags based on the following events/attributes
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value={{date 'YYYYMMDD'}}-0
|
type=raw,value=20240407-0
|
||||||
type=sha
|
type=sha
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
|
|||||||
19
.github/workflows/fuzz-build.yaml
vendored
19
.github/workflows/fuzz-build.yaml
vendored
@@ -1,9 +1,11 @@
|
|||||||
name: Cloud Hypervisor Cargo Fuzz Build
|
name: Cloud Hypervisor Cargo Fuzz Build
|
||||||
on: [pull_request, create]
|
on: [pull_request, merge_group]
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: github.event_name == 'pull_request'
|
|
||||||
name: Cargo Fuzz Build
|
name: Cargo Fuzz Build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -12,18 +14,19 @@ jobs:
|
|||||||
- nightly
|
- nightly
|
||||||
target:
|
target:
|
||||||
- x86_64-unknown-linux-gnu
|
- x86_64-unknown-linux-gnu
|
||||||
|
env:
|
||||||
|
RUSTFLAGS: -D warnings
|
||||||
steps:
|
steps:
|
||||||
- name: Code checkout
|
- name: Code checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Rust toolchain (${{ matrix.rust }})
|
- name: Install Rust toolchain (${{ matrix.rust }})
|
||||||
uses: actions-rs/toolchain@v1
|
uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
toolchain: ${{ matrix.rust }}
|
toolchain: ${{ matrix.rust }}
|
||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
override: true
|
|
||||||
- name: Install Cargo fuzz
|
- name: Install Cargo fuzz
|
||||||
# Temporary fix for cargo-fuzz on latest nightly: https://github.com/rust-fuzz/cargo-fuzz/issues/276
|
run: cargo install cargo-fuzz
|
||||||
#run: cargo install cargo-fuzz
|
- name: Fuzz Build
|
||||||
run: cargo install --git https://github.com/rust-fuzz/cargo-fuzz --rev b4df3e58f767b5cad8d1aa6753961003f56f3609
|
|
||||||
- name: Cargo Fuzz Build
|
|
||||||
run: cargo fuzz build
|
run: cargo fuzz build
|
||||||
|
- name: Fuzz Check
|
||||||
|
run: cargo fuzz check
|
||||||
|
|||||||
1
.github/workflows/gitlint.yaml
vendored
1
.github/workflows/gitlint.yaml
vendored
@@ -1,5 +1,4 @@
|
|||||||
name: Commit messages check
|
name: Commit messages check
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
|
|||||||
1
.github/workflows/hadolint.yaml
vendored
1
.github/workflows/hadolint.yaml
vendored
@@ -1,5 +1,4 @@
|
|||||||
name: Lint Dockerfile
|
name: Lint Dockerfile
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
|
|||||||
54
.github/workflows/integration-arm64.yaml
vendored
Normal file
54
.github/workflows/integration-arm64.yaml
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
name: Cloud Hypervisor Tests (ARM64)
|
||||||
|
on: [pull_request, merge_group]
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
timeout-minutes: 60
|
||||||
|
name: Tests (ARM64)
|
||||||
|
runs-on: focal-arm64
|
||||||
|
steps:
|
||||||
|
- name: Fix workspace permissions
|
||||||
|
run: sudo chown -R github-runner:github-runner ${GITHUB_WORKSPACE}
|
||||||
|
- name: Code checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Run unit tests (musl)
|
||||||
|
run: scripts/dev_cli.sh tests --unit --libc musl
|
||||||
|
- name: Load openvswitch module
|
||||||
|
run: sudo modprobe openvswitch
|
||||||
|
- name: Run integration tests (musl)
|
||||||
|
timeout-minutes: 30
|
||||||
|
run: scripts/dev_cli.sh tests --integration --libc musl
|
||||||
|
- name: Install Azure CLI
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
run: |
|
||||||
|
sudo apt install -y ca-certificates curl apt-transport-https lsb-release gnupg
|
||||||
|
curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null
|
||||||
|
echo "deb [arch=arm64] https://packages.microsoft.com/repos/azure-cli/ focal main" | sudo tee /etc/apt/sources.list.d/azure-cli.list
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y azure-cli
|
||||||
|
- name: Download Windows image
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
IMG_BASENAME=windows-11-iot-enterprise-aarch64.raw
|
||||||
|
IMG_PATH=$HOME/workloads/$IMG_BASENAME
|
||||||
|
IMG_GZ_PATH=$HOME/workloads/$IMG_BASENAME.gz
|
||||||
|
IMG_GZ_BLOB_NAME=windows-11-iot-enterprise-aarch64-9-min.raw.gz
|
||||||
|
cp "scripts/$IMG_BASENAME.sha1" "$HOME/workloads/"
|
||||||
|
pushd "$HOME/workloads"
|
||||||
|
if sha1sum "$IMG_BASENAME.sha1" --check; then
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
popd
|
||||||
|
mkdir -p "$HOME/workloads"
|
||||||
|
az storage blob download --container-name private-images --file "$IMG_GZ_PATH" --name "$IMG_GZ_BLOB_NAME" --connection-string "${{ secrets.CH_PRIVATE_IMAGES }}"
|
||||||
|
gzip -d $IMG_GZ_PATH
|
||||||
|
- name: Run Windows guest integration tests
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
timeout-minutes: 30
|
||||||
|
run: scripts/dev_cli.sh tests --integration-windows --libc musl
|
||||||
22
.github/workflows/integration-metrics.yaml
vendored
Normal file
22
.github/workflows/integration-metrics.yaml
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
name: Cloud Hypervisor Tests (Metrics)
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Tests (Metrics)
|
||||||
|
runs-on: jammy-metrics
|
||||||
|
env:
|
||||||
|
METRICS_PUBLISH_KEY: ${{ secrets.METRICS_PUBLISH_KEY }}
|
||||||
|
steps:
|
||||||
|
- name: Code checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Run metrics tests
|
||||||
|
timeout-minutes: 60
|
||||||
|
run: scripts/dev_cli.sh tests --metrics -- -- --report-file /root/workloads/metrics.json
|
||||||
|
- name: Upload metrics report
|
||||||
|
run: 'curl -X PUT https://ch-metrics.azurewebsites.net/api/publishmetrics -H "x-functions-key: $METRICS_PUBLISH_KEY" -T ~/workloads/metrics.json'
|
||||||
28
.github/workflows/integration-rate-limiter.yaml
vendored
Normal file
28
.github/workflows/integration-rate-limiter.yaml
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
name: Cloud Hypervisor Tests (Rate-Limiter)
|
||||||
|
on: [merge_group, pull_request]
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Tests (Rate-Limiter)
|
||||||
|
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'jammy-rate-limiter' }}
|
||||||
|
env:
|
||||||
|
AUTH_DOWNLOAD_TOKEN: ${{ secrets.AUTH_DOWNLOAD_TOKEN }}
|
||||||
|
steps:
|
||||||
|
- name: Fix workspace permissions
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
run: sudo chown -R github-runner:github-runner ${GITHUB_WORKSPACE}
|
||||||
|
- name: Code checkout
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Run rate-limiter integration tests
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
timeout-minutes: 10
|
||||||
|
run: scripts/dev_cli.sh tests --integration-rate-limiter
|
||||||
|
- name: Skipping build for PR
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
run: echo "Skipping build for PR"
|
||||||
32
.github/workflows/integration-sgx.yaml
vendored
Normal file
32
.github/workflows/integration-sgx.yaml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Cloud Hypervisor Tests (SGX)
|
||||||
|
on: [merge_group, pull_request]
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Tests (SGX)
|
||||||
|
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'jammy-sgx' }}
|
||||||
|
env:
|
||||||
|
AUTH_DOWNLOAD_TOKEN: ${{ secrets.AUTH_DOWNLOAD_TOKEN }}
|
||||||
|
steps:
|
||||||
|
- name: Fix workspace permissions
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
run: sudo chown -R github-runner:github-runner ${GITHUB_WORKSPACE}
|
||||||
|
- name: Code checkout
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Run SGX integration tests
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
timeout-minutes: 10
|
||||||
|
run: scripts/dev_cli.sh tests --integration-sgx
|
||||||
|
- name: Run SGX integration tests for musl
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
timeout-minutes: 10
|
||||||
|
run: scripts/dev_cli.sh tests --integration-sgx --libc musl
|
||||||
|
- name: Skipping build for PR
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
run: echo "Skipping build for PR"
|
||||||
32
.github/workflows/integration-vfio.yaml
vendored
Normal file
32
.github/workflows/integration-vfio.yaml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Cloud Hypervisor Tests (VFIO)
|
||||||
|
on: [merge_group, pull_request]
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Tests (VFIO)
|
||||||
|
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'jammy-vfio' }}
|
||||||
|
env:
|
||||||
|
AUTH_DOWNLOAD_TOKEN: ${{ secrets.AUTH_DOWNLOAD_TOKEN }}
|
||||||
|
steps:
|
||||||
|
- name: Fix workspace permissions
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
run: sudo chown -R github-runner:github-runner ${GITHUB_WORKSPACE}
|
||||||
|
- name: Code checkout
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Run VFIO integration tests
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
timeout-minutes: 15
|
||||||
|
run: scripts/dev_cli.sh tests --integration-vfio
|
||||||
|
- name: Run VFIO integration tests for musl
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
timeout-minutes: 15
|
||||||
|
run: scripts/dev_cli.sh tests --integration-vfio --libc musl
|
||||||
|
- name: Skipping build for PR
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
run: echo "Skipping build for PR"
|
||||||
50
.github/workflows/integration-windows.yaml
vendored
Normal file
50
.github/workflows/integration-windows.yaml
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
name: Cloud Hypervisor Tests (Windows Guest)
|
||||||
|
on: [merge_group, pull_request]
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Tests (Windows Guest)
|
||||||
|
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'garm-jammy-16' }}
|
||||||
|
steps:
|
||||||
|
- name: Code checkout
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Install Docker
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -y install ca-certificates curl gnupg
|
||||||
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||||||
|
sudo chmod a+r /usr/share/keyrings/docker-archive-keyring.gpg
|
||||||
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt install -y docker-ce docker-ce-cli
|
||||||
|
- name: Install Azure CLI
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
run: |
|
||||||
|
sudo apt install -y ca-certificates curl apt-transport-https lsb-release gnupg
|
||||||
|
curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null
|
||||||
|
echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ jammy main" | sudo tee /etc/apt/sources.list.d/azure-cli.list
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y azure-cli
|
||||||
|
- name: Download Windows image
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
run: |
|
||||||
|
mkdir $HOME/workloads
|
||||||
|
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 "${{ secrets.CH_PRIVATE_IMAGES }}"
|
||||||
|
- name: Run Windows guest integration tests
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
timeout-minutes: 15
|
||||||
|
run: scripts/dev_cli.sh tests --integration-windows
|
||||||
|
- name: Run Windows guest integration tests for musl
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
timeout-minutes: 15
|
||||||
|
run: scripts/dev_cli.sh tests --integration-windows --libc musl
|
||||||
|
- name: Skipping build for PR
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
run: echo "Skipping build for PR"
|
||||||
52
.github/workflows/integration-x86-64.yaml
vendored
Normal file
52
.github/workflows/integration-x86-64.yaml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
name: Cloud Hypervisor Tests (x86-64)
|
||||||
|
on: [pull_request, merge_group]
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
timeout-minutes: 60
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
runner: ['garm-jammy', "garm-jammy-amd"]
|
||||||
|
libc: ["musl", 'gnu']
|
||||||
|
name: Tests (x86-64)
|
||||||
|
runs-on: ${{ github.event_name == 'pull_request' && !(matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') && 'ubuntu-latest' || format('{0}-16', matrix.runner) }}
|
||||||
|
steps:
|
||||||
|
- name: Code checkout
|
||||||
|
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Install Docker
|
||||||
|
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -y install ca-certificates curl gnupg
|
||||||
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||||||
|
sudo chmod a+r /usr/share/keyrings/docker-archive-keyring.gpg
|
||||||
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt install -y docker-ce docker-ce-cli
|
||||||
|
- name: Prepare for VDPA
|
||||||
|
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
|
||||||
|
run: scripts/prepare_vdpa.sh
|
||||||
|
- name: Run unit tests
|
||||||
|
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
|
||||||
|
run: scripts/dev_cli.sh tests --unit --libc ${{ matrix.libc }}
|
||||||
|
- name: Load openvswitch module
|
||||||
|
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
|
||||||
|
run: sudo modprobe openvswitch
|
||||||
|
- name: Run integration tests
|
||||||
|
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
|
||||||
|
timeout-minutes: 40
|
||||||
|
run: scripts/dev_cli.sh tests --integration --libc ${{ matrix.libc }}
|
||||||
|
- name: Run live-migration integration tests
|
||||||
|
if: ${{ github.event_name != 'pull_request' || (matrix.runner == 'garm-jammy' && matrix.libc == 'gnu') }}
|
||||||
|
timeout-minutes: 20
|
||||||
|
run: scripts/dev_cli.sh tests --integration-live-migration --libc ${{ matrix.libc }}
|
||||||
|
- name: Skipping build for PR
|
||||||
|
if: ${{ github.event_name == 'pull_request' && matrix.runner != 'garm-jammy' && matrix.libc != 'gnu' }}
|
||||||
|
run: echo "Skipping build for PR"
|
||||||
4
.github/workflows/openapi.yaml
vendored
4
.github/workflows/openapi.yaml
vendored
@@ -1,7 +1,5 @@
|
|||||||
name: Cloud Hypervisor OpenAPI Validation
|
name: Cloud Hypervisor OpenAPI Validation
|
||||||
|
on: [pull_request, merge_group]
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Validate:
|
Validate:
|
||||||
|
|||||||
10
.github/workflows/quality.yaml
vendored
10
.github/workflows/quality.yaml
vendored
@@ -1,9 +1,11 @@
|
|||||||
name: Cloud Hypervisor Quality Checks
|
name: Cloud Hypervisor Quality Checks
|
||||||
on: [pull_request, create]
|
on: [pull_request, merge_group]
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: github.event_name == 'pull_request'
|
|
||||||
name: Quality (clippy, rustfmt)
|
name: Quality (clippy, rustfmt)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
continue-on-error: ${{ matrix.experimental }}
|
continue-on-error: ${{ matrix.experimental }}
|
||||||
@@ -46,8 +48,8 @@ jobs:
|
|||||||
override: true
|
override: true
|
||||||
components: rustfmt, clippy
|
components: rustfmt, clippy
|
||||||
|
|
||||||
- name: Debug Check (default features)
|
- name: Bisectability Check (default features)
|
||||||
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
if: ${{ github.event_name == 'pull_request' && matrix.target == 'x86_64-unknown-linux-gnu' }}
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
commits=$(git rev-list origin/${{ github.base_ref }}..${{ github.sha }})
|
commits=$(git rev-list origin/${{ github.base_ref }}..${{ github.sha }})
|
||||||
|
|||||||
189
.github/workflows/release.yaml
vendored
189
.github/workflows/release.yaml
vendored
@@ -1,134 +1,69 @@
|
|||||||
name: Cloud Hypervisor Release
|
name: Cloud Hypervisor Release
|
||||||
on: [pull_request, create]
|
on: [create, merge_group]
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
if: (github.event_name == 'create' && github.event.ref_type == 'tag') || github.event_name == 'pull_request'
|
if: (github.event_name == 'create' && github.event.ref_type == 'tag') || github.event_name == 'merge_group'
|
||||||
name: Release
|
name: Release ${{ matrix.platform.target }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
platform:
|
||||||
|
- target: x86_64-unknown-linux-gnu
|
||||||
|
args: --all --release --features mshv
|
||||||
|
name_ch: cloud-hypervisor
|
||||||
|
name_ch_remote: ch-remote
|
||||||
|
- target: x86_64-unknown-linux-musl
|
||||||
|
args: --all --release --features mshv
|
||||||
|
name_ch: cloud-hypervisor-static
|
||||||
|
name_ch_remote: ch-remote-static
|
||||||
|
- target: aarch64-unknown-linux-musl
|
||||||
|
args: --all --release
|
||||||
|
name_ch: cloud-hypervisor-static-aarch64
|
||||||
|
name_ch_remote: ch-remote-static-aarch64
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Code checkout
|
- name: Code checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install musl-gcc
|
- name: Install musl-gcc
|
||||||
|
if: contains(matrix.platform.target, 'musl')
|
||||||
run: sudo apt install -y musl-tools
|
run: sudo apt install -y musl-tools
|
||||||
- name: Create release directory
|
- name: Create release directory
|
||||||
|
if: |
|
||||||
|
github.event_name == 'create' && github.event.ref_type == 'tag' &&
|
||||||
|
matrix.platform.target == 'x86_64-unknown-linux-gnu'
|
||||||
run: rsync -rv --exclude=.git . ../cloud-hypervisor-${{ github.event.ref }}
|
run: rsync -rv --exclude=.git . ../cloud-hypervisor-${{ github.event.ref }}
|
||||||
- name: Install Rust toolchain (x86_64-unknown-linux-gnu)
|
- name: Build ${{ matrix.platform.target }}
|
||||||
uses: actions-rs/toolchain@v1
|
uses: houseabsolute/actions-rust-cross@v0
|
||||||
with:
|
with:
|
||||||
toolchain: "1.70"
|
|
||||||
target: x86_64-unknown-linux-gnu
|
|
||||||
- name: Install Rust toolchain (x86_64-unknown-linux-musl)
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: "1.70"
|
|
||||||
target: x86_64-unknown-linux-musl
|
|
||||||
- name: Build
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
toolchain: "1.70"
|
|
||||||
command: build
|
command: build
|
||||||
args: --all --release --features mshv --target=x86_64-unknown-linux-gnu
|
target: ${{ matrix.platform.target }}
|
||||||
- name: Static Build
|
args: ${{ matrix.platform.args }}
|
||||||
uses: actions-rs/cargo@v1
|
strip: true
|
||||||
with:
|
toolchain: 1.74.1
|
||||||
toolchain: "1.70"
|
- name: Copy Release Binaries
|
||||||
command: build
|
|
||||||
args: --all --release --features mshv --target=x86_64-unknown-linux-musl
|
|
||||||
- name: Install Rust toolchain (aarch64-unknown-linux-musl)
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: "1.70"
|
|
||||||
target: aarch64-unknown-linux-musl
|
|
||||||
override: true
|
|
||||||
- name: Create Release
|
|
||||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||||
id: create_release
|
shell: bash
|
||||||
uses: actions/create-release@v1
|
run: |
|
||||||
env:
|
cp target/${{ matrix.platform.target }}/release/cloud-hypervisor ./${{ matrix.platform.name_ch }}
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
cp target/${{ matrix.platform.target }}/release/ch-remote ./${{ matrix.platform.name_ch_remote }}
|
||||||
with:
|
- name: Upload Release Artifacts
|
||||||
tag_name: ${{ github.ref }}
|
|
||||||
release_name: ${{ github.ref }}
|
|
||||||
draft: true
|
|
||||||
prerelease: true
|
|
||||||
- name: Upload cloud-hypervisor
|
|
||||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||||
id: upload-release-cloud-hypervisor
|
uses: actions/upload-artifact@v3
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
name: Artifacts for ${{ matrix.platform.target }}
|
||||||
asset_path: target/x86_64-unknown-linux-gnu/release/cloud-hypervisor
|
path: |
|
||||||
asset_name: cloud-hypervisor
|
./${{ matrix.platform.name_ch }}
|
||||||
asset_content_type: application/octet-stream
|
./${{ matrix.platform.name_ch_remote }}
|
||||||
- name: Upload static cloud-hypervisor
|
|
||||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
|
||||||
id: upload-release-static-cloud-hypervisor
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
asset_path: target/x86_64-unknown-linux-musl/release/cloud-hypervisor
|
|
||||||
asset_name: cloud-hypervisor-static
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
- name: Upload ch-remote
|
|
||||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
|
||||||
id: upload-release-ch-remote
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
asset_path: target/x86_64-unknown-linux-gnu/release/ch-remote
|
|
||||||
asset_name: ch-remote
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
- name: Upload static-ch-remote
|
|
||||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
|
||||||
id: upload-release-static-ch-remote
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
asset_path: target/x86_64-unknown-linux-musl/release/ch-remote
|
|
||||||
asset_name: ch-remote-static
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
- name: Clean build tree ahead of cross build
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: clean
|
|
||||||
- name: Static Build (AArch64)
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
use-cross: true
|
|
||||||
command: build
|
|
||||||
args: --all --release --target=aarch64-unknown-linux-musl
|
|
||||||
- name: Upload static AArch64 cloud-hypervisor
|
|
||||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
|
||||||
id: upload-release-static-aarch64-cloud-hypervisor
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
asset_path: target/aarch64-unknown-linux-musl/release/cloud-hypervisor
|
|
||||||
asset_name: cloud-hypervisor-static-aarch64
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
- name: Upload static AArch64 ch-remote
|
|
||||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
|
||||||
id: upload-release-static-aarch64-ch-remote
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
asset_path: target/aarch64-unknown-linux-musl/release/ch-remote
|
|
||||||
asset_name: ch-remote-static-aarch64
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
- name: Vendor
|
- name: Vendor
|
||||||
|
if: |
|
||||||
|
github.event_name == 'create' && github.event.ref_type == 'tag' &&
|
||||||
|
matrix.platform.target == 'x86_64-unknown-linux-gnu'
|
||||||
working-directory: ../cloud-hypervisor-${{ github.event.ref }}
|
working-directory: ../cloud-hypervisor-${{ github.event.ref }}
|
||||||
run: |
|
run: |
|
||||||
mkdir ../vendor-cargo-home
|
mkdir ../vendor-cargo-home
|
||||||
@@ -136,16 +71,24 @@ jobs:
|
|||||||
mkdir .cargo
|
mkdir .cargo
|
||||||
cargo vendor > .cargo/config.toml
|
cargo vendor > .cargo/config.toml
|
||||||
- name: Create vendored source archive
|
- name: Create vendored source archive
|
||||||
working-directory: ../
|
if: |
|
||||||
run: tar cJf cloud-hypervisor-${{ github.event.ref }}.tar.xz cloud-hypervisor-${{ github.event.ref }}
|
github.event_name == 'create' && github.event.ref_type == 'tag' &&
|
||||||
|
matrix.platform.target == 'x86_64-unknown-linux-gnu'
|
||||||
|
run: tar cJf cloud-hypervisor-${{ github.event.ref }}.tar.xz ../cloud-hypervisor-${{ github.event.ref }}
|
||||||
- name: Upload cloud-hypervisor vendored source archive
|
- name: Upload cloud-hypervisor vendored source archive
|
||||||
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
if: |
|
||||||
|
github.event_name == 'create' && github.event.ref_type == 'tag' &&
|
||||||
|
matrix.platform.target == 'x86_64-unknown-linux-gnu'
|
||||||
id: upload-release-cloud-hypervisor-vendored-sources
|
id: upload-release-cloud-hypervisor-vendored-sources
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-artifact@v3
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
path: cloud-hypervisor-${{ github.event.ref }}.tar.xz
|
||||||
asset_path: ../cloud-hypervisor-${{ github.event.ref }}.tar.xz
|
name: cloud-hypervisor-${{ github.event.ref }}.tar.xz
|
||||||
asset_name: cloud-hypervisor-${{ github.event.ref }}.tar.xz
|
- name: Create GitHub Release
|
||||||
asset_content_type: application/x-xz
|
if: github.event_name == 'create' && github.event.ref_type == 'tag'
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
./${{ matrix.platform.name_ch }}
|
||||||
|
./${{ matrix.platform.name_ch_remote }}
|
||||||
|
./cloud-hypervisor-${{ github.event.ref }}.tar.xz
|
||||||
|
|||||||
12
.github/workflows/reuse.yaml
vendored
Normal file
12
.github/workflows/reuse.yaml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
name: REUSE Compliance Check
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
reuse:
|
||||||
|
name: REUSE Compliance Check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: REUSE Compliance Check
|
||||||
|
uses: fsfe/reuse-action@v3
|
||||||
20
.github/workflows/shlint.yaml
vendored
Normal file
20
.github/workflows/shlint.yaml
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
name: Shell scripts check
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
merge_group:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sh-checker:
|
||||||
|
name: Check shell scripts
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Run the shell script checkers
|
||||||
|
uses: luizm/action-sh-checker@master
|
||||||
|
env:
|
||||||
|
SHFMT_OPTS: -i 4 -d
|
||||||
|
SHELLCHECK_OPTS: -x --source-path scripts
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@
|
|||||||
**/rusty-tags.vi
|
**/rusty-tags.vi
|
||||||
/rpm/SOURCES
|
/rpm/SOURCES
|
||||||
/.vscode
|
/.vscode
|
||||||
|
/vendor
|
||||||
|
|||||||
12
.reuse/dep5
Normal file
12
.reuse/dep5
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
|
Upstream-Name: cloud-hypervisor
|
||||||
|
Upstream-Contact: <>
|
||||||
|
Source: https://www.cloudhypervisor.org
|
||||||
|
|
||||||
|
Files: docs/*.md *.md
|
||||||
|
Copyright: 2024
|
||||||
|
License: CC-BY-4.0
|
||||||
|
|
||||||
|
Files: scripts/* test_data/* *.toml .git* fuzz/Cargo.lock fuzz/.gitignore resources/linux-config-* vmm/src/api/openapi/cloud-hypervisor.yaml CODEOWNERS Cargo.lock
|
||||||
|
Copyright: 2024
|
||||||
|
License: Apache-2.0
|
||||||
1114
Cargo.lock
generated
1114
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
36
Cargo.toml
36
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cloud-hypervisor"
|
name = "cloud-hypervisor"
|
||||||
version = "37.0.0"
|
version = "39.0.0"
|
||||||
authors = ["The Cloud Hypervisor Authors"]
|
authors = ["The Cloud Hypervisor Authors"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
default-run = "cloud-hypervisor"
|
default-run = "cloud-hypervisor"
|
||||||
@@ -15,7 +15,7 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
|||||||
# 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,
|
# 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.
|
# c.) There is a security issue that is addressed by the toolchain update.
|
||||||
rust-version = "1.70"
|
rust-version = "1.74.1"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
@@ -29,38 +29,32 @@ strip = false
|
|||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.81"
|
||||||
api_client = { path = "api_client" }
|
api_client = { path = "api_client" }
|
||||||
clap = { version = "4.4.7", features = ["string"] }
|
clap = { version = "4.5.4", features = ["string"] }
|
||||||
dhat = { version = "0.3.2", optional = true }
|
dhat = { version = "0.3.3", optional = true }
|
||||||
epoll = "4.3.3"
|
epoll = "4.3.3"
|
||||||
event_monitor = { path = "event_monitor" }
|
event_monitor = { path = "event_monitor" }
|
||||||
hypervisor = { path = "hypervisor" }
|
hypervisor = { path = "hypervisor" }
|
||||||
libc = "0.2.147"
|
libc = "0.2.153"
|
||||||
log = { version = "0.4.20", features = ["std"] }
|
log = { version = "0.4.21", features = ["std"] }
|
||||||
option_parser = { path = "option_parser" }
|
option_parser = { path = "option_parser" }
|
||||||
seccompiler = "0.4.0"
|
seccompiler = "0.4.0"
|
||||||
serde_json = "1.0.107"
|
serde_json = "1.0.115"
|
||||||
signal-hook = "0.3.17"
|
signal-hook = "0.3.17"
|
||||||
thiserror = "1.0.40"
|
thiserror = "1.0.58"
|
||||||
tpm = { path = "tpm"}
|
tpm = { path = "tpm"}
|
||||||
tracer = { path = "tracer" }
|
tracer = { path = "tracer" }
|
||||||
vmm = { path = "vmm" }
|
vmm = { path = "vmm" }
|
||||||
vmm-sys-util = "0.11.0"
|
vmm-sys-util = "0.12.1"
|
||||||
vm-memory = "0.13.1"
|
vm-memory = "0.14.1"
|
||||||
zbus = { version = "3.11.1", optional = true }
|
zbus = { version = "3.15.2", 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" }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
dirs = "5.0.0"
|
dirs = "5.0.1"
|
||||||
net_util = { path = "net_util" }
|
net_util = { path = "net_util" }
|
||||||
once_cell = "1.18.0"
|
once_cell = "1.19.0"
|
||||||
serde_json = "1.0.107"
|
serde_json = "1.0.115"
|
||||||
test_infra = { path = "test_infra" }
|
test_infra = { path = "test_infra" }
|
||||||
wait-timeout = "0.2.0"
|
wait-timeout = "0.2.0"
|
||||||
|
|
||||||
|
|||||||
530
Jenkinsfile
vendored
530
Jenkinsfile
vendored
@@ -1,530 +0,0 @@
|
|||||||
def runWorkers = true
|
|
||||||
pipeline {
|
|
||||||
agent none
|
|
||||||
options {
|
|
||||||
timeout(time: 4, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Early checks') {
|
|
||||||
agent { node { label 'built-in' } }
|
|
||||||
stages {
|
|
||||||
stage('Checkout') {
|
|
||||||
steps {
|
|
||||||
checkout scm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Check if worker build can be skipped') {
|
|
||||||
when {
|
|
||||||
expression {
|
|
||||||
return skipWorkerBuild()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
runWorkers = false
|
|
||||||
echo 'No changes requiring a build'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Check for RFC/WIP builds') {
|
|
||||||
when {
|
|
||||||
changeRequest comparator: 'REGEXP', title: '.*(rfc|RFC|wip|WIP).*'
|
|
||||||
beforeAgent true
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
error('Failing as this is marked as a WIP or RFC PR.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Cancel older builds') {
|
|
||||||
when { not { branch 'main' } }
|
|
||||||
steps {
|
|
||||||
cancelPreviousBuilds()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Build') {
|
|
||||||
parallel {
|
|
||||||
stage('Worker build') {
|
|
||||||
agent { node { label 'jammy' } }
|
|
||||||
when {
|
|
||||||
beforeAgent true
|
|
||||||
expression {
|
|
||||||
return runWorkers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
environment {
|
|
||||||
AUTH_DOWNLOAD_TOKEN = credentials('8a26fd74-d40e-414c-9132-ff3f867806ef')
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Checkout') {
|
|
||||||
steps {
|
|
||||||
checkout scm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Prepare environment') {
|
|
||||||
steps {
|
|
||||||
sh 'scripts/prepare_vdpa.sh'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run unit tests') {
|
|
||||||
steps {
|
|
||||||
sh 'scripts/dev_cli.sh tests --unit'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run integration tests') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'sudo modprobe openvswitch'
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run live-migration integration tests') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'sudo modprobe openvswitch'
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration-live-migration'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run unit tests for musl') {
|
|
||||||
steps {
|
|
||||||
sh 'scripts/dev_cli.sh tests --unit --libc musl'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run integration tests for musl') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'sudo modprobe openvswitch'
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration --libc musl'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run live-migration integration tests for musl') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'sudo modprobe openvswitch'
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration-live-migration --libc musl'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Worker build - AMD') {
|
|
||||||
agent { node { label 'jammy-amd' } }
|
|
||||||
when {
|
|
||||||
beforeAgent true
|
|
||||||
expression {
|
|
||||||
return runWorkers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
environment {
|
|
||||||
AUTH_DOWNLOAD_TOKEN = credentials('8a26fd74-d40e-414c-9132-ff3f867806ef')
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Checkout') {
|
|
||||||
steps {
|
|
||||||
checkout scm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Prepare environment') {
|
|
||||||
steps {
|
|
||||||
sh 'scripts/prepare_vdpa.sh'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run integration tests') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'sudo modprobe openvswitch'
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration -- -- --skip common_parallel::test_vfio'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run live-migration integration tests') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'sudo modprobe openvswitch'
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration-live-migration'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run integration tests for musl') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'sudo modprobe openvswitch'
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration --libc musl -- -- --skip common_parallel::test_vfio'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run live-migration integration tests for musl') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'sudo modprobe openvswitch'
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration-live-migration --libc musl'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('AArch64 worker build') {
|
|
||||||
agent { node { label 'bionic-arm64' } }
|
|
||||||
when {
|
|
||||||
beforeAgent true
|
|
||||||
expression {
|
|
||||||
return runWorkers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
environment {
|
|
||||||
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Checkout') {
|
|
||||||
steps {
|
|
||||||
checkout scm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run unit tests') {
|
|
||||||
steps {
|
|
||||||
sh 'scripts/dev_cli.sh tests --unit --libc musl'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run integration tests') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'sudo modprobe openvswitch'
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration --libc musl'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Install azure-cli') {
|
|
||||||
steps {
|
|
||||||
installAzureCli('focal', 'arm64')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Download Windows image') {
|
|
||||||
steps {
|
|
||||||
sh '''#!/bin/bash -x
|
|
||||||
IMG_BASENAME=windows-11-iot-enterprise-aarch64.raw
|
|
||||||
IMG_PATH=$HOME/workloads/$IMG_BASENAME
|
|
||||||
IMG_GZ_PATH=$HOME/workloads/$IMG_BASENAME.gz
|
|
||||||
IMG_GZ_BLOB_NAME=windows-11-iot-enterprise-aarch64-9-min.raw.gz
|
|
||||||
cp "scripts/$IMG_BASENAME.sha1" "$HOME/workloads/"
|
|
||||||
pushd "$HOME/workloads"
|
|
||||||
if sha1sum "$IMG_BASENAME.sha1" --check; then
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
popd
|
|
||||||
mkdir -p "$HOME/workloads"
|
|
||||||
az storage blob download \
|
|
||||||
--container-name private-images \
|
|
||||||
--file "$IMG_GZ_PATH" \
|
|
||||||
--name "$IMG_GZ_BLOB_NAME" \
|
|
||||||
--connection-string "$AZURE_CONNECTION_STRING"
|
|
||||||
gzip -d $IMG_GZ_PATH
|
|
||||||
'''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run Windows guest integration tests') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration-windows --libc musl'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
post {
|
|
||||||
always {
|
|
||||||
sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
|
|
||||||
deleteDir()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Worker build - Windows guest') {
|
|
||||||
agent { node { label 'jammy' } }
|
|
||||||
when {
|
|
||||||
beforeAgent true
|
|
||||||
expression {
|
|
||||||
return runWorkers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
environment {
|
|
||||||
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Checkout') {
|
|
||||||
steps {
|
|
||||||
checkout scm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Install azure-cli') {
|
|
||||||
steps {
|
|
||||||
installAzureCli('jammy', 'amd64')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Download assets') {
|
|
||||||
steps {
|
|
||||||
sh "mkdir ${env.HOME}/workloads"
|
|
||||||
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') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration-windows'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run Windows guest integration tests for musl') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration-windows --libc musl'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Worker build - Metrics') {
|
|
||||||
agent { node { label 'jammy-metrics' } }
|
|
||||||
when {
|
|
||||||
branch 'main'
|
|
||||||
beforeAgent true
|
|
||||||
expression {
|
|
||||||
return runWorkers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
environment {
|
|
||||||
METRICS_PUBLISH_KEY = credentials('52e0945f-ce7a-43d1-87af-67d1d87cc40f')
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Checkout') {
|
|
||||||
steps {
|
|
||||||
checkout scm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run metrics tests') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'scripts/dev_cli.sh tests --metrics -- -- --report-file /root/workloads/metrics.json'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Upload metrics report') {
|
|
||||||
steps {
|
|
||||||
sh 'curl -X PUT https://cloud-hypervisor-metrics.azurewebsites.net/api/publishmetrics -H "x-functions-key: $METRICS_PUBLISH_KEY" -T ~/workloads/metrics.json'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Worker build - Rate Limiter') {
|
|
||||||
agent { node { label 'focal-metrics' } }
|
|
||||||
when {
|
|
||||||
branch 'main'
|
|
||||||
beforeAgent true
|
|
||||||
expression {
|
|
||||||
return runWorkers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Checkout') {
|
|
||||||
steps {
|
|
||||||
checkout scm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run rate-limiter integration tests') {
|
|
||||||
options {
|
|
||||||
timeout(time: 10, unit: 'MINUTES')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration-rate-limiter'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Worker build - SGX') {
|
|
||||||
agent { node { label 'jammy-sgx' } }
|
|
||||||
when {
|
|
||||||
beforeAgent true
|
|
||||||
allOf {
|
|
||||||
branch 'main'
|
|
||||||
expression {
|
|
||||||
return runWorkers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
environment {
|
|
||||||
AUTH_DOWNLOAD_TOKEN = credentials('8a26fd74-d40e-414c-9132-ff3f867806ef')
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Checkout') {
|
|
||||||
steps {
|
|
||||||
checkout scm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run SGX integration tests') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration-sgx'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run SGX integration tests for musl') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration-sgx --libc musl'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
post {
|
|
||||||
always {
|
|
||||||
sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
|
|
||||||
deleteDir()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Worker build - VFIO') {
|
|
||||||
agent { node { label 'jammy-vfio' } }
|
|
||||||
when {
|
|
||||||
beforeAgent true
|
|
||||||
allOf {
|
|
||||||
branch 'main'
|
|
||||||
expression {
|
|
||||||
return runWorkers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
environment {
|
|
||||||
AUTH_DOWNLOAD_TOKEN = credentials('8a26fd74-d40e-414c-9132-ff3f867806ef')
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage('Checkout') {
|
|
||||||
steps {
|
|
||||||
checkout scm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run VFIO integration tests') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration-vfio'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Run VFIO integration tests for musl') {
|
|
||||||
options {
|
|
||||||
timeout(time: 1, unit: 'HOURS')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'scripts/dev_cli.sh tests --integration-vfio --libc musl'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
post {
|
|
||||||
always {
|
|
||||||
sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
|
|
||||||
deleteDir()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
post {
|
|
||||||
regression {
|
|
||||||
script {
|
|
||||||
if (env.BRANCH_NAME == 'main') {
|
|
||||||
slackSend(color: '#ff0000', message: '"main" branch build is now failing', channel: '#jenkins-ci')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fixed {
|
|
||||||
script {
|
|
||||||
if (env.BRANCH_NAME == 'main') {
|
|
||||||
slackSend(color: '#00ff00', message: '"main" branch build is now fixed', channel: '#jenkins-ci')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def cancelPreviousBuilds() {
|
|
||||||
// Check for other instances of this particular build, cancel any that are older than the current one
|
|
||||||
def jobName = env.JOB_NAME
|
|
||||||
def currentBuildNumber = env.BUILD_NUMBER.toInteger()
|
|
||||||
def currentJob = Jenkins.instance.getItemByFullName(jobName)
|
|
||||||
|
|
||||||
// Loop through all instances of this particular job/branch
|
|
||||||
for (def build : currentJob.builds) {
|
|
||||||
if (build.isBuilding() && (build.number.toInteger() < currentBuildNumber)) {
|
|
||||||
echo "Older build still queued. Sending kill signal to build number: ${build.number}"
|
|
||||||
build.doStop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def installAzureCli(distro, arch) {
|
|
||||||
sh 'sudo apt install -y ca-certificates curl apt-transport-https lsb-release gnupg'
|
|
||||||
sh 'curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null'
|
|
||||||
sh "echo \"deb [arch=${arch}] https://packages.microsoft.com/repos/azure-cli/ ${distro} main\" | sudo tee /etc/apt/sources.list.d/azure-cli.list"
|
|
||||||
sh 'sudo apt update'
|
|
||||||
sh 'sudo apt install -y azure-cli'
|
|
||||||
}
|
|
||||||
|
|
||||||
def boolean skipWorkerBuild() {
|
|
||||||
if (env.CHANGE_TARGET == null) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sh(
|
|
||||||
returnStatus: true,
|
|
||||||
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v '\\.md'"
|
|
||||||
) != 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sh(
|
|
||||||
returnStatus: true,
|
|
||||||
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v -E 'fuzz/'"
|
|
||||||
) != 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sh(
|
|
||||||
returnStatus: true,
|
|
||||||
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v -E '.github/'"
|
|
||||||
) != 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sh(
|
|
||||||
returnStatus: true,
|
|
||||||
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v '^\\.'"
|
|
||||||
) != 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sh(
|
|
||||||
returnStatus: true,
|
|
||||||
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v 'gitlint'"
|
|
||||||
) != 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
The documentation in this directory is covered by the following license:
|
All documentations (e.g. files with extension `.md`) in this repository is
|
||||||
|
covered by the following license:
|
||||||
|
|
||||||
Attribution 4.0 International
|
Attribution 4.0 International
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ do not wish to use the pre-built binaries.
|
|||||||
## Booting Linux
|
## Booting Linux
|
||||||
|
|
||||||
Cloud Hypervisor supports direct kernel boot (the x86-64 kernel requires the kernel
|
Cloud Hypervisor supports direct kernel boot (the x86-64 kernel requires the kernel
|
||||||
built with PVH support) or booting via a firmware (either [Rust Hypervisor
|
built with PVH support or a bzImage) or booting via a firmware (either [Rust Hypervisor
|
||||||
Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) or an
|
Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) or an
|
||||||
edk2 UEFI firmware called `CLOUDHV` / `CLOUDHV_EFI`.)
|
edk2 UEFI firmware called `CLOUDHV` / `CLOUDHV_EFI`.)
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ $ ./cloud-hypervisor \
|
|||||||
|
|
||||||
#### Building your Kernel
|
#### Building your Kernel
|
||||||
|
|
||||||
Cloud Hypervisor also supports direct kernel boot. For x86-64, a `vmlinux` ELF kernel (compiled with PVH support) is needed. In order to support development there is a custom branch; however provided the required options are enabled any recent kernel will suffice.
|
Cloud Hypervisor also supports direct kernel boot. For x86-64, a `vmlinux` ELF kernel (compiled with PVH support) or a regular bzImage are supported. In order to support development there is a custom branch; however provided the required options are enabled any recent kernel will suffice.
|
||||||
|
|
||||||
To build the kernel:
|
To build the kernel:
|
||||||
|
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
vmm-sys-util = "0.11.0"
|
vmm-sys-util = "0.12.1"
|
||||||
|
|||||||
@@ -10,21 +10,19 @@ sev_snp = []
|
|||||||
tdx = []
|
tdx = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.81"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.5.0"
|
||||||
hypervisor = { path = "../hypervisor" }
|
hypervisor = { path = "../hypervisor" }
|
||||||
libc = "0.2.147"
|
libc = "0.2.153"
|
||||||
linux-loader = { version = "0.10.0", features = ["elf", "bzimage", "pe"] }
|
linux-loader = { version = "0.11.0", features = ["elf", "bzimage", "pe"] }
|
||||||
log = "0.4.20"
|
log = "0.4.21"
|
||||||
serde = { version = "1.0.168", features = ["rc", "derive"] }
|
serde = { version = "1.0.197", features = ["rc", "derive"] }
|
||||||
thiserror = "1.0.40"
|
thiserror = "1.0.58"
|
||||||
uuid = "1.3.4"
|
uuid = "1.8.0"
|
||||||
versionize = "0.1.10"
|
vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-bitmap"] }
|
||||||
versionize_derive = "0.1.4"
|
|
||||||
vm-memory = { version = "0.13.1", features = ["backend-mmap", "backend-bitmap"] }
|
|
||||||
vm-migration = { path = "../vm-migration" }
|
vm-migration = { path = "../vm-migration" }
|
||||||
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
|
vmm-sys-util = { version = "0.12.1", features = ["with-serde"] }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||||
fdt_parser = { version = "0.1.4", package = "fdt" }
|
fdt_parser = { version = "0.1.5", package = "fdt" }
|
||||||
vm-fdt = { git = "https://github.com/rust-vmm/vm-fdt", branch = "main" }
|
vm-fdt = { git = "https://github.com/rust-vmm/vm-fdt", branch = "main" }
|
||||||
|
|||||||
@@ -111,8 +111,9 @@ pub const RAM_64BIT_START: GuestAddress = GuestAddress(0x1_0000_0000);
|
|||||||
pub const CMDLINE_MAX_SIZE: usize = 2048;
|
pub const CMDLINE_MAX_SIZE: usize = 2048;
|
||||||
|
|
||||||
/// FDT is at the beginning of RAM.
|
/// FDT is at the beginning of RAM.
|
||||||
/// Maximum size of the device tree blob as specified in https://www.kernel.org/doc/Documentation/arm64/booting.txt.
|
|
||||||
pub const FDT_START: GuestAddress = RAM_START;
|
pub const FDT_START: GuestAddress = RAM_START;
|
||||||
|
/// Maximum size of the device tree blob as specified in [the kernel
|
||||||
|
/// documentation](https://www.kernel.org/doc/Documentation/arm64/booting.txt).
|
||||||
pub const FDT_MAX_SIZE: u64 = 0x20_0000;
|
pub const FDT_MAX_SIZE: u64 = 0x20_0000;
|
||||||
|
|
||||||
/// Put ACPI table above dtb
|
/// Put ACPI table above dtb
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ use crate::{DeviceType, GuestMemoryMmap, NumaNodes, PciSpaceInfo, RegionType};
|
|||||||
use hypervisor::arch::aarch64::gic::Vgic;
|
use hypervisor::arch::aarch64::gic::Vgic;
|
||||||
use log::{log_enabled, Level};
|
use log::{log_enabled, Level};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic};
|
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic};
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
|
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
use std::os::fd::AsFd;
|
use std::os::fd::AsFd;
|
||||||
|
|||||||
@@ -18,9 +18,6 @@ use std::fmt;
|
|||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
|
|
||||||
use versionize_derive::Versionize;
|
|
||||||
use vm_migration::VersionMapped;
|
|
||||||
|
|
||||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<vm_memory::bitmap::AtomicBitmap>;
|
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<vm_memory::bitmap::AtomicBitmap>;
|
||||||
type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitmap>;
|
type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitmap>;
|
||||||
@@ -48,13 +45,17 @@ pub enum Error {
|
|||||||
ModlistSetup(#[source] vm_memory::GuestMemoryError),
|
ModlistSetup(#[source] vm_memory::GuestMemoryError),
|
||||||
#[error("RSDP extends past the end of guest memory")]
|
#[error("RSDP extends past the end of guest memory")]
|
||||||
RsdpPastRamEnd,
|
RsdpPastRamEnd,
|
||||||
|
#[error("Failed to setup Zero Page for bzImage")]
|
||||||
|
ZeroPageSetup(#[source] vm_memory::GuestMemoryError),
|
||||||
|
#[error("Zero Page for bzImage past RAM end")]
|
||||||
|
ZeroPagePastRamEnd,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type for returning public functions outcome.
|
/// Type for returning public functions outcome.
|
||||||
pub type Result<T> = result::Result<T, Error>;
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
/// Type for memory region types.
|
/// Type for memory region types.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize, Versionize)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||||
pub enum RegionType {
|
pub enum RegionType {
|
||||||
/// RAM type
|
/// RAM type
|
||||||
Ram,
|
Ram,
|
||||||
@@ -72,8 +73,6 @@ pub enum RegionType {
|
|||||||
Reserved,
|
Reserved,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VersionMapped for RegionType {}
|
|
||||||
|
|
||||||
/// Module for aarch64 related functionality.
|
/// Module for aarch64 related functionality.
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
pub mod aarch64;
|
pub mod aarch64;
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ use crate::InitramfsConfig;
|
|||||||
use crate::RegionType;
|
use crate::RegionType;
|
||||||
use hypervisor::arch::x86::{CpuIdEntry, CPUID_FLAG_VALID_INDEX};
|
use hypervisor::arch::x86::{CpuIdEntry, CPUID_FLAG_VALID_INDEX};
|
||||||
use hypervisor::{CpuVendor, HypervisorCpuError, HypervisorError};
|
use hypervisor::{CpuVendor, HypervisorCpuError, HypervisorError};
|
||||||
use linux_loader::loader::bootparam::boot_params;
|
use linux_loader::loader::bootparam::{boot_params, setup_header};
|
||||||
use linux_loader::loader::elf::start_info::{
|
use linux_loader::loader::elf::start_info::{
|
||||||
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
|
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
|
||||||
};
|
};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use vm_memory::{
|
use vm_memory::{
|
||||||
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
||||||
GuestMemoryRegion, GuestUsize,
|
GuestMemoryRegion, GuestUsize,
|
||||||
};
|
};
|
||||||
mod smbios;
|
mod smbios;
|
||||||
@@ -64,6 +64,8 @@ pub const _NSIG: i32 = 65;
|
|||||||
pub struct EntryPoint {
|
pub struct EntryPoint {
|
||||||
/// Address in guest memory where the guest must start execution
|
/// Address in guest memory where the guest must start execution
|
||||||
pub entry_addr: GuestAddress,
|
pub entry_addr: GuestAddress,
|
||||||
|
/// This field is used for bzImage to fill the zero page
|
||||||
|
pub setup_header: Option<setup_header>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const E820_RAM: u32 = 1;
|
const E820_RAM: u32 = 1;
|
||||||
@@ -116,38 +118,6 @@ impl SgxEpcRegion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a workaround to the Rust enforcement specifying that any implementation of a foreign
|
|
||||||
// trait (in this case `DataInit`) where:
|
|
||||||
// * the type that is implementing the trait is foreign or
|
|
||||||
// * all of the parameters being passed to the trait (if there are any) are also foreign
|
|
||||||
// is prohibited.
|
|
||||||
#[derive(Copy, Clone, Default)]
|
|
||||||
struct StartInfoWrapper(hvm_start_info);
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default)]
|
|
||||||
struct MemmapTableEntryWrapper(hvm_memmap_table_entry);
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default)]
|
|
||||||
struct ModlistEntryWrapper(hvm_modlist_entry);
|
|
||||||
|
|
||||||
// SAFETY: data structure only contain a series of integers
|
|
||||||
unsafe impl ByteValued for StartInfoWrapper {}
|
|
||||||
// SAFETY: data structure only contain a series of integers
|
|
||||||
unsafe impl ByteValued for MemmapTableEntryWrapper {}
|
|
||||||
// SAFETY: data structure only contain a series of integers
|
|
||||||
unsafe impl ByteValued for ModlistEntryWrapper {}
|
|
||||||
|
|
||||||
// This is a workaround to the Rust enforcement specifying that any implementation of a foreign
|
|
||||||
// trait (in this case `DataInit`) where:
|
|
||||||
// * the type that is implementing the trait is foreign or
|
|
||||||
// * all of the parameters being passed to the trait (if there are any) are also foreign
|
|
||||||
// is prohibited.
|
|
||||||
#[derive(Copy, Clone, Default)]
|
|
||||||
struct BootParamsWrapper(boot_params);
|
|
||||||
|
|
||||||
// SAFETY: BootParamsWrap is a wrapper over `boot_params` (a series of ints).
|
|
||||||
unsafe impl ByteValued for BootParamsWrapper {}
|
|
||||||
|
|
||||||
pub struct CpuidConfig {
|
pub struct CpuidConfig {
|
||||||
pub sgx_epc_sections: Option<Vec<SgxEpcSection>>,
|
pub sgx_epc_sections: Option<Vec<SgxEpcSection>>,
|
||||||
pub phys_bits: u8,
|
pub phys_bits: u8,
|
||||||
@@ -213,6 +183,9 @@ pub enum Error {
|
|||||||
/// Error retrieving TDX capabilities through the hypervisor (kvm/mshv) API
|
/// Error retrieving TDX capabilities through the hypervisor (kvm/mshv) API
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
TdxCapabilities(HypervisorError),
|
TdxCapabilities(HypervisorError),
|
||||||
|
|
||||||
|
/// Failed to configure E820 map for bzImage
|
||||||
|
E820Configuration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for super::Error {
|
impl From<Error> for super::Error {
|
||||||
@@ -221,6 +194,26 @@ impl From<Error> for super::Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_x2apic_id(cpu_id: u32, topology: Option<(u8, u8, u8)>) -> u32 {
|
||||||
|
if let Some(t) = topology {
|
||||||
|
let thread_mask_width = u8::BITS - (t.0 - 1).leading_zeros();
|
||||||
|
let core_mask_width = u8::BITS - (t.1 - 1).leading_zeros();
|
||||||
|
let die_mask_width = u8::BITS - (t.2 - 1).leading_zeros();
|
||||||
|
|
||||||
|
let thread_id = cpu_id % (t.0 as u32);
|
||||||
|
let core_id = cpu_id / (t.0 as u32) % (t.1 as u32);
|
||||||
|
let die_id = cpu_id / ((t.0 * t.1) as u32) % (t.2 as u32);
|
||||||
|
let socket_id = cpu_id / ((t.0 * t.1 * t.2) as u32);
|
||||||
|
|
||||||
|
return thread_id
|
||||||
|
| (core_id << thread_mask_width)
|
||||||
|
| (die_id << (thread_mask_width + core_mask_width))
|
||||||
|
| (socket_id << (thread_mask_width + core_mask_width + die_mask_width));
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_id
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum CpuidReg {
|
pub enum CpuidReg {
|
||||||
EAX,
|
EAX,
|
||||||
@@ -240,6 +233,26 @@ pub struct CpuidPatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CpuidPatch {
|
impl CpuidPatch {
|
||||||
|
pub fn get_cpuid_reg(
|
||||||
|
cpuid: &[CpuIdEntry],
|
||||||
|
function: u32,
|
||||||
|
index: Option<u32>,
|
||||||
|
reg: CpuidReg,
|
||||||
|
) -> Option<u32> {
|
||||||
|
for entry in cpuid.iter() {
|
||||||
|
if entry.function == function && (index.is_none() || index.unwrap() == entry.index) {
|
||||||
|
return match reg {
|
||||||
|
CpuidReg::EAX => Some(entry.eax),
|
||||||
|
CpuidReg::EBX => Some(entry.ebx),
|
||||||
|
CpuidReg::ECX => Some(entry.ecx),
|
||||||
|
CpuidReg::EDX => Some(entry.edx),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_cpuid_reg(
|
pub fn set_cpuid_reg(
|
||||||
cpuid: &mut Vec<CpuIdEntry>,
|
cpuid: &mut Vec<CpuIdEntry>,
|
||||||
function: u32,
|
function: u32,
|
||||||
@@ -777,31 +790,27 @@ pub fn configure_vcpu(
|
|||||||
cpu_vendor: CpuVendor,
|
cpu_vendor: CpuVendor,
|
||||||
topology: Option<(u8, u8, u8)>,
|
topology: Option<(u8, u8, u8)>,
|
||||||
) -> super::Result<()> {
|
) -> super::Result<()> {
|
||||||
|
let x2apic_id = get_x2apic_id(id as u32, topology);
|
||||||
|
|
||||||
// Per vCPU CPUID changes; common are handled via generate_common_cpuid()
|
// Per vCPU CPUID changes; common are handled via generate_common_cpuid()
|
||||||
let mut cpuid = cpuid;
|
let mut cpuid = cpuid;
|
||||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
|
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, x2apic_id);
|
||||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
|
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, x2apic_id);
|
||||||
if matches!(cpu_vendor, CpuVendor::AMD) {
|
if matches!(cpu_vendor, CpuVendor::AMD) {
|
||||||
CpuidPatch::set_cpuid_reg(
|
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x8000_001e, Some(0), CpuidReg::EAX, x2apic_id);
|
||||||
&mut cpuid,
|
|
||||||
0x8000_001e,
|
|
||||||
Some(0),
|
|
||||||
CpuidReg::EAX,
|
|
||||||
u32::from(id),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(t) = topology {
|
|
||||||
update_cpuid_topology(&mut cpuid, t.0, t.1, t.2, cpu_vendor, id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set ApicId in cpuid for each vcpu
|
// Set ApicId in cpuid for each vcpu
|
||||||
// SAFETY: get host cpuid when eax=1
|
// SAFETY: get host cpuid when eax=1
|
||||||
let mut cpu_ebx = unsafe { core::arch::x86_64::__cpuid(1) }.ebx;
|
let mut cpu_ebx = unsafe { core::arch::x86_64::__cpuid(1) }.ebx;
|
||||||
cpu_ebx &= 0xffffff;
|
cpu_ebx &= 0xffffff;
|
||||||
cpu_ebx |= (id as u32) << 24;
|
cpu_ebx |= x2apic_id << 24;
|
||||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
|
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
|
||||||
|
|
||||||
|
if let Some(t) = topology {
|
||||||
|
update_cpuid_topology(&mut cpuid, t.0, t.1, t.2, cpu_vendor, id);
|
||||||
|
}
|
||||||
|
|
||||||
// The TSC frequency CPUID leaf should not be included when running with HyperV emulation
|
// The TSC frequency CPUID leaf should not be included when running with HyperV emulation
|
||||||
if !kvm_hyperv {
|
if !kvm_hyperv {
|
||||||
if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? {
|
if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? {
|
||||||
@@ -839,8 +848,7 @@ pub fn configure_vcpu(
|
|||||||
|
|
||||||
regs::setup_msrs(vcpu).map_err(Error::MsrsConfiguration)?;
|
regs::setup_msrs(vcpu).map_err(Error::MsrsConfiguration)?;
|
||||||
if let Some((kernel_entry_point, guest_memory)) = boot_setup {
|
if let Some((kernel_entry_point, guest_memory)) = boot_setup {
|
||||||
regs::setup_regs(vcpu, kernel_entry_point.entry_addr.raw_value())
|
regs::setup_regs(vcpu, kernel_entry_point).map_err(Error::RegsConfiguration)?;
|
||||||
.map_err(Error::RegsConfiguration)?;
|
|
||||||
regs::setup_fpu(vcpu).map_err(Error::FpuConfiguration)?;
|
regs::setup_fpu(vcpu).map_err(Error::FpuConfiguration)?;
|
||||||
regs::setup_sregs(&guest_memory.memory(), vcpu).map_err(Error::SregsConfiguration)?;
|
regs::setup_sregs(&guest_memory.memory(), vcpu).map_err(Error::SregsConfiguration)?;
|
||||||
}
|
}
|
||||||
@@ -889,13 +897,16 @@ pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
|
|||||||
pub fn configure_system(
|
pub fn configure_system(
|
||||||
guest_mem: &GuestMemoryMmap,
|
guest_mem: &GuestMemoryMmap,
|
||||||
cmdline_addr: GuestAddress,
|
cmdline_addr: GuestAddress,
|
||||||
|
cmdline_size: usize,
|
||||||
initramfs: &Option<InitramfsConfig>,
|
initramfs: &Option<InitramfsConfig>,
|
||||||
_num_cpus: u8,
|
_num_cpus: u8,
|
||||||
|
setup_header: Option<setup_header>,
|
||||||
rsdp_addr: Option<GuestAddress>,
|
rsdp_addr: Option<GuestAddress>,
|
||||||
sgx_epc_region: Option<SgxEpcRegion>,
|
sgx_epc_region: Option<SgxEpcRegion>,
|
||||||
serial_number: Option<&str>,
|
serial_number: Option<&str>,
|
||||||
uuid: Option<&str>,
|
uuid: Option<&str>,
|
||||||
oem_strings: Option<&[&str]>,
|
oem_strings: Option<&[&str]>,
|
||||||
|
topology: Option<(u8, u8, u8)>,
|
||||||
) -> super::Result<()> {
|
) -> super::Result<()> {
|
||||||
// Write EBDA address to location where ACPICA expects to find it
|
// Write EBDA address to location where ACPICA expects to find it
|
||||||
guest_mem
|
guest_mem
|
||||||
@@ -908,7 +919,7 @@ pub fn configure_system(
|
|||||||
// Place the MP table after the SMIOS table aligned to 16 bytes
|
// Place the MP table after the SMIOS table aligned to 16 bytes
|
||||||
let offset = GuestAddress(layout::SMBIOS_START).unchecked_add(size);
|
let offset = GuestAddress(layout::SMBIOS_START).unchecked_add(size);
|
||||||
let offset = GuestAddress((offset.0 + 16) & !0xf);
|
let offset = GuestAddress((offset.0 + 16) & !0xf);
|
||||||
mptable::setup_mptable(offset, guest_mem, _num_cpus).map_err(Error::MpTableSetup)?;
|
mptable::setup_mptable(offset, guest_mem, _num_cpus, topology).map_err(Error::MpTableSetup)?;
|
||||||
|
|
||||||
// Check that the RAM is not smaller than the RSDP start address
|
// Check that the RAM is not smaller than the RSDP start address
|
||||||
if let Some(rsdp_addr) = rsdp_addr {
|
if let Some(rsdp_addr) = rsdp_addr {
|
||||||
@@ -917,25 +928,31 @@ pub fn configure_system(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configure_pvh(
|
match setup_header {
|
||||||
guest_mem,
|
Some(hdr) => configure_32bit_entry(
|
||||||
cmdline_addr,
|
guest_mem,
|
||||||
initramfs,
|
cmdline_addr,
|
||||||
rsdp_addr,
|
cmdline_size,
|
||||||
sgx_epc_region,
|
initramfs,
|
||||||
)
|
hdr,
|
||||||
|
rsdp_addr,
|
||||||
|
sgx_epc_region,
|
||||||
|
),
|
||||||
|
None => configure_pvh(
|
||||||
|
guest_mem,
|
||||||
|
cmdline_addr,
|
||||||
|
initramfs,
|
||||||
|
rsdp_addr,
|
||||||
|
sgx_epc_region,
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type RamRange = (u64, u64);
|
type RamRange = (u64, u64);
|
||||||
|
|
||||||
/// Returns usable physical memory ranges for the guest
|
/// Returns usable physical memory ranges for the guest
|
||||||
/// These should be used to create e820_RAM memory maps
|
/// These should be used to create e820_RAM memory maps
|
||||||
///
|
pub fn generate_ram_ranges(guest_mem: &GuestMemoryMmap) -> super::Result<Vec<RamRange>> {
|
||||||
/// There are up to two usable physical memory ranges,
|
|
||||||
/// divided by the gap at the end of 32bit address space.
|
|
||||||
pub fn generate_ram_ranges(
|
|
||||||
guest_mem: &GuestMemoryMmap,
|
|
||||||
) -> super::Result<(RamRange, Option<RamRange>)> {
|
|
||||||
// Merge continuous memory regions into one region.
|
// Merge continuous memory regions into one region.
|
||||||
// Note: memory regions from "GuestMemory" are sorted and non-zero sized.
|
// Note: memory regions from "GuestMemory" are sorted and non-zero sized.
|
||||||
let ram_regions = {
|
let ram_regions = {
|
||||||
@@ -968,15 +985,11 @@ pub fn generate_ram_ranges(
|
|||||||
ram_regions
|
ram_regions
|
||||||
};
|
};
|
||||||
|
|
||||||
if ram_regions.len() > 2 {
|
// Create the memory map entry for memory region before the gap
|
||||||
error!(
|
let mut ram_ranges = vec![];
|
||||||
"There should be up to two usable physical memory ranges, devidided by the
|
|
||||||
gap at the end of 32bit address space (e.g. between 3G and 4G)."
|
|
||||||
);
|
|
||||||
return Err(super::Error::MemmapTableSetup);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate the first usable physical memory range before the gap
|
// Generate the first usable physical memory range before the gap. The e820 map
|
||||||
|
// should only report memory above 1MiB.
|
||||||
let first_ram_range = {
|
let first_ram_range = {
|
||||||
let (first_region_start, first_region_end) =
|
let (first_region_start, first_region_end) =
|
||||||
ram_regions.first().ok_or(super::Error::MemmapTableSetup)?;
|
ram_regions.first().ok_or(super::Error::MemmapTableSetup)?;
|
||||||
@@ -1003,33 +1016,19 @@ pub fn generate_ram_ranges(
|
|||||||
|
|
||||||
(high_ram_start, *first_region_end)
|
(high_ram_start, *first_region_end)
|
||||||
};
|
};
|
||||||
|
ram_ranges.push(first_ram_range);
|
||||||
|
|
||||||
// Generate the second usable physical memory range after the gap if any
|
// Generate additional usable physical memory range after the gap if any.
|
||||||
let second_ram_range = if let Some((second_region_start, second_region_end)) =
|
for ram_region in ram_regions.iter().skip(1) {
|
||||||
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!(
|
info!(
|
||||||
"Second usable physical memory range, start: 0x{:08x}, end: 0x{:08x}",
|
"found usable physical memory range, start: 0x{:08x}, end: 0x{:08x}",
|
||||||
ram_64bit_start, second_region_end
|
ram_region.0, ram_region.1
|
||||||
);
|
);
|
||||||
|
|
||||||
Some((ram_64bit_start, *second_region_end))
|
ram_ranges.push(*ram_region);
|
||||||
} else {
|
}
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((first_ram_range, second_ram_range))
|
Ok(ram_ranges)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_pvh(
|
fn configure_pvh(
|
||||||
@@ -1041,29 +1040,30 @@ fn configure_pvh(
|
|||||||
) -> super::Result<()> {
|
) -> super::Result<()> {
|
||||||
const XEN_HVM_START_MAGIC_VALUE: u32 = 0x336ec578;
|
const XEN_HVM_START_MAGIC_VALUE: u32 = 0x336ec578;
|
||||||
|
|
||||||
let mut start_info: StartInfoWrapper = StartInfoWrapper(hvm_start_info::default());
|
let mut start_info = hvm_start_info {
|
||||||
|
magic: XEN_HVM_START_MAGIC_VALUE,
|
||||||
start_info.0.magic = XEN_HVM_START_MAGIC_VALUE;
|
version: 1, // pvh has version 1
|
||||||
start_info.0.version = 1; // pvh has version 1
|
nr_modules: 0,
|
||||||
start_info.0.nr_modules = 0;
|
cmdline_paddr: cmdline_addr.raw_value(),
|
||||||
start_info.0.cmdline_paddr = cmdline_addr.raw_value();
|
memmap_paddr: layout::MEMMAP_START.raw_value(),
|
||||||
start_info.0.memmap_paddr = layout::MEMMAP_START.raw_value();
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(rsdp_addr) = rsdp_addr {
|
if let Some(rsdp_addr) = rsdp_addr {
|
||||||
start_info.0.rsdp_paddr = rsdp_addr.0;
|
start_info.rsdp_paddr = rsdp_addr.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(initramfs_config) = initramfs {
|
if let Some(initramfs_config) = initramfs {
|
||||||
// The initramfs has been written to guest memory already, here we just need to
|
// The initramfs has been written to guest memory already, here we just need to
|
||||||
// create the module structure that describes it.
|
// create the module structure that describes it.
|
||||||
let ramdisk_mod: ModlistEntryWrapper = ModlistEntryWrapper(hvm_modlist_entry {
|
let ramdisk_mod = hvm_modlist_entry {
|
||||||
paddr: initramfs_config.address.raw_value(),
|
paddr: initramfs_config.address.raw_value(),
|
||||||
size: initramfs_config.size as u64,
|
size: initramfs_config.size as u64,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
};
|
||||||
|
|
||||||
start_info.0.nr_modules += 1;
|
start_info.nr_modules += 1;
|
||||||
start_info.0.modlist_paddr = layout::MODLIST_START.raw_value();
|
start_info.modlist_paddr = layout::MODLIST_START.raw_value();
|
||||||
|
|
||||||
// Write the modlist struct to guest memory.
|
// Write the modlist struct to guest memory.
|
||||||
guest_mem
|
guest_mem
|
||||||
@@ -1079,30 +1079,18 @@ fn configure_pvh(
|
|||||||
add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM);
|
add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM);
|
||||||
|
|
||||||
// Get usable physical memory ranges
|
// Get usable physical memory ranges
|
||||||
let (first_ram_range, second_ram_range) = generate_ram_ranges(guest_mem)?;
|
let ram_ranges = generate_ram_ranges(guest_mem)?;
|
||||||
|
|
||||||
// Create e820 memory map entry before the gap
|
// Create e820 memory map entries
|
||||||
info!(
|
for ram_range in ram_ranges {
|
||||||
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}",
|
|
||||||
first_ram_range.0, first_ram_range.1
|
|
||||||
);
|
|
||||||
add_memmap_entry(
|
|
||||||
&mut memmap,
|
|
||||||
first_ram_range.0,
|
|
||||||
first_ram_range.1 - first_ram_range.0,
|
|
||||||
E820_RAM,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create e820 memory map after the gap if any
|
|
||||||
if let Some(second_ram_range) = second_ram_range {
|
|
||||||
info!(
|
info!(
|
||||||
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}",
|
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}",
|
||||||
second_ram_range.0, second_ram_range.1
|
ram_range.0, ram_range.1
|
||||||
);
|
);
|
||||||
add_memmap_entry(
|
add_memmap_entry(
|
||||||
&mut memmap,
|
&mut memmap,
|
||||||
second_ram_range.0,
|
ram_range.0,
|
||||||
second_ram_range.1 - second_ram_range.0,
|
ram_range.1 - ram_range.0,
|
||||||
E820_RAM,
|
E820_RAM,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1123,7 +1111,7 @@ fn configure_pvh(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
start_info.0.memmap_entries = memmap.len() as u32;
|
start_info.memmap_entries = memmap.len() as u32;
|
||||||
|
|
||||||
// Copy the vector with the memmap table to the MEMMAP_START address
|
// Copy the vector with the memmap table to the MEMMAP_START address
|
||||||
// which is already saved in the memmap_paddr field of hvm_start_info struct.
|
// which is already saved in the memmap_paddr field of hvm_start_info struct.
|
||||||
@@ -1132,17 +1120,14 @@ fn configure_pvh(
|
|||||||
guest_mem
|
guest_mem
|
||||||
.checked_offset(
|
.checked_offset(
|
||||||
memmap_start_addr,
|
memmap_start_addr,
|
||||||
mem::size_of::<hvm_memmap_table_entry>() * start_info.0.memmap_entries as usize,
|
mem::size_of::<hvm_memmap_table_entry>() * start_info.memmap_entries as usize,
|
||||||
)
|
)
|
||||||
.ok_or(super::Error::MemmapTablePastRamEnd)?;
|
.ok_or(super::Error::MemmapTablePastRamEnd)?;
|
||||||
|
|
||||||
// For every entry in the memmap vector, create a MemmapTableEntryWrapper
|
// For every entry in the memmap vector, write it to guest memory.
|
||||||
// and write it to guest memory.
|
|
||||||
for memmap_entry in memmap {
|
for memmap_entry in memmap {
|
||||||
let map_entry_wrapper: MemmapTableEntryWrapper = MemmapTableEntryWrapper(memmap_entry);
|
|
||||||
|
|
||||||
guest_mem
|
guest_mem
|
||||||
.write_obj(map_entry_wrapper, memmap_start_addr)
|
.write_obj(memmap_entry, memmap_start_addr)
|
||||||
.map_err(|_| super::Error::MemmapTableSetup)?;
|
.map_err(|_| super::Error::MemmapTableSetup)?;
|
||||||
memmap_start_addr =
|
memmap_start_addr =
|
||||||
memmap_start_addr.unchecked_add(mem::size_of::<hvm_memmap_table_entry>() as u64);
|
memmap_start_addr.unchecked_add(mem::size_of::<hvm_memmap_table_entry>() as u64);
|
||||||
@@ -1165,6 +1150,113 @@ fn configure_pvh(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn configure_32bit_entry(
|
||||||
|
guest_mem: &GuestMemoryMmap,
|
||||||
|
cmdline_addr: GuestAddress,
|
||||||
|
cmdline_size: usize,
|
||||||
|
initramfs: &Option<InitramfsConfig>,
|
||||||
|
setup_hdr: setup_header,
|
||||||
|
rsdp_addr: Option<GuestAddress>,
|
||||||
|
sgx_epc_region: Option<SgxEpcRegion>,
|
||||||
|
) -> super::Result<()> {
|
||||||
|
const KERNEL_LOADER_OTHER: u8 = 0xff;
|
||||||
|
|
||||||
|
// Use the provided setup header
|
||||||
|
let mut params = boot_params {
|
||||||
|
hdr: setup_hdr,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Common bootparams settings
|
||||||
|
if params.hdr.type_of_loader == 0 {
|
||||||
|
params.hdr.type_of_loader = KERNEL_LOADER_OTHER;
|
||||||
|
}
|
||||||
|
params.hdr.cmd_line_ptr = cmdline_addr.raw_value() as u32;
|
||||||
|
params.hdr.cmdline_size = cmdline_size as u32;
|
||||||
|
|
||||||
|
if let Some(initramfs_config) = initramfs {
|
||||||
|
params.hdr.ramdisk_image = initramfs_config.address.raw_value() as u32;
|
||||||
|
params.hdr.ramdisk_size = initramfs_config.size as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_e820_entry(&mut params, 0, layout::EBDA_START.raw_value(), E820_RAM)?;
|
||||||
|
|
||||||
|
let mem_end = guest_mem.last_addr();
|
||||||
|
if mem_end < layout::MEM_32BIT_RESERVED_START {
|
||||||
|
add_e820_entry(
|
||||||
|
&mut params,
|
||||||
|
layout::HIGH_RAM_START.raw_value(),
|
||||||
|
mem_end.unchecked_offset_from(layout::HIGH_RAM_START) + 1,
|
||||||
|
E820_RAM,
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
add_e820_entry(
|
||||||
|
&mut params,
|
||||||
|
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_e820_entry(
|
||||||
|
&mut params,
|
||||||
|
layout::RAM_64BIT_START.raw_value(),
|
||||||
|
mem_end.unchecked_offset_from(layout::RAM_64BIT_START) + 1,
|
||||||
|
E820_RAM,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_e820_entry(
|
||||||
|
&mut params,
|
||||||
|
layout::PCI_MMCONFIG_START.0,
|
||||||
|
layout::PCI_MMCONFIG_SIZE,
|
||||||
|
E820_RESERVED,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if let Some(sgx_epc_region) = sgx_epc_region {
|
||||||
|
add_e820_entry(
|
||||||
|
&mut params,
|
||||||
|
sgx_epc_region.start().raw_value(),
|
||||||
|
sgx_epc_region.size(),
|
||||||
|
E820_RESERVED,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rsdp_addr) = rsdp_addr {
|
||||||
|
params.acpi_rsdp_addr = rsdp_addr.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let zero_page_addr = layout::ZERO_PAGE_START;
|
||||||
|
guest_mem
|
||||||
|
.checked_offset(zero_page_addr, mem::size_of::<boot_params>())
|
||||||
|
.ok_or(super::Error::ZeroPagePastRamEnd)?;
|
||||||
|
guest_mem
|
||||||
|
.write_obj(params, zero_page_addr)
|
||||||
|
.map_err(super::Error::ZeroPageSetup)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add an e820 region to the e820 map.
|
||||||
|
/// Returns Ok(()) if successful, or an error if there is no space left in the map.
|
||||||
|
fn add_e820_entry(
|
||||||
|
params: &mut boot_params,
|
||||||
|
addr: u64,
|
||||||
|
size: u64,
|
||||||
|
mem_type: u32,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if params.e820_entries >= params.e820_table.len() as u8 {
|
||||||
|
return Err(Error::E820Configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
params.e820_table[params.e820_entries as usize].addr = addr;
|
||||||
|
params.e820_table[params.e820_entries as usize].size = size;
|
||||||
|
params.e820_table[params.e820_entries as usize].type_ = mem_type;
|
||||||
|
params.e820_entries += 1;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn add_memmap_entry(memmap: &mut Vec<hvm_memmap_table_entry>, addr: u64, size: u64, mem_type: u32) {
|
fn add_memmap_entry(memmap: &mut Vec<hvm_memmap_table_entry>, addr: u64, size: u64, mem_type: u32) {
|
||||||
// Add the table entry to the vector
|
// Add the table entry to the vector
|
||||||
memmap.push(hvm_memmap_table_entry {
|
memmap.push(hvm_memmap_table_entry {
|
||||||
@@ -1228,10 +1320,24 @@ fn update_cpuid_topology(
|
|||||||
cpu_vendor: CpuVendor,
|
cpu_vendor: CpuVendor,
|
||||||
id: u8,
|
id: u8,
|
||||||
) {
|
) {
|
||||||
|
let x2apic_id = get_x2apic_id(
|
||||||
|
id as u32,
|
||||||
|
Some((threads_per_core, cores_per_die, dies_per_package)),
|
||||||
|
);
|
||||||
|
|
||||||
let thread_width = 8 - (threads_per_core - 1).leading_zeros();
|
let thread_width = 8 - (threads_per_core - 1).leading_zeros();
|
||||||
let core_width = (8 - (cores_per_die - 1).leading_zeros()) + thread_width;
|
let core_width = (8 - (cores_per_die - 1).leading_zeros()) + thread_width;
|
||||||
let die_width = (8 - (dies_per_package - 1).leading_zeros()) + core_width;
|
let die_width = (8 - (dies_per_package - 1).leading_zeros()) + core_width;
|
||||||
|
|
||||||
|
let mut cpu_ebx = CpuidPatch::get_cpuid_reg(cpuid, 0x1, None, CpuidReg::EBX).unwrap_or(0);
|
||||||
|
cpu_ebx |= ((dies_per_package as u32) * (cores_per_die as u32) * (threads_per_core as u32))
|
||||||
|
& 0xff << 16;
|
||||||
|
CpuidPatch::set_cpuid_reg(cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
|
||||||
|
|
||||||
|
let mut cpu_edx = CpuidPatch::get_cpuid_reg(cpuid, 0x1, None, CpuidReg::EDX).unwrap_or(0);
|
||||||
|
cpu_edx |= 1 << 28;
|
||||||
|
CpuidPatch::set_cpuid_reg(cpuid, 0x1, None, CpuidReg::EDX, cpu_edx);
|
||||||
|
|
||||||
// CPU Topology leaf 0xb
|
// CPU Topology leaf 0xb
|
||||||
CpuidPatch::set_cpuid_reg(cpuid, 0xb, Some(0), CpuidReg::EAX, thread_width);
|
CpuidPatch::set_cpuid_reg(cpuid, 0xb, Some(0), CpuidReg::EAX, thread_width);
|
||||||
CpuidPatch::set_cpuid_reg(
|
CpuidPatch::set_cpuid_reg(
|
||||||
@@ -1290,7 +1396,7 @@ fn update_cpuid_topology(
|
|||||||
0x8000_001e,
|
0x8000_001e,
|
||||||
Some(0),
|
Some(0),
|
||||||
CpuidReg::EBX,
|
CpuidReg::EBX,
|
||||||
((threads_per_core as u32 - 1) << 8) | (id as u32 & 0xff),
|
((threads_per_core as u32 - 1) << 8) | (x2apic_id & 0xff),
|
||||||
);
|
);
|
||||||
CpuidPatch::set_cpuid_reg(
|
CpuidPatch::set_cpuid_reg(
|
||||||
cpuid,
|
cpuid,
|
||||||
@@ -1301,21 +1407,21 @@ fn update_cpuid_topology(
|
|||||||
);
|
);
|
||||||
CpuidPatch::set_cpuid_reg(cpuid, 0x8000_001e, Some(0), CpuidReg::EDX, 0);
|
CpuidPatch::set_cpuid_reg(cpuid, 0x8000_001e, Some(0), CpuidReg::EDX, 0);
|
||||||
if cores_per_die * threads_per_core > 1 {
|
if cores_per_die * threads_per_core > 1 {
|
||||||
|
let ecx =
|
||||||
|
CpuidPatch::get_cpuid_reg(cpuid, 0x8000_0001, Some(0), CpuidReg::ECX).unwrap_or(0);
|
||||||
CpuidPatch::set_cpuid_reg(
|
CpuidPatch::set_cpuid_reg(
|
||||||
cpuid,
|
cpuid,
|
||||||
0x8000_0001,
|
0x8000_0001,
|
||||||
Some(0),
|
Some(0),
|
||||||
CpuidReg::ECX,
|
CpuidReg::ECX,
|
||||||
(1u32 << 1) | (1u32 << 22),
|
ecx | (1u32 << 1) | (1u32 << 22),
|
||||||
);
|
);
|
||||||
CpuidPatch::set_cpuid_reg(
|
CpuidPatch::set_cpuid_reg(
|
||||||
cpuid,
|
cpuid,
|
||||||
0x0000_0001,
|
0x0000_0001,
|
||||||
Some(0),
|
Some(0),
|
||||||
CpuidReg::EBX,
|
CpuidReg::EBX,
|
||||||
((id as u32) << 24)
|
(x2apic_id << 24) | (8 << 8) | (((cores_per_die * threads_per_core) as u32) << 16),
|
||||||
| (8 << 8)
|
|
||||||
| (((cores_per_die * threads_per_core) as u32) << 16),
|
|
||||||
);
|
);
|
||||||
let cpuid_patches = vec![
|
let cpuid_patches = vec![
|
||||||
// Patch tsc deadline timer bit
|
// Patch tsc deadline timer bit
|
||||||
@@ -1348,7 +1454,7 @@ fn update_cpuid_topology(
|
|||||||
// sections exposed to the guest.
|
// sections exposed to the guest.
|
||||||
fn update_cpuid_sgx(
|
fn update_cpuid_sgx(
|
||||||
cpuid: &mut Vec<CpuIdEntry>,
|
cpuid: &mut Vec<CpuIdEntry>,
|
||||||
epc_sections: &Vec<SgxEpcSection>,
|
epc_sections: &[SgxEpcSection],
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Something's wrong if there's no EPC section.
|
// Something's wrong if there's no EPC section.
|
||||||
if epc_sections.is_empty() {
|
if epc_sections.is_empty() {
|
||||||
@@ -1397,6 +1503,7 @@ fn update_cpuid_sgx(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use linux_loader::loader::bootparam::boot_e820_entry;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn regions_base_addr() {
|
fn regions_base_addr() {
|
||||||
@@ -1413,13 +1520,16 @@ mod tests {
|
|||||||
let config_err = configure_system(
|
let config_err = configure_system(
|
||||||
&gm,
|
&gm,
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
|
0,
|
||||||
&None,
|
&None,
|
||||||
1,
|
1,
|
||||||
|
None,
|
||||||
Some(layout::RSDP_POINTER),
|
Some(layout::RSDP_POINTER),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
assert!(config_err.is_err());
|
assert!(config_err.is_err());
|
||||||
|
|
||||||
@@ -1435,6 +1545,7 @@ mod tests {
|
|||||||
configure_system(
|
configure_system(
|
||||||
&gm,
|
&gm,
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
|
0,
|
||||||
&None,
|
&None,
|
||||||
no_vcpus,
|
no_vcpus,
|
||||||
None,
|
None,
|
||||||
@@ -1442,6 +1553,8 @@ mod tests {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -1462,6 +1575,7 @@ mod tests {
|
|||||||
configure_system(
|
configure_system(
|
||||||
&gm,
|
&gm,
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
|
0,
|
||||||
&None,
|
&None,
|
||||||
no_vcpus,
|
no_vcpus,
|
||||||
None,
|
None,
|
||||||
@@ -1469,12 +1583,15 @@ mod tests {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
configure_system(
|
configure_system(
|
||||||
&gm,
|
&gm,
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
|
0,
|
||||||
&None,
|
&None,
|
||||||
no_vcpus,
|
no_vcpus,
|
||||||
None,
|
None,
|
||||||
@@ -1482,10 +1599,52 @@ mod tests {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add_e820_entry() {
|
||||||
|
let e820_table = [(boot_e820_entry {
|
||||||
|
addr: 0x1,
|
||||||
|
size: 4,
|
||||||
|
type_: 1,
|
||||||
|
}); 128];
|
||||||
|
|
||||||
|
let expected_params = boot_params {
|
||||||
|
e820_table,
|
||||||
|
e820_entries: 1,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut params: boot_params = Default::default();
|
||||||
|
add_e820_entry(
|
||||||
|
&mut params,
|
||||||
|
e820_table[0].addr,
|
||||||
|
e820_table[0].size,
|
||||||
|
e820_table[0].type_,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
format!("{:?}", params.e820_table[0]),
|
||||||
|
format!("{:?}", expected_params.e820_table[0])
|
||||||
|
);
|
||||||
|
assert_eq!(params.e820_entries, expected_params.e820_entries);
|
||||||
|
|
||||||
|
// Exercise the scenario where the field storing the length of the e820 entry table is
|
||||||
|
// is bigger than the allocated memory.
|
||||||
|
params.e820_entries = params.e820_table.len() as u8 + 1;
|
||||||
|
assert!(add_e820_entry(
|
||||||
|
&mut params,
|
||||||
|
e820_table[0].addr,
|
||||||
|
e820_table[0].size,
|
||||||
|
e820_table[0].type_
|
||||||
|
)
|
||||||
|
.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_memmap_entry() {
|
fn test_add_memmap_entry() {
|
||||||
let mut memmap: Vec<hvm_memmap_table_entry> = Vec::new();
|
let mut memmap: Vec<hvm_memmap_table_entry> = Vec::new();
|
||||||
@@ -1510,4 +1669,25 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(format!("{memmap:?}"), format!("{expected_memmap:?}"));
|
assert_eq!(format!("{memmap:?}"), format!("{expected_memmap:?}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_x2apic_id() {
|
||||||
|
let x2apic_id = get_x2apic_id(0, Some((2, 3, 1)));
|
||||||
|
assert_eq!(x2apic_id, 0);
|
||||||
|
|
||||||
|
let x2apic_id = get_x2apic_id(1, Some((2, 3, 1)));
|
||||||
|
assert_eq!(x2apic_id, 1);
|
||||||
|
|
||||||
|
let x2apic_id = get_x2apic_id(2, Some((2, 3, 1)));
|
||||||
|
assert_eq!(x2apic_id, 2);
|
||||||
|
|
||||||
|
let x2apic_id = get_x2apic_id(6, Some((2, 3, 1)));
|
||||||
|
assert_eq!(x2apic_id, 8);
|
||||||
|
|
||||||
|
let x2apic_id = get_x2apic_id(7, Some((2, 3, 1)));
|
||||||
|
assert_eq!(x2apic_id, 9);
|
||||||
|
|
||||||
|
let x2apic_id = get_x2apic_id(8, Some((2, 3, 1)));
|
||||||
|
assert_eq!(x2apic_id, 10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
use crate::layout::{APIC_START, HIGH_RAM_START, IOAPIC_START};
|
use crate::layout::{APIC_START, HIGH_RAM_START, IOAPIC_START};
|
||||||
use crate::x86_64::mpspec;
|
use crate::x86_64::{get_x2apic_id, mpspec};
|
||||||
use crate::GuestMemoryMmap;
|
use crate::GuestMemoryMmap;
|
||||||
use libc::c_char;
|
use libc::c_char;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@@ -125,9 +125,18 @@ fn compute_mp_size(num_cpus: u8) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Performs setup of the MP table for the given `num_cpus`.
|
/// Performs setup of the MP table for the given `num_cpus`.
|
||||||
pub fn setup_mptable(offset: GuestAddress, mem: &GuestMemoryMmap, num_cpus: u8) -> Result<()> {
|
pub fn setup_mptable(
|
||||||
if num_cpus as u32 > MAX_SUPPORTED_CPUS {
|
offset: GuestAddress,
|
||||||
return Err(Error::TooManyCpus);
|
mem: &GuestMemoryMmap,
|
||||||
|
num_cpus: u8,
|
||||||
|
topology: Option<(u8, u8, u8)>,
|
||||||
|
) -> Result<()> {
|
||||||
|
if num_cpus > 0 {
|
||||||
|
let cpu_id_max = num_cpus - 1;
|
||||||
|
let x2apic_id_max = get_x2apic_id(cpu_id_max.into(), topology);
|
||||||
|
if x2apic_id_max >= MAX_SUPPORTED_CPUS {
|
||||||
|
return Err(Error::TooManyCpus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to keep track of the next base pointer into the MP table.
|
// Used to keep track of the next base pointer into the MP table.
|
||||||
@@ -141,7 +150,7 @@ pub fn setup_mptable(offset: GuestAddress, mem: &GuestMemoryMmap, num_cpus: u8)
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut checksum: u8 = 0;
|
let mut checksum: u8 = 0;
|
||||||
let ioapicid: u8 = num_cpus + 1;
|
let ioapicid: u8 = MAX_SUPPORTED_CPUS as u8 + 1;
|
||||||
|
|
||||||
// The checked_add here ensures the all of the following base_mp.unchecked_add's will be without
|
// The checked_add here ensures the all of the following base_mp.unchecked_add's will be without
|
||||||
// overflow.
|
// overflow.
|
||||||
@@ -179,7 +188,7 @@ pub fn setup_mptable(offset: GuestAddress, mem: &GuestMemoryMmap, num_cpus: u8)
|
|||||||
for cpu_id in 0..num_cpus {
|
for cpu_id in 0..num_cpus {
|
||||||
let mut mpc_cpu = MpcCpuWrapper(mpspec::mpc_cpu::default());
|
let mut mpc_cpu = MpcCpuWrapper(mpspec::mpc_cpu::default());
|
||||||
mpc_cpu.0.type_ = mpspec::MP_PROCESSOR as u8;
|
mpc_cpu.0.type_ = mpspec::MP_PROCESSOR as u8;
|
||||||
mpc_cpu.0.apicid = cpu_id;
|
mpc_cpu.0.apicid = get_x2apic_id(cpu_id as u32, topology) as u8;
|
||||||
mpc_cpu.0.apicver = APIC_VERSION;
|
mpc_cpu.0.apicver = APIC_VERSION;
|
||||||
mpc_cpu.0.cpuflag = mpspec::CPU_ENABLED as u8
|
mpc_cpu.0.cpuflag = mpspec::CPU_ENABLED as u8
|
||||||
| if cpu_id == 0 {
|
| if cpu_id == 0 {
|
||||||
@@ -291,8 +300,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::layout::MPTABLE_START;
|
use crate::layout::MPTABLE_START;
|
||||||
use vm_memory::{
|
use vm_memory::{
|
||||||
bitmap::BitmapSlice, GuestAddress, GuestUsize, VolatileMemoryError, VolatileSlice,
|
bitmap::BitmapSlice, GuestUsize, VolatileMemoryError, VolatileSlice, WriteVolatile,
|
||||||
WriteVolatile,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn table_entry_size(type_: u8) -> usize {
|
fn table_entry_size(type_: u8) -> usize {
|
||||||
@@ -312,7 +320,7 @@ mod tests {
|
|||||||
let mem =
|
let mem =
|
||||||
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap();
|
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap();
|
||||||
|
|
||||||
setup_mptable(MPTABLE_START, &mem, num_cpus).unwrap();
|
setup_mptable(MPTABLE_START, &mem, num_cpus, None).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -321,7 +329,7 @@ mod tests {
|
|||||||
let mem = GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus) - 1)])
|
let mem = GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus) - 1)])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(setup_mptable(MPTABLE_START, &mem, num_cpus).is_err());
|
assert!(setup_mptable(MPTABLE_START, &mem, num_cpus, None).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -330,7 +338,7 @@ mod tests {
|
|||||||
let mem =
|
let mem =
|
||||||
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap();
|
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap();
|
||||||
|
|
||||||
setup_mptable(MPTABLE_START, &mem, num_cpus).unwrap();
|
setup_mptable(MPTABLE_START, &mem, num_cpus, None).unwrap();
|
||||||
|
|
||||||
let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap();
|
let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap();
|
||||||
|
|
||||||
@@ -346,7 +354,7 @@ mod tests {
|
|||||||
let mem =
|
let mem =
|
||||||
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap();
|
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap();
|
||||||
|
|
||||||
setup_mptable(MPTABLE_START, &mem, num_cpus).unwrap();
|
setup_mptable(MPTABLE_START, &mem, num_cpus, None).unwrap();
|
||||||
|
|
||||||
let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap();
|
let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap();
|
||||||
let mpc_offset = GuestAddress(mpf_intel.0.physptr as GuestUsize);
|
let mpc_offset = GuestAddress(mpf_intel.0.physptr as GuestUsize);
|
||||||
@@ -384,7 +392,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
for i in 0..MAX_SUPPORTED_CPUS as u8 {
|
for i in 0..MAX_SUPPORTED_CPUS as u8 {
|
||||||
setup_mptable(MPTABLE_START, &mem, i).unwrap();
|
setup_mptable(MPTABLE_START, &mem, i, None).unwrap();
|
||||||
|
|
||||||
let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap();
|
let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap();
|
||||||
let mpc_offset = GuestAddress(mpf_intel.0.physptr as GuestUsize);
|
let mpc_offset = GuestAddress(mpf_intel.0.physptr as GuestUsize);
|
||||||
@@ -417,7 +425,7 @@ mod tests {
|
|||||||
let mem =
|
let mem =
|
||||||
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(cpus as u8))]).unwrap();
|
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(cpus as u8))]).unwrap();
|
||||||
|
|
||||||
let result = setup_mptable(MPTABLE_START, &mem, cpus as u8);
|
let result = setup_mptable(MPTABLE_START, &mem, cpus as u8, None);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,10 @@
|
|||||||
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
use crate::layout::{BOOT_GDT_START, BOOT_IDT_START, PVH_INFO_START};
|
use crate::layout::{
|
||||||
use crate::GuestMemoryMmap;
|
BOOT_GDT_START, BOOT_IDT_START, BOOT_STACK_POINTER, PVH_INFO_START, ZERO_PAGE_START,
|
||||||
|
};
|
||||||
|
use crate::{EntryPoint, GuestMemoryMmap};
|
||||||
use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt};
|
use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt};
|
||||||
use hypervisor::arch::x86::regs::CR0_PE;
|
use hypervisor::arch::x86::regs::CR0_PE;
|
||||||
use hypervisor::arch::x86::{FpuState, SpecialRegisters, StandardRegisters};
|
use hypervisor::arch::x86::{FpuState, SpecialRegisters, StandardRegisters};
|
||||||
@@ -77,13 +79,22 @@ pub fn setup_msrs(vcpu: &Arc<dyn hypervisor::Vcpu>) -> Result<()> {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
|
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
|
||||||
/// * `boot_ip` - Starting instruction pointer.
|
/// * `entry_point` - Description of the boot entry to set up.
|
||||||
pub fn setup_regs(vcpu: &Arc<dyn hypervisor::Vcpu>, boot_ip: u64) -> Result<()> {
|
pub fn setup_regs(vcpu: &Arc<dyn hypervisor::Vcpu>, entry_point: EntryPoint) -> Result<()> {
|
||||||
let regs = StandardRegisters {
|
let regs = match entry_point.setup_header {
|
||||||
rflags: 0x0000000000000002u64,
|
None => StandardRegisters {
|
||||||
rbx: PVH_INFO_START.raw_value(),
|
rflags: 0x0000000000000002u64,
|
||||||
rip: boot_ip,
|
rip: entry_point.entry_addr.raw_value(),
|
||||||
..Default::default()
|
rbx: PVH_INFO_START.raw_value(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Some(_) => StandardRegisters {
|
||||||
|
rflags: 0x0000000000000002u64,
|
||||||
|
rip: entry_point.entry_addr.raw_value(),
|
||||||
|
rsp: BOOT_STACK_POINTER.raw_value(),
|
||||||
|
rsi: ZERO_PAGE_START.raw_value(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
};
|
};
|
||||||
vcpu.set_regs(®s).map_err(Error::SetBaseRegisters)
|
vcpu.set_regs(®s).map_err(Error::SetBaseRegisters)
|
||||||
}
|
}
|
||||||
@@ -164,7 +175,6 @@ pub fn configure_segments_and_sregs(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::GuestMemoryMmap;
|
|
||||||
use vm_memory::GuestAddress;
|
use vm_memory::GuestAddress;
|
||||||
|
|
||||||
fn create_guest_mem() -> GuestMemoryMmap {
|
fn create_guest_mem() -> GuestMemoryMmap {
|
||||||
|
|||||||
@@ -9,19 +9,18 @@ default = []
|
|||||||
io_uring = ["dep:io-uring"]
|
io_uring = ["dep:io-uring"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.5.0"
|
||||||
crc32c = "0.6.4"
|
crc-any = "2.4.4"
|
||||||
io-uring = { version = "0.6.2", optional = true }
|
io-uring = { version = "0.6.3", optional = true }
|
||||||
libc = "0.2.147"
|
libc = "0.2.153"
|
||||||
log = "0.4.20"
|
log = "0.4.21"
|
||||||
remain = "0.2.11"
|
remain = "0.2.13"
|
||||||
smallvec = "1.11.0"
|
serde = { version = "1.0.197", features = ["derive"] }
|
||||||
thiserror = "1.0.40"
|
smallvec = "1.13.2"
|
||||||
uuid = { version = "1.3.4", features = ["v4"] }
|
thiserror = "1.0.58"
|
||||||
versionize = "0.1.10"
|
uuid = { version = "1.8.0", features = ["v4"] }
|
||||||
versionize_derive = "0.1.4"
|
virtio-bindings = { version = "0.2.2", features = ["virtio-v5_0_0"] }
|
||||||
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
|
virtio-queue = "0.11.0"
|
||||||
virtio-queue = "0.10.0"
|
vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||||
vm-memory = { version = "0.13.1", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vmm-sys-util = "0.11.0"
|
vmm-sys-util = "0.12.1"
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ use crate::vhdx::{Vhdx, VhdxError};
|
|||||||
#[cfg(feature = "io_uring")]
|
#[cfg(feature = "io_uring")]
|
||||||
use io_uring::{opcode, IoUring, Probe};
|
use io_uring::{opcode, IoUring, Probe};
|
||||||
use libc::{ioctl, S_IFBLK, S_IFMT};
|
use libc::{ioctl, S_IFBLK, S_IFMT};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::alloc::{alloc_zeroed, dealloc, Layout};
|
use std::alloc::{alloc_zeroed, dealloc, Layout};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
|
use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
|
||||||
@@ -53,8 +53,6 @@ use std::sync::Arc;
|
|||||||
use std::sync::MutexGuard;
|
use std::sync::MutexGuard;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
|
||||||
use versionize_derive::Versionize;
|
|
||||||
use virtio_bindings::virtio_blk::*;
|
use virtio_bindings::virtio_blk::*;
|
||||||
use virtio_queue::DescriptorChain;
|
use virtio_queue::DescriptorChain;
|
||||||
use vm_memory::{
|
use vm_memory::{
|
||||||
@@ -545,7 +543,7 @@ impl Request {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Versionize)]
|
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct VirtioBlockConfig {
|
pub struct VirtioBlockConfig {
|
||||||
pub capacity: u64,
|
pub capacity: u64,
|
||||||
@@ -568,7 +566,7 @@ pub struct VirtioBlockConfig {
|
|||||||
pub write_zeroes_may_unmap: u8,
|
pub write_zeroes_may_unmap: u8,
|
||||||
pub unused1: [u8; 3],
|
pub unused1: [u8; 3],
|
||||||
}
|
}
|
||||||
#[derive(Copy, Clone, Debug, Default, Versionize)]
|
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct VirtioBlockGeometry {
|
pub struct VirtioBlockGeometry {
|
||||||
pub cylinders: u16,
|
pub cylinders: u16,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
mod qcow_raw_file;
|
mod qcow_raw_file;
|
||||||
mod raw_file;
|
mod raw_file;
|
||||||
@@ -1822,7 +1824,6 @@ pub fn detect_image_type(file: &mut RawFile) -> Result<ImageType> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
|
||||||
use vmm_sys_util::tempfile::TempFile;
|
use vmm_sys_util::tempfile::TempFile;
|
||||||
use vmm_sys_util::write_zeroes::WriteZeroes;
|
use vmm_sys_util::write_zeroes::WriteZeroes;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
use super::RawFile;
|
use super::RawFile;
|
||||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
use crate::BlockBackend;
|
use crate::BlockBackend;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
use std::alloc::{alloc_zeroed, dealloc, Layout};
|
use std::alloc::{alloc_zeroed, dealloc, Layout};
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::fs::{File, Metadata};
|
use std::fs::{File, Metadata};
|
||||||
use std::io::{self, Read, Seek, SeekFrom, Write};
|
use std::io::{self, Read, Seek, SeekFrom, Write};
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
use std::collections::hash_map::IterMut;
|
use std::collections::hash_map::IterMut;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -136,7 +138,7 @@ impl<T: Cacheable> CacheMap<T> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
struct NumCache(pub u64);
|
struct NumCache(());
|
||||||
impl Cacheable for NumCache {
|
impl Cacheable for NumCache {
|
||||||
fn dirty(&self) -> bool {
|
fn dirty(&self) -> bool {
|
||||||
true
|
true
|
||||||
@@ -148,28 +150,28 @@ mod tests {
|
|||||||
let mut cache = CacheMap::<NumCache>::new(3);
|
let mut cache = CacheMap::<NumCache>::new(3);
|
||||||
let mut evicted = None;
|
let mut evicted = None;
|
||||||
cache
|
cache
|
||||||
.insert(0, NumCache(5), |index, _| {
|
.insert(0, NumCache(()), |index, _| {
|
||||||
evicted = Some(index);
|
evicted = Some(index);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(evicted, None);
|
assert_eq!(evicted, None);
|
||||||
cache
|
cache
|
||||||
.insert(1, NumCache(6), |index, _| {
|
.insert(1, NumCache(()), |index, _| {
|
||||||
evicted = Some(index);
|
evicted = Some(index);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(evicted, None);
|
assert_eq!(evicted, None);
|
||||||
cache
|
cache
|
||||||
.insert(2, NumCache(7), |index, _| {
|
.insert(2, NumCache(()), |index, _| {
|
||||||
evicted = Some(index);
|
evicted = Some(index);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(evicted, None);
|
assert_eq!(evicted, None);
|
||||||
cache
|
cache
|
||||||
.insert(3, NumCache(8), |index, _| {
|
.insert(3, NumCache(()), |index, _| {
|
||||||
evicted = Some(index);
|
evicted = Some(index);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::{read_aligned_block_size, DiskTopology};
|
use crate::{read_aligned_block_size, DiskTopology};
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Seek, SeekFrom};
|
use std::io::{Seek, SeekFrom};
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ extern crate log;
|
|||||||
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
|
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
|
||||||
use remain::sorted;
|
use remain::sorted;
|
||||||
use std::collections::btree_map::BTreeMap;
|
use std::collections::btree_map::BTreeMap;
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, Read, Seek, SeekFrom, Write};
|
use std::io::{self, Read, Seek, SeekFrom, Write};
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
@@ -91,7 +90,7 @@ pub type Result<T> = std::result::Result<T, VhdxHeaderError>;
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct FileTypeIdentifier {
|
pub struct FileTypeIdentifier {
|
||||||
pub signature: u64,
|
pub _signature: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileTypeIdentifier {
|
impl FileTypeIdentifier {
|
||||||
@@ -99,14 +98,14 @@ impl FileTypeIdentifier {
|
|||||||
pub fn new(f: &mut File) -> Result<FileTypeIdentifier> {
|
pub fn new(f: &mut File) -> Result<FileTypeIdentifier> {
|
||||||
f.seek(SeekFrom::Start(FILE_START))
|
f.seek(SeekFrom::Start(FILE_START))
|
||||||
.map_err(VhdxHeaderError::SeekFileTypeIdentifier)?;
|
.map_err(VhdxHeaderError::SeekFileTypeIdentifier)?;
|
||||||
let signature = f
|
let _signature = f
|
||||||
.read_u64::<LittleEndian>()
|
.read_u64::<LittleEndian>()
|
||||||
.map_err(VhdxHeaderError::ReadFileTypeIdentifier)?;
|
.map_err(VhdxHeaderError::ReadFileTypeIdentifier)?;
|
||||||
if signature != VHDX_SIGN {
|
if _signature != VHDX_SIGN {
|
||||||
return Err(VhdxHeaderError::InvalidVHDXSign);
|
return Err(VhdxHeaderError::InvalidVHDXSign);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(FileTypeIdentifier { signature })
|
Ok(FileTypeIdentifier { _signature })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +191,9 @@ impl Header {
|
|||||||
};
|
};
|
||||||
|
|
||||||
new_header.get_header_as_buffer(&mut buffer);
|
new_header.get_header_as_buffer(&mut buffer);
|
||||||
new_header.checksum = crc32c::crc32c(&buffer);
|
let mut crc = crc_any::CRC::crc32c();
|
||||||
|
crc.digest(&buffer);
|
||||||
|
new_header.checksum = crc.get_crc() as u32;
|
||||||
new_header.get_header_as_buffer(&mut buffer);
|
new_header.get_header_as_buffer(&mut buffer);
|
||||||
|
|
||||||
f.seek(SeekFrom::Start(start))
|
f.seek(SeekFrom::Start(start))
|
||||||
@@ -351,12 +352,6 @@ impl RegionTableEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct RegionEntry {
|
|
||||||
_start: u64,
|
|
||||||
_end: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum HeaderNo {
|
enum HeaderNo {
|
||||||
First,
|
First,
|
||||||
Second,
|
Second,
|
||||||
@@ -480,7 +475,10 @@ pub fn calculate_checksum(buffer: &mut [u8], csum_offset: usize) -> Result<u32>
|
|||||||
// Zero the checksum in the buffer
|
// Zero the checksum in the buffer
|
||||||
LittleEndian::write_u32(csum_buf, 0);
|
LittleEndian::write_u32(csum_buf, 0);
|
||||||
// Calculate the checksum on the resulting buffer
|
// Calculate the checksum on the resulting buffer
|
||||||
let new_csum = crc32c::crc32c(buffer);
|
let mut crc = crc_any::CRC::crc32c();
|
||||||
|
crc.digest(&buffer);
|
||||||
|
let new_csum = crc.get_crc() as u32;
|
||||||
|
|
||||||
// Put back the original checksum in the buffer
|
// Put back the original checksum in the buffer
|
||||||
LittleEndian::write_u32(&mut buffer[csum_offset..csum_offset + 4], orig_csum);
|
LittleEndian::write_u32(&mut buffer[csum_offset..csum_offset + 4], orig_csum);
|
||||||
|
|
||||||
|
|||||||
@@ -6,24 +6,23 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
|
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.81"
|
||||||
arch = { path = "../arch" }
|
arch = { path = "../arch" }
|
||||||
bitflags = "2.4.1"
|
bitflags = "2.5.0"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.5.0"
|
||||||
event_monitor = { path = "../event_monitor" }
|
event_monitor = { path = "../event_monitor" }
|
||||||
hypervisor = { path = "../hypervisor" }
|
hypervisor = { path = "../hypervisor" }
|
||||||
libc = "0.2.147"
|
libc = "0.2.153"
|
||||||
log = "0.4.20"
|
log = "0.4.21"
|
||||||
pci = { path = "../pci" }
|
pci = { path = "../pci" }
|
||||||
thiserror = "1.0.40"
|
serde = { version = "1.0.197", features = ["derive"] }
|
||||||
|
thiserror = "1.0.58"
|
||||||
tpm = { path = "../tpm" }
|
tpm = { path = "../tpm" }
|
||||||
versionize = "0.1.10"
|
|
||||||
versionize_derive = "0.1.4"
|
|
||||||
vm-allocator = { path = "../vm-allocator" }
|
vm-allocator = { path = "../vm-allocator" }
|
||||||
vm-device = { path = "../vm-device" }
|
vm-device = { path = "../vm-device" }
|
||||||
vm-memory = "0.13.1"
|
vm-memory = "0.14.1"
|
||||||
vm-migration = { path = "../vm-migration" }
|
vm-migration = { path = "../vm-migration" }
|
||||||
vmm-sys-util = "0.11.0"
|
vmm-sys-util = "0.12.1"
|
||||||
|
|
||||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||||
arch = { path = "../arch" }
|
arch = { path = "../arch" }
|
||||||
|
|||||||
64
devices/src/debug_console.rs
Normal file
64
devices/src/debug_console.rs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright © 2023 Cyberus Technology
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
//! Module for [`DebugconState`].
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::sync::{Arc, Barrier};
|
||||||
|
use vm_device::BusDevice;
|
||||||
|
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||||
|
|
||||||
|
/// I/O-port.
|
||||||
|
pub const DEFAULT_PORT: u64 = 0xe9;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct DebugconState {}
|
||||||
|
|
||||||
|
/// Emulates a debug console similar to the QEMU debugcon device. This device
|
||||||
|
/// is stateless and only prints the bytes (usually text) that are written to
|
||||||
|
/// it.
|
||||||
|
///
|
||||||
|
/// This device is only available on x86.
|
||||||
|
///
|
||||||
|
/// Reference:
|
||||||
|
/// - https://github.com/qemu/qemu/blob/master/hw/char/debugcon.c
|
||||||
|
/// - https://phip1611.de/blog/how-to-use-qemus-debugcon-feature-and-write-to-a-file/
|
||||||
|
pub struct DebugConsole {
|
||||||
|
id: String,
|
||||||
|
out: Box<dyn io::Write + Send>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugConsole {
|
||||||
|
pub fn new(id: String, out: Box<dyn io::Write + Send>) -> Self {
|
||||||
|
Self { id, out }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BusDevice for DebugConsole {
|
||||||
|
fn read(&mut self, _base: u64, _offset: u64, _data: &mut [u8]) {}
|
||||||
|
|
||||||
|
fn write(&mut self, _base: u64, _offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||||
|
if let Err(e) = self.out.write_all(data) {
|
||||||
|
// unlikely
|
||||||
|
error!("debug-console: failed writing data: {e:?}");
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Snapshottable for DebugConsole {
|
||||||
|
fn id(&self) -> String {
|
||||||
|
self.id.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn snapshot(&mut self) -> Result<Snapshot, MigratableError> {
|
||||||
|
Snapshot::new_from_state(&())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pausable for DebugConsole {}
|
||||||
|
impl Transportable for DebugConsole {}
|
||||||
|
impl Migratable for DebugConsole {}
|
||||||
@@ -11,19 +11,16 @@
|
|||||||
|
|
||||||
use super::interrupt_controller::{Error, InterruptController};
|
use super::interrupt_controller::{Error, InterruptController};
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
|
||||||
use versionize_derive::Versionize;
|
|
||||||
use vm_device::interrupt::{
|
use vm_device::interrupt::{
|
||||||
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
|
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
|
||||||
MsiIrqGroupConfig, MsiIrqSourceConfig,
|
MsiIrqGroupConfig, MsiIrqSourceConfig,
|
||||||
};
|
};
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
use vm_memory::GuestAddress;
|
use vm_memory::GuestAddress;
|
||||||
use vm_migration::{
|
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||||
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
|
|
||||||
};
|
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
@@ -136,7 +133,7 @@ pub struct Ioapic {
|
|||||||
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Versionize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct IoapicState {
|
pub struct IoapicState {
|
||||||
id_reg: u32,
|
id_reg: u32,
|
||||||
reg_sel: u32,
|
reg_sel: u32,
|
||||||
@@ -144,7 +141,6 @@ pub struct IoapicState {
|
|||||||
used_entries: [bool; NUM_IOAPIC_PINS],
|
used_entries: [bool; NUM_IOAPIC_PINS],
|
||||||
apic_address: u64,
|
apic_address: u64,
|
||||||
}
|
}
|
||||||
impl VersionMapped for IoapicState {}
|
|
||||||
|
|
||||||
impl BusDevice for Ioapic {
|
impl BusDevice for Ioapic {
|
||||||
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
||||||
@@ -444,7 +440,7 @@ impl Snapshottable for Ioapic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
Snapshot::new_from_versioned_state(&self.state())
|
Snapshot::new_from_state(&self.state())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
use libc::{clock_gettime, gmtime_r, timespec, tm, CLOCK_REALTIME};
|
use libc::{clock_gettime, gmtime_r, timespec, tm, CLOCK_REALTIME};
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
|||||||
@@ -8,16 +8,13 @@
|
|||||||
//!
|
//!
|
||||||
|
|
||||||
use crate::{read_le_u32, write_le_u32};
|
use crate::{read_le_u32, write_le_u32};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
|
||||||
use versionize_derive::Versionize;
|
|
||||||
use vm_device::interrupt::InterruptSourceGroup;
|
use vm_device::interrupt::InterruptSourceGroup;
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
use vm_migration::{
|
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||||
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
|
|
||||||
};
|
|
||||||
|
|
||||||
const OFS_DATA: u64 = 0x400; // Data Register
|
const OFS_DATA: u64 = 0x400; // Data Register
|
||||||
const GPIODIR: u64 = 0x400; // Direction Register
|
const GPIODIR: u64 = 0x400; // Direction Register
|
||||||
@@ -89,7 +86,7 @@ pub struct Gpio {
|
|||||||
interrupt: Arc<dyn InterruptSourceGroup>,
|
interrupt: Arc<dyn InterruptSourceGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Versionize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct GpioState {
|
pub struct GpioState {
|
||||||
data: u32,
|
data: u32,
|
||||||
old_in_data: u32,
|
old_in_data: u32,
|
||||||
@@ -102,8 +99,6 @@ pub struct GpioState {
|
|||||||
afsel: u32,
|
afsel: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VersionMapped for GpioState {}
|
|
||||||
|
|
||||||
impl Gpio {
|
impl Gpio {
|
||||||
/// Constructs an PL061 GPIO device.
|
/// Constructs an PL061 GPIO device.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@@ -328,7 +323,7 @@ impl Snapshottable for Gpio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
Snapshot::new_from_versioned_state(&self.state())
|
Snapshot::new_from_state(&self.state())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,8 +334,6 @@ impl Migratable for Gpio {}
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{read_le_u32, write_le_u32};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
|
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
|
|||||||
@@ -329,10 +329,9 @@ impl BusDevice for Rtc {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
read_be_u16, read_be_u32, read_le_i32, read_le_u16, read_le_u32, read_le_u64, write_be_u16,
|
read_be_u16, read_be_u32, read_le_i32, read_le_u16, read_le_u64, write_be_u16,
|
||||||
write_be_u32, write_le_i32, write_le_u16, write_le_u32, write_le_u64,
|
write_be_u32, write_le_i32, write_le_u16, write_le_u64,
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
|
||||||
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
|
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
|
|||||||
@@ -5,16 +5,13 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
use std::{io, result};
|
use std::{io, result};
|
||||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
|
||||||
use versionize_derive::Versionize;
|
|
||||||
use vm_device::interrupt::InterruptSourceGroup;
|
use vm_device::interrupt::InterruptSourceGroup;
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
use vm_migration::{
|
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||||
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
|
|
||||||
};
|
|
||||||
use vmm_sys_util::errno::Result;
|
use vmm_sys_util::errno::Result;
|
||||||
|
|
||||||
const LOOP_SIZE: usize = 0x40;
|
const LOOP_SIZE: usize = 0x40;
|
||||||
@@ -74,7 +71,7 @@ pub struct Serial {
|
|||||||
out: Option<Box<dyn io::Write + Send>>,
|
out: Option<Box<dyn io::Write + Send>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Versionize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct SerialState {
|
pub struct SerialState {
|
||||||
interrupt_enable: u8,
|
interrupt_enable: u8,
|
||||||
interrupt_identification: u8,
|
interrupt_identification: u8,
|
||||||
@@ -86,7 +83,6 @@ pub struct SerialState {
|
|||||||
baud_divisor: u16,
|
baud_divisor: u16,
|
||||||
in_buffer: Vec<u8>,
|
in_buffer: Vec<u8>,
|
||||||
}
|
}
|
||||||
impl VersionMapped for SerialState {}
|
|
||||||
|
|
||||||
impl Serial {
|
impl Serial {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@@ -334,7 +330,7 @@ impl Snapshottable for Serial {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
Snapshot::new_from_versioned_state(&self.state())
|
Snapshot::new_from_state(&self.state())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,8 +341,7 @@ impl Migratable for Serial {}
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::io;
|
use std::sync::Mutex;
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
|
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
|
|||||||
@@ -7,18 +7,15 @@
|
|||||||
//!
|
//!
|
||||||
|
|
||||||
use crate::{read_le_u32, write_le_u32};
|
use crate::{read_le_u32, write_le_u32};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use std::{io, result};
|
use std::{io, result};
|
||||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
|
||||||
use versionize_derive::Versionize;
|
|
||||||
use vm_device::interrupt::InterruptSourceGroup;
|
use vm_device::interrupt::InterruptSourceGroup;
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
use vm_migration::{
|
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||||
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Registers */
|
/* Registers */
|
||||||
const UARTDR: u64 = 0;
|
const UARTDR: u64 = 0;
|
||||||
@@ -94,7 +91,7 @@ pub struct Pl011 {
|
|||||||
timestamp: std::time::Instant,
|
timestamp: std::time::Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Versionize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Pl011State {
|
pub struct Pl011State {
|
||||||
flags: u32,
|
flags: u32,
|
||||||
lcr: u32,
|
lcr: u32,
|
||||||
@@ -113,8 +110,6 @@ pub struct Pl011State {
|
|||||||
read_trigger: u32,
|
read_trigger: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VersionMapped for Pl011State {}
|
|
||||||
|
|
||||||
impl Pl011 {
|
impl Pl011 {
|
||||||
/// Constructs an AMBA PL011 UART device.
|
/// Constructs an AMBA PL011 UART device.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@@ -454,7 +449,7 @@ impl Snapshottable for Pl011 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
Snapshot::new_from_versioned_state(&self.state())
|
Snapshot::new_from_state(&self.state())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,8 +460,7 @@ impl Migratable for Pl011 {}
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::io;
|
use std::sync::Mutex;
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
|
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ extern crate event_monitor;
|
|||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
pub mod acpi;
|
pub mod acpi;
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub mod debug_console;
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
pub mod gic;
|
pub mod gic;
|
||||||
pub mod interrupt_controller;
|
pub mod interrupt_controller;
|
||||||
|
|||||||
@@ -9,18 +9,15 @@ use pci::{
|
|||||||
PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
|
PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
|
||||||
PCI_CONFIGURATION_ID,
|
PCI_CONFIGURATION_ID,
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::{Arc, Barrier, Mutex};
|
use std::sync::{Arc, Barrier, Mutex};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
|
||||||
use versionize_derive::Versionize;
|
|
||||||
use vm_allocator::{AddressAllocator, SystemAllocator};
|
use vm_allocator::{AddressAllocator, SystemAllocator};
|
||||||
use vm_device::{BusDevice, Resource};
|
use vm_device::{BusDevice, Resource};
|
||||||
use vm_memory::{Address, GuestAddress};
|
use vm_memory::{Address, GuestAddress};
|
||||||
use vm_migration::{
|
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||||
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
|
|
||||||
};
|
|
||||||
|
|
||||||
const PVPANIC_VENDOR_ID: u16 = 0x1b36;
|
const PVPANIC_VENDOR_ID: u16 = 0x1b36;
|
||||||
const PVPANIC_DEVICE_ID: u16 = 0x0011;
|
const PVPANIC_DEVICE_ID: u16 = 0x0011;
|
||||||
@@ -60,23 +57,20 @@ pub struct PvPanicDevice {
|
|||||||
bar_regions: Vec<PciBarConfiguration>,
|
bar_regions: Vec<PciBarConfiguration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Versionize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct PvPanicDeviceState {
|
pub struct PvPanicDeviceState {
|
||||||
events: u8,
|
events: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VersionMapped for PvPanicDeviceState {}
|
|
||||||
|
|
||||||
impl PvPanicDevice {
|
impl PvPanicDevice {
|
||||||
pub fn new(id: String, snapshot: Option<Snapshot>) -> Result<Self, PvPanicError> {
|
pub fn new(id: String, snapshot: Option<Snapshot>) -> Result<Self, PvPanicError> {
|
||||||
let pci_configuration_state =
|
let pci_configuration_state =
|
||||||
vm_migration::versioned_state_from_id(snapshot.as_ref(), PCI_CONFIGURATION_ID)
|
vm_migration::state_from_id(snapshot.as_ref(), PCI_CONFIGURATION_ID).map_err(|e| {
|
||||||
.map_err(|e| {
|
PvPanicError::RetrievePciConfigurationState(anyhow!(
|
||||||
PvPanicError::RetrievePciConfigurationState(anyhow!(
|
"Failed to get PciConfigurationState from Snapshot: {}",
|
||||||
"Failed to get PciConfigurationState from Snapshot: {}",
|
e
|
||||||
e
|
))
|
||||||
))
|
})?;
|
||||||
})?;
|
|
||||||
|
|
||||||
let mut configuration = PciConfiguration::new(
|
let mut configuration = PciConfiguration::new(
|
||||||
PVPANIC_VENDOR_ID,
|
PVPANIC_VENDOR_ID,
|
||||||
@@ -97,7 +91,7 @@ impl PvPanicDevice {
|
|||||||
|
|
||||||
let state: Option<PvPanicDeviceState> = snapshot
|
let state: Option<PvPanicDeviceState> = snapshot
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|s| s.to_versioned_state())
|
.map(|s| s.to_state())
|
||||||
.transpose()
|
.transpose()
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
PvPanicError::CreatePvPanicDevice(anyhow!(
|
PvPanicError::CreatePvPanicDevice(anyhow!(
|
||||||
@@ -210,7 +204,7 @@ impl PciDevice for PvPanicDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bars.push(bar);
|
bars.push(bar);
|
||||||
self.bar_regions = bars.clone();
|
self.bar_regions.clone_from(&bars);
|
||||||
|
|
||||||
Ok(bars)
|
Ok(bars)
|
||||||
}
|
}
|
||||||
@@ -259,7 +253,7 @@ impl Snapshottable for PvPanicDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||||
let mut snapshot = Snapshot::new_from_versioned_state(&self.state())?;
|
let mut snapshot = Snapshot::new_from_state(&self.state())?;
|
||||||
|
|
||||||
// Snapshot PciConfiguration
|
// Snapshot PciConfiguration
|
||||||
snapshot.add_snapshot(self.configuration.id(), self.configuration.snapshot()?);
|
snapshot.add_snapshot(self.configuration.id(), self.configuration.snapshot()?);
|
||||||
|
|||||||
13
docs/api.md
13
docs/api.md
@@ -110,6 +110,7 @@ The Cloud Hypervisor API exposes the following actions through its endpoints:
|
|||||||
| Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/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 |
|
| 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 |
|
| Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted |
|
||||||
|
| Inject an NMI | `/vm.nmi` | N/A | N/A | The VM is booted |
|
||||||
| Prepare to receive a migration | `/vm.receive-migration` | `/schemas/ReceiveMigrationData` | N/A | N/A |
|
| 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) |
|
| Start to send migration to target | `/vm.send-migration` | `/schemas/SendMigrationData` | N/A | The VM is booted and (shared mem or hugepages enabled) |
|
||||||
|
|
||||||
@@ -147,7 +148,7 @@ We want to create a virtual machine with the following characteristics:
|
|||||||
`/opt/clh/images/focal-server-cloudimg-amd64.raw`
|
`/opt/clh/images/focal-server-cloudimg-amd64.raw`
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||||
-X PUT 'http://localhost/api/v1/vm.create' \
|
-X PUT 'http://localhost/api/v1/vm.create' \
|
||||||
@@ -167,7 +168,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
|||||||
Once the VM is created, we can boot it:
|
Once the VM is created, we can boot it:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.boot'
|
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.boot'
|
||||||
```
|
```
|
||||||
@@ -177,7 +178,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1
|
|||||||
We can fetch information about any VM, as soon as it's created:
|
We can fetch information about any VM, as soon as it's created:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||||
-X GET 'http://localhost/api/v1/vm.info' \
|
-X GET 'http://localhost/api/v1/vm.info' \
|
||||||
@@ -189,7 +190,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
|||||||
We can reboot a VM that's already booted:
|
We can reboot a VM that's already booted:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.reboot'
|
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.reboot'
|
||||||
```
|
```
|
||||||
@@ -199,7 +200,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1
|
|||||||
Once booted, we can shut a VM down from the REST API:
|
Once booted, we can shut a VM down from the REST API:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.shutdown'
|
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.shutdown'
|
||||||
```
|
```
|
||||||
@@ -385,7 +386,7 @@ APIs work together, let's look at a complete VM creation flow, from the
|
|||||||
[REST API](#rest-api) in order to creates a virtual machine:
|
[REST API](#rest-api) in order to creates a virtual machine:
|
||||||
```
|
```
|
||||||
shell
|
shell
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||||
-X PUT 'http://localhost/api/v1/vm.create' \
|
-X PUT 'http://localhost/api/v1/vm.create' \
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ We usually start from one of the custom cloud image we have previously created
|
|||||||
but we can use a stock cloud image as well.
|
but we can use a stock cloud image as well.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://cloud-hypervisor.azureedge.net/jammy-server-cloudimg-amd64-custom-20230119-0.raw
|
wget https://ch-images.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
|
mv jammy-server-cloudimg-amd64-custom-20230119-0.raw jammy-server-cloudimg-amd64-nvidia.raw
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -326,4 +326,4 @@ VM will be booted with this image.
|
|||||||
|
|
||||||
```
|
```
|
||||||
sudo cloud-init clean
|
sudo cloud-init clean
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
# `cloud-hypervisor` debug IO port
|
# `cloud-hypervisor` debug IO ports
|
||||||
|
|
||||||
`cloud-hypervisor` uses the [`0x80`](https://www.intel.com/content/www/us/en/support/articles/000005500/boards-and-kits.html)
|
When running x86 guests, `cloud-hypervisor` provides different kinds of debug ports:
|
||||||
I/O port to trace user defined guest events.
|
- [`0x80` debug port](https://www.intel.com/content/www/us/en/support/articles/000005500/boards-and-kits.html)
|
||||||
|
- Debug console (by default at `0xe9`).
|
||||||
|
- Firmware debug port at `0x402`.
|
||||||
|
|
||||||
|
All of them can be used to trace user-defined guest events and all of them can
|
||||||
|
be used simultaneously.
|
||||||
|
|
||||||
|
## Debug Ports Overview
|
||||||
|
|
||||||
|
### `0x80` I/O port
|
||||||
|
|
||||||
Whenever the guest write one byte between `0x0` and `0xF` on this particular
|
Whenever the guest write one byte between `0x0` and `0xF` on this particular
|
||||||
I/O port, `cloud-hypervisor` will log and timestamp that event at the `debug`
|
I/O port, `cloud-hypervisor` will log and timestamp that event at the `debug`
|
||||||
@@ -30,7 +39,7 @@ guest will have `cloud-hypervisor` generate timestamped logs of all those steps.
|
|||||||
That provides a basic but convenient way of measuring not only the overall guest
|
That provides a basic but convenient way of measuring not only the overall guest
|
||||||
boot time but all intermediate steps as well.
|
boot time but all intermediate steps as well.
|
||||||
|
|
||||||
## Logging
|
#### Logging
|
||||||
|
|
||||||
Assuming parts of the guest software stack have been instrumented to use the
|
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.
|
`cloud-hypervisor` debug I/O port, we may want to gather the related logs.
|
||||||
@@ -59,3 +68,29 @@ $ grep "Debug I/O port" /tmp/ch-fw.log
|
|||||||
cloud-hypervisor: 19.762449ms: DEBUG:vmm/src/vm.rs:510 -- [Debug I/O port: Firmware code 0x0] 0.019004 seconds
|
cloud-hypervisor: 19.762449ms: DEBUG:vmm/src/vm.rs:510 -- [Debug I/O port: Firmware code 0x0] 0.019004 seconds
|
||||||
cloud-hypervisor: 403.499628ms: DEBUG:vmm/src/vm.rs:510 -- [Debug I/O port: Firmware code 0x1] 0.402744 seconds
|
cloud-hypervisor: 403.499628ms: DEBUG:vmm/src/vm.rs:510 -- [Debug I/O port: Firmware code 0x1] 0.402744 seconds
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Debug console port
|
||||||
|
|
||||||
|
The debug console is inspired by QEMU and Bochs, which have a similar feature.
|
||||||
|
By default, the I/O port `0xe9` is used. This port can be configured like a
|
||||||
|
console. Thus, it can print to a tty, a file, or a pty, for example.
|
||||||
|
|
||||||
|
### Firmware debug port
|
||||||
|
|
||||||
|
The firmware debug port is also a simple port that prints all bytes written to
|
||||||
|
it. The firmware debug port only prints to stdout.
|
||||||
|
|
||||||
|
## When do I need these ports?
|
||||||
|
|
||||||
|
The ports are on the one hand interesting for firmware or kernel developers, as
|
||||||
|
they provide an easy way to print debug information from within a guest.
|
||||||
|
Furthermore, you can patch "normal" software to measure certain events, such as
|
||||||
|
the boot time of a guest.
|
||||||
|
|
||||||
|
## Which port should I choose?
|
||||||
|
|
||||||
|
The `0x80` debug port and the port of the firmware debug device are always
|
||||||
|
available. The debug console must be activated via the command line, but
|
||||||
|
provides more configuration options.
|
||||||
|
|
||||||
|
You can use different ports for different aspect of your logging messages.
|
||||||
@@ -103,7 +103,7 @@ firmware:
|
|||||||
### TDShim
|
### TDShim
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
> The latest version of TDShim being tested is [_66bb334_](https://github.com/confidential-containers/td-shim/tree/66bb33451befbf1291abe3cfea7ee9e99d922b0d).
|
> The latest version of TDShim being tested is [_v0.8.0_](https://github.com/confidential-containers/td-shim/releases/tag/v0.8.0).
|
||||||
|
|
||||||
This is a lightweight version of the TDVF, written in Rust and designed for
|
This is a lightweight version of the TDVF, written in Rust and designed for
|
||||||
direct kernel boot, which is useful for containers use cases.
|
direct kernel boot, which is useful for containers use cases.
|
||||||
@@ -113,7 +113,7 @@ and `LLVM` first. The TDshim can be build as follows:
|
|||||||
```bash
|
```bash
|
||||||
git clone https://github.com/confidential-containers/td-shim
|
git clone https://github.com/confidential-containers/td-shim
|
||||||
cd td-shim
|
cd td-shim
|
||||||
git checkout 66bb33451befbf1291abe3cfea7ee9e99d922b0d
|
git checkout v0.8.0
|
||||||
cargo install cargo-xbuild
|
cargo install cargo-xbuild
|
||||||
export CC=clang
|
export CC=clang
|
||||||
export AR=llvm-ar
|
export AR=llvm-ar
|
||||||
@@ -121,15 +121,13 @@ export CC_x86_64_unknown_none=clang
|
|||||||
export AR_x86_64_unknown_none=llvm-ar
|
export AR_x86_64_unknown_none=llvm-ar
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
./sh_script/preparation.sh
|
./sh_script/preparation.sh
|
||||||
cargo xbuild -p td-shim --target x86_64-unknown-none --release --features=main,tdx
|
cargo image --release
|
||||||
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
|
If debug logs from the TDShim is needed, here are the alternative
|
||||||
commands:
|
commands:
|
||||||
```bash
|
```bash
|
||||||
cargo xbuild -p td-shim --target x86_64-unknown-none --features=main,tdx
|
cargo image
|
||||||
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
|
And run a TDX VM by providing the firmware previously built, along with a guest
|
||||||
|
|||||||
@@ -42,3 +42,14 @@ actual rate limit users get can be as low as
|
|||||||
generally advisable to keep `bw/ops_refill_time` larger than `100 ms`
|
generally advisable to keep `bw/ops_refill_time` larger than `100 ms`
|
||||||
(`cool_down_time`) to make sure the actual rate limit is close to users'
|
(`cool_down_time`) to make sure the actual rate limit is close to users'
|
||||||
expectation ("refill-rate").
|
expectation ("refill-rate").
|
||||||
|
|
||||||
|
## Rate Limit Groups
|
||||||
|
It is possible to throttle the aggregate bandwidth or operations
|
||||||
|
of multiple virtio-blk devices using a `rate_limit_group`. virtio-blk devices may be
|
||||||
|
dynamically added and removed from a `rate_limit_group`. The following example
|
||||||
|
demonstrates how to throttle the aggregate bandwidth of two disks to 10 MiB/s.
|
||||||
|
```
|
||||||
|
--disk path=disk0.raw,rate_limit_group=group0 \
|
||||||
|
path=disk1.raw,rate_limit_group=group0 \
|
||||||
|
--rate-limit-group bw_size=1048576,bw_refill_time,bw_refill_time=100
|
||||||
|
```
|
||||||
|
|||||||
@@ -60,10 +60,7 @@ implement a full emulation of a physical IOMMU.
|
|||||||
|
|
||||||
### Kernel
|
### Kernel
|
||||||
|
|
||||||
Since virtio-iommu has landed partially into the version 5.3 of the Linux
|
As of Kernel 5.14, virtio-iommu is available for both X86-64 and Aarch64.
|
||||||
kernel, a special branch is needed to get things working with Cloud Hypervisor.
|
|
||||||
By partially, we are talking about x86 specifically, as it is already fully
|
|
||||||
functional for ARM architectures.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|||||||
62
docs/vfio.md
62
docs/vfio.md
@@ -122,4 +122,64 @@ $ ls /sys/kernel/iommu_groups/22/devices/
|
|||||||
|
|
||||||
This means these two devices are under the same IOMMU group 22. In such case,
|
This means these two devices are under the same IOMMU group 22. In such case,
|
||||||
it is important to bind both devices to VFIO and pass them both through the
|
it is important to bind both devices to VFIO and pass them both through the
|
||||||
VM, otherwise this could cause some functional and security issues.
|
VM, otherwise this could cause some functional and security issues.
|
||||||
|
|
||||||
|
### Advanced Configuration Options
|
||||||
|
|
||||||
|
When using NVIDIA GPUs in a VFIO passthrough configuration, advanced
|
||||||
|
configuration options are supported to enable GPUDirect P2P DMA over
|
||||||
|
PCIe. When enabled, loads and stores between GPUs use native PCIe
|
||||||
|
peer-to-peer transactions instead of a shared memory buffer. This drastically
|
||||||
|
decreases P2P latency between GPUs. This functionality is supported by
|
||||||
|
cloud-hypervisor on NVIDIA Turing, Ampere, Hopper, and Lovelace GPUs.
|
||||||
|
|
||||||
|
The NVIDIA driver does not enable GPUDirect P2P over PCIe within guests
|
||||||
|
by default because hardware support for routing P2P TLP between PCIe root
|
||||||
|
ports is optional. PCIe P2P should always be supported between devices
|
||||||
|
on the same PCIe switch. The `x_nv_gpudirect_clique` config argument may
|
||||||
|
be used to signal support for PCIe P2P traffic between NVIDIA VFIO endpoints.
|
||||||
|
The guest driver assumes that P2P traffic is supported between all endpoints
|
||||||
|
that are part of the same clique.
|
||||||
|
```
|
||||||
|
--device path=/sys/bus/pci/devices/0000:01:00.0/,x_nv_gpudirect_clique=0
|
||||||
|
```
|
||||||
|
|
||||||
|
The following command can be run on the guest to verify that GPUDirect P2P is
|
||||||
|
correctly enabled.
|
||||||
|
```
|
||||||
|
nvidia-smi topo -p2p r
|
||||||
|
GPU0 GPU1 GPU2 GPU3 GPU4 GPU5 GPU6 GPU7
|
||||||
|
GPU0 X OK OK OK OK OK OK OK
|
||||||
|
GPU1 OK X OK OK OK OK OK OK
|
||||||
|
GPU2 OK OK X OK OK OK OK OK
|
||||||
|
GPU3 OK OK OK X OK OK OK OK
|
||||||
|
GPU4 OK OK OK OK X OK OK OK
|
||||||
|
GPU5 OK OK OK OK OK X OK OK
|
||||||
|
GPU6 OK OK OK OK OK OK X OK
|
||||||
|
GPU7 OK OK OK OK OK OK OK X
|
||||||
|
```
|
||||||
|
|
||||||
|
Some VFIO devices have a 32-bit mmio BAR. When using many such devices, it is
|
||||||
|
possible to exhaust the 32-bit mmio space available on a PCI segment. The
|
||||||
|
following example demonstrates an example device with a 16 MiB 32-bit mmio BAR.
|
||||||
|
```
|
||||||
|
lspci -s 0000:01:00.0 -v
|
||||||
|
0000:01:00.0 3D controller: NVIDIA Corporation Device 26b9 (rev a1)
|
||||||
|
[...]
|
||||||
|
Memory at f9000000 (32-bit, non-prefetchable) [size=16M]
|
||||||
|
Memory at 46000000000 (64-bit, prefetchable) [size=64G]
|
||||||
|
Memory at 48040000000 (64-bit, prefetchable) [size=32M]
|
||||||
|
[...]
|
||||||
|
```
|
||||||
|
|
||||||
|
When using multiple PCI segments, the 32-bit mmio address space available to
|
||||||
|
be allocated to VFIO devices is equally split between all PCI segments by
|
||||||
|
default. This can be tuned with the `--pci-segment` flag. The following example
|
||||||
|
demonstrates a guest with two PCI segments. 2/3 of the 32-bit mmio address
|
||||||
|
space is available for use by devices on PCI segment 0 and 1/3 of the 32-bit
|
||||||
|
mmio address space is available for use by devices on PCI segment 1.
|
||||||
|
```
|
||||||
|
--platform num_pci_segments=2
|
||||||
|
--pci-segment pci_segment=0,mmio32_aperture_weight=2
|
||||||
|
--pci-segment pci_segment=1,mmio32_aperture_weight=1
|
||||||
|
```
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
The purpose of this document is to illustrate how to test vhost-user-net
|
The purpose of this document is to illustrate how to test vhost-user-net
|
||||||
in cloud-hypervisor with OVS/DPDK as the backend. This document was
|
in cloud-hypervisor with OVS/DPDK as the backend. This document was
|
||||||
tested with Open vSwitch v2.13.1, DPDK v19.11.3, and Cloud Hypervisor
|
tested with Open vSwitch v2.17.8, DPDK v21.11.4, and Cloud Hypervisor
|
||||||
v15.0 on Ubuntu 20.04.1 (host kernel v5.4.0).
|
v37.0 on Ubuntu 22.04.3 (host kernel v5.15.0).
|
||||||
|
|
||||||
## Framework
|
## Framework
|
||||||
|
|
||||||
@@ -74,8 +74,8 @@ Here is an example how to create a bridge and add two DPDK ports to it
|
|||||||
# create a bridge
|
# create a bridge
|
||||||
ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev
|
ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev
|
||||||
# create two DPDK ports and add them to the bridge
|
# create two DPDK ports and add them to the bridge
|
||||||
ovs-vsctl add-port ovsbr0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuser
|
ovs-vsctl add-port ovsbr0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuserclient options:vhost-server-path=/tmp/vhost-user1
|
||||||
ovs-vsctl add-port ovsbr0 vhost-user2 -- set Interface vhost-user2 type=dpdkvhostuser
|
ovs-vsctl add-port ovsbr0 vhost-user2 -- set Interface vhost-user2 type=dpdkvhostuserclient options:vhost-server-path=/tmp/vhost-user2
|
||||||
# set the number of rx queues
|
# set the number of rx queues
|
||||||
ovs-vsctl set Interface vhost-user1 options:n_rxq=2
|
ovs-vsctl set Interface vhost-user1 options:n_rxq=2
|
||||||
ovs-vsctl set Interface vhost-user2 options:n_rxq=2
|
ovs-vsctl set Interface vhost-user2 options:n_rxq=2
|
||||||
@@ -92,7 +92,7 @@ VMs run in client mode. They connect to the socket created by the `dpdkvhostuser
|
|||||||
--kernel vmlinux \
|
--kernel vmlinux \
|
||||||
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
|
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
|
||||||
--disk path=focal-server-cloudimg-amd64.raw \
|
--disk path=focal-server-cloudimg-amd64.raw \
|
||||||
--net mac=52:54:00:02:d9:01,vhost_user=true,socket=/var/run/openvswitch/vhost-user1,num_queues=4
|
--net mac=52:54:00:02:d9:01,vhost_user=true,socket=/tmp/vhost-user1,num_queues=4,vhost_mode=server
|
||||||
|
|
||||||
# From another terminal. We need to give the cloud-hypervisor binary the NET_ADMIN capabilities for it to set TAP interfaces up on the host.
|
# From another terminal. We need to give the cloud-hypervisor binary the NET_ADMIN capabilities for it to set TAP interfaces up on the host.
|
||||||
./cloud-hypervisor \
|
./cloud-hypervisor \
|
||||||
@@ -101,21 +101,21 @@ VMs run in client mode. They connect to the socket created by the `dpdkvhostuser
|
|||||||
--kernel vmlinux \
|
--kernel vmlinux \
|
||||||
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
|
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
|
||||||
--disk path=focal-server-cloudimg-amd64.raw \
|
--disk path=focal-server-cloudimg-amd64.raw \
|
||||||
--net mac=52:54:20:11:C5:02,vhost_user=true,socket=/var/run/openvswitch/vhost-user2,num_queues=4
|
--net mac=52:54:20:11:C5:02,vhost_user=true,socket=/tmp/vhost-user2,num_queues=4,vhost_mode=server
|
||||||
```
|
```
|
||||||
|
|
||||||
_Setup VM1_
|
_Setup VM1_
|
||||||
```bash
|
```bash
|
||||||
# From inside the guest
|
# From inside the guest
|
||||||
sudo ip addr add 172.100.0.1/24 dev ens2
|
sudo ip addr add 172.100.0.1/24 dev ens3
|
||||||
sudo ip link set up dev ens2
|
sudo ip link set up dev ens3
|
||||||
```
|
```
|
||||||
|
|
||||||
_Setup VM2_
|
_Setup VM2_
|
||||||
```bash
|
```bash
|
||||||
# From inside the guest
|
# From inside the guest
|
||||||
sudo ip addr add 172.100.0.2/24 dev ens2
|
sudo ip addr add 172.100.0.2/24 dev ens3
|
||||||
sudo ip link set up dev ens2
|
sudo ip link set up dev ens3
|
||||||
```
|
```
|
||||||
|
|
||||||
_Ping VM1 from VM2_
|
_Ping VM1 from VM2_
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# VSOCK support
|
# VSOCK support
|
||||||
|
|
||||||
VSOCK provides a way for guest and host to communicate through a socket. VSOCK sockets support both stream and datagram types.
|
VSOCK provides a way for guest and host to communicate through a socket. `cloud-hypervisor` only supports stream VSOCK sockets.
|
||||||
|
|
||||||
The `virtio-vsock` is based on the [Firecracker](https://github.com/firecracker-microvm/firecracker/blob/main/docs/vsock.md) implementation, where additional details can be found.
|
The `virtio-vsock` is based on the [Firecracker](https://github.com/firecracker-microvm/firecracker/blob/main/docs/vsock.md) implementation, where additional details can be found.
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ authors = ["The Cloud Hypervisor Authors"]
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
flume = "0.10.14"
|
flume = "0.11.0"
|
||||||
libc = "0.2.147"
|
libc = "0.2.153"
|
||||||
once_cell = "1.18.0"
|
once_cell = "1.19.0"
|
||||||
serde = { version = "1.0.168", features = ["rc", "derive"] }
|
serde = { version = "1.0.197", features = ["rc", "derive"] }
|
||||||
serde_json = "1.0.107"
|
serde_json = "1.0.115"
|
||||||
|
|||||||
423
fuzz/Cargo.lock
generated
423
fuzz/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -14,29 +14,26 @@ igvm = []
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
block = { path = "../block" }
|
block = { path = "../block" }
|
||||||
devices = { path = "../devices" }
|
devices = { path = "../devices" }
|
||||||
epoll = "4.3.1"
|
epoll = "4.3.3"
|
||||||
libc = "0.2.150"
|
libc = "0.2.153"
|
||||||
libfuzzer-sys = "0.4.7"
|
libfuzzer-sys = "0.4.7"
|
||||||
linux-loader = { version = "0.10.0", features = ["elf", "bzimage", "pe"] }
|
linux-loader = { version = "0.11.0", features = ["elf", "bzimage", "pe"] }
|
||||||
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
|
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
|
||||||
net_util = { path = "../net_util" }
|
net_util = { path = "../net_util" }
|
||||||
once_cell = "1.19.0"
|
once_cell = "1.19.0"
|
||||||
seccompiler = "0.4.0"
|
seccompiler = "0.4.0"
|
||||||
virtio-devices = { path = "../virtio-devices" }
|
virtio-devices = { path = "../virtio-devices" }
|
||||||
virtio-queue = "0.10.0"
|
virtio-queue = "0.11.0"
|
||||||
vmm = { path = "../vmm" }
|
vmm = { path = "../vmm" }
|
||||||
vmm-sys-util = "0.11.2"
|
vmm-sys-util = "0.12.1"
|
||||||
vm-memory = "0.13.1"
|
vm-memory = "0.14.1"
|
||||||
|
vm-migration = { path = "../vm-migration" }
|
||||||
vm-device = { path = "../vm-device" }
|
vm-device = { path = "../vm-device" }
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
|
|
||||||
[dependencies.cloud-hypervisor]
|
[dependencies.cloud-hypervisor]
|
||||||
path = ".."
|
path = ".."
|
||||||
|
|
||||||
[patch.crates-io]
|
|
||||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" }
|
|
||||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
|
||||||
|
|
||||||
# Prevent this from interfering with workspaces
|
# Prevent this from interfering with workspaces
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["."]
|
members = ["."]
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ use virtio_devices::{Block, VirtioDevice, VirtioInterrupt, VirtioInterruptType};
|
|||||||
use virtio_queue::{Queue, QueueT};
|
use virtio_queue::{Queue, QueueT};
|
||||||
use vm_memory::{bitmap::AtomicBitmap, Bytes, GuestAddress, GuestMemoryAtomic};
|
use vm_memory::{bitmap::AtomicBitmap, Bytes, GuestAddress, GuestMemoryAtomic};
|
||||||
use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
|
use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
||||||
|
|
||||||
@@ -49,6 +50,7 @@ fuzz_target!(|bytes| {
|
|||||||
let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap();
|
let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap();
|
||||||
let disk_file: File = unsafe { File::from_raw_fd(shm) };
|
let disk_file: File = unsafe { File::from_raw_fd(shm) };
|
||||||
let qcow_disk = Box::new(RawFileDiskSync::new(disk_file)) as Box<dyn DiskFile>;
|
let qcow_disk = Box::new(RawFileDiskSync::new(disk_file)) as Box<dyn DiskFile>;
|
||||||
|
let queue_affinity = BTreeMap::new();
|
||||||
let mut block = Block::new(
|
let mut block = Block::new(
|
||||||
"tmp".to_owned(),
|
"tmp".to_owned(),
|
||||||
qcow_disk,
|
qcow_disk,
|
||||||
@@ -62,6 +64,7 @@ fuzz_target!(|bytes| {
|
|||||||
None,
|
None,
|
||||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||||
None,
|
None,
|
||||||
|
queue_affinity,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
use devices::legacy::Cmos;
|
use devices::legacy::Cmos;
|
||||||
use libc::EFD_NONBLOCK;
|
use libc::EFD_NONBLOCK;
|
||||||
use libfuzzer_sys::fuzz_target;
|
use libfuzzer_sys::fuzz_target;
|
||||||
use std::sync::atomic::AtomicBool;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,18 @@ use libfuzzer_sys::fuzz_target;
|
|||||||
use micro_http::Request;
|
use micro_http::Request;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::sync::mpsc::{channel, Receiver};
|
use std::sync::mpsc::{channel, Receiver};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use vmm::api::{http::*, ApiRequest, ApiResponsePayload};
|
use vm_migration::MigratableError;
|
||||||
|
use vmm::api::{
|
||||||
|
http::*, ApiRequest, RequestHandler, VmInfoResponse, VmReceiveMigrationData,
|
||||||
|
VmSendMigrationData, VmmPingResponse,
|
||||||
|
};
|
||||||
|
use vmm::config::RestoreConfig;
|
||||||
|
use vmm::vm::{Error as VmError, VmState};
|
||||||
|
use vmm::vm_config::*;
|
||||||
use vmm::{EpollContext, EpollDispatch};
|
use vmm::{EpollContext, EpollDispatch};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
@@ -69,6 +78,208 @@ fn generate_request(bytes: &[u8]) -> Option<Request> {
|
|||||||
Request::try_from(&request, None).ok()
|
Request::try_from(&request, None).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct StubApiRequestHandler;
|
||||||
|
|
||||||
|
impl RequestHandler for StubApiRequestHandler {
|
||||||
|
fn vm_create(&mut self, _: Arc<Mutex<VmConfig>>) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_boot(&mut self) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_pause(&mut self) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_resume(&mut self) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_snapshot(&mut self, _: &str) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_restore(&mut self, _: RestoreConfig) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||||
|
fn vm_coredump(&mut self, _: &str) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_shutdown(&mut self) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_reboot(&mut self) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_info(&self) -> Result<VmInfoResponse, VmError> {
|
||||||
|
Ok(VmInfoResponse {
|
||||||
|
config: Arc::new(Mutex::new(VmConfig {
|
||||||
|
cpus: CpusConfig {
|
||||||
|
boot_vcpus: 1,
|
||||||
|
max_vcpus: 1,
|
||||||
|
topology: None,
|
||||||
|
kvm_hyperv: false,
|
||||||
|
max_phys_bits: 46,
|
||||||
|
affinity: None,
|
||||||
|
features: CpuFeatures::default(),
|
||||||
|
},
|
||||||
|
memory: MemoryConfig {
|
||||||
|
size: 536_870_912,
|
||||||
|
mergeable: false,
|
||||||
|
hotplug_method: HotplugMethod::Acpi,
|
||||||
|
hotplug_size: None,
|
||||||
|
hotplugged_size: None,
|
||||||
|
shared: false,
|
||||||
|
hugepages: false,
|
||||||
|
hugepage_size: None,
|
||||||
|
prefault: false,
|
||||||
|
zones: None,
|
||||||
|
thp: true,
|
||||||
|
},
|
||||||
|
payload: Some(PayloadConfig {
|
||||||
|
kernel: Some(PathBuf::from("/path/to/kernel")),
|
||||||
|
firmware: None,
|
||||||
|
cmdline: None,
|
||||||
|
initramfs: None,
|
||||||
|
#[cfg(feature = "igvm")]
|
||||||
|
igvm: None,
|
||||||
|
}),
|
||||||
|
rate_limit_groups: None,
|
||||||
|
disks: None,
|
||||||
|
net: None,
|
||||||
|
rng: RngConfig {
|
||||||
|
src: PathBuf::from("/dev/urandom"),
|
||||||
|
iommu: false,
|
||||||
|
},
|
||||||
|
balloon: None,
|
||||||
|
fs: None,
|
||||||
|
pmem: None,
|
||||||
|
serial: ConsoleConfig {
|
||||||
|
file: None,
|
||||||
|
mode: ConsoleOutputMode::Null,
|
||||||
|
iommu: false,
|
||||||
|
socket: None,
|
||||||
|
},
|
||||||
|
console: ConsoleConfig {
|
||||||
|
file: None,
|
||||||
|
mode: ConsoleOutputMode::Tty,
|
||||||
|
iommu: false,
|
||||||
|
socket: None,
|
||||||
|
},
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
debug_console: DebugConsoleConfig::default(),
|
||||||
|
devices: None,
|
||||||
|
user_devices: None,
|
||||||
|
vdpa: None,
|
||||||
|
vsock: None,
|
||||||
|
pvpanic: false,
|
||||||
|
iommu: false,
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
sgx_epc: None,
|
||||||
|
numa: None,
|
||||||
|
watchdog: false,
|
||||||
|
#[cfg(feature = "guest_debug")]
|
||||||
|
gdb: false,
|
||||||
|
pci_segments: None,
|
||||||
|
platform: None,
|
||||||
|
tpm: None,
|
||||||
|
preserved_fds: None,
|
||||||
|
})),
|
||||||
|
state: VmState::Running,
|
||||||
|
memory_actual_size: 0,
|
||||||
|
device_tree: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vmm_ping(&self) -> VmmPingResponse {
|
||||||
|
VmmPingResponse {
|
||||||
|
build_version: String::new(),
|
||||||
|
version: String::new(),
|
||||||
|
pid: 0,
|
||||||
|
features: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_delete(&mut self) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vmm_shutdown(&mut self) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_resize(&mut self, _: Option<u8>, _: Option<u64>, _: Option<u64>) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_resize_zone(&mut self, _: String, _: u64) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_add_device(&mut self, _: DeviceConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_add_user_device(&mut self, _: UserDeviceConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_remove_device(&mut self, _: String) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_add_disk(&mut self, _: DiskConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_add_fs(&mut self, _: FsConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_add_pmem(&mut self, _: PmemConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_add_net(&mut self, _: NetConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_add_vdpa(&mut self, _: VdpaConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_add_vsock(&mut self, _: VsockConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_counters(&mut self) -> Result<Option<Vec<u8>>, VmError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_power_button(&mut self) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_receive_migration(&mut self, _: VmReceiveMigrationData) -> Result<(), MigratableError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_send_migration(&mut self, _: VmSendMigrationData) -> Result<(), MigratableError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vm_nmi(&mut self) -> Result<(), VmError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receiver<ApiRequest>) {
|
fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receiver<ApiRequest>) {
|
||||||
let mut epoll = EpollContext::new().unwrap();
|
let mut epoll = EpollContext::new().unwrap();
|
||||||
epoll.add_event(&exit_evt, EpollDispatch::Exit).unwrap();
|
epoll.add_event(&exit_evt, EpollDispatch::Exit).unwrap();
|
||||||
@@ -98,89 +309,7 @@ fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receive
|
|||||||
EpollDispatch::Api => {
|
EpollDispatch::Api => {
|
||||||
for _ in 0..api_evt.read().unwrap() {
|
for _ in 0..api_evt.read().unwrap() {
|
||||||
let api_request = api_receiver.recv().unwrap();
|
let api_request = api_receiver.recv().unwrap();
|
||||||
match api_request {
|
api_request(&mut StubApiRequestHandler).unwrap();
|
||||||
ApiRequest::VmCreate(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmDelete(sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmBoot(sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmShutdown(sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmReboot(sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmInfo(sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmmPing(sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmPause(sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmResume(sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmSnapshot(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmRestore(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmmShutdown(sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmResize(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmResizeZone(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmAddDevice(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmAddUserDevice(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmRemoveDevice(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmAddDisk(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmAddFs(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmAddPmem(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmAddNet(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmAddVdpa(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmAddVsock(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmCounters(sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmReceiveMigration(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmSendMigration(_, sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
ApiRequest::VmPowerButton(sender) => {
|
|
||||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
use libfuzzer_sys::fuzz_target;
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
|||||||
@@ -12,28 +12,28 @@ sev_snp = ["igvm_parser", "igvm_defs"]
|
|||||||
tdx = []
|
tdx = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.81"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.5.0"
|
||||||
igvm_defs = { git = "https://github.com/microsoft/igvm", branch = "main", package = "igvm_defs", optional = true }
|
igvm_defs = { git = "https://github.com/microsoft/igvm", branch = "main", package = "igvm_defs", optional = true }
|
||||||
igvm_parser = { git = "https://github.com/microsoft/igvm", branch = "main", package = "igvm", optional = true }
|
igvm_parser = { git = "https://github.com/microsoft/igvm", branch = "main", package = "igvm", optional = true }
|
||||||
libc = "0.2.147"
|
libc = "0.2.153"
|
||||||
log = "0.4.20"
|
log = "0.4.21"
|
||||||
kvm-ioctls = { version = "0.13.0", optional = true }
|
kvm-bindings = { version = "0.8.1", optional = true, features = ["serde"] }
|
||||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
|
kvm-ioctls = { version = "0.17.0", optional = true }
|
||||||
mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||||
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
||||||
serde = { version = "1.0.168", features = ["rc", "derive"] }
|
serde = { version = "1.0.197", features = ["rc", "derive"] }
|
||||||
serde_with = { version = "3.4.0", default-features = false, features = ["macros"] }
|
serde_with = { version = "3.7.0", default-features = false, features = ["macros"] }
|
||||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||||
vm-memory = { version = "0.13.1", features = ["backend-mmap", "backend-atomic"] }
|
vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-atomic"] }
|
||||||
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
|
vmm-sys-util = { version = "0.12.1", features = ["with-serde"] }
|
||||||
thiserror = "1.0.40"
|
thiserror = "1.0.58"
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
||||||
optional = true
|
optional = true
|
||||||
version = "1.20.0"
|
version = "1.21.0"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
|
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.10.0"
|
env_logger = "0.11.3"
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::{CpuState, GicState, HypervisorDeviceError, HypervisorVmError};
|
use crate::{CpuState, GicState, HypervisorDeviceError, HypervisorVmError};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
pub mod gic;
|
pub mod gic;
|
||||||
|
|||||||
@@ -10,10 +10,8 @@
|
|||||||
// CMP-Compare Two Operands
|
// CMP-Compare Two Operands
|
||||||
//
|
//
|
||||||
|
|
||||||
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
|
||||||
use crate::arch::x86::emulator::instructions::*;
|
use crate::arch::x86::emulator::instructions::*;
|
||||||
use crate::arch::x86::regs::*;
|
use crate::arch::x86::regs::*;
|
||||||
use crate::arch::x86::Exception;
|
|
||||||
|
|
||||||
// CMP affects OF, SF, ZF, AF, PF and CF
|
// CMP affects OF, SF, ZF, AF, PF and CF
|
||||||
const FLAGS_MASK: u64 = CF | PF | AF | ZF | SF | OF;
|
const FLAGS_MASK: u64 = CF | PF | AF | ZF | SF | OF;
|
||||||
@@ -211,8 +209,6 @@ impl<T: CpuStateManager> InstructionHandler<T> for Cmp_rm64_imm8 {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(unused_mut)]
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::arch::x86::emulator::mock_vmm::*;
|
use crate::arch::x86::emulator::mock_vmm::*;
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,7 @@
|
|||||||
// Copies the second operand (source operand) to the first operand (destination operand).
|
// Copies the second operand (source operand) to the first operand (destination operand).
|
||||||
//
|
//
|
||||||
|
|
||||||
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
|
||||||
use crate::arch::x86::emulator::instructions::*;
|
use crate::arch::x86::emulator::instructions::*;
|
||||||
use crate::arch::x86::Exception;
|
|
||||||
|
|
||||||
macro_rules! mov_rm_r {
|
macro_rules! mov_rm_r {
|
||||||
($bound:ty) => {
|
($bound:ty) => {
|
||||||
@@ -271,7 +269,6 @@ impl<T: CpuStateManager> InstructionHandler<T> for Mov_RAX_moffs64 {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(unused_mut)]
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::arch::x86::emulator::mock_vmm::*;
|
use crate::arch::x86::emulator::mock_vmm::*;
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,8 @@
|
|||||||
// MOVS - Move Data from String to String
|
// MOVS - Move Data from String to String
|
||||||
//
|
//
|
||||||
|
|
||||||
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
|
||||||
use crate::arch::x86::emulator::instructions::*;
|
use crate::arch::x86::emulator::instructions::*;
|
||||||
use crate::arch::x86::regs::DF;
|
use crate::arch::x86::regs::DF;
|
||||||
use crate::arch::x86::Exception;
|
|
||||||
|
|
||||||
macro_rules! movs {
|
macro_rules! movs {
|
||||||
($bound:ty) => {
|
($bound:ty) => {
|
||||||
@@ -102,7 +100,6 @@ impl<T: CpuStateManager> InstructionHandler<T> for Movsb_m8_m8 {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(unused_mut)]
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::arch::x86::emulator::mock_vmm::*;
|
use crate::arch::x86::emulator::mock_vmm::*;
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,7 @@
|
|||||||
// OR - Logical inclusive OR
|
// OR - Logical inclusive OR
|
||||||
//
|
//
|
||||||
|
|
||||||
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
|
||||||
use crate::arch::x86::emulator::instructions::*;
|
use crate::arch::x86::emulator::instructions::*;
|
||||||
use crate::arch::x86::Exception;
|
|
||||||
|
|
||||||
macro_rules! or_rm_r {
|
macro_rules! or_rm_r {
|
||||||
($bound:ty) => {
|
($bound:ty) => {
|
||||||
@@ -52,7 +50,6 @@ impl<T: CpuStateManager> InstructionHandler<T> for Or_rm8_r8 {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(unused_mut)]
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use crate::arch::x86::emulator::mock_vmm::*;
|
use crate::arch::x86::emulator::mock_vmm::*;
|
||||||
|
|||||||
@@ -648,13 +648,9 @@ impl<'a, T: CpuStateManager> Emulator<'a, T> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod mock_vmm {
|
mod mock_vmm {
|
||||||
#![allow(unused_mut)]
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::arch::emulator::{EmulationError, PlatformEmulator};
|
use crate::arch::x86::emulator::EmulatorCpuState as CpuState;
|
||||||
use crate::arch::x86::emulator::{Emulator, EmulatorCpuState as CpuState};
|
|
||||||
use crate::arch::x86::gdt::{gdt_entry, segment_from_gdt};
|
use crate::arch::x86::gdt::{gdt_entry, segment_from_gdt};
|
||||||
use crate::arch::x86::Exception;
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -772,7 +768,6 @@ mod mock_vmm {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(unused_mut)]
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::arch::x86::emulator::mock_vmm::*;
|
use crate::arch::x86::emulator::mock_vmm::*;
|
||||||
|
|
||||||
|
|||||||
@@ -311,3 +311,17 @@ pub struct MsrEntry {
|
|||||||
pub index: u32,
|
pub index: u32,
|
||||||
pub data: u64,
|
pub data: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[serde_with::serde_as]
|
||||||
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct XsaveState {
|
||||||
|
#[serde_as(as = "[_; 1024usize]")]
|
||||||
|
pub region: [u32; 1024usize],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for XsaveState {
|
||||||
|
fn default() -> Self {
|
||||||
|
// SAFETY: this is plain old data structure
|
||||||
|
unsafe { ::std::mem::zeroed() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE-BSD-3-Clause file.
|
// found in the LICENSE-BSD-3-Clause file.
|
||||||
|
|
||||||
|
|||||||
@@ -107,14 +107,28 @@ pub enum HypervisorCpuError {
|
|||||||
///
|
///
|
||||||
/// Setting Saved Processor Extended States error
|
/// Setting Saved Processor Extended States error
|
||||||
///
|
///
|
||||||
|
#[cfg(feature = "kvm")]
|
||||||
#[error("Failed to set Saved Processor Extended States: {0}")]
|
#[error("Failed to set Saved Processor Extended States: {0}")]
|
||||||
SetXsaveState(#[source] anyhow::Error),
|
SetXsaveState(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
/// Getting Saved Processor Extended States error
|
/// Getting Saved Processor Extended States error
|
||||||
///
|
///
|
||||||
|
#[cfg(feature = "kvm")]
|
||||||
#[error("Failed to get Saved Processor Extended States: {0}")]
|
#[error("Failed to get Saved Processor Extended States: {0}")]
|
||||||
GetXsaveState(#[source] anyhow::Error),
|
GetXsaveState(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
|
/// Getting the VP state components error
|
||||||
|
///
|
||||||
|
#[cfg(feature = "mshv")]
|
||||||
|
#[error("Failed to get VP State Components: {0}")]
|
||||||
|
GetAllVpStateComponents(#[source] anyhow::Error),
|
||||||
|
///
|
||||||
|
/// Setting the VP state components error
|
||||||
|
///
|
||||||
|
#[cfg(feature = "mshv")]
|
||||||
|
#[error("Failed to set VP State Components: {0}")]
|
||||||
|
SetAllVpStateComponents(#[source] anyhow::Error),
|
||||||
|
///
|
||||||
/// Setting Extended Control Registers error
|
/// Setting Extended Control Registers error
|
||||||
///
|
///
|
||||||
#[error("Failed to set Extended Control Registers: {0}")]
|
#[error("Failed to set Extended Control Registers: {0}")]
|
||||||
@@ -272,18 +286,23 @@ pub enum HypervisorCpuError {
|
|||||||
///
|
///
|
||||||
#[error("Failed to get CPUID entries: {0}")]
|
#[error("Failed to get CPUID entries: {0}")]
|
||||||
GetCpuidVales(#[source] anyhow::Error),
|
GetCpuidVales(#[source] anyhow::Error),
|
||||||
|
///
|
||||||
|
/// Setting SEV control register error
|
||||||
|
///
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
#[error("Failed to set sev control register: {0}")]
|
||||||
|
SetSevControlRegister(#[source] anyhow::Error),
|
||||||
|
|
||||||
|
/// Error injecting NMI
|
||||||
|
///
|
||||||
|
#[error("Failed to inject NMI")]
|
||||||
|
Nmi(#[source] anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum VmExit<'a> {
|
pub enum VmExit {
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
IoOut(u16 /* port */, &'a [u8] /* data */),
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
IoIn(u16 /* port */, &'a mut [u8] /* data */),
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
IoapicEoi(u8 /* vector */),
|
IoapicEoi(u8 /* vector */),
|
||||||
MmioRead(u64 /* address */, &'a mut [u8]),
|
|
||||||
MmioWrite(u64 /* address */, &'a [u8]),
|
|
||||||
Ignore,
|
Ignore,
|
||||||
Reset,
|
Reset,
|
||||||
Shutdown,
|
Shutdown,
|
||||||
@@ -495,4 +514,14 @@ pub trait Vcpu: Send + Sync {
|
|||||||
) -> Result<[u32; 4]> {
|
) -> Result<[u32; 4]> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "mshv")]
|
||||||
|
fn set_sev_control_register(&self, _reg: u64) -> Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
///
|
||||||
|
/// Trigger NMI interrupt
|
||||||
|
///
|
||||||
|
fn nmi(&self) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ use std::sync::Arc;
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
///
|
|
||||||
///
|
|
||||||
pub enum HypervisorError {
|
pub enum HypervisorError {
|
||||||
///
|
///
|
||||||
/// Hypervisor availability check error
|
/// Hypervisor availability check error
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
mod dist_regs;
|
mod dist_regs;
|
||||||
mod icc_regs;
|
mod icc_regs;
|
||||||
@@ -6,7 +8,7 @@ mod redist_regs;
|
|||||||
|
|
||||||
use crate::arch::aarch64::gic::{Error, Result, Vgic, VgicConfig};
|
use crate::arch::aarch64::gic::{Error, Result, Vgic, VgicConfig};
|
||||||
use crate::device::HypervisorDeviceError;
|
use crate::device::HypervisorDeviceError;
|
||||||
use crate::kvm::{kvm_bindings, KvmVm};
|
use crate::kvm::KvmVm;
|
||||||
use crate::{CpuState, Vm};
|
use crate::{CpuState, Vm};
|
||||||
use dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
use dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
||||||
use icc_regs::{get_icc_regs, set_icc_regs};
|
use icc_regs::{get_icc_regs, set_icc_regs};
|
||||||
@@ -14,7 +16,6 @@ use kvm_ioctls::DeviceFd;
|
|||||||
use redist_regs::{construct_gicr_typers, get_redist_regs, set_redist_regs};
|
use redist_regs::{construct_gicr_typers, get_redist_regs, set_redist_regs};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::convert::TryInto;
|
|
||||||
|
|
||||||
const GITS_CTLR: u32 = 0x0000;
|
const GITS_CTLR: u32 = 0x0000;
|
||||||
const GITS_IIDR: u32 = 0x0004;
|
const GITS_IIDR: u32 = 0x0004;
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ use crate::{arm64_core_reg_id, offset_of};
|
|||||||
use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd};
|
use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
use std::convert::TryInto;
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
@@ -38,7 +36,6 @@ use std::os::unix::io::RawFd;
|
|||||||
use std::result;
|
use std::result;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
@@ -47,7 +44,7 @@ use vmm_sys_util::eventfd::EventFd;
|
|||||||
pub mod x86_64;
|
pub mod x86_64;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use crate::arch::x86::{
|
use crate::arch::x86::{
|
||||||
CpuIdEntry, FpuState, LapicState, MsrEntry, SpecialRegisters, StandardRegisters,
|
CpuIdEntry, FpuState, LapicState, MsrEntry, SpecialRegisters, StandardRegisters, XsaveState,
|
||||||
NUM_IOAPIC_PINS,
|
NUM_IOAPIC_PINS,
|
||||||
};
|
};
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
@@ -66,13 +63,11 @@ use kvm_bindings::{
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use x86_64::check_required_kvm_extensions;
|
use x86_64::check_required_kvm_extensions;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub use x86_64::{CpuId, ExtendedControlRegisters, MsrEntries, VcpuKvmState, Xsave};
|
pub use x86_64::{CpuId, ExtendedControlRegisters, MsrEntries, VcpuKvmState};
|
||||||
// aarch64 dependencies
|
// aarch64 dependencies
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
pub mod aarch64;
|
pub mod aarch64;
|
||||||
pub use kvm_bindings;
|
pub use kvm_bindings;
|
||||||
#[cfg(feature = "tdx")]
|
|
||||||
use kvm_bindings::KVMIO;
|
|
||||||
pub use kvm_bindings::{
|
pub use kvm_bindings::{
|
||||||
kvm_clock_data, kvm_create_device, kvm_device_type_KVM_DEV_TYPE_VFIO, kvm_guest_debug,
|
kvm_clock_data, kvm_create_device, kvm_device_type_KVM_DEV_TYPE_VFIO, kvm_guest_debug,
|
||||||
kvm_irq_routing, kvm_irq_routing_entry, kvm_mp_state, kvm_userspace_memory_region,
|
kvm_irq_routing, kvm_irq_routing_entry, kvm_mp_state, kvm_userspace_memory_region,
|
||||||
@@ -86,6 +81,8 @@ use kvm_bindings::{
|
|||||||
KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP2_MASK,
|
KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP2_MASK,
|
||||||
KVM_REG_ARM_CORE, KVM_REG_SIZE_U128, KVM_REG_SIZE_U32, KVM_REG_SIZE_U64,
|
KVM_REG_ARM_CORE, KVM_REG_SIZE_U128, KVM_REG_SIZE_U32, KVM_REG_SIZE_U64,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
use kvm_bindings::{kvm_run__bindgen_ty_1, KVMIO};
|
||||||
pub use kvm_ioctls;
|
pub use kvm_ioctls;
|
||||||
pub use kvm_ioctls::{Cap, Kvm};
|
pub use kvm_ioctls::{Cap, Kvm};
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
@@ -105,6 +102,15 @@ pub use {
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
const KVM_CAP_SGX_ATTRIBUTE: u32 = 196;
|
const KVM_CAP_SGX_ATTRIBUTE: u32 = 196;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
use vmm_sys_util::ioctl_io_nr;
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "tdx"), target_arch = "x86_64"))]
|
||||||
|
use vmm_sys_util::ioctl_ioc_nr;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
ioctl_io_nr!(KVM_NMI, kvm_bindings::KVMIO, 0x9a);
|
||||||
|
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
const KVM_EXIT_TDX: u32 = 50;
|
const KVM_EXIT_TDX: u32 = 50;
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
@@ -169,6 +175,52 @@ pub struct TdxCapabilities {
|
|||||||
pub cpuid_configs: [TdxCpuidConfig; TDX_MAX_NR_CPUID_CONFIGS],
|
pub cpuid_configs: [TdxCpuidConfig; TDX_MAX_NR_CPUID_CONFIGS],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct KvmTdxExit {
|
||||||
|
pub type_: u32,
|
||||||
|
pub pad: u32,
|
||||||
|
pub u: KvmTdxExitU,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub union KvmTdxExitU {
|
||||||
|
pub vmcall: KvmTdxExitVmcall,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Copy, Clone, PartialEq)]
|
||||||
|
pub struct KvmTdxExitVmcall {
|
||||||
|
pub type_: u64,
|
||||||
|
pub subfunction: u64,
|
||||||
|
pub reg_mask: u64,
|
||||||
|
pub in_r12: u64,
|
||||||
|
pub in_r13: u64,
|
||||||
|
pub in_r14: u64,
|
||||||
|
pub in_r15: u64,
|
||||||
|
pub in_rbx: u64,
|
||||||
|
pub in_rdi: u64,
|
||||||
|
pub in_rsi: u64,
|
||||||
|
pub in_r8: u64,
|
||||||
|
pub in_r9: u64,
|
||||||
|
pub in_rdx: u64,
|
||||||
|
pub status_code: u64,
|
||||||
|
pub out_r11: u64,
|
||||||
|
pub out_r12: u64,
|
||||||
|
pub out_r13: u64,
|
||||||
|
pub out_r14: u64,
|
||||||
|
pub out_r15: u64,
|
||||||
|
pub out_rbx: u64,
|
||||||
|
pub out_rdi: u64,
|
||||||
|
pub out_rsi: u64,
|
||||||
|
pub out_r8: u64,
|
||||||
|
pub out_r9: u64,
|
||||||
|
pub out_rdx: u64,
|
||||||
|
}
|
||||||
|
|
||||||
impl From<kvm_userspace_memory_region> for UserMemoryRegion {
|
impl From<kvm_userspace_memory_region> for UserMemoryRegion {
|
||||||
fn from(region: kvm_userspace_memory_region) -> Self {
|
fn from(region: kvm_userspace_memory_region) -> Self {
|
||||||
let mut flags = USER_MEMORY_REGION_READ;
|
let mut flags = USER_MEMORY_REGION_READ;
|
||||||
@@ -402,12 +454,12 @@ impl vm::Vm for KvmVm {
|
|||||||
id: u8,
|
id: u8,
|
||||||
vm_ops: Option<Arc<dyn VmOps>>,
|
vm_ops: Option<Arc<dyn VmOps>>,
|
||||||
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
|
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
|
||||||
let vc = self
|
let fd = self
|
||||||
.fd
|
.fd
|
||||||
.create_vcpu(id as u64)
|
.create_vcpu(id as u64)
|
||||||
.map_err(|e| vm::HypervisorVmError::CreateVcpu(e.into()))?;
|
.map_err(|e| vm::HypervisorVmError::CreateVcpu(e.into()))?;
|
||||||
let vcpu = KvmVcpu {
|
let vcpu = KvmVcpu {
|
||||||
fd: vc,
|
fd: Arc::new(Mutex::new(fd)),
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
msrs: self.msrs.clone(),
|
msrs: self.msrs.clone(),
|
||||||
vm_ops,
|
vm_ops,
|
||||||
@@ -1117,7 +1169,7 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
|||||||
|
|
||||||
/// Vcpu struct for KVM
|
/// Vcpu struct for KVM
|
||||||
pub struct KvmVcpu {
|
pub struct KvmVcpu {
|
||||||
fd: VcpuFd,
|
fd: Arc<Mutex<VcpuFd>>,
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
msrs: Vec<MsrEntry>,
|
msrs: Vec<MsrEntry>,
|
||||||
vm_ops: Option<Arc<dyn vm::VmOps>>,
|
vm_ops: Option<Arc<dyn vm::VmOps>>,
|
||||||
@@ -1145,6 +1197,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
fn get_regs(&self) -> cpu::Result<StandardRegisters> {
|
fn get_regs(&self) -> cpu::Result<StandardRegisters> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.fd
|
.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.get_regs()
|
.get_regs()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))?
|
.map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))?
|
||||||
.into())
|
.into())
|
||||||
@@ -1164,71 +1218,78 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
// These actually are the general-purpose registers of the Armv8-a
|
// These actually are the general-purpose registers of the Armv8-a
|
||||||
// architecture (i.e x0-x30 if used as a 64bit register or w0-30 when used as a 32bit register).
|
// architecture (i.e x0-x30 if used as a 64bit register or w0-30 when used as a 32bit register).
|
||||||
for i in 0..31 {
|
for i in 0..31 {
|
||||||
state.regs.regs[i] = self
|
let mut bytes = [0_u8; 8];
|
||||||
.fd
|
self.fd
|
||||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
.lock()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
.unwrap()
|
||||||
.try_into()
|
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||||
.unwrap();
|
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||||
|
state.regs.regs[i] = u64::from_le_bytes(bytes);
|
||||||
off += std::mem::size_of::<u64>();
|
off += std::mem::size_of::<u64>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are now entering the "Other register" section of the ARMv8-a architecture.
|
// We are now entering the "Other register" section of the ARMv8-a architecture.
|
||||||
// First one, stack pointer.
|
// First one, stack pointer.
|
||||||
let off = offset_of!(user_pt_regs, sp);
|
let off = offset_of!(user_pt_regs, sp);
|
||||||
state.regs.sp = self
|
let mut bytes = [0_u8; 8];
|
||||||
.fd
|
self.fd
|
||||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
.lock()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
.unwrap()
|
||||||
.try_into()
|
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||||
.unwrap();
|
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||||
|
state.regs.sp = u64::from_le_bytes(bytes);
|
||||||
|
|
||||||
// Second one, the program counter.
|
// Second one, the program counter.
|
||||||
let off = offset_of!(user_pt_regs, pc);
|
let off = offset_of!(user_pt_regs, pc);
|
||||||
state.regs.pc = self
|
let mut bytes = [0_u8; 8];
|
||||||
.fd
|
self.fd
|
||||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
.lock()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
.unwrap()
|
||||||
.try_into()
|
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||||
.unwrap();
|
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||||
|
state.regs.pc = u64::from_le_bytes(bytes);
|
||||||
|
|
||||||
// Next is the processor state.
|
// Next is the processor state.
|
||||||
let off = offset_of!(user_pt_regs, pstate);
|
let off = offset_of!(user_pt_regs, pstate);
|
||||||
state.regs.pstate = self
|
let mut bytes = [0_u8; 8];
|
||||||
.fd
|
self.fd
|
||||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
.lock()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
.unwrap()
|
||||||
.try_into()
|
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||||
.unwrap();
|
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||||
|
state.regs.pstate = u64::from_le_bytes(bytes);
|
||||||
|
|
||||||
// The stack pointer associated with EL1
|
// The stack pointer associated with EL1
|
||||||
let off = offset_of!(kvm_regs, sp_el1);
|
let off = offset_of!(kvm_regs, sp_el1);
|
||||||
state.sp_el1 = self
|
let mut bytes = [0_u8; 8];
|
||||||
.fd
|
self.fd
|
||||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
.lock()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
.unwrap()
|
||||||
.try_into()
|
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||||
.unwrap();
|
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||||
|
state.sp_el1 = u64::from_le_bytes(bytes);
|
||||||
|
|
||||||
// Exception Link Register for EL1, when taking an exception to EL1, this register
|
// Exception Link Register for EL1, when taking an exception to EL1, this register
|
||||||
// holds the address to which to return afterwards.
|
// holds the address to which to return afterwards.
|
||||||
let off = offset_of!(kvm_regs, elr_el1);
|
let off = offset_of!(kvm_regs, elr_el1);
|
||||||
state.elr_el1 = self
|
let mut bytes = [0_u8; 8];
|
||||||
.fd
|
self.fd
|
||||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
.lock()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
.unwrap()
|
||||||
.try_into()
|
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||||
.unwrap();
|
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||||
|
state.elr_el1 = u64::from_le_bytes(bytes);
|
||||||
|
|
||||||
// Saved Program Status Registers, there are 5 of them used in the kernel.
|
// Saved Program Status Registers, there are 5 of them used in the kernel.
|
||||||
let mut off = offset_of!(kvm_regs, spsr);
|
let mut off = offset_of!(kvm_regs, spsr);
|
||||||
for i in 0..KVM_NR_SPSR as usize {
|
for i in 0..KVM_NR_SPSR as usize {
|
||||||
state.spsr[i] = self
|
let mut bytes = [0_u8; 8];
|
||||||
.fd
|
self.fd
|
||||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
.lock()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
.unwrap()
|
||||||
.try_into()
|
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||||
.unwrap();
|
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||||
|
state.spsr[i] = u64::from_le_bytes(bytes);
|
||||||
off += std::mem::size_of::<u64>();
|
off += std::mem::size_of::<u64>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1236,30 +1297,35 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
// https://elixir.free-electrons.com/linux/v4.9.62/source/arch/arm64/include/uapi/asm/kvm.h#L53
|
// https://elixir.free-electrons.com/linux/v4.9.62/source/arch/arm64/include/uapi/asm/kvm.h#L53
|
||||||
let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs);
|
let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs);
|
||||||
for i in 0..32 {
|
for i in 0..32 {
|
||||||
state.fp_regs.vregs[i] = self
|
let mut bytes = [0_u8; 16];
|
||||||
.fd
|
self.fd
|
||||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U128, off))
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U128, off), &mut bytes)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||||
|
state.fp_regs.vregs[i] = u128::from_le_bytes(bytes);
|
||||||
off += mem::size_of::<u128>();
|
off += mem::size_of::<u128>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Floating-point Status Register
|
// Floating-point Status Register
|
||||||
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
|
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
|
||||||
state.fp_regs.fpsr = self
|
let mut bytes = [0_u8; 4];
|
||||||
.fd
|
self.fd
|
||||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off))
|
.lock()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
.unwrap()
|
||||||
.try_into()
|
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off), &mut bytes)
|
||||||
.unwrap();
|
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||||
|
state.fp_regs.fpsr = u32::from_le_bytes(bytes);
|
||||||
|
|
||||||
// Floating-point Control Register
|
// Floating-point Control Register
|
||||||
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
|
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
|
||||||
state.fp_regs.fpcr = self
|
let mut bytes = [0_u8; 4];
|
||||||
.fd
|
self.fd
|
||||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off))
|
.lock()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
.unwrap()
|
||||||
.try_into()
|
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off), &mut bytes)
|
||||||
.unwrap();
|
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||||
|
state.fp_regs.fpcr = u32::from_le_bytes(bytes);
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1270,6 +1336,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> {
|
fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> {
|
||||||
let regs = (*regs).into();
|
let regs = (*regs).into();
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_regs(®s)
|
.set_regs(®s)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into()))
|
||||||
}
|
}
|
||||||
@@ -1286,9 +1354,11 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
let mut off = offset_of!(user_pt_regs, regs);
|
let mut off = offset_of!(user_pt_regs, regs);
|
||||||
for i in 0..31 {
|
for i in 0..31 {
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_one_reg(
|
.set_one_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||||
state.regs.regs[i].into(),
|
&state.regs.regs[i].to_le_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
off += std::mem::size_of::<u64>();
|
off += std::mem::size_of::<u64>();
|
||||||
@@ -1296,50 +1366,62 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
|
|
||||||
let off = offset_of!(user_pt_regs, sp);
|
let off = offset_of!(user_pt_regs, sp);
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_one_reg(
|
.set_one_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||||
state.regs.sp.into(),
|
&state.regs.sp.to_le_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
|
|
||||||
let off = offset_of!(user_pt_regs, pc);
|
let off = offset_of!(user_pt_regs, pc);
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_one_reg(
|
.set_one_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||||
state.regs.pc.into(),
|
&state.regs.pc.to_le_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
|
|
||||||
let off = offset_of!(user_pt_regs, pstate);
|
let off = offset_of!(user_pt_regs, pstate);
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_one_reg(
|
.set_one_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||||
state.regs.pstate.into(),
|
&state.regs.pstate.to_le_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
|
|
||||||
let off = offset_of!(kvm_regs, sp_el1);
|
let off = offset_of!(kvm_regs, sp_el1);
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_one_reg(
|
.set_one_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||||
state.sp_el1.into(),
|
&state.sp_el1.to_le_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
|
|
||||||
let off = offset_of!(kvm_regs, elr_el1);
|
let off = offset_of!(kvm_regs, elr_el1);
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_one_reg(
|
.set_one_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||||
state.elr_el1.into(),
|
&state.elr_el1.to_le_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
|
|
||||||
let mut off = offset_of!(kvm_regs, spsr);
|
let mut off = offset_of!(kvm_regs, spsr);
|
||||||
for i in 0..KVM_NR_SPSR as usize {
|
for i in 0..KVM_NR_SPSR as usize {
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_one_reg(
|
.set_one_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||||
state.spsr[i].into(),
|
&state.spsr[i].to_le_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
off += std::mem::size_of::<u64>();
|
off += std::mem::size_of::<u64>();
|
||||||
@@ -1348,9 +1430,11 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs);
|
let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs);
|
||||||
for i in 0..32 {
|
for i in 0..32 {
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_one_reg(
|
.set_one_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U128, off),
|
arm64_core_reg_id!(KVM_REG_SIZE_U128, off),
|
||||||
state.fp_regs.vregs[i],
|
&state.fp_regs.vregs[i].to_le_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
off += mem::size_of::<u128>();
|
off += mem::size_of::<u128>();
|
||||||
@@ -1358,17 +1442,21 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
|
|
||||||
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
|
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_one_reg(
|
.set_one_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
|
arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
|
||||||
state.fp_regs.fpsr.into(),
|
&state.fp_regs.fpsr.to_le_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
|
|
||||||
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
|
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_one_reg(
|
.set_one_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
|
arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
|
||||||
state.fp_regs.fpcr.into(),
|
&state.fp_regs.fpcr.to_le_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1381,6 +1469,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
fn get_sregs(&self) -> cpu::Result<SpecialRegisters> {
|
fn get_sregs(&self) -> cpu::Result<SpecialRegisters> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.fd
|
.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.get_sregs()
|
.get_sregs()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))?
|
.map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))?
|
||||||
.into())
|
.into())
|
||||||
@@ -1393,6 +1483,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
fn set_sregs(&self, sregs: &SpecialRegisters) -> cpu::Result<()> {
|
fn set_sregs(&self, sregs: &SpecialRegisters) -> cpu::Result<()> {
|
||||||
let sregs = (*sregs).into();
|
let sregs = (*sregs).into();
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_sregs(&sregs)
|
.set_sregs(&sregs)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into()))
|
||||||
}
|
}
|
||||||
@@ -1404,6 +1496,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
fn get_fpu(&self) -> cpu::Result<FpuState> {
|
fn get_fpu(&self) -> cpu::Result<FpuState> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.fd
|
.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.get_fpu()
|
.get_fpu()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))?
|
.map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))?
|
||||||
.into())
|
.into())
|
||||||
@@ -1416,6 +1510,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
fn set_fpu(&self, fpu: &FpuState) -> cpu::Result<()> {
|
fn set_fpu(&self, fpu: &FpuState) -> cpu::Result<()> {
|
||||||
let fpu: kvm_bindings::kvm_fpu = (*fpu).clone().into();
|
let fpu: kvm_bindings::kvm_fpu = (*fpu).clone().into();
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_fpu(&fpu)
|
.set_fpu(&fpu)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into()))
|
||||||
}
|
}
|
||||||
@@ -1431,6 +1527,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
.map_err(|_| cpu::HypervisorCpuError::SetCpuid(anyhow!("failed to create CpuId")))?;
|
.map_err(|_| cpu::HypervisorCpuError::SetCpuid(anyhow!("failed to create CpuId")))?;
|
||||||
|
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_cpuid2(&kvm_cpuid)
|
.set_cpuid2(&kvm_cpuid)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into()))
|
||||||
}
|
}
|
||||||
@@ -1449,6 +1547,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.enable_cap(&cap)
|
.enable_cap(&cap)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::EnableHyperVSyncIc(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::EnableHyperVSyncIc(e.into()))
|
||||||
}
|
}
|
||||||
@@ -1460,6 +1560,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
fn get_cpuid2(&self, num_entries: usize) -> cpu::Result<Vec<CpuIdEntry>> {
|
fn get_cpuid2(&self, num_entries: usize) -> cpu::Result<Vec<CpuIdEntry>> {
|
||||||
let kvm_cpuid = self
|
let kvm_cpuid = self
|
||||||
.fd
|
.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.get_cpuid2(num_entries)
|
.get_cpuid2(num_entries)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetCpuid(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::GetCpuid(e.into()))?;
|
||||||
|
|
||||||
@@ -1475,6 +1577,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
fn get_lapic(&self) -> cpu::Result<LapicState> {
|
fn get_lapic(&self) -> cpu::Result<LapicState> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.fd
|
.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.get_lapic()
|
.get_lapic()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))?
|
.map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))?
|
||||||
.into())
|
.into())
|
||||||
@@ -1487,6 +1591,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
fn set_lapic(&self, klapic: &LapicState) -> cpu::Result<()> {
|
fn set_lapic(&self, klapic: &LapicState) -> cpu::Result<()> {
|
||||||
let klapic: kvm_bindings::kvm_lapic_state = (*klapic).clone().into();
|
let klapic: kvm_bindings::kvm_lapic_state = (*klapic).clone().into();
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_lapic(&klapic)
|
.set_lapic(&klapic)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into()))
|
||||||
}
|
}
|
||||||
@@ -1500,6 +1606,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
let mut kvm_msrs = MsrEntries::from_entries(&kvm_msrs).unwrap();
|
let mut kvm_msrs = MsrEntries::from_entries(&kvm_msrs).unwrap();
|
||||||
let succ = self
|
let succ = self
|
||||||
.fd
|
.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.get_msrs(&mut kvm_msrs)
|
.get_msrs(&mut kvm_msrs)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetMsrEntries(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::GetMsrEntries(e.into()))?;
|
||||||
|
|
||||||
@@ -1522,6 +1630,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
let kvm_msrs: Vec<kvm_msr_entry> = msrs.iter().map(|e| (*e).into()).collect();
|
let kvm_msrs: Vec<kvm_msr_entry> = msrs.iter().map(|e| (*e).into()).collect();
|
||||||
let kvm_msrs = MsrEntries::from_entries(&kvm_msrs).unwrap();
|
let kvm_msrs = MsrEntries::from_entries(&kvm_msrs).unwrap();
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_msrs(&kvm_msrs)
|
.set_msrs(&kvm_msrs)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into()))
|
||||||
}
|
}
|
||||||
@@ -1532,6 +1642,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
fn get_mp_state(&self) -> cpu::Result<MpState> {
|
fn get_mp_state(&self) -> cpu::Result<MpState> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.fd
|
.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.get_mp_state()
|
.get_mp_state()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetMpState(e.into()))?
|
.map_err(|e| cpu::HypervisorCpuError::GetMpState(e.into()))?
|
||||||
.into())
|
.into())
|
||||||
@@ -1542,6 +1654,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
///
|
///
|
||||||
fn set_mp_state(&self, mp_state: MpState) -> cpu::Result<()> {
|
fn set_mp_state(&self, mp_state: MpState) -> cpu::Result<()> {
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_mp_state(mp_state.into())
|
.set_mp_state(mp_state.into())
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetMpState(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetMpState(e.into()))
|
||||||
}
|
}
|
||||||
@@ -1553,6 +1667,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
fn translate_gva(&self, gva: u64, _flags: u64) -> cpu::Result<(u64, u32)> {
|
fn translate_gva(&self, gva: u64, _flags: u64) -> cpu::Result<(u64, u32)> {
|
||||||
let tr = self
|
let tr = self
|
||||||
.fd
|
.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.translate_gva(gva)
|
.translate_gva(gva)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::TranslateVirtualAddress(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::TranslateVirtualAddress(e.into()))?;
|
||||||
// tr.valid is set if the GVA is mapped to valid GPA.
|
// tr.valid is set if the GVA is mapped to valid GPA.
|
||||||
@@ -1569,7 +1685,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
/// Triggers the running of the current virtual CPU returning an exit reason.
|
/// Triggers the running of the current virtual CPU returning an exit reason.
|
||||||
///
|
///
|
||||||
fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
|
fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
|
||||||
match self.fd.run() {
|
match self.fd.lock().unwrap().run() {
|
||||||
Ok(run) => match run {
|
Ok(run) => match run {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
VcpuExit::IoIn(addr, data) => {
|
VcpuExit::IoIn(addr, data) => {
|
||||||
@@ -1580,7 +1696,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(cpu::VmExit::IoIn(addr, data))
|
Ok(cpu::VmExit::Ignore)
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
VcpuExit::IoOut(addr, data) => {
|
VcpuExit::IoOut(addr, data) => {
|
||||||
@@ -1591,7 +1707,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(cpu::VmExit::IoOut(addr, data))
|
Ok(cpu::VmExit::Ignore)
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
VcpuExit::IoapicEoi(vector) => Ok(cpu::VmExit::IoapicEoi(vector)),
|
VcpuExit::IoapicEoi(vector) => Ok(cpu::VmExit::IoapicEoi(vector)),
|
||||||
@@ -1609,7 +1725,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
Ok(cpu::VmExit::Shutdown)
|
Ok(cpu::VmExit::Shutdown)
|
||||||
} else {
|
} else {
|
||||||
Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
||||||
"Unexpected system event with type 0x{:x}, flags 0x{:x}",
|
"Unexpected system event with type 0x{:x}, flags 0x{:x?}",
|
||||||
event_type,
|
event_type,
|
||||||
flags
|
flags
|
||||||
)))
|
)))
|
||||||
@@ -1624,7 +1740,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(cpu::VmExit::MmioRead(addr, data))
|
Ok(cpu::VmExit::Ignore)
|
||||||
}
|
}
|
||||||
VcpuExit::MmioWrite(addr, data) => {
|
VcpuExit::MmioWrite(addr, data) => {
|
||||||
if let Some(vm_ops) = &self.vm_ops {
|
if let Some(vm_ops) = &self.vm_ops {
|
||||||
@@ -1634,7 +1750,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(cpu::VmExit::MmioWrite(addr, data))
|
Ok(cpu::VmExit::Ignore)
|
||||||
}
|
}
|
||||||
VcpuExit::Hyperv => Ok(cpu::VmExit::Hyperv),
|
VcpuExit::Hyperv => Ok(cpu::VmExit::Hyperv),
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
@@ -1663,7 +1779,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
/// potential soft lockups when being resumed.
|
/// potential soft lockups when being resumed.
|
||||||
///
|
///
|
||||||
fn notify_guest_clock_paused(&self) -> cpu::Result<()> {
|
fn notify_guest_clock_paused(&self) -> cpu::Result<()> {
|
||||||
if let Err(e) = self.fd.kvmclock_ctrl() {
|
if let Err(e) = self.fd.lock().unwrap().kvmclock_ctrl() {
|
||||||
// Linux kernel returns -EINVAL if the PV clock isn't yet initialised
|
// Linux kernel returns -EINVAL if the PV clock isn't yet initialised
|
||||||
// which could be because we're still in firmware or the guest doesn't
|
// which could be because we're still in firmware or the guest doesn't
|
||||||
// use KVM clock.
|
// use KVM clock.
|
||||||
@@ -1725,6 +1841,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_guest_debug(&dbg)
|
.set_guest_debug(&dbg)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))
|
||||||
}
|
}
|
||||||
@@ -1732,6 +1850,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> {
|
fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> {
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.vcpu_init(kvi)
|
.vcpu_init(kvi)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::VcpuInit(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::VcpuInit(e.into()))
|
||||||
}
|
}
|
||||||
@@ -1743,6 +1863,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
fn get_reg_list(&self, reg_list: &mut RegList) -> cpu::Result<()> {
|
fn get_reg_list(&self, reg_list: &mut RegList) -> cpu::Result<()> {
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.get_reg_list(reg_list)
|
.get_reg_list(reg_list)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetRegList(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::GetRegList(e.into()))
|
||||||
}
|
}
|
||||||
@@ -1773,12 +1895,13 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
| KVM_REG_ARM64_SYSREG_CRN_MASK
|
| KVM_REG_ARM64_SYSREG_CRN_MASK
|
||||||
| KVM_REG_ARM64_SYSREG_CRM_MASK
|
| KVM_REG_ARM64_SYSREG_CRM_MASK
|
||||||
| KVM_REG_ARM64_SYSREG_OP2_MASK)) as u64);
|
| KVM_REG_ARM64_SYSREG_OP2_MASK)) as u64);
|
||||||
Ok(self
|
let mut bytes = [0_u8; 8];
|
||||||
.fd
|
self.fd
|
||||||
.get_one_reg(id)
|
.lock()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?
|
.unwrap()
|
||||||
.try_into()
|
.get_one_reg(id, &mut bytes)
|
||||||
.unwrap())
|
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?;
|
||||||
|
Ok(u64::from_le_bytes(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -1803,9 +1926,11 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
// Get the register index of the PSTATE (Processor State) register.
|
// Get the register index of the PSTATE (Processor State) register.
|
||||||
let pstate = offset_of!(user_pt_regs, pstate) + kreg_off;
|
let pstate = offset_of!(user_pt_regs, pstate) + kreg_off;
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_one_reg(
|
.set_one_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate),
|
arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate),
|
||||||
PSTATE_FAULT_BITS_64.into(),
|
&PSTATE_FAULT_BITS_64.to_le_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
|
|
||||||
@@ -1814,7 +1939,12 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
// Setting the PC (Processor Counter) to the current program address (kernel address).
|
// Setting the PC (Processor Counter) to the current program address (kernel address).
|
||||||
let pc = offset_of!(user_pt_regs, pc) + kreg_off;
|
let pc = offset_of!(user_pt_regs, pc) + kreg_off;
|
||||||
self.fd
|
self.fd
|
||||||
.set_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), boot_ip.into())
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.set_one_reg(
|
||||||
|
arm64_core_reg_id!(KVM_REG_SIZE_U64, pc),
|
||||||
|
&boot_ip.to_le_bytes(),
|
||||||
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
|
|
||||||
// Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
|
// Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
|
||||||
@@ -1823,9 +1953,11 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
// We are choosing to place it the end of DRAM. See `get_fdt_addr`.
|
// We are choosing to place it the end of DRAM. See `get_fdt_addr`.
|
||||||
let regs0 = offset_of!(user_pt_regs, regs) + kreg_off;
|
let regs0 = offset_of!(user_pt_regs, regs) + kreg_off;
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_one_reg(
|
.set_one_reg(
|
||||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
|
arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
|
||||||
fdt_start.into(),
|
&fdt_start.to_le_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||||
}
|
}
|
||||||
@@ -1974,6 +2106,8 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
let mut sys_regs: Vec<Register> = Vec::new();
|
let mut sys_regs: Vec<Register> = Vec::new();
|
||||||
let mut reg_list = RegList::new(500).unwrap();
|
let mut reg_list = RegList::new(500).unwrap();
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.get_reg_list(&mut reg_list)
|
.get_reg_list(&mut reg_list)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetRegList(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::GetRegList(e.into()))?;
|
||||||
|
|
||||||
@@ -1990,14 +2124,15 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
// register list, we are simply calling KVM_GET_ONE_REG.
|
// register list, we are simply calling KVM_GET_ONE_REG.
|
||||||
let indices = reg_list.as_slice();
|
let indices = reg_list.as_slice();
|
||||||
for index in indices.iter() {
|
for index in indices.iter() {
|
||||||
|
let mut bytes = [0_u8; 8];
|
||||||
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.get_one_reg(*index, &mut bytes)
|
||||||
|
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?;
|
||||||
sys_regs.push(kvm_bindings::kvm_one_reg {
|
sys_regs.push(kvm_bindings::kvm_one_reg {
|
||||||
id: *index,
|
id: *index,
|
||||||
addr: self
|
addr: u64::from_le_bytes(bytes),
|
||||||
.fd
|
|
||||||
.get_one_reg(*index)
|
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?
|
|
||||||
.try_into()
|
|
||||||
.unwrap(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2107,7 +2242,9 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
// Set system registers
|
// Set system registers
|
||||||
for reg in &state.sys_regs {
|
for reg in &state.sys_regs {
|
||||||
self.fd
|
self.fd
|
||||||
.set_one_reg(reg.id, reg.addr.into())
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.set_one_reg(reg.id, ®.addr.to_le_bytes())
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetSysRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetSysRegister(e.into()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2121,15 +2258,20 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
///
|
///
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
fn tdx_init(&self, hob_address: u64) -> cpu::Result<()> {
|
fn tdx_init(&self, hob_address: u64) -> cpu::Result<()> {
|
||||||
tdx_command(&self.fd.as_raw_fd(), TdxCommand::InitVcpu, 0, hob_address)
|
tdx_command(
|
||||||
.map_err(cpu::HypervisorCpuError::InitializeTdx)
|
&self.fd.lock().unwrap().as_raw_fd(),
|
||||||
|
TdxCommand::InitVcpu,
|
||||||
|
0,
|
||||||
|
hob_address,
|
||||||
|
)
|
||||||
|
.map_err(cpu::HypervisorCpuError::InitializeTdx)
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Set the "immediate_exit" state
|
/// Set the "immediate_exit" state
|
||||||
///
|
///
|
||||||
fn set_immediate_exit(&self, exit: bool) {
|
fn set_immediate_exit(&self, exit: bool) {
|
||||||
self.fd.set_kvm_immediate_exit(exit.into());
|
self.fd.lock().unwrap().set_kvm_immediate_exit(exit.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -2137,9 +2279,15 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
///
|
///
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
fn get_tdx_exit_details(&mut self) -> cpu::Result<TdxExitDetails> {
|
fn get_tdx_exit_details(&mut self) -> cpu::Result<TdxExitDetails> {
|
||||||
let kvm_run = self.fd.get_kvm_run();
|
let mut fd = self.fd.as_ref().lock().unwrap();
|
||||||
|
let kvm_run = fd.get_kvm_run();
|
||||||
// SAFETY: accessing a union field in a valid structure
|
// SAFETY: accessing a union field in a valid structure
|
||||||
let tdx_vmcall = unsafe { &mut kvm_run.__bindgen_anon_1.tdx.u.vmcall };
|
let tdx_vmcall = unsafe {
|
||||||
|
&mut (*((&mut kvm_run.__bindgen_anon_1) as *mut kvm_run__bindgen_ty_1
|
||||||
|
as *mut KvmTdxExit))
|
||||||
|
.u
|
||||||
|
.vmcall
|
||||||
|
};
|
||||||
|
|
||||||
tdx_vmcall.status_code = TDG_VP_VMCALL_INVALID_OPERAND;
|
tdx_vmcall.status_code = TDG_VP_VMCALL_INVALID_OPERAND;
|
||||||
|
|
||||||
@@ -2161,9 +2309,15 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
///
|
///
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
fn set_tdx_status(&mut self, status: TdxExitStatus) {
|
fn set_tdx_status(&mut self, status: TdxExitStatus) {
|
||||||
let kvm_run = self.fd.get_kvm_run();
|
let mut fd = self.fd.as_ref().lock().unwrap();
|
||||||
|
let kvm_run = fd.get_kvm_run();
|
||||||
// SAFETY: accessing a union field in a valid structure
|
// SAFETY: accessing a union field in a valid structure
|
||||||
let tdx_vmcall = unsafe { &mut kvm_run.__bindgen_anon_1.tdx.u.vmcall };
|
let tdx_vmcall = unsafe {
|
||||||
|
&mut (*((&mut kvm_run.__bindgen_anon_1) as *mut kvm_run__bindgen_ty_1
|
||||||
|
as *mut KvmTdxExit))
|
||||||
|
.u
|
||||||
|
.vmcall
|
||||||
|
};
|
||||||
|
|
||||||
tdx_vmcall.status_code = match status {
|
tdx_vmcall.status_code = match status {
|
||||||
TdxExitStatus::Success => TDG_VP_VMCALL_SUCCESS,
|
TdxExitStatus::Success => TDG_VP_VMCALL_SUCCESS,
|
||||||
@@ -2205,7 +2359,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
addr: 0x0,
|
addr: 0x0,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
};
|
};
|
||||||
self.fd.has_device_attr(&cpu_attr).is_ok()
|
self.fd.lock().unwrap().has_device_attr(&cpu_attr).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
@@ -2223,9 +2377,13 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
flags: 0,
|
flags: 0,
|
||||||
};
|
};
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_device_attr(&cpu_attr_irq)
|
.set_device_attr(&cpu_attr_irq)
|
||||||
.map_err(|_| cpu::HypervisorCpuError::InitializePmu)?;
|
.map_err(|_| cpu::HypervisorCpuError::InitializePmu)?;
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_device_attr(&cpu_attr)
|
.set_device_attr(&cpu_attr)
|
||||||
.map_err(|_| cpu::HypervisorCpuError::InitializePmu)
|
.map_err(|_| cpu::HypervisorCpuError::InitializePmu)
|
||||||
}
|
}
|
||||||
@@ -2235,7 +2393,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
/// Get the frequency of the TSC if available
|
/// Get the frequency of the TSC if available
|
||||||
///
|
///
|
||||||
fn tsc_khz(&self) -> cpu::Result<Option<u32>> {
|
fn tsc_khz(&self) -> cpu::Result<Option<u32>> {
|
||||||
match self.fd.get_tsc_khz() {
|
match self.fd.lock().unwrap().get_tsc_khz() {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if e.errno() == libc::EIO {
|
if e.errno() == libc::EIO {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@@ -2252,7 +2410,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
/// Set the frequency of the TSC if available
|
/// Set the frequency of the TSC if available
|
||||||
///
|
///
|
||||||
fn set_tsc_khz(&self, freq: u32) -> cpu::Result<()> {
|
fn set_tsc_khz(&self, freq: u32) -> cpu::Result<()> {
|
||||||
match self.fd.set_tsc_khz(freq) {
|
match self.fd.lock().unwrap().set_tsc_khz(freq) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if e.errno() == libc::EIO {
|
if e.errno() == libc::EIO {
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -2263,6 +2421,23 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
///
|
||||||
|
/// Trigger NMI interrupt
|
||||||
|
///
|
||||||
|
fn nmi(&self) -> cpu::Result<()> {
|
||||||
|
match self.fd.lock().unwrap().nmi() {
|
||||||
|
Err(e) => {
|
||||||
|
if e.errno() == libc::EIO {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(cpu::HypervisorCpuError::Nmi(e.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KvmVcpu {
|
impl KvmVcpu {
|
||||||
@@ -2270,19 +2445,26 @@ impl KvmVcpu {
|
|||||||
///
|
///
|
||||||
/// X86 specific call that returns the vcpu's current "xsave struct".
|
/// X86 specific call that returns the vcpu's current "xsave struct".
|
||||||
///
|
///
|
||||||
fn get_xsave(&self) -> cpu::Result<Xsave> {
|
fn get_xsave(&self) -> cpu::Result<XsaveState> {
|
||||||
self.fd
|
Ok(self
|
||||||
|
.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.get_xsave()
|
.get_xsave()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))?
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// X86 specific call that sets the vcpu's current "xsave struct".
|
/// X86 specific call that sets the vcpu's current "xsave struct".
|
||||||
///
|
///
|
||||||
fn set_xsave(&self, xsave: &Xsave) -> cpu::Result<()> {
|
fn set_xsave(&self, xsave: &XsaveState) -> cpu::Result<()> {
|
||||||
|
let xsave: kvm_bindings::kvm_xsave = (*xsave).clone().into();
|
||||||
self.fd
|
self.fd
|
||||||
.set_xsave(xsave)
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.set_xsave(&xsave)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2292,6 +2474,8 @@ impl KvmVcpu {
|
|||||||
///
|
///
|
||||||
fn get_xcrs(&self) -> cpu::Result<ExtendedControlRegisters> {
|
fn get_xcrs(&self) -> cpu::Result<ExtendedControlRegisters> {
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.get_xcrs()
|
.get_xcrs()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into()))
|
||||||
}
|
}
|
||||||
@@ -2302,6 +2486,8 @@ impl KvmVcpu {
|
|||||||
///
|
///
|
||||||
fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> {
|
fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> {
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_xcrs(xcrs)
|
.set_xcrs(xcrs)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
|
||||||
}
|
}
|
||||||
@@ -2313,6 +2499,8 @@ impl KvmVcpu {
|
|||||||
///
|
///
|
||||||
fn get_vcpu_events(&self) -> cpu::Result<VcpuEvents> {
|
fn get_vcpu_events(&self) -> cpu::Result<VcpuEvents> {
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.get_vcpu_events()
|
.get_vcpu_events()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into()))
|
||||||
}
|
}
|
||||||
@@ -2324,6 +2512,8 @@ impl KvmVcpu {
|
|||||||
///
|
///
|
||||||
fn set_vcpu_events(&self, events: &VcpuEvents) -> cpu::Result<()> {
|
fn set_vcpu_events(&self, events: &VcpuEvents) -> cpu::Result<()> {
|
||||||
self.fd
|
self.fd
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.set_vcpu_events(events)
|
.set_vcpu_events(events)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetVcpuEvents(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetVcpuEvents(e.into()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
use crate::arch::x86::{
|
use crate::arch::x86::{
|
||||||
CpuIdEntry, DescriptorTable, FpuState, LapicState, MsrEntry, SegmentRegister, SpecialRegisters,
|
CpuIdEntry, DescriptorTable, FpuState, LapicState, MsrEntry, SegmentRegister, SpecialRegisters,
|
||||||
StandardRegisters, CPUID_FLAG_VALID_INDEX,
|
StandardRegisters, XsaveState, CPUID_FLAG_VALID_INDEX,
|
||||||
};
|
};
|
||||||
use crate::kvm::{Cap, Kvm, KvmError, KvmResult};
|
use crate::kvm::{Cap, Kvm, KvmError, KvmResult};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -23,7 +23,7 @@ pub use {
|
|||||||
kvm_bindings::kvm_lapic_state, kvm_bindings::kvm_mp_state as MpState,
|
kvm_bindings::kvm_lapic_state, kvm_bindings::kvm_mp_state as MpState,
|
||||||
kvm_bindings::kvm_msr_entry, kvm_bindings::kvm_regs, kvm_bindings::kvm_segment,
|
kvm_bindings::kvm_msr_entry, kvm_bindings::kvm_regs, kvm_bindings::kvm_segment,
|
||||||
kvm_bindings::kvm_sregs, kvm_bindings::kvm_vcpu_events as VcpuEvents,
|
kvm_bindings::kvm_sregs, kvm_bindings::kvm_vcpu_events as VcpuEvents,
|
||||||
kvm_bindings::kvm_xcrs as ExtendedControlRegisters, kvm_bindings::kvm_xsave as Xsave,
|
kvm_bindings::kvm_xcrs as ExtendedControlRegisters, kvm_bindings::kvm_xsave,
|
||||||
kvm_bindings::CpuId, kvm_bindings::MsrList, kvm_bindings::Msrs as MsrEntries,
|
kvm_bindings::CpuId, kvm_bindings::MsrList, kvm_bindings::Msrs as MsrEntries,
|
||||||
kvm_bindings::KVM_CPUID_FLAG_SIGNIFCANT_INDEX,
|
kvm_bindings::KVM_CPUID_FLAG_SIGNIFCANT_INDEX,
|
||||||
};
|
};
|
||||||
@@ -64,7 +64,7 @@ pub struct VcpuKvmState {
|
|||||||
pub sregs: kvm_sregs,
|
pub sregs: kvm_sregs,
|
||||||
pub fpu: FpuState,
|
pub fpu: FpuState,
|
||||||
pub lapic_state: LapicState,
|
pub lapic_state: LapicState,
|
||||||
pub xsave: Xsave,
|
pub xsave: XsaveState,
|
||||||
pub xcrs: ExtendedControlRegisters,
|
pub xcrs: ExtendedControlRegisters,
|
||||||
pub mp_state: MpState,
|
pub mp_state: MpState,
|
||||||
pub tsc_khz: Option<u32>,
|
pub tsc_khz: Option<u32>,
|
||||||
@@ -330,3 +330,18 @@ impl From<MsrEntry> for kvm_msr_entry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<kvm_xsave> for XsaveState {
|
||||||
|
fn from(s: kvm_xsave) -> Self {
|
||||||
|
Self { region: s.region }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<XsaveState> for kvm_xsave {
|
||||||
|
fn from(s: XsaveState) -> Self {
|
||||||
|
Self {
|
||||||
|
region: s.region,
|
||||||
|
extra: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate anyhow;
|
extern crate anyhow;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[allow(unused_imports)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
@@ -134,6 +134,7 @@ pub const USER_MEMORY_REGION_READ: u32 = 1;
|
|||||||
pub const USER_MEMORY_REGION_WRITE: u32 = 1 << 1;
|
pub const USER_MEMORY_REGION_WRITE: u32 = 1 << 1;
|
||||||
pub const USER_MEMORY_REGION_EXECUTE: u32 = 1 << 2;
|
pub const USER_MEMORY_REGION_EXECUTE: u32 = 1 << 2;
|
||||||
pub const USER_MEMORY_REGION_LOG_DIRTY: u32 = 1 << 3;
|
pub const USER_MEMORY_REGION_LOG_DIRTY: u32 = 1 << 3;
|
||||||
|
pub const USER_MEMORY_REGION_ADJUSTABLE: u32 = 1 << 4;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum MpState {
|
pub enum MpState {
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ use crate::hypervisor;
|
|||||||
use crate::vec_with_array_field;
|
use crate::vec_with_array_field;
|
||||||
use crate::vm::{self, InterruptSourceConfig, VmOps};
|
use crate::vm::{self, InterruptSourceConfig, VmOps};
|
||||||
use crate::HypervisorType;
|
use crate::HypervisorType;
|
||||||
pub use mshv_bindings::*;
|
use mshv_bindings::*;
|
||||||
use mshv_ioctls::{set_registers_64, Mshv, NoDatamatch, VcpuFd, VmFd, VmType};
|
use mshv_ioctls::{set_registers_64, InterruptRequest, Mshv, NoDatamatch, VcpuFd, VmFd, VmType};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
@@ -29,9 +29,13 @@ pub mod x86_64;
|
|||||||
#[cfg(feature = "sev_snp")]
|
#[cfg(feature = "sev_snp")]
|
||||||
use snp_constants::*;
|
use snp_constants::*;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
use crate::ClockData;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ClockData, CpuState, IoEventAddress, IrqRoutingEntry, MpState, UserMemoryRegion,
|
CpuState, IoEventAddress, IrqRoutingEntry, MpState, UserMemoryRegion,
|
||||||
USER_MEMORY_REGION_EXECUTE, USER_MEMORY_REGION_READ, USER_MEMORY_REGION_WRITE,
|
USER_MEMORY_REGION_ADJUSTABLE, USER_MEMORY_REGION_EXECUTE, USER_MEMORY_REGION_READ,
|
||||||
|
USER_MEMORY_REGION_WRITE,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "sev_snp")]
|
#[cfg(feature = "sev_snp")]
|
||||||
use igvm_defs::IGVM_VHS_SNP_ID_BLOCK;
|
use igvm_defs::IGVM_VHS_SNP_ID_BLOCK;
|
||||||
@@ -73,6 +77,9 @@ impl From<mshv_user_mem_region> for UserMemoryRegion {
|
|||||||
if region.flags & HV_MAP_GPA_EXECUTABLE != 0 {
|
if region.flags & HV_MAP_GPA_EXECUTABLE != 0 {
|
||||||
flags |= USER_MEMORY_REGION_EXECUTE;
|
flags |= USER_MEMORY_REGION_EXECUTE;
|
||||||
}
|
}
|
||||||
|
if region.flags & HV_MAP_GPA_ADJUSTABLE != 0 {
|
||||||
|
flags |= USER_MEMORY_REGION_ADJUSTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
UserMemoryRegion {
|
UserMemoryRegion {
|
||||||
guest_phys_addr: (region.guest_pfn << PAGE_SHIFT as u64)
|
guest_phys_addr: (region.guest_pfn << PAGE_SHIFT as u64)
|
||||||
@@ -97,6 +104,9 @@ impl From<UserMemoryRegion> for mshv_user_mem_region {
|
|||||||
if region.flags & USER_MEMORY_REGION_EXECUTE != 0 {
|
if region.flags & USER_MEMORY_REGION_EXECUTE != 0 {
|
||||||
flags |= HV_MAP_GPA_EXECUTABLE;
|
flags |= HV_MAP_GPA_EXECUTABLE;
|
||||||
}
|
}
|
||||||
|
if region.flags & USER_MEMORY_REGION_ADJUSTABLE != 0 {
|
||||||
|
flags |= HV_MAP_GPA_ADJUSTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
mshv_user_mem_region {
|
mshv_user_mem_region {
|
||||||
guest_pfn: region.guest_phys_addr >> PAGE_SHIFT,
|
guest_pfn: region.guest_phys_addr >> PAGE_SHIFT,
|
||||||
@@ -281,25 +291,39 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
|||||||
)
|
)
|
||||||
.map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?;
|
.map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?;
|
||||||
|
|
||||||
let msr_list = self.get_msr_list()?;
|
|
||||||
let num_msrs = msr_list.as_fam_struct_ref().nmsrs as usize;
|
|
||||||
let mut msrs: Vec<MsrEntry> = vec![
|
|
||||||
MsrEntry {
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
num_msrs
|
|
||||||
];
|
|
||||||
let indices = msr_list.as_slice();
|
|
||||||
for (pos, index) in indices.iter().enumerate() {
|
|
||||||
msrs[pos].index = *index;
|
|
||||||
}
|
|
||||||
let vm_fd = Arc::new(fd);
|
let vm_fd = Arc::new(fd);
|
||||||
|
|
||||||
Ok(Arc::new(MshvVm {
|
#[cfg(target_arch = "x86_64")]
|
||||||
fd: vm_fd,
|
{
|
||||||
msrs,
|
let msr_list = self.get_msr_list()?;
|
||||||
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
|
let num_msrs = msr_list.as_fam_struct_ref().nmsrs as usize;
|
||||||
}))
|
let mut msrs: Vec<MsrEntry> = vec![
|
||||||
|
MsrEntry {
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
num_msrs
|
||||||
|
];
|
||||||
|
let indices = msr_list.as_slice();
|
||||||
|
for (pos, index) in indices.iter().enumerate() {
|
||||||
|
msrs[pos].index = *index;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Arc::new(MshvVm {
|
||||||
|
fd: vm_fd,
|
||||||
|
msrs,
|
||||||
|
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
sev_snp_enabled: mshv_vm_type == VmType::Snp,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
{
|
||||||
|
Ok(Arc::new(MshvVm {
|
||||||
|
fd: vm_fd,
|
||||||
|
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a mshv vm object and return the object as Vm trait object
|
/// Create a mshv vm object and return the object as Vm trait object
|
||||||
@@ -317,6 +341,7 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
|||||||
let vm_type = 0;
|
let vm_type = 0;
|
||||||
self.create_vm_with_type(vm_type)
|
self.create_vm_with_type(vm_type)
|
||||||
}
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// Get the supported CpuID
|
/// Get the supported CpuID
|
||||||
///
|
///
|
||||||
@@ -336,10 +361,11 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
|||||||
pub struct MshvVcpu {
|
pub struct MshvVcpu {
|
||||||
fd: VcpuFd,
|
fd: VcpuFd,
|
||||||
vp_index: u8,
|
vp_index: u8,
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
cpuid: Vec<CpuIdEntry>,
|
cpuid: Vec<CpuIdEntry>,
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
msrs: Vec<MsrEntry>,
|
msrs: Vec<MsrEntry>,
|
||||||
vm_ops: Option<Arc<dyn vm::VmOps>>,
|
vm_ops: Option<Arc<dyn vm::VmOps>>,
|
||||||
#[cfg(feature = "sev_snp")]
|
|
||||||
vm_fd: Arc<VmFd>,
|
vm_fd: Arc<VmFd>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,6 +508,7 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
warn!("TRIPLE FAULT");
|
warn!("TRIPLE FAULT");
|
||||||
Ok(cpu::VmExit::Shutdown)
|
Ok(cpu::VmExit::Shutdown)
|
||||||
}
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT => {
|
hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT => {
|
||||||
let info = x.to_ioport_info().unwrap();
|
let info = x.to_ioport_info().unwrap();
|
||||||
let access_info = info.access_info;
|
let access_info = info.access_info;
|
||||||
@@ -572,6 +599,7 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
|
||||||
Ok(cpu::VmExit::Ignore)
|
Ok(cpu::VmExit::Ignore)
|
||||||
}
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
hv_message_type_HVMSG_UNMAPPED_GPA => {
|
hv_message_type_HVMSG_UNMAPPED_GPA => {
|
||||||
let info = x.to_memory_info().unwrap();
|
let info = x.to_memory_info().unwrap();
|
||||||
let insn_len = info.instruction_byte_count as usize;
|
let insn_len = info.instruction_byte_count as usize;
|
||||||
@@ -597,6 +625,70 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
|
|
||||||
Ok(cpu::VmExit::Ignore)
|
Ok(cpu::VmExit::Ignore)
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
hv_message_type_HVMSG_GPA_ATTRIBUTE_INTERCEPT => {
|
||||||
|
let info = x.to_gpa_attribute_info().unwrap();
|
||||||
|
let host_vis = info.__bindgen_anon_1.host_visibility();
|
||||||
|
if host_vis >= HV_MAP_GPA_READABLE | HV_MAP_GPA_WRITABLE {
|
||||||
|
warn!("Ignored attribute intercept with full host visibility");
|
||||||
|
return Ok(cpu::VmExit::Ignore);
|
||||||
|
}
|
||||||
|
|
||||||
|
let num_ranges = info.__bindgen_anon_1.range_count();
|
||||||
|
assert!(num_ranges >= 1);
|
||||||
|
if num_ranges > 1 {
|
||||||
|
return Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
||||||
|
"Unhandled VCPU exit(GPA_ATTRIBUTE_INTERCEPT): Expected num_ranges to be 1 but found num_ranges {:?}",
|
||||||
|
num_ranges
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: we could also deny the request with HvCallCompleteIntercept
|
||||||
|
let mut gpas = Vec::new();
|
||||||
|
let ranges = info.ranges;
|
||||||
|
let (gfn_start, gfn_count) = snp::parse_gpa_range(ranges[0]).unwrap();
|
||||||
|
debug!(
|
||||||
|
"Releasing pages: gfn_start: {:x?}, gfn_count: {:?}",
|
||||||
|
gfn_start, gfn_count
|
||||||
|
);
|
||||||
|
let gpa_start = gfn_start * HV_PAGE_SIZE as u64;
|
||||||
|
for i in 0..gfn_count {
|
||||||
|
gpas.push(gpa_start + i * HV_PAGE_SIZE as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut gpa_list =
|
||||||
|
vec_with_array_field::<mshv_modify_gpa_host_access, u64>(gpas.len());
|
||||||
|
gpa_list[0].gpa_list_size = gpas.len() as u64;
|
||||||
|
gpa_list[0].host_access = host_vis;
|
||||||
|
gpa_list[0].acquire = 0;
|
||||||
|
gpa_list[0].flags = 0;
|
||||||
|
|
||||||
|
// SAFETY: gpa_list initialized with gpas.len() and now it is being turned into
|
||||||
|
// gpas_slice with gpas.len() again. It is guaranteed to be large enough to hold
|
||||||
|
// everything from gpas.
|
||||||
|
unsafe {
|
||||||
|
let gpas_slice: &mut [u64] = gpa_list[0].gpa_list.as_mut_slice(gpas.len());
|
||||||
|
gpas_slice.copy_from_slice(gpas.as_slice());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.vm_fd
|
||||||
|
.modify_gpa_host_access(&gpa_list[0])
|
||||||
|
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
||||||
|
"Unhandled VCPU exit: attribute intercept - couldn't modify host access {}", e
|
||||||
|
)))?;
|
||||||
|
Ok(cpu::VmExit::Ignore)
|
||||||
|
}
|
||||||
|
hv_message_type_HVMSG_UNACCEPTED_GPA => {
|
||||||
|
let info = x.to_memory_info().unwrap();
|
||||||
|
let gva = info.guest_virtual_address;
|
||||||
|
let gpa = info.guest_physical_address;
|
||||||
|
|
||||||
|
Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
||||||
|
"Unhandled VCPU exit: Unaccepted GPA({:x}) found at GVA({:x})",
|
||||||
|
gpa,
|
||||||
|
gva,
|
||||||
|
)))
|
||||||
|
}
|
||||||
hv_message_type_HVMSG_X64_CPUID_INTERCEPT => {
|
hv_message_type_HVMSG_X64_CPUID_INTERCEPT => {
|
||||||
let info = x.to_cpuid_info().unwrap();
|
let info = x.to_cpuid_info().unwrap();
|
||||||
debug!("cpuid eax: {:x}", { info.rax });
|
debug!("cpuid eax: {:x}", { info.rax });
|
||||||
@@ -617,6 +709,7 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
debug!("Exception Info {:?}", { info.exception_vector });
|
debug!("Exception Info {:?}", { info.exception_vector });
|
||||||
Ok(cpu::VmExit::Ignore)
|
Ok(cpu::VmExit::Ignore)
|
||||||
}
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
hv_message_type_HVMSG_X64_APIC_EOI => {
|
hv_message_type_HVMSG_X64_APIC_EOI => {
|
||||||
let info = x.to_apic_eoi_info().unwrap();
|
let info = x.to_apic_eoi_info().unwrap();
|
||||||
// The kernel should dispatch the EOI to the correct thread.
|
// The kernel should dispatch the EOI to the correct thread.
|
||||||
@@ -1030,13 +1123,14 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
.sev_snp_ap_create(&mshv_ap_create_req)
|
.sev_snp_ap_create(&mshv_ap_create_req)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
|
||||||
|
|
||||||
let mut swei2_rw_gpa_arg = mshv_bindings::mshv_read_write_gpa {
|
let mut swei1_rw_gpa_arg = mshv_bindings::mshv_read_write_gpa {
|
||||||
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
|
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO1_OFFSET,
|
||||||
byte_count: std::mem::size_of::<u64>() as u32,
|
byte_count: std::mem::size_of::<u64>() as u32,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.fd
|
self.fd
|
||||||
.gpa_write(&mut swei2_rw_gpa_arg)
|
.gpa_write(&mut swei1_rw_gpa_arg)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?;
|
||||||
}
|
}
|
||||||
_ => panic!(
|
_ => panic!(
|
||||||
@@ -1066,6 +1160,46 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
fn init_pmu(&self, irq: u32) -> cpu::Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
fn has_pmu_support(&self) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> cpu::Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
fn get_sys_reg(&self, sys_reg: u32) -> cpu::Result<u64> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
fn get_reg_list(&self, reg_list: &mut RegList) -> cpu::Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
fn get_regs(&self) -> cpu::Result<StandardRegisters> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// X86 specific call to setup the CPUID registers.
|
/// X86 specific call to setup the CPUID registers.
|
||||||
@@ -1141,19 +1275,18 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// Set CPU state
|
/// Set CPU state for x86_64 guest.
|
||||||
///
|
///
|
||||||
fn set_state(&self, state: &CpuState) -> cpu::Result<()> {
|
fn set_state(&self, state: &CpuState) -> cpu::Result<()> {
|
||||||
let state: VcpuMshvState = state.clone().into();
|
let mut state: VcpuMshvState = state.clone().into();
|
||||||
self.set_msrs(&state.msrs)?;
|
self.set_msrs(&state.msrs)?;
|
||||||
self.set_vcpu_events(&state.vcpu_events)?;
|
self.set_vcpu_events(&state.vcpu_events)?;
|
||||||
self.set_regs(&state.regs.into())?;
|
self.set_regs(&state.regs.into())?;
|
||||||
self.set_sregs(&state.sregs.into())?;
|
self.set_sregs(&state.sregs.into())?;
|
||||||
self.set_fpu(&state.fpu)?;
|
self.set_fpu(&state.fpu)?;
|
||||||
self.set_xcrs(&state.xcrs)?;
|
self.set_xcrs(&state.xcrs)?;
|
||||||
self.set_lapic(&state.lapic)?;
|
|
||||||
self.set_xsave(&state.xsave)?;
|
|
||||||
// These registers are global and needed to be set only for first VCPU
|
// These registers are global and needed to be set only for first VCPU
|
||||||
// as Microsoft Hypervisor allows setting this regsier for only one VCPU
|
// as Microsoft Hypervisor allows setting this regsier for only one VCPU
|
||||||
if self.vp_index == 0 {
|
if self.vp_index == 0 {
|
||||||
@@ -1164,11 +1297,23 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
self.fd
|
self.fd
|
||||||
.set_debug_regs(&state.dbg)
|
.set_debug_regs(&state.dbg)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))?;
|
||||||
|
self.fd
|
||||||
|
.set_all_vp_state_components(&mut state.vp_states)
|
||||||
|
.map_err(|e| cpu::HypervisorCpuError::SetAllVpStateComponents(e.into()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
///
|
///
|
||||||
/// Get CPU State
|
/// Set CPU state for aarch64 guest.
|
||||||
|
///
|
||||||
|
fn set_state(&self, state: &CpuState) -> cpu::Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
///
|
||||||
|
/// Get CPU State for x86_64 guest
|
||||||
///
|
///
|
||||||
fn state(&self) -> cpu::Result<CpuState> {
|
fn state(&self) -> cpu::Result<CpuState> {
|
||||||
let regs = self.get_regs()?;
|
let regs = self.get_regs()?;
|
||||||
@@ -1178,8 +1323,6 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
let vcpu_events = self.get_vcpu_events()?;
|
let vcpu_events = self.get_vcpu_events()?;
|
||||||
let mut msrs = self.msrs.clone();
|
let mut msrs = self.msrs.clone();
|
||||||
self.get_msrs(&mut msrs)?;
|
self.get_msrs(&mut msrs)?;
|
||||||
let lapic = self.get_lapic()?;
|
|
||||||
let xsave = self.get_xsave()?;
|
|
||||||
let misc = self
|
let misc = self
|
||||||
.fd
|
.fd
|
||||||
.get_misc_regs()
|
.get_misc_regs()
|
||||||
@@ -1188,6 +1331,10 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
.fd
|
.fd
|
||||||
.get_debug_regs()
|
.get_debug_regs()
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetDebugRegs(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::GetDebugRegs(e.into()))?;
|
||||||
|
let vp_states = self
|
||||||
|
.fd
|
||||||
|
.get_all_vp_state_components()
|
||||||
|
.map_err(|e| cpu::HypervisorCpuError::GetAllVpStateComponents(e.into()))?;
|
||||||
|
|
||||||
Ok(VcpuMshvState {
|
Ok(VcpuMshvState {
|
||||||
msrs,
|
msrs,
|
||||||
@@ -1196,14 +1343,21 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
sregs: sregs.into(),
|
sregs: sregs.into(),
|
||||||
fpu,
|
fpu,
|
||||||
xcrs,
|
xcrs,
|
||||||
lapic,
|
|
||||||
dbg,
|
dbg,
|
||||||
xsave,
|
|
||||||
misc,
|
misc,
|
||||||
|
vp_states,
|
||||||
}
|
}
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
///
|
||||||
|
/// Get CPU state for aarch64 guest.
|
||||||
|
///
|
||||||
|
fn state(&self) -> cpu::Result<CpuState> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// Translate guest virtual address to guest physical address
|
/// Translate guest virtual address to guest physical address
|
||||||
@@ -1241,29 +1395,38 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
]
|
]
|
||||||
.to_vec()
|
.to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the AMD specific vcpu's sev control register.
|
||||||
|
///
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
fn set_sev_control_register(&self, vmsa_pfn: u64) -> cpu::Result<()> {
|
||||||
|
let sev_control_reg = snp::get_sev_control_register(vmsa_pfn);
|
||||||
|
|
||||||
|
self.fd
|
||||||
|
.set_sev_control_register(sev_control_reg)
|
||||||
|
.map_err(|e| cpu::HypervisorCpuError::SetSevControlRegister(e.into()))
|
||||||
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
///
|
||||||
|
/// Trigger NMI interrupt
|
||||||
|
///
|
||||||
|
fn nmi(&self) -> cpu::Result<()> {
|
||||||
|
let cfg = InterruptRequest {
|
||||||
|
interrupt_type: hv_interrupt_type_HV_X64_INTERRUPT_TYPE_NMI,
|
||||||
|
apic_id: self.vp_index as u64,
|
||||||
|
level_triggered: false,
|
||||||
|
vector: 0,
|
||||||
|
logical_destination_mode: false,
|
||||||
|
long_mode: false,
|
||||||
|
};
|
||||||
|
self.vm_fd
|
||||||
|
.request_virtual_interrupt(&cfg)
|
||||||
|
.map_err(|e| cpu::HypervisorCpuError::Nmi(e.into()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MshvVcpu {
|
impl MshvVcpu {
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
///
|
|
||||||
/// X86 specific call that returns the vcpu's current "xsave struct".
|
|
||||||
///
|
|
||||||
fn get_xsave(&self) -> cpu::Result<Xsave> {
|
|
||||||
self.fd
|
|
||||||
.get_xsave()
|
|
||||||
.map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
///
|
|
||||||
/// X86 specific call that sets the vcpu's current "xsave struct".
|
|
||||||
///
|
|
||||||
fn set_xsave(&self, xsave: &Xsave) -> cpu::Result<()> {
|
|
||||||
self.fd
|
|
||||||
.set_xsave(xsave)
|
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// X86 specific call that returns the vcpu's current "xcrs".
|
/// X86 specific call that returns the vcpu's current "xcrs".
|
||||||
@@ -1307,11 +1470,13 @@ impl MshvVcpu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
struct MshvEmulatorContext<'a> {
|
struct MshvEmulatorContext<'a> {
|
||||||
vcpu: &'a MshvVcpu,
|
vcpu: &'a MshvVcpu,
|
||||||
map: (u64, u64), // Initial GVA to GPA mapping provided by the hypervisor
|
map: (u64, u64), // Initial GVA to GPA mapping provided by the hypervisor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
impl<'a> MshvEmulatorContext<'a> {
|
impl<'a> MshvEmulatorContext<'a> {
|
||||||
// Do the actual gva -> gpa translation
|
// Do the actual gva -> gpa translation
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
@@ -1335,6 +1500,7 @@ impl<'a> MshvEmulatorContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
/// Platform emulation for Hyper-V
|
/// Platform emulation for Hyper-V
|
||||||
impl<'a> PlatformEmulator for MshvEmulatorContext<'a> {
|
impl<'a> PlatformEmulator for MshvEmulatorContext<'a> {
|
||||||
type CpuState = EmulatorCpuState;
|
type CpuState = EmulatorCpuState;
|
||||||
@@ -1435,8 +1601,11 @@ impl<'a> PlatformEmulator for MshvEmulatorContext<'a> {
|
|||||||
/// Wrapper over Mshv VM ioctls.
|
/// Wrapper over Mshv VM ioctls.
|
||||||
pub struct MshvVm {
|
pub struct MshvVm {
|
||||||
fd: Arc<VmFd>,
|
fd: Arc<VmFd>,
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
msrs: Vec<MsrEntry>,
|
msrs: Vec<MsrEntry>,
|
||||||
dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>,
|
dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>,
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
sev_snp_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MshvVm {
|
impl MshvVm {
|
||||||
@@ -1531,10 +1700,11 @@ impl vm::Vm for MshvVm {
|
|||||||
let vcpu = MshvVcpu {
|
let vcpu = MshvVcpu {
|
||||||
fd: vcpu_fd,
|
fd: vcpu_fd,
|
||||||
vp_index: id,
|
vp_index: id,
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
cpuid: Vec::new(),
|
cpuid: Vec::new(),
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
msrs: self.msrs.clone(),
|
msrs: self.msrs.clone(),
|
||||||
vm_ops,
|
vm_ops,
|
||||||
#[cfg(feature = "sev_snp")]
|
|
||||||
vm_fd: self.fd.clone(),
|
vm_fd: self.fd.clone(),
|
||||||
};
|
};
|
||||||
Ok(Arc::new(vcpu))
|
Ok(Arc::new(vcpu))
|
||||||
@@ -1556,6 +1726,11 @@ impl vm::Vm for MshvVm {
|
|||||||
addr: &IoEventAddress,
|
addr: &IoEventAddress,
|
||||||
datamatch: Option<DataMatch>,
|
datamatch: Option<DataMatch>,
|
||||||
) -> vm::Result<()> {
|
) -> vm::Result<()> {
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
if self.sev_snp_enabled {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let addr = &mshv_ioctls::IoEventAddress::from(*addr);
|
let addr = &mshv_ioctls::IoEventAddress::from(*addr);
|
||||||
debug!(
|
debug!(
|
||||||
"register_ioevent fd {} addr {:x?} datamatch {:?}",
|
"register_ioevent fd {} addr {:x?} datamatch {:?}",
|
||||||
@@ -1583,6 +1758,11 @@ impl vm::Vm for MshvVm {
|
|||||||
|
|
||||||
/// Unregister an event from a certain address it has been previously registered to.
|
/// Unregister an event from a certain address it has been previously registered to.
|
||||||
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> vm::Result<()> {
|
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> vm::Result<()> {
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
if self.sev_snp_enabled {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let addr = &mshv_ioctls::IoEventAddress::from(*addr);
|
let addr = &mshv_ioctls::IoEventAddress::from(*addr);
|
||||||
debug!("unregister_ioevent fd {} addr {:x?}", fd.as_raw_fd(), addr);
|
debug!("unregister_ioevent fd {} addr {:x?}", fd.as_raw_fd(), addr);
|
||||||
|
|
||||||
@@ -1635,7 +1815,7 @@ impl vm::Vm for MshvVm {
|
|||||||
readonly: bool,
|
readonly: bool,
|
||||||
_log_dirty_pages: bool,
|
_log_dirty_pages: bool,
|
||||||
) -> UserMemoryRegion {
|
) -> UserMemoryRegion {
|
||||||
let mut flags = HV_MAP_GPA_READABLE | HV_MAP_GPA_EXECUTABLE;
|
let mut flags = HV_MAP_GPA_READABLE | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_ADJUSTABLE;
|
||||||
if !readonly {
|
if !readonly {
|
||||||
flags |= HV_MAP_GPA_WRITABLE;
|
flags |= HV_MAP_GPA_WRITABLE;
|
||||||
}
|
}
|
||||||
@@ -1814,7 +1994,7 @@ impl vm::Vm for MshvVm {
|
|||||||
fn complete_isolated_import(
|
fn complete_isolated_import(
|
||||||
&self,
|
&self,
|
||||||
snp_id_block: IGVM_VHS_SNP_ID_BLOCK,
|
snp_id_block: IGVM_VHS_SNP_ID_BLOCK,
|
||||||
host_data: &[u8],
|
host_data: [u8; 32],
|
||||||
id_block_enabled: u8,
|
id_block_enabled: u8,
|
||||||
) -> vm::Result<()> {
|
) -> vm::Result<()> {
|
||||||
let mut auth_info = hv_snp_id_auth_info {
|
let mut auth_info = hv_snp_id_auth_info {
|
||||||
@@ -1847,7 +2027,7 @@ impl vm::Vm for MshvVm {
|
|||||||
policy: get_default_snp_guest_policy(),
|
policy: get_default_snp_guest_policy(),
|
||||||
},
|
},
|
||||||
id_auth_info: auth_info,
|
id_auth_info: auth_info,
|
||||||
host_data: host_data[0..32].try_into().unwrap(),
|
host_data,
|
||||||
id_block_enabled,
|
id_block_enabled,
|
||||||
author_key_enabled: 0,
|
author_key_enabled: 0,
|
||||||
},
|
},
|
||||||
@@ -1857,4 +2037,14 @@ impl vm::Vm for MshvVm {
|
|||||||
.complete_isolated_import(&data)
|
.complete_isolated_import(&data)
|
||||||
.map_err(|e| vm::HypervisorVmError::CompleteIsolatedImport(e.into()))
|
.map_err(|e| vm::HypervisorVmError::CompleteIsolatedImport(e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
fn create_vgic(&self, config: VgicConfig) -> vm::Result<Arc<Mutex<dyn Vgic>>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
fn get_preferred_target(&self, kvi: &mut VcpuInit) -> vm::Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ use std::fmt;
|
|||||||
///
|
///
|
||||||
pub use {
|
pub use {
|
||||||
mshv_bindings::hv_cpuid_entry, mshv_bindings::mshv_user_mem_region as MemoryRegion,
|
mshv_bindings::hv_cpuid_entry, mshv_bindings::mshv_user_mem_region as MemoryRegion,
|
||||||
mshv_bindings::msr_entry, mshv_bindings::CpuId, mshv_bindings::DebugRegisters,
|
mshv_bindings::msr_entry, mshv_bindings::AllVpStateComponents, mshv_bindings::CpuId,
|
||||||
mshv_bindings::FloatingPointUnit, mshv_bindings::LapicState as MshvLapicState,
|
mshv_bindings::DebugRegisters, mshv_bindings::FloatingPointUnit,
|
||||||
mshv_bindings::MiscRegs as MiscRegisters, mshv_bindings::MsrList,
|
mshv_bindings::LapicState as MshvLapicState, mshv_bindings::MiscRegs as MiscRegisters,
|
||||||
mshv_bindings::Msrs as MsrEntries, mshv_bindings::Msrs,
|
mshv_bindings::MsrList, mshv_bindings::Msrs as MsrEntries, mshv_bindings::Msrs,
|
||||||
mshv_bindings::SegmentRegister as MshvSegmentRegister,
|
mshv_bindings::SegmentRegister as MshvSegmentRegister,
|
||||||
mshv_bindings::SpecialRegisters as MshvSpecialRegisters,
|
mshv_bindings::SpecialRegisters as MshvSpecialRegisters,
|
||||||
mshv_bindings::StandardRegisters as MshvStandardRegisters, mshv_bindings::SuspendRegisters,
|
mshv_bindings::StandardRegisters as MshvStandardRegisters, mshv_bindings::SuspendRegisters,
|
||||||
@@ -38,10 +38,9 @@ pub struct VcpuMshvState {
|
|||||||
pub sregs: MshvSpecialRegisters,
|
pub sregs: MshvSpecialRegisters,
|
||||||
pub fpu: FpuState,
|
pub fpu: FpuState,
|
||||||
pub xcrs: ExtendedControlRegisters,
|
pub xcrs: ExtendedControlRegisters,
|
||||||
pub lapic: LapicState,
|
|
||||||
pub dbg: DebugRegisters,
|
pub dbg: DebugRegisters,
|
||||||
pub xsave: Xsave,
|
|
||||||
pub misc: MiscRegisters,
|
pub misc: MiscRegisters,
|
||||||
|
pub vp_states: AllVpStateComponents,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for VcpuMshvState {
|
impl fmt::Display for VcpuMshvState {
|
||||||
@@ -53,7 +52,7 @@ impl fmt::Display for VcpuMshvState {
|
|||||||
msr_entries[i][1] = entry.data;
|
msr_entries[i][1] = entry.data;
|
||||||
msr_entries[i][0] = entry.index as u64;
|
msr_entries[i][0] = entry.index as u64;
|
||||||
}
|
}
|
||||||
write!(f, "Number of MSRs: {}: MSRs: {:#010X?}, -- VCPU Events: {:?} -- Standard registers: {:?} Special Registers: {:?} ---- Floating Point Unit: {:?} --- Extended Control Register: {:?} --- Local APIC: {:?} --- DBG: {:?} --- Xsave: {:?}",
|
write!(f, "Number of MSRs: {}: MSRs: {:#010X?}, -- VCPU Events: {:?} -- Standard registers: {:?} Special Registers: {:?} ---- Floating Point Unit: {:?} --- Extended Control Register: {:?} --- DBG: {:?} --- VP States: {:?}",
|
||||||
msr_entries.len(),
|
msr_entries.len(),
|
||||||
msr_entries,
|
msr_entries,
|
||||||
self.vcpu_events,
|
self.vcpu_events,
|
||||||
@@ -61,9 +60,8 @@ impl fmt::Display for VcpuMshvState {
|
|||||||
self.sregs,
|
self.sregs,
|
||||||
self.fpu,
|
self.fpu,
|
||||||
self.xcrs,
|
self.xcrs,
|
||||||
self.lapic,
|
|
||||||
self.dbg,
|
self.dbg,
|
||||||
self.xsave,
|
self.vp_states,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -385,7 +385,7 @@ pub trait Vm: Send + Sync + Any {
|
|||||||
fn complete_isolated_import(
|
fn complete_isolated_import(
|
||||||
&self,
|
&self,
|
||||||
_snp_id_block: IGVM_VHS_SNP_ID_BLOCK,
|
_snp_id_block: IGVM_VHS_SNP_ID_BLOCK,
|
||||||
_host_data: &[u8],
|
_host_data: [u8; 32],
|
||||||
_id_block_enabled: u8,
|
_id_block_enabled: u8,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ authors = ["The Chromium OS Authors"]
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
vmm-sys-util = "0.11.0"
|
vmm-sys-util = "0.12.1"
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright TUNTAP, 2017 The Chromium OS Authors. All rights reserved.
|
// Copyright TUNTAP, 2017 The Chromium OS Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the THIRD-PARTY file.
|
// found in the THIRD-PARTY file.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
#![allow(non_upper_case_globals)]
|
#![allow(non_upper_case_globals)]
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|||||||
@@ -6,23 +6,21 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
epoll = "4.3.3"
|
epoll = "4.3.3"
|
||||||
getrandom = "0.2.10"
|
getrandom = "0.2.13"
|
||||||
libc = "0.2.147"
|
libc = "0.2.153"
|
||||||
log = "0.4.20"
|
log = "0.4.21"
|
||||||
net_gen = { path = "../net_gen" }
|
net_gen = { path = "../net_gen" }
|
||||||
rate_limiter = { path = "../rate_limiter" }
|
rate_limiter = { path = "../rate_limiter" }
|
||||||
serde = "1.0.168"
|
serde = "1.0.197"
|
||||||
thiserror = "1.0.40"
|
thiserror = "1.0.58"
|
||||||
versionize = "0.1.10"
|
virtio-bindings = "0.2.2"
|
||||||
versionize_derive = "0.1.4"
|
virtio-queue = "0.11.0"
|
||||||
virtio-bindings = "0.2.0"
|
vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||||
virtio-queue = "0.10.0"
|
|
||||||
vm-memory = { version = "0.13.1", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vmm-sys-util = "0.11.0"
|
vmm-sys-util = "0.12.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
once_cell = "1.18.0"
|
once_cell = "1.19.0"
|
||||||
pnet = "0.34.0"
|
pnet = "0.34.0"
|
||||||
pnet_datalink = "0.34.0"
|
pnet_datalink = "0.34.0"
|
||||||
serde_json = "1.0.107"
|
serde_json = "1.0.115"
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ mod open_tap;
|
|||||||
mod queue_pair;
|
mod queue_pair;
|
||||||
mod tap;
|
mod tap;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
use std::os::raw::c_uint;
|
use std::os::raw::c_uint;
|
||||||
use std::os::unix::io::{FromRawFd, RawFd};
|
use std::os::unix::io::{FromRawFd, RawFd};
|
||||||
use std::{io, mem, net};
|
use std::{io, mem, net};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
|
||||||
use versionize_derive::Versionize;
|
|
||||||
use virtio_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_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_CSUM, VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_TSO4,
|
||||||
@@ -45,7 +45,7 @@ pub enum Error {
|
|||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Copy, Clone, Debug, Default, Versionize)]
|
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct VirtioNetConfig {
|
pub struct VirtioNetConfig {
|
||||||
pub mac: [u8; 6],
|
pub mac: [u8; 6],
|
||||||
pub status: u16,
|
pub status: u16,
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::result::Result;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use serde::de::{Deserialize, Deserializer, Error};
|
use serde::de::{Deserialize, Deserializer, Error};
|
||||||
|
|||||||
@@ -290,6 +290,17 @@ impl TupleValue for Vec<u64> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TupleValue for Vec<usize> {
|
||||||
|
fn parse_value(input: &str) -> Result<Self, TupleError> {
|
||||||
|
Ok(IntegerList::from_str(input)
|
||||||
|
.map_err(TupleError::InvalidIntegerList)?
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|v| *v as usize)
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Tuple<S, T>(pub Vec<(S, T)>);
|
pub struct Tuple<S, T>(pub Vec<(S, T)>);
|
||||||
|
|
||||||
pub enum TupleError {
|
pub enum TupleError {
|
||||||
|
|||||||
@@ -10,21 +10,19 @@ kvm = ["vfio-ioctls/kvm"]
|
|||||||
mshv = ["vfio-ioctls/mshv"]
|
mshv = ["vfio-ioctls/mshv"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.81"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.5.0"
|
||||||
hypervisor = { path = "../hypervisor" }
|
hypervisor = { path = "../hypervisor" }
|
||||||
vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main", features = ["fam-wrappers"] }
|
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-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||||
vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" }
|
vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" }
|
||||||
|
|
||||||
vmm-sys-util = "0.11.0"
|
vmm-sys-util = "0.12.1"
|
||||||
libc = "0.2.147"
|
libc = "0.2.153"
|
||||||
log = "0.4.20"
|
log = "0.4.21"
|
||||||
serde = { version = "1.0.168", features = ["derive"] }
|
serde = { version = "1.0.197", features = ["derive"] }
|
||||||
thiserror = "1.0.40"
|
thiserror = "1.0.58"
|
||||||
versionize = "0.1.10"
|
|
||||||
versionize_derive = "0.1.4"
|
|
||||||
vm-allocator = { path = "../vm-allocator" }
|
vm-allocator = { path = "../vm-allocator" }
|
||||||
vm-device = { path = "../vm-device" }
|
vm-device = { path = "../vm-device" }
|
||||||
vm-memory = { version = "0.13.1", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||||
vm-migration = { path = "../vm-migration" }
|
vm-migration = { path = "../vm-migration" }
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user