mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
150 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d00eb4aa25 | ||
|
|
a1d8b63d86 | ||
|
|
0ce47c0538 | ||
|
|
828156db38 | ||
|
|
52df97e659 | ||
|
|
8e65d812cb | ||
|
|
610d694f1d | ||
|
|
25c6733feb | ||
|
|
39af0df279 | ||
|
|
5cc2876516 | ||
|
|
9009e785d9 | ||
|
|
a3231b1727 | ||
|
|
76a036e96d | ||
|
|
3e0bf235bb | ||
|
|
d0bafc72f8 | ||
|
|
2f3502eacc | ||
|
|
30cafccd23 | ||
|
|
88ebf565e0 | ||
|
|
0344805ed0 | ||
|
|
22873ae79e | ||
|
|
7dacfa3edc | ||
|
|
58d8206e2b | ||
|
|
1e1e61614c | ||
|
|
6a55768d94 | ||
|
|
5b177b205b | ||
|
|
f440976a7c | ||
|
|
0d573ae86c | ||
|
|
01420f5195 | ||
|
|
dfb1829f65 | ||
|
|
b5d11f72b3 | ||
|
|
00951f17d4 | ||
|
|
63c6c78c4e | ||
|
|
3fbdd7e16c | ||
|
|
455b0d5b62 | ||
|
|
bbefbe9273 | ||
|
|
84fc0e093d | ||
|
|
0eb78ab177 | ||
|
|
9aadbbe6d9 | ||
|
|
dc822be5e2 | ||
|
|
1a4747a20f | ||
|
|
83066cf58e | ||
|
|
495e444ca6 | ||
|
|
b99a3a7dc9 | ||
|
|
84a741a3fa | ||
|
|
db5d66747e | ||
|
|
dd6f07da23 | ||
|
|
8c135030d0 | ||
|
|
0468598fa3 | ||
|
|
7b7a3abfaa | ||
|
|
277ff84e55 | ||
|
|
a9f50dda08 | ||
|
|
73244aa6f2 | ||
|
|
6454c677d0 | ||
|
|
ca4857b5e6 | ||
|
|
1511cbda87 | ||
|
|
08021087ec | ||
|
|
90d79fa76b | ||
|
|
bebc5f957e | ||
|
|
5ac013df8b | ||
|
|
562a57012f | ||
|
|
93d19329f9 | ||
|
|
612dc544a8 | ||
|
|
59031531b6 | ||
|
|
2569621c4b | ||
|
|
1ea63f50a1 | ||
|
|
86f86c5348 | ||
|
|
0fb24ea3ae | ||
|
|
e390775bcb | ||
|
|
4450c44fbc | ||
|
|
a1caa6549a | ||
|
|
af3a59aa33 | ||
|
|
d7115ec656 | ||
|
|
7bbcc0f849 | ||
|
|
c4dc7a583d | ||
|
|
74485924b1 | ||
|
|
4889999277 | ||
|
|
eda0dc20d3 | ||
|
|
1e9c84af0f | ||
|
|
b50519651c | ||
|
|
08d859a7dd | ||
|
|
0dad7d9331 | ||
|
|
a496cecef1 | ||
|
|
a8f063db7c | ||
|
|
0066ddefe1 | ||
|
|
f9dd0aaf8a | ||
|
|
8b7880160e | ||
|
|
b7cb6257b5 | ||
|
|
6037c83585 | ||
|
|
b910a7922d | ||
|
|
ad6dfc5875 | ||
|
|
cb59976c68 | ||
|
|
520f54cb8d | ||
|
|
1a2d0e6dd8 | ||
|
|
7383087230 | ||
|
|
d72af85c42 | ||
|
|
d76d04e2f2 | ||
|
|
56c26b3d9c | ||
|
|
2280be825e | ||
|
|
73c822f64a | ||
|
|
43365ade2e | ||
|
|
e9d67dc405 | ||
|
|
fd4f32fa69 | ||
|
|
6fb88c3c5a | ||
|
|
d6c08d902b | ||
|
|
86afa38c64 | ||
|
|
ae68c802bd | ||
|
|
ccced2ebf4 | ||
|
|
d826b4fbdc | ||
|
|
0faa7afac2 | ||
|
|
da8eecc797 | ||
|
|
9dc9e224b9 | ||
|
|
b3fa56544c | ||
|
|
b30ddc0837 | ||
|
|
253c06d3ba | ||
|
|
46f6d9597d | ||
|
|
7b4f56e372 | ||
|
|
d6a2f48b32 | ||
|
|
c313bcbfd4 | ||
|
|
c741c01cc0 | ||
|
|
0aba41b3ee | ||
|
|
f67b3f79ea | ||
|
|
02173f42fc | ||
|
|
8ea0c542fd | ||
|
|
c1e896dddb | ||
|
|
a6040d7a30 | ||
|
|
a5d77cdee9 | ||
|
|
34f220edcd | ||
|
|
bcdac10149 | ||
|
|
ccda1a004e | ||
|
|
43f0dd6d25 | ||
|
|
a77160dca4 | ||
|
|
1d78812b63 | ||
|
|
8836715c2d | ||
|
|
330b5ea3be | ||
|
|
98bfd1e988 | ||
|
|
28382a1491 | ||
|
|
68e6a14deb | ||
|
|
f3778a7fc7 | ||
|
|
c6a110dd28 | ||
|
|
b0c7df2e59 | ||
|
|
1067059c4a | ||
|
|
8abe8c679b | ||
|
|
b6b686c71c | ||
|
|
171d12943d | ||
|
|
bdc44cd8bc | ||
|
|
33a55bac0f | ||
|
|
82ace6e327 | ||
|
|
2e56f0df77 | ||
|
|
a181b77bc8 | ||
|
|
9023412e31 |
18
.github/workflows/dco.yaml
vendored
Normal file
18
.github/workflows/dco.yaml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: DCO
|
||||
on:
|
||||
pull_request:
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Check DCO
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
pip3 install -U dco-check
|
||||
dco-check
|
||||
4
.github/workflows/fuzz-build.yaml
vendored
4
.github/workflows/fuzz-build.yaml
vendored
@@ -22,6 +22,8 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- name: Install Cargo fuzz
|
||||
run: cargo install -f 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 --git https://github.com/rust-fuzz/cargo-fuzz --rev b4df3e58f767b5cad8d1aa6753961003f56f3609
|
||||
- name: Cargo Fuzz Build
|
||||
run: cargo fuzz build
|
||||
|
||||
184
Cargo.lock
generated
184
Cargo.lock
generated
@@ -44,9 +44,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.43"
|
||||
version = "1.0.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
|
||||
checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
|
||||
|
||||
[[package]]
|
||||
name = "api_client"
|
||||
@@ -57,9 +57,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.3.2"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5ab7d9e73059c86c36473f459b52adbd99c3554a4fec492caef460806006f00"
|
||||
checksum = "e6df5aef5c5830360ce5218cecb8f018af3438af5686ae945094affc86fdec63"
|
||||
|
||||
[[package]]
|
||||
name = "arch"
|
||||
@@ -74,6 +74,7 @@ dependencies = [
|
||||
"linux-loader",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"thiserror",
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
@@ -108,7 +109,7 @@ checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
@@ -156,15 +157,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.70"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -190,13 +185,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cloud-hypervisor"
|
||||
version = "18.0.0"
|
||||
version = "19.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"api_client",
|
||||
"clap",
|
||||
"credibility",
|
||||
"dirs",
|
||||
"dirs 4.0.0",
|
||||
"epoll",
|
||||
"event_monitor",
|
||||
"hypervisor",
|
||||
@@ -216,15 +211,6 @@ dependencies = [
|
||||
"wait-timeout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32c"
|
||||
version = "0.6.0"
|
||||
@@ -279,6 +265,15 @@ dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.6"
|
||||
@@ -357,7 +352,7 @@ version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
@@ -413,14 +408,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iced-x86"
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7383772b06135cede839b7270023b46403656a9148024886e721e82639d3f90e"
|
||||
checksum = "46e977036f7f5139d580c7f19ad62df9cb8ebd8410bb569e73585226be80a86f"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-uring"
|
||||
version = "0.5.2"
|
||||
@@ -448,8 +452,8 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "kvm-bindings"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.4.0#1a68725639283e622f4bb64584885b30bfe8be44"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.5.0#9c497710ba9968d8efe15dbae03991b16cf82e23"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
@@ -458,9 +462,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kvm-ioctls"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2924454e22895c738e43331ae310459c74a11ded9c97dc250129ee10d2f9ca2"
|
||||
checksum = "48dc14f9047df1873cf6942caccc7431d19c3d496ca7a0d162260c4cf0f64b76"
|
||||
dependencies = [
|
||||
"kvm-bindings",
|
||||
"libc",
|
||||
@@ -475,15 +479,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.101"
|
||||
version = "0.2.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
|
||||
[[package]]
|
||||
name = "libssh2-sys"
|
||||
version = "0.2.21"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0186af0d8f171ae6b9c4c90ec51898bad5d08a2d5e470903a50d9ad8959cbee"
|
||||
checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -507,18 +511,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-loader"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c819cc8275b0f2c1ed9feec455ca288b45d82932384a6a5f7a86812ee3427459"
|
||||
checksum = "8a5e77493808403a6bd56a301a64ea6b9342e36ea845044bf0dfdf56fe52fa08"
|
||||
dependencies = [
|
||||
"vm-memory",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.3.4"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75"
|
||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
@@ -529,7 +533,7 @@ version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -560,7 +564,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mshv-bindings"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#0d6e4e82b9b575798de333e362129515e81049cb"
|
||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#99da566389546aedb56fc3d279e01c5dbde79bce"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"serde",
|
||||
@@ -572,7 +576,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mshv-ioctls"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#0d6e4e82b9b575798de333e362129515e81049cb"
|
||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#99da566389546aedb56fc3d279e01c5dbde79bce"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mshv-bindings",
|
||||
@@ -591,6 +595,7 @@ name = "net_util"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"epoll",
|
||||
"getrandom",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
@@ -618,9 +623,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.66"
|
||||
version = "0.9.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1996d2d305e561b70d1ee0c53f1542833f4e1ac6ce9a6708b6ff2738ca67dc82"
|
||||
checksum = "69df2d8dfc6ce3aaf44b40dec6f487d5a886516cf6879c49e98e0710f310a058"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
@@ -635,24 +640,25 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.10.2"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.7.2"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"cloudabi",
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall 0.1.57",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
@@ -681,9 +687,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.19"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
|
||||
checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb"
|
||||
|
||||
[[package]]
|
||||
name = "pnet"
|
||||
@@ -775,9 +781,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.29"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
|
||||
checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
@@ -795,9 +801,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -811,12 +817,6 @@ dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
@@ -833,7 +833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall 0.2.10",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -893,8 +893,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "seccompiler"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/seccompiler#da5788d52f1ae8886d8ed4624199b7e9fa64ac04"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01d1292a1131b22ccea49f30bd106f1238b5ddeec1a98d39268dcc31d540e68"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -933,9 +934,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.67"
|
||||
version = "1.0.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950"
|
||||
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -963,15 +964,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.6.1"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
|
||||
[[package]]
|
||||
name = "ssh2"
|
||||
version = "0.9.1"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d876d4d57f6bbf2245d43f7ec53759461f801a446d3693704aa6d27b257844d7"
|
||||
checksum = "269343e64430067a14937ae0e3c4ec604c178fb896dde0964b1acd22b3e2eeb1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@@ -993,9 +994,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.76"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
|
||||
checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1004,9 +1005,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.5"
|
||||
version = "0.12.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa"
|
||||
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1037,7 +1038,7 @@ dependencies = [
|
||||
name = "test_infra"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"dirs 3.0.2",
|
||||
"epoll",
|
||||
"libc",
|
||||
"ssh2",
|
||||
@@ -1057,18 +1058,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.29"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88"
|
||||
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.29"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c"
|
||||
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1077,9 +1078,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
@@ -1147,7 +1148,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio-ioctls"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=main#a8ee64b978ccd000df88732814d626651a091891"
|
||||
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=main#d51c1fad37be30c20385c55a217e2d90972ea31d"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"kvm-bindings",
|
||||
@@ -1192,9 +1193,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vhost"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a6b90237e10f1a61b35fba73885c3567e1a5a8c40d44daae335f7710210a7dc"
|
||||
checksum = "2d23ddeb452fb4f837526c6298cc8a2f4948e5595b0328a3d61b5eebe51874d7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@@ -1318,7 +1319,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vm-fdt"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#06cbff3a0248ec654467a87b1be7c0bcf78a41a8"
|
||||
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#9c2b252dc19f0e87546e4f7577eaf398f8e3c66a"
|
||||
|
||||
[[package]]
|
||||
name = "vm-memory"
|
||||
@@ -1389,6 +1390,7 @@ dependencies = [
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"vfio-ioctls",
|
||||
"vfio_user",
|
||||
"vhdx",
|
||||
"virtio-devices",
|
||||
"vm-allocator",
|
||||
@@ -1401,9 +1403,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vmm-sys-util"
|
||||
version = "0.8.0"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01cf11afbc4ebc0d5c7a7748a77d19e2042677fc15faa2f4ccccb27c18a60605"
|
||||
checksum = "733537bded03aaa93543f785ae997727b30d1d9f4a03b7861d23290474242e11"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@@ -1459,9 +1461,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e59ec1d2457bd6c0dd89b50e7d9d6b0b647809bf3f0a59ac85557046950b7b2"
|
||||
checksum = "ae0f717764196a220d8c58500e3a3595e2c9054f95d66267f9fd5f6e74ad0fec"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
|
||||
22
Cargo.toml
22
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cloud-hypervisor"
|
||||
version = "18.0.0"
|
||||
version = "19.0.0"
|
||||
authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
default-run = "cloud-hypervisor"
|
||||
@@ -13,21 +13,21 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.43"
|
||||
anyhow = "1.0.44"
|
||||
api_client = { path = "api_client" }
|
||||
clap = { version = "2.33.3", features = ["wrap_help"] }
|
||||
epoll = "4.3.1"
|
||||
event_monitor = { path = "event_monitor" }
|
||||
hypervisor = { path = "hypervisor" }
|
||||
libc = "0.2.101"
|
||||
libc = "0.2.103"
|
||||
log = { version = "0.4.14", features = ["std"] }
|
||||
option_parser = { path = "option_parser" }
|
||||
seccompiler = { git = "https://github.com/rust-vmm/seccompiler"}
|
||||
serde_json = "1.0.67"
|
||||
seccompiler = "0.2.0"
|
||||
serde_json = "1.0.68"
|
||||
signal-hook = "0.3.10"
|
||||
thiserror = "1.0.29"
|
||||
thiserror = "1.0.30"
|
||||
vmm = { path = "vmm" }
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
vm-memory = "0.6.0"
|
||||
|
||||
[build-dependencies]
|
||||
@@ -35,20 +35,20 @@ clap = { version = "2.33.3", features = ["wrap_help"] }
|
||||
|
||||
# List of patched crates
|
||||
[patch.crates-io]
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.4.0", features = ["with-serde", "fam-wrappers"] }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"] }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||
|
||||
[dev-dependencies]
|
||||
credibility = "0.1.3"
|
||||
dirs = "3.0.2"
|
||||
dirs = "4.0.0"
|
||||
lazy_static= "1.4.0"
|
||||
net_util = { path = "net_util" }
|
||||
serde_json = "1.0.67"
|
||||
serde_json = "1.0.68"
|
||||
test_infra = { path = "test_infra" }
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
[features]
|
||||
default = ["acpi", "cmos", "io_uring", "kvm"]
|
||||
default = ["common", "kvm"]
|
||||
# Common features for all hypervisors
|
||||
common = ["acpi", "cmos", "fwdebug", "io_uring"]
|
||||
acpi = ["vmm/acpi"]
|
||||
|
||||
2
Jenkinsfile
vendored
2
Jenkinsfile
vendored
@@ -228,6 +228,7 @@ pipeline{
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh "sudo modprobe openvswitch"
|
||||
sh "scripts/dev_cli.sh tests --integration-live-migration"
|
||||
}
|
||||
}
|
||||
@@ -236,6 +237,7 @@ pipeline{
|
||||
timeout(time: 1, unit: 'HOURS')
|
||||
}
|
||||
steps {
|
||||
sh "sudo modprobe openvswitch"
|
||||
sh "scripts/dev_cli.sh tests --integration-live-migration --libc musl"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
@@ -11,19 +11,20 @@ tdx = []
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { path = "../acpi_tables", optional = true }
|
||||
anyhow = "1.0.43"
|
||||
anyhow = "1.0.44"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.101"
|
||||
linux-loader = { version = "0.3.0", features = ["elf", "bzimage", "pe"] }
|
||||
libc = "0.2.103"
|
||||
linux-loader = { version = "0.4.0", features = ["elf", "bzimage", "pe"] }
|
||||
log = "0.4.14"
|
||||
serde = { version = "1.0.130", features = ["rc"] }
|
||||
thiserror = "1.0.29"
|
||||
serde_derive = "1.0.130"
|
||||
thiserror = "1.0.30"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = { version = "0.8.0", features = ["with-serde"] }
|
||||
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
||||
|
||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||
fdt_parser = { version = "0.1.3", package = 'fdt'}
|
||||
|
||||
@@ -35,9 +35,12 @@ const MSI_PHANDLE: u32 = 2;
|
||||
const CLOCK_PHANDLE: u32 = 3;
|
||||
// This is a value for uniquely identifying the FDT node containing the gpio controller.
|
||||
const GPIO_PHANDLE: u32 = 4;
|
||||
// This is a value for virtio-iommu. Now only one virtio-iommu device is supported.
|
||||
const VIRTIO_IOMMU_PHANDLE: u32 = 5;
|
||||
// NOTE: Keep FIRST_VCPU_PHANDLE the last PHANDLE defined.
|
||||
// This is a value for uniquely identifying the FDT node containing the first vCPU.
|
||||
// The last number of vCPU phandle depends on the number of vCPUs.
|
||||
const FIRST_VCPU_PHANDLE: u32 = 5;
|
||||
const FIRST_VCPU_PHANDLE: u32 = 6;
|
||||
|
||||
// Read the documentation specified when appending the root node to the FDT.
|
||||
const ADDRESS_CELLS: u32 = 0x2;
|
||||
@@ -79,7 +82,7 @@ type Result<T> = result::Result<T, Error>;
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
|
||||
guest_mem: &GuestMemoryMmap,
|
||||
cmdline: &CStr,
|
||||
cmdline: &str,
|
||||
vcpu_mpidr: Vec<u64>,
|
||||
vcpu_topology: Option<(u8, u8, u8)>,
|
||||
device_info: &HashMap<(DeviceType, String), T, S>,
|
||||
@@ -87,6 +90,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
|
||||
initrd: &Option<InitramfsConfig>,
|
||||
pci_space_address: &(u64, u64),
|
||||
numa_nodes: &NumaNodes,
|
||||
virtio_iommu_bdf: Option<u32>,
|
||||
) -> FdtWriterResult<Vec<u8>> {
|
||||
// Allocate stuff necessary for the holding the blob.
|
||||
let mut fdt = FdtWriter::new().unwrap();
|
||||
@@ -107,13 +111,18 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
|
||||
fdt.property_u32("interrupt-parent", GIC_PHANDLE)?;
|
||||
create_cpu_nodes(&mut fdt, &vcpu_mpidr, vcpu_topology, numa_nodes)?;
|
||||
create_memory_node(&mut fdt, guest_mem, numa_nodes)?;
|
||||
create_chosen_node(&mut fdt, cmdline.to_str().unwrap(), initrd)?;
|
||||
create_chosen_node(&mut fdt, cmdline, initrd)?;
|
||||
create_gic_node(&mut fdt, gic_device)?;
|
||||
create_timer_node(&mut fdt)?;
|
||||
create_clock_node(&mut fdt)?;
|
||||
create_psci_node(&mut fdt)?;
|
||||
create_devices_node(&mut fdt, device_info)?;
|
||||
create_pci_nodes(&mut fdt, pci_space_address.0, pci_space_address.1)?;
|
||||
create_pci_nodes(
|
||||
&mut fdt,
|
||||
pci_space_address.0,
|
||||
pci_space_address.1,
|
||||
virtio_iommu_bdf,
|
||||
)?;
|
||||
if numa_nodes.len() > 1 {
|
||||
create_distance_map_node(&mut fdt, numa_nodes)?;
|
||||
}
|
||||
@@ -540,6 +549,7 @@ fn create_pci_nodes(
|
||||
fdt: &mut FdtWriter,
|
||||
pci_device_base: u64,
|
||||
pci_device_size: u64,
|
||||
virtio_iommu_bdf: Option<u32>,
|
||||
) -> FdtWriterResult<()> {
|
||||
// Add node for PCIe controller.
|
||||
// See Documentation/devicetree/bindings/pci/host-generic-pci.txt in the kernel
|
||||
@@ -603,6 +613,40 @@ fn create_pci_nodes(
|
||||
fdt.property_null("interrupt-map-mask")?;
|
||||
fdt.property_null("dma-coherent")?;
|
||||
fdt.property_u32("msi-parent", MSI_PHANDLE)?;
|
||||
|
||||
if let Some(virtio_iommu_bdf) = virtio_iommu_bdf {
|
||||
// See kernel document Documentation/devicetree/bindings/pci/pci-iommu.txt
|
||||
// for 'iommu-map' attribute setting.
|
||||
let iommu_map = [
|
||||
0_u32,
|
||||
VIRTIO_IOMMU_PHANDLE,
|
||||
0_u32,
|
||||
virtio_iommu_bdf,
|
||||
virtio_iommu_bdf + 1,
|
||||
VIRTIO_IOMMU_PHANDLE,
|
||||
virtio_iommu_bdf + 1,
|
||||
0xffff - virtio_iommu_bdf,
|
||||
];
|
||||
fdt.property_array_u32("iommu-map", &iommu_map)?;
|
||||
|
||||
// See kernel document Documentation/devicetree/bindings/virtio/iommu.txt
|
||||
// for virtio-iommu node settings.
|
||||
let virtio_iommu_node_name = format!("virtio_iommu@{:x}", virtio_iommu_bdf);
|
||||
let virtio_iommu_node = fdt.begin_node(&virtio_iommu_node_name)?;
|
||||
fdt.property_u32("#iommu-cells", 1)?;
|
||||
fdt.property_string("compatible", "virtio,pci-iommu")?;
|
||||
|
||||
// 'reg' is a five-cell address encoded as
|
||||
// (phys.hi phys.mid phys.lo size.hi size.lo). phys.hi should contain the
|
||||
// device's BDF as 0b00000000 bbbbbbbb dddddfff 00000000. The other cells
|
||||
// should be zero.
|
||||
let reg = [virtio_iommu_bdf << 8, 0_u32, 0_u32, 0_u32, 0_u32];
|
||||
fdt.property_array_u32("reg", ®)?;
|
||||
fdt.property_u32("phandle", VIRTIO_IOMMU_PHANDLE)?;
|
||||
|
||||
fdt.end_node(virtio_iommu_node)?;
|
||||
}
|
||||
|
||||
fdt.end_node(pci_node)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -78,23 +78,17 @@ pub mod kvm {
|
||||
impl VersionMapped for Gicv3State {}
|
||||
|
||||
impl KvmGicV3 {
|
||||
// Unfortunately bindgen omits defines that are based on other defines.
|
||||
// See arch/arm64/include/uapi/asm/kvm.h file from the linux kernel.
|
||||
pub const SZ_64K: u64 = 0x0001_0000;
|
||||
const KVM_VGIC_V3_DIST_SIZE: u64 = KvmGicV3::SZ_64K;
|
||||
const KVM_VGIC_V3_REDIST_SIZE: u64 = (2 * KvmGicV3::SZ_64K);
|
||||
|
||||
// Device trees specific constants
|
||||
pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9;
|
||||
|
||||
/// Get the address of the GIC distributor.
|
||||
pub fn get_dist_addr() -> u64 {
|
||||
layout::MAPPED_IO_START - KvmGicV3::KVM_VGIC_V3_DIST_SIZE
|
||||
layout::GIC_V3_DIST_START
|
||||
}
|
||||
|
||||
/// Get the size of the GIC distributor.
|
||||
pub fn get_dist_size() -> u64 {
|
||||
KvmGicV3::KVM_VGIC_V3_DIST_SIZE
|
||||
layout::GIC_V3_DIST_SIZE
|
||||
}
|
||||
|
||||
/// Get the address of the GIC redistributors.
|
||||
@@ -104,7 +98,7 @@ pub mod kvm {
|
||||
|
||||
/// Get the size of the GIC redistributors.
|
||||
pub fn get_redists_size(vcpu_count: u64) -> u64 {
|
||||
vcpu_count * KvmGicV3::KVM_VGIC_V3_REDIST_SIZE
|
||||
vcpu_count * layout::GIC_V3_REDIST_SIZE
|
||||
}
|
||||
|
||||
/// Save the state of GIC.
|
||||
|
||||
@@ -13,6 +13,7 @@ pub mod kvm {
|
||||
use crate::aarch64::gic::gicv3::kvm::KvmGicV3;
|
||||
use crate::aarch64::gic::kvm::{save_pending_tables, KvmGicDevice};
|
||||
use crate::aarch64::gic::GicDevice;
|
||||
use crate::layout;
|
||||
use anyhow::anyhow;
|
||||
use hypervisor::kvm::kvm_bindings;
|
||||
use hypervisor::CpuState;
|
||||
@@ -179,10 +180,8 @@ pub mod kvm {
|
||||
impl VersionMapped for Gicv3ItsState {}
|
||||
|
||||
impl KvmGicV3Its {
|
||||
const KVM_VGIC_V3_ITS_SIZE: u64 = (2 * KvmGicV3::SZ_64K);
|
||||
|
||||
fn get_msi_size() -> u64 {
|
||||
KvmGicV3Its::KVM_VGIC_V3_ITS_SIZE
|
||||
layout::GIC_V3_ITS_SIZE
|
||||
}
|
||||
|
||||
fn get_msi_addr(vcpu_count: u64) -> u64 {
|
||||
|
||||
@@ -55,6 +55,17 @@ pub const UEFI_SIZE: u64 = 0x040_0000;
|
||||
/// Below this address will reside the GIC, above this address will reside the MMIO devices.
|
||||
pub const MAPPED_IO_START: u64 = 0x0900_0000;
|
||||
|
||||
/// See kernel file arch/arm64/include/uapi/asm/kvm.h for the GIC related definitions.
|
||||
/// 0x08ff_0000 ~ 0x0900_0000 is reserved for GICv3 Distributor
|
||||
pub const GIC_V3_DIST_SIZE: u64 = 0x01_0000;
|
||||
pub const GIC_V3_DIST_START: u64 = MAPPED_IO_START - GIC_V3_DIST_SIZE;
|
||||
/// Below 0x08ff_0000 is reserved for GICv3 Redistributor.
|
||||
/// The size defined here is for each vcpu.
|
||||
/// The total size is 'number_of_vcpu * GIC_V3_REDIST_SIZE'
|
||||
pub const GIC_V3_REDIST_SIZE: u64 = 0x02_0000;
|
||||
/// Below Redistributor area is GICv3 ITS
|
||||
pub const GIC_V3_ITS_SIZE: u64 = 0x02_0000;
|
||||
|
||||
/// Space 0x0900_0000 ~ 0x0905_0000 is reserved for legacy devices.
|
||||
pub const LEGACY_SERIAL_MAPPED_IO_START: u64 = 0x0900_0000;
|
||||
pub const LEGACY_RTC_MAPPED_IO_START: u64 = 0x0901_0000;
|
||||
|
||||
@@ -19,7 +19,6 @@ use gic::GicDevice;
|
||||
use log::{log_enabled, Level};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::CStr;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
use vm_memory::{
|
||||
@@ -136,18 +135,19 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
|
||||
guest_mem: &GuestMemoryMmap,
|
||||
cmdline_cstring: &CStr,
|
||||
cmdline: &str,
|
||||
vcpu_mpidr: Vec<u64>,
|
||||
vcpu_topology: Option<(u8, u8, u8)>,
|
||||
device_info: &HashMap<(DeviceType, String), T, S>,
|
||||
initrd: &Option<super::InitramfsConfig>,
|
||||
pci_space_address: &(u64, u64),
|
||||
virtio_iommu_bdf: Option<u32>,
|
||||
gic_device: &dyn GicDevice,
|
||||
numa_nodes: &NumaNodes,
|
||||
) -> super::Result<()> {
|
||||
let fdt_final = fdt::create_fdt(
|
||||
guest_mem,
|
||||
cmdline_cstring,
|
||||
cmdline,
|
||||
vcpu_mpidr,
|
||||
vcpu_topology,
|
||||
device_info,
|
||||
@@ -155,6 +155,7 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
|
||||
initrd,
|
||||
pci_space_address,
|
||||
numa_nodes,
|
||||
virtio_iommu_bdf,
|
||||
)
|
||||
.map_err(|_| Error::SetupFdt)?;
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::x86_64::SgxEpcSection;
|
||||
@@ -17,6 +19,9 @@ use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
use std::result;
|
||||
use std::sync::Arc;
|
||||
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use vm_migration::VersionMapped;
|
||||
|
||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<vm_memory::bitmap::AtomicBitmap>;
|
||||
type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitmap>;
|
||||
@@ -54,7 +59,7 @@ pub enum Error {
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
/// Type for memory region types.
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize, Versionize)]
|
||||
pub enum RegionType {
|
||||
/// RAM type
|
||||
Ram,
|
||||
@@ -72,6 +77,8 @@ pub enum RegionType {
|
||||
Reserved,
|
||||
}
|
||||
|
||||
impl VersionMapped for RegionType {}
|
||||
|
||||
/// Module for aarch64 related functionality.
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub mod aarch64;
|
||||
|
||||
@@ -60,6 +60,59 @@ impl Default for TdvfSectionType {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Default, Debug)]
|
||||
pub struct TdVmmDataRegion {
|
||||
pub start_address: u64,
|
||||
pub length: u64,
|
||||
pub region_type: TdVmmDataRegionType,
|
||||
}
|
||||
|
||||
unsafe impl ByteValued for TdVmmDataRegion {}
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum TdVmmDataRegionType {
|
||||
Signature = 0x0000,
|
||||
InterfaceVersion = 0x0001,
|
||||
SystemUuid = 0x0002,
|
||||
RamSize = 0x0003,
|
||||
GraphicsEnabled = 0x0004,
|
||||
SmpCpuCount = 0x0005,
|
||||
MachineId = 0x0006,
|
||||
KernelAddress = 0x0007,
|
||||
KernelSize = 0x0008,
|
||||
KernelCommandLine = 0x0009,
|
||||
InitrdAddress = 0x000a,
|
||||
InitrdSize = 0x000b,
|
||||
BootDevice = 0x000c,
|
||||
NumaData = 0x000d,
|
||||
BootMenu = 0x000e,
|
||||
MaximumCpuCount = 0x000f,
|
||||
KernelEntry = 0x0010,
|
||||
KernelData = 0x0011,
|
||||
InitrdData = 0x0012,
|
||||
CommandLineAddress = 0x0013,
|
||||
CommandLineSize = 0x0014,
|
||||
CommandLineData = 0x0015,
|
||||
KernelSetupAddress = 0x0016,
|
||||
KernelSetupSize = 0x0017,
|
||||
KernelSetupData = 0x0018,
|
||||
FileDir = 0x0019,
|
||||
AcpiTables = 0x8000,
|
||||
SmbiosTables = 0x8001,
|
||||
Irq0Override = 0x8002,
|
||||
E820Table = 0x8003,
|
||||
HpetData = 0x8004,
|
||||
Reserved = 0xffff,
|
||||
}
|
||||
|
||||
impl Default for TdVmmDataRegionType {
|
||||
fn default() -> Self {
|
||||
TdVmmDataRegionType::Reserved
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfError> {
|
||||
// The 32-bit offset to the TDVF metadata is located 32 bytes from
|
||||
// the end of the file.
|
||||
@@ -120,6 +173,7 @@ pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfErro
|
||||
enum HobType {
|
||||
Handoff = 0x1,
|
||||
ResourceDescriptor = 0x3,
|
||||
GuidExtension = 0x4,
|
||||
Unused = 0xfffe,
|
||||
EndOfHobList = 0xffff,
|
||||
}
|
||||
@@ -174,6 +228,22 @@ struct HobResourceDescriptor {
|
||||
}
|
||||
unsafe impl ByteValued for HobResourceDescriptor {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
struct HobGuidType {
|
||||
header: HobHeader,
|
||||
name: EfiGuid,
|
||||
}
|
||||
unsafe impl ByteValued for HobGuidType {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
struct TdVmmData {
|
||||
guid_type: HobGuidType,
|
||||
region: TdVmmDataRegion,
|
||||
}
|
||||
unsafe impl ByteValued for TdVmmData {}
|
||||
|
||||
pub struct TdHob {
|
||||
start_offset: u64,
|
||||
current_offset: u64,
|
||||
@@ -303,6 +373,38 @@ impl TdHob {
|
||||
0x403,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn add_td_vmm_data(
|
||||
&mut self,
|
||||
mem: &GuestMemoryMmap,
|
||||
region: TdVmmDataRegion,
|
||||
) -> Result<(), TdvfError> {
|
||||
let td_vmm_data = TdVmmData {
|
||||
guid_type: HobGuidType {
|
||||
header: HobHeader {
|
||||
r#type: HobType::GuidExtension,
|
||||
length: std::mem::size_of::<TdVmmData>() as u16,
|
||||
reserved: 0,
|
||||
},
|
||||
// TD_VMM_DATA_GUID CF2643E4-C0D3-46FF-0000-72EE623DDE38
|
||||
name: EfiGuid {
|
||||
data1: 0xcf26_43e4,
|
||||
data2: 0xc0d3,
|
||||
data3: 0x46ff,
|
||||
data4: [0x00, 0x00, 0x72, 0xee, 0x62, 0x3d, 0xde, 0x38],
|
||||
},
|
||||
},
|
||||
region,
|
||||
};
|
||||
info!(
|
||||
"Writing HOB TD_VMM_DATA {:x} {:x?}",
|
||||
self.current_offset, td_vmm_data
|
||||
);
|
||||
mem.write_obj(td_vmm_data, GuestAddress(self.current_offset))
|
||||
.map_err(TdvfError::GuestMemoryWriteHob)?;
|
||||
self.update_offset::<TdVmmData>();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -10,15 +10,15 @@ io_uring = []
|
||||
|
||||
[dependencies]
|
||||
io-uring = "0.5.2"
|
||||
libc = "0.2.101"
|
||||
libc = "0.2.103"
|
||||
log = "0.4.14"
|
||||
qcow = { path = "../qcow" }
|
||||
thiserror = "1.0.29"
|
||||
thiserror = "1.0.30"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
|
||||
@@ -6,19 +6,19 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { path = "../acpi_tables", optional = true }
|
||||
anyhow = "1.0.43"
|
||||
anyhow = "1.0.44"
|
||||
arch = { path = "../arch" }
|
||||
bitflags = "1.3.2"
|
||||
byteorder = "1.4.3"
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.101"
|
||||
libc = "0.2.103"
|
||||
log = "0.4.14"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = "0.6.0"
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -34,9 +34,7 @@ impl AcpiShutdownDevice {
|
||||
impl BusDevice for AcpiShutdownDevice {
|
||||
// Spec has all fields as zero
|
||||
fn read(&mut self, _base: u64, _offset: u64, data: &mut [u8]) {
|
||||
for i in data.iter_mut() {
|
||||
*i = 0;
|
||||
}
|
||||
data.fill(0)
|
||||
}
|
||||
|
||||
fn write(&mut self, _base: u64, _offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||
@@ -191,6 +189,10 @@ impl Default for AcpiPmTimerDevice {
|
||||
|
||||
impl BusDevice for AcpiPmTimerDevice {
|
||||
fn read(&mut self, _base: u64, _offset: u64, data: &mut [u8]) {
|
||||
if data.len() != std::mem::size_of::<u32>() {
|
||||
warn!("Invalid sized read of PM timer: {}", data.len());
|
||||
return;
|
||||
}
|
||||
let now = Instant::now();
|
||||
let since = now.duration_since(self.start);
|
||||
let nanos = since.as_nanos();
|
||||
|
||||
@@ -149,7 +149,10 @@ impl VersionMapped for IoapicState {}
|
||||
|
||||
impl BusDevice for Ioapic {
|
||||
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
||||
assert!(data.len() == 4);
|
||||
if data.len() != std::mem::size_of::<u32>() {
|
||||
warn!("Invalid read size on IOAPIC: {}", data.len());
|
||||
return;
|
||||
}
|
||||
|
||||
debug!("IOAPIC_R @ offset 0x{:x}", offset);
|
||||
|
||||
@@ -166,7 +169,10 @@ impl BusDevice for Ioapic {
|
||||
}
|
||||
|
||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||
assert!(data.len() == 4);
|
||||
if data.len() != std::mem::size_of::<u32>() {
|
||||
warn!("Invalid write size on IOAPIC: {}", data.len());
|
||||
return None;
|
||||
}
|
||||
|
||||
debug!("IOAPIC_W @ offset 0x{:x}", offset);
|
||||
|
||||
@@ -226,6 +232,10 @@ impl Ioapic {
|
||||
IOAPIC_REG_ID => self.id_reg = (val >> 24) & 0xf,
|
||||
IOWIN_OFF..=REG_MAX_OFFSET => {
|
||||
let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8);
|
||||
if index > NUM_IOAPIC_PINS {
|
||||
warn!("IOAPIC index out of range: {}", index);
|
||||
return;
|
||||
}
|
||||
if is_high_bits {
|
||||
self.reg_entries[index] &= 0xffff_ffff;
|
||||
self.reg_entries[index] |= u64::from(val) << 32;
|
||||
@@ -259,6 +269,10 @@ impl Ioapic {
|
||||
IOAPIC_REG_ID | IOAPIC_REG_ARBITRATION_ID => (self.id_reg & 0xf) << 24,
|
||||
IOWIN_OFF..=REG_MAX_OFFSET => {
|
||||
let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8);
|
||||
if index > NUM_IOAPIC_PINS {
|
||||
warn!("IOAPIC index out of range: {}", index);
|
||||
return 0;
|
||||
}
|
||||
if is_high_bits {
|
||||
(self.reg_entries[index] >> 32) as u32
|
||||
} else {
|
||||
|
||||
@@ -51,13 +51,14 @@ impl Cmos {
|
||||
impl BusDevice for Cmos {
|
||||
fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||
if data.len() != 1 {
|
||||
warn!("Invalid write size on CMOS device: {}", data.len());
|
||||
return None;
|
||||
}
|
||||
|
||||
match offset {
|
||||
INDEX_OFFSET => self.index = data[0] & INDEX_MASK,
|
||||
DATA_OFFSET => self.data[self.index as usize] = data[0],
|
||||
o => panic!("bad write offset on CMOS device: {}", o),
|
||||
o => warn!("bad write offset on CMOS device: {}", o),
|
||||
};
|
||||
None
|
||||
}
|
||||
@@ -69,6 +70,7 @@ impl BusDevice for Cmos {
|
||||
}
|
||||
|
||||
if data.len() != 1 {
|
||||
warn!("Invalid read size on CMOS device: {}", data.len());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -126,7 +128,10 @@ impl BusDevice for Cmos {
|
||||
}
|
||||
}
|
||||
}
|
||||
o => panic!("bad read offset on CMOS device: {}", o),
|
||||
o => {
|
||||
warn!("bad read offset on CMOS device: {}", o);
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +124,10 @@ impl Serial {
|
||||
Self::new(id, interrupt, None)
|
||||
}
|
||||
|
||||
pub fn set_out(&mut self, out: Box<dyn io::Write + Send>) {
|
||||
self.out = Some(out);
|
||||
}
|
||||
|
||||
/// Queues raw bytes for the guest to read and signals the interrupt if the line status would
|
||||
/// change.
|
||||
pub fn queue_input_bytes(&mut self, c: &[u8]) -> Result<()> {
|
||||
@@ -134,6 +138,13 @@ impl Serial {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn flush_output(&mut self) -> result::Result<(), io::Error> {
|
||||
if let Some(out) = self.out.as_mut() {
|
||||
out.flush()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_dlab_set(&self) -> bool {
|
||||
(self.line_control & LCR_DLAB_BIT) != 0
|
||||
}
|
||||
|
||||
@@ -138,6 +138,10 @@ impl Pl011 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_out(&mut self, out: Box<dyn io::Write + Send>) {
|
||||
self.out = Some(out);
|
||||
}
|
||||
|
||||
fn state(&self) -> Pl011State {
|
||||
Pl011State {
|
||||
flags: self.flags,
|
||||
@@ -192,6 +196,13 @@ impl Pl011 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn flush_output(&mut self) -> result::Result<(), io::Error> {
|
||||
if let Some(out) = self.out.as_mut() {
|
||||
out.flush()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pl011_get_baudrate(&self) -> u32 {
|
||||
if self.fbrd == 0 {
|
||||
return 0;
|
||||
|
||||
@@ -159,6 +159,8 @@ The same API can also be used to reduce the desired RAM for a VM. It is importan
|
||||
|
||||
Extra PCI devices can be added and removed from a running Cloud Hypervisor instance. This is controlled by making a HTTP API request to the VMM to ask for the additional device to be added, or for the existing device to be removed.
|
||||
|
||||
Note: On AArch64 platform, PCI device hotplug can only be achieved using ACPI. Please refer to the [documentation](arm64.md#uefi-booting) for more information.
|
||||
|
||||
To use PCI device hotplug start the VM with the HTTP server.
|
||||
|
||||
```shell
|
||||
|
||||
@@ -121,6 +121,29 @@ lspci
|
||||
00:04.0 Unassigned class [ffff]: Red Hat, Inc. Virtio RNG
|
||||
```
|
||||
|
||||
### Work with FDT on AArch64
|
||||
|
||||
On AArch64 architecture, the virtual IOMMU can still be used even if ACPI is not
|
||||
enabled. But the effect is different with what the aforementioned test showed.
|
||||
|
||||
When ACPI is disabled, virtual IOMMU is supported through Flattened Device Tree
|
||||
(FDT). In this case, the guest kernel can not tell which device should be
|
||||
IOMMU-attached and which should not. No matter how many devices you attached to
|
||||
the virtual IOMMU by setting `iommu=on` option, all the devices on the PCI bus
|
||||
will be attached to the virtual IOMMU (except the IOMMU itself). Each of the
|
||||
devices will be added into a IOMMU group.
|
||||
|
||||
As a result, the directory content of `/sys/kernel/iommu_groups` would be:
|
||||
|
||||
```bash
|
||||
ls /sys/kernel/iommu_groups/0/devices/
|
||||
0000:00:02.0
|
||||
ls /sys/kernel/iommu_groups/1/devices/
|
||||
0000:00:03.0
|
||||
ls /sys/kernel/iommu_groups/2/devices/
|
||||
0000:00:04.0
|
||||
```
|
||||
|
||||
## Faster mappings
|
||||
|
||||
By default, the guest memory is mapped with 4k pages and no huge pages, which
|
||||
|
||||
159
docs/memory.md
159
docs/memory.md
@@ -13,18 +13,19 @@ easiest way to get started with Cloud-Hypervisor.
|
||||
struct MemoryConfig {
|
||||
size: u64,
|
||||
mergeable: bool,
|
||||
shared: bool,
|
||||
hugepages: bool,
|
||||
hugepage_size: Option<u64>,
|
||||
hotplug_method: HotplugMethod,
|
||||
hotplug_size: Option<u64>,
|
||||
hotplugged_size: Option<u64>,
|
||||
shared: bool,
|
||||
hugepages: bool,
|
||||
hugepage_size: Option<u64>,
|
||||
prefault: bool,
|
||||
zones: Option<Vec<MemoryZoneConfig>>,
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
--memory <memory> Memory parameters "size=<guest_memory_size>,mergeable=on|off,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,hotplug_method=acpi|virtio-mem,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>"
|
||||
--memory <memory> Memory parameters "size=<guest_memory_size>,mergeable=on|off,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,hotplug_method=acpi|virtio-mem,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>,prefault=on|off" [default: size=512M]
|
||||
```
|
||||
|
||||
### `size`
|
||||
@@ -59,46 +60,6 @@ _Example_
|
||||
--memory size=1G,mergeable=on
|
||||
```
|
||||
|
||||
### `shared`
|
||||
|
||||
Specifies if the memory must be `mmap(2)` with `MAP_SHARED` flag.
|
||||
|
||||
By sharing a memory mapping, one can share the guest RAM with other processes
|
||||
running on the host. One can use this option when running vhost-user devices
|
||||
as part of the VM device model, as they will be driven by standalone daemons
|
||||
needing access to the guest RAM content.
|
||||
|
||||
By default this option is turned off, which results in performing `mmap(2)`
|
||||
with `MAP_PRIVATE` flag.
|
||||
|
||||
_Example_
|
||||
|
||||
```
|
||||
--memory size=1G,shared=on
|
||||
```
|
||||
|
||||
### `hugepages` and `hugepage_size`
|
||||
|
||||
Specifies if the memory must be created and `mmap(2)` with `MAP_HUGETLB` and size
|
||||
flags. This performs a memory mapping relying on the specified huge page size. If no huge page size is supplied the system's default huge page size is used.
|
||||
|
||||
By using hugepages, one can improve the overall performance of the VM, assuming
|
||||
the guest will allocate hugepages as well. Another interesting use case is VFIO
|
||||
as it speeds up the VM's boot time since the amount of IOMMU mappings are
|
||||
reduced.
|
||||
|
||||
The user is responsible for ensuring there are sufficient huge pages of the specified size for the VMM to use.
|
||||
Failure to do so may result in strange VMM behaviour, e.g. error with `ReadKernelImage` is common.
|
||||
If there is a strange error with `hugepages` enabled, just disable it or check whether there are enough huge pages.
|
||||
|
||||
By default this option is turned off.
|
||||
|
||||
_Example_
|
||||
|
||||
```
|
||||
--memory size=1G,hugepages=on,hugepage_size=2M
|
||||
```
|
||||
|
||||
### `hotplug_method`
|
||||
|
||||
Selects the way of adding and/or removing memory to/from a booted VM.
|
||||
@@ -144,6 +105,72 @@ _Example_
|
||||
--memory size=1G,hotplug_method=virtio-mem,hotplug_size=1G,hotplugged_size=512M
|
||||
```
|
||||
|
||||
### `shared`
|
||||
|
||||
Specifies if the memory must be `mmap(2)` with `MAP_SHARED` flag.
|
||||
|
||||
By sharing a memory mapping, one can share the guest RAM with other processes
|
||||
running on the host. One can use this option when running vhost-user devices
|
||||
as part of the VM device model, as they will be driven by standalone daemons
|
||||
needing access to the guest RAM content.
|
||||
|
||||
By default this option is turned off, which results in performing `mmap(2)`
|
||||
with `MAP_PRIVATE` flag.
|
||||
|
||||
_Example_
|
||||
|
||||
```
|
||||
--memory size=1G,shared=on
|
||||
```
|
||||
|
||||
### `hugepages` and `hugepage_size`
|
||||
|
||||
Specifies if the memory must be created and `mmap(2)` with `MAP_HUGETLB` and size
|
||||
flags. This performs a memory mapping relying on the specified huge page size.
|
||||
If no huge page size is supplied the system's default huge page size is used.
|
||||
|
||||
By using hugepages, one can improve the overall performance of the VM, assuming
|
||||
the guest will allocate hugepages as well. Another interesting use case is VFIO
|
||||
as it speeds up the VM's boot time since the amount of IOMMU mappings are
|
||||
reduced.
|
||||
|
||||
The user is responsible for ensuring there are sufficient huge pages of the
|
||||
specified size for the VMM to use. Failure to do so may result in strange VMM
|
||||
behaviour, e.g. error with `ReadKernelImage` is common. If there is a strange
|
||||
error with `hugepages` enabled, just disable it or check whether there are enough
|
||||
huge pages.
|
||||
|
||||
By default this option is turned off.
|
||||
|
||||
_Example_
|
||||
|
||||
```
|
||||
--memory size=1G,hugepages=on,hugepage_size=2M
|
||||
```
|
||||
|
||||
### `prefault`
|
||||
|
||||
Specifies if the memory must be `mmap(2)` with `MAP_POPULATE` flag.
|
||||
|
||||
By triggering prefault, one can allocate all required physical memory and create
|
||||
its page tables while calling `mmap`. With physical memory allocated, the number
|
||||
of page faults will decrease during running, and performance will also improve.
|
||||
|
||||
Note that boot of VM will be slower with `prefault` enabled because of allocating
|
||||
physical memory and creating page tables in advance, and physical memory of the
|
||||
specified size will be consumed quickly.
|
||||
|
||||
This option only takes effect at boot of VM. There is also a `prefault` option in
|
||||
restore and its choice will overwrite `prefault` in memory.
|
||||
|
||||
By default this option is turned off.
|
||||
|
||||
_Example_
|
||||
|
||||
```
|
||||
--memory size=1G,prefault=on
|
||||
```
|
||||
|
||||
## Advanced Parameters
|
||||
|
||||
`MemoryZoneConfig` or what is known as `--memory-zone` from the CLI perspective
|
||||
@@ -157,14 +184,16 @@ struct MemoryZoneConfig {
|
||||
file: Option<PathBuf>,
|
||||
shared: bool,
|
||||
hugepages: bool,
|
||||
hugepage_size: Option<u64>,
|
||||
host_numa_node: Option<u32>,
|
||||
hotplug_size: Option<u64>,
|
||||
hotplugged_size: Option<u64>,
|
||||
prefault: bool,
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
--memory-zone <memory-zone> User defined memory zone parameters "size=<guest_memory_region_size>,file=<backing_file>,shared=on|off,hugepages=on|off,host_numa_node=<node_id>,id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>"
|
||||
--memory-zone <memory-zone> User defined memory zone parameters "size=<guest_memory_region_size>,file=<backing_file>,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,host_numa_node=<node_id>,id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>,prefault=on|off"
|
||||
```
|
||||
|
||||
This parameter expects one or more occurences, allowing for a list of memory
|
||||
@@ -252,24 +281,30 @@ _Example_
|
||||
--memory-zone id=mem0,size=1G,shared=on
|
||||
```
|
||||
|
||||
### `hugepages`
|
||||
### `hugepages` and `hugepage_size`
|
||||
|
||||
Specifies if the memory zone must be `mmap(2)` with `MAP_HUGETLB` and
|
||||
`MAP_HUGE_2MB` flags. This performs a memory zone mapping relying on 2MiB
|
||||
pages instead of the default 4kiB pages.
|
||||
Specifies if the memory must be created and `mmap(2)` with `MAP_HUGETLB` and size
|
||||
flags. This performs a memory mapping relying on the specified huge page size.
|
||||
If no huge page size is supplied the system's default huge page size is used.
|
||||
|
||||
By using hugepages, one can improve the overall performance of the VM, assuming
|
||||
the guest will allocate hugepages as well. Another interesting use case is VFIO
|
||||
as it speeds up the VM's boot time since the amount of IOMMU mappings are
|
||||
reduced.
|
||||
|
||||
The user is responsible for ensuring there are sufficient huge pages of the
|
||||
specified size for the VMM to use. Failure to do so may result in strange VMM
|
||||
behaviour, e.g. error with `ReadKernelImage` is common. If there is a strange
|
||||
error with `hugepages` enabled, just disable it or check whether there are enough
|
||||
huge pages.
|
||||
|
||||
By default this option is turned off.
|
||||
|
||||
_Example_
|
||||
|
||||
```
|
||||
--memory size=0
|
||||
--memory-zone id=mem0,size=1G,hugepages=on
|
||||
--memory-zone id=mem0,size=1G,hugepages=on,hugepage_size=2M
|
||||
```
|
||||
|
||||
### `host_numa_node`
|
||||
@@ -336,6 +371,30 @@ _Example_
|
||||
--memory-zone id=mem0,size=1G,hotplug_size=1G,hotplugged_size=512M
|
||||
```
|
||||
|
||||
### `prefault`
|
||||
|
||||
Specifies if the memory must be `mmap(2)` with `MAP_POPULATE` flag.
|
||||
|
||||
By triggering prefault, one can allocate all required physical memory and create
|
||||
its page tables while calling `mmap`. With physical memory allocated, the number
|
||||
of page faults will decrease during running, and performance will also improve.
|
||||
|
||||
Note that boot of VM will be slower with `prefault` enabled because of allocating
|
||||
physical memory and creating page tables in advance, and physical memory of the
|
||||
specified size will be consumed quickly.
|
||||
|
||||
This option only takes effect at boot of VM. There is also a `prefault` option in
|
||||
restore and its choice will overwrite `prefault` in memory.
|
||||
|
||||
By default this option is turned off.
|
||||
|
||||
_Example_
|
||||
|
||||
```
|
||||
--memory size=0
|
||||
--memory-zone id=mem0,size=1G,prefault=on
|
||||
```
|
||||
|
||||
## NUMA settings
|
||||
|
||||
`NumaConfig` or what is known as `--numa` from the CLI perspective has been
|
||||
|
||||
@@ -5,7 +5,7 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.101"
|
||||
libc = "0.2.103"
|
||||
serde = { version = "1.0.130", features = ["rc"] }
|
||||
serde_derive = "1.0.130"
|
||||
serde_json = "1.0.67"
|
||||
serde_json = "1.0.68"
|
||||
|
||||
85
fuzz/Cargo.lock
generated
85
fuzz/Cargo.lock
generated
@@ -20,9 +20,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.43"
|
||||
version = "1.0.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
|
||||
checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
|
||||
|
||||
[[package]]
|
||||
name = "api_client"
|
||||
@@ -39,9 +39,9 @@ checksum = "577b08a4acd7b99869f863c50011b01eb73424ccc798ecd996f2e24817adfca7"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.3.2"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5ab7d9e73059c86c36473f459b52adbd99c3554a4fec492caef460806006f00"
|
||||
checksum = "e6df5aef5c5830360ce5218cecb8f018af3438af5686ae945094affc86fdec63"
|
||||
|
||||
[[package]]
|
||||
name = "arch"
|
||||
@@ -56,6 +56,7 @@ dependencies = [
|
||||
"linux-loader",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"thiserror",
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
@@ -117,9 +118,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.70"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
|
||||
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -145,7 +146,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cloud-hypervisor"
|
||||
version = "17.0.0"
|
||||
version = "18.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"api_client",
|
||||
@@ -284,9 +285,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iced-x86"
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7383772b06135cede839b7270023b46403656a9148024886e721e82639d3f90e"
|
||||
checksum = "46e977036f7f5139d580c7f19ad62df9cb8ebd8410bb569e73585226be80a86f"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"static_assertions",
|
||||
@@ -310,8 +311,8 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "kvm-bindings"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.4.0#1a68725639283e622f4bb64584885b30bfe8be44"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.5.0#9c497710ba9968d8efe15dbae03991b16cf82e23"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
@@ -320,9 +321,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kvm-ioctls"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2924454e22895c738e43331ae310459c74a11ded9c97dc250129ee10d2f9ca2"
|
||||
checksum = "48dc14f9047df1873cf6942caccc7431d19c3d496ca7a0d162260c4cf0f64b76"
|
||||
dependencies = [
|
||||
"kvm-bindings",
|
||||
"libc",
|
||||
@@ -337,9 +338,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.101"
|
||||
version = "0.2.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
@@ -354,9 +355,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-loader"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c819cc8275b0f2c1ed9feec455ca288b45d82932384a6a5f7a86812ee3427459"
|
||||
checksum = "8a5e77493808403a6bd56a301a64ea6b9342e36ea845044bf0dfdf56fe52fa08"
|
||||
dependencies = [
|
||||
"vm-memory",
|
||||
]
|
||||
@@ -391,6 +392,7 @@ name = "net_util"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"epoll",
|
||||
"getrandom",
|
||||
"libc",
|
||||
"log",
|
||||
"net_gen",
|
||||
@@ -438,9 +440,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.29"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
|
||||
checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
@@ -458,9 +460,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -502,8 +504,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "seccompiler"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/seccompiler#da5788d52f1ae8886d8ed4624199b7e9fa64ac04"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01d1292a1131b22ccea49f30bd106f1238b5ddeec1a98d39268dcc31d540e68"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -542,9 +545,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.67"
|
||||
version = "1.0.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950"
|
||||
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -584,9 +587,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.76"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
|
||||
checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -615,18 +618,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.29"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88"
|
||||
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.29"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c"
|
||||
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -635,9 +638,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
@@ -699,7 +702,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio-ioctls"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=main#a8ee64b978ccd000df88732814d626651a091891"
|
||||
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=main#d51c1fad37be30c20385c55a217e2d90972ea31d"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"kvm-bindings",
|
||||
@@ -742,9 +745,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vhost"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a6b90237e10f1a61b35fba73885c3567e1a5a8c40d44daae335f7710210a7dc"
|
||||
checksum = "2d23ddeb452fb4f837526c6298cc8a2f4948e5595b0328a3d61b5eebe51874d7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@@ -887,6 +890,7 @@ dependencies = [
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"vfio-ioctls",
|
||||
"vfio_user",
|
||||
"vhdx",
|
||||
"virtio-devices",
|
||||
"vm-allocator",
|
||||
@@ -899,9 +903,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vmm-sys-util"
|
||||
version = "0.8.0"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01cf11afbc4ebc0d5c7a7748a77d19e2042677fc15faa2f4ccccb27c18a60605"
|
||||
checksum = "733537bded03aaa93543f785ae997727b30d1d9f4a03b7861d23290474242e11"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@@ -936,8 +940,3 @@ name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[patch.unused]]
|
||||
name = "vm-memory"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/rust-vmm/vm-memory?rev=5bd7138758183a73ac0da27ce40c004d95f1a7e9#5bd7138758183a73ac0da27ce40c004d95f1a7e9"
|
||||
|
||||
@@ -10,13 +10,13 @@ cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
block_util = { path = "../block_util" }
|
||||
libc = "0.2.101"
|
||||
libc = "0.2.103"
|
||||
libfuzzer-sys = "0.4.2"
|
||||
qcow = { path = "../qcow" }
|
||||
seccompiler = { git = "https://github.com/rust-vmm/seccompiler"}
|
||||
seccompiler = "0.2.0"
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-devices = { path = "../virtio-devices" }
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vm-memory = "0.6.0"
|
||||
|
||||
@@ -24,8 +24,7 @@ vm-memory = "0.6.0"
|
||||
path = ".."
|
||||
|
||||
[patch.crates-io]
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.4.0", features = ["with-serde", "fam-wrappers"] }
|
||||
vm-memory = { git = "https://github.com/rust-vmm/vm-memory", rev = "5bd7138758183a73ac0da27ce40c004d95f1a7e9"}
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"] }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||
|
||||
# Prevent this from interfering with workspaces
|
||||
|
||||
@@ -11,23 +11,23 @@ mshv = ["mshv-ioctls", "mshv-bindings"]
|
||||
tdx = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.43"
|
||||
anyhow = "1.0.44"
|
||||
epoll = "4.3.1"
|
||||
thiserror = "1.0.29"
|
||||
libc = "0.2.101"
|
||||
thiserror = "1.0.30"
|
||||
libc = "0.2.103"
|
||||
log = "0.4.14"
|
||||
kvm-ioctls = { version = "0.9.0", optional = true }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.4.0", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
kvm-ioctls = { version = "0.10.0", optional = true }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-bindings = {git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
||||
serde = { version = "1.0.130", features = ["rc"] }
|
||||
serde_derive = "1.0.130"
|
||||
serde_json = "1.0.67"
|
||||
serde_json = "1.0.68"
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = { version = "0.8.0", features = ["with-serde"] }
|
||||
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
default-features = false
|
||||
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
|
||||
|
||||
|
||||
@@ -1153,10 +1153,11 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
// 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);
|
||||
for i in 0..32 {
|
||||
state.fp_regs.vregs[i][0] = self
|
||||
state.fp_regs.vregs[i] = self
|
||||
.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U128, off))
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
||||
.into();
|
||||
off += mem::size_of::<u128>();
|
||||
}
|
||||
|
||||
@@ -1233,7 +1234,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
self.fd
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U128, off),
|
||||
state.fp_regs.vregs[i][0],
|
||||
state.fp_regs.vregs[i] as u64,
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
off += mem::size_of::<u128>();
|
||||
@@ -1373,8 +1374,8 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
0x40000020, 0x40000021, 0x40000080, 0x40000081, 0x40000082, 0x40000083, 0x40000084,
|
||||
0x40000090, 0x40000091, 0x40000092, 0x40000093, 0x40000094, 0x40000095, 0x40000096,
|
||||
0x40000097, 0x40000098, 0x40000099, 0x4000009a, 0x4000009b, 0x4000009c, 0x4000009d,
|
||||
0x4000009f, 0x400000b0, 0x400000b1, 0x400000b2, 0x400000b3, 0x400000b4, 0x400000b5,
|
||||
0x400000b6, 0x400000b7,
|
||||
0x4000009e, 0x4000009f, 0x400000b0, 0x400000b1, 0x400000b2, 0x400000b3, 0x400000b4,
|
||||
0x400000b5, 0x400000b6, 0x400000b7,
|
||||
];
|
||||
for index in hyperv_synic_msrs {
|
||||
let msr = kvm_msr_entry {
|
||||
|
||||
@@ -288,9 +288,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
}
|
||||
#[allow(non_upper_case_globals)]
|
||||
fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
|
||||
// Safe because this is just only done during initialization.
|
||||
// TODO don't zero it everytime we enter this function.
|
||||
let hv_message: hv_message = unsafe { std::mem::zeroed() };
|
||||
let hv_message: hv_message = hv_message::default();
|
||||
match self.fd.run(hv_message) {
|
||||
Ok(x) => match x.header.message_type {
|
||||
hv_message_type_HVMSG_X64_HALT => {
|
||||
|
||||
@@ -5,4 +5,4 @@ authors = ["The Chromium OS Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
@@ -6,7 +6,8 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.101"
|
||||
getrandom = "0.2"
|
||||
libc = "0.2.103"
|
||||
log = "0.4.14"
|
||||
net_gen = { path = "../net_gen" }
|
||||
rate_limiter = { path = "../rate_limiter" }
|
||||
@@ -16,9 +17,9 @@ versionize_derive = "0.1.4"
|
||||
virtio-bindings = "0.1.0"
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
pnet = "0.28.0"
|
||||
serde_json = "1.0.67"
|
||||
serde_json = "1.0.68"
|
||||
|
||||
@@ -82,21 +82,12 @@ impl MacAddr {
|
||||
pub fn local_random() -> MacAddr {
|
||||
// Generate a fully random MAC
|
||||
let mut random_bytes = [0u8; MAC_ADDR_LEN];
|
||||
unsafe {
|
||||
// Man page says this function will not be interrupted by a signal
|
||||
// for requests less than 256 bytes
|
||||
if libc::getrandom(
|
||||
random_bytes.as_mut_ptr() as *mut _ as *mut libc::c_void,
|
||||
MAC_ADDR_LEN,
|
||||
0,
|
||||
) < 0
|
||||
{
|
||||
error!(
|
||||
"Error populating MAC address with random data: {}",
|
||||
std::io::Error::last_os_error()
|
||||
)
|
||||
}
|
||||
};
|
||||
if let Err(e) = getrandom::getrandom(&mut random_bytes) {
|
||||
error!(
|
||||
"Error populating MAC address with random data: {}",
|
||||
e.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
// Set the first byte to make the OUI a locally administered OUI
|
||||
random_bytes[0] = 0x2e;
|
||||
|
||||
@@ -10,15 +10,15 @@ kvm = ["vfio-ioctls/kvm"]
|
||||
mshv = ["vfio-ioctls/mshv"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.43"
|
||||
anyhow = "1.0.44"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio-ioctls", branch = "main", default-features = false }
|
||||
vfio_user = { path = "../vfio_user" }
|
||||
vmm-sys-util = "0.8.0"
|
||||
libc = "0.2.101"
|
||||
vmm-sys-util = "0.9.0"
|
||||
libc = "0.2.103"
|
||||
log = "0.4.14"
|
||||
thiserror = "1.0.29"
|
||||
thiserror = "1.0.30"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
|
||||
@@ -197,8 +197,8 @@ pub struct PciConfigIo {
|
||||
impl PciConfigIo {
|
||||
pub fn new(pci_bus: Arc<Mutex<PciBus>>) -> Self {
|
||||
PciConfigIo {
|
||||
pci_bus,
|
||||
config_address: 0,
|
||||
pci_bus,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,6 +222,7 @@ impl PciConfigIo {
|
||||
}
|
||||
|
||||
self.pci_bus
|
||||
.as_ref()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.devices
|
||||
@@ -249,7 +250,7 @@ impl PciConfigIo {
|
||||
return None;
|
||||
}
|
||||
|
||||
let pci_bus = self.pci_bus.lock().unwrap();
|
||||
let pci_bus = self.pci_bus.as_ref().lock().unwrap();
|
||||
if let Some(d) = pci_bus.devices.get(&(device as u32)) {
|
||||
let mut device = d.lock().unwrap();
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ pub use self::device::{
|
||||
pub use self::msi::{msi_num_enabled_vectors, MsiCap, MsiConfig};
|
||||
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_TABLE_ENTRY_SIZE};
|
||||
pub use self::vfio::{VfioPciDevice, VfioPciError};
|
||||
pub use self::vfio_user::{VfioUserPciDevice, VfioUserPciDeviceError};
|
||||
pub use self::vfio_user::{VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError};
|
||||
|
||||
/// PCI has four interrupt pins A->D.
|
||||
#[derive(Copy, Clone)]
|
||||
@@ -42,3 +42,8 @@ impl PciInterruptPin {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub const PCI_CONFIG_IO_PORT: u64 = 0xcf8;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub const PCI_CONFIG_IO_PORT_SIZE: u64 = 0x8;
|
||||
|
||||
@@ -11,7 +11,6 @@ use crate::{
|
||||
use hypervisor::HypervisorVmError;
|
||||
use std::any::Any;
|
||||
use std::os::unix::prelude::AsRawFd;
|
||||
use std::path::Path;
|
||||
use std::ptr::null_mut;
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use std::u32;
|
||||
@@ -20,10 +19,14 @@ use vfio_bindings::bindings::vfio::*;
|
||||
use vfio_ioctls::VfioIrq;
|
||||
use vfio_user::{Client, Error as VfioUserError};
|
||||
use vm_allocator::SystemAllocator;
|
||||
use vm_device::dma_mapping::ExternalDmaMapping;
|
||||
use vm_device::interrupt::{InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig};
|
||||
use vm_device::BusDevice;
|
||||
use vm_memory::bitmap::AtomicBitmap;
|
||||
use vm_memory::{Address, GuestAddress, GuestMemoryRegion, GuestRegionMmap, GuestUsize};
|
||||
use vm_memory::{
|
||||
Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryRegion, GuestRegionMmap,
|
||||
GuestUsize,
|
||||
};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
pub struct VfioUserPciDevice {
|
||||
@@ -61,12 +64,10 @@ impl PciSubclass for PciVfioUserSubclass {
|
||||
impl VfioUserPciDevice {
|
||||
pub fn new(
|
||||
vm: &Arc<dyn hypervisor::Vm>,
|
||||
path: &Path,
|
||||
client: Arc<Mutex<Client>>,
|
||||
msi_interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
|
||||
) -> Result<Self, VfioUserPciDeviceError> {
|
||||
let mut client = Client::new(path).map_err(VfioUserPciDeviceError::Client)?;
|
||||
|
||||
// This is used for the BAR and capabilities only
|
||||
let configuration = PciConfiguration::new(
|
||||
0,
|
||||
@@ -80,12 +81,15 @@ impl VfioUserPciDevice {
|
||||
0,
|
||||
None,
|
||||
);
|
||||
if client.resettable() {
|
||||
client.reset().map_err(VfioUserPciDeviceError::Client)?;
|
||||
let resettable = client.lock().unwrap().resettable();
|
||||
if resettable {
|
||||
client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.reset()
|
||||
.map_err(VfioUserPciDeviceError::Client)?;
|
||||
}
|
||||
|
||||
let client = Arc::new(Mutex::new(client));
|
||||
|
||||
let vfio_wrapper = VfioUserClientWrapper {
|
||||
client: client.clone(),
|
||||
};
|
||||
@@ -483,3 +487,57 @@ impl Drop for VfioUserPciDevice {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VfioUserDmaMapping<M: GuestAddressSpace> {
|
||||
client: Arc<Mutex<Client>>,
|
||||
memory: Arc<M>,
|
||||
}
|
||||
|
||||
impl<M: GuestAddressSpace> VfioUserDmaMapping<M> {
|
||||
pub fn new(client: Arc<Mutex<Client>>, memory: Arc<M>) -> Self {
|
||||
Self { client, memory }
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioUserDmaMapping<M> {
|
||||
fn map(&self, iova: u64, gpa: u64, size: u64) -> std::result::Result<(), std::io::Error> {
|
||||
let mem = self.memory.memory();
|
||||
let guest_addr = GuestAddress(gpa);
|
||||
let region = mem.find_region(guest_addr);
|
||||
|
||||
if let Some(region) = region {
|
||||
let file_offset = region.file_offset().unwrap();
|
||||
let offset = (GuestAddress(gpa).checked_offset_from(region.start_addr())).unwrap()
|
||||
+ file_offset.start();
|
||||
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.dma_map(offset, iova, size, file_offset.file().as_raw_fd())
|
||||
.map_err(|e| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("Error mapping region: {}", e),
|
||||
)
|
||||
})
|
||||
} else {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("Region not found for 0x{:x}", gpa),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn unmap(&self, iova: u64, size: u64) -> std::result::Result<(), std::io::Error> {
|
||||
self.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.dma_unmap(iova, size)
|
||||
.map_err(|e| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("Error unmapping region: {}", e),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ path = "src/qcow.rs"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.4.3"
|
||||
libc = "0.2.101"
|
||||
libc = "0.2.103"
|
||||
log = "0.4.14"
|
||||
remain = "0.2.2"
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
@@ -4,6 +4,6 @@ version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.101"
|
||||
libc = "0.2.103"
|
||||
log = "0.4.14"
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
120
release-notes.md
120
release-notes.md
@@ -1,3 +1,12 @@
|
||||
- [v19.0](#v190)
|
||||
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
|
||||
- [PCI boot time optimisations](#pci-boot-time-optimisations)
|
||||
- [Improved TDX support](#improved-tdx-support)
|
||||
- [Live migration enhancements](#live-migration-enhancements)
|
||||
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
|
||||
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
|
||||
- [Notable bug fixes](#notable-bug-fixes)
|
||||
- [Contributors](#contributors)
|
||||
- [v18.0](#v180)
|
||||
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
|
||||
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
|
||||
@@ -7,23 +16,23 @@
|
||||
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
||||
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
||||
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
||||
- [Notable bug fixes](#notable-bug-fixes)
|
||||
- [Contributors](#contributors)
|
||||
- [Notable bug fixes](#notable-bug-fixes-1)
|
||||
- [Contributors](#contributors-1)
|
||||
- [v17.0](#v170)
|
||||
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
|
||||
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
|
||||
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
|
||||
- [Improved SGX support](#improved-sgx-support)
|
||||
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
|
||||
- [Notable bug fixes](#notable-bug-fixes-1)
|
||||
- [Contributors](#contributors-1)
|
||||
- [Notable bug fixes](#notable-bug-fixes-2)
|
||||
- [Contributors](#contributors-2)
|
||||
- [v16.0](#v160)
|
||||
- [Improved live migration support](#improved-live-migration-support)
|
||||
- [Improved `vhost-user` support](#improved-vhost-user-support)
|
||||
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
|
||||
- [Notable bug fixes](#notable-bug-fixes-2)
|
||||
- [Notable bug fixes](#notable-bug-fixes-3)
|
||||
- [Removed functionality](#removed-functionality)
|
||||
- [Contributors](#contributors-2)
|
||||
- [Contributors](#contributors-3)
|
||||
- [v15.0](#v150)
|
||||
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
||||
- [Network device rate limiting](#network-device-rate-limiting)
|
||||
@@ -31,7 +40,7 @@
|
||||
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
||||
- [Bug fixes](#bug-fixes)
|
||||
- [Deprecations](#deprecations)
|
||||
- [Contributors](#contributors-3)
|
||||
- [Contributors](#contributors-4)
|
||||
- [v0.14.1](#v0141)
|
||||
- [v0.14.0](#v0140)
|
||||
- [Structured event monitoring](#structured-event-monitoring)
|
||||
@@ -41,7 +50,7 @@
|
||||
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
|
||||
- [Block device rate limiting](#block-device-rate-limiting)
|
||||
- [Deprecations](#deprecations-1)
|
||||
- [Contributors](#contributors-4)
|
||||
- [Contributors](#contributors-5)
|
||||
- [v0.13.0](#v0130)
|
||||
- [Wider VFIO device support](#wider-vfio-device-support)
|
||||
- [Improved huge page support](#improved-huge-page-support)
|
||||
@@ -49,33 +58,33 @@
|
||||
- [VHD disk image support](#vhd-disk-image-support)
|
||||
- [Improved Virtio device threading](#improved-virtio-device-threading)
|
||||
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
|
||||
- [Contributors](#contributors-5)
|
||||
- [Contributors](#contributors-6)
|
||||
- [v0.12.0](#v0120)
|
||||
- [ARM64 enhancements](#arm64-enhancements)
|
||||
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
|
||||
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
|
||||
- [Enhanced "info" API](#enhanced-info-api)
|
||||
- [Contributors](#contributors-6)
|
||||
- [Contributors](#contributors-7)
|
||||
- [v0.11.0](#v0110)
|
||||
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
|
||||
- [Windows Guest Support](#windows-guest-support)
|
||||
- [`vhost-user` "Self Spawning" Deprecation](#vhost-user-self-spawning-deprecation)
|
||||
- [`virtio-mmmio` Removal](#virtio-mmmio-removal)
|
||||
- [`virtio-mmio` Removal](#virtio-mmio-removal)
|
||||
- [Snapshot/Restore support for ARM64](#snapshotrestore-support-for-arm64)
|
||||
- [Improved Linux Boot Time](#improved-linux-boot-time)
|
||||
- [`SIGTERM/SIGINT` Interrupt Signal Handling](#sigtermsigint-interrupt-signal-handling)
|
||||
- [Default Log Level Changed](#default-log-level-changed)
|
||||
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
|
||||
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||
- [Contributors](#contributors-7)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Contributors](#contributors-8)
|
||||
- [v0.10.0](#v0100)
|
||||
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
|
||||
- [Memory Zones](#memory-zones)
|
||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
|
||||
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Contributors](#contributors-8)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Contributors](#contributors-9)
|
||||
- [v0.9.0](#v090)
|
||||
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
|
||||
- [Block and Network Device Statistics](#block-and-network-device-statistics)
|
||||
@@ -88,17 +97,17 @@
|
||||
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
|
||||
- [Intel SGX Support](#intel-sgx-support)
|
||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Contributors](#contributors-9)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||
- [Contributors](#contributors-10)
|
||||
- [v0.8.0](#v080)
|
||||
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
|
||||
- [Experimental ARM64 Support](#experimental-arm64-support)
|
||||
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
|
||||
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
|
||||
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes)
|
||||
- [Contributors](#contributors-10)
|
||||
- [Contributors](#contributors-11)
|
||||
- [v0.7.0](#v070)
|
||||
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
|
||||
- [Alternative `libc` Support](#alternative-libc-support)
|
||||
@@ -108,14 +117,14 @@
|
||||
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
||||
- [Updated Distribution Support](#updated-distribution-support)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
||||
- [Contributors](#contributors-11)
|
||||
- [Contributors](#contributors-12)
|
||||
- [v0.6.0](#v060)
|
||||
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
|
||||
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
|
||||
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
|
||||
- [Command Line Interface](#command-line-interface)
|
||||
- [PVH Boot](#pvh-boot)
|
||||
- [Contributors](#contributors-12)
|
||||
- [Contributors](#contributors-13)
|
||||
- [v0.5.1](#v051)
|
||||
- [v0.5.0](#v050)
|
||||
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
||||
@@ -123,7 +132,7 @@
|
||||
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
||||
- [Development Tools](#development-tools)
|
||||
- [Kata Containers Integration](#kata-containers-integration)
|
||||
- [Contributors](#contributors-13)
|
||||
- [Contributors](#contributors-14)
|
||||
- [v0.4.0](#v040)
|
||||
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
||||
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
||||
@@ -132,7 +141,7 @@
|
||||
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
|
||||
- [PCI BAR reprogramming](#pci-bar-reprogramming)
|
||||
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
|
||||
- [Contributors](#contributors-14)
|
||||
- [Contributors](#contributors-15)
|
||||
- [v0.3.0](#v030)
|
||||
- [Block device offloading](#block-device-offloading)
|
||||
- [Network device backend](#network-device-backend)
|
||||
@@ -159,6 +168,69 @@
|
||||
- [Unit testing](#unit-testing)
|
||||
- [Integration tests parallelization](#integration-tests-parallelization)
|
||||
|
||||
# v19.0
|
||||
|
||||
This release has been tracked through the [v19.0
|
||||
project](https://github.com/cloud-hypervisor/cloud-hypervisor/projects/22).
|
||||
|
||||
### Improved PTY handling for serial and `virtio-console`
|
||||
|
||||
The PTY support for serial has been enhanced with improved buffering when the
|
||||
the PTY is not yet connected to. Using `virtio-console` with PTY now results in
|
||||
the console being resized if the PTY window is also resized.
|
||||
|
||||
### PCI boot time optimisations
|
||||
|
||||
Multiple optimisations have been made to the PCI handling resulting in
|
||||
significant improvements in the boot time of the guest.
|
||||
|
||||
### Improved TDX support
|
||||
|
||||
When using the latest TDVF firmware the ACPI tables created by the VMM are now
|
||||
exposed via the firmware to the guest.
|
||||
|
||||
### Live migration enhancements
|
||||
|
||||
Live migration support has been enhanced to support migration with `virtio-mem`
|
||||
based memory hotplug and the `virtio-balloon` device now supports live
|
||||
migration.
|
||||
|
||||
### `virtio-mem` support with `vfio-user`
|
||||
|
||||
The use of `vfio-user` userspaces devices can now be used in conjunction with
|
||||
`virtio-mem` based memory hotplug and unplug.
|
||||
|
||||
### AArch64 for `virtio-iommu`
|
||||
|
||||
A paravirtualised IOMMU can now be used on the AArch64 platform.
|
||||
|
||||
### Notable bug fixes
|
||||
|
||||
* ACPI hotplugged memory is correctly restored after a live migration or
|
||||
snapshot/restore (#3165)
|
||||
* Multiple devices from the same IOMMU group can be passed through via VFIO
|
||||
(#3078 #3113)
|
||||
* Live migration with large blocks of memory was buggy due to an in issue in
|
||||
the underlying crate (#3157)
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Alyssa Ross <hi@alyssa.is>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Henry Wang <Henry.Wang@arm.com>
|
||||
* Hui Zhu <teawater@antfin.com>
|
||||
* Jianyong Wu <jianyong.wu@arm.com>
|
||||
* Li Yu <liyu.yukiteru@bytedance.com>
|
||||
* Michael Zhao <michael.zhao@arm.com>
|
||||
* Muminul Islam <muislam@microsoft.com>
|
||||
* Rob Bradford <robert.bradford@intel.com>
|
||||
* Sebastien Boeuf <sebastien.boeuf@intel.com>
|
||||
* Wei Liu <liuwe@microsoft.com>
|
||||
* William Douglas <william.douglas@intel.com>
|
||||
* Yu Li <liyu.yukiteru@bytedance.com>
|
||||
|
||||
# v18.0
|
||||
|
||||
This release has been tracked through the [v18.0
|
||||
@@ -629,7 +701,7 @@ Automatically spawning a `vhost-user-net` or `vhost-user-block` backend is now
|
||||
deprecated. Users of this functionality will receive a warning and should make
|
||||
adjustments. The functionality will be removed in the next release.
|
||||
|
||||
### `virtio-mmmio` Removal
|
||||
### `virtio-mmio` Removal
|
||||
|
||||
Support for using the `virtio-mmio` transport, rather than using PCI, has been
|
||||
removed. This has been to simplify the code and significantly
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FROM ubuntu:20.04 as dev
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG RUST_TOOLCHAIN="1.54.0"
|
||||
ARG RUST_TOOLCHAIN="1.55.0"
|
||||
ARG CLH_SRC_DIR="/cloud-hypervisor"
|
||||
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
|
||||
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"
|
||||
@@ -59,9 +59,19 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
# On AArch64, `setcap` binary should be installed via `libcap2-bin`.
|
||||
# The `setcap` binary is used in integration tests.
|
||||
# `libguestfs-tools` is used for modifying cloud image kernel, and it requires
|
||||
# kernel (any version) image in `/boot` and modules in `/lib/modules`.
|
||||
apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq libcap2-bin \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
||||
libcap2-bin \
|
||||
libguestfs-tools \
|
||||
linux-image-5.8.0-63-generic \
|
||||
autotools-dev \
|
||||
autoconf \
|
||||
automake \
|
||||
perl \
|
||||
texinfo \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*; fi
|
||||
|
||||
@@ -91,3 +101,26 @@ RUN export ARCH="$(uname -m)" \
|
||||
RUN echo 'source $CARGO_HOME/env' >> $HOME/.bashrc \
|
||||
&& mkdir $HOME/.cargo \
|
||||
&& ln -s $CARGO_HOME/env $HOME/.cargo/env
|
||||
|
||||
# install virtiofsd
|
||||
RUN git clone --depth 1 https://gitlab.com/virtio-fs/qemu.git -b qemu5.0-virtiofs-dax \
|
||||
&& cd qemu \
|
||||
&& ./configure --prefix=$PWD --target-list=x86_64-softmmu \
|
||||
&& make virtiofsd -j `nproc` \
|
||||
&& cp virtiofsd /usr/local/bin \
|
||||
&& cd .. && rm -rf qemu
|
||||
|
||||
# install SPDK NVMe
|
||||
RUN git clone https://github.com/spdk/spdk \
|
||||
&& cd spdk \
|
||||
&& git checkout a827fd7eeca67209d4c0aaad9a3ed55692e7e36e \
|
||||
&& git submodule update --init \
|
||||
&& apt-get update \
|
||||
&& ./scripts/pkgdep.sh \
|
||||
&& ./configure --with-vfio-user \
|
||||
&& make -j `nproc` \
|
||||
&& mkdir /usr/local/bin/spdk-nvme \
|
||||
&& cp ./build/bin/nvmf_tgt /usr/local/bin/spdk-nvme \
|
||||
&& cp ./scripts/rpc.py /usr/local/bin/spdk-nvme \
|
||||
&& cp -r ./scripts/rpc /usr/local/bin/spdk-nvme \
|
||||
&& cd .. && rm -rf spdk
|
||||
|
||||
@@ -1947,7 +1947,7 @@ CONFIG_RTC_INTF_DEV=y
|
||||
# CONFIG_RTC_DRV_DS1685_FAMILY is not set
|
||||
# CONFIG_RTC_DRV_DS1742 is not set
|
||||
# CONFIG_RTC_DRV_DS2404 is not set
|
||||
# CONFIG_RTC_DRV_EFI is not set
|
||||
CONFIG_RTC_DRV_EFI=y
|
||||
# CONFIG_RTC_DRV_STK17TA8 is not set
|
||||
# CONFIG_RTC_DRV_M48T86 is not set
|
||||
# CONFIG_RTC_DRV_M48T35 is not set
|
||||
|
||||
215
scripts/check-image-compatability.sh
Executable file
215
scripts/check-image-compatability.sh
Executable file
@@ -0,0 +1,215 @@
|
||||
#!/bin/bash
|
||||
: '
|
||||
This script checks if an image is compatible with Cloud Hypervisor.
|
||||
At first, it detects the image type(raw or qcow2),
|
||||
partition type whether it is DOS or GPT.
|
||||
Then it mounts the image and checks if VIRTIO Configs
|
||||
are enabled in the kernel config. In the end, it provides
|
||||
a message about the compatibility of the image.
|
||||
'
|
||||
|
||||
|
||||
|
||||
usage="$(basename "$0") [-h] -f -w -- program to check Cloud Hypervisor compatible image
|
||||
|
||||
where:
|
||||
-h show this help text
|
||||
-f image file location
|
||||
-w directory to be used for temporary files"
|
||||
|
||||
function check_command {
|
||||
if ! command -v $1 &> /dev/null
|
||||
then
|
||||
echo "Command $1 could not be found"
|
||||
exit 1
|
||||
fi
|
||||
};
|
||||
|
||||
function check_if_root {
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Please run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
};
|
||||
|
||||
check_if_root
|
||||
working_dir=""
|
||||
while getopts ':hf:w:' option; do
|
||||
case "$option" in
|
||||
h) echo "$usage"
|
||||
exit
|
||||
;;
|
||||
f) file_name=$OPTARG
|
||||
;;
|
||||
w) working_dir=$OPTARG
|
||||
;;
|
||||
:) printf "missing argument for -%s\n" "$OPTARG" >&2
|
||||
echo "$usage" >&2
|
||||
exit 1
|
||||
;;
|
||||
\?) printf "illegal option: -%s\n" "$OPTARG" >&2
|
||||
echo "$usage" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
if [ -z "${file_name}" ]; then
|
||||
echo "You must provide the image file name"
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -f ${file_name} ]]; then
|
||||
echo "File ${file_name} does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
file_abs_path=`readlink -m ${file_name}`
|
||||
if [[ "${working_dir}" != "" && ! -d "${working_dir}" ]]; then
|
||||
echo "Directory ${working_dir} does not exist"
|
||||
exit 1
|
||||
elif [[ "${working_dir}" == "" ]]; then
|
||||
working_dir=`mktemp -d`
|
||||
tmp_created=1
|
||||
else
|
||||
working_dir=`readlink -m ${working_dir}`
|
||||
fi
|
||||
|
||||
#get file extension and image type
|
||||
extension="${file_name##*.}"
|
||||
filename="${file_name%.*}"
|
||||
dest_file=${working_dir}/${filename}.raw
|
||||
image_type=$(qemu-img info ${file_abs_path} | grep 'file format:' | awk '{ print $3 }')
|
||||
echo "Image type detected as ${image_type}"
|
||||
|
||||
|
||||
if [[ "${image_type}" == "raw" ]]; then
|
||||
dest_file=${file_abs_path}
|
||||
elif [[ "$image_type" == "qcow2" ]]; then
|
||||
if lsmod | grep "nbd" &> /dev/null ; then
|
||||
echo "Module nbd is loaded!"
|
||||
else
|
||||
echo "Module nbd is not loaded. Trying to load the module"
|
||||
modprobe nbd max_part=8
|
||||
if [ $? != 0 ]; then
|
||||
echo "failed to load nbd module. Exiting"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
check_command qemu-img
|
||||
dest_file=/dev/nbd0
|
||||
qemu-nbd --connect=${dest_file} ${file_abs_path} --read-only
|
||||
fi
|
||||
|
||||
check_command blkid
|
||||
#get part info
|
||||
part_type=$(blkid -o value -s PTTYPE ${dest_file})
|
||||
|
||||
check_command partx
|
||||
nr_partitions=`partx -g ${dest_file} | wc -l`
|
||||
|
||||
check_command fdisk
|
||||
out=`fdisk -l ${dest_file} --bytes | grep -i -A ${nr_partitions} 'Device' | tail -n +2`
|
||||
|
||||
IFS='
|
||||
'
|
||||
i=0
|
||||
declare -A liness
|
||||
for x in $out ; do
|
||||
lines[$i]=$x
|
||||
i=$((i+1))
|
||||
done
|
||||
|
||||
declare -A partitions
|
||||
IFS=' '
|
||||
i=0
|
||||
ROWS=${#lines[@]}
|
||||
|
||||
for line in "${lines[@]}";
|
||||
do
|
||||
j=0
|
||||
read -a str_arr <<< "$line"
|
||||
for val in "${str_arr[@]}";
|
||||
do
|
||||
if [[ "$val" != "*" ]]; then
|
||||
partitions[$i,$j]=$val
|
||||
j=$((j+1))
|
||||
fi
|
||||
done
|
||||
i=$((i+1))
|
||||
done
|
||||
|
||||
COLUMNS=$j
|
||||
COUNT=${#partitions[@]}
|
||||
START_ADDRESS_INDEX=1
|
||||
FILE_SYS_INDEX2=$((COLUMNS-1))
|
||||
FILE_SYS_INDEX1=$((COLUMNS-2))
|
||||
DEVICE_INDEX=0
|
||||
# Here we have all the partition info now lets mount and analyze the contents
|
||||
for ((i=0;i<ROWS;i++)) do
|
||||
if [[ "$part_type" == "gpt" && "${partitions[$i,${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i,${FILE_SYS_INDEX2}]}" == "filesystem" ]]; then
|
||||
echo "The image has GPT partitions"
|
||||
MOUNT_ROW=$i
|
||||
break
|
||||
elif [[ "$part_type" == "dos" && "${partitions[$i,${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i,${FILE_SYS_INDEX2}]}" == "" ]]; then
|
||||
echo "The image has DOS partitions"
|
||||
MOUNT_ROW=$i
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
start_address=${partitions[${MOUNT_ROW},${START_ADDRESS_INDEX}]}
|
||||
offset=$((start_address*512))
|
||||
|
||||
MOUNT_DIR=/mnt/clh-img-check/
|
||||
rm -rf ${MOUNT_DIR}
|
||||
mkdir ${MOUNT_DIR}
|
||||
if [[ "${image_type}" == "raw" ]]; then
|
||||
mount -o ro,loop,offset=$offset ${dest_file} ${MOUNT_DIR}
|
||||
elif [[ "${image_type}" == "qcow2" ]]; then
|
||||
mount -o ro ${partitions[${MOUNT_ROW},${DEVICE_INDEX}]} ${MOUNT_DIR}
|
||||
fi
|
||||
|
||||
CONFIG_DIR=${MOUNT_DIR}boot/
|
||||
if [[ "$part_type" == "dos" ]]; then
|
||||
CONFIG_DIR=${MOUNT_DIR}
|
||||
fi
|
||||
|
||||
#check VIRTIO
|
||||
HAS_VIRTIO=1
|
||||
for conf_file in ${CONFIG_DIR}config*; do
|
||||
out=`grep -E "CONFIG_VIRTIO=y|CONFIG_VIRTIO_BLK=y|CONFIG_VIRTIO_BLK=m" ${conf_file} | wc -l`
|
||||
if [[ "$out" != "2" ]]; then
|
||||
echo "VIRTIO not found"
|
||||
HAS_VIRTIO=0
|
||||
fi
|
||||
done
|
||||
|
||||
#clean up
|
||||
umount ${MOUNT_DIR}
|
||||
|
||||
if [[ "${tmp_created}" == "1" ]]; then
|
||||
rm -rf ${working_dir}
|
||||
fi
|
||||
|
||||
if [[ "${image_type}" == "qcow2" ]];then
|
||||
qemu-nbd --disconnect ${dest_file} > /dev/null
|
||||
fi
|
||||
|
||||
result=""
|
||||
if [[ "${part_type}" == "dos" ]]; then
|
||||
result="dos mode not supported"
|
||||
fi
|
||||
if [[ "${HAS_VIRTIO}" == "0" ]]; then
|
||||
if [[ "$result" != "" ]]; then
|
||||
result="${result},"
|
||||
fi
|
||||
result="$result VirtIO module not found in the image"
|
||||
fi
|
||||
if [[ "$result" == "" ]];then
|
||||
echo "No incompatibilities found"
|
||||
else
|
||||
echo "$result"
|
||||
fi
|
||||
@@ -243,8 +243,8 @@ cmd_build() {
|
||||
ensure_latest_ctr
|
||||
|
||||
process_volumes_args
|
||||
if [[ "$hypervisor" != "kvm" ]]; then
|
||||
die "Hypervisor value must be kvm"
|
||||
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
|
||||
die "Hypervisor value must be kvm or mshv"
|
||||
fi
|
||||
if [[ "$hypervisor" = "mshv" ]]; then
|
||||
exported_device="/dev/mshv"
|
||||
@@ -336,12 +336,14 @@ cmd_tests() {
|
||||
esac
|
||||
shift
|
||||
done
|
||||
if [[ "$hypervisor" != "kvm" ]]; then
|
||||
die "Hypervisor value must be kvm"
|
||||
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
|
||||
die "Hypervisor value must be kvm or mshv"
|
||||
fi
|
||||
|
||||
if [[ "$hypervisor" = "mshv" ]]; then
|
||||
exported_device="/dev/mshv"
|
||||
fi
|
||||
|
||||
set -- "$@" '--hypervisor' $hypervisor
|
||||
|
||||
ensure_build_dir
|
||||
|
||||
@@ -8,70 +8,97 @@ export BUILD_TARGET=${BUILD_TARGET-aarch64-unknown-linux-gnu}
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
WORKLOADS_LOCK="$WORKLOADS_DIR/integration_test.lock"
|
||||
EDK2_BUILD_DIR="$WORKLOADS_DIR/edk2_build"
|
||||
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
|
||||
build_edk2() {
|
||||
EDK2_REPO="https://github.com/tianocore/edk2.git"
|
||||
EDK2_DIR="edk2"
|
||||
EDK2_BRANCH="master"
|
||||
EDK2_PLAT_REPO="https://github.com/tianocore/edk2-platforms.git"
|
||||
EDK2_PLAT_DIR="edk2-platforms"
|
||||
ACPICA_REPO="https://github.com/acpica/acpica.git"
|
||||
ACPICA_DIR="acpica"
|
||||
# Checkout source code of a GIT repo with specified branch and commit
|
||||
# Args:
|
||||
# $1: Target directory
|
||||
# $2: GIT URL of the repo
|
||||
# $3: Required branch
|
||||
# $4: Required commit (optional)
|
||||
checkout_repo() {
|
||||
SRC_DIR="$1"
|
||||
GIT_URL="$2"
|
||||
GIT_BRANCH="$3"
|
||||
GIT_COMMIT="$4"
|
||||
|
||||
export WORKSPACE="$EDK2_BUILD_DIR"
|
||||
export PACKAGES_PATH="$WORKSPACE/$EDK2_DIR:$WORKSPACE/$EDK2_PLAT_DIR"
|
||||
export IASL_PREFIX="$WORKSPACE/acpica/generate/unix/bin/"
|
||||
|
||||
cd "$WORKLOADS_DIR"
|
||||
if [ ! -d "$WORKSPACE" ]; then
|
||||
mkdir -p "$WORKSPACE"
|
||||
fi
|
||||
|
||||
pushd "$WORKSPACE"
|
||||
|
||||
# Check whether the local HEAD commit same as the remote HEAD or not. Remove the folder if they are different.
|
||||
if [ -d "$EDK2_DIR" ]; then
|
||||
pushd $EDK2_DIR
|
||||
# Check whether the local HEAD commit same as the requested commit or not.
|
||||
# If commit is not specified, compare local HEAD and remote HEAD.
|
||||
# Remove the folder if there is difference.
|
||||
if [ -d "$SRC_DIR" ]; then
|
||||
pushd $SRC_DIR
|
||||
git fetch
|
||||
EDK2_LOCAL_HEAD=$(git rev-parse HEAD)
|
||||
EDK2_REMOTE_HEAD=$(git rev-parse remotes/origin/$EDK2_BRANCH)
|
||||
SRC_LOCAL_COMMIT=$(git rev-parse HEAD)
|
||||
if [ -z "$GIT_COMMIT" ]; then
|
||||
GIT_COMMIT=$(git rev-parse remotes/origin/"$GIT_BRANCH")
|
||||
fi
|
||||
popd
|
||||
if [ "$EDK2_LOCAL_HEAD" != "$EDK2_REMOTE_HEAD" ]; then
|
||||
# If EDK2 code is out of date, remove and rebuild all
|
||||
rm -rf "$EDK2_DIR"
|
||||
rm -rf "$EDK2_PLAT_DIR"
|
||||
rm -rf "$ACPICA_DIR"
|
||||
if [ "$SRC_LOCAL_COMMIT" != "$GIT_COMMIT" ]; then
|
||||
rm -rf "$SRC_DIR"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -d "$EDK2_DIR" ]; then
|
||||
time git clone --depth 1 "$EDK2_REPO" -b "$EDK2_BRANCH" "$EDK2_DIR"
|
||||
pushd $EDK2_DIR
|
||||
git submodule update --init
|
||||
popd
|
||||
# Checkout the specified branch and commit (if required)
|
||||
if [ ! -d "$SRC_DIR" ]; then
|
||||
git clone --depth 1 "$GIT_URL" -b "$GIT_BRANCH" "$SRC_DIR"
|
||||
if [ "$GIT_COMMIT" ]; then
|
||||
pushd "$SRC_DIR"
|
||||
git fetch --depth 1 origin "$GIT_COMMIT"
|
||||
git reset --hard FETCH_HEAD
|
||||
popd
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
build_custom_linux() {
|
||||
SRCDIR=$PWD
|
||||
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
||||
LINUX_CUSTOM_BRANCH="ch-5.14"
|
||||
LINUX_CUSTOM_URL="https://github.com/cloud-hypervisor/linux.git"
|
||||
|
||||
checkout_repo "$LINUX_CUSTOM_DIR" "$LINUX_CUSTOM_URL" "$LINUX_CUSTOM_BRANCH"
|
||||
|
||||
cp $SRCDIR/resources/linux-config-aarch64 $LINUX_CUSTOM_DIR/.config
|
||||
|
||||
pushd $LINUX_CUSTOM_DIR
|
||||
time make -j `nproc`
|
||||
cp arch/arm64/boot/Image "$WORKLOADS_DIR/" || exit 1
|
||||
cp arch/arm64/boot/Image.gz "$WORKLOADS_DIR/" || exit 1
|
||||
popd
|
||||
}
|
||||
|
||||
build_edk2() {
|
||||
EDK2_BUILD_DIR="$WORKLOADS_DIR/edk2_build"
|
||||
EDK2_REPO="https://github.com/tianocore/edk2.git"
|
||||
EDK2_DIR="$EDK2_BUILD_DIR/edk2"
|
||||
EDK2_PLAT_REPO="https://github.com/tianocore/edk2-platforms.git"
|
||||
EDK2_PLAT_DIR="$EDK2_BUILD_DIR/edk2-platforms"
|
||||
ACPICA_REPO="https://github.com/acpica/acpica.git"
|
||||
ACPICA_DIR="$EDK2_BUILD_DIR/acpica"
|
||||
export WORKSPACE="$EDK2_BUILD_DIR"
|
||||
export PACKAGES_PATH="$EDK2_DIR:$EDK2_PLAT_DIR"
|
||||
export IASL_PREFIX="$ACPICA_DIR/generate/unix/bin/"
|
||||
|
||||
if [ ! -d "$EDK2_BUILD_DIR" ]; then
|
||||
mkdir -p "$EDK2_BUILD_DIR"
|
||||
fi
|
||||
|
||||
if [ ! -d "$EDK2_PLAT_DIR" ]; then
|
||||
time git clone --depth 1 "$EDK2_PLAT_REPO" -b master "$EDK2_PLAT_DIR"
|
||||
fi
|
||||
|
||||
if [ ! -d "$ACPICA_DIR" ]; then
|
||||
time git clone --depth 1 "$ACPICA_REPO" -b master "$ACPICA_DIR"
|
||||
fi
|
||||
|
||||
make -C "$ACPICA_DIR"/
|
||||
# Prepare source code
|
||||
checkout_repo "$EDK2_DIR" "$EDK2_REPO" master "46b4606ba23498d3d0e66b53e498eb3d5d592586"
|
||||
pushd "$EDK2_DIR"
|
||||
git submodule update --init
|
||||
popd
|
||||
checkout_repo "$EDK2_PLAT_DIR" "$EDK2_PLAT_REPO" master "8227e9e9f6a8aefbd772b40138f835121ccb2307"
|
||||
checkout_repo "$ACPICA_DIR" "$ACPICA_REPO" master "b9c69f81a05c45611c91ea9cbce8756078d76233"
|
||||
|
||||
pushd "$EDK2_BUILD_DIR"
|
||||
# Build
|
||||
make -C acpica -j `nproc`
|
||||
source edk2/edksetup.sh
|
||||
make -C edk2/BaseTools
|
||||
|
||||
build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtCloudHv.dsc -b RELEASE
|
||||
make -C edk2/BaseTools -j `nproc`
|
||||
build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtCloudHv.dsc -b RELEASE -n 0
|
||||
cp Build/ArmVirtCloudHv-AARCH64/RELEASE_GCC5/FV/CLOUDHV_EFI.fd "$WORKLOADS_DIR"
|
||||
|
||||
echo "Info: build UEFI successfully"
|
||||
|
||||
popd
|
||||
}
|
||||
|
||||
@@ -105,7 +132,7 @@ update_workloads() {
|
||||
popd
|
||||
fi
|
||||
|
||||
FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-arm64-custom.raw"
|
||||
FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-arm64-custom-20210929-0.raw"
|
||||
FOCAL_OS_RAW_IMAGE_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_RAW_IMAGE_NAME"
|
||||
FOCAL_OS_RAW_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_NAME"
|
||||
if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
|
||||
@@ -114,9 +141,7 @@ update_workloads() {
|
||||
popd
|
||||
fi
|
||||
|
||||
# Convert the raw image to qcow2 image to remove compressed blocks from the disk. Therefore letting the
|
||||
# qcow2 format image can be directly used in the integration test.
|
||||
FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME="focal-server-cloudimg-arm64-custom.qcow2"
|
||||
FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME="focal-server-cloudimg-arm64-custom-20210929-0.qcow2"
|
||||
FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
|
||||
FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
|
||||
if [ ! -f "$FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE" ]; then
|
||||
@@ -159,59 +184,26 @@ update_workloads() {
|
||||
fi
|
||||
popd
|
||||
|
||||
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
||||
PE_IMAGE="$WORKLOADS_DIR/Image"
|
||||
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
||||
# Build custom kernel for guest VMs
|
||||
build_custom_linux
|
||||
|
||||
build_custom_linux_kernel() {
|
||||
pushd $LINUX_CUSTOM_DIR
|
||||
time make -j `nproc`
|
||||
cp arch/arm64/boot/Image $WORKLOADS_DIR/Image || exit 1
|
||||
popd
|
||||
}
|
||||
|
||||
SRCDIR=$PWD
|
||||
LINUX_CUSTOM_BRANCH="ch-5.14"
|
||||
|
||||
# Check whether the local HEAD commit same as the remote HEAD or not. Remove the folder if they are different.
|
||||
if [ -d "$LINUX_CUSTOM_DIR" ]; then
|
||||
pushd $LINUX_CUSTOM_DIR
|
||||
git fetch
|
||||
LINUX_CUSTOM_LOCAL_HEAD=$(git rev-parse HEAD)
|
||||
LINUX_CUSTOM_REMOTE_HEAD=$(git rev-parse remotes/origin/$LINUX_CUSTOM_BRANCH)
|
||||
popd
|
||||
if [ "$LINUX_CUSTOM_LOCAL_HEAD" != "$LINUX_CUSTOM_REMOTE_HEAD" ]; then
|
||||
rm -rf "$LINUX_CUSTOM_DIR"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -d "$LINUX_CUSTOM_DIR" ]; then
|
||||
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b $LINUX_CUSTOM_BRANCH $LINUX_CUSTOM_DIR
|
||||
fi
|
||||
|
||||
cp $SRCDIR/resources/linux-config-aarch64 $LINUX_CUSTOM_DIR/.config
|
||||
build_custom_linux_kernel
|
||||
|
||||
VIRTIOFSD="$WORKLOADS_DIR/virtiofsd"
|
||||
QEMU_DIR="qemu_build"
|
||||
|
||||
if [ ! -f "$VIRTIOFSD" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
git clone --depth 1 "https://gitlab.com/virtio-fs/qemu.git" -b "qemu5.0-virtiofs-dax" $QEMU_DIR
|
||||
pushd $QEMU_DIR
|
||||
time ./configure --prefix=$PWD --target-list=aarch64-softmmu
|
||||
time make virtiofsd -j `nproc`
|
||||
cp virtiofsd $VIRTIOFSD || exit 1
|
||||
popd
|
||||
rm -rf $QEMU_DIR
|
||||
popd
|
||||
fi
|
||||
# Update the kernel in the cloud image for some tests that requires recent kernel version
|
||||
FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_NAME="focal-server-cloudimg-arm64-custom-20210929-0-update-kernel.raw"
|
||||
cp "$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_NAME" "$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_NAME"
|
||||
FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR="$WORKLOADS_DIR/focal-server-cloudimg-root"
|
||||
mkdir -p "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"
|
||||
# Mount the 'raw' image, replace the compressed kernel file and umount the working folder
|
||||
guestmount -a "$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_NAME" -m /dev/sda1 "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR" || exit 1
|
||||
cp "$WORKLOADS_DIR"/Image.gz "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"/boot/vmlinuz
|
||||
guestunmount "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"
|
||||
|
||||
# Build virtiofsd
|
||||
VIRTIOFSD_RS="$WORKLOADS_DIR/virtiofsd-rs"
|
||||
VIRTIOFSD_RS_DIR="virtiofsd_rs_build"
|
||||
if [ ! -f "$VIRTIOFSD_RS" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
git clone --depth 1 "https://gitlab.com/virtio-fs/virtiofsd-rs.git" $VIRTIOFSD_RS_DIR
|
||||
git clone "https://gitlab.com/virtio-fs/virtiofsd-rs.git" $VIRTIOFSD_RS_DIR
|
||||
git checkout c847ab63acabed2ed6e6913b9c76bb5099a1d4cb
|
||||
pushd $VIRTIOFSD_RS_DIR
|
||||
time cargo build --release
|
||||
cp target/release/virtiofsd-rs $VIRTIOFSD_RS || exit 1
|
||||
@@ -292,12 +284,8 @@ sudo bash -c "echo 1000000 > /sys/kernel/mm/ksm/pages_to_scan"
|
||||
sudo bash -c "echo 10 > /sys/kernel/mm/ksm/sleep_millisecs"
|
||||
sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
|
||||
|
||||
# Setup ovs-dpdk
|
||||
# Setup huge-pages for ovs-dpdk
|
||||
echo 2048 | sudo tee /proc/sys/vm/nr_hugepages
|
||||
service openvswitch-switch start
|
||||
ovs-vsctl init
|
||||
ovs-vsctl set Open_vSwitch . other_config:dpdk-init=true
|
||||
service openvswitch-switch restart
|
||||
|
||||
# Run all direct kernel boot (Device Tree) test cases in mod `parallel`
|
||||
time cargo test $features_test "tests::parallel::$test_filter"
|
||||
|
||||
@@ -15,6 +15,11 @@ process_common_args "$@"
|
||||
features_build=""
|
||||
features_test="--features integration_tests"
|
||||
|
||||
if [ "$hypervisor" = "mshv" ] ; then
|
||||
features_build="--no-default-features --features mshv,common"
|
||||
features_test="--no-default-features --features mshv,common,integration_tests"
|
||||
fi
|
||||
|
||||
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||
|
||||
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
|
||||
@@ -79,8 +84,11 @@ strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||
strip target/$BUILD_TARGET/release/vhost_user_net
|
||||
strip target/$BUILD_TARGET/release/ch-remote
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
# Test ovs-dpdk relies on hugepages
|
||||
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
time cargo test $features_test "tests::live_migration::$test_filter" -- --test-threads=1
|
||||
RES=$?
|
||||
|
||||
|
||||
@@ -5,6 +5,12 @@ source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
|
||||
process_common_args "$@"
|
||||
|
||||
if [[ "$hypervisor" = "mshv" ]]; then
|
||||
echo "Unsupported SGX test for MSHV"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# For now these values are deafult for kvm
|
||||
features_build=""
|
||||
features_test="--features integration_tests"
|
||||
|
||||
@@ -15,6 +15,11 @@ process_common_args "$@"
|
||||
features_build=""
|
||||
features_test="--features integration_tests"
|
||||
|
||||
if [ "$hypervisor" = "mshv" ] ; then
|
||||
features_build="--no-default-features --features mshv,common"
|
||||
features_test="--no-default-features --features mshv,common,integration_tests"
|
||||
fi
|
||||
|
||||
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||
|
||||
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
@@ -118,25 +123,12 @@ if [ -d "$LINUX_CUSTOM_DIR" ]; then
|
||||
rm -rf $LINUX_CUSTOM_DIR
|
||||
fi
|
||||
|
||||
VIRTIOFSD="$WORKLOADS_DIR/virtiofsd"
|
||||
QEMU_DIR="qemu_build"
|
||||
if [ ! -f "$VIRTIOFSD" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
git clone --depth 1 "https://gitlab.com/virtio-fs/qemu.git" -b "qemu5.0-virtiofs-dax" $QEMU_DIR
|
||||
pushd $QEMU_DIR
|
||||
time ./configure --prefix=$PWD --target-list=x86_64-softmmu
|
||||
time make virtiofsd -j `nproc`
|
||||
cp virtiofsd $VIRTIOFSD || exit 1
|
||||
popd
|
||||
rm -rf $QEMU_DIR
|
||||
popd
|
||||
fi
|
||||
|
||||
VIRTIOFSD_RS="$WORKLOADS_DIR/virtiofsd-rs"
|
||||
VIRTIOFSD_RS_DIR="virtiofsd_rs_build"
|
||||
if [ ! -f "$VIRTIOFSD_RS" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
git clone --depth 1 "https://gitlab.com/virtio-fs/virtiofsd-rs.git" $VIRTIOFSD_RS_DIR
|
||||
git clone "https://gitlab.com/virtio-fs/virtiofsd-rs.git" $VIRTIOFSD_RS_DIR
|
||||
git checkout c847ab63acabed2ed6e6913b9c76bb5099a1d4cb
|
||||
pushd $VIRTIOFSD_RS_DIR
|
||||
time cargo build --release
|
||||
cp target/release/virtiofsd-rs $VIRTIOFSD_RS || exit 1
|
||||
@@ -202,12 +194,6 @@ sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
|
||||
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
# Setup ovs-dpdk
|
||||
service openvswitch-switch start
|
||||
ovs-vsctl init
|
||||
ovs-vsctl set Open_vSwitch . other_config:dpdk-init=true
|
||||
service openvswitch-switch restart
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
time cargo test $features_test "tests::parallel::$test_filter"
|
||||
RES=$?
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
786fe1c33588334e92b35c65e414da068df180bc bionic-server-cloudimg-arm64.raw
|
||||
6e66f9f4b01adc72c884c1c1111e60afadc9c871 bionic-server-cloudimg-arm64.qcow2
|
||||
e4addb6e212a298144f9eb0eb6e36019d013f0e7 alpine-minirootfs-aarch64.tar.gz
|
||||
063d1a9f32db641138e6e0c53f58e6545a3d48e6 focal-server-cloudimg-arm64-custom.raw
|
||||
013837926872f1c7d1b3a1a95305e4a31c8600ab focal-server-cloudimg-arm64-custom.qcow2
|
||||
25b4f9ac308898d63b73d7db0e0e2d4768853723 focal-server-cloudimg-arm64-custom-20210929-0.qcow2
|
||||
9953b31bb1923cdd8d91b1b7cc9ad3a9be1e0a59 focal-server-cloudimg-arm64-custom-20210929-0.raw
|
||||
|
||||
@@ -33,8 +33,7 @@ process_common_args() {
|
||||
esac
|
||||
shift
|
||||
done
|
||||
if [[ "$hypervisor" != "kvm" ]]; then
|
||||
echo "Hypervisor value must be kvm"
|
||||
exit 1
|
||||
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
|
||||
die "Hypervisor value must be kvm or mshv"
|
||||
fi
|
||||
}
|
||||
|
||||
18
src/main.rs
18
src/main.rs
@@ -117,7 +117,8 @@ impl log::Log for Logger {
|
||||
}
|
||||
|
||||
fn prepare_default_values() -> (String, String, String) {
|
||||
let default_vcpus = format! {"boot={}", config::DEFAULT_VCPUS};
|
||||
let default_vcpus =
|
||||
format! {"boot={},max_phys_bits={}", config::DEFAULT_VCPUS,config::DEFAULT_MAX_PHYS_BITS};
|
||||
let default_memory = format! {"size={}M", config::DEFAULT_MEMORY_MB};
|
||||
let default_rng = format! {"src={}", config::DEFAULT_RNG_SOURCE};
|
||||
|
||||
@@ -163,7 +164,8 @@ fn create_app<'a, 'b>(
|
||||
hugepages=on|off,hugepage_size=<hugepage_size>,\
|
||||
hotplug_method=acpi|virtio-mem,\
|
||||
hotplug_size=<hotpluggable_memory_size>,\
|
||||
hotplugged_size=<hotplugged_memory_size>\"",
|
||||
hotplugged_size=<hotplugged_memory_size>,\
|
||||
prefault=on|off\"",
|
||||
)
|
||||
.default_value(default_memory)
|
||||
.group("vm-config"),
|
||||
@@ -178,7 +180,8 @@ fn create_app<'a, 'b>(
|
||||
hugepages=on|off,hugepage_size=<hugepage_size>,\
|
||||
host_numa_node=<node_id>,\
|
||||
id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,\
|
||||
hotplugged_size=<hotplugged_memory_size>\"",
|
||||
hotplugged_size=<hotplugged_memory_size>,\
|
||||
prefault=on|off\"",
|
||||
)
|
||||
.takes_value(true)
|
||||
.min_values(1)
|
||||
@@ -501,7 +504,9 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
||||
// installing handlers for, to make sure they only ever run on the
|
||||
// dedicated signal handling thread we'll start in a bit.
|
||||
for sig in vmm::vm::HANDLED_SIGNALS {
|
||||
block_signal(sig).unwrap();
|
||||
if let Err(e) = block_signal(sig) {
|
||||
eprintln!("Error blocking signals: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
event!("vmm", "starting");
|
||||
@@ -632,7 +637,7 @@ mod unit_tests {
|
||||
max_vcpus: 1,
|
||||
topology: None,
|
||||
kvm_hyperv: false,
|
||||
max_phys_bits: None,
|
||||
max_phys_bits: 46,
|
||||
},
|
||||
memory: MemoryConfig {
|
||||
size: 536_870_912,
|
||||
@@ -642,8 +647,9 @@ mod unit_tests {
|
||||
hotplugged_size: None,
|
||||
shared: false,
|
||||
hugepages: false,
|
||||
zones: None,
|
||||
hugepage_size: None,
|
||||
prefault: false,
|
||||
zones: None,
|
||||
},
|
||||
kernel: Some(KernelConfig {
|
||||
path: PathBuf::from("/path/to/kernel"),
|
||||
|
||||
@@ -9,5 +9,5 @@ dirs = "3.0.1"
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.91"
|
||||
ssh2 = "0.9.1"
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,13 +5,13 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.43"
|
||||
libc = "0.2.101"
|
||||
anyhow = "1.0.44"
|
||||
libc = "0.2.103"
|
||||
log = "0.4.14"
|
||||
serde = {version = ">=1.0.27", features = ["rc"] }
|
||||
serde_derive = ">=1.0.27"
|
||||
serde_json = ">=1.0.9"
|
||||
thiserror = "1.0.29"
|
||||
thiserror = "1.0.30"
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = ">=0.3.1"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ license = "Apache-2.0"
|
||||
[dependencies]
|
||||
byteorder = "1.4.3"
|
||||
crc32c = "0.6.0"
|
||||
libc = "0.2.101"
|
||||
libc = "0.2.103"
|
||||
log = "0.4.14"
|
||||
remain = "0.2.2"
|
||||
thiserror = "1.0"
|
||||
|
||||
@@ -9,10 +9,10 @@ default = []
|
||||
|
||||
[dependencies]
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.101"
|
||||
libc = "0.2.103"
|
||||
log = "0.4.14"
|
||||
virtio-bindings = "0.1.0"
|
||||
vm-memory = { version = "0.6.0", features = ["backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.8.0"
|
||||
vhost = { version = "0.1.0", features = ["vhost-user-slave"] }
|
||||
vmm-sys-util = "0.9.0"
|
||||
vhost = { version = "0.2.0", features = ["vhost-user-slave"] }
|
||||
|
||||
@@ -9,12 +9,12 @@ block_util = { path = "../block_util" }
|
||||
clap = { version = "2.33.3", features = ["wrap_help"] }
|
||||
env_logger = "0.9.0"
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.101"
|
||||
libc = "0.2.103"
|
||||
log = "0.4.14"
|
||||
option_parser = { path = "../option_parser" }
|
||||
qcow = { path = "../qcow" }
|
||||
vhost_user_backend = { path = "../vhost_user_backend" }
|
||||
vhost = { version = "0.1.0", features = ["vhost-user-slave"] }
|
||||
vhost = { version = "0.2.0", features = ["vhost-user-slave"] }
|
||||
virtio-bindings = "0.1.0"
|
||||
vm-memory = "0.6.0"
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
@@ -8,12 +8,12 @@ edition = "2018"
|
||||
clap = { version = "2.33.3", features = ["wrap_help"] }
|
||||
env_logger = "0.9.0"
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.101"
|
||||
libc = "0.2.103"
|
||||
log = "0.4.14"
|
||||
net_util = { path = "../net_util" }
|
||||
option_parser = { path = "../option_parser" }
|
||||
vhost_user_backend = { path = "../vhost_user_backend" }
|
||||
vhost = { version = "0.1.0", features = ["vhost-user-slave"] }
|
||||
vhost = { version = "0.2.0", features = ["vhost-user-slave"] }
|
||||
virtio-bindings = "0.1.0"
|
||||
vm-memory = "0.6.0"
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
@@ -10,30 +10,30 @@ io_uring = ["block_util/io_uring"]
|
||||
mshv = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.43"
|
||||
arc-swap = "1.3.2"
|
||||
anyhow = "1.0.44"
|
||||
arc-swap = "1.4.0"
|
||||
block_util = { path = "../block_util" }
|
||||
byteorder = "1.4.3"
|
||||
epoll = "4.3.1"
|
||||
event_monitor = { path = "../event_monitor" }
|
||||
io-uring = "0.5.2"
|
||||
libc = "0.2.101"
|
||||
libc = "0.2.103"
|
||||
log = "0.4.14"
|
||||
net_gen = { path = "../net_gen" }
|
||||
net_util = { path = "../net_util" }
|
||||
pci = { path = "../pci" }
|
||||
rate_limiter = { path = "../rate_limiter" }
|
||||
seccompiler = { git = "https://github.com/rust-vmm/seccompiler"}
|
||||
seccompiler = "0.2.0"
|
||||
serde = "1.0.130"
|
||||
serde_derive = "1.0.130"
|
||||
serde_json = "1.0.67"
|
||||
serde_json = "1.0.68"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vhost = { version = "0.1.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern"] }
|
||||
vhost = { version = "0.2.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern"] }
|
||||
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
@@ -29,12 +29,15 @@ use std::result;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use vm_memory::GuestMemory;
|
||||
use vm_memory::{
|
||||
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic,
|
||||
GuestMemoryError,
|
||||
};
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshottable, Transportable};
|
||||
use vm_migration::VersionMapped;
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
const QUEUE_SIZE: u16 = 128;
|
||||
@@ -82,8 +85,8 @@ pub enum Error {
|
||||
|
||||
// Got from include/uapi/linux/virtio_balloon.h
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
struct VirtioBalloonConfig {
|
||||
#[derive(Copy, Clone, Debug, Default, Versionize)]
|
||||
pub struct VirtioBalloonConfig {
|
||||
// Number of pages host wants Guest to give up.
|
||||
num_pages: u32,
|
||||
// Number of pages we've actually got in balloon.
|
||||
@@ -120,11 +123,11 @@ struct VirtioBalloonResize {
|
||||
}
|
||||
|
||||
impl VirtioBalloonResize {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
pub fn new(size: u64) -> io::Result<Self> {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
Ok(Self {
|
||||
size: Arc::new(AtomicU64::new(0)),
|
||||
size: Arc::new(AtomicU64::new(size)),
|
||||
tx,
|
||||
rx,
|
||||
evt: EventFd::new(EFD_NONBLOCK)?,
|
||||
@@ -335,6 +338,15 @@ impl EpollHelperHandler for BalloonEpollHandler {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Versionize)]
|
||||
pub struct BalloonState {
|
||||
pub avail_features: u64,
|
||||
pub acked_features: u64,
|
||||
pub config: VirtioBalloonConfig,
|
||||
}
|
||||
|
||||
impl VersionMapped for BalloonState {}
|
||||
|
||||
// Virtio device for exposing entropy to the guest OS through virtio.
|
||||
pub struct Balloon {
|
||||
common: VirtioCommon,
|
||||
@@ -374,7 +386,7 @@ impl Balloon {
|
||||
..Default::default()
|
||||
},
|
||||
id,
|
||||
resize: VirtioBalloonResize::new()?,
|
||||
resize: VirtioBalloonResize::new(size)?,
|
||||
config: Arc::new(Mutex::new(config)),
|
||||
seccomp_action,
|
||||
exit_evt,
|
||||
@@ -389,6 +401,20 @@ impl Balloon {
|
||||
pub fn get_actual(&self) -> u64 {
|
||||
(self.config.lock().unwrap().actual as u64) << VIRTIO_BALLOON_PFN_SHIFT
|
||||
}
|
||||
|
||||
fn state(&self) -> BalloonState {
|
||||
BalloonState {
|
||||
avail_features: self.common.avail_features,
|
||||
acked_features: self.common.acked_features,
|
||||
config: *(self.config.lock().unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_state(&mut self, state: &BalloonState) {
|
||||
self.common.avail_features = state.avail_features;
|
||||
self.common.acked_features = state.acked_features;
|
||||
*(self.config.lock().unwrap()) = state.config;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Balloon {
|
||||
@@ -503,6 +529,15 @@ impl Snapshottable for Balloon {
|
||||
fn id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
|
||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||
Snapshot::new_from_versioned_state(&self.id(), &self.state())
|
||||
}
|
||||
|
||||
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
||||
self.set_state(&snapshot.to_versioned_state(&self.id)?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Transportable for Balloon {}
|
||||
impl Migratable for Balloon {}
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::seccomp_filters::Thread;
|
||||
use crate::thread_helper::spawn_virtio_thread;
|
||||
use crate::GuestMemoryMmap;
|
||||
use crate::VirtioInterrupt;
|
||||
use libc::EFD_NONBLOCK;
|
||||
use libc::{EFD_NONBLOCK, TIOCGWINSZ};
|
||||
use seccompiler::SeccompAction;
|
||||
use std::cmp;
|
||||
use std::collections::VecDeque;
|
||||
@@ -42,11 +42,13 @@ const INPUT_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 3;
|
||||
const CONFIG_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 4;
|
||||
// File written to (input ready)
|
||||
const FILE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 5;
|
||||
// Console resized
|
||||
const RESIZE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 6;
|
||||
|
||||
//Console size feature bit
|
||||
const VIRTIO_CONSOLE_F_SIZE: u64 = 0;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Versionize)]
|
||||
#[derive(Copy, Clone, Debug, Versionize)]
|
||||
#[repr(C, packed)]
|
||||
pub struct VirtioConsoleConfig {
|
||||
cols: u16,
|
||||
@@ -55,6 +57,17 @@ pub struct VirtioConsoleConfig {
|
||||
emerg_wr: u32,
|
||||
}
|
||||
|
||||
impl Default for VirtioConsoleConfig {
|
||||
fn default() -> Self {
|
||||
VirtioConsoleConfig {
|
||||
cols: 0,
|
||||
rows: 0,
|
||||
max_nr_ports: 1,
|
||||
emerg_wr: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Safe because it only has data and has no implicit padding.
|
||||
unsafe impl ByteValued for VirtioConsoleConfig {}
|
||||
|
||||
@@ -63,11 +76,13 @@ struct ConsoleEpollHandler {
|
||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||
in_buffer: Arc<Mutex<VecDeque<u8>>>,
|
||||
resizer: Arc<ConsoleResizer>,
|
||||
endpoint: Endpoint,
|
||||
input_queue_evt: EventFd,
|
||||
output_queue_evt: EventFd,
|
||||
input_evt: EventFd,
|
||||
config_evt: EventFd,
|
||||
resize_pipe: Option<File>,
|
||||
kill_evt: EventFd,
|
||||
pause_evt: EventFd,
|
||||
}
|
||||
@@ -199,6 +214,9 @@ impl ConsoleEpollHandler {
|
||||
helper.add_event(self.output_queue_evt.as_raw_fd(), OUTPUT_QUEUE_EVENT)?;
|
||||
helper.add_event(self.input_evt.as_raw_fd(), INPUT_EVENT)?;
|
||||
helper.add_event(self.config_evt.as_raw_fd(), CONFIG_EVENT)?;
|
||||
if let Some(resize_pipe) = self.resize_pipe.as_ref() {
|
||||
helper.add_event(resize_pipe.as_raw_fd(), RESIZE_EVENT)?;
|
||||
}
|
||||
if let Some(in_file) = self.endpoint.in_file() {
|
||||
helper.add_event(in_file.as_raw_fd(), FILE_EVENT)?;
|
||||
}
|
||||
@@ -254,6 +272,14 @@ impl EpollHelperHandler for ConsoleEpollHandler {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
RESIZE_EVENT => {
|
||||
if let Err(e) = self.resize_pipe.as_ref().unwrap().read_exact(&mut [0]) {
|
||||
error!("Failed to get resize event: {:?}", e);
|
||||
return true;
|
||||
}
|
||||
|
||||
self.resizer.update_console_size();
|
||||
}
|
||||
FILE_EVENT => {
|
||||
let mut input = [0u8; 64];
|
||||
if let Some(ref mut in_file) = self.endpoint.in_file() {
|
||||
@@ -282,34 +308,29 @@ impl EpollHelperHandler for ConsoleEpollHandler {
|
||||
/// Resize handler
|
||||
pub struct ConsoleResizer {
|
||||
config_evt: EventFd,
|
||||
tty: Option<File>,
|
||||
config: Arc<Mutex<VirtioConsoleConfig>>,
|
||||
acked_features: AtomicU64,
|
||||
}
|
||||
|
||||
impl ConsoleResizer {
|
||||
pub fn update_console_size(&self, cols: u16, rows: u16) {
|
||||
if self
|
||||
.acked_features
|
||||
.fetch_and(1u64 << VIRTIO_CONSOLE_F_SIZE, Ordering::AcqRel)
|
||||
!= 0
|
||||
{
|
||||
pub fn update_console_size(&self) {
|
||||
if let Some(tty) = self.tty.as_ref() {
|
||||
let (cols, rows) = get_win_size(tty);
|
||||
self.config.lock().unwrap().update_console_size(cols, rows);
|
||||
//Send the interrupt to the driver
|
||||
let _ = self.config_evt.write(1);
|
||||
if self
|
||||
.acked_features
|
||||
.fetch_and(1u64 << VIRTIO_CONSOLE_F_SIZE, Ordering::AcqRel)
|
||||
!= 0
|
||||
{
|
||||
// Send the interrupt to the driver
|
||||
let _ = self.config_evt.write(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtioConsoleConfig {
|
||||
pub fn new(cols: u16, rows: u16) -> Self {
|
||||
VirtioConsoleConfig {
|
||||
cols,
|
||||
rows,
|
||||
max_nr_ports: 1u32,
|
||||
emerg_wr: 0u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_console_size(&mut self, cols: u16, rows: u16) {
|
||||
self.cols = cols;
|
||||
self.rows = rows;
|
||||
@@ -322,6 +343,7 @@ pub struct Console {
|
||||
id: String,
|
||||
config: Arc<Mutex<VirtioConsoleConfig>>,
|
||||
resizer: Arc<ConsoleResizer>,
|
||||
resize_pipe: Option<File>,
|
||||
endpoint: Endpoint,
|
||||
seccomp_action: SeccompAction,
|
||||
in_buffer: Arc<Mutex<VecDeque<u8>>>,
|
||||
@@ -336,6 +358,24 @@ pub struct ConsoleState {
|
||||
in_buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
fn get_win_size(tty: &dyn AsRawFd) -> (u16, u16) {
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
struct WindowSize {
|
||||
rows: u16,
|
||||
cols: u16,
|
||||
xpixel: u16,
|
||||
ypixel: u16,
|
||||
}
|
||||
let ws: WindowSize = WindowSize::default();
|
||||
|
||||
unsafe {
|
||||
libc::ioctl(tty.as_raw_fd(), TIOCGWINSZ, &ws);
|
||||
}
|
||||
|
||||
(ws.cols, ws.rows)
|
||||
}
|
||||
|
||||
impl VersionMapped for ConsoleState {}
|
||||
|
||||
impl Console {
|
||||
@@ -343,8 +383,7 @@ impl Console {
|
||||
pub fn new(
|
||||
id: String,
|
||||
endpoint: Endpoint,
|
||||
cols: u16,
|
||||
rows: u16,
|
||||
resize_pipe: Option<File>,
|
||||
iommu: bool,
|
||||
seccomp_action: SeccompAction,
|
||||
exit_evt: EventFd,
|
||||
@@ -356,13 +395,16 @@ impl Console {
|
||||
}
|
||||
|
||||
let config_evt = EventFd::new(EFD_NONBLOCK).unwrap();
|
||||
let console_config = Arc::new(Mutex::new(VirtioConsoleConfig::new(cols, rows)));
|
||||
let console_config = Arc::new(Mutex::new(VirtioConsoleConfig::default()));
|
||||
let resizer = Arc::new(ConsoleResizer {
|
||||
config_evt,
|
||||
config: console_config.clone(),
|
||||
tty: endpoint.out_file().as_ref().map(|t| t.try_clone().unwrap()),
|
||||
acked_features: AtomicU64::new(0),
|
||||
});
|
||||
|
||||
resizer.update_console_size();
|
||||
|
||||
Ok((
|
||||
Console {
|
||||
common: VirtioCommon {
|
||||
@@ -376,6 +418,7 @@ impl Console {
|
||||
id,
|
||||
config: console_config,
|
||||
resizer: resizer.clone(),
|
||||
resize_pipe,
|
||||
endpoint,
|
||||
seccomp_action,
|
||||
in_buffer: Arc::new(Mutex::new(VecDeque::new())),
|
||||
@@ -463,6 +506,8 @@ impl VirtioDevice for Console {
|
||||
output_queue_evt: queue_evts.remove(0),
|
||||
input_evt,
|
||||
config_evt: self.resizer.config_evt.try_clone().unwrap(),
|
||||
resize_pipe: self.resize_pipe.as_ref().map(|p| p.try_clone().unwrap()),
|
||||
resizer: Arc::clone(&self.resizer),
|
||||
kill_evt,
|
||||
pause_evt,
|
||||
};
|
||||
|
||||
@@ -54,8 +54,6 @@ const EVENT_Q_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 2;
|
||||
/// will conflict with x86.
|
||||
const PROBE_PROP_SIZE: u32 =
|
||||
(size_of::<VirtioIommuProbeProperty>() + size_of::<VirtioIommuProbeResvMem>()) as u32;
|
||||
const MSI_IOVA_START: u64 = 0xfee0_0000;
|
||||
const MSI_IOVA_END: u64 = 0xfeef_ffff;
|
||||
|
||||
/// Virtio IOMMU features
|
||||
#[allow(unused)]
|
||||
@@ -352,6 +350,7 @@ impl Request {
|
||||
mapping: &Arc<IommuMapping>,
|
||||
ext_mapping: &BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
||||
ext_domain_mapping: &mut BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
||||
msi_iova_space: (u64, u64),
|
||||
) -> result::Result<usize, Error> {
|
||||
// The head contains the request type which MUST be readable.
|
||||
if avail_desc.is_write_only() {
|
||||
@@ -372,6 +371,8 @@ impl Request {
|
||||
return Err(Error::InvalidRequest);
|
||||
};
|
||||
|
||||
let (msi_iova_start, msi_iova_end) = msi_iova_space;
|
||||
|
||||
// Create the reply
|
||||
let mut reply: Vec<u8> = Vec::new();
|
||||
|
||||
@@ -515,8 +516,8 @@ impl Request {
|
||||
|
||||
let resv_mem = VirtioIommuProbeResvMem {
|
||||
subtype: VIRTIO_IOMMU_RESV_MEM_T_MSI,
|
||||
start: MSI_IOVA_START,
|
||||
end: MSI_IOVA_END,
|
||||
start: msi_iova_start,
|
||||
end: msi_iova_end,
|
||||
..Default::default()
|
||||
};
|
||||
reply.extend_from_slice(resv_mem.as_slice());
|
||||
@@ -562,6 +563,7 @@ struct IommuEpollHandler {
|
||||
mapping: Arc<IommuMapping>,
|
||||
ext_mapping: BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
||||
ext_domain_mapping: BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
||||
msi_iova_space: (u64, u64),
|
||||
}
|
||||
|
||||
impl IommuEpollHandler {
|
||||
@@ -576,6 +578,7 @@ impl IommuEpollHandler {
|
||||
&self.mapping,
|
||||
&self.ext_mapping,
|
||||
&mut self.ext_domain_mapping,
|
||||
self.msi_iova_space,
|
||||
) {
|
||||
Ok(len) => len as u32,
|
||||
Err(e) => {
|
||||
@@ -702,6 +705,7 @@ pub struct Iommu {
|
||||
ext_mapping: BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
|
||||
seccomp_action: SeccompAction,
|
||||
exit_evt: EventFd,
|
||||
msi_iova_space: (u64, u64),
|
||||
}
|
||||
|
||||
#[derive(Versionize)]
|
||||
@@ -719,6 +723,7 @@ impl Iommu {
|
||||
id: String,
|
||||
seccomp_action: SeccompAction,
|
||||
exit_evt: EventFd,
|
||||
msi_iova_space: (u64, u64),
|
||||
) -> io::Result<(Self, Arc<IommuMapping>)> {
|
||||
let config = VirtioIommuConfig {
|
||||
page_size_mask: VIRTIO_IOMMU_PAGE_SIZE_MASK,
|
||||
@@ -748,6 +753,7 @@ impl Iommu {
|
||||
ext_mapping: BTreeMap::new(),
|
||||
seccomp_action,
|
||||
exit_evt,
|
||||
msi_iova_space,
|
||||
},
|
||||
mapping,
|
||||
))
|
||||
@@ -843,6 +849,7 @@ impl VirtioDevice for Iommu {
|
||||
mapping: self.mapping.clone(),
|
||||
ext_mapping: self.ext_mapping.clone(),
|
||||
ext_domain_mapping: BTreeMap::new(),
|
||||
msi_iova_space: self.msi_iova_space,
|
||||
};
|
||||
|
||||
let paused = self.common.paused.clone();
|
||||
|
||||
@@ -33,12 +33,17 @@ use std::result;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use vm_device::dma_mapping::ExternalDmaMapping;
|
||||
use vm_memory::{
|
||||
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic,
|
||||
GuestMemoryError, GuestMemoryRegion,
|
||||
};
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshottable, Transportable};
|
||||
use vm_migration::protocol::MemoryRangeTable;
|
||||
use vm_migration::{
|
||||
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
|
||||
};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
const QUEUE_SIZE: u16 = 128;
|
||||
@@ -159,8 +164,8 @@ struct VirtioMemResp {
|
||||
unsafe impl ByteValued for VirtioMemResp {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
struct VirtioMemConfig {
|
||||
#[derive(Copy, Clone, Debug, Default, Versionize)]
|
||||
pub struct VirtioMemConfig {
|
||||
// Block size and alignment. Cannot change.
|
||||
block_size: u64,
|
||||
// Valid with VIRTIO_MEM_F_ACPI_PXM. Cannot change.
|
||||
@@ -320,14 +325,14 @@ impl Request {
|
||||
}
|
||||
|
||||
pub struct ResizeSender {
|
||||
size: Arc<AtomicU64>,
|
||||
hotplugged_size: Arc<AtomicU64>,
|
||||
tx: mpsc::Sender<Result<(), Error>>,
|
||||
evt: EventFd,
|
||||
}
|
||||
|
||||
impl ResizeSender {
|
||||
fn size(&self) -> u64 {
|
||||
self.size.load(Ordering::Acquire)
|
||||
self.hotplugged_size.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
fn send(&self, r: Result<(), Error>) -> Result<(), mpsc::SendError<Result<(), Error>>> {
|
||||
@@ -338,7 +343,7 @@ impl ResizeSender {
|
||||
impl Clone for ResizeSender {
|
||||
fn clone(&self) -> Self {
|
||||
ResizeSender {
|
||||
size: self.size.clone(),
|
||||
hotplugged_size: self.hotplugged_size.clone(),
|
||||
tx: self.tx.clone(),
|
||||
evt: self
|
||||
.evt
|
||||
@@ -349,18 +354,18 @@ impl Clone for ResizeSender {
|
||||
}
|
||||
|
||||
pub struct Resize {
|
||||
size: Arc<AtomicU64>,
|
||||
hotplugged_size: Arc<AtomicU64>,
|
||||
tx: mpsc::Sender<Result<(), Error>>,
|
||||
rx: mpsc::Receiver<Result<(), Error>>,
|
||||
evt: EventFd,
|
||||
}
|
||||
|
||||
impl Resize {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
pub fn new(hotplugged_size: u64) -> io::Result<Self> {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
Ok(Resize {
|
||||
size: Arc::new(AtomicU64::new(0)),
|
||||
hotplugged_size: Arc::new(AtomicU64::new(hotplugged_size)),
|
||||
tx,
|
||||
rx,
|
||||
evt: EventFd::new(EFD_NONBLOCK)?,
|
||||
@@ -369,25 +374,34 @@ impl Resize {
|
||||
|
||||
pub fn new_resize_sender(&self) -> Result<ResizeSender, Error> {
|
||||
Ok(ResizeSender {
|
||||
size: self.size.clone(),
|
||||
hotplugged_size: self.hotplugged_size.clone(),
|
||||
tx: self.tx.clone(),
|
||||
evt: self.evt.try_clone().map_err(Error::EventFdTryCloneFail)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn work(&self, size: u64) -> Result<(), Error> {
|
||||
self.size.store(size, Ordering::Release);
|
||||
pub fn work(&self, desired_size: u64) -> Result<(), Error> {
|
||||
self.hotplugged_size.store(desired_size, Ordering::Release);
|
||||
self.evt.write(1).map_err(Error::EventFdWriteFail)?;
|
||||
self.rx.recv().map_err(Error::MpscRecvFail)?
|
||||
}
|
||||
}
|
||||
|
||||
struct BlocksState(Vec<bool>);
|
||||
#[derive(Clone, Versionize)]
|
||||
pub struct BlocksState {
|
||||
bitmap: Vec<bool>,
|
||||
}
|
||||
|
||||
impl BlocksState {
|
||||
pub fn new(region_size: u64) -> Self {
|
||||
BlocksState {
|
||||
bitmap: vec![false; (region_size / VIRTIO_MEM_DEFAULT_BLOCK_SIZE) as usize],
|
||||
}
|
||||
}
|
||||
|
||||
fn is_range_state(&self, first_block_index: usize, nb_blocks: u16, plug: bool) -> bool {
|
||||
for state in self
|
||||
.0
|
||||
.bitmap
|
||||
.iter()
|
||||
.skip(first_block_index)
|
||||
.take(nb_blocks as usize)
|
||||
@@ -401,7 +415,7 @@ impl BlocksState {
|
||||
|
||||
fn set_range(&mut self, first_block_index: usize, nb_blocks: u16, plug: bool) {
|
||||
for state in self
|
||||
.0
|
||||
.bitmap
|
||||
.iter_mut()
|
||||
.skip(first_block_index)
|
||||
.take(nb_blocks as usize)
|
||||
@@ -411,7 +425,27 @@ impl BlocksState {
|
||||
}
|
||||
|
||||
fn inner(&self) -> &Vec<bool> {
|
||||
&self.0
|
||||
&self.bitmap
|
||||
}
|
||||
|
||||
pub fn memory_ranges(&self, start_addr: u64, plugged: bool) -> MemoryRangeTable {
|
||||
let mut bitmap: Vec<u64> = Vec::new();
|
||||
let mut i = 0;
|
||||
for (j, bit) in self.bitmap.iter().enumerate() {
|
||||
if j % 64 == 0 {
|
||||
bitmap.push(0);
|
||||
|
||||
if j != 0 {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if *bit == plugged {
|
||||
bitmap[i] |= 1 << (j % 64);
|
||||
}
|
||||
}
|
||||
|
||||
MemoryRangeTable::from_bitmap(bitmap, start_addr, VIRTIO_MEM_DEFAULT_BLOCK_SIZE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,7 +462,7 @@ struct MemEpollHandler {
|
||||
kill_evt: EventFd,
|
||||
pause_evt: EventFd,
|
||||
hugepages: bool,
|
||||
dma_mapping_handlers: Arc<Mutex<BTreeMap<u32, Arc<dyn ExternalDmaMapping>>>>,
|
||||
dma_mapping_handlers: Arc<Mutex<BTreeMap<VirtioMemMappingSource, Arc<dyn ExternalDmaMapping>>>>,
|
||||
}
|
||||
|
||||
impl MemEpollHandler {
|
||||
@@ -734,7 +768,22 @@ impl EpollHelperHandler for MemEpollHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// Virtio device for exposing entropy to the guest OS through virtio.
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum VirtioMemMappingSource {
|
||||
Container,
|
||||
Device(u32),
|
||||
}
|
||||
|
||||
#[derive(Versionize)]
|
||||
pub struct MemState {
|
||||
pub avail_features: u64,
|
||||
pub acked_features: u64,
|
||||
pub config: VirtioMemConfig,
|
||||
pub blocks_state: BlocksState,
|
||||
}
|
||||
|
||||
impl VersionMapped for MemState {}
|
||||
|
||||
pub struct Mem {
|
||||
common: VirtioCommon,
|
||||
id: String,
|
||||
@@ -744,7 +793,7 @@ pub struct Mem {
|
||||
config: Arc<Mutex<VirtioMemConfig>>,
|
||||
seccomp_action: SeccompAction,
|
||||
hugepages: bool,
|
||||
dma_mapping_handlers: Arc<Mutex<BTreeMap<u32, Arc<dyn ExternalDmaMapping>>>>,
|
||||
dma_mapping_handlers: Arc<Mutex<BTreeMap<VirtioMemMappingSource, Arc<dyn ExternalDmaMapping>>>>,
|
||||
blocks_state: Arc<Mutex<BlocksState>>,
|
||||
exit_evt: EventFd,
|
||||
}
|
||||
@@ -761,6 +810,7 @@ impl Mem {
|
||||
initial_size: u64,
|
||||
hugepages: bool,
|
||||
exit_evt: EventFd,
|
||||
blocks_state: Arc<Mutex<BlocksState>>,
|
||||
) -> io::Result<Mem> {
|
||||
let region_len = region.len();
|
||||
|
||||
@@ -833,18 +883,14 @@ impl Mem {
|
||||
seccomp_action,
|
||||
hugepages,
|
||||
dma_mapping_handlers: Arc::new(Mutex::new(BTreeMap::new())),
|
||||
blocks_state: Arc::new(Mutex::new(BlocksState(vec![
|
||||
false;
|
||||
(config.region_size / config.block_size)
|
||||
as usize
|
||||
]))),
|
||||
blocks_state,
|
||||
exit_evt,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_dma_mapping_handler(
|
||||
&mut self,
|
||||
device_id: u32,
|
||||
source: VirtioMemMappingSource,
|
||||
handler: Arc<dyn ExternalDmaMapping>,
|
||||
) -> result::Result<(), Error> {
|
||||
let config = self.config.lock().unwrap();
|
||||
@@ -863,17 +909,20 @@ impl Mem {
|
||||
self.dma_mapping_handlers
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(device_id, handler);
|
||||
.insert(source, handler);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_dma_mapping_handler(&mut self, device_id: u32) -> result::Result<(), Error> {
|
||||
pub fn remove_dma_mapping_handler(
|
||||
&mut self,
|
||||
source: VirtioMemMappingSource,
|
||||
) -> result::Result<(), Error> {
|
||||
let handler = self
|
||||
.dma_mapping_handlers
|
||||
.lock()
|
||||
.unwrap()
|
||||
.remove(&device_id)
|
||||
.remove(&source)
|
||||
.ok_or(Error::InvalidDmaMappingHandler)?;
|
||||
|
||||
let config = self.config.lock().unwrap();
|
||||
@@ -891,6 +940,22 @@ impl Mem {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn state(&self) -> MemState {
|
||||
MemState {
|
||||
avail_features: self.common.avail_features,
|
||||
acked_features: self.common.acked_features,
|
||||
config: *(self.config.lock().unwrap()),
|
||||
blocks_state: self.blocks_state.lock().unwrap().clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_state(&mut self, state: &MemState) {
|
||||
self.common.avail_features = state.avail_features;
|
||||
self.common.acked_features = state.acked_features;
|
||||
*(self.config.lock().unwrap()) = state.config;
|
||||
*(self.blocks_state.lock().unwrap()) = state.blocks_state.clone();
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Mem {
|
||||
@@ -932,7 +997,6 @@ impl VirtioDevice for Mem {
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
let (kill_evt, pause_evt) = self.common.dup_eventfds();
|
||||
let config = self.config.lock().unwrap();
|
||||
let mut handler = MemEpollHandler {
|
||||
host_addr: self.host_addr,
|
||||
host_fd: self.host_fd,
|
||||
@@ -949,12 +1013,20 @@ impl VirtioDevice for Mem {
|
||||
dma_mapping_handlers: Arc::clone(&self.dma_mapping_handlers),
|
||||
};
|
||||
|
||||
handler
|
||||
.discard_memory_range(0, config.region_size)
|
||||
.map_err(|e| {
|
||||
error!("failed discarding memory range: {:?}", e);
|
||||
ActivateError::BadActivate
|
||||
})?;
|
||||
let unplugged_memory_ranges = self.blocks_state.lock().unwrap().memory_ranges(0, false);
|
||||
for range in unplugged_memory_ranges.regions() {
|
||||
handler
|
||||
.discard_memory_range(range.gpa, range.length)
|
||||
.map_err(|e| {
|
||||
error!(
|
||||
"failed discarding memory range [0x{:x}-0x{:x}]: {:?}",
|
||||
range.gpa,
|
||||
range.gpa + range.length - 1,
|
||||
e
|
||||
);
|
||||
ActivateError::BadActivate
|
||||
})?;
|
||||
}
|
||||
|
||||
let paused = self.common.paused.clone();
|
||||
let paused_sync = self.common.paused_sync.clone();
|
||||
@@ -999,6 +1071,15 @@ impl Snapshottable for Mem {
|
||||
fn id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
|
||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||
Snapshot::new_from_versioned_state(&self.id(), &self.state())
|
||||
}
|
||||
|
||||
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
||||
self.set_state(&snapshot.to_versioned_state(&self.id)?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Transportable for Mem {}
|
||||
impl Migratable for Mem {}
|
||||
|
||||
@@ -48,6 +48,7 @@ macro_rules! or {
|
||||
}
|
||||
|
||||
// See include/uapi/asm-generic/ioctls.h in the kernel code.
|
||||
const TIOCGWINSZ: u64 = 0x5413;
|
||||
const FIONBIO: u64 = 0x5421;
|
||||
|
||||
// See include/uapi/linux/vfio.h in the kernel code.
|
||||
@@ -57,6 +58,10 @@ const VFIO_IOMMU_UNMAP_DMA: u64 = 0x3b72;
|
||||
// See include/uapi/linux/if_tun.h in the kernel code.
|
||||
const TUNSETOFFLOAD: u64 = 0x4004_54d0;
|
||||
|
||||
fn create_virtio_console_ioctl_seccomp_rule() -> Vec<SeccompRule> {
|
||||
or![and![Cond::new(1, ArgLen::Dword, Eq, TIOCGWINSZ).unwrap()]]
|
||||
}
|
||||
|
||||
fn create_virtio_iommu_ioctl_seccomp_rule() -> Vec<SeccompRule> {
|
||||
or![
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, VFIO_IOMMU_MAP_DMA).unwrap()],
|
||||
@@ -72,171 +77,62 @@ fn create_virtio_mem_ioctl_seccomp_rule() -> Vec<SeccompRule> {
|
||||
}
|
||||
|
||||
fn virtio_balloon_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_fallocate, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
vec![(libc::SYS_fallocate, vec![])]
|
||||
}
|
||||
|
||||
fn virtio_block_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_fallocate, vec![]),
|
||||
(libc::SYS_fdatasync, vec![]),
|
||||
(libc::SYS_fsync, vec![]),
|
||||
(libc::SYS_ftruncate, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_getrandom, vec![]),
|
||||
(libc::SYS_io_uring_enter, vec![]),
|
||||
(libc::SYS_lseek, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_mmap, vec![]),
|
||||
(libc::SYS_mprotect, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_openat, vec![]),
|
||||
(libc::SYS_prctl, vec![]),
|
||||
(libc::SYS_pread64, vec![]),
|
||||
(libc::SYS_preadv, vec![]),
|
||||
(libc::SYS_pwritev, vec![]),
|
||||
(libc::SYS_pwrite64, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sched_getaffinity, vec![]),
|
||||
(libc::SYS_set_robust_list, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_timerfd_settime, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
}
|
||||
|
||||
fn virtio_console_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_mmap, vec![]),
|
||||
(libc::SYS_ioctl, create_virtio_console_ioctl_seccomp_rule()),
|
||||
(libc::SYS_mprotect, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_prctl, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sched_getaffinity, vec![]),
|
||||
(libc::SYS_set_robust_list, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
}
|
||||
|
||||
fn virtio_iommu_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_ioctl, create_virtio_iommu_ioctl_seccomp_rule()),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_mmap, vec![]),
|
||||
(libc::SYS_mprotect, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
}
|
||||
|
||||
fn virtio_mem_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_fallocate, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_ioctl, create_virtio_mem_ioctl_seccomp_rule()),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
(libc::SYS_recvfrom, vec![]),
|
||||
(libc::SYS_sendmsg, vec![]),
|
||||
]
|
||||
}
|
||||
|
||||
fn virtio_net_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_openat, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_readv, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_timerfd_settime, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
(libc::SYS_writev, vec![]),
|
||||
]
|
||||
}
|
||||
@@ -246,191 +142,57 @@ fn create_virtio_net_ctl_ioctl_seccomp_rule() -> Vec<SeccompRule> {
|
||||
}
|
||||
|
||||
fn virtio_net_ctl_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_ioctl, create_virtio_net_ctl_ioctl_seccomp_rule()),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
vec![(libc::SYS_ioctl, create_virtio_net_ctl_ioctl_seccomp_rule())]
|
||||
}
|
||||
|
||||
fn virtio_pmem_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_fsync, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
vec![(libc::SYS_fsync, vec![])]
|
||||
}
|
||||
|
||||
fn virtio_rng_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_mmap, vec![]),
|
||||
(libc::SYS_mprotect, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_prctl, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sched_getaffinity, vec![]),
|
||||
(libc::SYS_set_robust_list, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
}
|
||||
|
||||
fn virtio_vhost_fs_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_connect, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_mmap, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_nanosleep, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_recvmsg, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sendmsg, vec![]),
|
||||
(libc::SYS_sendto, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_socket, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
}
|
||||
|
||||
fn virtio_vhost_net_ctl_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn virtio_vhost_net_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_accept4, vec![]),
|
||||
(libc::SYS_bind, vec![]),
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_getcwd, vec![]),
|
||||
(libc::SYS_listen, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_recvmsg, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_rt_sigreturn, vec![]),
|
||||
(libc::SYS_sendmsg, vec![]),
|
||||
(libc::SYS_sendto, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_socket, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_unlink, vec![]),
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
(libc::SYS_unlinkat, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
}
|
||||
|
||||
fn virtio_vhost_block_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn create_vsock_ioctl_seccomp_rule() -> Vec<SeccompRule> {
|
||||
@@ -440,63 +202,25 @@ fn create_vsock_ioctl_seccomp_rule() -> Vec<SeccompRule> {
|
||||
fn virtio_vsock_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_accept4, vec![]),
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_connect, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_ioctl, create_vsock_ioctl_seccomp_rule()),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_mmap, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_recvfrom, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_socket, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
}
|
||||
|
||||
fn virtio_watchdog_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_mmap, vec![]),
|
||||
(libc::SYS_mprotect, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_prctl, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sched_getaffinity, vec![]),
|
||||
(libc::SYS_set_robust_list, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_timerfd_settime, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
}
|
||||
|
||||
fn get_seccomp_rules(thread_type: Thread) -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
match thread_type {
|
||||
let mut rules = match thread_type {
|
||||
Thread::VirtioBalloon => virtio_balloon_thread_rules(),
|
||||
Thread::VirtioBlock => virtio_block_thread_rules(),
|
||||
Thread::VirtioConsole => virtio_console_thread_rules(),
|
||||
@@ -512,7 +236,33 @@ fn get_seccomp_rules(thread_type: Thread) -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
Thread::VirtioVhostNetCtl => virtio_vhost_net_ctl_thread_rules(),
|
||||
Thread::VirtioVsock => virtio_vsock_thread_rules(),
|
||||
Thread::VirtioWatchdog => virtio_watchdog_thread_rules(),
|
||||
}
|
||||
};
|
||||
rules.append(&mut virtio_thread_common());
|
||||
rules
|
||||
}
|
||||
|
||||
fn virtio_thread_common() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
vec![
|
||||
(libc::SYS_brk, vec![]),
|
||||
#[cfg(feature = "mshv")]
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
(libc::SYS_epoll_create1, vec![]),
|
||||
(libc::SYS_epoll_ctl, vec![]),
|
||||
(libc::SYS_epoll_pwait, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_epoll_wait, vec![]),
|
||||
(libc::SYS_exit, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_mmap, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
]
|
||||
}
|
||||
|
||||
/// Generate a BPF program based on the seccomp_action value
|
||||
|
||||
@@ -521,7 +521,14 @@ impl VirtioDevice for Fs {
|
||||
MasterReqHandler::new(vu_master_req_handler).map_err(|e| {
|
||||
ActivateError::VhostUserFsSetup(Error::MasterReqHandlerCreation(e))
|
||||
})?;
|
||||
req_handler.set_reply_ack_flag(true);
|
||||
|
||||
if self.vu_common.acked_protocol_features
|
||||
& VhostUserProtocolFeatures::REPLY_ACK.bits()
|
||||
!= 0
|
||||
{
|
||||
req_handler.set_reply_ack_flag(true);
|
||||
}
|
||||
|
||||
Some(req_handler)
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -554,7 +554,7 @@ impl VhostUserHandle {
|
||||
let ptr = region.as_ptr() as *const u64;
|
||||
std::slice::from_raw_parts(ptr, len).to_vec()
|
||||
};
|
||||
Ok(MemoryRangeTable::from_bitmap(bitmap, 0))
|
||||
Ok(MemoryRangeTable::from_bitmap(bitmap, 0, 4096))
|
||||
} else {
|
||||
Err(Error::MissingShmLogRegion)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,6 @@ authors = ["The Chromium OS Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.101"
|
||||
libc = "0.2.103"
|
||||
vm-memory = "0.6.0"
|
||||
arch = { path = "../arch" }
|
||||
|
||||
@@ -10,12 +10,12 @@ kvm = ["vfio-ioctls/kvm"]
|
||||
mshv = ["vfio-ioctls/mshv"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.43"
|
||||
thiserror = "1.0.29"
|
||||
anyhow = "1.0.44"
|
||||
thiserror = "1.0.30"
|
||||
serde = { version = "1.0.130", features = ["rc"] }
|
||||
serde_derive = "1.0.130"
|
||||
serde_json = "1.0.67"
|
||||
serde_json = "1.0.68"
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio-ioctls", branch = "main", default-features = false }
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap"] }
|
||||
vmm-sys-util = "0.8.0"
|
||||
vmm-sys-util = "0.9.0"
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.43"
|
||||
thiserror = "1.0.29"
|
||||
anyhow = "1.0.44"
|
||||
thiserror = "1.0.30"
|
||||
serde = { version = "1.0.130", features = ["rc"] }
|
||||
serde_derive = "1.0.130"
|
||||
serde_json = "1.0.67"
|
||||
serde_json = "1.0.68"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
|
||||
@@ -15,7 +15,7 @@ use versionize::{VersionMap, Versionize};
|
||||
pub mod protocol;
|
||||
|
||||
/// Global VMM version for versioning
|
||||
const MAJOR_VERSION: u16 = 18;
|
||||
const MAJOR_VERSION: u16 = 19;
|
||||
const MINOR_VERSION: u16 = 0;
|
||||
const VMM_VERSION: u16 = MAJOR_VERSION << 12 | MINOR_VERSION & 0b1111;
|
||||
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use crate::MigratableError;
|
||||
use crate::{MigratableError, VersionMapped};
|
||||
use std::io::{Read, Write};
|
||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||
use versionize_derive::Versionize;
|
||||
use vm_memory::ByteValued;
|
||||
|
||||
// Migration protocol
|
||||
@@ -28,8 +31,6 @@ use vm_memory::ByteValued;
|
||||
// The destination can at any time send an "error response" to cancel
|
||||
// The source can at any time send an "abandon request" to cancel
|
||||
|
||||
use std::io::{Read, Write};
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Command {
|
||||
@@ -173,19 +174,21 @@ impl Response {
|
||||
unsafe impl ByteValued for Response {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Serialize, Deserialize, Versionize)]
|
||||
pub struct MemoryRange {
|
||||
pub gpa: u64,
|
||||
pub length: u64,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Clone, Default, Serialize, Deserialize, Versionize)]
|
||||
pub struct MemoryRangeTable {
|
||||
data: Vec<MemoryRange>,
|
||||
}
|
||||
|
||||
impl VersionMapped for MemoryRangeTable {}
|
||||
|
||||
impl MemoryRangeTable {
|
||||
pub fn from_bitmap(bitmap: Vec<u64>, start_addr: u64) -> Self {
|
||||
let page_size = 4096;
|
||||
pub fn from_bitmap(bitmap: Vec<u64>, start_addr: u64, page_size: u64) -> Self {
|
||||
let mut table = MemoryRangeTable::default();
|
||||
let mut entry: Option<MemoryRange> = None;
|
||||
for (i, block) in bitmap.iter().enumerate() {
|
||||
|
||||
@@ -16,8 +16,8 @@ tdx = ["arch/tdx", "hypervisor/tdx"]
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { path = "../acpi_tables", optional = true }
|
||||
anyhow = "1.0.43"
|
||||
arc-swap = "1.3.2"
|
||||
anyhow = "1.0.44"
|
||||
arc-swap = "1.4.0"
|
||||
arch = { path = "../arch" }
|
||||
bitflags = "1.3.2"
|
||||
block_util = { path = "../block_util" }
|
||||
@@ -27,24 +27,25 @@ epoll = "4.3.1"
|
||||
event_monitor = { path = "../event_monitor" }
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
lazy_static = "1.4.0"
|
||||
libc = "0.2.101"
|
||||
linux-loader = { version = "0.3.0", features = ["elf", "bzimage", "pe"] }
|
||||
libc = "0.2.103"
|
||||
linux-loader = { version = "0.4.0", features = ["elf", "bzimage", "pe"] }
|
||||
log = "0.4.14"
|
||||
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
|
||||
net_util = { path = "../net_util" }
|
||||
option_parser = { path = "../option_parser" }
|
||||
pci = { path = "../pci" }
|
||||
qcow = { path = "../qcow" }
|
||||
seccompiler = { git = "https://github.com/rust-vmm/seccompiler"}
|
||||
seccompiler = "0.2.0"
|
||||
serde = { version = "1.0.130", features = ["rc"] }
|
||||
serde_derive = "1.0.130"
|
||||
serde_json = "1.0.67"
|
||||
serde_json = "1.0.68"
|
||||
signal-hook = "0.3.10"
|
||||
thiserror = "1.0.29"
|
||||
thiserror = "1.0.30"
|
||||
uuid = "0.8.2"
|
||||
versionize = "0.1.6"
|
||||
versionize_derive = "0.1.4"
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio-ioctls", branch = "main", default-features = false }
|
||||
vfio_user = { path = "../vfio_user" }
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-devices = { path = "../virtio-devices" }
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
@@ -52,7 +53,7 @@ vm-device = { path = "../vm-device" }
|
||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = { version = "0.8.0", features = ["with-serde"] }
|
||||
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
||||
|
||||
[dev-dependencies]
|
||||
credibility = "0.1.3"
|
||||
|
||||
@@ -233,7 +233,7 @@ fn create_mcfg_table() -> Sdt {
|
||||
base_address: arch::layout::PCI_MMCONFIG_START.0,
|
||||
segment: 0,
|
||||
start: 0,
|
||||
end: ((arch::layout::PCI_MMCONFIG_SIZE - 1) >> 20) as u8,
|
||||
end: 0,
|
||||
..Default::default()
|
||||
});
|
||||
mcfg
|
||||
|
||||
@@ -14,6 +14,7 @@ use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::os::unix::io::{IntoRawFd, RawFd};
|
||||
use std::os::unix::net::UnixListener;
|
||||
use std::panic::AssertUnwindSafe;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::sync::Arc;
|
||||
@@ -267,6 +268,7 @@ fn start_http_thread(
|
||||
api_notifier: EventFd,
|
||||
api_sender: Sender<ApiRequest>,
|
||||
seccomp_action: &SeccompAction,
|
||||
exit_evt: EventFd,
|
||||
) -> Result<thread::JoinHandle<Result<()>>> {
|
||||
// Retrieve seccomp filter for API thread
|
||||
let api_seccomp_filter =
|
||||
@@ -277,32 +279,44 @@ fn start_http_thread(
|
||||
.spawn(move || {
|
||||
// Apply seccomp filter for API thread.
|
||||
if !api_seccomp_filter.is_empty() {
|
||||
apply_filter(&api_seccomp_filter).map_err(Error::ApplySeccompFilter)?;
|
||||
apply_filter(&api_seccomp_filter)
|
||||
.map_err(Error::ApplySeccompFilter)
|
||||
.map_err(|e| {
|
||||
error!("Error applying seccomp filter: {:?}", e);
|
||||
exit_evt.write(1).ok();
|
||||
e
|
||||
})?;
|
||||
}
|
||||
|
||||
server.start_server().unwrap();
|
||||
loop {
|
||||
match server.requests() {
|
||||
Ok(request_vec) => {
|
||||
for server_request in request_vec {
|
||||
server
|
||||
.respond(server_request.process(|request| {
|
||||
std::panic::catch_unwind(AssertUnwindSafe(move || {
|
||||
server.start_server().unwrap();
|
||||
loop {
|
||||
match server.requests() {
|
||||
Ok(request_vec) => {
|
||||
for server_request in request_vec {
|
||||
if let Err(e) = server.respond(server_request.process(|request| {
|
||||
handle_http_request(request, &api_notifier, &api_sender)
|
||||
}))
|
||||
.or_else(|e| {
|
||||
})) {
|
||||
error!("HTTP server error on response: {}", e);
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!(
|
||||
"HTTP server error on retrieving incoming request. Error: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!(
|
||||
"HTTP server error on retrieving incoming request. Error: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
.map_err(|_| {
|
||||
error!("http-server thread panicked");
|
||||
exit_evt.write(1).ok()
|
||||
})
|
||||
.ok();
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.map_err(Error::HttpThreadSpawn)
|
||||
}
|
||||
@@ -312,13 +326,14 @@ pub fn start_http_path_thread(
|
||||
api_notifier: EventFd,
|
||||
api_sender: Sender<ApiRequest>,
|
||||
seccomp_action: &SeccompAction,
|
||||
exit_evt: EventFd,
|
||||
) -> Result<thread::JoinHandle<Result<()>>> {
|
||||
std::fs::remove_file(path).unwrap_or_default();
|
||||
let socket_path = PathBuf::from(path);
|
||||
let socket_fd = UnixListener::bind(socket_path).map_err(Error::CreateApiServerSocket)?;
|
||||
let server =
|
||||
HttpServer::new_from_fd(socket_fd.into_raw_fd()).map_err(Error::CreateApiServer)?;
|
||||
start_http_thread(server, api_notifier, api_sender, seccomp_action)
|
||||
start_http_thread(server, api_notifier, api_sender, seccomp_action, exit_evt)
|
||||
}
|
||||
|
||||
pub fn start_http_fd_thread(
|
||||
@@ -326,7 +341,8 @@ pub fn start_http_fd_thread(
|
||||
api_notifier: EventFd,
|
||||
api_sender: Sender<ApiRequest>,
|
||||
seccomp_action: &SeccompAction,
|
||||
exit_evt: EventFd,
|
||||
) -> Result<thread::JoinHandle<Result<()>>> {
|
||||
let server = HttpServer::new_from_fd(fd).map_err(Error::CreateApiServer)?;
|
||||
start_http_thread(server, api_notifier, api_sender, seccomp_action)
|
||||
start_http_thread(server, api_notifier, api_sender, seccomp_action, exit_evt)
|
||||
}
|
||||
|
||||
@@ -546,6 +546,9 @@ components:
|
||||
hotplugged_size:
|
||||
type: integer
|
||||
format: int64
|
||||
prefault:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
MemoryConfig:
|
||||
required:
|
||||
@@ -577,6 +580,9 @@ components:
|
||||
hugepage_size:
|
||||
type: integer
|
||||
format: int64
|
||||
prefault:
|
||||
type: boolean
|
||||
default: false
|
||||
zones:
|
||||
type: array
|
||||
items:
|
||||
|
||||
27
vmm/src/clone3.rs
Normal file
27
vmm/src/clone3.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2021 Alyssa Ross <hi@alyssa.is>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use libc::{c_long, size_t, syscall, SYS_clone3};
|
||||
|
||||
pub const CLONE_CLEAR_SIGHAND: u64 = 0x100000000;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct clone_args {
|
||||
pub flags: u64,
|
||||
pub pidfd: u64,
|
||||
pub child_tid: u64,
|
||||
pub parent_tid: u64,
|
||||
pub exit_signal: u64,
|
||||
pub stack: u64,
|
||||
pub stack_size: u64,
|
||||
pub tls: u64,
|
||||
pub set_tid: u64,
|
||||
pub set_tid_size: u64,
|
||||
pub cgroup: u64,
|
||||
}
|
||||
|
||||
pub unsafe fn clone3(args: &mut clone_args, size: size_t) -> c_long {
|
||||
syscall(SYS_clone3, args, size)
|
||||
}
|
||||
@@ -20,6 +20,12 @@ use virtio_devices::{RateLimiterConfig, TokenBucketConfig};
|
||||
|
||||
pub const DEFAULT_VCPUS: u8 = 1;
|
||||
pub const DEFAULT_MEMORY_MB: u64 = 512;
|
||||
|
||||
// When booting with PVH boot the maximum physical addressable size
|
||||
// is a 46 bit address space even when the host supports with 5-level
|
||||
// paging.
|
||||
pub const DEFAULT_MAX_PHYS_BITS: u8 = 46;
|
||||
|
||||
pub const DEFAULT_RNG_SOURCE: &str = "/dev/urandom";
|
||||
pub const DEFAULT_NUM_QUEUES_VUNET: usize = 2;
|
||||
pub const DEFAULT_QUEUE_SIZE_VUNET: u16 = 256;
|
||||
@@ -410,6 +416,10 @@ impl FromStr for CpuTopology {
|
||||
}
|
||||
}
|
||||
|
||||
fn default_cpuconfig_max_phys_bits() -> u8 {
|
||||
DEFAULT_MAX_PHYS_BITS
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
pub struct CpusConfig {
|
||||
pub boot_vcpus: u8,
|
||||
@@ -418,8 +428,8 @@ pub struct CpusConfig {
|
||||
pub topology: Option<CpuTopology>,
|
||||
#[serde(default)]
|
||||
pub kvm_hyperv: bool,
|
||||
#[serde(default)]
|
||||
pub max_phys_bits: Option<u8>,
|
||||
#[serde(default = "default_cpuconfig_max_phys_bits")]
|
||||
pub max_phys_bits: u8,
|
||||
}
|
||||
|
||||
impl CpusConfig {
|
||||
@@ -449,7 +459,8 @@ impl CpusConfig {
|
||||
.0;
|
||||
let max_phys_bits = parser
|
||||
.convert::<u8>("max_phys_bits")
|
||||
.map_err(Error::ParseCpus)?;
|
||||
.map_err(Error::ParseCpus)?
|
||||
.unwrap_or(DEFAULT_MAX_PHYS_BITS);
|
||||
|
||||
Ok(CpusConfig {
|
||||
boot_vcpus,
|
||||
@@ -468,7 +479,7 @@ impl Default for CpusConfig {
|
||||
max_vcpus: DEFAULT_VCPUS,
|
||||
topology: None,
|
||||
kvm_hyperv: false,
|
||||
max_phys_bits: None,
|
||||
max_phys_bits: DEFAULT_MAX_PHYS_BITS,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -491,6 +502,8 @@ pub struct MemoryZoneConfig {
|
||||
pub hotplug_size: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub hotplugged_size: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub prefault: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
@@ -511,6 +524,8 @@ pub struct MemoryConfig {
|
||||
#[serde(default)]
|
||||
pub hugepage_size: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub prefault: bool,
|
||||
#[serde(default)]
|
||||
pub zones: Option<Vec<MemoryZoneConfig>>,
|
||||
}
|
||||
|
||||
@@ -526,7 +541,8 @@ impl MemoryConfig {
|
||||
.add("hotplugged_size")
|
||||
.add("shared")
|
||||
.add("hugepages")
|
||||
.add("hugepage_size");
|
||||
.add("hugepage_size")
|
||||
.add("prefault");
|
||||
parser.parse(memory).map_err(Error::ParseMemory)?;
|
||||
|
||||
let size = parser
|
||||
@@ -565,6 +581,11 @@ impl MemoryConfig {
|
||||
.convert::<ByteSized>("hugepage_size")
|
||||
.map_err(Error::ParseMemory)?
|
||||
.map(|v| v.0);
|
||||
let prefault = parser
|
||||
.convert::<Toggle>("prefault")
|
||||
.map_err(Error::ParseMemory)?
|
||||
.unwrap_or(Toggle(false))
|
||||
.0;
|
||||
|
||||
let zones: Option<Vec<MemoryZoneConfig>> = if let Some(memory_zones) = &memory_zones {
|
||||
let mut zones = Vec::new();
|
||||
@@ -579,7 +600,8 @@ impl MemoryConfig {
|
||||
.add("hugepage_size")
|
||||
.add("host_numa_node")
|
||||
.add("hotplug_size")
|
||||
.add("hotplugged_size");
|
||||
.add("hotplugged_size")
|
||||
.add("prefault");
|
||||
parser.parse(memory_zone).map_err(Error::ParseMemoryZone)?;
|
||||
|
||||
let id = parser.get("id").ok_or(Error::ParseMemoryZoneIdMissing)?;
|
||||
@@ -615,6 +637,11 @@ impl MemoryConfig {
|
||||
.convert::<ByteSized>("hotplugged_size")
|
||||
.map_err(Error::ParseMemoryZone)?
|
||||
.map(|v| v.0);
|
||||
let prefault = parser
|
||||
.convert::<Toggle>("prefault")
|
||||
.map_err(Error::ParseMemoryZone)?
|
||||
.unwrap_or(Toggle(false))
|
||||
.0;
|
||||
|
||||
zones.push(MemoryZoneConfig {
|
||||
id,
|
||||
@@ -626,6 +653,7 @@ impl MemoryConfig {
|
||||
host_numa_node,
|
||||
hotplug_size,
|
||||
hotplugged_size,
|
||||
prefault,
|
||||
});
|
||||
}
|
||||
Some(zones)
|
||||
@@ -642,6 +670,7 @@ impl MemoryConfig {
|
||||
shared,
|
||||
hugepages,
|
||||
hugepage_size,
|
||||
prefault,
|
||||
zones,
|
||||
})
|
||||
}
|
||||
@@ -676,6 +705,7 @@ impl Default for MemoryConfig {
|
||||
shared: false,
|
||||
hugepages: false,
|
||||
hugepage_size: None,
|
||||
prefault: false,
|
||||
zones: None,
|
||||
}
|
||||
}
|
||||
@@ -2678,6 +2708,7 @@ mod tests {
|
||||
shared: false,
|
||||
hugepages: false,
|
||||
hugepage_size: None,
|
||||
prefault: false,
|
||||
zones: None,
|
||||
},
|
||||
kernel: Some(KernelConfig {
|
||||
|
||||
@@ -406,14 +406,14 @@ const CPU_SELECTION_OFFSET: u64 = 0;
|
||||
impl BusDevice for CpuManager {
|
||||
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
||||
// The Linux kernel, quite reasonably, doesn't zero the memory it gives us.
|
||||
data.copy_from_slice(&[0; 8][0..data.len()]);
|
||||
data.fill(0);
|
||||
|
||||
match offset {
|
||||
CPU_SELECTION_OFFSET => {
|
||||
data[0] = self.selected_cpu;
|
||||
}
|
||||
CPU_STATUS_OFFSET => {
|
||||
if self.selected_cpu < self.present_vcpus() {
|
||||
if self.selected_cpu < self.max_vcpus() {
|
||||
let state = &self.vcpu_states[usize::from(self.selected_cpu)];
|
||||
if state.active() {
|
||||
data[0] |= 1 << CPU_ENABLE_FLAG;
|
||||
@@ -424,6 +424,8 @@ impl BusDevice for CpuManager {
|
||||
if state.removing {
|
||||
data[0] |= 1 << CPU_REMOVING_FLAG;
|
||||
}
|
||||
} else {
|
||||
warn!("Out of range vCPU id: {}", self.selected_cpu);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@@ -441,23 +443,28 @@ impl BusDevice for CpuManager {
|
||||
self.selected_cpu = data[0];
|
||||
}
|
||||
CPU_STATUS_OFFSET => {
|
||||
let state = &mut self.vcpu_states[usize::from(self.selected_cpu)];
|
||||
// The ACPI code writes back a 1 to acknowledge the insertion
|
||||
if (data[0] & (1 << CPU_INSERTING_FLAG) == 1 << CPU_INSERTING_FLAG)
|
||||
&& state.inserting
|
||||
{
|
||||
state.inserting = false;
|
||||
}
|
||||
// Ditto for removal
|
||||
if (data[0] & (1 << CPU_REMOVING_FLAG) == 1 << CPU_REMOVING_FLAG) && state.removing
|
||||
{
|
||||
state.removing = false;
|
||||
}
|
||||
// Trigger removal of vCPU
|
||||
if data[0] & (1 << CPU_EJECT_FLAG) == 1 << CPU_EJECT_FLAG {
|
||||
if let Err(e) = self.remove_vcpu(self.selected_cpu) {
|
||||
error!("Error removing vCPU: {:?}", e);
|
||||
if self.selected_cpu < self.max_vcpus() {
|
||||
let state = &mut self.vcpu_states[usize::from(self.selected_cpu)];
|
||||
// The ACPI code writes back a 1 to acknowledge the insertion
|
||||
if (data[0] & (1 << CPU_INSERTING_FLAG) == 1 << CPU_INSERTING_FLAG)
|
||||
&& state.inserting
|
||||
{
|
||||
state.inserting = false;
|
||||
}
|
||||
// Ditto for removal
|
||||
if (data[0] & (1 << CPU_REMOVING_FLAG) == 1 << CPU_REMOVING_FLAG)
|
||||
&& state.removing
|
||||
{
|
||||
state.removing = false;
|
||||
}
|
||||
// Trigger removal of vCPU
|
||||
if data[0] & (1 << CPU_EJECT_FLAG) == 1 << CPU_EJECT_FLAG {
|
||||
if let Err(e) = self.remove_vcpu(self.selected_cpu) {
|
||||
error!("Error removing vCPU: {:?}", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!("Out of range vCPU id: {}", self.selected_cpu);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@@ -546,11 +553,7 @@ impl CpuManager {
|
||||
.map(|sgx_epc_region| sgx_epc_region.epc_sections().values().cloned().collect());
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let cpuid = {
|
||||
let phys_bits = physical_bits(
|
||||
config.max_phys_bits,
|
||||
#[cfg(feature = "tdx")]
|
||||
tdx_enabled,
|
||||
);
|
||||
let phys_bits = physical_bits(config.max_phys_bits);
|
||||
arch::generate_common_cpuid(
|
||||
hypervisor,
|
||||
config
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
137
vmm/src/lib.rs
137
vmm/src/lib.rs
@@ -28,6 +28,7 @@ use crate::seccomp_filters::{get_seccomp_filter, Thread};
|
||||
use crate::vm::{Error as VmError, Vm, VmState};
|
||||
use anyhow::anyhow;
|
||||
use libc::EFD_NONBLOCK;
|
||||
use memory_manager::MemoryManagerSnapshotData;
|
||||
use seccompiler::{apply_filter, SeccompAction};
|
||||
use serde::ser::{Serialize, SerializeStruct, Serializer};
|
||||
use std::fs::File;
|
||||
@@ -46,7 +47,10 @@ use vm_migration::{protocol::*, Migratable};
|
||||
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
mod acpi;
|
||||
pub mod api;
|
||||
mod clone3;
|
||||
pub mod config;
|
||||
pub mod cpu;
|
||||
pub mod device_manager;
|
||||
@@ -54,12 +58,12 @@ pub mod device_tree;
|
||||
pub mod interrupt;
|
||||
pub mod memory_manager;
|
||||
pub mod migration;
|
||||
mod pci_segment;
|
||||
pub mod seccomp_filters;
|
||||
pub mod vm;
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
mod acpi;
|
||||
mod serial_buffer;
|
||||
mod serial_manager;
|
||||
mod sigwinch_listener;
|
||||
pub mod vm;
|
||||
|
||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
||||
type GuestRegionMmap = vm_memory::GuestRegionMmap<AtomicBitmap>;
|
||||
@@ -147,10 +151,8 @@ pub type Result<T> = result::Result<T, Error>;
|
||||
pub enum EpollDispatch {
|
||||
Exit = 0,
|
||||
Reset = 1,
|
||||
Stdin = 2,
|
||||
Api = 3,
|
||||
ActivateVirtioDevices = 4,
|
||||
SerialPty = 5,
|
||||
Api = 2,
|
||||
ActivateVirtioDevices = 3,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
@@ -160,10 +162,8 @@ impl From<u64> for EpollDispatch {
|
||||
match v {
|
||||
0 => Exit,
|
||||
1 => Reset,
|
||||
2 => Stdin,
|
||||
3 => Api,
|
||||
4 => ActivateVirtioDevices,
|
||||
5 => SerialPty,
|
||||
2 => Api,
|
||||
3 => ActivateVirtioDevices,
|
||||
_ => Unknown,
|
||||
}
|
||||
}
|
||||
@@ -182,18 +182,6 @@ impl EpollContext {
|
||||
Ok(EpollContext { epoll_file })
|
||||
}
|
||||
|
||||
pub fn add_stdin(&mut self) -> result::Result<(), io::Error> {
|
||||
let dispatch_index = EpollDispatch::Stdin as u64;
|
||||
epoll::ctl(
|
||||
self.epoll_file.as_raw_fd(),
|
||||
epoll::ControlOptions::EPOLL_CTL_ADD,
|
||||
libc::STDIN_FILENO,
|
||||
epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_event<T>(&mut self, fd: &T, token: EpollDispatch) -> result::Result<(), io::Error>
|
||||
where
|
||||
T: AsRawFd,
|
||||
@@ -262,30 +250,47 @@ pub fn start_vmm_thread(
|
||||
get_seccomp_filter(seccomp_action, Thread::Vmm).map_err(Error::CreateSeccompFilter)?;
|
||||
|
||||
let vmm_seccomp_action = seccomp_action.clone();
|
||||
let thread = thread::Builder::new()
|
||||
.name("vmm".to_string())
|
||||
.spawn(move || {
|
||||
// Apply seccomp filter for VMM thread.
|
||||
if !vmm_seccomp_filter.is_empty() {
|
||||
apply_filter(&vmm_seccomp_filter).map_err(Error::ApplySeccompFilter)?;
|
||||
}
|
||||
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
|
||||
let thread = {
|
||||
let exit_evt = exit_evt.try_clone().map_err(Error::EventFdClone)?;
|
||||
thread::Builder::new()
|
||||
.name("vmm".to_string())
|
||||
.spawn(move || {
|
||||
// Apply seccomp filter for VMM thread.
|
||||
if !vmm_seccomp_filter.is_empty() {
|
||||
apply_filter(&vmm_seccomp_filter).map_err(Error::ApplySeccompFilter)?;
|
||||
}
|
||||
|
||||
let mut vmm = Vmm::new(
|
||||
vmm_version.to_string(),
|
||||
api_event,
|
||||
vmm_seccomp_action,
|
||||
hypervisor,
|
||||
)?;
|
||||
let mut vmm = Vmm::new(
|
||||
vmm_version.to_string(),
|
||||
api_event,
|
||||
vmm_seccomp_action,
|
||||
hypervisor,
|
||||
exit_evt,
|
||||
)?;
|
||||
|
||||
vmm.control_loop(Arc::new(api_receiver))
|
||||
})
|
||||
.map_err(Error::VmmThreadSpawn)?;
|
||||
vmm.control_loop(Arc::new(api_receiver))
|
||||
})
|
||||
.map_err(Error::VmmThreadSpawn)?
|
||||
};
|
||||
|
||||
// The VMM thread is started, we can start serving HTTP requests
|
||||
if let Some(http_path) = http_path {
|
||||
api::start_http_path_thread(http_path, http_api_event, api_sender, seccomp_action)?;
|
||||
api::start_http_path_thread(
|
||||
http_path,
|
||||
http_api_event,
|
||||
api_sender,
|
||||
seccomp_action,
|
||||
exit_evt,
|
||||
)?;
|
||||
} else if let Some(http_fd) = http_fd {
|
||||
api::start_http_fd_thread(http_fd, http_api_event, api_sender, seccomp_action)?;
|
||||
api::start_http_fd_thread(
|
||||
http_fd,
|
||||
http_api_event,
|
||||
api_sender,
|
||||
seccomp_action,
|
||||
exit_evt,
|
||||
)?;
|
||||
}
|
||||
Ok(thread)
|
||||
}
|
||||
@@ -295,6 +300,7 @@ struct VmMigrationConfig {
|
||||
vm_config: Arc<Mutex<VmConfig>>,
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
common_cpuid: hypervisor::CpuId,
|
||||
memory_manager_data: MemoryManagerSnapshotData,
|
||||
}
|
||||
|
||||
pub struct Vmm {
|
||||
@@ -316,9 +322,9 @@ impl Vmm {
|
||||
api_evt: EventFd,
|
||||
seccomp_action: SeccompAction,
|
||||
hypervisor: Arc<dyn hypervisor::Hypervisor>,
|
||||
exit_evt: EventFd,
|
||||
) -> Result<Self> {
|
||||
let mut epoll = EpollContext::new().map_err(Error::Epoll)?;
|
||||
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
|
||||
let reset_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
|
||||
let activate_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
|
||||
|
||||
@@ -388,19 +394,8 @@ impl Vmm {
|
||||
activate_evt,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)?;
|
||||
if let Some(serial_pty) = vm.serial_pty() {
|
||||
self.epoll
|
||||
.add_event(&serial_pty.main, EpollDispatch::SerialPty)
|
||||
.map_err(VmError::EventfdError)?;
|
||||
};
|
||||
if matches!(
|
||||
vm_config.lock().unwrap().serial.mode,
|
||||
config::ConsoleOutputMode::Tty
|
||||
) && unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0
|
||||
{
|
||||
self.epoll.add_stdin().map_err(VmError::EventfdError)?;
|
||||
}
|
||||
|
||||
self.vm = Some(vm);
|
||||
}
|
||||
@@ -515,6 +510,10 @@ impl Vmm {
|
||||
let config = vm.get_config();
|
||||
let serial_pty = vm.serial_pty();
|
||||
let console_pty = vm.console_pty();
|
||||
let console_resize_pipe = vm
|
||||
.console_resize_pipe()
|
||||
.as_ref()
|
||||
.map(|pipe| pipe.try_clone().unwrap());
|
||||
self.vm_shutdown()?;
|
||||
|
||||
let exit_evt = self.exit_evt.try_clone().map_err(VmError::EventFdClone)?;
|
||||
@@ -539,6 +538,7 @@ impl Vmm {
|
||||
activate_evt,
|
||||
serial_pty,
|
||||
console_pty,
|
||||
console_resize_pipe,
|
||||
)?);
|
||||
}
|
||||
|
||||
@@ -766,7 +766,7 @@ impl Vmm {
|
||||
where
|
||||
T: Read + Write,
|
||||
{
|
||||
// Read in config data
|
||||
// Read in config data along with memory manager data
|
||||
let mut data = Vec::with_capacity(req.length() as usize);
|
||||
unsafe {
|
||||
data.set_len(req.length() as usize);
|
||||
@@ -804,6 +804,7 @@ impl Vmm {
|
||||
&self.seccomp_action,
|
||||
self.hypervisor.clone(),
|
||||
activate_evt,
|
||||
&vm_migration_config.memory_manager_data,
|
||||
)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!("Error creating VM from snapshot: {:?}", e))
|
||||
@@ -1040,11 +1041,7 @@ impl Vmm {
|
||||
let common_cpuid = {
|
||||
#[cfg(feature = "tdx")]
|
||||
let tdx_enabled = vm_config.lock().unwrap().tdx.is_some();
|
||||
let phys_bits = vm::physical_bits(
|
||||
vm_config.lock().unwrap().cpus.max_phys_bits,
|
||||
#[cfg(feature = "tdx")]
|
||||
tdx_enabled,
|
||||
);
|
||||
let phys_bits = vm::physical_bits(vm_config.lock().unwrap().cpus.max_phys_bits);
|
||||
arch::generate_common_cpuid(
|
||||
hypervisor,
|
||||
None,
|
||||
@@ -1063,8 +1060,8 @@ impl Vmm {
|
||||
vm_config,
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
common_cpuid,
|
||||
memory_manager_data: vm.memory_manager_data(),
|
||||
};
|
||||
|
||||
let config_data = serde_json::to_vec(&vm_migration_config).unwrap();
|
||||
Request::config(config_data.len() as u64).write_to(&mut socket)?;
|
||||
socket
|
||||
@@ -1212,11 +1209,7 @@ impl Vmm {
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
let tdx_enabled = vm_config.tdx.is_some();
|
||||
let phys_bits = vm::physical_bits(
|
||||
vm_config.cpus.max_phys_bits,
|
||||
#[cfg(feature = "tdx")]
|
||||
tdx_enabled,
|
||||
);
|
||||
let phys_bits = vm::physical_bits(vm_config.cpus.max_phys_bits);
|
||||
arch::generate_common_cpuid(
|
||||
self.hypervisor.clone(),
|
||||
None,
|
||||
@@ -1283,11 +1276,6 @@ impl Vmm {
|
||||
self.reset_evt.read().map_err(Error::EventFdRead)?;
|
||||
self.vm_reboot().map_err(Error::VmReboot)?;
|
||||
}
|
||||
EpollDispatch::Stdin => {
|
||||
if let Some(ref vm) = self.vm {
|
||||
vm.handle_stdin().map_err(Error::Stdin)?;
|
||||
}
|
||||
}
|
||||
EpollDispatch::ActivateVirtioDevices => {
|
||||
if let Some(ref vm) = self.vm {
|
||||
let count = self.activate_evt.read().map_err(Error::EventFdRead)?;
|
||||
@@ -1299,11 +1287,6 @@ impl Vmm {
|
||||
.map_err(Error::ActivateVirtioDevices)?;
|
||||
}
|
||||
}
|
||||
event @ EpollDispatch::SerialPty => {
|
||||
if let Some(ref vm) = self.vm {
|
||||
vm.handle_pty(event).map_err(Error::Pty)?;
|
||||
}
|
||||
}
|
||||
EpollDispatch::Api => {
|
||||
// Consume the event.
|
||||
self.api_evt.read().map_err(Error::EventFdRead)?;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
131
vmm/src/pci_segment.rs
Normal file
131
vmm/src/pci_segment.rs
Normal file
@@ -0,0 +1,131 @@
|
||||
// Portions Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
//
|
||||
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE-BSD-3-Clause file.
|
||||
//
|
||||
// Copyright © 2019 - 2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
//
|
||||
|
||||
use crate::device_manager::{AddressManager, DeviceManagerError, DeviceManagerResult};
|
||||
use pci::{DeviceRelocation, PciBus, PciConfigMmio, PciRoot};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use pci::{PciConfigIo, PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use vm_device::BusDevice;
|
||||
|
||||
pub(crate) struct PciSegment {
|
||||
id: u16,
|
||||
pub(crate) pci_bus: Arc<Mutex<PciBus>>,
|
||||
pub(crate) pci_config_mmio: Arc<Mutex<PciConfigMmio>>,
|
||||
mmio_config_address: u64,
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub(crate) pci_config_io: Option<Arc<Mutex<PciConfigIo>>>,
|
||||
|
||||
// Bitmap of PCI devices to hotplug.
|
||||
pub(crate) pci_devices_up: u32,
|
||||
// Bitmap of PCI devices to hotunplug.
|
||||
pub(crate) pci_devices_down: u32,
|
||||
// List of allocated IRQs for each PCI slot.
|
||||
pub(crate) pci_irq_slots: [u8; 32],
|
||||
}
|
||||
|
||||
impl PciSegment {
|
||||
pub(crate) fn new_default_segment(
|
||||
address_manager: &Arc<AddressManager>,
|
||||
) -> DeviceManagerResult<PciSegment> {
|
||||
let pci_root = PciRoot::new(None);
|
||||
let pci_bus = Arc::new(Mutex::new(PciBus::new(
|
||||
pci_root,
|
||||
Arc::clone(address_manager) as Arc<dyn DeviceRelocation>,
|
||||
)));
|
||||
|
||||
let pci_config_mmio = Arc::new(Mutex::new(PciConfigMmio::new(Arc::clone(&pci_bus))));
|
||||
address_manager
|
||||
.mmio_bus
|
||||
.insert(
|
||||
Arc::clone(&pci_config_mmio) as Arc<Mutex<dyn BusDevice>>,
|
||||
arch::layout::PCI_MMCONFIG_START.0,
|
||||
arch::layout::PCI_MMCONFIG_SIZE,
|
||||
)
|
||||
.map_err(DeviceManagerError::BusError)?;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let pci_config_io = Arc::new(Mutex::new(PciConfigIo::new(Arc::clone(&pci_bus))));
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
address_manager
|
||||
.io_bus
|
||||
.insert(
|
||||
pci_config_io.clone(),
|
||||
PCI_CONFIG_IO_PORT,
|
||||
PCI_CONFIG_IO_PORT_SIZE,
|
||||
)
|
||||
.map_err(DeviceManagerError::BusError)?;
|
||||
|
||||
let mut segment = PciSegment {
|
||||
id: 0,
|
||||
pci_bus,
|
||||
pci_config_mmio,
|
||||
mmio_config_address: arch::layout::PCI_MMCONFIG_START.0,
|
||||
pci_devices_up: 0,
|
||||
pci_devices_down: 0,
|
||||
pci_irq_slots: [0; 32],
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pci_config_io: Some(pci_config_io),
|
||||
};
|
||||
|
||||
// Reserve some IRQs for PCI devices in case they need to support INTx.
|
||||
segment.reserve_legacy_interrupts_for_pci_devices(address_manager)?;
|
||||
|
||||
info!(
|
||||
"Adding PCI segment: id={}, PCI MMIO config address: 0x{:x}",
|
||||
segment.id, segment.mmio_config_address
|
||||
);
|
||||
Ok(segment)
|
||||
}
|
||||
|
||||
pub(crate) fn next_device_bdf(&self) -> DeviceManagerResult<u32> {
|
||||
// We need to shift the device id since the 3 first bits
|
||||
// are dedicated to the PCI function, and we know we don't
|
||||
// do multifunction. Also, because we only support one PCI
|
||||
// bus, the bus 0, we don't need to add anything to the
|
||||
// global device ID.
|
||||
Ok(self
|
||||
.pci_bus
|
||||
.lock()
|
||||
.unwrap()
|
||||
.next_device_id()
|
||||
.map_err(DeviceManagerError::NextPciDeviceId)?
|
||||
<< 3)
|
||||
}
|
||||
|
||||
fn reserve_legacy_interrupts_for_pci_devices(
|
||||
&mut self,
|
||||
address_manager: &Arc<AddressManager>,
|
||||
) -> DeviceManagerResult<()> {
|
||||
// Reserve 8 IRQs which will be shared across all PCI devices.
|
||||
let num_irqs = 8;
|
||||
let mut irqs: Vec<u8> = Vec::new();
|
||||
for _ in 0..num_irqs {
|
||||
irqs.push(
|
||||
address_manager
|
||||
.allocator
|
||||
.lock()
|
||||
.unwrap()
|
||||
.allocate_irq()
|
||||
.ok_or(DeviceManagerError::AllocateIrq)? as u8,
|
||||
);
|
||||
}
|
||||
|
||||
// There are 32 devices on the PCI bus, let's assign them an IRQ.
|
||||
for i in 0..32 {
|
||||
self.pci_irq_slots[i] = irqs[(i % num_irqs) as usize];
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ pub enum Thread {
|
||||
SignalHandler,
|
||||
Vcpu,
|
||||
Vmm,
|
||||
PtyForeground,
|
||||
}
|
||||
|
||||
/// Shorthand for chaining `SeccompCondition`s with the `and` operator in a `SeccompRule`.
|
||||
@@ -39,6 +40,8 @@ macro_rules! or {
|
||||
// See include/uapi/asm-generic/ioctls.h in the kernel code.
|
||||
const TCGETS: u64 = 0x5401;
|
||||
const TCSETS: u64 = 0x5402;
|
||||
const TIOCSCTTY: u64 = 0x540E;
|
||||
const TIOCSPGRP: u64 = 0x5410;
|
||||
const TIOCGWINSZ: u64 = 0x5413;
|
||||
const TIOCSPTLCK: u64 = 0x4004_5431;
|
||||
const TIOCGTPEER: u64 = 0x5441;
|
||||
@@ -217,9 +220,11 @@ fn create_vmm_ioctl_seccomp_rule_common() -> Result<Vec<SeccompRule>, BackendErr
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, SIOCSIFNETMASK)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TCSETS)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TCGETS)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TIOCGWINSZ)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSPTLCK)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TIOCGTPEER)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TIOCGWINSZ)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSCTTY)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSPGRP)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSPTLCK)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TUNGETFEATURES)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TUNGETIFF)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TUNSETIFF)?],
|
||||
@@ -356,6 +361,7 @@ fn signal_handler_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, Backend
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_ioctl, create_signal_handler_ioctl_seccomp_rule()?),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_mmap, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_recvfrom, vec![]),
|
||||
(libc::SYS_rt_sigprocmask, vec![]),
|
||||
@@ -366,6 +372,35 @@ fn signal_handler_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, Backend
|
||||
])
|
||||
}
|
||||
|
||||
fn create_pty_foreground_ioctl_seccomp_rule() -> Result<Vec<SeccompRule>, BackendError> {
|
||||
Ok(or![
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSCTTY)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, TIOCSPGRP)?],
|
||||
])
|
||||
}
|
||||
|
||||
fn pty_foreground_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
|
||||
Ok(vec![
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_exit_group, vec![]),
|
||||
(libc::SYS_getpgid, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_getpgrp, vec![]),
|
||||
(libc::SYS_ioctl, create_pty_foreground_ioctl_seccomp_rule()?),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_poll, vec![]),
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
(libc::SYS_ppoll, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
(libc::SYS_rt_sigaction, vec![]),
|
||||
(libc::SYS_rt_sigreturn, vec![]),
|
||||
(libc::SYS_setsid, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(libc::SYS_write, vec![]),
|
||||
])
|
||||
}
|
||||
|
||||
// The filter containing the white listed syscall rules required by the VMM to
|
||||
// function.
|
||||
fn vmm_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
|
||||
@@ -380,6 +415,7 @@ fn vmm_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
|
||||
(libc::SYS_clock_gettime, vec![]),
|
||||
(libc::SYS_clock_nanosleep, vec![]),
|
||||
(libc::SYS_clone, vec![]),
|
||||
(libc::SYS_clone3, vec![]),
|
||||
(libc::SYS_close, vec![]),
|
||||
(libc::SYS_connect, vec![]),
|
||||
(libc::SYS_dup, vec![]),
|
||||
@@ -405,6 +441,9 @@ fn vmm_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
(libc::SYS_newfstatat, vec![]),
|
||||
(libc::SYS_futex, vec![]),
|
||||
(libc::SYS_getpgid, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_getpgrp, vec![]),
|
||||
(libc::SYS_getpid, vec![]),
|
||||
(libc::SYS_getrandom, vec![]),
|
||||
(libc::SYS_gettid, vec![]),
|
||||
@@ -430,6 +469,10 @@ fn vmm_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
|
||||
(libc::SYS_open, vec![]),
|
||||
(libc::SYS_openat, vec![]),
|
||||
(libc::SYS_pipe2, vec![]),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
(libc::SYS_poll, vec![]),
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
(libc::SYS_ppoll, vec![]),
|
||||
(libc::SYS_prctl, vec![]),
|
||||
(libc::SYS_pread64, vec![]),
|
||||
(libc::SYS_preadv, vec![]),
|
||||
@@ -453,6 +496,7 @@ fn vmm_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
|
||||
(libc::SYS_sendto, vec![]),
|
||||
(libc::SYS_set_robust_list, vec![]),
|
||||
(libc::SYS_set_tid_address, vec![]),
|
||||
(libc::SYS_setsid, vec![]),
|
||||
(libc::SYS_sigaltstack, vec![]),
|
||||
(
|
||||
libc::SYS_socket,
|
||||
@@ -598,6 +642,7 @@ fn api_thread_rules() -> Result<Vec<(i64, Vec<SeccompRule>)>, BackendError> {
|
||||
(libc::SYS_getrandom, vec![]),
|
||||
(libc::SYS_ioctl, create_api_ioctl_seccomp_rule()?),
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_mmap, vec![]),
|
||||
(libc::SYS_mprotect, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_recvfrom, vec![]),
|
||||
@@ -613,6 +658,7 @@ fn get_seccomp_rules(thread_type: Thread) -> Result<Vec<(i64, Vec<SeccompRule>)>
|
||||
Thread::SignalHandler => Ok(signal_handler_thread_rules()?),
|
||||
Thread::Vcpu => Ok(vcpu_thread_rules()?),
|
||||
Thread::Vmm => Ok(vmm_thread_rules()?),
|
||||
Thread::PtyForeground => Ok(pty_foreground_thread_rules()?),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use crate::serial_manager::EpollDispatch;
|
||||
|
||||
use std::io::Write;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
// Circular buffer implementation for serial output.
|
||||
// Read from head; push to tail
|
||||
@@ -12,6 +15,9 @@ pub(crate) struct SerialBuffer {
|
||||
head: usize,
|
||||
tail: usize,
|
||||
out: Box<dyn Write + Send>,
|
||||
buffering: bool,
|
||||
out_fd: Option<RawFd>,
|
||||
epoll_fd: Option<RawFd>,
|
||||
}
|
||||
|
||||
const MAX_BUFFER_SIZE: usize = 16 << 10;
|
||||
@@ -23,10 +29,21 @@ impl SerialBuffer {
|
||||
head: 0,
|
||||
tail: 0,
|
||||
out,
|
||||
buffering: false,
|
||||
out_fd: None,
|
||||
epoll_fd: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn flush_buffer(&mut self) -> Result<(), std::io::Error> {
|
||||
pub(crate) fn add_out_fd(&mut self, out_fd: RawFd) {
|
||||
self.out_fd = Some(out_fd);
|
||||
}
|
||||
|
||||
pub(crate) fn add_epoll_fd(&mut self, epoll_fd: RawFd) {
|
||||
self.epoll_fd = Some(epoll_fd);
|
||||
}
|
||||
|
||||
pub fn flush_buffer(&mut self) -> Result<(), std::io::Error> {
|
||||
if self.tail <= self.head {
|
||||
// The buffer to be written is in two parts
|
||||
let buf = &self.buffer[self.head..];
|
||||
@@ -45,6 +62,7 @@ impl SerialBuffer {
|
||||
if !matches!(e.kind(), std::io::ErrorKind::WouldBlock) {
|
||||
return Err(e);
|
||||
}
|
||||
self.add_out_poll()?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@@ -58,6 +76,7 @@ impl SerialBuffer {
|
||||
self.buffer.shrink_to_fit();
|
||||
self.head = 0;
|
||||
self.tail = 0;
|
||||
self.remove_out_poll()?;
|
||||
} else {
|
||||
self.head += bytes_written;
|
||||
}
|
||||
@@ -67,11 +86,45 @@ impl SerialBuffer {
|
||||
if !matches!(e.kind(), std::io::ErrorKind::WouldBlock) {
|
||||
return Err(e);
|
||||
}
|
||||
self.add_out_poll()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_out_poll(&mut self) -> Result<(), std::io::Error> {
|
||||
if self.out_fd.is_some() && self.epoll_fd.is_some() && !self.buffering {
|
||||
self.buffering = true;
|
||||
let out_fd = self.out_fd.as_ref().unwrap();
|
||||
let epoll_fd = self.epoll_fd.as_ref().unwrap();
|
||||
epoll::ctl(
|
||||
*epoll_fd,
|
||||
epoll::ControlOptions::EPOLL_CTL_MOD,
|
||||
*out_fd,
|
||||
epoll::Event::new(
|
||||
epoll::Events::EPOLLIN | epoll::Events::EPOLLOUT,
|
||||
EpollDispatch::File as u64,
|
||||
),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_out_poll(&mut self) -> Result<(), std::io::Error> {
|
||||
if self.out_fd.is_some() && self.epoll_fd.is_some() && self.buffering {
|
||||
self.buffering = false;
|
||||
let out_fd = self.out_fd.as_ref().unwrap();
|
||||
let epoll_fd = self.epoll_fd.as_ref().unwrap();
|
||||
epoll::ctl(
|
||||
*epoll_fd,
|
||||
epoll::ControlOptions::EPOLL_CTL_MOD,
|
||||
*out_fd,
|
||||
epoll::Event::new(epoll::Events::EPOLLIN, EpollDispatch::File as u64),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Write for SerialBuffer {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
|
||||
@@ -83,6 +136,7 @@ impl Write for SerialBuffer {
|
||||
if !matches!(e.kind(), std::io::ErrorKind::WouldBlock) {
|
||||
return Err(e);
|
||||
}
|
||||
self.add_out_poll()?;
|
||||
self.buffer.push(*v);
|
||||
self.tail += 1;
|
||||
} else {
|
||||
@@ -116,6 +170,6 @@ impl Write for SerialBuffer {
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<(), std::io::Error> {
|
||||
Ok(())
|
||||
self.flush_buffer()
|
||||
}
|
||||
}
|
||||
|
||||
270
vmm/src/serial_manager.rs
Normal file
270
vmm/src/serial_manager.rs
Normal file
@@ -0,0 +1,270 @@
|
||||
// Copyright © 2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use crate::config::ConsoleOutputMode;
|
||||
use crate::device_manager::PtyPair;
|
||||
use crate::serial_buffer::SerialBuffer;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use devices::legacy::Pl011;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use devices::legacy::Serial;
|
||||
use libc::EFD_NONBLOCK;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||
use std::panic::AssertUnwindSafe;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{io, result, thread};
|
||||
use thiserror::Error;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// Cannot clone File.
|
||||
#[error("Error cloning File: {0}")]
|
||||
FileClone(#[source] io::Error),
|
||||
|
||||
/// Cannot create epoll context.
|
||||
#[error("Error creating epoll context: {0}")]
|
||||
Epoll(#[source] io::Error),
|
||||
|
||||
/// Cannot handle the VM input stream.
|
||||
#[error("Error handling VM input: {0:?}")]
|
||||
ReadInput(#[source] io::Error),
|
||||
|
||||
/// Cannot queue input to the serial device.
|
||||
#[error("Error queuing input to the serial device: {0}")]
|
||||
QueueInput(#[source] vmm_sys_util::errno::Error),
|
||||
|
||||
/// Cannot flush output on the serial buffer.
|
||||
#[error("Error flushing serial device's output buffer: {0}")]
|
||||
FlushOutput(#[source] io::Error),
|
||||
|
||||
/// Cannot make the file descriptor non-blocking.
|
||||
#[error("Error making input file descriptor non-blocking: {0}")]
|
||||
SetNonBlocking(#[source] io::Error),
|
||||
|
||||
/// Cannot create EventFd.
|
||||
#[error("Error creating EventFd: {0}")]
|
||||
EventFd(#[source] io::Error),
|
||||
|
||||
/// Cannot spawn SerialManager thread.
|
||||
#[error("Error spawning SerialManager thread: {0}")]
|
||||
SpawnSerialManager(#[source] io::Error),
|
||||
}
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[repr(u64)]
|
||||
pub enum EpollDispatch {
|
||||
File = 0,
|
||||
Kill = 1,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl From<u64> for EpollDispatch {
|
||||
fn from(v: u64) -> Self {
|
||||
use EpollDispatch::*;
|
||||
match v {
|
||||
0 => File,
|
||||
1 => Kill,
|
||||
_ => Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SerialManager {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
serial: Arc<Mutex<Serial>>,
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
serial: Arc<Mutex<Pl011>>,
|
||||
epoll_file: File,
|
||||
in_file: File,
|
||||
kill_evt: EventFd,
|
||||
handle: Option<thread::JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl SerialManager {
|
||||
pub fn new(
|
||||
#[cfg(target_arch = "x86_64")] serial: Arc<Mutex<Serial>>,
|
||||
#[cfg(target_arch = "aarch64")] serial: Arc<Mutex<Pl011>>,
|
||||
pty_pair: Option<Arc<Mutex<PtyPair>>>,
|
||||
mode: ConsoleOutputMode,
|
||||
) -> Result<Option<Self>> {
|
||||
let in_file = match mode {
|
||||
ConsoleOutputMode::Pty => {
|
||||
if let Some(pty_pair) = pty_pair {
|
||||
pty_pair
|
||||
.lock()
|
||||
.unwrap()
|
||||
.main
|
||||
.try_clone()
|
||||
.map_err(Error::FileClone)?
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
ConsoleOutputMode::Tty => {
|
||||
// If running on an interactive TTY then accept input
|
||||
if unsafe { libc::isatty(libc::STDIN_FILENO) == 1 } {
|
||||
let stdin_clone = unsafe { File::from_raw_fd(libc::dup(libc::STDIN_FILENO)) };
|
||||
let ret = unsafe {
|
||||
let mut flags = libc::fcntl(stdin_clone.as_raw_fd(), libc::F_GETFL);
|
||||
flags |= libc::O_NONBLOCK;
|
||||
libc::fcntl(stdin_clone.as_raw_fd(), libc::F_SETFL, flags)
|
||||
};
|
||||
|
||||
if ret < 0 {
|
||||
return Err(Error::SetNonBlocking(std::io::Error::last_os_error()));
|
||||
}
|
||||
|
||||
stdin_clone
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
_ => return Ok(None),
|
||||
};
|
||||
|
||||
let epoll_fd = epoll::create(true).map_err(Error::Epoll)?;
|
||||
let kill_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFd)?;
|
||||
|
||||
epoll::ctl(
|
||||
epoll_fd,
|
||||
epoll::ControlOptions::EPOLL_CTL_ADD,
|
||||
kill_evt.as_raw_fd(),
|
||||
epoll::Event::new(epoll::Events::EPOLLIN, EpollDispatch::Kill as u64),
|
||||
)
|
||||
.map_err(Error::Epoll)?;
|
||||
|
||||
epoll::ctl(
|
||||
epoll_fd,
|
||||
epoll::ControlOptions::EPOLL_CTL_ADD,
|
||||
in_file.as_raw_fd(),
|
||||
epoll::Event::new(epoll::Events::EPOLLIN, EpollDispatch::File as u64),
|
||||
)
|
||||
.map_err(Error::Epoll)?;
|
||||
|
||||
if mode == ConsoleOutputMode::Pty {
|
||||
let writer = in_file.try_clone().map_err(Error::FileClone)?;
|
||||
let mut buffer = SerialBuffer::new(Box::new(writer));
|
||||
buffer.add_out_fd(in_file.as_raw_fd());
|
||||
buffer.add_epoll_fd(epoll_fd);
|
||||
serial.as_ref().lock().unwrap().set_out(Box::new(buffer));
|
||||
}
|
||||
|
||||
// Use 'File' to enforce closing on 'epoll_fd'
|
||||
let epoll_file = unsafe { File::from_raw_fd(epoll_fd) };
|
||||
|
||||
Ok(Some(SerialManager {
|
||||
serial,
|
||||
epoll_file,
|
||||
in_file,
|
||||
kill_evt,
|
||||
handle: None,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn start_thread(&mut self, exit_evt: EventFd) -> Result<()> {
|
||||
// Don't allow this to be run if the handle exists
|
||||
if self.handle.is_some() {
|
||||
warn!("Tried to start multiple SerialManager threads, ignoring");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let epoll_fd = self.epoll_file.as_raw_fd();
|
||||
let mut in_file = self.in_file.try_clone().map_err(Error::FileClone)?;
|
||||
let serial = self.serial.clone();
|
||||
|
||||
let thread = thread::Builder::new()
|
||||
.name("serial-manager".to_string())
|
||||
.spawn(move || {
|
||||
std::panic::catch_unwind(AssertUnwindSafe(move || {
|
||||
// 3 for File, Kill, and Unknown
|
||||
const EPOLL_EVENTS_LEN: usize = 3;
|
||||
|
||||
let mut events =
|
||||
vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN];
|
||||
|
||||
loop {
|
||||
let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::Interrupted {
|
||||
// It's well defined from the epoll_wait() syscall
|
||||
// documentation that the epoll loop can be interrupted
|
||||
// before any of the requested events occurred or the
|
||||
// timeout expired. In both those cases, epoll_wait()
|
||||
// returns an error of type EINTR, but this should not
|
||||
// be considered as a regular error. Instead it is more
|
||||
// appropriate to retry, by calling into epoll_wait().
|
||||
continue;
|
||||
}
|
||||
return Err(Error::Epoll(e));
|
||||
}
|
||||
};
|
||||
|
||||
for event in events.iter().take(num_events) {
|
||||
let dispatch_event: EpollDispatch = event.data.into();
|
||||
match dispatch_event {
|
||||
EpollDispatch::Unknown => {
|
||||
let event = event.data;
|
||||
warn!("Unknown serial manager loop event: {}", event);
|
||||
}
|
||||
EpollDispatch::File => {
|
||||
if event.events & libc::EPOLLOUT as u32 != 0 {
|
||||
serial
|
||||
.as_ref()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.flush_output()
|
||||
.map_err(Error::FlushOutput)?;
|
||||
}
|
||||
if event.events & libc::EPOLLIN as u32 != 0 {
|
||||
let mut input = [0u8; 64];
|
||||
let count =
|
||||
in_file.read(&mut input).map_err(Error::ReadInput)?;
|
||||
|
||||
// Replace "\n" with "\r" to deal with Windows SAC (#1170)
|
||||
if count == 1 && input[0] == 0x0a {
|
||||
input[0] = 0x0d;
|
||||
}
|
||||
|
||||
serial
|
||||
.as_ref()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.queue_input_bytes(&input[..count])
|
||||
.map_err(Error::QueueInput)?;
|
||||
}
|
||||
}
|
||||
EpollDispatch::Kill => {
|
||||
info!("KILL event received, stopping epoll loop");
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
.map_err(|_| {
|
||||
error!("serial-manager thread panicked");
|
||||
exit_evt.write(1).ok()
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
.map_err(Error::SpawnSerialManager)?;
|
||||
self.handle = Some(thread);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SerialManager {
|
||||
fn drop(&mut self) {
|
||||
self.kill_evt.write(1).ok();
|
||||
if let Some(handle) = self.handle.take() {
|
||||
handle.join().ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
135
vmm/src/sigwinch_listener.rs
Normal file
135
vmm/src/sigwinch_listener.rs
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright 2021 Alyssa Ross <hi@alyssa.is>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::clone3::{clone3, clone_args, CLONE_CLEAR_SIGHAND};
|
||||
use libc::{
|
||||
c_int, c_void, close, getpgrp, ioctl, pipe2, poll, pollfd, setsid, sigemptyset, siginfo_t,
|
||||
sigprocmask, tcsetpgrp, O_CLOEXEC, POLLERR, SIGWINCH, SIG_SETMASK, STDIN_FILENO, STDOUT_FILENO,
|
||||
TIOCSCTTY,
|
||||
};
|
||||
use seccompiler::{apply_filter, BpfProgram};
|
||||
use std::cell::RefCell;
|
||||
use std::fs::File;
|
||||
use std::io::{self, ErrorKind, Read, Write};
|
||||
use std::mem::size_of;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::os::unix::prelude::*;
|
||||
use std::process::exit;
|
||||
use std::ptr::null_mut;
|
||||
use vmm_sys_util::signal::register_signal_handler;
|
||||
|
||||
thread_local! {
|
||||
// The tty file descriptor is stored in a global variable so it
|
||||
// can be accessed by a signal handler.
|
||||
static TX: RefCell<Option<File>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
fn with_tx<R, F: FnOnce(&File) -> R>(f: F) -> R {
|
||||
TX.with(|tx| f(tx.borrow().as_ref().unwrap()))
|
||||
}
|
||||
|
||||
// This function has to be safe to call from a signal handler, and
|
||||
// therefore must not panic.
|
||||
fn notify() {
|
||||
if let Err(e) = with_tx(|mut tx| tx.write_all(b"\n")) {
|
||||
if e.kind() == ErrorKind::BrokenPipe {
|
||||
exit(0);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn sigwinch_handler(_signo: c_int, _info: *mut siginfo_t, _unused: *mut c_void) {
|
||||
notify();
|
||||
}
|
||||
|
||||
fn unblock_all_signals() -> io::Result<()> {
|
||||
let mut set = MaybeUninit::uninit();
|
||||
if unsafe { sigemptyset(set.as_mut_ptr()) } == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let set = unsafe { set.assume_init() };
|
||||
|
||||
if unsafe { sigprocmask(SIG_SETMASK, &set, null_mut()) } == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sigwinch_listener_main(seccomp_filter: BpfProgram, tx: File, tty: &File) -> ! {
|
||||
TX.with(|opt| opt.replace(Some(tx)));
|
||||
|
||||
unsafe {
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
}
|
||||
|
||||
unblock_all_signals().unwrap();
|
||||
|
||||
apply_filter(&seccomp_filter).unwrap();
|
||||
|
||||
register_signal_handler(SIGWINCH, sigwinch_handler).unwrap();
|
||||
|
||||
unsafe {
|
||||
// Create a new session (and therefore a new process group).
|
||||
assert_ne!(setsid(), -1);
|
||||
|
||||
// Set the tty to be this process's controlling terminal.
|
||||
assert_ne!(ioctl(tty.as_raw_fd(), TIOCSCTTY, 0), -1);
|
||||
|
||||
// Become the foreground process group of the tty.
|
||||
assert_ne!(tcsetpgrp(tty.as_raw_fd(), getpgrp()), -1);
|
||||
}
|
||||
|
||||
notify();
|
||||
|
||||
// Wait for the pipe to close, indicating the parent has exited.
|
||||
with_tx(|tx| {
|
||||
let mut pollfd = pollfd {
|
||||
fd: tx.as_raw_fd(),
|
||||
events: 0,
|
||||
revents: 0,
|
||||
};
|
||||
|
||||
while unsafe { poll(&mut pollfd, 1, -1) } == -1 {
|
||||
let e = io::Error::last_os_error();
|
||||
if !matches!(e.kind(), ErrorKind::Interrupted | ErrorKind::WouldBlock) {
|
||||
panic!("poll: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(pollfd.revents, POLLERR);
|
||||
});
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
pub fn start_sigwinch_listener(seccomp_filter: BpfProgram, pty: &File) -> io::Result<File> {
|
||||
let mut pipe = [-1; 2];
|
||||
if unsafe { pipe2(pipe.as_mut_ptr(), O_CLOEXEC) } == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
let mut rx = unsafe { File::from_raw_fd(pipe[0]) };
|
||||
let tx = unsafe { File::from_raw_fd(pipe[1]) };
|
||||
|
||||
let mut args = clone_args::default();
|
||||
args.flags |= CLONE_CLEAR_SIGHAND;
|
||||
|
||||
match unsafe { clone3(&mut args, size_of::<clone_args>()) } {
|
||||
-1 => return Err(io::Error::last_os_error()),
|
||||
0 => {
|
||||
drop(rx);
|
||||
sigwinch_listener_main(seccomp_filter, tx, pty);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
drop(tx);
|
||||
|
||||
// Wait for a notification indicating readiness.
|
||||
rx.read_exact(&mut [0])?;
|
||||
|
||||
Ok(rx)
|
||||
}
|
||||
422
vmm/src/vm.rs
422
vmm/src/vm.rs
@@ -14,25 +14,27 @@
|
||||
#[cfg(any(target_arch = "aarch64", feature = "acpi"))]
|
||||
use crate::config::NumaConfig;
|
||||
use crate::config::{
|
||||
ConsoleOutputMode, DeviceConfig, DiskConfig, FsConfig, HotplugMethod, NetConfig, PmemConfig,
|
||||
UserDeviceConfig, ValidationError, VmConfig, VsockConfig,
|
||||
};
|
||||
use crate::device_manager::{
|
||||
self, get_win_size, Console, DeviceManager, DeviceManagerError, PtyPair,
|
||||
DeviceConfig, DiskConfig, FsConfig, HotplugMethod, NetConfig, PmemConfig, UserDeviceConfig,
|
||||
ValidationError, VmConfig, VsockConfig,
|
||||
};
|
||||
use crate::cpu;
|
||||
use crate::device_manager::{self, Console, DeviceManager, DeviceManagerError, PtyPair};
|
||||
use crate::device_tree::DeviceTree;
|
||||
use crate::memory_manager::{Error as MemoryManagerError, MemoryManager};
|
||||
use crate::memory_manager::{
|
||||
Error as MemoryManagerError, MemoryManager, MemoryManagerSnapshotData,
|
||||
};
|
||||
use crate::migration::{get_vm_snapshot, url_to_path, VM_SNAPSHOT_FILE};
|
||||
use crate::seccomp_filters::{get_seccomp_filter, Thread};
|
||||
use crate::GuestMemoryMmap;
|
||||
use crate::{cpu, EpollDispatch};
|
||||
use crate::{
|
||||
PciDeviceInfo, CPU_MANAGER_SNAPSHOT_ID, DEVICE_MANAGER_SNAPSHOT_ID, MEMORY_MANAGER_SNAPSHOT_ID,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use arch::get_host_cpu_phys_bits;
|
||||
#[cfg(all(feature = "tdx", feature = "acpi"))]
|
||||
use arch::x86_64::tdx::TdVmmDataRegionType;
|
||||
#[cfg(feature = "tdx")]
|
||||
use arch::x86_64::tdx::TdvfSection;
|
||||
use arch::x86_64::tdx::{TdVmmDataRegion, TdvfSection};
|
||||
use arch::EntryPoint;
|
||||
#[cfg(any(target_arch = "aarch64", feature = "acpi"))]
|
||||
use arch::{NumaNode, NumaNodes};
|
||||
@@ -55,7 +57,6 @@ use std::cmp;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::CString;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::fmt;
|
||||
use std::fs::{File, OpenOptions};
|
||||
@@ -67,14 +68,16 @@ use std::panic::AssertUnwindSafe;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::{result, str, thread};
|
||||
use vm_device::Bus;
|
||||
use vm_memory::{
|
||||
Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
||||
GuestMemoryRegion,
|
||||
};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use vm_device::BusDevice;
|
||||
#[cfg(any(target_arch = "aarch64", feature = "tdx"))]
|
||||
use vm_memory::Address;
|
||||
use vm_memory::{Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic};
|
||||
#[cfg(feature = "tdx")]
|
||||
use vm_memory::{GuestMemory, GuestMemoryRegion};
|
||||
use vm_migration::{
|
||||
protocol::{MemoryRange, MemoryRangeTable},
|
||||
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
|
||||
Transportable,
|
||||
protocol::MemoryRangeTable, Migratable, MigratableError, Pausable, Snapshot,
|
||||
SnapshotDataSection, Snapshottable, Transportable,
|
||||
};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::signal::unblock_signal;
|
||||
@@ -112,9 +115,6 @@ pub enum Error {
|
||||
/// Cannot modify the command line
|
||||
CmdLineInsertStr(linux_loader::cmdline::Error),
|
||||
|
||||
/// Cannot convert command line into CString
|
||||
CmdLineCString(std::ffi::NulError),
|
||||
|
||||
/// Cannot configure system
|
||||
ConfigureSystem(arch::Error),
|
||||
|
||||
@@ -362,6 +362,8 @@ struct VmOps {
|
||||
mmio_bus: Arc<Bus>,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
timestamp: std::time::Instant,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pci_config_io: Arc<Mutex<dyn BusDevice>>,
|
||||
}
|
||||
|
||||
impl VmOps {
|
||||
@@ -419,6 +421,17 @@ impl VmmOps for VmOps {
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn pio_read(&self, port: u64, data: &mut [u8]) -> hypervisor::vm::Result<()> {
|
||||
use pci::{PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
|
||||
|
||||
if (PCI_CONFIG_IO_PORT..(PCI_CONFIG_IO_PORT + PCI_CONFIG_IO_PORT_SIZE)).contains(&port) {
|
||||
self.pci_config_io.lock().unwrap().read(
|
||||
PCI_CONFIG_IO_PORT,
|
||||
port - PCI_CONFIG_IO_PORT,
|
||||
data,
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Err(vm_device::BusError::MissingAddressRange) = self.io_bus.read(port, data) {
|
||||
warn!("Guest PIO read to unregistered address 0x{:x}", port);
|
||||
}
|
||||
@@ -427,11 +440,22 @@ impl VmmOps for VmOps {
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn pio_write(&self, port: u64, data: &[u8]) -> hypervisor::vm::Result<()> {
|
||||
use pci::{PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
|
||||
|
||||
if port == DEBUG_IOPORT as u64 && data.len() == 1 {
|
||||
self.log_debug_ioport(data[0]);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if (PCI_CONFIG_IO_PORT..(PCI_CONFIG_IO_PORT + PCI_CONFIG_IO_PORT_SIZE)).contains(&port) {
|
||||
self.pci_config_io.lock().unwrap().write(
|
||||
PCI_CONFIG_IO_PORT,
|
||||
port - PCI_CONFIG_IO_PORT,
|
||||
data,
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match self.io_bus.write(port, data) {
|
||||
Err(vm_device::BusError::MissingAddressRange) => {
|
||||
warn!("Guest PIO write to unregistered address 0x{:x}", port);
|
||||
@@ -447,24 +471,10 @@ impl VmmOps for VmOps {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn physical_bits(max_phys_bits: Option<u8>, #[cfg(feature = "tdx")] tdx_enabled: bool) -> u8 {
|
||||
#[cfg(not(feature = "tdx"))]
|
||||
pub fn physical_bits(max_phys_bits: u8) -> u8 {
|
||||
let host_phys_bits = get_host_cpu_phys_bits();
|
||||
#[cfg(feature = "tdx")]
|
||||
let mut host_phys_bits = get_host_cpu_phys_bits();
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
if tdx_enabled {
|
||||
// When running TDX guest, the Guest Physical Address space is limited
|
||||
// by a shared bit that is located on bit 47 for 4 level paging, and on
|
||||
// bit 51 for 5 level paging (when GPAW bit is 1). In order to keep
|
||||
// things simple, and since a 47 bits address space is 128TiB large, we
|
||||
// ensure to limit the physical addressable space to 47 bits when
|
||||
// runnning TDX.
|
||||
host_phys_bits = std::cmp::min(host_phys_bits, 47)
|
||||
}
|
||||
|
||||
cmp::min(host_phys_bits, max_phys_bits.unwrap_or(host_phys_bits))
|
||||
cmp::min(host_phys_bits, max_phys_bits)
|
||||
}
|
||||
|
||||
pub const HANDLED_SIGNALS: [i32; 3] = [SIGWINCH, SIGTERM, SIGINT];
|
||||
@@ -548,6 +558,10 @@ impl Vm {
|
||||
let mmio_bus = Arc::clone(device_manager.lock().unwrap().mmio_bus());
|
||||
// Create the VmOps structure, which implements the VmmOps trait.
|
||||
// And send it to the hypervisor.
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let pci_config_io =
|
||||
device_manager.lock().unwrap().pci_config_io() as Arc<Mutex<dyn BusDevice>>;
|
||||
let vm_ops: Arc<dyn VmmOps> = Arc::new(VmOps {
|
||||
memory,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@@ -555,6 +569,8 @@ impl Vm {
|
||||
mmio_bus,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
timestamp: std::time::Instant::now(),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pci_config_io,
|
||||
});
|
||||
|
||||
let exit_evt_clone = exit_evt.try_clone().map_err(Error::EventFdClone)?;
|
||||
@@ -710,6 +726,7 @@ impl Vm {
|
||||
activate_evt: EventFd,
|
||||
serial_pty: Option<PtyPair>,
|
||||
console_pty: Option<PtyPair>,
|
||||
console_resize_pipe: Option<File>,
|
||||
) -> Result<Self> {
|
||||
#[cfg(feature = "tdx")]
|
||||
let tdx_enabled = config.lock().unwrap().tdx.is_some();
|
||||
@@ -727,18 +744,15 @@ impl Vm {
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
vm.enable_split_irq().unwrap();
|
||||
let phys_bits = physical_bits(
|
||||
config.lock().unwrap().cpus.max_phys_bits,
|
||||
#[cfg(feature = "tdx")]
|
||||
tdx_enabled,
|
||||
);
|
||||
let phys_bits = physical_bits(config.lock().unwrap().cpus.max_phys_bits);
|
||||
let memory_manager = MemoryManager::new(
|
||||
vm.clone(),
|
||||
&config.lock().unwrap().memory.clone(),
|
||||
false,
|
||||
None,
|
||||
phys_bits,
|
||||
#[cfg(feature = "tdx")]
|
||||
tdx_enabled,
|
||||
None,
|
||||
)
|
||||
.map_err(Error::MemoryManager)?;
|
||||
|
||||
@@ -773,7 +787,7 @@ impl Vm {
|
||||
.device_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
.create_devices(serial_pty, console_pty)
|
||||
.create_devices(serial_pty, console_pty, console_resize_pipe)
|
||||
.map_err(Error::DeviceManager)?;
|
||||
Ok(new_vm)
|
||||
}
|
||||
@@ -803,11 +817,7 @@ impl Vm {
|
||||
let memory_manager = if let Some(memory_manager_snapshot) =
|
||||
snapshot.snapshots.get(MEMORY_MANAGER_SNAPSHOT_ID)
|
||||
{
|
||||
let phys_bits = physical_bits(
|
||||
config.lock().unwrap().cpus.max_phys_bits,
|
||||
#[cfg(feature = "tdx")]
|
||||
config.lock().unwrap().tdx.is_some(),
|
||||
);
|
||||
let phys_bits = physical_bits(config.lock().unwrap().cpus.max_phys_bits);
|
||||
MemoryManager::new_from_snapshot(
|
||||
memory_manager_snapshot,
|
||||
vm.clone(),
|
||||
@@ -845,24 +855,22 @@ impl Vm {
|
||||
seccomp_action: &SeccompAction,
|
||||
hypervisor: Arc<dyn hypervisor::Hypervisor>,
|
||||
activate_evt: EventFd,
|
||||
memory_manager_data: &MemoryManagerSnapshotData,
|
||||
) -> Result<Self> {
|
||||
hypervisor.check_required_extensions().unwrap();
|
||||
let vm = hypervisor.create_vm().unwrap();
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
vm.enable_split_irq().unwrap();
|
||||
let phys_bits = physical_bits(
|
||||
config.lock().unwrap().cpus.max_phys_bits,
|
||||
#[cfg(feature = "tdx")]
|
||||
config.lock().unwrap().tdx.is_some(),
|
||||
);
|
||||
let phys_bits = physical_bits(config.lock().unwrap().cpus.max_phys_bits);
|
||||
|
||||
let memory_manager = MemoryManager::new(
|
||||
vm.clone(),
|
||||
&config.lock().unwrap().memory.clone(),
|
||||
false,
|
||||
None,
|
||||
phys_bits,
|
||||
#[cfg(feature = "tdx")]
|
||||
false,
|
||||
Some(memory_manager_data),
|
||||
)
|
||||
.map_err(Error::MemoryManager)?;
|
||||
|
||||
@@ -904,7 +912,7 @@ impl Vm {
|
||||
Ok(arch::InitramfsConfig { address, size })
|
||||
}
|
||||
|
||||
fn get_cmdline(&mut self) -> Result<CString> {
|
||||
fn get_cmdline(&mut self) -> Result<Cmdline> {
|
||||
let mut cmdline = Cmdline::new(arch::CMDLINE_MAX_SIZE);
|
||||
cmdline
|
||||
.insert_str(self.config.lock().unwrap().cmdline.args.clone())
|
||||
@@ -912,7 +920,7 @@ impl Vm {
|
||||
for entry in self.device_manager.lock().unwrap().cmdline_additions() {
|
||||
cmdline.insert_str(entry).map_err(Error::CmdLineInsertStr)?;
|
||||
}
|
||||
CString::new(cmdline).map_err(Error::CmdLineCString)
|
||||
Ok(cmdline)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
@@ -957,7 +965,7 @@ impl Vm {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn load_kernel(&mut self) -> Result<EntryPoint> {
|
||||
info!("Loading kernel");
|
||||
let cmdline_cstring = self.get_cmdline()?;
|
||||
let cmdline = self.get_cmdline()?;
|
||||
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
|
||||
let mem = guest_memory.memory();
|
||||
let mut kernel = self.kernel.as_ref().unwrap();
|
||||
@@ -973,12 +981,8 @@ impl Vm {
|
||||
}
|
||||
};
|
||||
|
||||
linux_loader::loader::load_cmdline(
|
||||
mem.deref(),
|
||||
arch::layout::CMDLINE_START,
|
||||
&cmdline_cstring,
|
||||
)
|
||||
.map_err(Error::LoadCmdLine)?;
|
||||
linux_loader::loader::load_cmdline(mem.deref(), arch::layout::CMDLINE_START, &cmdline)
|
||||
.map_err(Error::LoadCmdLine)?;
|
||||
|
||||
if let PvhEntryPresent(entry_addr) = entry_addr.pvh_boot_cap {
|
||||
// Use the PVH kernel entry point to boot the guest
|
||||
@@ -990,7 +994,7 @@ impl Vm {
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn configure_system(&mut self) -> Result<()> {
|
||||
fn configure_system(&mut self, #[cfg(feature = "acpi")] rsdp_addr: GuestAddress) -> Result<()> {
|
||||
info!("Configuring system");
|
||||
let mem = self.memory_manager.lock().unwrap().boot_guest_memory();
|
||||
|
||||
@@ -1001,23 +1005,10 @@ impl Vm {
|
||||
|
||||
let boot_vcpus = self.cpu_manager.lock().unwrap().boot_vcpus();
|
||||
|
||||
#[allow(unused_mut, unused_assignments)]
|
||||
let mut rsdp_addr: Option<GuestAddress> = None;
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
{
|
||||
rsdp_addr = Some(crate::acpi::create_acpi_tables(
|
||||
&mem,
|
||||
&self.device_manager,
|
||||
&self.cpu_manager,
|
||||
&self.memory_manager,
|
||||
&self.numa_nodes,
|
||||
));
|
||||
info!(
|
||||
"Created ACPI tables: rsdp_addr = 0x{:x}",
|
||||
rsdp_addr.unwrap().0
|
||||
);
|
||||
}
|
||||
let rsdp_addr = Some(rsdp_addr);
|
||||
#[cfg(not(feature = "acpi"))]
|
||||
let rsdp_addr = None;
|
||||
|
||||
let sgx_epc_region = self
|
||||
.memory_manager
|
||||
@@ -1040,8 +1031,11 @@ impl Vm {
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn configure_system(&mut self) -> Result<()> {
|
||||
let cmdline_cstring = self.get_cmdline()?;
|
||||
fn configure_system(
|
||||
&mut self,
|
||||
#[cfg(feature = "acpi")] _rsdp_addr: GuestAddress,
|
||||
) -> Result<()> {
|
||||
let cmdline = self.get_cmdline()?;
|
||||
let vcpu_mpidrs = self.cpu_manager.lock().unwrap().get_mpidrs();
|
||||
let vcpu_topology = self.cpu_manager.lock().unwrap().get_vcpu_topology();
|
||||
let mem = self.memory_manager.lock().unwrap().boot_guest_memory();
|
||||
@@ -1078,16 +1072,13 @@ impl Vm {
|
||||
|
||||
let pci_space = (pci_space_start.0, pci_space_size);
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
{
|
||||
let _ = crate::acpi::create_acpi_tables(
|
||||
&mem,
|
||||
&self.device_manager,
|
||||
&self.cpu_manager,
|
||||
&self.memory_manager,
|
||||
&self.numa_nodes,
|
||||
);
|
||||
}
|
||||
let virtio_iommu_bdf = self
|
||||
.device_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iommu_attached_devices()
|
||||
.as_ref()
|
||||
.map(|(v, _)| *v);
|
||||
|
||||
let gic_device = create_gic(
|
||||
&self.memory_manager.lock().as_ref().unwrap().vm,
|
||||
@@ -1099,12 +1090,13 @@ impl Vm {
|
||||
|
||||
arch::configure_system(
|
||||
&mem,
|
||||
&cmdline_cstring,
|
||||
cmdline.as_str(),
|
||||
vcpu_mpidrs,
|
||||
vcpu_topology,
|
||||
device_info,
|
||||
&initramfs_config,
|
||||
&pci_space,
|
||||
virtio_iommu_bdf,
|
||||
&*gic_device,
|
||||
&self.numa_nodes,
|
||||
)
|
||||
@@ -1142,6 +1134,10 @@ impl Vm {
|
||||
self.device_manager.lock().unwrap().console_pty()
|
||||
}
|
||||
|
||||
pub fn console_resize_pipe(&self) -> Option<Arc<File>> {
|
||||
self.device_manager.lock().unwrap().console_resize_pipe()
|
||||
}
|
||||
|
||||
pub fn shutdown(&mut self) -> Result<()> {
|
||||
let mut state = self.state.try_write().map_err(|_| Error::PoisonedState)?;
|
||||
let new_state = VmState::Shutdown;
|
||||
@@ -1602,8 +1598,7 @@ impl Vm {
|
||||
for signal in signals.forever() {
|
||||
match signal {
|
||||
SIGWINCH => {
|
||||
let (col, row) = get_win_size();
|
||||
console_input_clone.update_console_size(col, row);
|
||||
console_input_clone.update_console_size();
|
||||
}
|
||||
SIGTERM | SIGINT => {
|
||||
if on_tty {
|
||||
@@ -1644,7 +1639,11 @@ impl Vm {
|
||||
}
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
fn populate_tdx_sections(&mut self, sections: &[TdvfSection]) -> Result<Option<u64>> {
|
||||
fn populate_tdx_sections(
|
||||
&mut self,
|
||||
sections: &[TdvfSection],
|
||||
vmm_data_regions: &[TdVmmDataRegion],
|
||||
) -> Result<Option<u64>> {
|
||||
use arch::x86_64::tdx::*;
|
||||
// Get the memory end *before* we start adding TDVF ram regions
|
||||
let boot_guest_memory = self
|
||||
@@ -1710,6 +1709,20 @@ impl Vm {
|
||||
sorted_sections.retain(|section| {
|
||||
!matches!(section.r#type, TdvfSectionType::Bfv | TdvfSectionType::Cfv)
|
||||
});
|
||||
|
||||
// Add VMM specific data memory region to TdvfSections as TdHob type
|
||||
// to ensure the firmware won't ignore/reject the ranges.
|
||||
for region in vmm_data_regions {
|
||||
sorted_sections.push(TdvfSection {
|
||||
data_offset: 0,
|
||||
data_size: 0,
|
||||
address: region.start_address,
|
||||
size: region.length,
|
||||
r#type: TdvfSectionType::TdHob,
|
||||
attributes: 0,
|
||||
});
|
||||
}
|
||||
|
||||
sorted_sections.sort_by_key(|section| section.address);
|
||||
sorted_sections.reverse();
|
||||
let mut current_section = sorted_sections.pop();
|
||||
@@ -1777,13 +1790,25 @@ impl Vm {
|
||||
)
|
||||
.map_err(Error::PopulateHob)?;
|
||||
|
||||
// Add VMM specific data to the TdHob. The content of the data is
|
||||
// is written as part of the HOB, which will be retrieved from the
|
||||
// firmware, and processed accordingly to the type.
|
||||
for region in vmm_data_regions {
|
||||
hob.add_td_vmm_data(&mem, *region)
|
||||
.map_err(Error::PopulateHob)?;
|
||||
}
|
||||
|
||||
hob.finish(&mem).map_err(Error::PopulateHob)?;
|
||||
|
||||
Ok(hob_offset)
|
||||
}
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
fn init_tdx_memory(&mut self, sections: &[TdvfSection]) -> Result<()> {
|
||||
fn init_tdx_memory(
|
||||
&mut self,
|
||||
sections: &[TdvfSection],
|
||||
regions: &[TdVmmDataRegion],
|
||||
) -> Result<()> {
|
||||
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
|
||||
let mem = guest_memory.memory();
|
||||
|
||||
@@ -1798,6 +1823,22 @@ impl Vm {
|
||||
)
|
||||
.map_err(Error::InitializeTdxMemoryRegion)?;
|
||||
}
|
||||
|
||||
// The same way we let the hypervisor know about the TDVF sections, we
|
||||
// must declare the VMM specific regions shared with the guest so that
|
||||
// they won't be discarded.
|
||||
for region in regions {
|
||||
self.vm
|
||||
.tdx_init_memory_region(
|
||||
mem.get_host_address(GuestAddress(region.start_address))
|
||||
.unwrap() as u64,
|
||||
region.start_address,
|
||||
region.length,
|
||||
false,
|
||||
)
|
||||
.map_err(Error::InitializeTdxMemoryRegion)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1888,16 +1929,52 @@ impl Vm {
|
||||
#[cfg(feature = "tdx")]
|
||||
let sections = self.extract_tdvf_sections()?;
|
||||
|
||||
// Configuring the TDX regions requires that the vCPUs are created
|
||||
#[cfg(feature = "acpi")]
|
||||
let rsdp_addr = {
|
||||
let mem = self.memory_manager.lock().unwrap().guest_memory().memory();
|
||||
|
||||
let rsdp_addr = crate::acpi::create_acpi_tables(
|
||||
&mem,
|
||||
&self.device_manager,
|
||||
&self.cpu_manager,
|
||||
&self.memory_manager,
|
||||
&self.numa_nodes,
|
||||
);
|
||||
info!("Created ACPI tables: rsdp_addr = 0x{:x}", rsdp_addr.0);
|
||||
|
||||
rsdp_addr
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "tdx", not(feature = "acpi")))]
|
||||
let vmm_data_regions: Vec<TdVmmDataRegion> = Vec::new();
|
||||
|
||||
// Create a VMM specific data region to share the ACPI tables with
|
||||
// the guest. Reserving 64kiB to ensure the ACPI tables will fit.
|
||||
#[cfg(all(feature = "tdx", feature = "acpi"))]
|
||||
let vmm_data_regions = vec![TdVmmDataRegion {
|
||||
start_address: rsdp_addr.0,
|
||||
length: 0x10000,
|
||||
region_type: TdVmmDataRegionType::AcpiTables,
|
||||
}];
|
||||
|
||||
// Configuring the TDX regions requires that the vCPUs are created.
|
||||
#[cfg(feature = "tdx")]
|
||||
let hob_address = if self.config.lock().unwrap().tdx.is_some() {
|
||||
self.populate_tdx_sections(§ions)?
|
||||
// TDX sections are written to memory.
|
||||
self.populate_tdx_sections(§ions, &vmm_data_regions)?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Configure shared state based on loaded kernel
|
||||
entry_point.map(|_| self.configure_system()).transpose()?;
|
||||
entry_point
|
||||
.map(|_| {
|
||||
self.configure_system(
|
||||
#[cfg(feature = "acpi")]
|
||||
rsdp_addr,
|
||||
)
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
if let Some(hob_address) = hob_address {
|
||||
@@ -1908,7 +1985,10 @@ impl Vm {
|
||||
.unwrap()
|
||||
.initialize_tdx(hob_address)
|
||||
.map_err(Error::CpuManager)?;
|
||||
self.init_tdx_memory(§ions)?;
|
||||
// Let the hypervisor know which memory ranges are shared with the
|
||||
// guest. This prevents the guest from ignoring/discarding memory
|
||||
// regions provided by the host.
|
||||
self.init_tdx_memory(§ions, &vmm_data_regions)?;
|
||||
// With TDX memory and CPU state configured TDX setup is complete
|
||||
self.vm.tdx_finalize().map_err(Error::FinalizeTdx)?;
|
||||
}
|
||||
@@ -1928,53 +2008,6 @@ impl Vm {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_pty(&self, event: EpollDispatch) -> Result<()> {
|
||||
// Could be a little dangerous, picks up a lock on device_manager
|
||||
// and goes into a blocking read. If the epoll loops starts to be
|
||||
// services by multiple threads likely need to revist this.
|
||||
let dm = self.device_manager.lock().unwrap();
|
||||
|
||||
if matches!(event, EpollDispatch::SerialPty) {
|
||||
if let Some(mut pty) = dm.serial_pty() {
|
||||
let mut out = [0u8; 64];
|
||||
let count = pty.main.read(&mut out).map_err(Error::PtyConsole)?;
|
||||
let console = dm.console();
|
||||
console
|
||||
.queue_input_bytes_serial(&out[..count])
|
||||
.map_err(Error::Console)?;
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_stdin(&self) -> Result<()> {
|
||||
let mut out = [0u8; 64];
|
||||
let count = io::stdin()
|
||||
.lock()
|
||||
.read_raw(&mut out)
|
||||
.map_err(Error::Console)?;
|
||||
|
||||
// Replace "\n" with "\r" to deal with Windows SAC (#1170)
|
||||
if count == 1 && out[0] == 0x0a {
|
||||
out[0] = 0x0d;
|
||||
}
|
||||
|
||||
if matches!(
|
||||
self.config.lock().unwrap().serial.mode,
|
||||
ConsoleOutputMode::Tty
|
||||
) {
|
||||
self.device_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
.console()
|
||||
.queue_input_bytes_serial(&out[..count])
|
||||
.map_err(Error::Console)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets a thread-safe reference counted pointer to the VM configuration.
|
||||
pub fn get_config(&self) -> Arc<Mutex<VmConfig>> {
|
||||
Arc::clone(&self.config)
|
||||
@@ -2127,14 +2160,33 @@ impl Vm {
|
||||
let mem = guest_memory.memory();
|
||||
|
||||
for range in ranges.regions() {
|
||||
mem.read_exact_from(GuestAddress(range.gpa), fd, range.length as usize)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!(
|
||||
"Error transferring memory to socket: {}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
let mut offset: u64 = 0;
|
||||
// Here we are manually handling the retry in case we can't the
|
||||
// whole region at once because we can't use the implementation
|
||||
// from vm-memory::GuestMemory of read_exact_from() as it is not
|
||||
// following the correct behavior. For more info about this issue
|
||||
// see: https://github.com/rust-vmm/vm-memory/issues/174
|
||||
loop {
|
||||
let bytes_read = mem
|
||||
.read_from(
|
||||
GuestAddress(range.gpa + offset),
|
||||
fd,
|
||||
(range.length - offset) as usize,
|
||||
)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateReceive(anyhow!(
|
||||
"Error receiving memory from socket: {}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
offset += bytes_read as u64;
|
||||
|
||||
if offset == range.length {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2150,30 +2202,41 @@ impl Vm {
|
||||
let mem = guest_memory.memory();
|
||||
|
||||
for range in ranges.regions() {
|
||||
mem.write_all_to(GuestAddress(range.gpa), fd, range.length as usize)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!(
|
||||
"Error transferring memory to socket: {}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
let mut offset: u64 = 0;
|
||||
// Here we are manually handling the retry in case we can't the
|
||||
// whole region at once because we can't use the implementation
|
||||
// from vm-memory::GuestMemory of write_all_to() as it is not
|
||||
// following the correct behavior. For more info about this issue
|
||||
// see: https://github.com/rust-vmm/vm-memory/issues/174
|
||||
loop {
|
||||
let bytes_written = mem
|
||||
.write_to(
|
||||
GuestAddress(range.gpa + offset),
|
||||
fd,
|
||||
(range.length - offset) as usize,
|
||||
)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!(
|
||||
"Error transferring memory to socket: {}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
offset += bytes_written as u64;
|
||||
|
||||
if offset == range.length {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn memory_range_table(&self) -> std::result::Result<MemoryRangeTable, MigratableError> {
|
||||
let mut table = MemoryRangeTable::default();
|
||||
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
|
||||
|
||||
for region in guest_memory.memory().iter() {
|
||||
table.push(MemoryRange {
|
||||
gpa: region.start_addr().raw_value(),
|
||||
length: region.len() as u64,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(table)
|
||||
self.memory_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
.memory_range_table(false)
|
||||
}
|
||||
|
||||
pub fn device_tree(&self) -> Arc<Mutex<DeviceTree>> {
|
||||
@@ -2209,6 +2272,10 @@ impl Vm {
|
||||
.notify_power_button()
|
||||
.map_err(Error::PowerButton)
|
||||
}
|
||||
|
||||
pub fn memory_manager_data(&self) -> MemoryManagerSnapshotData {
|
||||
self.memory_manager.lock().unwrap().snapshot_data()
|
||||
}
|
||||
}
|
||||
|
||||
impl Pausable for Vm {
|
||||
@@ -2312,11 +2379,7 @@ impl Snapshottable for Vm {
|
||||
let common_cpuid = {
|
||||
#[cfg(feature = "tdx")]
|
||||
let tdx_enabled = self.config.lock().unwrap().tdx.is_some();
|
||||
let phys_bits = physical_bits(
|
||||
self.config.lock().unwrap().cpus.max_phys_bits,
|
||||
#[cfg(feature = "tdx")]
|
||||
tdx_enabled,
|
||||
);
|
||||
let phys_bits = physical_bits(self.config.lock().unwrap().cpus.max_phys_bits);
|
||||
arch::generate_common_cpuid(
|
||||
self.hypervisor.clone(),
|
||||
None,
|
||||
@@ -2621,7 +2684,7 @@ mod tests {
|
||||
let gic = create_gic(&vm, 1).unwrap();
|
||||
assert!(create_fdt(
|
||||
&mem,
|
||||
&CString::new("console=tty0").unwrap(),
|
||||
"console=tty0",
|
||||
vec![0],
|
||||
Some((0, 0, 0)),
|
||||
&dev_info,
|
||||
@@ -2629,6 +2692,7 @@ mod tests {
|
||||
&None,
|
||||
&(0x1_0000_0000, 0x1_0000),
|
||||
&BTreeMap::new(),
|
||||
None,
|
||||
)
|
||||
.is_ok())
|
||||
}
|
||||
@@ -2638,7 +2702,7 @@ mod tests {
|
||||
#[test]
|
||||
pub fn test_vm() {
|
||||
use hypervisor::VmExit;
|
||||
use vm_memory::{GuestMemory, GuestMemoryRegion};
|
||||
use vm_memory::{Address, GuestMemory, GuestMemoryRegion};
|
||||
// This example based on https://lwn.net/Articles/658511/
|
||||
let code = [
|
||||
0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */
|
||||
|
||||
Reference in New Issue
Block a user