Compare commits

..

8 Commits
v25.0 ... v23.1

Author SHA1 Message Date
Rob Bradford
479fef1b8e build: Release v23.1 (bug fix release)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-09 14:54:18 +01:00
Bo Chen
fc8f867879 vmm: Add 'shutdown()' to vCPU seccomp filter
This is required when hot-removing a vfio-user device. Details code path
below:

Thread 6 "vcpu0" received signal SIGSYS, Bad system call.
[Switching to Thread 0x7f8196889700 (LWP 2358305)]
0x00007f8196dae7ab in shutdown () at ../sysdeps/unix/syscall-template.S:78
78	T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
(gdb) bt
  0x00007f8196dae7ab in shutdown () at ../sysdeps/unix/syscall-template.S:78
  0x000056189240737d in std::sys::unix::net::Socket::shutdown ()
    at library/std/src/sys/unix/net.rs:383
  std::os::unix::net::stream::UnixStream::shutdown () at library/std/src/os/unix/net/stream.rs:479
  0x000056189210e23d in vfio_user::Client::shutdown (self=0x7f8190014300)
    at vfio_user/src/lib.rs:787
  0x00005618920b9d02 in <pci::vfio_user::VfioUserPciDevice as core::ops::drop::Drop>::drop (
    self=0x7f819002d7c0) at pci/src/vfio_user.rs:551
  0x00005618920b8787 in core::ptr::drop_in_place<pci::vfio_user::VfioUserPciDevice> ()
    at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/ptr/mod.rs:188
  0x00005618920b92e3 in core::ptr::drop_in_place<core::cell::UnsafeCell<dyn pci::device::PciDevice>>
    () at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/ptr/mod.rs:188
  0x00005618920b9362 in core::ptr::drop_in_place<std::sync::mutex::Mutex<dyn pci::device::PciDevice>> () at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/ptr/mod.rs:188
  0x00005618920d8a3e in alloc::sync::Arc<T>::drop_slow (self=0x7f81968852b8)
    at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/alloc/src/sync.rs:1092
  0x00005618920ba273 in <alloc::sync::Arc<T> as core::ops::drop::Drop>::drop (self=0x7f81968852b8)
    at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/alloc/src/sync.rs:1688
 0x00005618920b76fb in core::ptr::drop_in_place<alloc::sync::Arc<std::sync::mutex::Mutex<dyn pci::device::PciDevice>>> ()
    at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/ptr/mod.rs:188
 0x0000561891b5e47d in vmm::device_manager::DeviceManager::eject_device (self=0x7f8190009600,
    pci_segment_id=0, device_id=3) at vmm/src/device_manager.rs:4000
 0x0000561891b674bc in <vmm::device_manager::DeviceManager as vm_device::bus::BusDevice>::write (
    self=0x7f8190009600, base=70368744108032, offset=8, data=&[u8](size=4) = {...})
    at vmm/src/device_manager.rs:4625
 0x00005618921927d5 in vm_device::bus::Bus::write (self=0x7f8190006e00, addr=70368744108040,
    data=&[u8](size=4) = {...}) at vm-device/src/bus.rs:235
 0x0000561891b72e10 in <vmm::vm::VmOps as hypervisor::vm::VmmOps>::mmio_write (
    self=0x7f81900097b0, gpa=70368744108040, data=&[u8](size=4) = {...}) at vmm/src/vm.rs:378
 0x0000561892133ae2 in <hypervisor::kvm::KvmVcpu as hypervisor::cpu::Vcpu>::run (
    self=0x7f8190013c90) at hypervisor/src/kvm/mod.rs:1114
 0x0000561891914e85 in vmm::cpu::Vcpu::run (self=0x7f819001b230) at vmm/src/cpu.rs:348
 0x000056189189f2cb in vmm::cpu::CpuManager::start_vcpu::{{closure}}::{{closure}} ()
    at vmm/src/cpu.rs:953

Signed-off-by: Bo Chen <chen.bo@intel.com>
(cherry picked from commit 42c19e14c5)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-09 14:54:18 +01:00
Sebastien Boeuf
e2eb59bcc8 vmm: Remove FsConfig from VmConfig when unplugging fs device
All hotpluggable devices were properly removed from the VmConfig when a
remove-device command was issued, except for the "fs" type. Fix this
lack of support as it is causing the integration tests to fail with the
recent addition of verifying that identifiers are unique.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
(cherry picked from commit a5a2e591c9)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-09 14:54:18 +01:00
LiHui
1e557fdb3c vmm: api: Do not delete the API socket on API server creation
The socket will safely deleted on shutdown and so it is not necessary to
delete the API socket when starting the HTTP server.

Fixes: #4026

Signed-off-by: LiHui <andrewli@kubesphere.io>
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
(cherry picked from commit ec0c1b01c4)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-09 14:54:18 +01:00
Rob Bradford
10ce348aa6 tests: Use different API sockets when restoring
This prevents a conflict since the old API socket will not have been
cleaned up (due to the use of SIGKILL.)

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
(cherry picked from commit 4fed2d4ed7)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-09 14:54:18 +01:00
Rob Bradford
63130d0f92 vmm: seccomp: Allow SYS_rseq as required by newer glibc
glibc 2.35 as shipped by Fedora 36 now uses the rseq syscall.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
(cherry picked from commit 4a04d1f8f2)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-09 14:54:18 +01:00
Rob Bradford
e6cc364703 virtio-devices: mem: Reject resize if device not activated by guest
If the guest has not activated the virtio-mem device then reject an
attempt to resize using it.

Fixes: #4001

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
(cherry picked from commit c274ce4d49)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-09 14:54:18 +01:00
Fabiano Fidêncio
a861918f06 docs: Fix the name of the I/O operations knobs
The I/O operations knobs are prefixed `ops_` rather than `bw_`, as `bw_`
refers to the "bandwidth" knobs.

Signed-off-by: Fabiano Fidêncio <fabiano.fidencio@intel.com>
(cherry picked from commit a87d1bbaa1)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-09 14:54:18 +01:00
145 changed files with 4464 additions and 7262 deletions

View File

@@ -13,7 +13,7 @@ jobs:
- stable - stable
- beta - beta
- nightly - nightly
- "1.60" - 1.56
target: target:
- x86_64-unknown-linux-gnu - x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl - x86_64-unknown-linux-musl
@@ -39,28 +39,25 @@ jobs:
git checkout $GITHUB_SHA git checkout $GITHUB_SHA
- name: Build (default features) - name: Build (default features)
run: cargo rustc --locked --bin cloud-hypervisor -- -D warnings run: cargo rustc --bin cloud-hypervisor -- -D warnings
- name: Build (common + kvm) - name: Build (common + kvm)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "common,kvm" -- -D warnings run: cargo rustc --bin cloud-hypervisor --no-default-features --features "common,kvm" -- -D warnings
- name: Build (default features + tdx) - name: Build (default features + tdx)
run: cargo rustc --locked --bin cloud-hypervisor --features "tdx" -- -D warnings run: cargo rustc --bin cloud-hypervisor --features "tdx" -- -D warnings
- name: Build (default features + amx) - name: Build (default features + amx)
run: cargo rustc --locked --bin cloud-hypervisor --features "amx" -- -D warnings run: cargo rustc --bin cloud-hypervisor --features "amx" -- -D warnings
- name: Build (default features + gdb) - name: Build (default features + gdb)
run: cargo rustc --locked --bin cloud-hypervisor --features "gdb" -- -D warnings run: cargo rustc --bin cloud-hypervisor --features "gdb" -- -D warnings
- name: Build (default features + guest_debug)
run: cargo rustc --locked --bin cloud-hypervisor --features "guest_debug" -- -D warnings
- name: Build (common + mshv) - name: Build (common + mshv)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "common,mshv" -- -D warnings run: cargo rustc --bin cloud-hypervisor --no-default-features --features "common,mshv" -- -D warnings
- name: Release Build (default features) - name: Release Build (default features)
run: cargo build --locked --all --release --target=${{ matrix.target }} run: cargo build --all --release --target=${{ matrix.target }}
- name: Check build did not modify any files - name: Check build did not modify any files
run: test -z "$(git status --porcelain)" run: test -z "$(git status --porcelain)"

View File

@@ -34,22 +34,19 @@ jobs:
run: cargo fmt -- --check run: cargo fmt -- --check
- name: Clippy (common + kvm) - name: Clippy (common + kvm)
run: cargo clippy --locked --all --all-targets --no-default-features --tests --features "common,kvm" -- -D warnings run: cargo clippy --all --all-targets --no-default-features --tests --features "common,kvm" -- -D warnings
- name: Clippy (default features) - name: Clippy (default features)
run: cargo clippy --locked --all --all-targets --tests -- -D warnings run: cargo clippy --all --all-targets --tests -- -D warnings
- name: Clippy (default features + amx) - name: Clippy (default features + amx)
run: cargo clippy --locked --all --all-targets --tests --features "amx" -- -D warnings run: cargo clippy --all --all-targets --tests --features "amx" -- -D warnings
- name: Clippy (default features + gdb) - name: Clippy (default features + gdb)
run: cargo clippy --locked --all --all-targets --tests --features "gdb" -- -D warnings run: cargo clippy --all --all-targets --tests --features "gdb" -- -D warnings
- name: Clippy (default features + guest_debug)
run: cargo clippy --locked --all --all-targets --tests --features "guest_debug" -- -D warnings
- name: Clippy (common + mshv) - name: Clippy (common + mshv)
run: cargo clippy --locked --all --all-targets --no-default-features --tests --features "common,mshv" -- -D warnings run: cargo clippy --all --all-targets --no-default-features --tests --features "common,mshv" -- -D warnings
- name: Check build did not modify any files - name: Check build did not modify any files
run: test -z "$(git status --porcelain)" run: test -z "$(git status --porcelain)"

View File

@@ -16,23 +16,23 @@ jobs:
- name: Install Rust toolchain (x86_64-unknown-linux-gnu) - name: Install Rust toolchain (x86_64-unknown-linux-gnu)
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: "1.62" toolchain: 1.58
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
- name: Install Rust toolchain (x86_64-unknown-linux-musl) - name: Install Rust toolchain (x86_64-unknown-linux-musl)
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: "1.62" toolchain: 1.58
target: x86_64-unknown-linux-musl target: x86_64-unknown-linux-musl
- name: Build - name: Build
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
toolchain: "1.62" toolchain: 1.58
command: build command: build
args: --all --release --target=x86_64-unknown-linux-gnu args: --all --release --target=x86_64-unknown-linux-gnu
- name: Static Build - name: Static Build
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
toolchain: "1.62" toolchain: 1.58
command: build command: build
args: --all --release --target=x86_64-unknown-linux-musl args: --all --release --target=x86_64-unknown-linux-musl
- name: Strip cloud-hypervisor binaries - name: Strip cloud-hypervisor binaries
@@ -40,7 +40,7 @@ jobs:
- name: Install Rust toolchain (aarch64-unknown-linux-musl) - name: Install Rust toolchain (aarch64-unknown-linux-musl)
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: "1.62" toolchain: 1.58
target: aarch64-unknown-linux-musl target: aarch64-unknown-linux-musl
override: true override: true
- name: Static Build (AArch64) - name: Static Build (AArch64)

1
.gitignore vendored
View File

@@ -4,4 +4,3 @@
**/*.rs.bk **/*.rs.bk
**/Cargo.lock **/Cargo.lock
**/rusty-tags.vi **/rusty-tags.vi
/rpm/SOURCES

View File

@@ -1,2 +0,0 @@
# Add the list of code owners here (using their GitHub username)
* @cloud-hypervisor/cloud-hypervisor-reviewers

View File

@@ -2,14 +2,12 @@
Cloud Hypervisor is an open source project licensed under the [Apache v2 Cloud Hypervisor is an open source project licensed under the [Apache v2
License](https://opensource.org/licenses/Apache-2.0) and the [BSD 3 License](https://opensource.org/licenses/Apache-2.0) and the [BSD 3
Clause](https://opensource.org/licenses/BSD-3-Clause) license. Individual files Clause](https://opensource.org/licenses/BSD-3-Clause) license. Contributions
contain details of their licensing and changes to that file are under the same can be made under either license or both. Individual files contain details of
license unless the contribution changes the license of the file. When importing their licensing and changes to that file are under the same license unless the
code from a third party project (e.g. Firecracker or CrosVM) please respect the contribution changes the license of the file. When importing code from a third
license of those projects. party project (e.g. Firecracker or CrosVM) please respect the license of those
projects.
New code should be under the [Apache v2
License](https://opensource.org/licenses/Apache-2.0).
## Coding Style ## Coding Style
@@ -65,9 +63,11 @@ you want to merge your changes to `cloud-hypervisor`:
2. Within your fork, create a branch for your contribution. 2. Within your fork, create a branch for your contribution.
3. [Create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) 3. [Create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)
against the main branch of the Cloud Hypervisor repository. against the main branch of the Cloud Hypervisor repository.
4. To update your pull request amend existing commits whenever applicable and 4. Add reviewers to your pull request and then work with your reviewers to address
any comments and obtain minimum of 2 [maintainers](MAINTAINERS.md) approvals.
To update your pull request amend existing commits whenever applicable and
then push the new changes to your pull request branch. then push the new changes to your pull request branch.
5. Once the pull request is approved it can be integrated. 5. Once the pull request is approved, one of the maintainers will merge it.
## Issue tracking ## Issue tracking

262
Cargo.lock generated
View File

@@ -20,9 +20,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.58" version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
[[package]] [[package]]
name = "api_client" name = "api_client"
@@ -50,6 +50,7 @@ dependencies = [
"linux-loader", "linux-loader",
"log", "log",
"serde", "serde",
"serde_derive",
"thiserror", "thiserror",
"versionize", "versionize",
"versionize_derive", "versionize_derive",
@@ -130,33 +131,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.2.8" version = "3.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83" checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
dependencies = [ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
"clap_lex",
"indexmap", "indexmap",
"once_cell", "lazy_static",
"os_str_bytes",
"strsim", "strsim",
"termcolor", "termcolor",
"terminal_size", "terminal_size",
"textwrap", "textwrap",
] ]
[[package]]
name = "clap_lex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
[[package]] [[package]]
name = "cloud-hypervisor" name = "cloud-hypervisor"
version = "25.0.0" version = "23.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"api_client", "api_client",
@@ -165,10 +157,10 @@ dependencies = [
"epoll", "epoll",
"event_monitor", "event_monitor",
"hypervisor", "hypervisor",
"lazy_static",
"libc", "libc",
"log", "log",
"net_util", "net_util",
"once_cell",
"option_parser", "option_parser",
"seccompiler", "seccompiler",
"serde_json", "serde_json",
@@ -206,7 +198,6 @@ dependencies = [
"bitflags", "bitflags",
"byteorder", "byteorder",
"epoll", "epoll",
"hypervisor",
"libc", "libc",
"log", "log",
"versionize", "versionize",
@@ -266,6 +257,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"libc", "libc",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
] ]
@@ -277,9 +269,9 @@ checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
[[package]] [[package]]
name = "gdbstub" name = "gdbstub"
version = "0.6.2" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c1f9371c87c11642ee94dcf92cb48b1484ba250b8e8bff3df71c28651f3f4e7" checksum = "9fa2ca5d6b045de372cef3991f873389b421b4cabcfbe52f7787fae8b8b37906"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if", "cfg-if",
@@ -291,9 +283,9 @@ dependencies = [
[[package]] [[package]]
name = "gdbstub_arch" name = "gdbstub_arch"
version = "0.2.3" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c24f469ba9556c5a063d6df35a8a338025fccf96ecae44f330a156b686f7a268" checksum = "51dc4b5718ac76d21e8605c0966dd32d80273b89b11e6cfef467b04e45934d37"
dependencies = [ dependencies = [
"gdbstub", "gdbstub",
"num-traits", "num-traits",
@@ -301,9 +293,9 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.7" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@@ -318,9 +310,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.12.1" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
@@ -352,6 +344,7 @@ dependencies = [
"mshv-bindings", "mshv-bindings",
"mshv-ioctls", "mshv-ioctls",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
"thiserror", "thiserror",
"vm-memory", "vm-memory",
@@ -370,9 +363,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.9.1" version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@@ -399,18 +392,18 @@ dependencies = [
[[package]] [[package]]
name = "ipnetwork" name = "ipnetwork"
version = "0.19.0" version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f84f1612606f3753f205a4e9a2efd6fe5b4c573a6269b2cc6c3003d44a0d127" checksum = "4088d739b183546b239688ddbc79891831df421773df95e236daf7867866d355"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.2" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]] [[package]]
name = "kvm-bindings" name = "kvm-bindings"
@@ -425,7 +418,7 @@ dependencies = [
[[package]] [[package]]
name = "kvm-ioctls" name = "kvm-ioctls"
version = "0.11.0" version = "0.11.0"
source = "git+https://github.com/rust-vmm/kvm-ioctls?branch=main#ccf0bda07485b2433616de998c000aa5f04ce806" source = "git+https://github.com/rust-vmm/kvm-ioctls?branch=main#1e03e29cdfbb0cb108a98de7a78045a5a517f18e"
dependencies = [ dependencies = [
"kvm-bindings", "kvm-bindings",
"libc", "libc",
@@ -440,9 +433,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.126" version = "0.2.123"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd"
[[package]] [[package]]
name = "libssh2-sys" name = "libssh2-sys"
@@ -460,9 +453,9 @@ dependencies = [
[[package]] [[package]]
name = "libz-sys" name = "libz-sys"
version = "1.1.8" version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" checksum = "6f35facd4a5673cb5a48822be2be1d4236c1c99cb4113cab7061ac720d5bf859"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@@ -491,9 +484,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.17" version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@@ -506,14 +499,14 @@ checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.5.0" version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]] [[package]]
name = "micro_http" name = "micro_http"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#863b0370ba7e57f7df5b908ada9e5b44809ccae9" source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#a730d86940081ad044cdfbc1285c1db6d3048392"
dependencies = [ dependencies = [
"libc", "libc",
"vmm-sys-util", "vmm-sys-util",
@@ -522,7 +515,7 @@ dependencies = [
[[package]] [[package]]
name = "mshv-bindings" name = "mshv-bindings"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rust-vmm/mshv?branch=main#7ac1b80bff7220171c9a626b23b51620ca774468" source = "git+https://github.com/rust-vmm/mshv?branch=main#75cf309d566c3d9ba91e81582a7864032ecc5bbb"
dependencies = [ dependencies = [
"libc", "libc",
"serde", "serde",
@@ -534,7 +527,7 @@ dependencies = [
[[package]] [[package]]
name = "mshv-ioctls" name = "mshv-ioctls"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rust-vmm/mshv?branch=main#7ac1b80bff7220171c9a626b23b51620ca774468" source = "git+https://github.com/rust-vmm/mshv?branch=main#75cf309d566c3d9ba91e81582a7864032ecc5bbb"
dependencies = [ dependencies = [
"libc", "libc",
"mshv-bindings", "mshv-bindings",
@@ -554,12 +547,11 @@ version = "0.1.0"
dependencies = [ dependencies = [
"epoll", "epoll",
"getrandom", "getrandom",
"lazy_static",
"libc", "libc",
"log", "log",
"net_gen", "net_gen",
"once_cell",
"pnet", "pnet",
"pnet_datalink",
"rate_limiter", "rate_limiter",
"serde", "serde",
"serde_json", "serde_json",
@@ -572,41 +564,29 @@ dependencies = [
"vmm-sys-util", "vmm-sys-util",
] ]
[[package]]
name = "no-std-net"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65"
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.15" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "once_cell"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
[[package]] [[package]]
name = "openssl-src" name = "openssl-src"
version = "111.22.0+1.1.1q" version = "111.18.0+1.1.1n"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f31f0d509d1c1ae9cada2f9539ff8f37933831fd5098879e482aa687d659853" checksum = "7897a926e1e8d00219127dc020130eca4292e5ca666dd592480d72c3eca2ff6c"
dependencies = [ dependencies = [
"cc", "cc",
] ]
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.74" version = "0.9.72"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cc", "cc",
@@ -622,9 +602,12 @@ version = "0.1.0"
[[package]] [[package]]
name = "os_str_bytes" name = "os_str_bytes"
version = "6.1.0" version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
@@ -667,6 +650,7 @@ dependencies = [
"libc", "libc",
"log", "log",
"serde", "serde",
"serde_derive",
"thiserror", "thiserror",
"versionize", "versionize",
"versionize_derive", "versionize_derive",
@@ -687,6 +671,7 @@ dependencies = [
"clap", "clap",
"dirs", "dirs",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
"test_infra", "test_infra",
"thiserror", "thiserror",
@@ -701,30 +686,29 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]] [[package]]
name = "pnet" name = "pnet"
version = "0.31.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0caaf5b11fd907ff15cf14a4477bfabca4b37ab9e447a4f8dead969a59cdafad" checksum = "8750e073f82219c01e771133c64718d7685aef922da8a0d430a46aed05b6341a"
dependencies = [ dependencies = [
"ipnetwork",
"pnet_base", "pnet_base",
"pnet_datalink", "pnet_datalink",
"pnet_packet", "pnet_packet",
"pnet_sys",
"pnet_transport", "pnet_transport",
] ]
[[package]] [[package]]
name = "pnet_base" name = "pnet_base"
version = "0.31.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d3a993d49e5fd5d4d854d6999d4addca1f72d86c65adf224a36757161c02b6" checksum = "8205fe084bd43a3af79b3155c19feddd62e733640498842e631a2ffe107d1538"
dependencies = [
"no-std-net",
]
[[package]] [[package]]
name = "pnet_datalink" name = "pnet_datalink"
version = "0.31.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e466faf03a98ad27f6e15cd27a2b7cc89e73e640a43527742977bc503c37f8aa" checksum = "6f85aef5e52e22ff06b1b11f2eb6d52959a9e0ecad3cb3f5cc2d78cadc077f0e"
dependencies = [ dependencies = [
"ipnetwork", "ipnetwork",
"libc", "libc",
@@ -735,9 +719,9 @@ dependencies = [
[[package]] [[package]]
name = "pnet_macros" name = "pnet_macros"
version = "0.31.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48dd52a5211fac27e7acb14cfc9f30ae16ae0e956b7b779c8214c74559cef4c3" checksum = "98cc3af95fed6dc318dfede3e81320f96ad5e237c6f7c4688108b19c8e67432d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -747,18 +731,18 @@ dependencies = [
[[package]] [[package]]
name = "pnet_macros_support" name = "pnet_macros_support"
version = "0.31.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89de095dc7739349559913aed1ef6a11e73ceade4897dadc77c5e09de6740750" checksum = "feaba58ba96abb218ec584d6caf0d3ff48922df05dbbeb1560553c197091b29e"
dependencies = [ dependencies = [
"pnet_base", "pnet_base",
] ]
[[package]] [[package]]
name = "pnet_packet" name = "pnet_packet"
version = "0.31.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc3b5111e697c39c8b9795b9fdccbc301ab696699e88b9ea5a4e4628978f495f" checksum = "f246edaaf1aaf82072d4cd38ee18bcc5dfc0464093f9ca39e4ac5962d68cf9d4"
dependencies = [ dependencies = [
"glob", "glob",
"pnet_base", "pnet_base",
@@ -768,9 +752,9 @@ dependencies = [
[[package]] [[package]]
name = "pnet_sys" name = "pnet_sys"
version = "0.31.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "328e231f0add6d247d82421bf3790b4b33b39c8930637f428eef24c4c6a90805" checksum = "028c87a5e3a48fc07df099a2025f2ef16add5993712e1494ba69a6707ee7ed06"
dependencies = [ dependencies = [
"libc", "libc",
"winapi", "winapi",
@@ -778,9 +762,9 @@ dependencies = [
[[package]] [[package]]
name = "pnet_transport" name = "pnet_transport"
version = "0.31.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff597185e6f1f5671b3122e4dba892a1c73e17c17e723d7669bd9299cbe7f124" checksum = "950f2a7961e19d22e19e84ff0a6e0955013185fe149673499662633d02b41b7a"
dependencies = [ dependencies = [
"libc", "libc",
"pnet_base", "pnet_base",
@@ -790,11 +774,11 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.40" version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
dependencies = [ dependencies = [
"unicode-ident", "unicode-xid",
] ]
[[package]] [[package]]
@@ -810,9 +794,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.20" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -848,9 +832,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.6.0" version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -859,15 +843,15 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.27" version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]] [[package]]
name = "remain" name = "remain"
version = "0.2.3" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c35270ea384ac1762895831cc8acb96f171468e52cec82ed9186f9416209fa4" checksum = "70ba1e78fa68412cb93ef642fd4d20b9a941be49ee9333875ebaf13112673ea7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -885,9 +869,9 @@ dependencies = [
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.10" version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
@@ -906,24 +890,21 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.12" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.138" version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.138" version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -932,9 +913,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.82" version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@@ -943,9 +924,9 @@ dependencies = [
[[package]] [[package]]
name = "signal-hook" name = "signal-hook"
version = "0.3.14" version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
dependencies = [ dependencies = [
"libc", "libc",
"signal-hook-registry", "signal-hook-registry",
@@ -962,9 +943,9 @@ dependencies = [
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.9.0" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
[[package]] [[package]]
name = "ssh2" name = "ssh2"
@@ -992,13 +973,13 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.98" version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"unicode-ident", "unicode-xid",
] ]
[[package]] [[package]]
@@ -1038,8 +1019,8 @@ version = "0.1.0"
dependencies = [ dependencies = [
"dirs", "dirs",
"epoll", "epoll",
"lazy_static",
"libc", "libc",
"once_cell",
"ssh2", "ssh2",
"vmm-sys-util", "vmm-sys-util",
"wait-timeout", "wait-timeout",
@@ -1056,41 +1037,35 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.31" version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.31" version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
] ]
[[package]]
name = "unicode-ident"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.3" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.1.2" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [ dependencies = [
"getrandom", "getrandom",
] ]
@@ -1140,7 +1115,7 @@ dependencies = [
[[package]] [[package]]
name = "vfio-ioctls" name = "vfio-ioctls"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#38272d3f06bbc0b4b3cfa3f5da07fd1c1c89e4d1" source = "git+https://github.com/rust-vmm/vfio?branch=main#f75a77c1ab6349c105bc1462a65508726b4c2e0f"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"kvm-bindings", "kvm-bindings",
@@ -1199,9 +1174,9 @@ dependencies = [
[[package]] [[package]]
name = "vhost-user-backend" name = "vhost-user-backend"
version = "0.5.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eeb6723bbee20dbc2db95c575941922fb96e77eb41786ecd1c8c03348709c4c" checksum = "1490f2028d4f119b2292efe218b5f8cfc6471f039b53b6a6eb5d9513e964facc"
dependencies = [ dependencies = [
"libc", "libc",
"log", "log",
@@ -1274,6 +1249,7 @@ dependencies = [
"rate_limiter", "rate_limiter",
"seccompiler", "seccompiler",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
"thiserror", "thiserror",
"versionize", "versionize",
@@ -1291,9 +1267,9 @@ dependencies = [
[[package]] [[package]]
name = "virtio-queue" name = "virtio-queue"
version = "0.4.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "519c0a333c871650269cba303bc108075d52a0c0d64f9b91fae61829b53725af" checksum = "3785325315e6496fa88673842ee6cd198b9658e88e8b0e1ad48a5dc818b221dc"
dependencies = [ dependencies = [
"log", "log",
"vm-memory", "vm-memory",
@@ -1314,8 +1290,8 @@ name = "vm-device"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"hypervisor",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
"thiserror", "thiserror",
"vfio-ioctls", "vfio-ioctls",
@@ -1330,9 +1306,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#ca35d96191f8232bd7a
[[package]] [[package]]
name = "vm-memory" name = "vm-memory"
version = "0.8.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "767ed8aaebbff902e02e6d3749dc2baef55e46565f8a6414a065e5baee4b4a81" checksum = "339d4349c126fdcd87e034631d7274370cf19eb0e87b33166bcd956589fc72c5"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"libc", "libc",
@@ -1345,6 +1321,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
"thiserror", "thiserror",
"versionize", "versionize",
@@ -1379,17 +1356,18 @@ dependencies = [
"gdbstub", "gdbstub",
"gdbstub_arch", "gdbstub_arch",
"hypervisor", "hypervisor",
"lazy_static",
"libc", "libc",
"linux-loader", "linux-loader",
"log", "log",
"micro_http", "micro_http",
"net_util", "net_util",
"once_cell",
"option_parser", "option_parser",
"pci", "pci",
"qcow", "qcow",
"seccompiler", "seccompiler",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
"signal-hook", "signal-hook",
"thiserror", "thiserror",
@@ -1432,9 +1410,9 @@ dependencies = [
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]] [[package]]
name = "winapi" name = "winapi"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "cloud-hypervisor" name = "cloud-hypervisor"
version = "25.0.0" version = "23.1.0"
authors = ["The Cloud Hypervisor Authors"] authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
default-run = "cloud-hypervisor" default-run = "cloud-hypervisor"
@@ -10,31 +10,31 @@ description = "Open source Virtual Machine Monitor (VMM) that runs on top of KVM
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor" homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
# Minimum buildable version: # Minimum buildable version:
# Keep in sync with version in .github/workflows/build.yaml # Keep in sync with version in .github/workflows/build.yaml
rust-version = "1.60" rust-version = "1.56"
[profile.release] [profile.release]
lto = true lto = true
[dependencies] [dependencies]
anyhow = "1.0.58" anyhow = "1.0.56"
api_client = { path = "api_client" } api_client = { path = "api_client" }
clap = { version = "3.2.8", features = ["wrap_help","cargo"] } clap = { version = "3.1.8", features = ["wrap_help","cargo"] }
epoll = "4.3.1" epoll = "4.3.1"
event_monitor = { path = "event_monitor" } event_monitor = { path = "event_monitor" }
hypervisor = { path = "hypervisor" } hypervisor = { path = "hypervisor" }
libc = "0.2.126" libc = "0.2.123"
log = { version = "0.4.17", features = ["std"] } log = { version = "0.4.16", features = ["std"] }
option_parser = { path = "option_parser" } option_parser = { path = "option_parser" }
seccompiler = "0.2.0" seccompiler = "0.2.0"
serde_json = "1.0.82" serde_json = "1.0.79"
signal-hook = "0.3.14" signal-hook = "0.3.13"
thiserror = "1.0.31" thiserror = "1.0.30"
vmm = { path = "vmm" } vmm = { path = "vmm" }
vmm-sys-util = "0.9.0" vmm-sys-util = "0.9.0"
vm-memory = "0.8.0" vm-memory = "0.7.0"
[build-dependencies] [build-dependencies]
clap = { version = "3.2.8", features = ["cargo"] } clap = { version = "3.1.8", features = ["cargo"] }
# List of patched crates # List of patched crates
[patch.crates-io] [patch.crates-io]
@@ -44,9 +44,9 @@ versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_deri
[dev-dependencies] [dev-dependencies]
dirs = "4.0.0" dirs = "4.0.0"
lazy_static= "1.4.0"
net_util = { path = "net_util" } net_util = { path = "net_util" }
once_cell = "1.13.0" serde_json = "1.0.79"
serde_json = "1.0.82"
test_infra = { path = "test_infra" } test_infra = { path = "test_infra" }
wait-timeout = "0.2.0" wait-timeout = "0.2.0"
@@ -58,7 +58,6 @@ amx = ["vmm/amx"]
cmos = ["vmm/cmos"] cmos = ["vmm/cmos"]
fwdebug = ["vmm/fwdebug"] fwdebug = ["vmm/fwdebug"]
gdb = ["vmm/gdb"] gdb = ["vmm/gdb"]
guest_debug = ["vmm/guest_debug"]
kvm = ["vmm/kvm"] kvm = ["vmm/kvm"]
mshv = ["vmm/mshv"] mshv = ["vmm/mshv"]
tdx = ["vmm/tdx"] tdx = ["vmm/tdx"]

24
Jenkinsfile vendored
View File

@@ -23,19 +23,6 @@ pipeline{
} }
} }
} }
stage ('Check for fuzzer cargo files only changes') {
when {
expression {
return fuzzCargoFileOnly()
}
}
steps {
script {
runWorkers = false
echo "Fuzzer cargo files only changes, no need to run the CI"
}
}
}
stage ('Check for RFC/WIP builds') { stage ('Check for RFC/WIP builds') {
when { when {
changeRequest comparator: 'REGEXP', title: '.*(rfc|RFC|wip|WIP).*' changeRequest comparator: 'REGEXP', title: '.*(rfc|RFC|wip|WIP).*'
@@ -415,14 +402,3 @@ def boolean docsFileOnly() {
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v '\\.md'" script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v '\\.md'"
) != 0 ) != 0
} }
def boolean fuzzCargoFileOnly() {
if (env.CHANGE_TARGET == null) {
return false;
}
return sh(
returnStatus: true,
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v -E 'fuzz\\/Cargo.(toml|lock)'"
) != 0
}

View File

@@ -88,10 +88,12 @@ Hypervisor. Here, all the steps are based on Ubuntu, for other Linux
distributions please replace the package manager and package name. distributions please replace the package manager and package name.
```shell ```shell
# Install build-essential, git, and qemu-img # Install git
$ sudo apt install git build-essential qemu-img $ sudo apt install git
# Install rust tool chain # Install rust tool chain
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh $ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Install build-essential
$ sudo apt install build-essential
# If you want to build statically linked binary please add musl target # If you want to build statically linked binary please add musl target
$ rustup target add x86_64-unknown-linux-musl $ rustup target add x86_64-unknown-linux-musl
``` ```
@@ -166,7 +168,7 @@ cloud image. Here we will use a Ubuntu image:
$ pushd $CLOUDH $ pushd $CLOUDH
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img $ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-server-cloudimg-amd64.raw $ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-server-cloudimg-amd64.raw
$ wget https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/download/0.4.0/hypervisor-fw $ wget https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/download/0.3.2/hypervisor-fw
$ popd $ popd
``` ```
@@ -289,8 +291,6 @@ As of 2022-04-05, the following cloud images are supported:
Direct kernel boot to userspace should work with a rootfs from most Direct kernel boot to userspace should work with a rootfs from most
distributions. distributions.
Further details can be found in the [release documentation](docs/releases.md).
## Hot Plug ## Hot Plug
Cloud Hypervisor supports hotplug of CPUs, passthrough devices (VFIO), Cloud Hypervisor supports hotplug of CPUs, passthrough devices (VFIO),

View File

@@ -5,4 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
vm-memory = "0.8.0" vm-memory = "0.7.0"

View File

@@ -68,7 +68,7 @@ impl Aml for Path {
}; };
for part in self.name_parts.clone().iter_mut() { for part in self.name_parts.clone().iter_mut() {
bytes.extend_from_slice(part.as_ref()); bytes.extend_from_slice(&part.to_vec());
} }
} }
} }

View File

@@ -10,17 +10,18 @@ tdx = []
[dependencies] [dependencies]
acpi_tables = { path = "../acpi_tables" } acpi_tables = { path = "../acpi_tables" }
anyhow = "1.0.58" anyhow = "1.0.56"
byteorder = "1.4.3" byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
libc = "0.2.126" libc = "0.2.123"
linux-loader = { version = "0.4.0", features = ["elf", "bzimage", "pe"] } linux-loader = { version = "0.4.0", features = ["elf", "bzimage", "pe"] }
log = "0.4.17" log = "0.4.16"
serde = { version = "1.0.138", features = ["rc", "derive"] } serde = { version = "1.0.136", features = ["rc"] }
thiserror = "1.0.31" serde_derive = "1.0.136"
thiserror = "1.0.30"
versionize = "0.1.6" versionize = "0.1.6"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-bitmap"] } vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-bitmap"] }
vm-migration = { path = "../vm-migration" } vm-migration = { path = "../vm-migration" }
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] } vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }

View File

@@ -8,18 +8,17 @@
use crate::{NumaNodes, PciSpaceInfo}; use crate::{NumaNodes, PciSpaceInfo};
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
use hypervisor::arch::aarch64::gic::Vgic;
use std::cmp; use std::cmp;
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::CStr; use std::ffi::CStr;
use std::fmt::Debug; use std::fmt::Debug;
use std::result; use std::result;
use std::str; use std::str;
use std::sync::{Arc, Mutex};
use super::super::DeviceType; use super::super::DeviceType;
use super::super::GuestMemoryMmap; use super::super::GuestMemoryMmap;
use super::super::InitramfsConfig; use super::super::InitramfsConfig;
use super::gic::GicDevice;
use super::layout::{ use super::layout::{
IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START, IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START,
PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT, PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
@@ -91,7 +90,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
vcpu_mpidr: Vec<u64>, vcpu_mpidr: Vec<u64>,
vcpu_topology: Option<(u8, u8, u8)>, vcpu_topology: Option<(u8, u8, u8)>,
device_info: &HashMap<(DeviceType, String), T, S>, device_info: &HashMap<(DeviceType, String), T, S>,
gic_device: &Arc<Mutex<dyn Vgic>>, gic_device: &dyn GicDevice,
initrd: &Option<InitramfsConfig>, initrd: &Option<InitramfsConfig>,
pci_space_info: &[PciSpaceInfo], pci_space_info: &[PciSpaceInfo],
numa_nodes: &NumaNodes, numa_nodes: &NumaNodes,
@@ -316,18 +315,18 @@ fn create_chosen_node(
Ok(()) Ok(())
} }
fn create_gic_node(fdt: &mut FdtWriter, gic_device: &Arc<Mutex<dyn Vgic>>) -> FdtWriterResult<()> { fn create_gic_node(fdt: &mut FdtWriter, gic_device: &dyn GicDevice) -> FdtWriterResult<()> {
let gic_reg_prop = gic_device.lock().unwrap().device_properties(); let gic_reg_prop = gic_device.device_properties();
let intc_node = fdt.begin_node("intc")?; let intc_node = fdt.begin_node("intc")?;
fdt.property_string("compatible", gic_device.lock().unwrap().fdt_compatibility())?; fdt.property_string("compatible", gic_device.fdt_compatibility())?;
fdt.property_null("interrupt-controller")?; fdt.property_null("interrupt-controller")?;
// "interrupt-cells" field specifies the number of cells needed to encode an // "interrupt-cells" field specifies the number of cells needed to encode an
// interrupt source. The type shall be a <u32> and the value shall be 3 if no PPI affinity description // interrupt source. The type shall be a <u32> and the value shall be 3 if no PPI affinity description
// is required. // is required.
fdt.property_u32("#interrupt-cells", 3)?; fdt.property_u32("#interrupt-cells", 3)?;
fdt.property_array_u64("reg", &gic_reg_prop)?; fdt.property_array_u64("reg", gic_reg_prop)?;
fdt.property_u32("phandle", GIC_PHANDLE)?; fdt.property_u32("phandle", GIC_PHANDLE)?;
fdt.property_u32("#address-cells", 2)?; fdt.property_u32("#address-cells", 2)?;
fdt.property_u32("#size-cells", 2)?; fdt.property_u32("#size-cells", 2)?;
@@ -335,18 +334,18 @@ fn create_gic_node(fdt: &mut FdtWriter, gic_device: &Arc<Mutex<dyn Vgic>>) -> Fd
let gic_intr_prop = [ let gic_intr_prop = [
GIC_FDT_IRQ_TYPE_PPI, GIC_FDT_IRQ_TYPE_PPI,
gic_device.lock().unwrap().fdt_maint_irq(), gic_device.fdt_maint_irq(),
IRQ_TYPE_LEVEL_HI, IRQ_TYPE_LEVEL_HI,
]; ];
fdt.property_array_u32("interrupts", &gic_intr_prop)?; fdt.property_array_u32("interrupts", &gic_intr_prop)?;
if gic_device.lock().unwrap().msi_compatible() { if gic_device.msi_compatible() {
let msic_node = fdt.begin_node("msic")?; let msic_node = fdt.begin_node("msic")?;
fdt.property_string("compatible", gic_device.lock().unwrap().msi_compatibility())?; fdt.property_string("compatible", gic_device.msi_compatibility())?;
fdt.property_null("msi-controller")?; fdt.property_null("msi-controller")?;
fdt.property_u32("phandle", MSI_PHANDLE)?; fdt.property_u32("phandle", MSI_PHANDLE)?;
let msi_reg_prop = gic_device.lock().unwrap().msi_properties(); let msi_reg_prop = gic_device.msi_properties();
fdt.property_array_u64("reg", &msi_reg_prop)?; fdt.property_array_u64("reg", msi_reg_prop)?;
fdt.end_node(msic_node)?; fdt.end_node(msic_node)?;
} }

View File

@@ -1,11 +1,11 @@
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::arch::aarch64::gic::{Error, Result}; use super::{Error, Result};
use crate::kvm::kvm_bindings::{ use crate::layout::IRQ_BASE;
use hypervisor::kvm::kvm_bindings::{
kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
}; };
use crate::Device;
use std::sync::Arc; use std::sync::Arc;
/* /*
@@ -77,7 +77,12 @@ static VGIC_DIST_REGS: &[DistReg] = &[
VGIC_DIST_REG!(GICD_IPRIORITYR, 8, 0), VGIC_DIST_REG!(GICD_IPRIORITYR, 8, 0),
]; ];
fn dist_attr_access(gic: &Arc<dyn Device>, offset: u32, val: &u32, set: bool) -> Result<()> { fn dist_attr_access(
gic: &Arc<dyn hypervisor::Device>,
offset: u32,
val: &u32,
set: bool,
) -> Result<()> {
let mut gic_dist_attr = kvm_device_attr { let mut gic_dist_attr = kvm_device_attr {
group: KVM_DEV_ARM_VGIC_GRP_DIST_REGS, group: KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
attr: offset as u64, attr: offset as u64,
@@ -95,18 +100,18 @@ fn dist_attr_access(gic: &Arc<dyn Device>, offset: u32, val: &u32, set: bool) ->
} }
/// Get the distributor control register. /// Get the distributor control register.
pub fn read_ctlr(gic: &Arc<dyn Device>) -> Result<u32> { pub fn read_ctlr(gic: &Arc<dyn hypervisor::Device>) -> Result<u32> {
let val: u32 = 0; let val: u32 = 0;
dist_attr_access(gic, GICD_CTLR, &val, false)?; dist_attr_access(gic, GICD_CTLR, &val, false)?;
Ok(val) Ok(val)
} }
/// Set the distributor control register. /// Set the distributor control register.
pub fn write_ctlr(gic: &Arc<dyn Device>, val: u32) -> Result<()> { pub fn write_ctlr(gic: &Arc<dyn hypervisor::Device>, val: u32) -> Result<()> {
dist_attr_access(gic, GICD_CTLR, &val, true) dist_attr_access(gic, GICD_CTLR, &val, true)
} }
fn get_interrupts_num(gic: &Arc<dyn Device>) -> Result<u32> { fn get_interrupts_num(gic: &Arc<dyn hypervisor::Device>) -> Result<u32> {
let num_irq = 0; let num_irq = 0;
let mut nr_irqs_attr = kvm_device_attr { let mut nr_irqs_attr = kvm_device_attr {
@@ -120,12 +125,7 @@ fn get_interrupts_num(gic: &Arc<dyn Device>) -> Result<u32> {
Ok(num_irq) Ok(num_irq)
} }
fn compute_reg_len(gic: &Arc<dyn Device>, reg: &DistReg, base: u32) -> Result<u32> { fn compute_reg_len(gic: &Arc<dyn hypervisor::Device>, reg: &DistReg, base: u32) -> Result<u32> {
// FIXME:
// Redefine some GIC constants to avoid the dependency on `layout` crate.
// This is temporary solution, will be fixed in future refactoring.
const LAYOUT_IRQ_BASE: u32 = 32;
let mut end = base; let mut end = base;
let num_irq = get_interrupts_num(gic)?; let num_irq = get_interrupts_num(gic)?;
if reg.length > 0 { if reg.length > 0 {
@@ -138,8 +138,8 @@ fn compute_reg_len(gic: &Arc<dyn Device>, reg: &DistReg, base: u32) -> Result<u3
// This is the type of register that takes into account the number of interrupts // This is the type of register that takes into account the number of interrupts
// that the model has. It is also the type of register where // that the model has. It is also the type of register where
// a register relates to multiple interrupts. // a register relates to multiple interrupts.
end = base + (reg.bpi as u32 * (num_irq - LAYOUT_IRQ_BASE) / 8); end = base + (reg.bpi as u32 * (num_irq - IRQ_BASE) / 8);
if reg.bpi as u32 * (num_irq - LAYOUT_IRQ_BASE) % 8 > 0 { if reg.bpi as u32 * (num_irq - IRQ_BASE) % 8 > 0 {
end += REG_SIZE as u32; end += REG_SIZE as u32;
} }
} }
@@ -147,7 +147,7 @@ fn compute_reg_len(gic: &Arc<dyn Device>, reg: &DistReg, base: u32) -> Result<u3
} }
/// Set distributor registers of the GIC. /// Set distributor registers of the GIC.
pub fn set_dist_regs(gic: &Arc<dyn Device>, state: &[u32]) -> Result<()> { pub fn set_dist_regs(gic: &Arc<dyn hypervisor::Device>, state: &[u32]) -> Result<()> {
let mut idx = 0; let mut idx = 0;
for dreg in VGIC_DIST_REGS { for dreg in VGIC_DIST_REGS {
@@ -164,7 +164,7 @@ pub fn set_dist_regs(gic: &Arc<dyn Device>, state: &[u32]) -> Result<()> {
Ok(()) Ok(())
} }
/// Get distributor registers of the GIC. /// Get distributor registers of the GIC.
pub fn get_dist_regs(gic: &Arc<dyn Device>) -> Result<Vec<u32>> { pub fn get_dist_regs(gic: &Arc<dyn hypervisor::Device>) -> Result<Vec<u32>> {
let mut state = Vec::new(); let mut state = Vec::new();
for dreg in VGIC_DIST_REGS { for dreg in VGIC_DIST_REGS {

View File

@@ -0,0 +1,262 @@
// Copyright 2021 Arm Limited (or its affiliates). All rights reserved.
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// This file implements the GicV3 device.
pub mod kvm {
use crate::aarch64::gic::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
use crate::aarch64::gic::icc_regs::{get_icc_regs, set_icc_regs};
use crate::aarch64::gic::kvm::{save_pending_tables, KvmGicDevice};
use crate::aarch64::gic::redist_regs::{
construct_gicr_typers, get_redist_regs, set_redist_regs,
};
use crate::aarch64::gic::GicDevice;
use crate::layout;
use anyhow::anyhow;
use hypervisor::kvm::kvm_bindings;
use hypervisor::CpuState;
use std::any::Any;
use std::convert::TryInto;
use std::sync::Arc;
use std::{boxed::Box, result};
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_memory::Address;
use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable,
VersionMapped,
};
/// Errors thrown while saving/restoring the GICv3.
#[derive(Debug)]
pub enum Error {
/// Error in saving RDIST pending tables into guest RAM.
SavePendingTables(crate::aarch64::gic::Error),
/// Error in saving GIC distributor registers.
SaveDistributorRegisters(crate::aarch64::gic::Error),
/// Error in restoring GIC distributor registers.
RestoreDistributorRegisters(crate::aarch64::gic::Error),
/// Error in saving GIC distributor control registers.
SaveDistributorCtrlRegisters(crate::aarch64::gic::Error),
/// Error in restoring GIC distributor control registers.
RestoreDistributorCtrlRegisters(crate::aarch64::gic::Error),
/// Error in saving GIC redistributor registers.
SaveRedistributorRegisters(crate::aarch64::gic::Error),
/// Error in restoring GIC redistributor registers.
RestoreRedistributorRegisters(crate::aarch64::gic::Error),
/// Error in saving GIC CPU interface registers.
SaveIccRegisters(crate::aarch64::gic::Error),
/// Error in restoring GIC CPU interface registers.
RestoreIccRegisters(crate::aarch64::gic::Error),
}
type Result<T> = result::Result<T, Error>;
pub struct KvmGicV3 {
/// The hypervisor agnostic device for the GicV3
device: Arc<dyn hypervisor::Device>,
/// Vector holding values of GICR_TYPER for each vCPU
gicr_typers: Vec<u64>,
/// GIC device properties, to be used for setting up the fdt entry
properties: [u64; 4],
/// Number of CPUs handled by the device
vcpu_count: u64,
}
#[derive(Versionize)]
pub struct Gicv3State {
dist: Vec<u32>,
rdist: Vec<u32>,
icc: Vec<u32>,
// special register that enables interrupts and affinity routing
gicd_ctlr: u32,
}
impl VersionMapped for Gicv3State {}
impl KvmGicV3 {
// Device trees specific constants
pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9;
/// Get the address of the GIC distributor.
pub fn get_dist_addr() -> u64 {
layout::GIC_V3_DIST_START.raw_value()
}
/// Get the size of the GIC distributor.
pub fn get_dist_size() -> u64 {
layout::GIC_V3_DIST_SIZE
}
/// Get the address of the GIC redistributors.
pub fn get_redists_addr(vcpu_count: u64) -> u64 {
KvmGicV3::get_dist_addr() - KvmGicV3::get_redists_size(vcpu_count)
}
/// Get the size of the GIC redistributors.
pub fn get_redists_size(vcpu_count: u64) -> u64 {
vcpu_count * layout::GIC_V3_REDIST_SIZE
}
/// Save the state of GIC.
fn state(&self, gicr_typers: &[u64]) -> Result<Gicv3State> {
let gicd_ctlr =
read_ctlr(self.device()).map_err(Error::SaveDistributorCtrlRegisters)?;
let dist_state =
get_dist_regs(self.device()).map_err(Error::SaveDistributorRegisters)?;
let rdist_state = get_redist_regs(self.device(), gicr_typers)
.map_err(Error::SaveRedistributorRegisters)?;
let icc_state =
get_icc_regs(self.device(), gicr_typers).map_err(Error::SaveIccRegisters)?;
Ok(Gicv3State {
dist: dist_state,
rdist: rdist_state,
icc: icc_state,
gicd_ctlr,
})
}
/// Restore the state of GIC.
fn set_state(&mut self, gicr_typers: &[u64], state: &Gicv3State) -> Result<()> {
write_ctlr(self.device(), state.gicd_ctlr)
.map_err(Error::RestoreDistributorCtrlRegisters)?;
set_dist_regs(self.device(), &state.dist)
.map_err(Error::RestoreDistributorRegisters)?;
set_redist_regs(self.device(), gicr_typers, &state.rdist)
.map_err(Error::RestoreRedistributorRegisters)?;
set_icc_regs(self.device(), gicr_typers, &state.icc)
.map_err(Error::RestoreIccRegisters)?;
Ok(())
}
}
impl GicDevice for KvmGicV3 {
fn device(&self) -> &Arc<dyn hypervisor::Device> {
&self.device
}
fn fdt_compatibility(&self) -> &str {
"arm,gic-v3"
}
fn fdt_maint_irq(&self) -> u32 {
KvmGicV3::ARCH_GIC_V3_MAINT_IRQ
}
fn device_properties(&self) -> &[u64] {
&self.properties
}
fn vcpu_count(&self) -> u64 {
self.vcpu_count
}
fn set_its_device(&mut self, _its_device: Option<Arc<dyn hypervisor::Device>>) {}
fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
let gicr_typers = construct_gicr_typers(vcpu_states);
self.gicr_typers = gicr_typers;
}
fn as_any_concrete_mut(&mut self) -> &mut dyn Any {
self
}
}
impl KvmGicDevice for KvmGicV3 {
fn version() -> u32 {
kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3
}
fn create_device(
device: Arc<dyn hypervisor::Device>,
vcpu_count: u64,
) -> Box<dyn GicDevice> {
Box::new(KvmGicV3 {
device,
gicr_typers: vec![0; vcpu_count.try_into().unwrap()],
properties: [
KvmGicV3::get_dist_addr(),
KvmGicV3::get_dist_size(),
KvmGicV3::get_redists_addr(vcpu_count),
KvmGicV3::get_redists_size(vcpu_count),
],
vcpu_count,
})
}
fn init_device_attributes(
_vm: &Arc<dyn hypervisor::Vm>,
gic_device: &mut dyn GicDevice,
) -> crate::aarch64::gic::Result<()> {
/* Setting up the distributor attribute.
We are placing the GIC below 1GB so we need to substract the size of the distributor.
*/
Self::set_device_attribute(
gic_device.device(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_DIST),
&KvmGicV3::get_dist_addr() as *const u64 as u64,
0,
)?;
/* Setting up the redistributors' attribute.
We are calculating here the start of the redistributors address. We have one per CPU.
*/
Self::set_device_attribute(
gic_device.device(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_REDIST),
&KvmGicV3::get_redists_addr(gic_device.vcpu_count()) as *const u64 as u64,
0,
)?;
Ok(())
}
}
pub const GIC_V3_SNAPSHOT_ID: &str = "gic-v3";
impl Snapshottable for KvmGicV3 {
fn id(&self) -> String {
GIC_V3_SNAPSHOT_ID.to_string()
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let gicr_typers = self.gicr_typers.clone();
Snapshot::new_from_versioned_state(&self.id(), &self.state(&gicr_typers).unwrap())
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
let gicr_typers = self.gicr_typers.clone();
self.set_state(&gicr_typers, &snapshot.to_versioned_state(&self.id())?)
.map_err(|e| {
MigratableError::Restore(anyhow!("Could not restore GICv3 state {:?}", e))
})
}
}
impl Pausable for KvmGicV3 {
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
// Flush redistributors pending tables to guest RAM.
save_pending_tables(self.device()).map_err(|e| {
MigratableError::Pause(anyhow!("Could not save GICv3 GIC pending tables {:?}", e))
})?;
Ok(())
}
}
impl Transportable for KvmGicV3 {}
impl Migratable for KvmGicV3 {}
}

View File

@@ -0,0 +1,514 @@
// Copyright 2021 Arm Limited (or its affiliates). All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//
// This file implements the GicV3 device with ITS (Virtual Interrupt Translation Service).
pub mod kvm {
use crate::aarch64::gic::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
use crate::aarch64::gic::icc_regs::{get_icc_regs, set_icc_regs};
use crate::aarch64::gic::redist_regs::{
construct_gicr_typers, get_redist_regs, set_redist_regs,
};
use crate::aarch64::gic::gicv3::kvm::KvmGicV3;
use crate::aarch64::gic::kvm::{save_pending_tables, KvmGicDevice};
use crate::aarch64::gic::GicDevice;
use crate::layout;
use anyhow::anyhow;
use hypervisor::kvm::kvm_bindings;
use hypervisor::CpuState;
use std::any::Any;
use std::convert::TryInto;
use std::sync::Arc;
use std::{boxed::Box, result};
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable,
VersionMapped,
};
const GITS_CTLR: u32 = 0x0000;
const GITS_IIDR: u32 = 0x0004;
const GITS_CBASER: u32 = 0x0080;
const GITS_CWRITER: u32 = 0x0088;
const GITS_CREADR: u32 = 0x0090;
const GITS_BASER: u32 = 0x0100;
/// Errors thrown while saving/restoring the GICv3ITS.
#[derive(Debug)]
pub enum Error {
/// Error in saving RDIST pending tables into guest RAM.
SavePendingTables(crate::aarch64::gic::Error),
/// Error in saving GIC distributor registers.
SaveDistributorRegisters(crate::aarch64::gic::Error),
/// Error in restoring GIC distributor registers.
RestoreDistributorRegisters(crate::aarch64::gic::Error),
/// Error in saving GIC distributor control registers.
SaveDistributorCtrlRegisters(crate::aarch64::gic::Error),
/// Error in restoring GIC distributor control registers.
RestoreDistributorCtrlRegisters(crate::aarch64::gic::Error),
/// Error in saving GIC redistributor registers.
SaveRedistributorRegisters(crate::aarch64::gic::Error),
/// Error in restoring GIC redistributor registers.
RestoreRedistributorRegisters(crate::aarch64::gic::Error),
/// Error in saving GIC CPU interface registers.
SaveIccRegisters(crate::aarch64::gic::Error),
/// Error in restoring GIC CPU interface registers.
RestoreIccRegisters(crate::aarch64::gic::Error),
/// Error in saving GICv3ITS IIDR register.
SaveITSIIDR(crate::aarch64::gic::Error),
/// Error in restoring GICv3ITS IIDR register.
RestoreITSIIDR(crate::aarch64::gic::Error),
/// Error in saving GICv3ITS CBASER register.
SaveITSCBASER(crate::aarch64::gic::Error),
/// Error in restoring GICv3ITS CBASER register.
RestoreITSCBASER(crate::aarch64::gic::Error),
/// Error in saving GICv3ITS CREADR register.
SaveITSCREADR(crate::aarch64::gic::Error),
/// Error in restoring GICv3ITS CREADR register.
RestoreITSCREADR(crate::aarch64::gic::Error),
/// Error in saving GICv3ITS CWRITER register.
SaveITSCWRITER(crate::aarch64::gic::Error),
/// Error in restoring GICv3ITS CWRITER register.
RestoreITSCWRITER(crate::aarch64::gic::Error),
/// Error in saving GICv3ITS BASER register.
SaveITSBASER(crate::aarch64::gic::Error),
/// Error in restoring GICv3ITS BASER register.
RestoreITSBASER(crate::aarch64::gic::Error),
/// Error in saving GICv3ITS CTLR register.
SaveITSCTLR(crate::aarch64::gic::Error),
/// Error in restoring GICv3ITS CTLR register.
RestoreITSCTLR(crate::aarch64::gic::Error),
/// Error in saving GICv3ITS restore tables.
SaveITSTables(crate::aarch64::gic::Error),
/// Error in restoring GICv3ITS restore tables.
RestoreITSTables(crate::aarch64::gic::Error),
}
type Result<T> = result::Result<T, Error>;
/// Access an ITS device attribute.
///
/// This is a helper function to get/set the ITS device attribute depending
/// the bool parameter `set` provided.
pub fn gicv3_its_attr_access(
its_device: &Arc<dyn hypervisor::Device>,
group: u32,
attr: u32,
val: &u64,
set: bool,
) -> crate::aarch64::gic::Result<()> {
let mut gicv3_its_attr = kvm_bindings::kvm_device_attr {
group,
attr: attr as u64,
addr: val as *const u64 as u64,
flags: 0,
};
if set {
its_device
.set_device_attr(&gicv3_its_attr)
.map_err(crate::aarch64::gic::Error::SetDeviceAttribute)?;
} else {
its_device
.get_device_attr(&mut gicv3_its_attr)
.map_err(crate::aarch64::gic::Error::GetDeviceAttribute)?;
}
Ok(())
}
/// Function that saves/restores ITS tables into guest RAM.
///
/// The tables get flushed to guest RAM whenever the VM gets stopped.
pub fn gicv3_its_tables_access(
its_device: &Arc<dyn hypervisor::Device>,
save: bool,
) -> crate::aarch64::gic::Result<()> {
let attr = if save {
u64::from(kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES)
} else {
u64::from(kvm_bindings::KVM_DEV_ARM_ITS_RESTORE_TABLES)
};
let init_gic_attr = kvm_bindings::kvm_device_attr {
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
attr,
addr: 0,
flags: 0,
};
its_device
.set_device_attr(&init_gic_attr)
.map_err(crate::aarch64::gic::Error::SetDeviceAttribute)
}
pub struct KvmGicV3Its {
/// The hypervisor agnostic device for the GicV3
device: Arc<dyn hypervisor::Device>,
/// The hypervisor agnostic device for the Its device
its_device: Option<Arc<dyn hypervisor::Device>>,
/// Vector holding values of GICR_TYPER for each vCPU
gicr_typers: Vec<u64>,
/// GIC device properties, to be used for setting up the fdt entry
gic_properties: [u64; 4],
/// MSI device properties, to be used for setting up the fdt entry
msi_properties: [u64; 2],
/// Number of CPUs handled by the device
vcpu_count: u64,
}
#[derive(Versionize)]
pub struct Gicv3ItsState {
dist: Vec<u32>,
rdist: Vec<u32>,
icc: Vec<u32>,
// special register that enables interrupts and affinity routing
gicd_ctlr: u32,
its_ctlr: u64,
its_iidr: u64,
its_cbaser: u64,
its_cwriter: u64,
its_creadr: u64,
its_baser: [u64; 8],
}
impl VersionMapped for Gicv3ItsState {}
impl KvmGicV3Its {
fn get_msi_size() -> u64 {
layout::GIC_V3_ITS_SIZE
}
fn get_msi_addr(vcpu_count: u64) -> u64 {
KvmGicV3::get_redists_addr(vcpu_count) - KvmGicV3Its::get_msi_size()
}
/// Save the state of GICv3ITS.
fn state(&self, gicr_typers: &[u64]) -> Result<Gicv3ItsState> {
let gicd_ctlr =
read_ctlr(self.device()).map_err(Error::SaveDistributorCtrlRegisters)?;
let dist_state =
get_dist_regs(self.device()).map_err(Error::SaveDistributorRegisters)?;
let rdist_state = get_redist_regs(self.device(), gicr_typers)
.map_err(Error::SaveRedistributorRegisters)?;
let icc_state =
get_icc_regs(self.device(), gicr_typers).map_err(Error::SaveIccRegisters)?;
let its_baser_state: [u64; 8] = [0; 8];
for i in 0..8 {
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_BASER + i * 8,
&its_baser_state[i as usize],
false,
)
.map_err(Error::SaveITSBASER)?;
}
let its_ctlr_state: u64 = 0;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CTLR,
&its_ctlr_state,
false,
)
.map_err(Error::SaveITSCTLR)?;
let its_cbaser_state: u64 = 0;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CBASER,
&its_cbaser_state,
false,
)
.map_err(Error::SaveITSCBASER)?;
let its_creadr_state: u64 = 0;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CREADR,
&its_creadr_state,
false,
)
.map_err(Error::SaveITSCREADR)?;
let its_cwriter_state: u64 = 0;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CWRITER,
&its_cwriter_state,
false,
)
.map_err(Error::SaveITSCWRITER)?;
let its_iidr_state: u64 = 0;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_IIDR,
&its_iidr_state,
false,
)
.map_err(Error::SaveITSIIDR)?;
Ok(Gicv3ItsState {
dist: dist_state,
rdist: rdist_state,
icc: icc_state,
gicd_ctlr,
its_ctlr: its_ctlr_state,
its_iidr: its_iidr_state,
its_cbaser: its_cbaser_state,
its_cwriter: its_cwriter_state,
its_creadr: its_creadr_state,
its_baser: its_baser_state,
})
}
/// Restore the state of GICv3ITS.
fn set_state(&mut self, gicr_typers: &[u64], state: &Gicv3ItsState) -> Result<()> {
write_ctlr(self.device(), state.gicd_ctlr)
.map_err(Error::RestoreDistributorCtrlRegisters)?;
set_dist_regs(self.device(), &state.dist)
.map_err(Error::RestoreDistributorRegisters)?;
set_redist_regs(self.device(), gicr_typers, &state.rdist)
.map_err(Error::RestoreRedistributorRegisters)?;
set_icc_regs(self.device(), gicr_typers, &state.icc)
.map_err(Error::RestoreIccRegisters)?;
//Restore GICv3ITS registers
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_IIDR,
&state.its_iidr,
true,
)
.map_err(Error::RestoreITSIIDR)?;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CBASER,
&state.its_cbaser,
true,
)
.map_err(Error::RestoreITSCBASER)?;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CREADR,
&state.its_creadr,
true,
)
.map_err(Error::RestoreITSCREADR)?;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CWRITER,
&state.its_cwriter,
true,
)
.map_err(Error::RestoreITSCWRITER)?;
for i in 0..8 {
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_BASER + i * 8,
&state.its_baser[i as usize],
true,
)
.map_err(Error::RestoreITSBASER)?;
}
// Restore ITS tables
gicv3_its_tables_access(self.its_device().unwrap(), false)
.map_err(Error::RestoreITSTables)?;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CTLR,
&state.its_ctlr,
true,
)
.map_err(Error::RestoreITSCTLR)?;
Ok(())
}
}
impl GicDevice for KvmGicV3Its {
fn device(&self) -> &Arc<dyn hypervisor::Device> {
&self.device
}
fn its_device(&self) -> Option<&Arc<dyn hypervisor::Device>> {
self.its_device.as_ref()
}
fn fdt_compatibility(&self) -> &str {
"arm,gic-v3"
}
fn msi_compatible(&self) -> bool {
true
}
fn msi_compatibility(&self) -> &str {
"arm,gic-v3-its"
}
fn fdt_maint_irq(&self) -> u32 {
KvmGicV3::ARCH_GIC_V3_MAINT_IRQ
}
fn msi_properties(&self) -> &[u64] {
&self.msi_properties
}
fn device_properties(&self) -> &[u64] {
&self.gic_properties
}
fn vcpu_count(&self) -> u64 {
self.vcpu_count
}
fn set_its_device(&mut self, its_device: Option<Arc<dyn hypervisor::Device>>) {
self.its_device = its_device;
}
fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
let gicr_typers = construct_gicr_typers(vcpu_states);
self.gicr_typers = gicr_typers;
}
fn as_any_concrete_mut(&mut self) -> &mut dyn Any {
self
}
}
impl KvmGicDevice for KvmGicV3Its {
fn version() -> u32 {
KvmGicV3::version()
}
fn create_device(
device: Arc<dyn hypervisor::Device>,
vcpu_count: u64,
) -> Box<dyn GicDevice> {
Box::new(KvmGicV3Its {
device,
its_device: None,
gicr_typers: vec![0; vcpu_count.try_into().unwrap()],
gic_properties: [
KvmGicV3::get_dist_addr(),
KvmGicV3::get_dist_size(),
KvmGicV3::get_redists_addr(vcpu_count),
KvmGicV3::get_redists_size(vcpu_count),
],
msi_properties: [
KvmGicV3Its::get_msi_addr(vcpu_count),
KvmGicV3Its::get_msi_size(),
],
vcpu_count,
})
}
fn init_device_attributes(
vm: &Arc<dyn hypervisor::Vm>,
gic_device: &mut dyn GicDevice,
) -> crate::aarch64::gic::Result<()> {
KvmGicV3::init_device_attributes(vm, gic_device)?;
let mut its_device = kvm_bindings::kvm_create_device {
type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS,
fd: 0,
flags: 0,
};
let its_fd = vm
.create_device(&mut its_device)
.map_err(crate::aarch64::gic::Error::CreateGic)?;
Self::set_device_attribute(
&its_fd,
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
u64::from(kvm_bindings::KVM_VGIC_ITS_ADDR_TYPE),
&KvmGicV3Its::get_msi_addr(gic_device.vcpu_count()) as *const u64 as u64,
0,
)?;
Self::set_device_attribute(
&its_fd,
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
0,
0,
)?;
gic_device.set_its_device(Some(its_fd));
Ok(())
}
}
pub const GIC_V3_ITS_SNAPSHOT_ID: &str = "gic-v3-its";
impl Snapshottable for KvmGicV3Its {
fn id(&self) -> String {
GIC_V3_ITS_SNAPSHOT_ID.to_string()
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let gicr_typers = self.gicr_typers.clone();
Snapshot::new_from_versioned_state(&self.id(), &self.state(&gicr_typers).unwrap())
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
let gicr_typers = self.gicr_typers.clone();
self.set_state(&gicr_typers, &snapshot.to_versioned_state(&self.id())?)
.map_err(|e| {
MigratableError::Restore(anyhow!("Could not restore GICv3ITS state {:?}", e))
})
}
}
impl Pausable for KvmGicV3Its {
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
// Flush redistributors pending tables to guest RAM.
save_pending_tables(self.device()).map_err(|e| {
MigratableError::Pause(anyhow!(
"Could not save GICv3ITS GIC pending tables {:?}",
e
))
})?;
// Flush ITS tables to guest RAM.
gicv3_its_tables_access(self.its_device().unwrap(), true).map_err(|e| {
MigratableError::Pause(anyhow!("Could not save GICv3ITS ITS tables {:?}", e))
})?;
Ok(())
}
}
impl Transportable for KvmGicV3Its {}
impl Migratable for KvmGicV3Its {}
}

View File

@@ -1,15 +1,13 @@
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::arch::aarch64::gic::{Error, Result}; use super::{Error, Result};
use crate::kvm::kvm_bindings::{ use hypervisor::kvm::kvm_bindings::{
kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, KVM_REG_ARM64_SYSREG_CRM_MASK, kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, KVM_REG_ARM64_SYSREG_CRM_MASK,
KVM_REG_ARM64_SYSREG_CRM_SHIFT, KVM_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_CRN_SHIFT, KVM_REG_ARM64_SYSREG_CRM_SHIFT, KVM_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_CRN_SHIFT,
KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_SHIFT, KVM_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_SHIFT, KVM_REG_ARM64_SYSREG_OP1_MASK,
KVM_REG_ARM64_SYSREG_OP1_SHIFT, KVM_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM64_SYSREG_OP2_SHIFT, KVM_REG_ARM64_SYSREG_OP1_SHIFT, KVM_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM64_SYSREG_OP2_SHIFT,
}; };
use crate::Device;
use std::sync::Arc; use std::sync::Arc;
const KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT: u32 = 32; const KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT: u32 = 32;
@@ -80,7 +78,7 @@ static VGIC_ICC_REGS: &[u64] = &[
]; ];
fn icc_attr_access( fn icc_attr_access(
gic: &Arc<dyn Device>, gic: &Arc<dyn hypervisor::Device>,
offset: u64, offset: u64,
typer: u64, typer: u64,
val: &u32, val: &u32,
@@ -103,7 +101,7 @@ fn icc_attr_access(
} }
/// Get ICC registers. /// Get ICC registers.
pub fn get_icc_regs(gic: &Arc<dyn Device>, gicr_typer: &[u64]) -> Result<Vec<u32>> { pub fn get_icc_regs(gic: &Arc<dyn hypervisor::Device>, gicr_typer: &[u64]) -> Result<Vec<u32>> {
let mut state: Vec<u32> = Vec::new(); let mut state: Vec<u32> = Vec::new();
// We need this for the ICC_AP<m>R<n>_EL1 registers. // We need this for the ICC_AP<m>R<n>_EL1 registers.
let mut num_priority_bits = 0; let mut num_priority_bits = 0;
@@ -156,7 +154,11 @@ pub fn get_icc_regs(gic: &Arc<dyn Device>, gicr_typer: &[u64]) -> Result<Vec<u32
} }
/// Set ICC registers. /// Set ICC registers.
pub fn set_icc_regs(gic: &Arc<dyn Device>, gicr_typer: &[u64], state: &[u32]) -> Result<()> { pub fn set_icc_regs(
gic: &Arc<dyn hypervisor::Device>,
gicr_typer: &[u64],
state: &[u32],
) -> Result<()> {
let mut num_priority_bits = 0; let mut num_priority_bits = 0;
let mut idx = 0; let mut idx = 0;
for ix in gicr_typer { for ix in gicr_typer {

220
arch/src/aarch64/gic/mod.rs Normal file
View File

@@ -0,0 +1,220 @@
// Copyright 2021 Arm Limited (or its affiliates). All rights reserved.
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
pub mod dist_regs;
pub mod gicv3;
pub mod gicv3_its;
pub mod icc_regs;
pub mod redist_regs;
pub use self::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
pub use self::icc_regs::{get_icc_regs, set_icc_regs};
pub use self::redist_regs::{get_redist_regs, set_redist_regs};
use hypervisor::CpuState;
use std::any::Any;
use std::result;
use std::sync::Arc;
/// Errors thrown while setting up the GIC.
#[derive(Debug)]
pub enum Error {
/// Error while calling KVM ioctl for setting up the global interrupt controller.
CreateGic(hypervisor::HypervisorVmError),
/// Error while setting device attributes for the GIC.
SetDeviceAttribute(hypervisor::HypervisorDeviceError),
/// Error while getting device attributes for the GIC.
GetDeviceAttribute(hypervisor::HypervisorDeviceError),
}
type Result<T> = result::Result<T, Error>;
pub trait GicDevice: Send {
/// Returns the hypervisor agnostic Device of the GIC device
fn device(&self) -> &Arc<dyn hypervisor::Device>;
/// Returns the hypervisor agnostic Device of the ITS device
fn its_device(&self) -> Option<&Arc<dyn hypervisor::Device>> {
None
}
/// Returns the fdt compatibility property of the device
fn fdt_compatibility(&self) -> &str;
/// Returns the maint_irq fdt property of the device
fn fdt_maint_irq(&self) -> u32;
/// Returns an array with GIC device properties
fn device_properties(&self) -> &[u64];
/// Returns the number of vCPUs this GIC handles
fn vcpu_count(&self) -> u64;
/// Returns whether the GIC device is MSI compatible or not
fn msi_compatible(&self) -> bool {
false
}
/// Returns the MSI compatibility property of the device
fn msi_compatibility(&self) -> &str {
""
}
/// Returns the MSI reg property of the device
fn msi_properties(&self) -> &[u64] {
&[]
}
fn set_its_device(&mut self, its_device: Option<Arc<dyn hypervisor::Device>>);
/// Get the values of GICR_TYPER for each vCPU.
fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]);
/// Downcast the trait object to its concrete type.
fn as_any_concrete_mut(&mut self) -> &mut dyn Any;
}
pub mod kvm {
use super::GicDevice;
use super::Result;
use crate::aarch64::gic::gicv3_its::kvm::KvmGicV3Its;
use crate::layout;
use hypervisor::kvm::kvm_bindings;
use std::boxed::Box;
use std::sync::Arc;
/// Trait for GIC devices.
pub trait KvmGicDevice: Send + Sync + GicDevice {
/// Returns the GIC version of the device
fn version() -> u32;
/// Create the GIC device object
fn create_device(
device: Arc<dyn hypervisor::Device>,
vcpu_count: u64,
) -> Box<dyn GicDevice>;
/// Setup the device-specific attributes
fn init_device_attributes(
vm: &Arc<dyn hypervisor::Vm>,
gic_device: &mut dyn GicDevice,
) -> Result<()>;
/// Initialize a GIC device
fn init_device(vm: &Arc<dyn hypervisor::Vm>) -> Result<Arc<dyn hypervisor::Device>> {
let mut gic_device = kvm_bindings::kvm_create_device {
type_: Self::version(),
fd: 0,
flags: 0,
};
vm.create_device(&mut gic_device)
.map_err(super::Error::CreateGic)
}
/// Set a GIC device attribute
fn set_device_attribute(
device: &Arc<dyn hypervisor::Device>,
group: u32,
attr: u64,
addr: u64,
flags: u32,
) -> Result<()> {
let attr = kvm_bindings::kvm_device_attr {
flags,
group,
attr,
addr,
};
device
.set_device_attr(&attr)
.map_err(super::Error::SetDeviceAttribute)?;
Ok(())
}
/// Get a GIC device attribute
fn get_device_attribute(
device: &Arc<dyn hypervisor::Device>,
group: u32,
attr: u64,
addr: u64,
flags: u32,
) -> Result<()> {
let mut attr = kvm_bindings::kvm_device_attr {
flags,
group,
attr,
addr,
};
device
.get_device_attr(&mut attr)
.map_err(super::Error::GetDeviceAttribute)?;
Ok(())
}
/// Finalize the setup of a GIC device
fn finalize_device(gic_device: &dyn GicDevice) -> Result<()> {
/* We need to tell the kernel how many irqs to support with this vgic.
* See the `layout` module for details.
*/
let nr_irqs: u32 = layout::IRQ_NUM;
let nr_irqs_ptr = &nr_irqs as *const u32;
Self::set_device_attribute(
gic_device.device(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
0,
nr_irqs_ptr as u64,
0,
)?;
/* Finalize the GIC.
* See https://code.woboq.org/linux/linux/virt/kvm/arm/vgic/vgic-kvm-device.c.html#211.
*/
Self::set_device_attribute(
gic_device.device(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
0,
0,
)?;
Ok(())
}
/// Method to initialize the GIC device
#[allow(clippy::new_ret_no_self)]
fn new(vm: &Arc<dyn hypervisor::Vm>, vcpu_count: u64) -> Result<Box<dyn GicDevice>> {
let vgic_fd = Self::init_device(vm)?;
let mut device = Self::create_device(vgic_fd, vcpu_count);
Self::init_device_attributes(vm, &mut *device)?;
Self::finalize_device(&*device)?;
Ok(device)
}
}
/// Create a GICv3-ITS device.
///
pub fn create_gic(vm: &Arc<dyn hypervisor::Vm>, vcpu_count: u64) -> Result<Box<dyn GicDevice>> {
debug!("creating a GICv3-ITS");
KvmGicV3Its::new(vm, vcpu_count)
}
/// Function that saves RDIST pending tables into guest RAM.
///
/// The tables get flushed to guest RAM whenever the VM gets stopped.
pub fn save_pending_tables(gic: &Arc<dyn hypervisor::Device>) -> Result<()> {
let init_gic_attr = kvm_bindings::kvm_device_attr {
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
attr: u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES),
addr: 0,
flags: 0,
};
gic.set_device_attr(&init_gic_attr)
.map_err(super::Error::SetDeviceAttribute)
}
}

View File

@@ -1,10 +1,9 @@
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::arch::aarch64::gic::{Error, Result}; use super::{Error, Result};
use crate::kvm::kvm_bindings::{kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS}; use hypervisor::kvm::kvm_bindings::{kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS};
use crate::{CpuState, Device}; use hypervisor::CpuState;
use std::sync::Arc; use std::sync::Arc;
// Relevant redistributor registers that we want to save/restore. // Relevant redistributor registers that we want to save/restore.
@@ -84,7 +83,7 @@ static VGIC_SGI_REGS: &[RdistReg] = &[
]; ];
fn redist_attr_access( fn redist_attr_access(
gic: &Arc<dyn Device>, gic: &Arc<dyn hypervisor::Device>,
offset: u32, offset: u32,
typer: u64, typer: u64,
val: &u32, val: &u32,
@@ -107,7 +106,7 @@ fn redist_attr_access(
} }
fn access_redists_aux( fn access_redists_aux(
gic: &Arc<dyn Device>, gic: &Arc<dyn hypervisor::Device>,
gicr_typer: &[u64], gicr_typer: &[u64],
state: &mut Vec<u32>, state: &mut Vec<u32>,
reg_list: &[RdistReg], reg_list: &[RdistReg],
@@ -137,7 +136,7 @@ fn access_redists_aux(
} }
/// Get redistributor registers. /// Get redistributor registers.
pub fn get_redist_regs(gic: &Arc<dyn Device>, gicr_typer: &[u64]) -> Result<Vec<u32>> { pub fn get_redist_regs(gic: &Arc<dyn hypervisor::Device>, gicr_typer: &[u64]) -> Result<Vec<u32>> {
let mut state = Vec::new(); let mut state = Vec::new();
let mut idx: usize = 0; let mut idx: usize = 0;
access_redists_aux( access_redists_aux(
@@ -154,7 +153,11 @@ pub fn get_redist_regs(gic: &Arc<dyn Device>, gicr_typer: &[u64]) -> Result<Vec<
} }
/// Set redistributor registers. /// Set redistributor registers.
pub fn set_redist_regs(gic: &Arc<dyn Device>, gicr_typer: &[u64], state: &[u32]) -> Result<()> { pub fn set_redist_regs(
gic: &Arc<dyn hypervisor::Device>,
gicr_typer: &[u64],
state: &[u32],
) -> Result<()> {
let mut idx: usize = 0; let mut idx: usize = 0;
let mut mut_state = state.to_owned(); let mut mut_state = state.to_owned();
access_redists_aux( access_redists_aux(

View File

@@ -4,19 +4,23 @@
/// Module for the flattened device tree. /// Module for the flattened device tree.
pub mod fdt; pub mod fdt;
/// Module for the global interrupt controller configuration.
pub mod gic;
/// Layout for this aarch64 system. /// Layout for this aarch64 system.
pub mod layout; pub mod layout;
/// Logic for configuring aarch64 registers.
pub mod regs;
/// Module for loading UEFI binary. /// Module for loading UEFI binary.
pub mod uefi; pub mod uefi;
pub use self::fdt::DeviceInfoForFdt; pub use self::fdt::DeviceInfoForFdt;
use crate::{DeviceType, GuestMemoryMmap, NumaNodes, PciSpaceInfo, RegionType}; use crate::{DeviceType, GuestMemoryMmap, NumaNodes, PciSpaceInfo, RegionType};
use hypervisor::arch::aarch64::gic::Vgic; use gic::GicDevice;
use log::{log_enabled, Level}; use log::{log_enabled, Level};
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryInto; use std::convert::TryInto;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::{Arc, Mutex}; use std::sync::Arc;
use vm_memory::{Address, GuestAddress, GuestMemory, GuestUsize}; use vm_memory::{Address, GuestAddress, GuestMemory, GuestUsize};
/// Errors thrown while configuring aarch64 system. /// Errors thrown while configuring aarch64 system.
@@ -29,13 +33,13 @@ pub enum Error {
WriteFdtToMemory(fdt::Error), WriteFdtToMemory(fdt::Error),
/// Failed to create a GIC. /// Failed to create a GIC.
SetupGic, SetupGic(gic::Error),
/// Failed to compute the initramfs address. /// Failed to compute the initramfs address.
InitramfsAddress, InitramfsAddress,
/// Error configuring the general purpose registers /// Error configuring the general purpose registers
RegsConfiguration(hypervisor::HypervisorCpuError), RegsConfiguration(regs::Error),
/// Error configuring the MPIDR register /// Error configuring the MPIDR register
VcpuRegMpidr(hypervisor::HypervisorCpuError), VcpuRegMpidr(hypervisor::HypervisorCpuError),
@@ -46,7 +50,7 @@ pub enum Error {
impl From<Error> for super::Error { impl From<Error> for super::Error {
fn from(e: Error) -> super::Error { fn from(e: Error) -> super::Error {
super::Error::PlatformSpecific(e) super::Error::AArch64Setup(e)
} }
} }
@@ -60,20 +64,16 @@ pub struct EntryPoint {
/// Configure the specified VCPU, and return its MPIDR. /// Configure the specified VCPU, and return its MPIDR.
pub fn configure_vcpu( pub fn configure_vcpu(
vcpu: &Arc<dyn hypervisor::Vcpu>, fd: &Arc<dyn hypervisor::Vcpu>,
id: u8, id: u8,
kernel_entry_point: Option<EntryPoint>, kernel_entry_point: Option<EntryPoint>,
) -> super::Result<u64> { ) -> super::Result<u64> {
if let Some(kernel_entry_point) = kernel_entry_point { if let Some(kernel_entry_point) = kernel_entry_point {
vcpu.setup_regs( regs::setup_regs(fd, id, kernel_entry_point.entry_addr.raw_value())
id, .map_err(Error::RegsConfiguration)?;
kernel_entry_point.entry_addr.raw_value(),
super::layout::FDT_START.raw_value(),
)
.map_err(Error::RegsConfiguration)?;
} }
let mpidr = vcpu.read_mpidr().map_err(Error::VcpuRegMpidr)?; let mpidr = fd.read_mpidr().map_err(Error::VcpuRegMpidr)?;
Ok(mpidr) Ok(mpidr)
} }
@@ -143,7 +143,7 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
initrd: &Option<super::InitramfsConfig>, initrd: &Option<super::InitramfsConfig>,
pci_space_info: &[PciSpaceInfo], pci_space_info: &[PciSpaceInfo],
virtio_iommu_bdf: Option<u32>, virtio_iommu_bdf: Option<u32>,
gic_device: &Arc<Mutex<dyn Vgic>>, gic_device: &dyn GicDevice,
numa_nodes: &NumaNodes, numa_nodes: &NumaNodes,
pmu_supported: bool, pmu_supported: bool,
) -> super::Result<()> { ) -> super::Result<()> {
@@ -185,10 +185,10 @@ pub fn initramfs_load_addr(
if guest_mem.address_in_range(offset) { if guest_mem.address_in_range(offset) {
Ok(offset.raw_value()) Ok(offset.raw_value())
} else { } else {
Err(super::Error::PlatformSpecific(Error::InitramfsAddress)) Err(super::Error::AArch64Setup(Error::InitramfsAddress))
} }
} }
None => Err(super::Error::PlatformSpecific(Error::InitramfsAddress)), None => Err(super::Error::AArch64Setup(Error::InitramfsAddress)),
} }
} }

75
arch/src/aarch64/regs.rs Normal file
View File

@@ -0,0 +1,75 @@
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.
use hypervisor::kvm::kvm_bindings::{
kvm_regs, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM_CORE, KVM_REG_SIZE_U64,
};
use hypervisor::{arm64_core_reg_id, offset__of};
use std::sync::Arc;
use std::{mem, result};
use vm_memory::Address;
/// Errors thrown while setting aarch64 registers.
#[derive(Debug)]
pub enum Error {
/// Failed to set core register (PC, PSTATE or general purpose ones).
SetCoreRegister(hypervisor::HypervisorCpuError),
/// Failed to get a system register.
GetSysRegister(hypervisor::HypervisorCpuError),
}
type Result<T> = result::Result<T, Error>;
#[allow(non_upper_case_globals)]
// PSR (Processor State Register) bits.
// Taken from arch/arm64/include/uapi/asm/ptrace.h.
const PSR_MODE_EL1h: u64 = 0x0000_0005;
const PSR_F_BIT: u64 = 0x0000_0040;
const PSR_I_BIT: u64 = 0x0000_0080;
const PSR_A_BIT: u64 = 0x0000_0100;
const PSR_D_BIT: u64 = 0x0000_0200;
// Taken from arch/arm64/kvm/inject_fault.c.
const PSTATE_FAULT_BITS_64: u64 = PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT;
/// Configure core registers for a given CPU.
///
/// # Arguments
///
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
/// * `cpu_id` - Index of current vcpu.
/// * `boot_ip` - Starting instruction pointer.
/// * `mem` - Reserved DRAM for current VM.
pub fn setup_regs(vcpu: &Arc<dyn hypervisor::Vcpu>, cpu_id: u8, boot_ip: u64) -> Result<()> {
let kreg_off = offset__of!(kvm_regs, regs);
// Get the register index of the PSTATE (Processor State) register.
let pstate = offset__of!(user_pt_regs, pstate) + kreg_off;
vcpu.set_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate),
PSTATE_FAULT_BITS_64,
)
.map_err(Error::SetCoreRegister)?;
// Other vCPUs are powered off initially awaiting PSCI wakeup.
if cpu_id == 0 {
// Setting the PC (Processor Counter) to the current program address (kernel address).
let pc = offset__of!(user_pt_regs, pc) + kreg_off;
vcpu.set_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), boot_ip as u64)
.map_err(Error::SetCoreRegister)?;
// Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
// "The device tree blob (dtb) must be placed on an 8-byte boundary and must
// not exceed 2 megabytes in size." -> https://www.kernel.org/doc/Documentation/arm64/booting.txt.
// We are choosing to place it the end of DRAM. See `get_fdt_addr`.
let regs0 = offset__of!(user_pt_regs, regs) + kreg_off;
vcpu.set_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
super::layout::FDT_START.raw_value(),
)
.map_err(Error::SetCoreRegister)?;
}
Ok(())
}

View File

@@ -9,15 +9,15 @@
#[macro_use] #[macro_use]
extern crate log; extern crate log;
#[macro_use]
extern crate serde_derive;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::x86_64::SgxEpcSection; use crate::x86_64::SgxEpcSection;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt; use std::fmt;
use std::result; use std::result;
use std::sync::Arc; use std::sync::Arc;
use thiserror::Error;
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult}; use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
use versionize_derive::Versionize; use versionize_derive::Versionize;
use vm_migration::VersionMapped; use vm_migration::VersionMapped;
@@ -26,27 +26,31 @@ type GuestMemoryMmap = vm_memory::GuestMemoryMmap<vm_memory::bitmap::AtomicBitma
type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitmap>; type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitmap>;
/// Type for returning error code. /// Type for returning error code.
#[derive(Debug, Error)] #[derive(Debug)]
pub enum Error { pub enum Error {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
#[error("Platform specific error (x86_64): {0:?}")] /// X86_64 specific error triggered during system configuration.
PlatformSpecific(x86_64::Error), X86_64Setup(x86_64::Error),
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
#[error("Platform specific error (aarch64): {0:?}")] /// AArch64 specific error triggered during system configuration.
PlatformSpecific(aarch64::Error), AArch64Setup(aarch64::Error),
#[error("The memory map table extends past the end of guest memory")] /// The zero page extends past the end of guest_mem.
ZeroPagePastRamEnd,
/// Error writing the zero page of guest memory.
ZeroPageSetup(vm_memory::GuestMemoryError),
/// The memory map table extends past the end of guest memory.
MemmapTablePastRamEnd, MemmapTablePastRamEnd,
#[error("Error writing memory map table to guest memory")] /// Error writing memory map table to guest memory.
MemmapTableSetup, MemmapTableSetup,
#[error("The hvm_start_info structure extends past the end of guest memory")] /// The hvm_start_info structure extends past the end of guest memory.
StartInfoPastRamEnd, StartInfoPastRamEnd,
#[error("Error writing hvm_start_info to guest memory")] /// Error writing hvm_start_info to guest memory.
StartInfoSetup, StartInfoSetup,
#[error("Failed to compute initramfs address")] /// Failed to compute initramfs address.
InitramfsAddress, InitramfsAddress,
#[error("Error writing module entry to guest memory: {0}")] /// Error writing module entry to guest memory.
ModlistSetup(#[source] vm_memory::GuestMemoryError), ModlistSetup(vm_memory::GuestMemoryError),
#[error("RSDP extends past the end of guest memory")] /// RSDP Beyond Guest Memory
RsdpPastRamEnd, RsdpPastRamEnd,
} }
@@ -54,7 +58,7 @@ pub enum Error {
pub type Result<T> = result::Result<T, Error>; pub type Result<T> = result::Result<T, Error>;
/// Type for memory region types. /// Type for memory region types.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize, Versionize)] #[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize, Versionize)]
pub enum RegionType { pub enum RegionType {
/// RAM type /// RAM type
Ram, Ram,

View File

@@ -15,8 +15,7 @@ pub mod regs;
use crate::GuestMemoryMmap; use crate::GuestMemoryMmap;
use crate::InitramfsConfig; use crate::InitramfsConfig;
use crate::RegionType; use crate::RegionType;
use hypervisor::x86_64::{CpuId, CpuIdEntry, CPUID_FLAG_VALID_INDEX}; use hypervisor::{CpuId, CpuIdEntry, HypervisorError, CPUID_FLAG_VALID_INDEX};
use hypervisor::HypervisorError;
use linux_loader::loader::bootparam::boot_params; use linux_loader::loader::bootparam::boot_params;
use linux_loader::loader::elf::start_info::{ use linux_loader::loader::elf::start_info::{
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info, hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
@@ -198,7 +197,7 @@ pub enum Error {
impl From<Error> for super::Error { impl From<Error> for super::Error {
fn from(e: Error) -> super::Error { fn from(e: Error) -> super::Error {
super::Error::PlatformSpecific(e) super::Error::X86_64Setup(e)
} }
} }
@@ -744,7 +743,7 @@ pub fn generate_common_cpuid(
} }
pub fn configure_vcpu( pub fn configure_vcpu(
vcpu: &Arc<dyn hypervisor::Vcpu>, fd: &Arc<dyn hypervisor::Vcpu>,
id: u8, id: u8,
kernel_entry_point: Option<EntryPoint>, kernel_entry_point: Option<EntryPoint>,
vm_memory: &GuestMemoryAtomic<GuestMemoryMmap>, vm_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
@@ -756,23 +755,23 @@ pub fn configure_vcpu(
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id)); CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id)); CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
vcpu.set_cpuid2(&cpuid) fd.set_cpuid2(&cpuid)
.map_err(|e| Error::SetSupportedCpusFailed(e.into()))?; .map_err(|e| Error::SetSupportedCpusFailed(e.into()))?;
if kvm_hyperv { if kvm_hyperv {
vcpu.enable_hyperv_synic().unwrap(); fd.enable_hyperv_synic().unwrap();
} }
regs::setup_msrs(vcpu).map_err(Error::MsrsConfiguration)?; regs::setup_msrs(fd).map_err(Error::MsrsConfiguration)?;
if let Some(kernel_entry_point) = kernel_entry_point { if let Some(kernel_entry_point) = kernel_entry_point {
if let Some(entry_addr) = kernel_entry_point.entry_addr { if let Some(entry_addr) = kernel_entry_point.entry_addr {
// Safe to unwrap because this method is called after the VM is configured // Safe to unwrap because this method is called after the VM is configured
regs::setup_regs(vcpu, entry_addr.raw_value()).map_err(Error::RegsConfiguration)?; regs::setup_regs(fd, entry_addr.raw_value()).map_err(Error::RegsConfiguration)?;
regs::setup_fpu(vcpu).map_err(Error::FpuConfiguration)?; regs::setup_fpu(fd).map_err(Error::FpuConfiguration)?;
regs::setup_sregs(&vm_memory.memory(), vcpu).map_err(Error::SregsConfiguration)?; regs::setup_sregs(&vm_memory.memory(), fd).map_err(Error::SregsConfiguration)?;
} }
} }
interrupts::set_lint(vcpu).map_err(|e| Error::LocalIntConfiguration(e.into()))?; interrupts::set_lint(fd).map_err(|e| Error::LocalIntConfiguration(e.into()))?;
Ok(()) Ok(())
} }
@@ -839,14 +838,13 @@ pub fn configure_system(
_num_cpus: u8, _num_cpus: u8,
rsdp_addr: Option<GuestAddress>, rsdp_addr: Option<GuestAddress>,
sgx_epc_region: Option<SgxEpcRegion>, sgx_epc_region: Option<SgxEpcRegion>,
serial_number: Option<&str>,
) -> super::Result<()> { ) -> super::Result<()> {
// Write EBDA address to location where ACPICA expects to find it // Write EBDA address to location where ACPICA expects to find it
guest_mem guest_mem
.write_obj((layout::EBDA_START.0 >> 4) as u16, layout::EBDA_POINTER) .write_obj((layout::EBDA_START.0 >> 4) as u16, layout::EBDA_POINTER)
.map_err(Error::EbdaSetup)?; .map_err(Error::EbdaSetup)?;
let size = smbios::setup_smbios(guest_mem, serial_number).map_err(Error::SmbiosSetup)?; let size = smbios::setup_smbios(guest_mem).map_err(Error::SmbiosSetup)?;
// Place the MP table after the SMIOS table aligned to 16 bytes // Place the MP table after the SMIOS table aligned to 16 bytes
let offset = GuestAddress(layout::SMBIOS_START).unchecked_add(size); let offset = GuestAddress(layout::SMBIOS_START).unchecked_add(size);
@@ -1195,7 +1193,6 @@ mod tests {
1, 1,
Some(layout::RSDP_POINTER), Some(layout::RSDP_POINTER),
None, None,
None,
); );
assert!(config_err.is_err()); assert!(config_err.is_err());
@@ -1209,7 +1206,7 @@ mod tests {
.collect(); .collect();
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap(); let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None, None).unwrap(); configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
// Now assigning some memory that is equal to the start of the 32bit memory hole. // Now assigning some memory that is equal to the start of the 32bit memory hole.
let mem_size = 3328 << 20; let mem_size = 3328 << 20;
@@ -1220,9 +1217,9 @@ mod tests {
.map(|r| (r.0, r.1)) .map(|r| (r.0, r.1))
.collect(); .collect();
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap(); let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None, None).unwrap(); configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None, None).unwrap(); configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
// Now assigning some memory that falls after the 32bit memory hole. // Now assigning some memory that falls after the 32bit memory hole.
let mem_size = 3330 << 20; let mem_size = 3330 << 20;
@@ -1233,9 +1230,9 @@ mod tests {
.map(|r| (r.0, r.1)) .map(|r| (r.0, r.1))
.collect(); .collect();
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap(); let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None, None).unwrap(); configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None, None).unwrap(); configure_system(&gm, GuestAddress(0), &None, no_vcpus, None, None).unwrap();
} }
#[test] #[test]

View File

@@ -9,7 +9,7 @@
use crate::layout::{BOOT_GDT_START, BOOT_IDT_START, PVH_INFO_START}; use crate::layout::{BOOT_GDT_START, BOOT_IDT_START, PVH_INFO_START};
use crate::GuestMemoryMmap; use crate::GuestMemoryMmap;
use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt}; use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt};
use hypervisor::arch::x86::regs::CR0_PE; use hypervisor::arch::x86::regs::*;
use hypervisor::x86_64::{FpuState, SpecialRegisters, StandardRegisters}; use hypervisor::x86_64::{FpuState, SpecialRegisters, StandardRegisters};
use std::sync::Arc; use std::sync::Arc;
use std::{mem, result}; use std::{mem, result};

View File

@@ -162,7 +162,7 @@ fn write_string(
Ok(curptr) Ok(curptr)
} }
pub fn setup_smbios(mem: &GuestMemoryMmap, serial_number: Option<&str>) -> Result<u64> { pub fn setup_smbios(mem: &GuestMemoryMmap) -> Result<u64> {
let physptr = GuestAddress(SMBIOS_START) let physptr = GuestAddress(SMBIOS_START)
.checked_add(mem::size_of::<Smbios30Entrypoint>() as u64) .checked_add(mem::size_of::<Smbios30Entrypoint>() as u64)
.ok_or(Error::NotEnoughMemory)?; .ok_or(Error::NotEnoughMemory)?;
@@ -195,15 +195,11 @@ pub fn setup_smbios(mem: &GuestMemoryMmap, serial_number: Option<&str>) -> Resul
handle, handle,
manufacturer: 1, // First string written in this section manufacturer: 1, // First string written in this section
product_name: 2, // Second string written in this section product_name: 2, // Second string written in this section
serial_number: serial_number.map(|_| 3).unwrap_or_default(), // 3rd string
..Default::default() ..Default::default()
}; };
curptr = write_and_incr(mem, smbios_sysinfo, curptr)?; curptr = write_and_incr(mem, smbios_sysinfo, curptr)?;
curptr = write_string(mem, "Cloud Hypervisor", curptr)?; curptr = write_string(mem, "Cloud Hypervisor", curptr)?;
curptr = write_string(mem, "cloud-hypervisor", curptr)?; curptr = write_string(mem, "cloud-hypervisor", curptr)?;
if let Some(serial_number) = serial_number {
curptr = write_string(mem, serial_number, curptr)?;
}
curptr = write_and_incr(mem, 0u8, curptr)?; curptr = write_and_incr(mem, 0u8, curptr)?;
} }
@@ -267,7 +263,7 @@ mod tests {
fn entrypoint_checksum() { fn entrypoint_checksum() {
let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(SMBIOS_START), 4096)]).unwrap(); let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(SMBIOS_START), 4096)]).unwrap();
setup_smbios(&mem, None).unwrap(); setup_smbios(&mem).unwrap();
let smbios_ep: Smbios30Entrypoint = mem.read_obj(GuestAddress(SMBIOS_START)).unwrap(); let smbios_ep: Smbios30Entrypoint = mem.read_obj(GuestAddress(SMBIOS_START)).unwrap();

View File

@@ -9,16 +9,16 @@ default = []
[dependencies] [dependencies]
io-uring = "0.5.2" io-uring = "0.5.2"
libc = "0.2.126" libc = "0.2.123"
log = "0.4.17" log = "0.4.16"
qcow = { path = "../qcow" } qcow = { path = "../qcow" }
thiserror = "1.0.31" thiserror = "1.0.30"
versionize = "0.1.6" versionize = "0.1.6"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"
vhdx = { path = "../vhdx" } vhdx = { path = "../vhdx" }
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] } virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
virtio-queue = "0.4.0" virtio-queue = "0.2.0"
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" } vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.9.0" vmm-sys-util = "0.9.0"

View File

@@ -104,7 +104,7 @@ impl DiskTopology {
pub type DiskFileResult<T> = std::result::Result<T, DiskFileError>; pub type DiskFileResult<T> = std::result::Result<T, DiskFileError>;
pub trait DiskFile: Send { pub trait DiskFile: Send + Sync {
fn size(&mut self) -> DiskFileResult<u64>; fn size(&mut self) -> DiskFileResult<u64>;
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>>; fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>>;
fn topology(&mut self) -> DiskTopology { fn topology(&mut self) -> DiskTopology {
@@ -127,7 +127,7 @@ pub enum AsyncIoError {
pub type AsyncIoResult<T> = std::result::Result<T, AsyncIoError>; pub type AsyncIoResult<T> = std::result::Result<T, AsyncIoError>;
pub trait AsyncIo: Send { pub trait AsyncIo: Send + Sync {
fn notifier(&self) -> &EventFd; fn notifier(&self) -> &EventFd;
fn read_vectored( fn read_vectored(
&mut self, &mut self,

View File

@@ -138,7 +138,7 @@ impl ExecuteError {
} }
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum RequestType { pub enum RequestType {
In, In,
Out, Out,

View File

@@ -6,18 +6,17 @@ edition = "2021"
[dependencies] [dependencies]
acpi_tables = { path = "../acpi_tables" } acpi_tables = { path = "../acpi_tables" }
anyhow = "1.0.58" anyhow = "1.0.56"
arch = { path = "../arch" } arch = { path = "../arch" }
bitflags = "1.3.2" bitflags = "1.3.2"
byteorder = "1.4.3" byteorder = "1.4.3"
epoll = "4.3.1" epoll = "4.3.1"
hypervisor = { path = "../hypervisor" } libc = "0.2.123"
libc = "0.2.126" log = "0.4.16"
log = "0.4.17"
versionize = "0.1.6" versionize = "0.1.6"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"
vm-device = { path = "../vm-device" } vm-device = { path = "../vm-device" }
vm-memory = "0.8.0" vm-memory = "0.7.0"
vm-migration = { path = "../vm-migration" } vm-migration = { path = "../vm-migration" }
vmm-sys-util = "0.9.0" vmm-sys-util = "0.9.0"

View File

@@ -4,34 +4,30 @@
use super::interrupt_controller::{Error, InterruptController}; use super::interrupt_controller::{Error, InterruptController};
extern crate arch; extern crate arch;
use anyhow::anyhow; use arch::aarch64::gic::GicDevice;
use arch::layout;
use hypervisor::{arch::aarch64::gic::Vgic, CpuState};
use std::result; use std::result;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use vm_device::interrupt::{ use vm_device::interrupt::{
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup, InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
LegacyIrqSourceConfig, MsiIrqGroupConfig, LegacyIrqSourceConfig, MsiIrqGroupConfig,
}; };
use vm_memory::Address;
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
type Result<T> = result::Result<T, Error>; type Result<T> = result::Result<T, Error>;
// Reserve 32 IRQs for legacy devices. // Reserve 32 IRQs for legacy device.
pub const IRQ_LEGACY_BASE: usize = layout::IRQ_BASE as usize; pub const IRQ_LEGACY_BASE: usize = arch::layout::IRQ_BASE as usize;
pub const IRQ_LEGACY_COUNT: usize = 32; pub const IRQ_LEGACY_COUNT: usize = 32;
// Gic (Generic Interupt Controller) struct provides all the functionality of a // This Gic struct implements InterruptController to provide interrupt delivery service.
// GIC device. It wraps a hypervisor-emulated GIC device (Vgic) provided by the // The Gic source files in arch/ folder maintain the Aarch64 specific Gic device.
// `hypervisor` crate. // The 2 Gic instances could be merged together.
// Gic struct also implements InterruptController to provide interrupt delivery // Leave this refactoring to future. Two options may be considered:
// service. // 1. Move Gic*.rs from arch/ folder here.
// 2. Move this file and ioapic.rs to arch/, as they are architecture specific.
pub struct Gic { pub struct Gic {
interrupt_source_group: Arc<dyn InterruptSourceGroup>, interrupt_source_group: Arc<dyn InterruptSourceGroup>,
// The hypervisor agnostic virtual GIC gic_device: Option<Arc<Mutex<Box<dyn GicDevice>>>>,
vgic: Option<Arc<Mutex<dyn Vgic>>>,
} }
impl Gic { impl Gic {
@@ -48,32 +44,16 @@ impl Gic {
Ok(Gic { Ok(Gic {
interrupt_source_group, interrupt_source_group,
vgic: None, gic_device: None,
}) })
} }
pub fn create_vgic( pub fn set_gic_device(&mut self, gic_device: Arc<Mutex<Box<dyn GicDevice>>>) {
&mut self, self.gic_device = Some(gic_device);
vm: &Arc<dyn hypervisor::Vm>,
vcpu_count: u64,
) -> Result<Arc<Mutex<dyn Vgic>>> {
let vgic = vm
.create_vgic(
vcpu_count,
layout::GIC_V3_DIST_START.raw_value(),
layout::GIC_V3_DIST_SIZE,
layout::GIC_V3_REDIST_SIZE,
layout::GIC_V3_ITS_SIZE,
layout::IRQ_NUM,
)
.map_err(Error::CreateGic)?;
self.vgic = Some(vgic.clone());
Ok(vgic.clone())
} }
pub fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) { pub fn get_gic_device(&self) -> Option<&Arc<Mutex<Box<dyn GicDevice>>>> {
let vgic = self.vgic.as_ref().unwrap().clone(); self.gic_device.as_ref()
vgic.lock().unwrap().set_gicr_typers(vcpu_states);
} }
} }
@@ -117,43 +97,3 @@ impl InterruptController for Gic {
self.interrupt_source_group.notifier(irq as InterruptIndex) self.interrupt_source_group.notifier(irq as InterruptIndex)
} }
} }
pub const GIC_V3_ITS_SNAPSHOT_ID: &str = "gic-v3-its";
impl Snapshottable for Gic {
fn id(&self) -> String {
GIC_V3_ITS_SNAPSHOT_ID.to_string()
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let vgic = self.vgic.as_ref().unwrap().clone();
let state = vgic.lock().unwrap().state().unwrap();
Snapshot::new_from_state(&self.id(), &state)
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
let vgic = self.vgic.as_ref().unwrap().clone();
vgic.lock()
.unwrap()
.set_state(&snapshot.to_state(&self.id())?)
.map_err(|e| {
MigratableError::Restore(anyhow!("Could not restore GICv3ITS state {:?}", e))
})?;
Ok(())
}
}
impl Pausable for Gic {
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
// Flush tables to guest RAM
let vgic = self.vgic.as_ref().unwrap().clone();
vgic.lock().unwrap().save_data_tables().map_err(|e| {
MigratableError::Pause(anyhow!(
"Could not save GICv3ITS GIC pending tables {:?}",
e
))
})?;
Ok(())
}
}
impl Transportable for Gic {}
impl Migratable for Gic {}

View File

@@ -24,8 +24,6 @@ pub enum Error {
UpdateInterrupt(io::Error), UpdateInterrupt(io::Error),
/// Failed enabling the interrupt. /// Failed enabling the interrupt.
EnableInterrupt(io::Error), EnableInterrupt(io::Error),
/// Failed creating GIC device.
CreateGic(hypervisor::HypervisorVmError),
} }
type Result<T> = result::Result<T, Error>; type Result<T> = result::Result<T, Error>;

View File

@@ -1,86 +0,0 @@
// Copyright © 2022 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
use std::fmt;
use std::time::Instant;
use vm_device::BusDevice;
/// Debug I/O port, see:
/// https://www.intel.com/content/www/us/en/support/articles/000005500/boards-and-kits.html
///
/// Since we're not a physical platform, we can freely assign code ranges for
/// debugging specific parts of our virtual platform.
pub enum DebugIoPortRange {
Firmware,
Bootloader,
Kernel,
Userspace,
Custom,
}
#[cfg(target_arch = "x86_64")]
const DEBUG_IOPORT_PREFIX: &str = "Debug I/O port";
#[cfg(target_arch = "x86_64")]
impl DebugIoPortRange {
fn from_u8(value: u8) -> DebugIoPortRange {
match value {
0x00..=0x1f => DebugIoPortRange::Firmware,
0x20..=0x3f => DebugIoPortRange::Bootloader,
0x40..=0x5f => DebugIoPortRange::Kernel,
0x60..=0x7f => DebugIoPortRange::Userspace,
_ => DebugIoPortRange::Custom,
}
}
}
#[cfg(target_arch = "x86_64")]
impl fmt::Display for DebugIoPortRange {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DebugIoPortRange::Firmware => write!(f, "{}: Firmware", DEBUG_IOPORT_PREFIX),
DebugIoPortRange::Bootloader => write!(f, "{}: Bootloader", DEBUG_IOPORT_PREFIX),
DebugIoPortRange::Kernel => write!(f, "{}: Kernel", DEBUG_IOPORT_PREFIX),
DebugIoPortRange::Userspace => write!(f, "{}: Userspace", DEBUG_IOPORT_PREFIX),
DebugIoPortRange::Custom => write!(f, "{}: Custom", DEBUG_IOPORT_PREFIX),
}
}
}
pub struct DebugPort {
timestamp: Instant,
}
impl DebugPort {
pub fn new(timestamp: Instant) -> Self {
Self { timestamp }
}
}
impl BusDevice for DebugPort {
fn read(&mut self, _base: u64, _offset: u64, _data: &mut [u8]) {
error!("Invalid read to debug port")
}
fn write(
&mut self,
_base: u64,
_offset: u64,
data: &[u8],
) -> Option<std::sync::Arc<std::sync::Barrier>> {
let elapsed = self.timestamp.elapsed();
let code = data[0];
warn!(
"[{} code 0x{:x}] {}.{:>06} seconds",
DebugIoPortRange::from_u8(code),
code,
elapsed.as_secs(),
elapsed.as_micros()
);
None
}
}

View File

@@ -6,8 +6,6 @@
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
mod cmos; mod cmos;
#[cfg(target_arch = "x86_64")]
mod debug_port;
#[cfg(feature = "fwdebug")] #[cfg(feature = "fwdebug")]
mod fwdebug; mod fwdebug;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
@@ -20,8 +18,6 @@ mod serial;
mod uart_pl011; mod uart_pl011;
pub use self::cmos::Cmos; pub use self::cmos::Cmos;
#[cfg(target_arch = "x86_64")]
pub use self::debug_port::DebugPort;
#[cfg(feature = "fwdebug")] #[cfg(feature = "fwdebug")]
pub use self::fwdebug::FwDebugDevice; pub use self::fwdebug::FwDebugDevice;
pub use self::i8042::I8042Device; pub use self::i8042::I8042Device;

View File

@@ -10,7 +10,6 @@ use crate::{read_le_u32, write_le_u32};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt; use std::fmt;
use std::sync::{Arc, Barrier}; use std::sync::{Arc, Barrier};
use std::time::Instant;
use std::{io, result}; use std::{io, result};
use versionize::{VersionMap, Versionize, VersionizeResult}; use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize; use versionize_derive::Versionize;
@@ -121,7 +120,6 @@ impl Pl011 {
id: String, id: String,
irq: Arc<dyn InterruptSourceGroup>, irq: Arc<dyn InterruptSourceGroup>,
out: Option<Box<dyn io::Write + Send>>, out: Option<Box<dyn io::Write + Send>>,
timestamp: Instant,
) -> Self { ) -> Self {
Self { Self {
id, id,
@@ -142,7 +140,7 @@ impl Pl011 {
read_trigger: 1u32, read_trigger: 1u32,
irq, irq,
out, out,
timestamp, timestamp: std::time::Instant::now(),
} }
} }
@@ -497,7 +495,6 @@ mod tests {
String::from(SERIAL_NAME), String::from(SERIAL_NAME),
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())), Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
Some(Box::new(pl011_out.clone())), Some(Box::new(pl011_out.clone())),
Instant::now(),
); );
pl011.write(0, UARTDR as u64, &[b'x', b'y']); pl011.write(0, UARTDR as u64, &[b'x', b'y']);
@@ -518,7 +515,6 @@ mod tests {
String::from(SERIAL_NAME), String::from(SERIAL_NAME),
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())), Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
Some(Box::new(pl011_out)), Some(Box::new(pl011_out)),
Instant::now(),
); );
// write 1 to the interrupt event fd, so that read doesn't block in case the event fd // write 1 to the interrupt event fd, so that read doesn't block in case the event fd

View File

@@ -89,7 +89,6 @@ Trigger power button of the VM | `/vm.power-button` | N/A
Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted
Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused
Task a snapshot of the VM | `/vm.snapshot` | `/schemas/VmSnapshotConfig`| N/A | The VM is paused Task a snapshot of the VM | `/vm.snapshot` | `/schemas/VmSnapshotConfig`| N/A | The VM is paused
Perform a coredump of the VM | `/vm.coredump` | `/schemas/VmCoredumpData` | N/A | The VM is paused
Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted
Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted

View File

@@ -6,22 +6,22 @@ This document describes the device model supported by `cloud-hypervisor`.
| Device | Build configurable | Enabled by default | Runtime configurable | | Device | Build configurable | Enabled by default | Runtime configurable |
| :----: | :----: | :----: | :----: | | :----: | :----: | :----: | :----: |
| Serial port | :x: | :x: | :heavy_check_mark: | | Serial port | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
| RTC/CMOS | :heavy_check_mark: | :heavy_check_mark: | :x: | | RTC/CMOS | :heavy_check_mark: | :heavy_check_mark: | :negative_squared_cross_mark: |
| I/O APIC | :x: | :x: | :heavy_check_mark: | | I/O APIC | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
| i8042 shutdown/reboot | :x: | :x: | :x: | | i8042 shutdown/reboot | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :negative_squared_cross_mark: |
| ACPI shutdown/reboot | :x: | :heavy_check_mark: | :x: | | ACPI shutdown/reboot | :negative_squared_cross_mark: | :heavy_check_mark: | :negative_squared_cross_mark: |
| virtio-blk | :x: | :x: | :heavy_check_mark: | | virtio-blk | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
| virtio-console | :x: | :x: | :heavy_check_mark: | | virtio-console | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
| virtio-iommu | :x: | :x: | :heavy_check_mark: | | virtio-iommu | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
| virtio-net | :x: | :x: | :heavy_check_mark: | | virtio-net | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
| virtio-pmem | :x: | :x: | :heavy_check_mark: | | virtio-pmem | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
| virtio-rng | :x: | :x: | :heavy_check_mark: | | virtio-rng | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
| virtio-vsock | :x: | :x: | :heavy_check_mark: | | virtio-vsock | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
| vhost-user-blk | :x: | :x: | :heavy_check_mark: | | vhost-user-blk | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
| vhost-user-fs | :x: | :x: | :heavy_check_mark: | | vhost-user-fs | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
| vhost-user-net | :x: | :x: | :heavy_check_mark: | | vhost-user-net | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
| VFIO | :heavy_check_mark: | :x: | :heavy_check_mark: | | VFIO | :heavy_check_mark: | :negative_squared_cross_mark: | :heavy_check_mark: |
## Legacy devices ## Legacy devices

View File

@@ -43,22 +43,3 @@ $ perf report -g
``` ```
If profiling with a network device attached either the TAP device must be already created and configured or the profiling must be done as root so that the TAP device can be created. If profiling with a network device attached either the TAP device must be already created and configured or the profiling must be done as root so that the TAP device can be created.
## Userspace only profiling with LBR
The use of LBR (Last Branch Record; available since Haswell) offers lower
overhead if only userspace profiling is required. This lower overhead can allow
a higher frequency of sampling. This also removes the requirement to compile
with custom `RUSTFLAGS` however debug symbols should still be included:
e.g.
```
$ perf record --call-graph lbr --all-user --user-callchains -g target/release/cloud-hypervisor \
--kernel ~/src/linux/vmlinux \
--pmem file=~/workloads/focal.raw \
--cpus boot=1 --memory size=1G \
--cmdline "root=/dev/pmem0p1 console=ttyS0" \
--serial tty --console off \
--api-socket=/tmp/api1
```

View File

@@ -1,103 +0,0 @@
# Release Documentation
## Abstract
This document provides guidance to users, downstream maintainers and
any other consumers of the Cloud Hypervisor project, this document
describes the release process, release cadence, stability expectations and
related topics.
## Basic Terms
### Stability
For Cloud Hypervisor the following areas are subject to stability guarantees:
- [REST API](api.md#rest-api)
- [Command line options](api.md#command-line-interface)
- [Device Model](device_model.md)
- Device tree, device list, ACPI, Hyper-V enlightenments and any other
features exposed to guest
- KVM compatibility
- Rust edition compatibility
This list is incomplete but this document serves as a best effort guide to stability
across releases.
### Experimental features
Experimental features are under active development and no guarantees are made about their stability.
List of experimental features:
- TDX
- vfio-user
- vDPA
### Security
Security fixes should be included in a new point release.
For security issues an advisory will be published via the GitHub security advisory process along with the release. Watching the project on GitHub will notify you of those issues.
## Releases
### Versioning
The versioning scheme uses `MAJOR.POINT` pattern:
- `MAJOR` can introduce incompatible changes along with support for new features. Changes to the [API](api.md#rest-api),
[CLI options](api.md#command-line-interface) and [device model](device_model.md)
require a notice at least 2 releases in advance for the actual change to take
place.
- `POINT` contains bug fixes and/or security fixes.
### Major Release Cadence
Cloud Hypervisor is under active development. A new major release is issued approximately
every 6 weeks. Point releases are issued on demand, when important bug fixes are in
the queue. A major release would receive bug fixes for the next two cycles (~12 weeks)
and then be considered EOL.
```
+ - Active release support
E - EOL
2021 2022 2023
| | | | | | | | |
18.0 | | | ++++++++E
19.0 | | | |++++++++E
20.0 | | | | ++++++++E
21.0 | | | | | ++++++++E
22.0 | | | | | +++++++++E
23.0 | | | | | | +++++++++E
```
### Major Release Stability Considerations
Snapshot/restore support is not compatible across `MAJOR` versions.
Live migration support is not compatible across `MAJOR` versions.
### LTS Release Cadence
A regular release is promoted to LTS every 12 months. An LTS release is supported for 18 months. This gives a 6 months window for users to move to the new LTS.
```
+ - Active release support
E - EOL
2022 2023 2024 2025 2026
| | | | | | | | | | | | | | | | |
23.0 | |+++++++++++++++++++++++++++++E
43.0 | | | | | |+++++++++++++++++++++++++++++E
63.0 | | | | | | | | | |+++++++++++++++++++++++++++++E
```
### LTS Stablity Considerations
An LTS release is just a `MAJOR` release for which point releases are made for
longer following the same rules for what can be backported to a `POINT` release.
The focus lays on critical and security bug fixes which are pulled at the
maintainer's discretion.

View File

@@ -75,7 +75,8 @@ Here is an example how to create a bridge and add two DPDK ports to it
ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev
# create two DPDK ports and add them to the bridge # create two DPDK ports and add them to the bridge
ovs-vsctl add-port ovsbr0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuser ovs-vsctl add-port ovsbr0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuser
ovs-vsctl add-port ovsbr0 vhost-user2 -- set Interface vhost-user2 type=dpdkvhostuser ovs-vsctl add-port ovsbr0 vhost-user2 -- set Interface vhost-user2
type=dpdkvhostuser
# set the number of rx queues # set the number of rx queues
ovs-vsctl set Interface vhost-user1 options:n_rxq=2 ovs-vsctl set Interface vhost-user1 options:n_rxq=2
ovs-vsctl set Interface vhost-user2 options:n_rxq=2 ovs-vsctl set Interface vhost-user2 options:n_rxq=2

View File

@@ -5,6 +5,7 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
libc = "0.2.126" libc = "0.2.123"
serde = { version = "1.0.138", features = ["rc", "derive"] } serde = { version = "1.0.136", features = ["rc"] }
serde_json = "1.0.82" serde_derive = "1.0.136"
serde_json = "1.0.79"

View File

@@ -3,11 +3,12 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
use serde::Serialize; #[macro_use]
extern crate serde_derive;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::io::Write;
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@@ -49,9 +50,6 @@ pub fn event_log(source: &str, event: &str, properties: Option<&HashMap<Cow<str>
properties, properties,
}; };
serde_json::to_writer_pretty(file, &e).ok(); serde_json::to_writer_pretty(file, &e).ok();
let mut file = file;
file.write_all(b"\n\n").ok();
} }
} }

208
fuzz/Cargo.lock generated
View File

@@ -11,9 +11,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.58" version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
[[package]] [[package]]
name = "api_client" name = "api_client"
@@ -24,9 +24,9 @@ dependencies = [
[[package]] [[package]]
name = "arbitrary" name = "arbitrary"
version = "1.1.3" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60" checksum = "c38b6b6b79f671c25e1a3e785b7b82d7562ffc9cd3efdc98627e5668a2472490"
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
@@ -47,6 +47,7 @@ dependencies = [
"linux-loader", "linux-loader",
"log", "log",
"serde", "serde",
"serde_derive",
"thiserror", "thiserror",
"versionize", "versionize",
"versionize_derive", "versionize_derive",
@@ -127,33 +128,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.2.8" version = "3.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83" checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
dependencies = [ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
"clap_lex",
"indexmap", "indexmap",
"once_cell", "lazy_static",
"os_str_bytes",
"strsim", "strsim",
"termcolor", "termcolor",
"terminal_size", "terminal_size",
"textwrap", "textwrap",
] ]
[[package]]
name = "clap_lex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
[[package]] [[package]]
name = "cloud-hypervisor" name = "cloud-hypervisor"
version = "24.0.0" version = "22.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"api_client", "api_client",
@@ -216,7 +208,6 @@ dependencies = [
"bitflags", "bitflags",
"byteorder", "byteorder",
"epoll", "epoll",
"hypervisor",
"libc", "libc",
"log", "log",
"versionize", "versionize",
@@ -243,6 +234,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"libc", "libc",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
] ]
@@ -253,10 +245,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e" checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
[[package]] [[package]]
name = "getrandom" name = "gdbstub"
version = "0.2.7" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" checksum = "9fa2ca5d6b045de372cef3991f873389b421b4cabcfbe52f7787fae8b8b37906"
dependencies = [
"bitflags",
"cfg-if",
"log",
"managed",
"num-traits",
"paste",
]
[[package]]
name = "gdbstub_arch"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51dc4b5718ac76d21e8605c0966dd32d80273b89b11e6cfef467b04e45934d37"
dependencies = [
"gdbstub",
"num-traits",
]
[[package]]
name = "getrandom"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@@ -265,9 +281,9 @@ dependencies = [
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.12.1" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
@@ -290,6 +306,7 @@ dependencies = [
"libc", "libc",
"log", "log",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
"thiserror", "thiserror",
"vm-memory", "vm-memory",
@@ -308,9 +325,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.9.1" version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@@ -328,9 +345,9 @@ dependencies = [
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.2" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]] [[package]]
name = "kvm-bindings" name = "kvm-bindings"
@@ -360,9 +377,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.126" version = "0.2.123"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd"
[[package]] [[package]]
name = "libfuzzer-sys" name = "libfuzzer-sys"
@@ -386,13 +403,25 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.17" version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "managed"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]] [[package]]
name = "micro_http" name = "micro_http"
version = "0.1.0" version = "0.1.0"
@@ -430,10 +459,19 @@ dependencies = [
] ]
[[package]] [[package]]
name = "once_cell" name = "num-traits"
version = "1.13.0" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]] [[package]]
name = "option_parser" name = "option_parser"
@@ -441,9 +479,18 @@ version = "0.1.0"
[[package]] [[package]]
name = "os_str_bytes" name = "os_str_bytes"
version = "6.1.0" version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]]
name = "paste"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
[[package]] [[package]]
name = "pci" name = "pci"
@@ -455,6 +502,7 @@ dependencies = [
"libc", "libc",
"log", "log",
"serde", "serde",
"serde_derive",
"thiserror", "thiserror",
"versionize", "versionize",
"versionize_derive", "versionize_derive",
@@ -470,11 +518,11 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.40" version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
dependencies = [ dependencies = [
"unicode-ident", "unicode-xid",
] ]
[[package]] [[package]]
@@ -490,9 +538,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.20" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -508,9 +556,9 @@ dependencies = [
[[package]] [[package]]
name = "remain" name = "remain"
version = "0.2.3" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c35270ea384ac1762895831cc8acb96f171468e52cec82ed9186f9416209fa4" checksum = "70ba1e78fa68412cb93ef642fd4d20b9a941be49ee9333875ebaf13112673ea7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -528,9 +576,9 @@ dependencies = [
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.10" version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]] [[package]]
name = "seccompiler" name = "seccompiler"
@@ -543,24 +591,21 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.12" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.138" version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.138" version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -569,9 +614,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.82" version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@@ -580,9 +625,9 @@ dependencies = [
[[package]] [[package]]
name = "signal-hook" name = "signal-hook"
version = "0.3.14" version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
dependencies = [ dependencies = [
"libc", "libc",
"signal-hook-registry", "signal-hook-registry",
@@ -611,13 +656,13 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.98" version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"unicode-ident", "unicode-xid",
] ]
[[package]] [[package]]
@@ -650,18 +695,18 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.31" version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.31" version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -669,16 +714,16 @@ dependencies = [
] ]
[[package]] [[package]]
name = "unicode-ident" name = "unicode-xid"
version = "1.0.1" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.1.2" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [ dependencies = [
"getrandom", "getrandom",
] ]
@@ -802,6 +847,7 @@ dependencies = [
"rate_limiter", "rate_limiter",
"seccompiler", "seccompiler",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
"thiserror", "thiserror",
"versionize", "versionize",
@@ -819,9 +865,9 @@ dependencies = [
[[package]] [[package]]
name = "virtio-queue" name = "virtio-queue"
version = "0.3.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88f2d73c184c18f8acc32dab77fcb6e3af92d53262538d3a68aa474810d6863c" checksum = "3785325315e6496fa88673842ee6cd198b9658e88e8b0e1ad48a5dc818b221dc"
dependencies = [ dependencies = [
"log", "log",
"vm-memory", "vm-memory",
@@ -842,8 +888,8 @@ name = "vm-device"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"hypervisor",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
"thiserror", "thiserror",
"vfio-ioctls", "vfio-ioctls",
@@ -858,9 +904,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#720e48e435b791ec6cb
[[package]] [[package]]
name = "vm-memory" name = "vm-memory"
version = "0.8.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "767ed8aaebbff902e02e6d3749dc2baef55e46565f8a6414a065e5baee4b4a81" checksum = "339d4349c126fdcd87e034631d7274370cf19eb0e87b33166bcd956589fc72c5"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"libc", "libc",
@@ -873,6 +919,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
"thiserror", "thiserror",
"versionize", "versionize",
@@ -904,18 +951,21 @@ dependencies = [
"devices", "devices",
"epoll", "epoll",
"event_monitor", "event_monitor",
"gdbstub",
"gdbstub_arch",
"hypervisor", "hypervisor",
"lazy_static",
"libc", "libc",
"linux-loader", "linux-loader",
"log", "log",
"micro_http", "micro_http",
"net_util", "net_util",
"once_cell",
"option_parser", "option_parser",
"pci", "pci",
"qcow", "qcow",
"seccompiler", "seccompiler",
"serde", "serde",
"serde_derive",
"serde_json", "serde_json",
"signal-hook", "signal-hook",
"thiserror", "thiserror",
@@ -949,9 +999,9 @@ dependencies = [
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]] [[package]]
name = "winapi" name = "winapi"

View File

@@ -10,16 +10,16 @@ cargo-fuzz = true
[dependencies] [dependencies]
block_util = { path = "../block_util" } block_util = { path = "../block_util" }
libc = "0.2.126" libc = "0.2.123"
libfuzzer-sys = "0.4.3" libfuzzer-sys = "0.4.3"
qcow = { path = "../qcow" } qcow = { path = "../qcow" }
seccompiler = "0.2.0" seccompiler = "0.2.0"
vhdx = { path = "../vhdx" } vhdx = { path = "../vhdx" }
virtio-devices = { path = "../virtio-devices" } virtio-devices = { path = "../virtio-devices" }
virtio-queue = "0.4.0" virtio-queue = "0.2.0"
vmm-sys-util = "0.9.0" vmm-sys-util = "0.9.0"
vm-virtio = { path = "../vm-virtio" } vm-virtio = { path = "../vm-virtio" }
vm-memory = "0.8.0" vm-memory = "0.7.0"
[dependencies.cloud-hypervisor] [dependencies.cloud-hypervisor]
path = ".." path = ".."

View File

@@ -11,18 +11,19 @@ mshv = ["mshv-ioctls", "mshv-bindings"]
tdx = [] tdx = []
[dependencies] [dependencies]
anyhow = "1.0.58" anyhow = "1.0.56"
epoll = "4.3.1" epoll = "4.3.1"
thiserror = "1.0.31" thiserror = "1.0.30"
libc = "0.2.126" libc = "0.2.123"
log = "0.4.17" log = "0.4.16"
kvm-ioctls = { version = "0.11.0", optional = true } kvm-ioctls = { version = "0.11.0", optional = true }
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true } kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true } mshv-bindings = {git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true} mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
serde = { version = "1.0.138", features = ["rc", "derive"] } serde = { version = "1.0.136", features = ["rc"] }
serde_json = "1.0.82" serde_derive = "1.0.136"
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic"] } serde_json = "1.0.79"
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic"] }
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] } vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86] [target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]

View File

@@ -1,59 +0,0 @@
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
use crate::{CpuState, Device, GicState, HypervisorDeviceError, HypervisorVmError};
use std::any::Any;
use std::result;
use std::sync::Arc;
/// Errors thrown while setting up the VGIC.
#[derive(Debug)]
pub enum Error {
/// Error while calling KVM ioctl for setting up the global interrupt controller.
CreateGic(HypervisorVmError),
/// Error while setting device attributes for the GIC.
SetDeviceAttribute(HypervisorDeviceError),
/// Error while getting device attributes for the GIC.
GetDeviceAttribute(HypervisorDeviceError),
}
pub type Result<T> = result::Result<T, Error>;
/// Hypervisor agnostic interface for a virtualized GIC
pub trait Vgic: Send + Sync {
/// Returns the fdt compatibility property of the device
fn fdt_compatibility(&self) -> &str;
/// Returns the maint_irq fdt property of the device
fn fdt_maint_irq(&self) -> u32;
/// Returns an array with GIC device properties
fn device_properties(&self) -> [u64; 4];
/// Returns the number of vCPUs this GIC handles
fn vcpu_count(&self) -> u64;
/// Returns whether the GIC device is MSI compatible or not
fn msi_compatible(&self) -> bool;
/// Returns the MSI compatibility property of the device
fn msi_compatibility(&self) -> &str;
/// Returns the MSI reg property of the device
fn msi_properties(&self) -> [u64; 2];
fn set_its_device(&mut self, its_device: Option<Arc<dyn Device>>);
/// Get the values of GICR_TYPER for each vCPU.
fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]);
/// Downcast the trait object to its concrete type.
fn as_any_concrete_mut(&mut self) -> &mut dyn Any;
/// Save the state of GICv3ITS.
fn state(&self) -> Result<GicState>;
/// Restore the state of GICv3ITS.
fn set_state(&mut self, state: &GicState) -> Result<()>;
/// Saves GIC internal data tables into RAM.
fn save_data_tables(&self) -> Result<()>;
}

View File

@@ -1,3 +0,0 @@
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
pub mod gic;

View File

@@ -99,7 +99,7 @@ pub enum EmulationError<T: Debug> {
/// A CpuState is an architecture specific type, representing a CPU state. /// A CpuState is an architecture specific type, representing a CPU state.
/// The emulator and its instruction handlers modify a given CPU state and /// The emulator and its instruction handlers modify a given CPU state and
/// eventually ask the platform to commit it back through `set_cpu_state`. /// eventually ask the platform to commit it back through `set_cpu_state`.
pub trait PlatformEmulator { pub trait PlatformEmulator: Send + Sync {
type CpuState: Clone; type CpuState: Clone;
/// Read guest memory into a u8 slice. /// Read guest memory into a u8 slice.

View File

@@ -10,14 +10,9 @@
// //
// Copyright © 2020, Microsoft Corporation // Copyright © 2020, Microsoft Corporation
// //
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
//
pub mod emulator; pub mod emulator;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
#[macro_use] #[macro_use]
pub mod x86; pub mod x86;
#[cfg(target_arch = "aarch64")]
pub mod aarch64;

View File

@@ -28,11 +28,14 @@ fn get_op<T: CpuStateManager>(
))); )));
} }
if !matches!(op_size, 1 | 2 | 4 | 8) { match op_size {
return Err(PlatformError::InvalidOperand(anyhow!( 1 | 2 | 4 | 8 => {}
"Invalid operand size {:?}", _ => {
op_size return Err(PlatformError::InvalidOperand(anyhow!(
))); "Invalid operand size {:?}",
op_size
)))
}
} }
let value = match insn let value = match insn
@@ -78,11 +81,14 @@ fn set_op<T: CpuStateManager>(
))); )));
} }
if !matches!(op_size, 1 | 2 | 4 | 8) { match op_size {
return Err(PlatformError::InvalidOperand(anyhow!( 1 | 2 | 4 | 8 => {}
"Invalid operand size {:?}", _ => {
op_size return Err(PlatformError::InvalidOperand(anyhow!(
))); "Invalid operand size {:?}",
op_size
)))
}
} }
match insn match insn

View File

@@ -6,8 +6,9 @@
use crate::arch::emulator::{EmulationError, EmulationResult, PlatformEmulator, PlatformError}; use crate::arch::emulator::{EmulationError, EmulationResult, PlatformEmulator, PlatformError};
use crate::arch::x86::emulator::instructions::*; use crate::arch::x86::emulator::instructions::*;
use crate::arch::x86::regs::{CR0_PE, EFER_LMA}; use crate::arch::x86::regs::*;
use crate::arch::x86::{segment_type_expand_down, segment_type_ro, Exception, SegmentRegisterOps}; use crate::arch::x86::*;
use crate::arch::x86::{Exception, SegmentRegisterOps};
use crate::x86_64::{SegmentRegister, SpecialRegisters, StandardRegisters}; use crate::x86_64::{SegmentRegister, SpecialRegisters, StandardRegisters};
use anyhow::Context; use anyhow::Context;
use iced_x86::*; use iced_x86::*;
@@ -16,7 +17,7 @@ use iced_x86::*;
mod instructions; mod instructions;
/// x86 CPU modes /// x86 CPU modes
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq)]
pub enum CpuMode { pub enum CpuMode {
/// Real mode /// Real mode
Real, Real,

View File

@@ -12,12 +12,6 @@
use crate::aarch64::VcpuInit; use crate::aarch64::VcpuInit;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use crate::aarch64::{RegList, Register, StandardRegisters}; use crate::aarch64::{RegList, Register, StandardRegisters};
#[cfg(feature = "tdx")]
use crate::kvm::{TdxExitDetails, TdxExitStatus};
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
use crate::x86_64::SuspendRegisters;
#[cfg(target_arch = "x86_64")]
use crate::x86_64::Xsave;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::x86_64::{CpuId, LapicState}; use crate::x86_64::{CpuId, LapicState};
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@@ -29,6 +23,12 @@ use crate::CpuState;
use crate::DeviceAttr; use crate::DeviceAttr;
#[cfg(feature = "kvm")] #[cfg(feature = "kvm")]
use crate::MpState; use crate::MpState;
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
use crate::SuspendRegisters;
#[cfg(target_arch = "x86_64")]
use crate::Xsave;
#[cfg(feature = "tdx")]
use crate::{TdxExitDetails, TdxExitStatus};
use thiserror::Error; use thiserror::Error;
#[cfg(all(feature = "kvm", target_arch = "x86_64"))] #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
use vm_memory::GuestAddress; use vm_memory::GuestAddress;
@@ -453,11 +453,6 @@ pub trait Vcpu: Send + Sync {
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
fn read_mpidr(&self) -> Result<u64>; fn read_mpidr(&self) -> Result<u64>;
/// ///
/// Configure core registers for a given CPU.
///
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> Result<()>;
///
/// Retrieve the vCPU state. /// Retrieve the vCPU state.
/// This function is necessary to snapshot the VM /// This function is necessary to snapshot the VM
/// ///

View File

@@ -7,13 +7,13 @@
// Copyright 2018-2019 CrowdStrike, Inc. // Copyright 2018-2019 CrowdStrike, Inc.
// //
// //
#[cfg(feature = "tdx")]
use crate::kvm::TdxCapabilities;
use crate::vm::Vm; use crate::vm::Vm;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::x86_64::CpuId; use crate::x86_64::CpuId;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::x86_64::MsrList; use crate::x86_64::MsrList;
#[cfg(feature = "tdx")]
use crate::TdxCapabilities;
use std::sync::Arc; use std::sync::Arc;
use thiserror::Error; use thiserror::Error;
@@ -66,11 +66,6 @@ pub enum HypervisorError {
/// ///
#[error("Failed to retrieve TDX capabilities:{0}")] #[error("Failed to retrieve TDX capabilities:{0}")]
TdxCapabilities(#[source] anyhow::Error), TdxCapabilities(#[source] anyhow::Error),
///
/// Failed to set partition property
///
#[error("Failed to set partition property:{0}")]
SetPartitionProperty(#[source] anyhow::Error),
} }
/// ///

View File

@@ -1,615 +0,0 @@
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
mod dist_regs;
mod icc_regs;
mod redist_regs;
use crate::arch::aarch64::gic::{Error, Result, Vgic};
use crate::kvm::kvm_bindings;
use crate::{CpuState, Device, Vm};
use dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
use icc_regs::{get_icc_regs, set_icc_regs};
use redist_regs::{construct_gicr_typers, get_redist_regs, set_redist_regs};
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::convert::TryInto;
use std::sync::Arc;
const GITS_CTLR: u32 = 0x0000;
const GITS_IIDR: u32 = 0x0004;
const GITS_CBASER: u32 = 0x0080;
const GITS_CWRITER: u32 = 0x0088;
const GITS_CREADR: u32 = 0x0090;
const GITS_BASER: u32 = 0x0100;
/// Access an ITS device attribute.
///
/// This is a helper function to get/set the ITS device attribute depending
/// the bool parameter `set` provided.
pub fn gicv3_its_attr_access(
its_device: &Arc<dyn Device>,
group: u32,
attr: u32,
val: &u64,
set: bool,
) -> Result<()> {
let mut gicv3_its_attr = kvm_bindings::kvm_device_attr {
group,
attr: attr as u64,
addr: val as *const u64 as u64,
flags: 0,
};
if set {
its_device
.set_device_attr(&gicv3_its_attr)
.map_err(Error::SetDeviceAttribute)
} else {
its_device
.get_device_attr(&mut gicv3_its_attr)
.map_err(Error::GetDeviceAttribute)
}
}
/// Function that saves/restores ITS tables into guest RAM.
///
/// The tables get flushed to guest RAM whenever the VM gets stopped.
pub fn gicv3_its_tables_access(its_device: &Arc<dyn Device>, save: bool) -> Result<()> {
let attr = if save {
u64::from(kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES)
} else {
u64::from(kvm_bindings::KVM_DEV_ARM_ITS_RESTORE_TABLES)
};
let init_gic_attr = kvm_bindings::kvm_device_attr {
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
attr,
addr: 0,
flags: 0,
};
its_device
.set_device_attr(&init_gic_attr)
.map_err(Error::SetDeviceAttribute)
}
pub struct KvmGicV3Its {
/// The hypervisor agnostic device for the GicV3
device: Arc<dyn Device>,
/// The hypervisor agnostic device for the Its device
its_device: Option<Arc<dyn Device>>,
/// Vector holding values of GICR_TYPER for each vCPU
gicr_typers: Vec<u64>,
/// GIC distributor address
dist_addr: u64,
/// GIC distributor size
dist_size: u64,
/// GIC distributors address
redists_addr: u64,
/// GIC distributors size
redists_size: u64,
/// GIC MSI address
msi_addr: u64,
/// GIC MSI size
msi_size: u64,
/// Number of CPUs handled by the device
vcpu_count: u64,
}
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct Gicv3ItsState {
dist: Vec<u32>,
rdist: Vec<u32>,
icc: Vec<u32>,
// special register that enables interrupts and affinity routing
gicd_ctlr: u32,
its_ctlr: u64,
its_iidr: u64,
its_cbaser: u64,
its_cwriter: u64,
its_creadr: u64,
its_baser: [u64; 8],
}
impl KvmGicV3Its {
/// Device trees specific constants
pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9;
/// Returns the GIC version of the device
fn version() -> u32 {
kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3
}
fn device(&self) -> &Arc<dyn Device> {
&self.device
}
fn its_device(&self) -> Option<&Arc<dyn Device>> {
self.its_device.as_ref()
}
/// Setup the device-specific attributes
fn init_device_attributes(&mut self, vm: &dyn Vm, nr_irqs: u32) -> Result<()> {
// GicV3 part attributes
/* Setting up the distributor attribute.
We are placing the GIC below 1GB so we need to substract the size of the distributor.
*/
Self::set_device_attribute(
self.device(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_DIST),
&self.dist_addr as *const u64 as u64,
0,
)?;
/* Setting up the redistributors' attribute.
We are calculating here the start of the redistributors address. We have one per CPU.
*/
Self::set_device_attribute(
self.device(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_REDIST),
&self.redists_addr as *const u64 as u64,
0,
)?;
// ITS part attributes
let mut its_device = kvm_bindings::kvm_create_device {
type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS,
fd: 0,
flags: 0,
};
let its_fd = vm
.create_device(&mut its_device)
.map_err(Error::CreateGic)?;
Self::set_device_attribute(
&its_fd,
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
u64::from(kvm_bindings::KVM_VGIC_ITS_ADDR_TYPE),
&self.msi_addr as *const u64 as u64,
0,
)?;
Self::set_device_attribute(
&its_fd,
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
0,
0,
)?;
self.set_its_device(Some(its_fd));
/* We need to tell the kernel how many irqs to support with this vgic.
* See the `layout` module for details.
*/
let nr_irqs_ptr = &nr_irqs as *const u32;
Self::set_device_attribute(
self.device(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
0,
nr_irqs_ptr as u64,
0,
)?;
/* Finalize the GIC.
* See https://code.woboq.org/linux/linux/virt/kvm/arm/vgic/vgic-kvm-device.c.html#211.
*/
Self::set_device_attribute(
self.device(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
0,
0,
)
}
/// Create a KVM Vgic device
fn create_device(vm: &dyn Vm) -> Result<Arc<dyn Device>> {
let mut gic_device = kvm_bindings::kvm_create_device {
type_: Self::version(),
fd: 0,
flags: 0,
};
vm.create_device(&mut gic_device).map_err(Error::CreateGic)
}
/// Set a GIC device attribute
fn set_device_attribute(
device: &Arc<dyn Device>,
group: u32,
attr: u64,
addr: u64,
flags: u32,
) -> Result<()> {
let attr = kvm_bindings::kvm_device_attr {
flags,
group,
attr,
addr,
};
device
.set_device_attr(&attr)
.map_err(Error::SetDeviceAttribute)
}
/// Method to initialize the GIC device
#[allow(clippy::new_ret_no_self)]
pub fn new(
vm: &dyn Vm,
vcpu_count: u64,
dist_addr: u64,
dist_size: u64,
redist_size: u64,
msi_size: u64,
nr_irqs: u32,
) -> Result<KvmGicV3Its> {
let vgic = Self::create_device(vm)?;
let redists_size: u64 = redist_size * vcpu_count;
let redists_addr: u64 = dist_addr - redists_size;
let msi_addr: u64 = redists_addr - msi_size;
let mut gic_device = KvmGicV3Its {
device: vgic,
its_device: None,
gicr_typers: vec![0; vcpu_count.try_into().unwrap()],
dist_addr,
dist_size,
redists_addr,
redists_size,
msi_addr,
msi_size,
vcpu_count,
};
gic_device.init_device_attributes(vm, nr_irqs)?;
Ok(gic_device)
}
}
impl Vgic for KvmGicV3Its {
fn fdt_compatibility(&self) -> &str {
"arm,gic-v3"
}
fn msi_compatible(&self) -> bool {
true
}
fn msi_compatibility(&self) -> &str {
"arm,gic-v3-its"
}
fn fdt_maint_irq(&self) -> u32 {
KvmGicV3Its::ARCH_GIC_V3_MAINT_IRQ
}
fn vcpu_count(&self) -> u64 {
self.vcpu_count
}
fn device_properties(&self) -> [u64; 4] {
[
self.dist_addr,
self.dist_size,
self.redists_addr,
self.redists_size,
]
}
fn msi_properties(&self) -> [u64; 2] {
[self.msi_addr, self.msi_size]
}
fn set_its_device(&mut self, its_device: Option<Arc<dyn Device>>) {
self.its_device = its_device;
}
fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
let gicr_typers = construct_gicr_typers(vcpu_states);
self.gicr_typers = gicr_typers;
}
fn as_any_concrete_mut(&mut self) -> &mut dyn Any {
self
}
/// Save the state of GICv3ITS.
fn state(&self) -> Result<Gicv3ItsState> {
let gicr_typers = self.gicr_typers.clone();
let gicd_ctlr = read_ctlr(self.device())?;
let dist_state = get_dist_regs(self.device())?;
let rdist_state = get_redist_regs(self.device(), &gicr_typers)?;
let icc_state = get_icc_regs(self.device(), &gicr_typers)?;
let its_baser_state: [u64; 8] = [0; 8];
for i in 0..8 {
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_BASER + i * 8,
&its_baser_state[i as usize],
false,
)?;
}
let its_ctlr_state: u64 = 0;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CTLR,
&its_ctlr_state,
false,
)?;
let its_cbaser_state: u64 = 0;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CBASER,
&its_cbaser_state,
false,
)?;
let its_creadr_state: u64 = 0;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CREADR,
&its_creadr_state,
false,
)?;
let its_cwriter_state: u64 = 0;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CWRITER,
&its_cwriter_state,
false,
)?;
let its_iidr_state: u64 = 0;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_IIDR,
&its_iidr_state,
false,
)?;
Ok(Gicv3ItsState {
dist: dist_state,
rdist: rdist_state,
icc: icc_state,
gicd_ctlr,
its_ctlr: its_ctlr_state,
its_iidr: its_iidr_state,
its_cbaser: its_cbaser_state,
its_cwriter: its_cwriter_state,
its_creadr: its_creadr_state,
its_baser: its_baser_state,
})
}
/// Restore the state of GICv3ITS.
fn set_state(&mut self, state: &Gicv3ItsState) -> Result<()> {
let gicr_typers = self.gicr_typers.clone();
write_ctlr(self.device(), state.gicd_ctlr)?;
set_dist_regs(self.device(), &state.dist)?;
set_redist_regs(self.device(), &gicr_typers, &state.rdist)?;
set_icc_regs(self.device(), &gicr_typers, &state.icc)?;
//Restore GICv3ITS registers
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_IIDR,
&state.its_iidr,
true,
)?;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CBASER,
&state.its_cbaser,
true,
)?;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CREADR,
&state.its_creadr,
true,
)?;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CWRITER,
&state.its_cwriter,
true,
)?;
for i in 0..8 {
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_BASER + i * 8,
&state.its_baser[i as usize],
true,
)?;
}
// Restore ITS tables
gicv3_its_tables_access(self.its_device().unwrap(), false)?;
gicv3_its_attr_access(
self.its_device().unwrap(),
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
GITS_CTLR,
&state.its_ctlr,
true,
)
}
/// Saves GIC internal data tables into RAM, including:
/// - RDIST pending tables
/// - ITS tables into guest RAM.
fn save_data_tables(&self) -> Result<()> {
// Flash RDIST pending tables
let init_gic_attr = kvm_bindings::kvm_device_attr {
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
attr: u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES),
addr: 0,
flags: 0,
};
self.device()
.set_device_attr(&init_gic_attr)
.map_err(Error::SetDeviceAttribute)?;
// Flush ITS tables to guest RAM.
gicv3_its_tables_access(self.its_device().unwrap(), true)
}
}
#[cfg(test)]
mod tests {
use crate::aarch64::gic::{
get_dist_regs, get_icc_regs, get_redist_regs, set_dist_regs, set_icc_regs, set_redist_regs,
};
use crate::kvm::KvmGicV3Its;
#[test]
fn test_create_gic() {
let hv = crate::new().unwrap();
let vm = hv.create_vm().unwrap();
assert!(KvmGicV3Its::new(
&*vm,
1,
0x0900_0000 - 0x01_0000,
0x01_0000,
0x02_0000,
0x02_0000,
256
)
.is_ok());
}
#[test]
fn test_get_set_dist_regs() {
let hv = crate::new().unwrap();
let vm = hv.create_vm().unwrap();
let _ = vm.create_vcpu(0, None).unwrap();
let gic = KvmGicV3Its::new(
&*vm,
1,
0x0900_0000 - 0x01_0000,
0x01_0000,
0x02_0000,
0x02_0000,
256,
)
.expect("Cannot create gic");
let res = get_dist_regs(gic.device());
assert!(res.is_ok());
let state = res.unwrap();
assert_eq!(state.len(), 568);
let res = set_dist_regs(gic.device(), &state);
assert!(res.is_ok());
}
#[test]
fn test_get_set_redist_regs() {
let hv = crate::new().unwrap();
let vm = hv.create_vm().unwrap();
let _ = vm.create_vcpu(0, None).unwrap();
let gic = KvmGicV3Its::new(
&*vm,
1,
0x0900_0000 - 0x01_0000,
0x01_0000,
0x02_0000,
0x02_0000,
256,
)
.expect("Cannot create gic");
let gicr_typer = vec![123];
let res = get_redist_regs(gic.device(), &gicr_typer);
assert!(res.is_ok());
let state = res.unwrap();
println!("{}", state.len());
assert!(state.len() == 24);
assert!(set_redist_regs(gic.device(), &gicr_typer, &state).is_ok());
}
#[test]
fn test_get_set_icc_regs() {
let hv = crate::new().unwrap();
let vm = hv.create_vm().unwrap();
let _ = vm.create_vcpu(0, None).unwrap();
let gic = KvmGicV3Its::new(
&*vm,
1,
0x0900_0000 - 0x01_0000,
0x01_0000,
0x02_0000,
0x02_0000,
256,
)
.expect("Cannot create gic");
let gicr_typer = vec![123];
let res = get_icc_regs(gic.device(), &gicr_typer);
assert!(res.is_ok());
let state = res.unwrap();
println!("{}", state.len());
assert!(state.len() == 9);
assert!(set_icc_regs(gic.device(), &gicr_typer, &state).is_ok());
}
#[test]
fn test_save_data_tables() {
let hv = crate::new().unwrap();
let vm = hv.create_vm().unwrap();
let _ = vm.create_vcpu(0, None).unwrap();
let gic = vm
.create_vgic(
1,
0x0900_0000 - 0x01_0000,
0x01_0000,
0x02_0000,
0x02_0000,
256,
)
.expect("Cannot create gic");
assert!(gic.lock().unwrap().save_data_tables().is_ok());
}
}

View File

@@ -8,8 +8,9 @@
// //
// //
pub mod gic; ///
/// Export generically-named wrappers of kvm-bindings for Unix-based platforms
///
use crate::kvm::{KvmError, KvmResult}; use crate::kvm::{KvmError, KvmResult};
use kvm_bindings::{ use kvm_bindings::{
kvm_mp_state, kvm_one_reg, kvm_regs, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG, kvm_mp_state, kvm_one_reg, kvm_regs, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG,
@@ -22,7 +23,7 @@ use kvm_bindings::{
pub use kvm_bindings::{ pub use kvm_bindings::{
kvm_one_reg as Register, kvm_regs as StandardRegisters, kvm_vcpu_init as VcpuInit, RegList, kvm_one_reg as Register, kvm_regs as StandardRegisters, kvm_vcpu_init as VcpuInit, RegList,
}; };
use serde::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
pub use {kvm_ioctls::Cap, kvm_ioctls::Kvm}; pub use {kvm_ioctls::Cap, kvm_ioctls::Kvm};
// This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having // This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having

View File

@@ -8,24 +8,20 @@
// //
// //
#[cfg(target_arch = "aarch64")]
use crate::aarch64::gic::KvmGicV3Its;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
pub use crate::aarch64::{ pub use crate::aarch64::{
check_required_kvm_extensions, gic::Gicv3ItsState as GicState, is_system_register, VcpuInit, check_required_kvm_extensions, is_system_register, VcpuInit, VcpuKvmState as CpuState,
VcpuKvmState as CpuState, MPIDR_EL1, MPIDR_EL1,
}; };
#[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::gic::Vgic;
use crate::cpu; use crate::cpu;
use crate::device; use crate::device;
use crate::hypervisor; use crate::hypervisor;
use crate::vec_with_array_field; use crate::vec_with_array_field;
use crate::vm::{self, InterruptSourceConfig, VmOps}; use crate::vm::{self, VmmOps};
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use crate::{arm64_core_reg_id, offset__of}; use crate::{arm64_core_reg_id, offset__of};
use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd}; use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd};
use serde::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use std::convert::TryInto; use std::convert::TryInto;
@@ -35,8 +31,6 @@ use std::os::unix::io::{AsRawFd, RawFd};
use std::result; use std::result;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
#[cfg(target_arch = "aarch64")]
use std::sync::Mutex;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
// x86_64 dependencies // x86_64 dependencies
@@ -160,7 +154,7 @@ pub struct TdxCapabilities {
pub cpuid_configs: [TdxCpuidConfig; TDX_MAX_NR_CPUID_CONFIGS], pub cpuid_configs: [TdxCpuidConfig; TDX_MAX_NR_CPUID_CONFIGS],
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)]
pub struct KvmVmState {} pub struct KvmVmState {}
pub use KvmVmState as VmState; pub use KvmVmState as VmState;
@@ -240,7 +234,7 @@ impl vm::Vm for KvmVm {
fn create_vcpu( fn create_vcpu(
&self, &self,
id: u8, id: u8,
vm_ops: Option<Arc<dyn VmOps>>, vmmops: Option<Arc<dyn VmmOps>>,
) -> vm::Result<Arc<dyn cpu::Vcpu>> { ) -> vm::Result<Arc<dyn cpu::Vcpu>> {
let vc = self let vc = self
.fd .fd
@@ -250,37 +244,12 @@ impl vm::Vm for KvmVm {
fd: vc, fd: vc,
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
msrs: self.msrs.clone(), msrs: self.msrs.clone(),
vm_ops, vmmops,
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
hyperv_synic: AtomicBool::new(false), hyperv_synic: AtomicBool::new(false),
}; };
Ok(Arc::new(vcpu)) Ok(Arc::new(vcpu))
} }
#[cfg(target_arch = "aarch64")]
///
/// Creates a virtual GIC device.
///
fn create_vgic(
&self,
vcpu_count: u64,
dist_addr: u64,
dist_size: u64,
redist_size: u64,
msi_size: u64,
nr_irqs: u32,
) -> vm::Result<Arc<Mutex<dyn Vgic>>> {
let gic_device = KvmGicV3Its::new(
self,
vcpu_count,
dist_addr,
dist_size,
redist_size,
msi_size,
nr_irqs,
)
.map_err(|e| vm::HypervisorVmError::CreateVgic(anyhow!("Vgic error {:?}", e)))?;
Ok(Arc::new(Mutex::new(gic_device)))
}
/// ///
/// Registers an event to be signaled whenever a certain address is written to. /// Registers an event to be signaled whenever a certain address is written to.
/// ///
@@ -315,64 +284,6 @@ impl vm::Vm for KvmVm {
.unregister_ioevent(fd, addr, NoDatamatch) .unregister_ioevent(fd, addr, NoDatamatch)
.map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into())) .map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into()))
} }
///
/// Constructs a routing entry
///
fn make_routing_entry(
&self,
gsi: u32,
config: &InterruptSourceConfig,
) -> kvm_irq_routing_entry {
match &config {
InterruptSourceConfig::MsiIrq(cfg) => {
let mut kvm_route = kvm_irq_routing_entry {
gsi,
type_: KVM_IRQ_ROUTING_MSI,
..Default::default()
};
kvm_route.u.msi.address_lo = cfg.low_addr;
kvm_route.u.msi.address_hi = cfg.high_addr;
kvm_route.u.msi.data = cfg.data;
if self.check_extension(crate::kvm::Cap::MsiDevid) {
// On AArch64, there is limitation on the range of the 'devid',
// it can not be greater than 65536 (the max of u16).
//
// BDF can not be used directly, because 'segment' is in high
// 16 bits. The layout of the u32 BDF is:
// |---- 16 bits ----|-- 8 bits --|-- 5 bits --|-- 3 bits --|
// | segment | bus | device | function |
//
// Now that we support 1 bus only in a segment, we can build a
// 'devid' by replacing the 'bus' bits with the low 8 bits of
// 'segment' data.
// This way we can resolve the range checking problem and give
// different `devid` to all the devices. Limitation is that at
// most 256 segments can be supported.
//
let modified_devid = (cfg.devid & 0x00ff_0000) >> 8 | cfg.devid & 0xff;
kvm_route.flags = KVM_MSI_VALID_DEVID;
kvm_route.u.msi.__bindgen_anon_1.devid = modified_devid;
}
kvm_route
}
InterruptSourceConfig::LegacyIrq(cfg) => {
let mut kvm_route = kvm_irq_routing_entry {
gsi,
type_: KVM_IRQ_ROUTING_IRQCHIP,
..Default::default()
};
kvm_route.u.irqchip.irqchip = cfg.irqchip;
kvm_route.u.irqchip.pin = cfg.pin;
kvm_route
}
}
}
/// ///
/// Sets the GSI routing table entries, overwriting any previously set /// Sets the GSI routing table entries, overwriting any previously set
/// entries, as per the `KVM_SET_GSI_ROUTING` ioctl. /// entries, as per the `KVM_SET_GSI_ROUTING` ioctl.
@@ -905,7 +816,7 @@ pub struct KvmVcpu {
fd: VcpuFd, fd: VcpuFd,
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
msrs: MsrEntries, msrs: MsrEntries,
vm_ops: Option<Arc<dyn vm::VmOps>>, vmmops: Option<Arc<dyn vm::VmmOps>>,
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
hyperv_synic: AtomicBool, hyperv_synic: AtomicBool,
} }
@@ -1145,8 +1056,8 @@ impl cpu::Vcpu for KvmVcpu {
Ok(run) => match run { Ok(run) => match run {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
VcpuExit::IoIn(addr, data) => { VcpuExit::IoIn(addr, data) => {
if let Some(vm_ops) = &self.vm_ops { if let Some(vmmops) = &self.vmmops {
return vm_ops return vmmops
.pio_read(addr.into(), data) .pio_read(addr.into(), data)
.map(|_| cpu::VmExit::Ignore) .map(|_| cpu::VmExit::Ignore)
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into())); .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
@@ -1156,8 +1067,8 @@ impl cpu::Vcpu for KvmVcpu {
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
VcpuExit::IoOut(addr, data) => { VcpuExit::IoOut(addr, data) => {
if let Some(vm_ops) = &self.vm_ops { if let Some(vmmops) = &self.vmmops {
return vm_ops return vmmops
.pio_write(addr.into(), data) .pio_write(addr.into(), data)
.map(|_| cpu::VmExit::Ignore) .map(|_| cpu::VmExit::Ignore)
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into())); .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
@@ -1189,8 +1100,8 @@ impl cpu::Vcpu for KvmVcpu {
} }
VcpuExit::MmioRead(addr, data) => { VcpuExit::MmioRead(addr, data) => {
if let Some(vm_ops) = &self.vm_ops { if let Some(vmmops) = &self.vmmops {
return vm_ops return vmmops
.mmio_read(addr, data) .mmio_read(addr, data)
.map(|_| cpu::VmExit::Ignore) .map(|_| cpu::VmExit::Ignore)
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into())); .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
@@ -1199,8 +1110,8 @@ impl cpu::Vcpu for KvmVcpu {
Ok(cpu::VmExit::MmioRead(addr, data)) Ok(cpu::VmExit::MmioRead(addr, data))
} }
VcpuExit::MmioWrite(addr, data) => { VcpuExit::MmioWrite(addr, data) => {
if let Some(vm_ops) = &self.vm_ops { if let Some(vmmops) = &self.vmmops {
return vm_ops return vmmops
.mmio_write(addr, data) .mmio_write(addr, data)
.map(|_| cpu::VmExit::Ignore) .map(|_| cpu::VmExit::Ignore)
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into())); .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()));
@@ -1566,51 +1477,6 @@ impl cpu::Vcpu for KvmVcpu {
.get_one_reg(MPIDR_EL1) .get_one_reg(MPIDR_EL1)
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into())) .map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))
} }
///
/// Configure core registers for a given CPU.
///
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> cpu::Result<()> {
#[allow(non_upper_case_globals)]
// PSR (Processor State Register) bits.
// Taken from arch/arm64/include/uapi/asm/ptrace.h.
const PSR_MODE_EL1h: u64 = 0x0000_0005;
const PSR_F_BIT: u64 = 0x0000_0040;
const PSR_I_BIT: u64 = 0x0000_0080;
const PSR_A_BIT: u64 = 0x0000_0100;
const PSR_D_BIT: u64 = 0x0000_0200;
// Taken from arch/arm64/kvm/inject_fault.c.
const PSTATE_FAULT_BITS_64: u64 =
PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT;
let kreg_off = offset__of!(kvm_regs, regs);
// Get the register index of the PSTATE (Processor State) register.
let pstate = offset__of!(user_pt_regs, pstate) + kreg_off;
self.set_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate),
PSTATE_FAULT_BITS_64,
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
// Other vCPUs are powered off initially awaiting PSCI wakeup.
if cpu_id == 0 {
// Setting the PC (Processor Counter) to the current program address (kernel address).
let pc = offset__of!(user_pt_regs, pc) + kreg_off;
self.set_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), boot_ip as u64)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
// Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
// "The device tree blob (dtb) must be placed on an 8-byte boundary and must
// not exceed 2 megabytes in size." -> https://www.kernel.org/doc/Documentation/arm64/booting.txt.
// We are choosing to place it the end of DRAM. See `get_fdt_addr`.
let regs0 = offset__of!(user_pt_regs, regs) + kreg_off;
self.set_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0), fdt_start)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
}
Ok(())
}
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
/// Get the current CPU state /// Get the current CPU state

View File

@@ -10,7 +10,7 @@
use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB}; use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB};
use crate::kvm::{Cap, Kvm, KvmError, KvmResult}; use crate::kvm::{Cap, Kvm, KvmError, KvmResult};
use serde::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
/// ///
/// Export generically-named wrappers of kvm-bindings for Unix-based platforms /// Export generically-named wrappers of kvm-bindings for Unix-based platforms

View File

@@ -18,8 +18,6 @@
//! - arm64 //! - arm64
//! //!
#![allow(clippy::significant_drop_in_scrutinee)]
#[macro_use] #[macro_use]
extern crate anyhow; extern crate anyhow;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@@ -39,10 +37,10 @@ pub mod kvm;
pub mod mshv; pub mod mshv;
/// Hypevisor related module /// Hypevisor related module
mod hypervisor; pub mod hypervisor;
/// Vm related module /// Vm related module
mod vm; pub mod vm;
/// CPU related module /// CPU related module
mod cpu; mod cpu;
@@ -50,32 +48,18 @@ mod cpu;
/// Device related module /// Device related module
mod device; mod device;
pub use crate::hypervisor::{Hypervisor, HypervisorError};
pub use cpu::{HypervisorCpuError, Vcpu, VmExit}; pub use cpu::{HypervisorCpuError, Vcpu, VmExit};
pub use device::{Device, HypervisorDeviceError}; pub use device::{Device, HypervisorDeviceError};
pub use hypervisor::{Hypervisor, HypervisorError}; #[cfg(feature = "tdx")]
#[cfg(all(feature = "kvm", target_arch = "x86_64"))] pub use kvm::TdxCapabilities;
pub use kvm::x86_64;
#[cfg(all(feature = "kvm", target_arch = "aarch64"))]
pub use kvm::{aarch64, GicState};
// Aliased types exposed from both hypervisors
#[cfg(feature = "kvm")] #[cfg(feature = "kvm")]
pub use kvm::{ pub use kvm::*;
ClockData, CpuState, CreateDevice, DeviceAttr, DeviceFd, IoEventAddress, IrqRoutingEntry,
MemoryRegion, MpState, VcpuEvents, VcpuExit, VmState,
};
#[cfg(all(feature = "mshv", target_arch = "x86_64"))] #[cfg(all(feature = "mshv", target_arch = "x86_64"))]
pub use mshv::x86_64; pub use mshv::*;
// Aliased types exposed from both hypervisors pub use vm::{DataMatch, HypervisorVmError, Vm};
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
pub use mshv::{
CpuState, CreateDevice, DeviceAttr, DeviceFd, IoEventAddress, IrqRoutingEntry, MemoryRegion,
MpState, VcpuEvents, VcpuExit, VmState,
};
use std::sync::Arc; use std::sync::Arc;
pub use vm::{
DataMatch, HypervisorVmError, InterruptSourceConfig, LegacyIrqSourceConfig, MsiIrqSourceConfig,
Vm, VmOps,
};
pub fn new() -> std::result::Result<Arc<dyn Hypervisor>, HypervisorError> { pub fn new() -> std::result::Result<Arc<dyn Hypervisor>, HypervisorError> {
#[cfg(feature = "kvm")] #[cfg(feature = "kvm")]

View File

@@ -11,11 +11,11 @@ use crate::cpu;
use crate::cpu::Vcpu; use crate::cpu::Vcpu;
use crate::hypervisor; use crate::hypervisor;
use crate::vec_with_array_field; use crate::vec_with_array_field;
use crate::vm::{self, InterruptSourceConfig, VmOps}; use crate::vm::{self, VmmOps};
pub use mshv_bindings::*; pub use mshv_bindings::*;
pub use mshv_ioctls::IoEventAddress; pub use mshv_ioctls::IoEventAddress;
use mshv_ioctls::{set_registers_64, Mshv, NoDatamatch, VcpuFd, VmFd}; use mshv_ioctls::{set_registers_64, Mshv, NoDatamatch, VcpuFd, VmFd};
use serde::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use vm::DataMatch; use vm::DataMatch;
@@ -108,17 +108,6 @@ impl hypervisor::Hypervisor for MshvHypervisor {
break; break;
} }
// Default Microsoft Hypervisor behavior for unimplemented MSR is to
// send a fault to the guest if it tries to access it. It is possible
// to override this behavior with a more suitable option i.e., ignore
// writes from the guest and return zero in attempt to read unimplemented
// MSR.
fd.set_partition_property(
hv_partition_property_code_HV_PARTITION_PROPERTY_UNIMPLEMENTED_MSR_ACTION,
hv_unimplemented_msr_action_HV_UNIMPLEMENTED_MSR_ACTION_IGNORE_WRITE_READ_ZERO as u64,
)
.map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?;
let msr_list = self.get_msr_list()?; let msr_list = self.get_msr_list()?;
let num_msrs = msr_list.as_fam_struct_ref().nmsrs as usize; let num_msrs = msr_list.as_fam_struct_ref().nmsrs as usize;
let mut msrs = MsrEntries::new(num_msrs).unwrap(); let mut msrs = MsrEntries::new(num_msrs).unwrap();
@@ -133,7 +122,7 @@ impl hypervisor::Hypervisor for MshvHypervisor {
fd: vm_fd, fd: vm_fd,
msrs, msrs,
hv_state: hv_state_init(), hv_state: hv_state_init(),
vm_ops: None, vmmops: None,
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())), dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
})) }))
} }
@@ -162,7 +151,7 @@ pub struct MshvVcpu {
cpuid: CpuId, cpuid: CpuId,
msrs: MsrEntries, msrs: MsrEntries,
hv_state: Arc<RwLock<HvState>>, // Mshv State hv_state: Arc<RwLock<HvState>>, // Mshv State
vm_ops: Option<Arc<dyn vm::VmOps>>, vmmops: Option<Arc<dyn vm::VmmOps>>,
} }
/// Implementation of Vcpu trait for Microsoft Hypervisor /// Implementation of Vcpu trait for Microsoft Hypervisor
@@ -366,14 +355,14 @@ impl cpu::Vcpu for MshvVcpu {
if is_write { if is_write {
let data = (info.rax as u32).to_le_bytes(); let data = (info.rax as u32).to_le_bytes();
if let Some(vm_ops) = &self.vm_ops { if let Some(vmmops) = &self.vmmops {
vm_ops vmmops
.pio_write(port.into(), &data[0..len]) .pio_write(port.into(), &data[0..len])
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
} }
} else { } else {
if let Some(vm_ops) = &self.vm_ops { if let Some(vmmops) = &self.vmmops {
vm_ops vmmops
.pio_read(port.into(), &mut data[0..len]) .pio_read(port.into(), &mut data[0..len])
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
} }
@@ -666,9 +655,9 @@ impl<'a> PlatformEmulator for MshvEmulatorContext<'a> {
gpa gpa
); );
if let Some(vm_ops) = &self.vcpu.vm_ops { if let Some(vmmops) = &self.vcpu.vmmops {
if vm_ops.guest_mem_read(gpa, data).is_err() { if vmmops.guest_mem_read(gpa, data).is_err() {
vm_ops vmmops
.mmio_read(gpa, data) .mmio_read(gpa, data)
.map_err(|e| PlatformError::MemoryReadFailure(e.into()))?; .map_err(|e| PlatformError::MemoryReadFailure(e.into()))?;
} }
@@ -686,9 +675,9 @@ impl<'a> PlatformEmulator for MshvEmulatorContext<'a> {
gpa gpa
); );
if let Some(vm_ops) = &self.vcpu.vm_ops { if let Some(vmmops) = &self.vcpu.vmmops {
if vm_ops.guest_mem_write(gpa, data).is_err() { if vmmops.guest_mem_write(gpa, data).is_err() {
vm_ops vmmops
.mmio_write(gpa, data) .mmio_write(gpa, data)
.map_err(|e| PlatformError::MemoryWriteFailure(e.into()))?; .map_err(|e| PlatformError::MemoryWriteFailure(e.into()))?;
} }
@@ -757,7 +746,7 @@ pub struct MshvVm {
msrs: MsrEntries, msrs: MsrEntries,
// Hypervisor State // Hypervisor State
hv_state: Arc<RwLock<HvState>>, hv_state: Arc<RwLock<HvState>>,
vm_ops: Option<Arc<dyn vm::VmOps>>, vmmops: Option<Arc<dyn vm::VmmOps>>,
dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>, dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>,
} }
@@ -827,7 +816,7 @@ impl vm::Vm for MshvVm {
fn create_vcpu( fn create_vcpu(
&self, &self,
id: u8, id: u8,
vm_ops: Option<Arc<dyn VmOps>>, vmmops: Option<Arc<dyn VmmOps>>,
) -> vm::Result<Arc<dyn cpu::Vcpu>> { ) -> vm::Result<Arc<dyn cpu::Vcpu>> {
let vcpu_fd = self let vcpu_fd = self
.fd .fd
@@ -839,7 +828,7 @@ impl vm::Vm for MshvVm {
cpuid: CpuId::new(1).unwrap(), cpuid: CpuId::new(1).unwrap(),
msrs: self.msrs.clone(), msrs: self.msrs.clone(),
hv_state: self.hv_state.clone(), hv_state: self.hv_state.clone(),
vm_ops, vmmops,
}; };
Ok(Arc::new(vcpu)) Ok(Arc::new(vcpu))
} }
@@ -968,27 +957,6 @@ impl vm::Vm for MshvVm {
.map_err(|e| vm::HypervisorVmError::CreatePassthroughDevice(e.into())) .map_err(|e| vm::HypervisorVmError::CreatePassthroughDevice(e.into()))
} }
///
/// Constructs a routing entry
///
fn make_routing_entry(
&self,
gsi: u32,
config: &InterruptSourceConfig,
) -> mshv_msi_routing_entry {
match config {
InterruptSourceConfig::MsiIrq(cfg) => mshv_msi_routing_entry {
gsi,
address_lo: cfg.low_addr,
address_hi: cfg.high_addr,
data: cfg.data,
},
_ => {
unreachable!()
}
}
}
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> { fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
let mut msi_routing = let mut msi_routing =
vec_with_array_field::<mshv_msi_routing, mshv_msi_routing_entry>(entries.len()); vec_with_array_field::<mshv_msi_routing, mshv_msi_routing_entry>(entries.len());
@@ -1059,3 +1027,6 @@ impl vm::Vm for MshvVm {
.map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into())) .map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into()))
} }
} }
pub use hv_cpuid_entry as CpuIdEntry;
pub const CPUID_FLAG_VALID_INDEX: u32 = 0;

View File

@@ -8,14 +8,13 @@
// //
// //
use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB}; use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB};
use serde::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::fmt; use std::fmt;
/// ///
/// Export generically-named wrappers of mshv_bindings for Unix-based platforms /// Export generically-named wrappers of mshv_bindings for Unix-based platforms
/// ///
pub use { pub use {
mshv_bindings::hv_cpuid_entry as CpuIdEntry,
mshv_bindings::mshv_user_mem_region as MemoryRegion, mshv_bindings::msr_entry as MsrEntry, mshv_bindings::mshv_user_mem_region as MemoryRegion, mshv_bindings::msr_entry as MsrEntry,
mshv_bindings::CpuId, mshv_bindings::DebugRegisters, mshv_bindings::CpuId, mshv_bindings::DebugRegisters,
mshv_bindings::FloatingPointUnit as FpuState, mshv_bindings::LapicState, mshv_bindings::FloatingPointUnit as FpuState, mshv_bindings::LapicState,
@@ -26,8 +25,6 @@ pub use {
mshv_bindings::Xcrs as ExtendedControlRegisters, mshv_bindings::Xcrs as ExtendedControlRegisters,
}; };
pub const CPUID_FLAG_VALID_INDEX: u32 = 0;
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct VcpuMshvState { pub struct VcpuMshvState {
pub msrs: MsrEntries, pub msrs: MsrEntries,

View File

@@ -10,27 +10,23 @@
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use crate::aarch64::VcpuInit; use crate::aarch64::VcpuInit;
#[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::gic::Vgic;
use crate::cpu::Vcpu; use crate::cpu::Vcpu;
use crate::device::Device; use crate::device::Device;
#[cfg(feature = "kvm")]
use crate::kvm::KvmVmState as VmState;
#[cfg(feature = "mshv")]
use crate::mshv::HvState as VmState;
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
use crate::x86_64::CpuId; use crate::x86_64::CpuId;
#[cfg(all(feature = "kvm", target_arch = "x86_64"))] #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
use crate::ClockData; use crate::ClockData;
use crate::CreateDevice; use crate::CreateDevice;
#[cfg(feature = "mshv")]
use crate::HvState as VmState;
#[cfg(feature = "kvm")]
use crate::KvmVmState as VmState;
use crate::{IoEventAddress, IrqRoutingEntry, MemoryRegion}; use crate::{IoEventAddress, IrqRoutingEntry, MemoryRegion};
#[cfg(feature = "kvm")] #[cfg(feature = "kvm")]
use kvm_ioctls::Cap; use kvm_ioctls::Cap;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use std::fs::File; use std::fs::File;
use std::sync::Arc; use std::sync::Arc;
#[cfg(target_arch = "aarch64")]
use std::sync::Mutex;
use thiserror::Error; use thiserror::Error;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
@@ -214,50 +210,12 @@ pub enum HypervisorVmError {
/// ///
#[error("Failed to initialize memory region TDX: {0}")] #[error("Failed to initialize memory region TDX: {0}")]
InitMemRegionTdx(#[source] std::io::Error), InitMemRegionTdx(#[source] std::io::Error),
///
/// Create Vgic error
///
#[error("Failed to create Vgic: {0}")]
CreateVgic(#[source] anyhow::Error),
} }
/// ///
/// Result type for returning from a function /// Result type for returning from a function
/// ///
pub type Result<T> = std::result::Result<T, HypervisorVmError>; pub type Result<T> = std::result::Result<T, HypervisorVmError>;
/// Configuration data for legacy interrupts.
///
/// On x86 platforms, legacy interrupts means those interrupts routed through PICs or IOAPICs.
#[derive(Copy, Clone, Debug)]
pub struct LegacyIrqSourceConfig {
pub irqchip: u32,
pub pin: u32,
}
/// Configuration data for MSI/MSI-X interrupts.
///
/// On x86 platforms, these interrupts are vectors delivered directly to the LAPIC.
#[derive(Copy, Clone, Debug, Default)]
pub struct MsiIrqSourceConfig {
/// High address to delivery message signaled interrupt.
pub high_addr: u32,
/// Low address to delivery message signaled interrupt.
pub low_addr: u32,
/// Data to write to delivery message signaled interrupt.
pub data: u32,
/// Unique ID of the device to delivery message signaled interrupt.
pub devid: u32,
}
/// Configuration data for an interrupt source.
#[derive(Copy, Clone, Debug)]
pub enum InterruptSourceConfig {
/// Configuration data for Legacy interrupts.
LegacyIrq(LegacyIrqSourceConfig),
/// Configuration data for PciMsi, PciMsix and generic MSI interrupts.
MsiIrq(MsiIrqSourceConfig),
}
/// ///
/// Trait to represent a Vm /// Trait to represent a Vm
/// ///
@@ -277,18 +235,7 @@ pub trait Vm: Send + Sync {
/// Unregister an event that will, when signaled, trigger the `gsi` IRQ. /// Unregister an event that will, when signaled, trigger the `gsi` IRQ.
fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()>; fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()>;
/// Creates a new KVM vCPU file descriptor and maps the memory corresponding /// Creates a new KVM vCPU file descriptor and maps the memory corresponding
fn create_vcpu(&self, id: u8, vm_ops: Option<Arc<dyn VmOps>>) -> Result<Arc<dyn Vcpu>>; fn create_vcpu(&self, id: u8, vmmops: Option<Arc<dyn VmmOps>>) -> Result<Arc<dyn Vcpu>>;
#[cfg(target_arch = "aarch64")]
fn create_vgic(
&self,
vcpu_count: u64,
dist_addr: u64,
dist_size: u64,
redist_size: u64,
msi_size: u64,
nr_irqs: u32,
) -> Result<Arc<Mutex<dyn Vgic>>>;
/// Registers an event to be signaled whenever a certain address is written to. /// Registers an event to be signaled whenever a certain address is written to.
fn register_ioevent( fn register_ioevent(
&self, &self,
@@ -298,8 +245,6 @@ pub trait Vm: Send + Sync {
) -> Result<()>; ) -> Result<()>;
/// Unregister an event from a certain address it has been previously registered to. /// Unregister an event from a certain address it has been previously registered to.
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>; fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>;
// Construct a routing entry
fn make_routing_entry(&self, gsi: u32, config: &InterruptSourceConfig) -> IrqRoutingEntry;
/// Sets the GSI routing table entries, overwriting any previously set /// Sets the GSI routing table entries, overwriting any previously set
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> Result<()>; fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> Result<()>;
/// Creates a memory region structure that can be used with {create/remove}_user_memory_region /// Creates a memory region structure that can be used with {create/remove}_user_memory_region
@@ -364,7 +309,7 @@ pub trait Vm: Send + Sync {
) -> Result<()>; ) -> Result<()>;
} }
pub trait VmOps: Send + Sync { pub trait VmmOps: Send + Sync {
fn guest_mem_write(&self, gpa: u64, buf: &[u8]) -> Result<usize>; fn guest_mem_write(&self, gpa: u64, buf: &[u8]) -> Result<usize>;
fn guest_mem_read(&self, gpa: u64, buf: &mut [u8]) -> Result<usize>; fn guest_mem_read(&self, gpa: u64, buf: &mut [u8]) -> Result<usize>;
fn mmio_read(&self, gpa: u64, data: &mut [u8]) -> Result<()>; fn mmio_read(&self, gpa: u64, data: &mut [u8]) -> Result<()>;

View File

@@ -7,21 +7,20 @@ edition = "2021"
[dependencies] [dependencies]
epoll = "4.3.1" epoll = "4.3.1"
getrandom = "0.2" getrandom = "0.2"
libc = "0.2.126" libc = "0.2.123"
log = "0.4.17" log = "0.4.16"
net_gen = { path = "../net_gen" } net_gen = { path = "../net_gen" }
rate_limiter = { path = "../rate_limiter" } rate_limiter = { path = "../rate_limiter" }
serde = "1.0.138" serde = "1.0.136"
versionize = "0.1.6" versionize = "0.1.6"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"
virtio-bindings = "0.1.0" virtio-bindings = "0.1.0"
virtio-queue = "0.4.0" virtio-queue = "0.2.0"
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" } vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.9.0" vmm-sys-util = "0.9.0"
[dev-dependencies] [dev-dependencies]
once_cell = "1.13.0" lazy_static = "1.4.0"
pnet = "0.31.0" pnet = "0.29.0"
pnet_datalink = "0.31.0" serde_json = "1.0.79"
serde_json = "1.0.82"

View File

@@ -5,6 +5,11 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file. // found in the THIRD-PARTY file.
// This is only used by the tests module from tap.rs, but we cannot use #[macro_use] unless the
// reference to lazy_static is declared at the root level of the importing crate.
#[cfg(test)]
#[macro_use]
extern crate lazy_static;
#[macro_use] #[macro_use]
extern crate log; extern crate log;

View File

@@ -15,7 +15,7 @@ use serde::ser::{Serialize, Serializer};
pub const MAC_ADDR_LEN: usize = 6; pub const MAC_ADDR_LEN: usize = 6;
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct MacAddr { pub struct MacAddr {
bytes: [u8; MAC_ADDR_LEN], bytes: [u8; MAC_ADDR_LEN],
} }

View File

@@ -321,13 +321,15 @@ impl Tap {
// If TAP device is already up don't try and enable it // If TAP device is already up don't try and enable it
let ifru_flags = unsafe { ifreq.ifr_ifru.ifru_flags }; let ifru_flags = unsafe { ifreq.ifr_ifru.ifru_flags };
if ifru_flags & net_gen::net_device_flags_IFF_UP as i16 if ifru_flags
== net_gen::net_device_flags_IFF_UP as i16 & (net_gen::net_device_flags_IFF_UP | net_gen::net_device_flags_IFF_RUNNING) as i16
== (net_gen::net_device_flags_IFF_UP | net_gen::net_device_flags_IFF_RUNNING) as i16
{ {
return Ok(()); return Ok(());
} }
ifreq.ifr_ifru.ifru_flags = net_gen::net_device_flags_IFF_UP as i16; ifreq.ifr_ifru.ifru_flags =
(net_gen::net_device_flags_IFF_UP | net_gen::net_device_flags_IFF_RUNNING) as i16;
// ioctl is safe. Called with a valid sock fd, and we check the return. // ioctl is safe. Called with a valid sock fd, and we check the return.
let ret = let ret =
@@ -393,35 +395,38 @@ impl AsRawFd for Tap {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
extern crate pnet;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use std::str; use std::str;
use std::sync::{mpsc, Mutex}; use std::sync::{mpsc, Mutex};
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use once_cell::sync::Lazy; use self::pnet::datalink::Channel::Ethernet;
use self::pnet::datalink::{self, DataLinkReceiver, DataLinkSender, NetworkInterface};
use pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket}; use self::pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket};
use pnet::packet::ip::IpNextHeaderProtocols; use self::pnet::packet::ip::IpNextHeaderProtocols;
use pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet}; use self::pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet};
use pnet::packet::udp::{MutableUdpPacket, UdpPacket}; use self::pnet::packet::udp::{MutableUdpPacket, UdpPacket};
use pnet::packet::{MutablePacket, Packet}; use self::pnet::packet::{MutablePacket, Packet};
use pnet::util::MacAddr; use self::pnet::util::MacAddr;
use pnet_datalink::Channel::Ethernet;
use pnet_datalink::{DataLinkReceiver, DataLinkSender, NetworkInterface};
use super::*; use super::*;
static DATA_STRING: &str = "test for tap"; static DATA_STRING: &str = "test for tap";
static SUBNET_MASK: &str = "255.255.255.0"; static SUBNET_MASK: &str = "255.255.255.0";
// We needed to have a mutex as a global variable, so we used once_cell for testing. The main // We needed to have a mutex as a global variable, so we used the crate that provides the
// potential problem, caused by tests being run in parallel by cargo, is creating different // lazy_static! macro for testing. The main potential problem, caused by tests being run in
// TAPs and trying to associate the same address, so we hide the IP address &str behind this // parallel by cargo, is creating different TAPs and trying to associate the same address,
// mutex, more as a convention to remember to lock it at the very beginning of each function // so we hide the IP address &str behind this mutex, more as a convention to remember to lock
// susceptible to this issue. Another variant is to use a different IP address per function, // it at the very beginning of each function susceptible to this issue. Another variant is
// but we must remember to pick an unique one each time. // to use a different IP address per function, but we must remember to pick an unique one
static TAP_IP_LOCK: Lazy<Mutex<&'static str>> = Lazy::new(|| Mutex::new("192.168.241.1")); // each time.
lazy_static! {
static ref TAP_IP_LOCK: Mutex<&'static str> = Mutex::new("192.168.241.1");
}
// Describes the outcomes we are currently interested in when parsing a packet (we use // Describes the outcomes we are currently interested in when parsing a packet (we use
// an UDP packet for testing). // an UDP packet for testing).
@@ -538,10 +543,10 @@ mod tests {
let interface_name_matches = |iface: &NetworkInterface| iface.name == ifname; let interface_name_matches = |iface: &NetworkInterface| iface.name == ifname;
// Find the network interface with the provided name. // Find the network interface with the provided name.
let interfaces = pnet_datalink::interfaces(); let interfaces = datalink::interfaces();
let interface = interfaces.into_iter().find(interface_name_matches).unwrap(); let interface = interfaces.into_iter().find(interface_name_matches).unwrap();
if let Ok(Ethernet(tx, rx)) = pnet_datalink::channel(&interface, Default::default()) { if let Ok(Ethernet(tx, rx)) = datalink::channel(&interface, Default::default()) {
(interface.mac.unwrap(), tx, rx) (interface.mac.unwrap(), tx, rx)
} else { } else {
panic!("datalink channel error or unhandled channel type"); panic!("datalink channel error or unhandled channel type");

View File

@@ -77,7 +77,7 @@ impl OptionParser {
} }
for option in split_commas_outside_brackets(input)?.iter() { for option in split_commas_outside_brackets(input)?.iter() {
let parts: Vec<&str> = option.splitn(2, '=').collect(); let parts: Vec<&str> = option.split('=').collect();
match self.options.get_mut(parts[0]) { match self.options.get_mut(parts[0]) {
None => return Err(OptionParserError::UnknownOption(parts[0].to_owned())), None => return Err(OptionParserError::UnknownOption(parts[0].to_owned())),

View File

@@ -10,21 +10,22 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"] mshv = ["vfio-ioctls/mshv"]
[dependencies] [dependencies]
anyhow = "1.0.58" anyhow = "1.0.56"
byteorder = "1.4.3" byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false } vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
vfio_user = { path = "../vfio_user" } vfio_user = { path = "../vfio_user" }
vmm-sys-util = "0.9.0" vmm-sys-util = "0.9.0"
libc = "0.2.126" libc = "0.2.123"
log = "0.4.17" log = "0.4.16"
serde = { version="1.0.138", features=["derive"] } serde = "1.0.136"
thiserror = "1.0.31" serde_derive = "1.0.136"
thiserror = "1.0.30"
versionize = "0.1.6" versionize = "0.1.6"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"
vm-allocator = { path = "../vm-allocator" } vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" } vm-device = { path = "../vm-device" }
vm-memory = "0.8.0" vm-memory = "0.7.0"
vm-migration = { path = "../vm-migration" } vm-migration = { path = "../vm-migration" }
[dependencies.vfio-bindings] [dependencies.vfio-bindings]

View File

@@ -6,13 +6,13 @@ use crate::configuration::{
PciBarRegionType, PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType, PciBarRegionType, PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType,
}; };
use crate::device::{DeviceRelocation, Error as PciDeviceError, PciDevice}; use crate::device::{DeviceRelocation, Error as PciDeviceError, PciDevice};
use crate::PciBarConfiguration;
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use std::any::Any; use std::any::Any;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::DerefMut; use std::ops::DerefMut;
use std::sync::{Arc, Barrier, Mutex}; use std::sync::{Arc, Barrier, Mutex};
use vm_device::{Bus, BusDevice}; use vm_device::{Bus, BusDevice};
use vm_memory::{Address, GuestAddress, GuestUsize};
const VENDOR_ID_INTEL: u16 = 0x8086; const VENDOR_ID_INTEL: u16 = 0x8086;
const DEVICE_ID_INTEL_VIRT_PCIE_HOST: u16 = 0x0d57; const DEVICE_ID_INTEL_VIRT_PCIE_HOST: u16 = 0x0d57;
@@ -88,10 +88,6 @@ impl PciDevice for PciRoot {
fn as_any(&mut self) -> &mut dyn Any { fn as_any(&mut self) -> &mut dyn Any {
self self
} }
fn id(&self) -> Option<String> {
None
}
} }
pub struct PciBus { pub struct PciBus {
@@ -122,21 +118,21 @@ impl PciBus {
dev: Arc<Mutex<dyn BusDevice>>, dev: Arc<Mutex<dyn BusDevice>>,
#[cfg(target_arch = "x86_64")] io_bus: &Bus, #[cfg(target_arch = "x86_64")] io_bus: &Bus,
mmio_bus: &Bus, mmio_bus: &Bus,
bars: Vec<PciBarConfiguration>, bars: Vec<(GuestAddress, GuestUsize, PciBarRegionType)>,
) -> Result<()> { ) -> Result<()> {
for bar in bars { for (address, size, type_) in bars {
match bar.region_type() { match type_ {
PciBarRegionType::IoRegion => { PciBarRegionType::IoRegion => {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
io_bus io_bus
.insert(dev.clone(), bar.addr(), bar.size()) .insert(dev.clone(), address.raw_value(), size)
.map_err(PciRootError::PioInsert)?; .map_err(PciRootError::PioInsert)?;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
error!("I/O region is not supported"); error!("I/O region is not supported");
} }
PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => { PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
mmio_bus mmio_bus
.insert(dev.clone(), bar.addr(), bar.size()) .insert(dev.clone(), address.raw_value(), size)
.map_err(PciRootError::MmioInsert)?; .map_err(PciRootError::MmioInsert)?;
} }
} }

View File

@@ -9,7 +9,6 @@ use std::fmt::{self, Display};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult}; use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
use versionize_derive::Versionize; use versionize_derive::Versionize;
use vm_device::PciBarType;
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped}; use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped};
// The number of 32bit registers in the config space, 4096 bytes. // The number of 32bit registers in the config space, 4096 bytes.
@@ -19,7 +18,6 @@ const STATUS_REG: usize = 1;
const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000; const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
const BAR0_REG: usize = 4; const BAR0_REG: usize = 4;
const ROM_BAR_REG: usize = 12; const ROM_BAR_REG: usize = 12;
const ROM_BAR_IDX: usize = 6;
const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc; const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0; const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
const ROM_BAR_ADDR_MASK: u32 = 0xffff_f800; const ROM_BAR_ADDR_MASK: u32 = 0xffff_f800;
@@ -187,7 +185,7 @@ pub trait PciProgrammingInterface {
} }
/// Types of PCI capabilities. /// Types of PCI capabilities.
#[derive(PartialEq, Eq, Copy, Clone)] #[derive(PartialEq, Copy, Clone)]
#[allow(dead_code)] #[allow(dead_code)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[repr(C)] #[repr(C)]
@@ -321,55 +319,24 @@ pub struct PciConfiguration {
} }
/// See pci_regs.h in kernel /// See pci_regs.h in kernel
#[derive(Copy, Clone, PartialEq, Eq, Versionize, Debug)] #[derive(Copy, Clone, PartialEq, Versionize, Debug)]
pub enum PciBarRegionType { pub enum PciBarRegionType {
Memory32BitRegion = 0, Memory32BitRegion = 0,
IoRegion = 0x01, IoRegion = 0x01,
Memory64BitRegion = 0x04, Memory64BitRegion = 0x04,
} }
impl From<PciBarType> for PciBarRegionType {
fn from(type_: PciBarType) -> Self {
match type_ {
PciBarType::Io => PciBarRegionType::IoRegion,
PciBarType::Mmio32 => PciBarRegionType::Memory32BitRegion,
PciBarType::Mmio64 => PciBarRegionType::Memory64BitRegion,
}
}
}
#[allow(clippy::from_over_into)]
impl Into<PciBarType> for PciBarRegionType {
fn into(self) -> PciBarType {
match self {
PciBarRegionType::IoRegion => PciBarType::Io,
PciBarRegionType::Memory32BitRegion => PciBarType::Mmio32,
PciBarRegionType::Memory64BitRegion => PciBarType::Mmio64,
}
}
}
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum PciBarPrefetchable { pub enum PciBarPrefetchable {
NotPrefetchable = 0, NotPrefetchable = 0,
Prefetchable = 0x08, Prefetchable = 0x08,
} }
#[allow(clippy::from_over_into)]
impl Into<bool> for PciBarPrefetchable {
fn into(self) -> bool {
match self {
PciBarPrefetchable::NotPrefetchable => false,
PciBarPrefetchable::Prefetchable => true,
}
}
}
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct PciBarConfiguration { pub struct PciBarConfiguration {
addr: u64, addr: u64,
size: u64, size: u64,
idx: usize, reg_idx: usize,
region_type: PciBarRegionType, region_type: PciBarRegionType,
prefetchable: PciBarPrefetchable, prefetchable: PciBarPrefetchable,
} }
@@ -589,23 +556,22 @@ impl PciConfiguration {
/// Adds a region specified by `config`. Configures the specified BAR(s) to /// Adds a region specified by `config`. Configures the specified BAR(s) to
/// report this region and size to the guest kernel. Enforces a few constraints /// report this region and size to the guest kernel. Enforces a few constraints
/// (i.e, region size must be power of two, register not already used). /// (i.e, region size must be power of two, register not already used). Returns 'None' on
pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<()> { /// failure all, `Some(BarIndex)` on success.
let bar_idx = config.idx; pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<usize> {
let reg_idx = BAR0_REG + bar_idx; if self.bars[config.reg_idx].used {
return Err(Error::BarInUse(config.reg_idx));
if self.bars[bar_idx].used {
return Err(Error::BarInUse(bar_idx));
} }
if config.size.count_ones() != 1 { if config.size.count_ones() != 1 {
return Err(Error::BarSizeInvalid(config.size)); return Err(Error::BarSizeInvalid(config.size));
} }
if bar_idx >= NUM_BAR_REGS { if config.reg_idx >= NUM_BAR_REGS {
return Err(Error::BarInvalid(bar_idx)); return Err(Error::BarInvalid(config.reg_idx));
} }
let bar_idx = BAR0_REG + config.reg_idx;
let end_addr = config let end_addr = config
.addr .addr
.checked_add(config.size - 1) .checked_add(config.size - 1)
@@ -618,20 +584,20 @@ impl PciConfiguration {
// Encode the BAR size as expected by the software running in // Encode the BAR size as expected by the software running in
// the guest. // the guest.
self.bars[bar_idx].size = self.bars[config.reg_idx].size =
encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?; encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
} }
PciBarRegionType::Memory64BitRegion => { PciBarRegionType::Memory64BitRegion => {
if bar_idx + 1 >= NUM_BAR_REGS { if config.reg_idx + 1 >= NUM_BAR_REGS {
return Err(Error::BarInvalid64(bar_idx)); return Err(Error::BarInvalid64(config.reg_idx));
} }
if end_addr > u64::max_value() { if end_addr > u64::max_value() {
return Err(Error::BarAddressInvalid(config.addr, config.size)); return Err(Error::BarAddressInvalid(config.addr, config.size));
} }
if self.bars[bar_idx + 1].used { if self.bars[config.reg_idx + 1].used {
return Err(Error::BarInUse64(bar_idx)); return Err(Error::BarInUse64(config.reg_idx));
} }
// Encode the BAR size as expected by the software running in // Encode the BAR size as expected by the software running in
@@ -639,12 +605,12 @@ impl PciConfiguration {
let (bar_size_hi, bar_size_lo) = let (bar_size_hi, bar_size_lo) =
encode_64_bits_bar_size(config.size).ok_or(Error::Encode64BarSize)?; encode_64_bits_bar_size(config.size).ok_or(Error::Encode64BarSize)?;
self.registers[reg_idx + 1] = (config.addr >> 32) as u32; self.registers[bar_idx + 1] = (config.addr >> 32) as u32;
self.writable_bits[reg_idx + 1] = 0xffff_ffff; self.writable_bits[bar_idx + 1] = 0xffff_ffff;
self.bars[bar_idx + 1].addr = self.registers[reg_idx + 1]; self.bars[config.reg_idx + 1].addr = self.registers[bar_idx + 1];
self.bars[bar_idx].size = bar_size_lo; self.bars[config.reg_idx].size = bar_size_lo;
self.bars[bar_idx + 1].size = bar_size_hi; self.bars[config.reg_idx + 1].size = bar_size_hi;
self.bars[bar_idx + 1].used = true; self.bars[config.reg_idx + 1].used = true;
} }
} }
@@ -656,30 +622,26 @@ impl PciConfiguration {
PciBarRegionType::IoRegion => (BAR_IO_ADDR_MASK, config.region_type as u32), PciBarRegionType::IoRegion => (BAR_IO_ADDR_MASK, config.region_type as u32),
}; };
self.registers[reg_idx] = ((config.addr as u32) & mask) | lower_bits; self.registers[bar_idx] = ((config.addr as u32) & mask) | lower_bits;
self.writable_bits[reg_idx] = mask; self.writable_bits[bar_idx] = mask;
self.bars[bar_idx].addr = self.registers[reg_idx]; self.bars[config.reg_idx].addr = self.registers[bar_idx];
self.bars[bar_idx].used = true; self.bars[config.reg_idx].used = true;
self.bars[bar_idx].r#type = Some(config.region_type); self.bars[config.reg_idx].r#type = Some(config.region_type);
Ok(config.reg_idx)
Ok(())
} }
/// Adds rom expansion BAR. /// Adds rom expansion BAR.
pub fn add_pci_rom_bar(&mut self, config: &PciBarConfiguration, active: u32) -> Result<()> { pub fn add_pci_rom_bar(&mut self, config: &PciBarConfiguration, active: u32) -> Result<usize> {
let bar_idx = config.idx;
let reg_idx = ROM_BAR_REG;
if self.rom_bar_used { if self.rom_bar_used {
return Err(Error::RomBarInUse(bar_idx)); return Err(Error::RomBarInUse(config.reg_idx));
} }
if config.size.count_ones() != 1 { if config.size.count_ones() != 1 {
return Err(Error::RomBarSizeInvalid(config.size)); return Err(Error::RomBarSizeInvalid(config.size));
} }
if bar_idx != ROM_BAR_IDX { if config.reg_idx != ROM_BAR_REG {
return Err(Error::RomBarInvalid(bar_idx)); return Err(Error::RomBarInvalid(config.reg_idx));
} }
let end_addr = config let end_addr = config
@@ -691,14 +653,13 @@ impl PciConfiguration {
return Err(Error::RomBarAddressInvalid(config.addr, config.size)); return Err(Error::RomBarAddressInvalid(config.addr, config.size));
} }
self.registers[reg_idx] = (config.addr as u32) | active; self.registers[config.reg_idx] = (config.addr as u32) | active;
self.writable_bits[reg_idx] = ROM_BAR_ADDR_MASK; self.writable_bits[config.reg_idx] = ROM_BAR_ADDR_MASK;
self.rom_bar_addr = self.registers[reg_idx]; self.rom_bar_addr = self.registers[config.reg_idx];
self.rom_bar_size = self.rom_bar_size =
encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?; encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
self.rom_bar_used = true; self.rom_bar_used = true;
Ok(config.reg_idx)
Ok(())
} }
/// Returns the address of the given BAR region. /// Returns the address of the given BAR region.
@@ -950,7 +911,7 @@ impl Snapshottable for PciConfiguration {
impl Default for PciBarConfiguration { impl Default for PciBarConfiguration {
fn default() -> Self { fn default() -> Self {
PciBarConfiguration { PciBarConfiguration {
idx: 0, reg_idx: 0,
addr: 0, addr: 0,
size: 0, size: 0,
region_type: PciBarRegionType::Memory64BitRegion, region_type: PciBarRegionType::Memory64BitRegion,
@@ -961,13 +922,13 @@ impl Default for PciBarConfiguration {
impl PciBarConfiguration { impl PciBarConfiguration {
pub fn new( pub fn new(
idx: usize, reg_idx: usize,
size: u64, size: u64,
region_type: PciBarRegionType, region_type: PciBarRegionType,
prefetchable: PciBarPrefetchable, prefetchable: PciBarPrefetchable,
) -> Self { ) -> Self {
PciBarConfiguration { PciBarConfiguration {
idx, reg_idx,
addr: 0, addr: 0,
size, size,
region_type, region_type,
@@ -976,8 +937,8 @@ impl PciBarConfiguration {
} }
#[must_use] #[must_use]
pub fn set_index(mut self, idx: usize) -> Self { pub fn set_register_index(mut self, reg_idx: usize) -> Self {
self.idx = idx; self.reg_idx = reg_idx;
self self
} }
@@ -993,31 +954,15 @@ impl PciBarConfiguration {
self self
} }
pub fn get_size(&self) -> u64 {
self.size
}
#[must_use] #[must_use]
pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self { pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self {
self.region_type = region_type; self.region_type = region_type;
self self
} }
pub fn idx(&self) -> usize {
self.idx
}
pub fn addr(&self) -> u64 {
self.addr
}
pub fn size(&self) -> u64 {
self.size
}
pub fn region_type(&self) -> PciBarRegionType {
self.region_type
}
pub fn prefetchable(&self) -> PciBarPrefetchable {
self.prefetchable
}
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -3,13 +3,13 @@
// found in the LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
use crate::configuration::{self, PciBarRegionType}; use crate::configuration::{self, PciBarRegionType};
use crate::PciBarConfiguration;
use std::any::Any; use std::any::Any;
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::sync::{Arc, Barrier, Mutex}; use std::sync::{Arc, Barrier, Mutex};
use std::{self, io, result}; use std::{self, io, result};
use vm_allocator::{AddressAllocator, SystemAllocator}; use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_device::{BusDevice, Resource}; use vm_device::BusDevice;
use vm_memory::{GuestAddress, GuestUsize};
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@@ -19,8 +19,6 @@ pub enum Error {
IoAllocationFailed(u64), IoAllocationFailed(u64),
/// Registering an IO BAR failed. /// Registering an IO BAR failed.
IoRegistrationFailed(u64, configuration::Error), IoRegistrationFailed(u64, configuration::Error),
/// Expected resource not found.
MissingResource,
} }
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
@@ -36,7 +34,6 @@ impl Display for Error {
IoRegistrationFailed(addr, e) => { IoRegistrationFailed(addr, e) => {
write!(f, "failed to register an IO BAR, addr={} err={}", addr, e) write!(f, "failed to register an IO BAR, addr={} err={}", addr, e)
} }
MissingResource => write!(f, "failed to find expected resource"),
} }
} }
} }
@@ -56,8 +53,7 @@ pub trait PciDevice: BusDevice {
&mut self, &mut self,
_allocator: &Arc<Mutex<SystemAllocator>>, _allocator: &Arc<Mutex<SystemAllocator>>,
_mmio_allocator: &mut AddressAllocator, _mmio_allocator: &mut AddressAllocator,
_resources: Option<Vec<Resource>>, ) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>> {
) -> Result<Vec<PciBarConfiguration>> {
Ok(Vec::new()) Ok(Vec::new())
} }
@@ -107,9 +103,6 @@ pub trait PciDevice: BusDevice {
/// Provides a mutable reference to the Any trait. This is useful to let /// Provides a mutable reference to the Any trait. This is useful to let
/// the caller have access to the underlying type behind the trait. /// the caller have access to the underlying type behind the trait.
fn as_any(&mut self) -> &mut dyn Any; fn as_any(&mut self) -> &mut dyn Any;
/// Optionally returns a unique identifier.
fn id(&self) -> Option<String>;
} }
/// This trait defines a set of functions which can be triggered whenever a /// This trait defines a set of functions which can be triggered whenever a

View File

@@ -52,7 +52,7 @@ pub const PCI_CONFIG_IO_PORT: u64 = 0xcf8;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub const PCI_CONFIG_IO_PORT_SIZE: u64 = 0x8; pub const PCI_CONFIG_IO_PORT_SIZE: u64 = 0x8;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd)] #[derive(Clone, Copy, PartialEq, PartialOrd)]
pub struct PciBdf(u32); pub struct PciBdf(u32);
struct PciBdfVisitor; struct PciBdfVisitor;

View File

@@ -3,17 +3,11 @@
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
// //
use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use std::io;
use std::sync::Arc; use std::sync::Arc;
use thiserror::Error;
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_device::interrupt::{ use vm_device::interrupt::{
InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig, InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig,
}; };
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped};
// MSI control masks // MSI control masks
const MSI_CTL_ENABLE: u16 = 0x1; const MSI_CTL_ENABLE: u16 = 0x1;
@@ -38,15 +32,7 @@ pub fn msi_num_enabled_vectors(msg_ctl: u16) -> usize {
1 << field 1 << field
} }
#[derive(Error, Debug)] #[derive(Clone, Copy, Default)]
enum Error {
#[error("Failed enabling the interrupt route: {0}")]
EnableInterruptRoute(io::Error),
#[error("Failed updating the interrupt route: {0}")]
UpdateInterruptRoute(io::Error),
}
#[derive(Clone, Copy, Default, Versionize)]
pub struct MsiCap { pub struct MsiCap {
// Message Control Register // Message Control Register
// 0: MSI enable. // 0: MSI enable.
@@ -171,15 +157,8 @@ impl MsiCap {
} }
} }
#[derive(Versionize)]
struct MsiConfigState {
cap: MsiCap,
}
impl VersionMapped for MsiConfigState {}
pub struct MsiConfig { pub struct MsiConfig {
pub cap: MsiCap, cap: MsiCap,
interrupt_source_group: Arc<dyn InterruptSourceGroup>, interrupt_source_group: Arc<dyn InterruptSourceGroup>,
} }
@@ -196,39 +175,6 @@ impl MsiConfig {
} }
} }
fn state(&self) -> MsiConfigState {
MsiConfigState { cap: self.cap }
}
fn set_state(&mut self, state: &MsiConfigState) -> Result<(), Error> {
self.cap = state.cap;
if self.enabled() {
for idx in 0..self.num_enabled_vectors() {
let config = MsiIrqSourceConfig {
high_addr: self.cap.msg_addr_hi,
low_addr: self.cap.msg_addr_lo,
data: self.cap.msg_data as u32,
devid: 0,
};
self.interrupt_source_group
.update(
idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
self.cap.vector_masked(idx),
)
.map_err(Error::UpdateInterruptRoute)?;
}
self.interrupt_source_group
.enable()
.map_err(Error::EnableInterruptRoute)?;
}
Ok(())
}
pub fn enabled(&self) -> bool { pub fn enabled(&self) -> bool {
self.cap.enabled() self.cap.enabled()
} }
@@ -276,26 +222,3 @@ impl MsiConfig {
} }
} }
} }
impl Pausable for MsiConfig {}
impl Snapshottable for MsiConfig {
fn id(&self) -> String {
String::from("msi_config")
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_versioned_state(&self.id(), &self.state())
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
self.set_state(&snapshot.to_versioned_state(&self.id())?)
.map_err(|e| {
MigratableError::Restore(anyhow!(
"Could not restore state for {}: {:?}",
self.id(),
e
))
})
}
}

View File

@@ -441,7 +441,7 @@ impl Snapshottable for MsixConfig {
#[allow(dead_code)] #[allow(dead_code)]
#[repr(packed)] #[repr(packed)]
#[derive(Clone, Copy, Default, Versionize)] #[derive(Clone, Copy, Default)]
pub struct MsixCap { pub struct MsixCap {
// Message Control Register // Message Control Register
// 10-0: MSI-X Table size // 10-0: MSI-X Table size

File diff suppressed because it is too large Load Diff

View File

@@ -3,12 +3,11 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
use crate::vfio::{Interrupt, UserMemoryRegion, Vfio, VfioCommon, VfioError}; use crate::vfio::{Interrupt, Vfio, VfioCommon, VfioError};
use crate::{BarReprogrammingParams, PciBarConfiguration, VfioPciError}; use crate::{BarReprogrammingParams, PciBarRegionType, VfioPciError};
use crate::{ use crate::{
PciBdf, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass, PciBdf, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
}; };
use anyhow::anyhow;
use hypervisor::HypervisorVmError; use hypervisor::HypervisorVmError;
use std::any::Any; use std::any::Any;
use std::os::unix::prelude::AsRawFd; use std::os::unix::prelude::AsRawFd;
@@ -22,20 +21,19 @@ use vfio_user::{Client, Error as VfioUserError};
use vm_allocator::{AddressAllocator, SystemAllocator}; use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_device::dma_mapping::ExternalDmaMapping; use vm_device::dma_mapping::ExternalDmaMapping;
use vm_device::interrupt::{InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig}; use vm_device::interrupt::{InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig};
use vm_device::{BusDevice, Resource}; use vm_device::BusDevice;
use vm_memory::bitmap::AtomicBitmap; use vm_memory::bitmap::AtomicBitmap;
use vm_memory::{ use vm_memory::{
Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryRegion, GuestRegionMmap, Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryRegion, GuestRegionMmap,
GuestUsize,
}; };
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
pub struct VfioUserPciDevice { pub struct VfioUserPciDevice {
id: String,
vm: Arc<dyn hypervisor::Vm>, vm: Arc<dyn hypervisor::Vm>,
client: Arc<Mutex<Client>>, client: Arc<Mutex<Client>>,
vfio_wrapper: VfioUserClientWrapper,
common: VfioCommon, common: VfioCommon,
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]
@@ -64,16 +62,12 @@ impl PciSubclass for PciVfioUserSubclass {
} }
impl VfioUserPciDevice { impl VfioUserPciDevice {
#[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
id: String,
vm: &Arc<dyn hypervisor::Vm>, vm: &Arc<dyn hypervisor::Vm>,
client: Arc<Mutex<Client>>, client: Arc<Mutex<Client>>,
msi_interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>, msi_interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>, legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
bdf: PciBdf, bdf: PciBdf,
restoring: bool,
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
) -> Result<Self, VfioUserPciDeviceError> { ) -> Result<Self, VfioUserPciDeviceError> {
// This is used for the BAR and capabilities only // This is used for the BAR and capabilities only
let configuration = PciConfiguration::new( let configuration = PciConfiguration::new(
@@ -109,31 +103,29 @@ impl VfioUserPciDevice {
msi: None, msi: None,
msix: None, msix: None,
}, },
msi_interrupt_manager,
legacy_interrupt_group,
vfio_wrapper: Arc::new(vfio_wrapper) as Arc<dyn Vfio>,
}; };
// No need to parse capabilities from the device if on the restore path. common.parse_capabilities(msi_interrupt_manager, &vfio_wrapper, bdf);
// The initialization will be performed later when restore() will be common
// called. .initialize_legacy_interrupt(legacy_interrupt_group, &vfio_wrapper)
if !restoring { .map_err(VfioUserPciDeviceError::InitializeLegacyInterrupts)?;
common.parse_capabilities(bdf);
common
.initialize_legacy_interrupt()
.map_err(VfioUserPciDeviceError::InitializeLegacyInterrupts)?;
}
Ok(Self { Ok(Self {
id,
vm: vm.clone(), vm: vm.clone(),
client, client,
vfio_wrapper,
common, common,
memory_slot,
}) })
} }
pub fn map_mmio_regions(&mut self) -> Result<(), VfioUserPciDeviceError> { pub fn map_mmio_regions<F>(
&mut self,
vm: &Arc<dyn hypervisor::Vm>,
mem_slot: F,
) -> Result<(), VfioUserPciDeviceError>
where
F: Fn() -> u32,
{
for mmio_region in &mut self.common.mmio_regions { for mmio_region in &mut self.common.mmio_regions {
let region_flags = self let region_flags = self
.client .client
@@ -151,15 +143,6 @@ impl VfioUserPciDevice {
.file_offset .file_offset
.clone(); .clone();
let sparse_areas = self
.client
.lock()
.unwrap()
.region(mmio_region.index)
.unwrap()
.sparse_areas
.clone();
if region_flags & VFIO_REGION_INFO_FLAG_MMAP != 0 { if region_flags & VFIO_REGION_INFO_FLAG_MMAP != 0 {
let mut prot = 0; let mut prot = 0;
if region_flags & VFIO_REGION_INFO_FLAG_READ != 0 { if region_flags & VFIO_REGION_INFO_FLAG_READ != 0 {
@@ -169,58 +152,41 @@ impl VfioUserPciDevice {
prot |= libc::PROT_WRITE; prot |= libc::PROT_WRITE;
} }
let mmaps = if sparse_areas.is_empty() { let host_addr = unsafe {
vec![vfio_region_sparse_mmap_area { libc::mmap(
offset: 0, null_mut(),
size: mmio_region.length, mmio_region.length as usize,
}] prot,
} else { libc::MAP_SHARED,
sparse_areas file_offset.as_ref().unwrap().file().as_raw_fd(),
file_offset.as_ref().unwrap().start() as libc::off_t,
)
}; };
for s in mmaps.iter() { if host_addr == libc::MAP_FAILED {
let host_addr = unsafe { error!(
libc::mmap( "Could not mmap regions, error:{}",
null_mut(), std::io::Error::last_os_error()
s.size as usize,
prot,
libc::MAP_SHARED,
file_offset.as_ref().unwrap().file().as_raw_fd(),
file_offset.as_ref().unwrap().start() as libc::off_t
+ s.offset as libc::off_t,
)
};
if host_addr == libc::MAP_FAILED {
error!(
"Could not mmap regions, error:{}",
std::io::Error::last_os_error()
);
continue;
}
let user_memory_region = UserMemoryRegion {
slot: (self.memory_slot)(),
start: mmio_region.start.0 + s.offset,
size: s.size,
host_addr: host_addr as u64,
};
mmio_region.user_memory_regions.push(user_memory_region);
let mem_region = self.vm.make_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
); );
continue;
self.vm
.create_user_memory_region(mem_region)
.map_err(VfioUserPciDeviceError::MapRegionGuest)?;
} }
let slot = mem_slot();
let mem_region = vm.make_user_memory_region(
slot,
mmio_region.start.0,
mmio_region.length as u64,
host_addr as u64,
false,
false,
);
vm.create_user_memory_region(mem_region)
.map_err(VfioUserPciDeviceError::MapRegionGuest)?;
mmio_region.mem_slot = Some(slot);
mmio_region.host_addr = Some(host_addr as u64);
mmio_region.mmap_size = Some(mmio_region.length as usize);
} }
} }
@@ -229,13 +195,17 @@ impl VfioUserPciDevice {
pub fn unmap_mmio_regions(&mut self) { pub fn unmap_mmio_regions(&mut self) {
for mmio_region in self.common.mmio_regions.iter() { for mmio_region in self.common.mmio_regions.iter() {
for user_memory_region in mmio_region.user_memory_regions.iter() { if let (Some(host_addr), Some(mmap_size), Some(mem_slot)) = (
mmio_region.host_addr,
mmio_region.mmap_size,
mmio_region.mem_slot,
) {
// Remove region // Remove region
let r = self.vm.make_user_memory_region( let r = self.vm.make_user_memory_region(
user_memory_region.slot, mem_slot,
user_memory_region.start, mmio_region.start.raw_value(),
user_memory_region.size, mmap_size as u64,
user_memory_region.host_addr, host_addr as u64,
false, false,
false, false,
); );
@@ -244,13 +214,7 @@ impl VfioUserPciDevice {
error!("Could not remove the userspace memory region: {}", e); error!("Could not remove the userspace memory region: {}", e);
} }
// Remove mmaps let ret = unsafe { libc::munmap(host_addr as *mut libc::c_void, mmap_size) };
let ret = unsafe {
libc::munmap(
user_memory_region.host_addr as *mut libc::c_void,
user_memory_region.size as usize,
)
};
if ret != 0 { if ret != 0 {
error!( error!(
"Could not unmap region {}, error:{}", "Could not unmap region {}, error:{}",
@@ -428,10 +392,9 @@ impl PciDevice for VfioUserPciDevice {
&mut self, &mut self,
allocator: &Arc<Mutex<SystemAllocator>>, allocator: &Arc<Mutex<SystemAllocator>>,
mmio_allocator: &mut AddressAllocator, mmio_allocator: &mut AddressAllocator,
resources: Option<Vec<Resource>>, ) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
) -> Result<Vec<PciBarConfiguration>, PciDeviceError> {
self.common self.common
.allocate_bars(allocator, mmio_allocator, resources) .allocate_bars(allocator, mmio_allocator, &self.vfio_wrapper)
} }
fn free_bars( fn free_bars(
@@ -462,19 +425,22 @@ impl PciDevice for VfioUserPciDevice {
offset: u64, offset: u64,
data: &[u8], data: &[u8],
) -> Option<Arc<Barrier>> { ) -> Option<Arc<Barrier>> {
self.common.write_config_register(reg_idx, offset, data) self.common
.write_config_register(reg_idx, offset, data, &self.vfio_wrapper)
} }
fn read_config_register(&mut self, reg_idx: usize) -> u32 { fn read_config_register(&mut self, reg_idx: usize) -> u32 {
self.common.read_config_register(reg_idx) self.common
.read_config_register(reg_idx, &self.vfio_wrapper)
} }
fn read_bar(&mut self, base: u64, offset: u64, data: &mut [u8]) { fn read_bar(&mut self, base: u64, offset: u64, data: &mut [u8]) {
self.common.read_bar(base, offset, data) self.common.read_bar(base, offset, data, &self.vfio_wrapper)
} }
fn write_bar(&mut self, base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> { fn write_bar(&mut self, base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
self.common.write_bar(base, offset, data) self.common
.write_bar(base, offset, data, &self.vfio_wrapper)
} }
fn move_bar(&mut self, old_base: u64, new_base: u64) -> Result<(), std::io::Error> { fn move_bar(&mut self, old_base: u64, new_base: u64) -> Result<(), std::io::Error> {
@@ -483,41 +449,35 @@ impl PciDevice for VfioUserPciDevice {
if mmio_region.start.raw_value() == old_base { if mmio_region.start.raw_value() == old_base {
mmio_region.start = GuestAddress(new_base); mmio_region.start = GuestAddress(new_base);
for user_memory_region in mmio_region.user_memory_regions.iter_mut() { if let Some(mem_slot) = mmio_region.mem_slot {
// Remove old region if let Some(host_addr) = mmio_region.host_addr {
let old_region = self.vm.make_user_memory_region( // Remove original region
user_memory_region.slot, let old_region = self.vm.make_user_memory_region(
user_memory_region.start, mem_slot,
user_memory_region.size, old_base,
user_memory_region.host_addr, mmio_region.length as u64,
false, host_addr as u64,
false, false,
); false,
);
self.vm self.vm
.remove_user_memory_region(old_region) .remove_user_memory_region(old_region)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?; .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
// Update the user memory region with the correct start address. let new_region = self.vm.make_user_memory_region(
if new_base > old_base { mem_slot,
user_memory_region.start += new_base - old_base; new_base,
} else { mmio_region.length as u64,
user_memory_region.start -= old_base - new_base; host_addr as u64,
false,
false,
);
self.vm
.create_user_memory_region(new_region)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
} }
// Insert new region
let new_region = self.vm.make_user_memory_region(
user_memory_region.slot,
user_memory_region.start,
user_memory_region.size,
user_memory_region.host_addr,
false,
false,
);
self.vm
.create_user_memory_region(new_region)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
} }
info!("Moved bar 0x{:x} -> 0x{:x}", old_base, new_base); info!("Moved bar 0x{:x} -> 0x{:x}", old_base, new_base);
} }
@@ -525,10 +485,6 @@ impl PciDevice for VfioUserPciDevice {
Ok(()) Ok(())
} }
fn id(&self) -> Option<String> {
Some(self.id.clone())
}
} }
impl Drop for VfioUserPciDevice { impl Drop for VfioUserPciDevice {
@@ -537,18 +493,18 @@ impl Drop for VfioUserPciDevice {
if let Some(msix) = &self.common.interrupt.msix { if let Some(msix) = &self.common.interrupt.msix {
if msix.bar.enabled() { if msix.bar.enabled() {
self.common.disable_msix(); self.common.disable_msix(&self.vfio_wrapper);
} }
} }
if let Some(msi) = &self.common.interrupt.msi { if let Some(msi) = &self.common.interrupt.msi {
if msi.cfg.enabled() { if msi.cfg.enabled() {
self.common.disable_msi() self.common.disable_msi(&self.vfio_wrapper)
} }
} }
if self.common.interrupt.intx_in_use() { if self.common.interrupt.intx_in_use() {
self.common.disable_intx(); self.common.disable_intx(&self.vfio_wrapper);
} }
if let Err(e) = self.client.lock().unwrap().shutdown() { if let Err(e) = self.client.lock().unwrap().shutdown() {
@@ -557,40 +513,6 @@ impl Drop for VfioUserPciDevice {
} }
} }
impl Pausable for VfioUserPciDevice {}
impl Snapshottable for VfioUserPciDevice {
fn id(&self) -> String {
self.id.clone()
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let mut vfio_pci_dev_snapshot = Snapshot::new(&self.id);
// Snapshot VfioCommon
vfio_pci_dev_snapshot.add_snapshot(self.common.snapshot()?);
Ok(vfio_pci_dev_snapshot)
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
// Restore VfioCommon
if let Some(vfio_common_snapshot) = snapshot.snapshots.get(&self.common.id()) {
self.common.restore(*vfio_common_snapshot.clone())?;
self.map_mmio_regions().map_err(|e| {
MigratableError::Restore(anyhow!(
"Could not map MMIO regions for VfioUserPciDevice on restore {:?}",
e
))
})?;
}
Ok(())
}
}
impl Transportable for VfioUserPciDevice {}
impl Migratable for VfioUserPciDevice {}
pub struct VfioUserDmaMapping<M: GuestAddressSpace> { pub struct VfioUserDmaMapping<M: GuestAddressSpace> {
client: Arc<Mutex<Client>>, client: Arc<Mutex<Client>>,
memory: Arc<M>, memory: Arc<M>,
@@ -624,10 +546,10 @@ impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioUserDmaMappi
) )
}) })
} else { } else {
Err(std::io::Error::new( return Err(std::io::Error::new(
std::io::ErrorKind::Other, std::io::ErrorKind::Other,
format!("Region not found for 0x{:x}", gpa), format!("Region not found for 0x{:x}", gpa),
)) ));
} }
} }

View File

@@ -6,13 +6,14 @@ edition = "2021"
build = "build.rs" build = "build.rs"
[dependencies] [dependencies]
clap = { version = "3.2.8", features = ["wrap_help","cargo"] } clap = { version = "3.1.8", features = ["wrap_help","cargo"] }
dirs = "4.0.0" dirs = "4.0.0"
serde = { version = "1.0.138", features = ["rc", "derive"] } serde = { version = "1.0.136", features = ["rc"] }
serde_json = "1.0.82" serde_derive = "1.0.136"
serde_json = "1.0.78"
test_infra = { path = "../test_infra" } test_infra = { path = "../test_infra" }
thiserror = "1.0.31" thiserror = "1.0.30"
wait-timeout = "0.2.0" wait-timeout = "0.2.0"
[build-dependencies] [build-dependencies]
clap = { version = "3.2.8", features = ["cargo"] } clap = { version = "3.1.8", features = ["cargo"] }

View File

@@ -12,14 +12,8 @@ mod performance_tests;
use clap::{Arg, Command as ClapCommand}; use clap::{Arg, Command as ClapCommand};
use performance_tests::*; use performance_tests::*;
use serde::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::{ use std::{env, fmt, process::Command, sync::mpsc::channel, thread, time::Duration};
env, fmt,
process::Command,
sync::{mpsc::channel, Arc},
thread,
time::Duration,
};
use thiserror::Error; use thiserror::Error;
#[derive(Error, Debug)] #[derive(Error, Debug)]
@@ -53,30 +47,18 @@ impl Default for MetricsReport {
let mut git_human_readable = "".to_string(); let mut git_human_readable = "".to_string();
if let Ok(git_out) = Command::new("git").args(&["describe", "--dirty"]).output() { if let Ok(git_out) = Command::new("git").args(&["describe", "--dirty"]).output() {
if git_out.status.success() { if git_out.status.success() {
git_human_readable = String::from_utf8(git_out.stdout) if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
.unwrap() git_human_readable = git_out_str.trim().to_string();
.trim() }
.to_string();
} else {
eprintln!(
"Error generating human readable git reference: {}",
String::from_utf8(git_out.stderr).unwrap()
);
} }
} }
let mut git_revision = "".to_string(); let mut git_revision = "".to_string();
if let Ok(git_out) = Command::new("git").args(&["rev-parse", "HEAD"]).output() { if let Ok(git_out) = Command::new("git").args(&["rev-parse", "HEAD"]).output() {
if git_out.status.success() { if git_out.status.success() {
git_revision = String::from_utf8(git_out.stdout) if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
.unwrap() git_revision = git_out_str.trim().to_string();
.trim() }
.to_string();
} else {
eprintln!(
"Error generating git reference: {}",
String::from_utf8(git_out.stderr).unwrap()
);
} }
} }
@@ -86,15 +68,9 @@ impl Default for MetricsReport {
.output() .output()
{ {
if git_out.status.success() { if git_out.status.success() {
git_commit_date = String::from_utf8(git_out.stdout) if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
.unwrap() git_commit_date = git_out_str.trim().to_string();
.trim() }
.to_string();
} else {
eprintln!(
"Error generating git commit date: {}",
String::from_utf8(git_out.stderr).unwrap()
);
} }
} }
@@ -108,21 +84,6 @@ impl Default for MetricsReport {
} }
} }
#[derive(Default)]
pub struct PerformanceTestOverrides {
test_iterations: Option<u32>,
}
impl fmt::Display for PerformanceTestOverrides {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(test_iterations) = self.test_iterations {
write!(f, "test_iterations = {}", test_iterations)?;
}
Ok(())
}
}
pub struct PerformanceTestControl { pub struct PerformanceTestControl {
test_timeout: u32, test_timeout: u32,
test_iterations: u32, test_iterations: u32,
@@ -130,7 +91,6 @@ pub struct PerformanceTestControl {
queue_size: Option<u32>, queue_size: Option<u32>,
net_rx: Option<bool>, net_rx: Option<bool>,
fio_ops: Option<FioOps>, fio_ops: Option<FioOps>,
num_boot_vcpus: Option<u8>,
} }
impl fmt::Display for PerformanceTestControl { impl fmt::Display for PerformanceTestControl {
@@ -165,7 +125,6 @@ impl PerformanceTestControl {
queue_size: None, queue_size: None,
net_rx: None, net_rx: None,
fio_ops: None, fio_ops: None,
num_boot_vcpus: Some(1),
} }
} }
} }
@@ -181,12 +140,9 @@ struct PerformanceTest {
} }
impl PerformanceTest { impl PerformanceTest {
pub fn run(&self, overrides: &PerformanceTestOverrides) -> PerformanceTestResult { pub fn run(&self) -> PerformanceTestResult {
let mut metrics = Vec::new(); let mut metrics = Vec::new();
for _ in 0..overrides for _ in 0..self.control.test_iterations {
.test_iterations
.unwrap_or(self.control.test_iterations)
{
metrics.push((self.func_ptr)(&self.control)); metrics.push((self.func_ptr)(&self.control));
} }
@@ -206,9 +162,8 @@ impl PerformanceTest {
// Calculate the timeout for each test // Calculate the timeout for each test
// Note: To cover the setup/cleanup time, 20s is added for each iteration of the test // Note: To cover the setup/cleanup time, 20s is added for each iteration of the test
pub fn calc_timeout(&self, test_iterations: &Option<u32>) -> u64 { pub fn calc_timeout(&self) -> u64 {
((self.control.test_timeout + 20) * test_iterations.unwrap_or(self.control.test_iterations)) ((self.control.test_timeout + 20) * self.control.test_iterations) as u64
as u64
} }
} }
@@ -261,7 +216,7 @@ mod adjuster {
} }
} }
const TEST_LIST: [PerformanceTest; 17] = [ const TEST_LIST: [PerformanceTest; 15] = [
PerformanceTest { PerformanceTest {
name: "boot_time_ms", name: "boot_time_ms",
func_ptr: performance_boot_time, func_ptr: performance_boot_time,
@@ -282,28 +237,6 @@ const TEST_LIST: [PerformanceTest; 17] = [
}, },
unit_adjuster: adjuster::s_to_ms, unit_adjuster: adjuster::s_to_ms,
}, },
PerformanceTest {
name: "boot_time_16_vcpus_ms",
func_ptr: performance_boot_time,
control: PerformanceTestControl {
test_timeout: 2,
test_iterations: 10,
num_boot_vcpus: Some(16),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::s_to_ms,
},
PerformanceTest {
name: "boot_time_16_vcpus_pmem_ms",
func_ptr: performance_boot_time_pmem,
control: PerformanceTestControl {
test_timeout: 2,
test_iterations: 10,
num_boot_vcpus: Some(16),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::s_to_ms,
},
PerformanceTest { PerformanceTest {
name: "virtio_net_latency_us", name: "virtio_net_latency_us",
func_ptr: performance_net_latency, func_ptr: performance_net_latency,
@@ -448,20 +381,12 @@ const TEST_LIST: [PerformanceTest; 17] = [
}, },
]; ];
fn run_test_with_timeout( fn run_test_with_timeout(test: &'static PerformanceTest) -> Result<PerformanceTestResult, Error> {
test: &'static PerformanceTest,
overrides: &Arc<PerformanceTestOverrides>,
) -> Result<PerformanceTestResult, Error> {
let (sender, receiver) = channel::<Result<PerformanceTestResult, Error>>(); let (sender, receiver) = channel::<Result<PerformanceTestResult, Error>>();
let test_iterations = overrides.test_iterations;
let overrides = overrides.clone();
thread::spawn(move || { thread::spawn(move || {
println!( println!("Test '{}' running .. ({})", test.name, test.control);
"Test '{}' running .. (control: {}, overrides: {})",
test.name, test.control, overrides
);
let output = match std::panic::catch_unwind(|| test.run(&overrides)) { let output = match std::panic::catch_unwind(|| test.run()) {
Ok(test_result) => { Ok(test_result) => {
println!( println!(
"Test '{}' .. ok: mean = {}, std_dev = {}", "Test '{}' .. ok: mean = {}, std_dev = {}",
@@ -476,7 +401,7 @@ fn run_test_with_timeout(
}); });
// Todo: Need to cleanup/kill all hanging child processes // Todo: Need to cleanup/kill all hanging child processes
let test_timeout = test.calc_timeout(&test_iterations); let test_timeout = test.calc_timeout();
receiver receiver
.recv_timeout(Duration::from_secs(test_timeout)) .recv_timeout(Duration::from_secs(test_timeout))
.map_err(|_| { .map_err(|_| {
@@ -520,12 +445,6 @@ fn main() {
.help("Report file. Standard error is used if not specified") .help("Report file. Standard error is used if not specified")
.takes_value(true), .takes_value(true),
) )
.arg(
Arg::new("iterations")
.long("iterations")
.help("Override number of test iterations")
.takes_value(true),
)
.get_matches(); .get_matches();
// It seems that the tool (ethr) used for testing the virtio-net latency // It seems that the tool (ethr) used for testing the virtio-net latency
@@ -554,17 +473,9 @@ fn main() {
init_tests(); init_tests();
let overrides = Arc::new(PerformanceTestOverrides {
test_iterations: cmd_arguments
.value_of("iterations")
.map(|s| s.parse())
.transpose()
.unwrap_or_default(),
});
for test in test_list.iter() { for test in test_list.iter() {
if test_filter.is_empty() || test_filter.iter().any(|&s| test.name.contains(s)) { if test_filter.is_empty() || test_filter.iter().any(|&s| test.name.contains(s)) {
match run_test_with_timeout(test, &overrides) { match run_test_with_timeout(test) {
Ok(r) => { Ok(r) => {
metrics_report.results.push(r); metrics_report.results.push(r);
} }

View File

@@ -238,7 +238,6 @@ pub fn performance_net_throughput(control: &PerformanceTestControl) -> f64 {
.default_disks() .default_disks()
.args(&["--net", net_params.as_str()]) .args(&["--net", net_params.as_str()])
.capture_output() .capture_output()
.verbosity(VerbosityLevel::Warn)
.set_print_cmd(false) .set_print_cmd(false)
.spawn() .spawn()
.unwrap(); .unwrap();
@@ -368,7 +367,6 @@ pub fn performance_net_latency(control: &PerformanceTestControl) -> f64 {
.default_disks() .default_disks()
.args(&["--net", net_params.as_str()]) .args(&["--net", net_params.as_str()])
.capture_output() .capture_output()
.verbosity(VerbosityLevel::Warn)
.set_print_cmd(false) .set_print_cmd(false)
.spawn() .spawn()
.unwrap(); .unwrap();
@@ -474,12 +472,7 @@ fn parse_boot_time_output(output: &[u8]) -> Result<f64, Error> {
} }
fn measure_boot_time(cmd: &mut GuestCommand, test_timeout: u32) -> Result<f64, Error> { fn measure_boot_time(cmd: &mut GuestCommand, test_timeout: u32) -> Result<f64, Error> {
let mut child = cmd let mut child = cmd.capture_output().set_print_cmd(false).spawn().unwrap();
.capture_output()
.verbosity(VerbosityLevel::Warn)
.set_print_cmd(false)
.spawn()
.unwrap();
thread::sleep(Duration::new(test_timeout as u64, 0)); thread::sleep(Duration::new(test_timeout as u64, 0));
let _ = child.kill(); let _ = child.kill();
@@ -506,10 +499,6 @@ pub fn performance_boot_time(control: &PerformanceTestControl) -> f64 {
let mut cmd = GuestCommand::new(&guest); let mut cmd = GuestCommand::new(&guest);
let c = cmd let c = cmd
.args(&[
"--cpus",
&format!("boot={}", control.num_boot_vcpus.unwrap_or(1)),
])
.args(&["--memory", "size=1G"]) .args(&["--memory", "size=1G"])
.args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()]) .args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()])
.args(&["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE]) .args(&["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
@@ -533,10 +522,6 @@ pub fn performance_boot_time_pmem(control: &PerformanceTestControl) -> f64 {
let guest = performance_test_new_guest(Box::new(focal)); let guest = performance_test_new_guest(Box::new(focal));
let mut cmd = GuestCommand::new(&guest); let mut cmd = GuestCommand::new(&guest);
let c = cmd let c = cmd
.args(&[
"--cpus",
&format!("boot={}", control.num_boot_vcpus.unwrap_or(1)),
])
.args(&["--memory", "size=1G,hugepages=on"]) .args(&["--memory", "size=1G,hugepages=on"])
.args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()]) .args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()])
.args(&["--cmdline", "root=/dev/pmem0p1 console=ttyS0 quiet rw"]) .args(&["--cmdline", "root=/dev/pmem0p1 console=ttyS0 quiet rw"])
@@ -670,7 +655,6 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
.default_net() .default_net()
.args(&["--api-socket", &api_socket]) .args(&["--api-socket", &api_socket])
.capture_output() .capture_output()
.verbosity(VerbosityLevel::Warn)
.set_print_cmd(false) .set_print_cmd(false)
.spawn() .spawn()
.unwrap(); .unwrap();

View File

@@ -10,7 +10,7 @@ path = "src/qcow.rs"
[dependencies] [dependencies]
byteorder = "1.4.3" byteorder = "1.4.3"
libc = "0.2.126" libc = "0.2.123"
log = "0.4.17" log = "0.4.16"
remain = "0.2.3" remain = "0.2.2"
vmm-sys-util = "0.9.0" vmm-sys-util = "0.9.0"

View File

@@ -516,19 +516,6 @@ impl QcowFile {
let l2_entries = cluster_size / size_of::<u64>() as u64; let l2_entries = cluster_size / size_of::<u64>() as u64;
// Check for compressed blocks
for l2_addr_disk in l1_table.get_values() {
if *l2_addr_disk != 0 {
if let Err(e) = Self::read_l2_cluster(&mut raw_file, *l2_addr_disk) {
if let Some(os_error) = e.raw_os_error() {
if os_error == ENOTSUP {
return Err(Error::CompressedBlocksNotSupported);
}
}
}
}
}
let mut qcow = QcowFile { let mut qcow = QcowFile {
raw_file, raw_file,
header, header,

View File

@@ -4,6 +4,6 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
libc = "0.2.126" libc = "0.2.123"
log = "0.4.17" log = "0.4.16"
vmm-sys-util = "0.9.0" vmm-sys-util = "0.9.0"

View File

@@ -91,7 +91,7 @@ pub enum BucketReduction {
/// TokenBucket provides a lower level interface to rate limiting with a /// TokenBucket provides a lower level interface to rate limiting with a
/// configurable capacity, refill-rate and initial burst. /// configurable capacity, refill-rate and initial burst.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq)]
pub struct TokenBucket { pub struct TokenBucket {
// Bucket defining traits. // Bucket defining traits.
size: u64, size: u64,

View File

@@ -1,28 +1,12 @@
- [v25.0](#v250)
- [`ch-remote` Improvements](#ch-remote-improvements)
- [VM "Coredump" Support](#vm-coredump-support)
- [Notable Bug Fixes](#notable-bug-fixes)
- [Removals](#removals)
- [Contributors](#contributors)
- [v24.0](#v240)
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
- [Sparse Mmap support](#sparse-mmap-support)
- [Expose Platform Serial Number](#expose-platform-serial-number)
- [Notable Bug Fixes](#notable-bug-fixes-1)
- [Notable Improvements](#notable-improvements)
- [Deprecations](#deprecations)
- [New on the Website](#new-on-the-website)
- [Contributors](#contributors-1)
- [v23.1](#v231) - [v23.1](#v231)
- [v23.0](#v230) - [v23.0](#v230)
- [vDPA Support](#vdpa-support) - [vDPA Support](#vdpa-support)
- [Updated OS Support list](#updated-os-support-list) - [Updated OS Support list](#updated-os-support-list)
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements) - [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
- [`AMX` Support](#amx-support) - [`AMX` Support](#amx-support)
- [Notable Bug Fixes](#notable-bug-fixes-2) - [Notable Bug Fixes](#notable-bug-fixes)
- [Deprecations](#deprecations-1) - [Deprecations](#deprecations)
- [Contributors](#contributors-2) - [Contributors](#contributors)
- [v22.1](#v221) - [v22.1](#v221)
- [v22.0](#v220) - [v22.0](#v220)
- [GDB Debug Stub Support](#gdb-debug-stub-support) - [GDB Debug Stub Support](#gdb-debug-stub-support)
@@ -33,13 +17,13 @@
- [PMU Support for AArch64](#pmu-support-for-aarch64) - [PMU Support for AArch64](#pmu-support-for-aarch64)
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license) - [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd) - [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
- [Notable Bug Fixes](#notable-bug-fixes-3) - [Notable Bug Fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-3) - [Contributors](#contributors-1)
- [v21.0](#v210) - [v21.0](#v210)
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade) - [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515) - [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
- [Notable Bug fixes](#notable-bug-fixes-4) - [Notable Bug fixes](#notable-bug-fixes-2)
- [Contributors](#contributors-4) - [Contributors](#contributors-2)
- [v20.2](#v202) - [v20.2](#v202)
- [v20.1](#v201) - [v20.1](#v201)
- [v20.0](#v200) - [v20.0](#v200)
@@ -48,8 +32,8 @@
- [Improved VFIO support](#improved-vfio-support) - [Improved VFIO support](#improved-vfio-support)
- [Safer code](#safer-code) - [Safer code](#safer-code)
- [Extended documentation](#extended-documentation) - [Extended documentation](#extended-documentation)
- [Notable bug fixes](#notable-bug-fixes-5) - [Notable bug fixes](#notable-bug-fixes-3)
- [Contributors](#contributors-5) - [Contributors](#contributors-3)
- [v19.0](#v190) - [v19.0](#v190)
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console) - [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
- [PCI boot time optimisations](#pci-boot-time-optimisations) - [PCI boot time optimisations](#pci-boot-time-optimisations)
@@ -57,8 +41,8 @@
- [Live migration enhancements](#live-migration-enhancements) - [Live migration enhancements](#live-migration-enhancements)
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user) - [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu) - [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
- [Notable bug fixes](#notable-bug-fixes-6) - [Notable bug fixes](#notable-bug-fixes-4)
- [Contributors](#contributors-6) - [Contributors](#contributors-4)
- [v18.0](#v180) - [v18.0](#v180)
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support) - [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices) - [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
@@ -68,31 +52,31 @@
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor) - [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
- [AArch64 CPU topology support](#aarch64-cpu-topology-support) - [AArch64 CPU topology support](#aarch64-cpu-topology-support)
- [Power button support on AArch64](#power-button-support-on-aarch64) - [Power button support on AArch64](#power-button-support-on-aarch64)
- [Notable bug fixes](#notable-bug-fixes-7) - [Notable bug fixes](#notable-bug-fixes-5)
- [Contributors](#contributors-7) - [Contributors](#contributors-5)
- [v17.0](#v170) - [v17.0](#v170)
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi) - [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend) - [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices) - [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
- [Improved SGX support](#improved-sgx-support) - [Improved SGX support](#improved-sgx-support)
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices) - [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
- [Notable bug fixes](#notable-bug-fixes-8) - [Notable bug fixes](#notable-bug-fixes-6)
- [Contributors](#contributors-8) - [Contributors](#contributors-6)
- [v16.0](#v160) - [v16.0](#v160)
- [Improved live migration support](#improved-live-migration-support) - [Improved live migration support](#improved-live-migration-support)
- [Improved `vhost-user` support](#improved-vhost-user-support) - [Improved `vhost-user` support](#improved-vhost-user-support)
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support) - [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
- [Notable bug fixes](#notable-bug-fixes-9) - [Notable bug fixes](#notable-bug-fixes-7)
- [Removed functionality](#removed-functionality) - [Removed functionality](#removed-functionality)
- [Contributors](#contributors-9) - [Contributors](#contributors-7)
- [v15.0](#v150) - [v15.0](#v150)
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees) - [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
- [Network device rate limiting](#network-device-rate-limiting) - [Network device rate limiting](#network-device-rate-limiting)
- [Support for runtime control of `virtio-net` guest offload](#support-for-runtime-control-of-virtio-net-guest-offload) - [Support for runtime control of `virtio-net` guest offload](#support-for-runtime-control-of-virtio-net-guest-offload)
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter) - [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
- [Bug fixes](#bug-fixes) - [Bug fixes](#bug-fixes)
- [Deprecations](#deprecations-2) - [Deprecations](#deprecations-1)
- [Contributors](#contributors-10) - [Contributors](#contributors-8)
- [v0.14.1](#v0141) - [v0.14.1](#v0141)
- [v0.14.0](#v0140) - [v0.14.0](#v0140)
- [Structured event monitoring](#structured-event-monitoring) - [Structured event monitoring](#structured-event-monitoring)
@@ -101,8 +85,8 @@
- [Updated hotplug documentation](#updated-hotplug-documentation) - [Updated hotplug documentation](#updated-hotplug-documentation)
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console) - [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
- [Block device rate limiting](#block-device-rate-limiting) - [Block device rate limiting](#block-device-rate-limiting)
- [Deprecations](#deprecations-3) - [Deprecations](#deprecations-2)
- [Contributors](#contributors-11) - [Contributors](#contributors-9)
- [v0.13.0](#v0130) - [v0.13.0](#v0130)
- [Wider VFIO device support](#wider-vfio-device-support) - [Wider VFIO device support](#wider-vfio-device-support)
- [Improved huge page support](#improved-huge-page-support) - [Improved huge page support](#improved-huge-page-support)
@@ -110,13 +94,13 @@
- [VHD disk image support](#vhd-disk-image-support) - [VHD disk image support](#vhd-disk-image-support)
- [Improved Virtio device threading](#improved-virtio-device-threading) - [Improved Virtio device threading](#improved-virtio-device-threading)
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button) - [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
- [Contributors](#contributors-12) - [Contributors](#contributors-10)
- [v0.12.0](#v0120) - [v0.12.0](#v0120)
- [ARM64 enhancements](#arm64-enhancements) - [ARM64 enhancements](#arm64-enhancements)
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning) - [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend) - [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
- [Enhanced "info" API](#enhanced-info-api) - [Enhanced "info" API](#enhanced-info-api)
- [Contributors](#contributors-13) - [Contributors](#contributors-11)
- [v0.11.0](#v0110) - [v0.11.0](#v0110)
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block) - [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
- [Windows Guest Support](#windows-guest-support) - [Windows Guest Support](#windows-guest-support)
@@ -128,15 +112,15 @@
- [Default Log Level Changed](#default-log-level-changed) - [Default Log Level Changed](#default-log-level-changed)
- [New `--balloon` Parameter Added](#new---balloon-parameter-added) - [New `--balloon` Parameter Added](#new---balloon-parameter-added)
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support) - [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
- [Notable Bug Fixes](#notable-bug-fixes-10) - [Notable Bug Fixes](#notable-bug-fixes-8)
- [Contributors](#contributors-14) - [Contributors](#contributors-12)
- [v0.10.0](#v0100) - [v0.10.0](#v0100)
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors) - [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
- [Memory Zones](#memory-zones) - [Memory Zones](#memory-zones)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements) - [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control) - [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
- [Notable Bug Fixes](#notable-bug-fixes-11) - [Notable Bug Fixes](#notable-bug-fixes-9)
- [Contributors](#contributors-15) - [Contributors](#contributors-13)
- [v0.9.0](#v090) - [v0.9.0](#v090)
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support) - [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
- [Block and Network Device Statistics](#block-and-network-device-statistics) - [Block and Network Device Statistics](#block-and-network-device-statistics)
@@ -149,17 +133,17 @@
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support) - [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
- [Intel SGX Support](#intel-sgx-support) - [Intel SGX Support](#intel-sgx-support)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1) - [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-12) - [Notable Bug Fixes](#notable-bug-fixes-10)
- [Contributors](#contributors-16) - [Contributors](#contributors-14)
- [v0.8.0](#v080) - [v0.8.0](#v080)
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support) - [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
- [Experimental ARM64 Support](#experimental-arm64-support) - [Experimental ARM64 Support](#experimental-arm64-support)
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests) - [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices) - [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements) - [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-13) - [Notable Bug Fixes](#notable-bug-fixes-11)
- [Command Line and API Changes](#command-line-and-api-changes) - [Command Line and API Changes](#command-line-and-api-changes)
- [Contributors](#contributors-17) - [Contributors](#contributors-15)
- [v0.7.0](#v070) - [v0.7.0](#v070)
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug) - [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
- [Alternative `libc` Support](#alternative-libc-support) - [Alternative `libc` Support](#alternative-libc-support)
@@ -169,14 +153,14 @@
- [`Seccomp` Sandboxing](#seccomp-sandboxing) - [`Seccomp` Sandboxing](#seccomp-sandboxing)
- [Updated Distribution Support](#updated-distribution-support) - [Updated Distribution Support](#updated-distribution-support)
- [Command Line and API Changes](#command-line-and-api-changes-1) - [Command Line and API Changes](#command-line-and-api-changes-1)
- [Contributors](#contributors-18) - [Contributors](#contributors-16)
- [v0.6.0](#v060) - [v0.6.0](#v060)
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug) - [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
- [Shared Filesystem Improvements](#shared-filesystem-improvements) - [Shared Filesystem Improvements](#shared-filesystem-improvements)
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading) - [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
- [Command Line Interface](#command-line-interface) - [Command Line Interface](#command-line-interface)
- [PVH Boot](#pvh-boot) - [PVH Boot](#pvh-boot)
- [Contributors](#contributors-19) - [Contributors](#contributors-17)
- [v0.5.1](#v051) - [v0.5.1](#v051)
- [v0.5.0](#v050) - [v0.5.0](#v050)
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing) - [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
@@ -184,7 +168,7 @@
- [New Interrupt Management Framework](#new-interrupt-management-framework) - [New Interrupt Management Framework](#new-interrupt-management-framework)
- [Development Tools](#development-tools) - [Development Tools](#development-tools)
- [Kata Containers Integration](#kata-containers-integration) - [Kata Containers Integration](#kata-containers-integration)
- [Contributors](#contributors-20) - [Contributors](#contributors-18)
- [v0.4.0](#v040) - [v0.4.0](#v040)
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition) - [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation) - [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
@@ -193,7 +177,7 @@
- [Userspace IOAPIC by default](#userspace-ioapic-by-default) - [Userspace IOAPIC by default](#userspace-ioapic-by-default)
- [PCI BAR reprogramming](#pci-bar-reprogramming) - [PCI BAR reprogramming](#pci-bar-reprogramming)
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization) - [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
- [Contributors](#contributors-21) - [Contributors](#contributors-19)
- [v0.3.0](#v030) - [v0.3.0](#v030)
- [Block device offloading](#block-device-offloading) - [Block device offloading](#block-device-offloading)
- [Network device backend](#network-device-backend) - [Network device backend](#network-device-backend)
@@ -219,131 +203,6 @@
- [Console over virtio](#console-over-virtio) - [Console over virtio](#console-over-virtio)
- [Unit testing](#unit-testing) - [Unit testing](#unit-testing)
- [Integration tests parallelization](#integration-tests-parallelization) - [Integration tests parallelization](#integration-tests-parallelization)
# v25.0
This release has been tracked through the [v25.0
project](https://github.com/cloud-hypervisor/cloud-hypervisor/projects/29).
### `ch-remote` Improvements
The `ch-remote` command has gained support for creating the VM from a JSON
config and support for booting and deleting the VM from the VMM.
### VM "Coredump" Support
Under the `guest_debug` feature flag it is now possible to extract the memory
of the guest for use in debugging with e.g. the `crash` utility. (#4012)
### Notable Bug Fixes
* Always restore console mode on exit (#4249, #4248)
* Restore vCPUs in numerical order which fixes aarch64 snapshot/restore (#4244)
* Don't try and configure `IFF_RUNNING` on TAP devices (#4279)
* Propagate configured queue size through to vhost-user backend (#4286)
* Always Program vCPU CPUID before running the vCPU to fix running on Linux
5.16 (#4156)
* Enable ACPI MADT "Online Capable" flag for hotpluggable vCPUs to fix newer
Linux guest
### Removals
The following functionality has been removed:
* The `mergeable` option from the `virtio-pmem` support has been removed
(#3968)
* The `dax` option from the `virtio-fs` support has been removed (#3889)
### Contributors
Many thanks to everyone who has contributed to our release:
* Dylan Bargatze <dbargatz@users.noreply.github.com>
* Jinank Jain <jinankjain@microsoft.com>
* Michael Zhao <michael.zhao@arm.com>
* Rob Bradford <robert.bradford@intel.com>
* Sebastien Boeuf <sebastien.boeuf@intel.com>
* Wei Liu <liuwe@microsoft.com>
* Yi Wang <wang.yi59@zte.com.cn>
# v24.0
This release has been tracked through the [v24.0
project](https://github.com/cloud-hypervisor/cloud-hypervisor/projects/28).
### Bypass Mode for `virtio-iommu`
`virtio-iommu` specification describes how a device can be attached by default
to a bypass domain. This feature is particularly helpful for booting a VM with
guest software which doesn't support `virtio-iommu` but still need to access
the device. Now that Cloud Hypervisor supports this feature, it can boot a VM
with Rust Hypervisor Firmware or OVMF even if the `virtio-block` device exposing
the disk image is placed behind a virtual IOMMU.
### Ensure Identifiers Uniqueness
Multiple checks have been added to the code to prevent devices with identical
identifiers from being created, and therefore avoid unexpected behaviors at boot
or whenever a device was hot plugged into the VM.
### Sparse Mmap support
Sparse mmap support has been added to both VFIO and vfio-user devices. This
allows the device regions that are not fully mappable to be partially mapped.
And the more a device region can be mapped into the guest address space, the
fewer VM exits will be generated when this device is accessed. This directly
impacts the performance related to this device.
### Expose Platform Serial Number
A new `serial_number` option has been added to `--platform`, allowing a user to
set a specific serial number for the platform. This number is exposed to the
guest through the SMBIOS.
### Notable Bug Fixes
* Fix loading RAW firmware (#4072)
* Reject compressed QCOW images (#4055)
* Reject virtio-mem resize if device is not activated (#4003)
* Fix potential mmap leaks from VFIO/vfio-user MMIO regions (#4069)
* Fix algorithm finding HOB memory resources (#3983)
### Notable Improvements
* Refactor interrupt handling (#4083)
* Load kernel asynchronously (#4022)
* Only create ACPI memory manager DSDT when resizable (#4013)
### Deprecations
Deprecated features will be removed in a subsequent release and users should
plan to use alternatives
* The `mergeable` option from the `virtio-pmem` support has been deprecated
(#3968)
* The `dax` option from the `virtio-fs` support has been deprecated (#3889)
### New on the Website
A new blog post [Achieving Bare Metal Performance Within a Virtual
Machine](https://www.cloudhypervisor.org/blog/achieving-bare-metal-performance-within-a-virtual-machine)
has been added to the Cloud Hypervisor website.
### Contributors
Many thanks to everyone who has contributed to our release:
* Anatol Belski <anbelski@linux.microsoft.com>
* Bo Chen <chen.bo@intel.com>
* Fabiano Fidêncio <fabiano.fidencio@intel.com>
* LiHui <andrewli@kubesphere.io>
* Maksym Pavlenko <pavlenko.maksym@gmail.com>
* Rob Bradford <robert.bradford@intel.com>
* Sebastien Boeuf <sebastien.boeuf@intel.com>
* Steven Dake <steven.dake@gmail.com>
* Vincent Batts <vbatts@hashbangbash.com>
* Wei Liu <liuwe@microsoft.com>
# v23.1 # v23.1
This is a bug fix release. The following issues have been addressed: This is a bug fix release. The following issues have been addressed:

View File

@@ -4,7 +4,7 @@
FROM ubuntu:20.04 as dev FROM ubuntu:20.04 as dev
ARG TARGETARCH ARG TARGETARCH
ARG RUST_TOOLCHAIN="1.62.0" ARG RUST_TOOLCHAIN="1.59.0"
ARG CLH_SRC_DIR="/cloud-hypervisor" ARG CLH_SRC_DIR="/cloud-hypervisor"
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build" ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry" ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"

View File

@@ -1,32 +1,25 @@
# If this flag is set to 1, rustup installation needs to exist on the system and # This spec file assumes you're building on an environment where:
# <arch>-unknown-linux-gnu target is required. # * You have access to the internet during the build
# If this flag is set to 0, distro specific Rust packages will be pulled into the build environment. # * You have rustup installed on your system
# * You have both x86_64-unknown-linux-gnu and x86_64-unknown-linux-musl
# targets installed.
%define using_rustup 1 %define using_rustup 1
# If this flag is set to 1, <arch>-unknown-linux-musl target is required.
%define using_musl_libc 1 %define using_musl_libc 1
# If this flag is set to 1, the vendored crates archive and cargo.toml need to be prepared and
# offline build is implied. Attached script update_src can be used for the vendorization.
# If this flag is set to 0, access to the internet is required during the build.
%define using_vendored_crates 0
Name: cloud-hypervisor Name: cloud-hypervisor
Summary: Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM. Summary: Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM.
Version: 25.0 Version: 23.1
Release: 0%{?dist} Release: 0%{?dist}
License: ASL 2.0 or BSD-3-clause License: ASL 2.0 or BSD-3-clause
Group: Applications/System Group: Applications/System
Source0: https://github.com/cloud-hypervisor/cloud-hypervisor/archive/v%{version}.tar.gz Source0: https://github.com/cloud-hypervisor/cloud-hypervisor/archive/v%{version}.tar.gz
%if 0%{?using_vendored_crates} ExclusiveArch: x86_64
Source1: vendor.tar.gz
Source2: config.toml
%endif
ExclusiveArch: x86_64 aarch64
BuildRequires: gcc BuildRequires: gcc
BuildRequires: glibc-devel BuildRequires: glibc-devel
BuildRequires: binutils BuildRequires: binutils
BuildRequires: git BuildRequires: git
BuildRequires: openssl-devel
%if ! 0%{?using_rustup} %if ! 0%{?using_rustup}
BuildRequires: rust BuildRequires: rust
@@ -38,51 +31,29 @@ Requires: glibc
Requires: libgcc Requires: libgcc
Requires: libcap Requires: libcap
%ifarch x86_64
%define rust_def_target x86_64-unknown-linux-gnu
%if 0%{?using_musl_libc}
%define rust_musl_target x86_64-unknown-linux-musl
%endif
%endif
%ifarch aarch64
%define rust_def_target aarch64-unknown-linux-gnu
%if 0%{?using_musl_libc}
%define rust_musl_target aarch64-unknown-linux-musl
%endif
%endif
%if 0%{?using_vendored_crates}
%define cargo_offline --offline
%endif
%description %description
Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM. The project focuses on exclusively running modern, cloud workloads, on top of a limited set of hardware architectures and platforms. Cloud workloads refers to those that are usually run by customers inside a cloud provider. For our purposes this means modern Linux* distributions with most I/O handled by paravirtualised devices (i.e. virtio), no requirement for legacy devices and recent CPUs and KVM. Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM. The project focuses on exclusively running modern, cloud workloads, on top of a limited set of hardware architectures and platforms. Cloud workloads refers to those that are usually run by customers inside a cloud provider. For our purposes this means modern Linux* distributions with most I/O handled by paravirtualised devices (i.e. virtio), no requirement for legacy devices and recent CPUs and KVM.
%prep %prep
%setup -q %setup -q
%if 0%{?using_vendored_crates}
tar xf %{SOURCE1}
mkdir -p .cargo
cp %{SOURCE2} .cargo/
%endif
%install %install
rm -rf %{buildroot} rm -rf %{buildroot}
install -d %{buildroot}%{_bindir} install -d %{buildroot}%{_bindir}
install -D -m755 ./target/%{rust_def_target}/release/cloud-hypervisor %{buildroot}%{_bindir} install -D -m755 ./target/x86_64-unknown-linux-gnu/release/cloud-hypervisor %{buildroot}%{_bindir}
install -D -m755 ./target/%{rust_def_target}/release/ch-remote %{buildroot}%{_bindir} install -D -m755 ./target/x86_64-unknown-linux-gnu/release/ch-remote %{buildroot}%{_bindir}
install -d %{buildroot}%{_libdir} install -d %{buildroot}%{_libdir}
install -d %{buildroot}%{_libdir}/cloud-hypervisor install -d %{buildroot}%{_libdir}/cloud-hypervisor
install -D -m755 target/%{rust_def_target}/release/vhost_user_block %{buildroot}%{_libdir}/cloud-hypervisor install -D -m755 target/x86_64-unknown-linux-gnu/release/vhost_user_block %{buildroot}%{_libdir}/cloud-hypervisor
install -D -m755 target/%{rust_def_target}/release/vhost_user_net %{buildroot}%{_libdir}/cloud-hypervisor install -D -m755 target/x86_64-unknown-linux-gnu/release/vhost_user_net %{buildroot}%{_libdir}/cloud-hypervisor
%if 0%{?using_musl_libc} %if 0%{?using_musl_libc}
install -d %{buildroot}%{_libdir}/cloud-hypervisor/static install -d %{buildroot}%{_libdir}/cloud-hypervisor/static
install -D -m755 target/%{rust_musl_target}/release/cloud-hypervisor %{buildroot}%{_libdir}/cloud-hypervisor/static install -D -m755 target/x86_64-unknown-linux-musl/release/cloud-hypervisor %{buildroot}%{_libdir}/cloud-hypervisor/static
install -D -m755 target/%{rust_musl_target}/release/vhost_user_block %{buildroot}%{_libdir}/cloud-hypervisor/static install -D -m755 target/x86_64-unknown-linux-musl/release/vhost_user_block %{buildroot}%{_libdir}/cloud-hypervisor/static
install -D -m755 target/%{rust_musl_target}/release/vhost_user_net %{buildroot}%{_libdir}/cloud-hypervisor/static install -D -m755 target/x86_64-unknown-linux-musl/release/vhost_user_net %{buildroot}%{_libdir}/cloud-hypervisor/static
install -D -m755 target/%{rust_musl_target}/release/ch-remote %{buildroot}%{_libdir}/cloud-hypervisor/static install -D -m755 target/x86_64-unknown-linux-musl/release/ch-remote %{buildroot}%{_libdir}/cloud-hypervisor/static
%endif %endif
@@ -103,25 +74,21 @@ fi
echo ${cargo_version} echo ${cargo_version}
%if 0%{?using_rustup} %if 0%{?using_rustup}
rustup target list --installed | grep -e "%{rust_def_target}" rustup target list --installed | grep x86_64-unknown-linux-gnu
if [[ $? -ne 0 ]]; then if [[ $? -ne 0 ]]; then
echo "Target %{rust_def_target} not found, please install(#rustup target add %{rust_def_target}). exiting" echo "Target x86_64-unknown-linux-gnu not found, please install(#rustup target add x86_64-unknown-linux-gnu). exiting"
fi fi
%if 0%{?using_musl_libc} %if 0%{?using_musl_libc}
rustup target list --installed | grep -e "%{rust_musl_target}" rustup target list --installed | grep x86_64-unknown-linux-musl
if [[ $? -ne 0 ]]; then if [[ $? -ne 0 ]]; then
echo "Target %{rust_musl_target} not found, please install(#rustup target add %{rust_musl_target}). exiting" echo "Target x86_64-unknown-linux-musl not found, please install(#rustup target add x86_64-unknown-linux-musl). exiting"
fi fi
%endif %endif
%endif %endif
%if 0%{?using_vendored_crates} cargo build --release --target=x86_64-unknown-linux-gnu --all
# For vendored build, prepend this so openssl-sys doesn't trigger full OpenSSL build
export OPENSSL_NO_VENDOR=1
%endif
cargo build --release --target=%{rust_def_target} --all %{cargo_offline}
%if 0%{?using_musl_libc} %if 0%{?using_musl_libc}
cargo build --release --target=%{rust_musl_target} --all %{cargo_offline} cargo build --release --target=x86_64-unknown-linux-musl --all
%endif %endif
@@ -145,17 +112,8 @@ rm -rf %{buildroot}
%changelog %changelog
* Thu Jul 07 2022 Rob Bradford <robert.bradford@intel.com> 25.0-0 * Mon May 09 2022 Rob Bradford <robert.bradford@intel.com> 23.1-0
- Update to 25.0
* Wed May 25 2022 Sebastien Boeuf <sebastien.boeuf@intel.com> 24.0-0
- Update to 24.0
* Tue May 18 2022 Anatol Belski <anbelski@linux.microsoft.com> - 23.1-0
- Update to 23.1 - Update to 23.1
- Add support for aarch64 build
- Add offline build configuration using vendored crates
- Fix dependency for openssl-sys
* Thu Apr 13 2022 Rob Bradford <robert.bradford@intel.com> 23.0-0 * Thu Apr 13 2022 Rob Bradford <robert.bradford@intel.com> 23.0-0
- Update to 23.0 - Update to 23.0

View File

@@ -1,36 +0,0 @@
#!/bin/bash
set -e
CH_VER=$1
CH_SPEC_DIR=$(pwd)
CH_TMP_DIR=$CH_SPEC_DIR/ch_tmp
CH_SRC_DIR=$CH_SPEC_DIR/SOURCES
if [ -z $CH_VER ]; then
echo "Replace sources with the given <version>"
echo "Usage: $0 <version>"
exit 1
fi
rm -rf $CH_TMP_DIR
if [ ! -d $CH_SRC_DIR ]; then
mkdir $CH_SRC_DIR
fi
rm -f $CH_SRC_DIR/v*.tar.gz $CH_SRC_DIR/config.toml $CH_SRC_DIR/vendor.tar.gz
wget https://github.com/cloud-hypervisor/cloud-hypervisor/archive/v${CH_VER}.tar.gz -O $CH_SRC_DIR/v${CH_VER}.tar.gz
mkdir $CH_TMP_DIR
tar xf $CH_SRC_DIR/v${CH_VER}.tar.gz -C $CH_TMP_DIR --strip-components=1
pushd $CH_TMP_DIR
cargo vendor > $CH_SRC_DIR/config.toml
tar czvf $CH_SRC_DIR/vendor.tar.gz vendor
popd
rm -rf $CH_TMP_DIR

View File

@@ -7,7 +7,7 @@
CLI_NAME="Cloud Hypervisor" CLI_NAME="Cloud Hypervisor"
CTR_IMAGE_TAG="cloudhypervisor/dev" CTR_IMAGE_TAG="cloudhypervisor/dev"
CTR_IMAGE_VERSION="20220705-0" CTR_IMAGE_VERSION="20220405-0"
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}" CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
DOCKER_RUNTIME="docker" DOCKER_RUNTIME="docker"
@@ -226,11 +226,6 @@ cmd_build() {
} ;; } ;;
"--debug") { build="debug"; } ;; "--debug") { build="debug"; } ;;
"--release") { build="release"; } ;; "--release") { build="release"; } ;;
"--runtime")
shift
DOCKER_RUNTIME="$1"
export DOCKER_RUNTIME
;;
"--libc") "--libc")
shift shift
[[ "$1" =~ ^(musl|gnu)$ ]] || [[ "$1" =~ ^(musl|gnu)$ ]] ||

View File

@@ -192,15 +192,6 @@ update_workloads() {
fi fi
popd popd
# Download Cloud Hypervisor binary from its last stable release
LAST_RELEASE_VERSION="v23.0"
CH_RELEASE_URL="https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$LAST_RELEASE_VERSION/cloud-hypervisor-static-aarch64"
CH_RELEASE_NAME="cloud-hypervisor-static-aarch64"
pushd $WORKLOADS_DIR
time wget --quiet $CH_RELEASE_URL -O "$CH_RELEASE_NAME" || exit 1
chmod +x $CH_RELEASE_NAME
popd
# Build custom kernel for guest VMs # Build custom kernel for guest VMs
build_custom_linux build_custom_linux

View File

@@ -45,15 +45,6 @@ if [ $? -ne 0 ]; then
fi fi
popd popd
# Download Cloud Hypervisor binary from its last stable release
LAST_RELEASE_VERSION="v23.0"
CH_RELEASE_URL="https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$LAST_RELEASE_VERSION/cloud-hypervisor-static"
CH_RELEASE_NAME="cloud-hypervisor-static"
pushd $WORKLOADS_DIR
time wget --quiet $CH_RELEASE_URL -O "$CH_RELEASE_NAME" || exit 1
chmod +x $CH_RELEASE_NAME
popd
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches # Build custom kernel based on virtio-pmem and virtio-fs upstream patches
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux" VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"

View File

@@ -113,9 +113,6 @@ if [ -n "$test_filter" ]; then
test_binary_args+=("--test-filter $test_filter") test_binary_args+=("--test-filter $test_filter")
fi fi
# Ensure that git commands can be run in this directory (for metrics report)
git config --global --add safe.directory $PWD
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1
time target/$BUILD_TARGET/release/performance-metrics ${test_binary_args[*]} time target/$BUILD_TARGET/release/performance-metrics ${test_binary_args[*]}
RES=$? RES=$?

View File

@@ -11,8 +11,6 @@ cargo_args=("")
if [[ $hypervisor = "mshv" ]]; then if [[ $hypervisor = "mshv" ]]; then
cargo_args+=("--no-default-features") cargo_args+=("--no-default-features")
cargo_args+=("--features common,$hypervisor") cargo_args+=("--features common,$hypervisor")
elif [[ $(uname -m) = "x86_64" ]]; then
cargo_args+=("--features tdx")
fi fi
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then

View File

@@ -12,7 +12,6 @@ use api_client::Error as ApiClientError;
use clap::{Arg, ArgMatches, Command}; use clap::{Arg, ArgMatches, Command};
use option_parser::{ByteSized, ByteSizedParseError}; use option_parser::{ByteSized, ByteSizedParseError};
use std::fmt; use std::fmt;
use std::io::Read;
use std::os::unix::net::UnixStream; use std::os::unix::net::UnixStream;
use std::process; use std::process;
@@ -32,8 +31,6 @@ enum Error {
AddVdpaConfig(vmm::config::Error), AddVdpaConfig(vmm::config::Error),
AddVsockConfig(vmm::config::Error), AddVsockConfig(vmm::config::Error),
Restore(vmm::config::Error), Restore(vmm::config::Error),
ReadingStdin(std::io::Error),
ReadingFile(std::io::Error),
} }
impl fmt::Display for Error { impl fmt::Display for Error {
@@ -54,8 +51,6 @@ impl fmt::Display for Error {
AddVdpaConfig(e) => write!(f, "Error parsing vDPA device syntax: {}", e), AddVdpaConfig(e) => write!(f, "Error parsing vDPA device syntax: {}", e),
AddVsockConfig(e) => write!(f, "Error parsing vsock syntax: {}", e), AddVsockConfig(e) => write!(f, "Error parsing vsock syntax: {}", e),
Restore(e) => write!(f, "Error parsing restore syntax: {}", e), Restore(e) => write!(f, "Error parsing restore syntax: {}", e),
ReadingStdin(e) => write!(f, "Error reading from stdin: {}", e),
ReadingFile(e) => write!(f, "Error reading from file: {}", e),
} }
} }
} }
@@ -269,20 +264,6 @@ fn restore_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Erro
.map_err(Error::ApiClient) .map_err(Error::ApiClient)
} }
fn coredump_api_command(socket: &mut UnixStream, destination_url: &str) -> Result<(), Error> {
let coredump_config = vmm::api::VmCoredumpData {
destination_url: String::from(destination_url),
};
simple_api_command(
socket,
"PUT",
"coredump",
Some(&serde_json::to_string(&coredump_config).unwrap()),
)
.map_err(Error::ApiClient)
}
fn receive_migration_api_command(socket: &mut UnixStream, url: &str) -> Result<(), Error> { fn receive_migration_api_command(socket: &mut UnixStream, url: &str) -> Result<(), Error> {
let receive_migration_data = vmm::api::VmReceiveMigrationData { let receive_migration_data = vmm::api::VmReceiveMigrationData {
receiver_url: url.to_owned(), receiver_url: url.to_owned(),
@@ -314,19 +295,6 @@ fn send_migration_api_command(
.map_err(Error::ApiClient) .map_err(Error::ApiClient)
} }
fn create_api_command(socket: &mut UnixStream, path: &str) -> Result<(), Error> {
let mut data = String::default();
if path == "-" {
std::io::stdin()
.read_to_string(&mut data)
.map_err(Error::ReadingStdin)?;
} else {
data = std::fs::read_to_string(path).map_err(Error::ReadingFile)?;
}
simple_api_command(socket, "PUT", "create", Some(&data)).map_err(Error::ApiClient)
}
fn do_command(matches: &ArgMatches) -> Result<(), Error> { fn do_command(matches: &ArgMatches) -> Result<(), Error> {
let mut socket = let mut socket =
UnixStream::connect(matches.value_of("api-socket").unwrap()).map_err(Error::Connect)?; UnixStream::connect(matches.value_of("api-socket").unwrap()).map_err(Error::Connect)?;
@@ -454,14 +422,6 @@ fn do_command(matches: &ArgMatches) -> Result<(), Error> {
.value_of("restore_config") .value_of("restore_config")
.unwrap(), .unwrap(),
), ),
Some("coredump") => coredump_api_command(
&mut socket,
matches
.subcommand_matches("coredump")
.unwrap()
.value_of("coredump_config")
.unwrap(),
),
Some("send-migration") => send_migration_api_command( Some("send-migration") => send_migration_api_command(
&mut socket, &mut socket,
matches matches
@@ -482,14 +442,6 @@ fn do_command(matches: &ArgMatches) -> Result<(), Error> {
.value_of("receive_migration_config") .value_of("receive_migration_config")
.unwrap(), .unwrap(),
), ),
Some("create") => create_api_command(
&mut socket,
matches
.subcommand_matches("create")
.unwrap()
.value_of("path")
.unwrap(),
),
Some(c) => simple_api_command(&mut socket, "PUT", c, None).map_err(Error::ApiClient), Some(c) => simple_api_command(&mut socket, "PUT", c, None).map_err(Error::ApiClient),
None => unreachable!(), None => unreachable!(),
} }
@@ -624,8 +576,6 @@ fn main() {
), ),
) )
.subcommand(Command::new("resume").about("Resume the VM")) .subcommand(Command::new("resume").about("Resume the VM"))
.subcommand(Command::new("boot").about("Boot a created VM"))
.subcommand(Command::new("delete").about("Delete a VM"))
.subcommand(Command::new("shutdown").about("Shutdown the VM")) .subcommand(Command::new("shutdown").about("Shutdown the VM"))
.subcommand( .subcommand(
Command::new("snapshot") Command::new("snapshot")
@@ -645,11 +595,6 @@ fn main() {
.help(vmm::config::RestoreConfig::SYNTAX), .help(vmm::config::RestoreConfig::SYNTAX),
), ),
) )
.subcommand(
Command::new("coredump")
.about("Create a coredump from VM")
.arg(Arg::new("coredump_config").index(1).help("<file_path>")),
)
.subcommand( .subcommand(
Command::new("send-migration") Command::new("send-migration")
.about("Initiate a VM migration") .about("Initiate a VM migration")
@@ -672,11 +617,6 @@ fn main() {
.index(1) .index(1)
.help("<receiver_url>"), .help("<receiver_url>"),
), ),
)
.subcommand(
Command::new("create")
.about("Create VM from a JSON configuration")
.arg(Arg::new("path").index(1).default_value("-")),
); );
let matches = app.get_matches(); let matches = app.get_matches();

View File

@@ -23,7 +23,6 @@ use thiserror::Error;
use vmm::config; use vmm::config;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::signal::block_signal; use vmm_sys_util::signal::block_signal;
use vmm_sys_util::terminal::Terminal;
#[derive(Error, Debug)] #[derive(Error, Debug)]
enum Error { enum Error {
@@ -162,7 +161,7 @@ fn create_app<'a>(
Arg::new("platform") Arg::new("platform")
.long("platform") .long("platform")
.help( .help(
"num_pci_segments=<num pci segments>,iommu_segments=<list_of_segments>,serial_number=<(DMI) device serial number>", "num_pci_segments=<num pci segments>,iommu_segments=<list_of_segments>",
) )
.takes_value(true) .takes_value(true)
.group("vm-config"), .group("vm-config"),
@@ -624,13 +623,6 @@ fn main() {
} }
}; };
let on_tty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
if on_tty {
// Don't forget to set the terminal in canonical mode
// before to exit.
std::io::stdin().lock().set_canon_mode().unwrap();
}
std::process::exit(exit_code); std::process::exit(exit_code);
} }
@@ -1331,6 +1323,40 @@ mod unit_tests {
}"#, }"#,
false, false,
), ),
#[cfg(target_arch = "x86_64")]
(
vec![
"cloud-hypervisor",
"--kernel",
"/path/to/kernel",
"--pmem",
"file=/path/to/img/1,size=1G,mergeable=on",
],
r#"{
"kernel": {"path": "/path/to/kernel"},
"pmem": [
{"file": "/path/to/img/1", "size": 1073741824, "mergeable": true}
]
}"#,
true,
),
#[cfg(target_arch = "x86_64")]
(
vec![
"cloud-hypervisor",
"--kernel",
"/path/to/kernel",
"--pmem",
"file=/path/to/img/1,size=1G,mergeable=off",
],
r#"{
"kernel": {"path": "/path/to/kernel"},
"pmem": [
{"file": "/path/to/img/1", "size": 1073741824, "mergeable": false}
]
}"#,
true,
),
] ]
.iter() .iter()
.for_each(|(cli, openapi, equal)| { .for_each(|(cli, openapi, equal)| {

View File

@@ -7,8 +7,8 @@ edition = "2021"
[dependencies] [dependencies]
dirs = "4.0.0" dirs = "4.0.0"
epoll = "4.3.1" epoll = "4.3.1"
libc = "0.2.126" lazy_static = "1.4.0"
once_cell = "1.13.0" libc = "0.2.123"
ssh2 = { version = "0.9.1", features = ["vendored-openssl"]} ssh2 = { version = "0.9.1", features = ["vendored-openssl"]}
vmm-sys-util = "0.9.0" vmm-sys-util = "0.9.0"
wait-timeout = "0.2.0" wait-timeout = "0.2.0"

View File

@@ -3,11 +3,12 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
use once_cell::sync::Lazy; #[macro_use]
extern crate lazy_static;
use ssh2::Session; use ssh2::Session;
use std::env; use std::env;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::fmt::Debug;
use std::fs; use std::fs;
use std::io; use std::io;
use std::io::{Read, Write}; use std::io::{Read, Write};
@@ -50,7 +51,7 @@ pub struct GuestNetworkConfig {
pub const DEFAULT_TCP_LISTENER_MESSAGE: &str = "booted"; pub const DEFAULT_TCP_LISTENER_MESSAGE: &str = "booted";
pub const DEFAULT_TCP_LISTENER_PORT: u16 = 8000; pub const DEFAULT_TCP_LISTENER_PORT: u16 = 8000;
pub const DEFAULT_TCP_LISTENER_TIMEOUT: i32 = 120; pub const DEFAULT_TCP_LISTENER_TIMEOUT: i32 = 80;
#[derive(Debug)] #[derive(Debug)]
pub enum WaitForBootError { pub enum WaitForBootError {
@@ -720,7 +721,9 @@ pub fn exec_host_command_output(command: &str) -> Output {
pub const PIPE_SIZE: i32 = 32 << 20; pub const PIPE_SIZE: i32 = 32 << 20;
static NEXT_VM_ID: Lazy<Mutex<u8>> = Lazy::new(|| Mutex::new(1)); lazy_static! {
static ref NEXT_VM_ID: Mutex<u8> = Mutex::new(1);
}
pub struct Guest { pub struct Guest {
pub tmp_dir: TempDir, pub tmp_dir: TempDir,
@@ -828,12 +831,30 @@ impl Guest {
) )
} }
pub fn api_create_body(&self, cpu_count: u8, kernel_path: &str, kernel_cmd: &str) -> String { pub fn api_create_body(
&self,
cpu_count: u8,
_fw_path: &str,
_kernel_path: &str,
_kernel_cmd: &str,
) -> String {
#[cfg(all(target_arch = "x86_64", not(feature = "mshv")))]
format! {"{{\"cpus\":{{\"boot_vcpus\":{},\"max_vcpus\":{}}},\"kernel\":{{\"path\":\"{}\"}},\"cmdline\":{{\"args\": \"\"}},\"net\":[{{\"ip\":\"{}\", \"mask\":\"255.255.255.0\", \"mac\":\"{}\"}}], \"disks\":[{{\"path\":\"{}\"}}, {{\"path\":\"{}\"}}]}}",
cpu_count,
cpu_count,
_fw_path,
self.network.host_ip,
self.network.guest_mac,
self.disk_config.disk(DiskType::OperatingSystem).unwrap().as_str(),
self.disk_config.disk(DiskType::CloudInit).unwrap().as_str(),
}
#[cfg(any(target_arch = "aarch64", feature = "mshv"))]
format! {"{{\"cpus\":{{\"boot_vcpus\":{},\"max_vcpus\":{}}},\"kernel\":{{\"path\":\"{}\"}},\"cmdline\":{{\"args\": \"{}\"}},\"net\":[{{\"ip\":\"{}\", \"mask\":\"255.255.255.0\", \"mac\":\"{}\"}}], \"disks\":[{{\"path\":\"{}\"}}, {{\"path\":\"{}\"}}]}}", format! {"{{\"cpus\":{{\"boot_vcpus\":{},\"max_vcpus\":{}}},\"kernel\":{{\"path\":\"{}\"}},\"cmdline\":{{\"args\": \"{}\"}},\"net\":[{{\"ip\":\"{}\", \"mask\":\"255.255.255.0\", \"mac\":\"{}\"}}], \"disks\":[{{\"path\":\"{}\"}}, {{\"path\":\"{}\"}}]}}",
cpu_count, cpu_count,
cpu_count, cpu_count,
kernel_path, _kernel_path,
kernel_cmd, _kernel_cmd,
self.network.host_ip, self.network.host_ip,
self.network.guest_mac, self.network.guest_mac,
self.disk_config.disk(DiskType::OperatingSystem).unwrap().as_str(), self.disk_config.disk(DiskType::OperatingSystem).unwrap().as_str(),
@@ -963,6 +984,13 @@ impl Guest {
Ok(()) Ok(())
} }
pub fn get_entropy(&self) -> Result<u32, Error> {
self.ssh_command("cat /proc/sys/kernel/random/entropy_avail")?
.trim()
.parse()
.map_err(Error::Parsing)
}
pub fn get_pci_bridge_class(&self) -> Result<String, Error> { pub fn get_pci_bridge_class(&self) -> Result<String, Error> {
Ok(self Ok(self
.ssh_command("cat /sys/bus/pci/devices/0000:00:00.0/class")? .ssh_command("cat /sys/bus/pci/devices/0000:00:00.0/class")?
@@ -1008,6 +1036,50 @@ impl Guest {
Ok(false) Ok(false)
} }
pub fn valid_virtio_fs_cache_size(
&self,
dax: bool,
cache_size: Option<u64>,
) -> Result<bool, Error> {
// SHM region is called different things depending on kernel
let shm_region = self
.ssh_command("sudo grep 'virtio[0-9]\\|virtio-pci-shm' /proc/iomem || true")?
.trim()
.to_string();
if shm_region.is_empty() {
return Ok(!dax);
}
// From this point, the region is not empty, hence it is an error
// if DAX is off.
if !dax {
return Ok(false);
}
let cache = if let Some(cache) = cache_size {
cache
} else {
// 8Gib by default
0x0002_0000_0000
};
let args: Vec<&str> = shm_region.split(':').collect();
if args.is_empty() {
return Ok(false);
}
let args: Vec<&str> = args[0].trim().split('-').collect();
if args.len() != 2 {
return Ok(false);
}
let start_addr = u64::from_str_radix(args[0], 16).map_err(Error::Parsing)?;
let end_addr = u64::from_str_radix(args[1], 16).map_err(Error::Parsing)?;
Ok(cache == (end_addr - start_addr + 1))
}
pub fn check_vsock(&self, socket: &str) { pub fn check_vsock(&self, socket: &str) {
// Listen from guest on vsock CID=3 PORT=16 // Listen from guest on vsock CID=3 PORT=16
// SOCKET-LISTEN:<domain>:<protocol>:<local-address> // SOCKET-LISTEN:<domain>:<protocol>:<local-address>
@@ -1087,12 +1159,7 @@ impl Guest {
.unwrap(); .unwrap();
} }
pub fn check_devices_common( pub fn check_devices_common(&self, socket: Option<&String>, console_text: Option<&String>) {
&self,
socket: Option<&String>,
console_text: Option<&String>,
pmem_path: Option<&String>,
) {
// Check block devices are readable // Check block devices are readable
self.ssh_command("sudo dd if=/dev/vda of=/dev/null bs=1M iflag=direct count=1024") self.ssh_command("sudo dd if=/dev/vda of=/dev/null bs=1M iflag=direct count=1024")
.unwrap(); .unwrap();
@@ -1111,63 +1178,6 @@ impl Guest {
self.ssh_command(&console_cmd).unwrap(); self.ssh_command(&console_cmd).unwrap();
} }
// The net device is 'automatically' exercised through the above 'ssh' commands // The net device is 'automatically' exercised through the above 'ssh' commands
// Check if the pmem device is usable
if let Some(pmem_path) = pmem_path {
assert_eq!(
self.ssh_command(&format!("ls {}", pmem_path))
.unwrap()
.trim(),
pmem_path
);
assert_eq!(
self.ssh_command(&format!("sudo mount {} /mnt", pmem_path))
.unwrap(),
""
);
assert_eq!(self.ssh_command("ls /mnt").unwrap(), "lost+found\n");
self.ssh_command("echo test123 | sudo tee /mnt/test")
.unwrap();
assert_eq!(self.ssh_command("sudo umount /mnt").unwrap(), "");
assert_eq!(self.ssh_command("ls /mnt").unwrap(), "");
assert_eq!(
self.ssh_command(&format!("sudo mount {} /mnt", pmem_path))
.unwrap(),
""
);
assert_eq!(
self.ssh_command("sudo cat /mnt/test || true")
.unwrap()
.trim(),
"test123"
);
self.ssh_command("sudo rm /mnt/test").unwrap();
assert_eq!(self.ssh_command("sudo umount /mnt").unwrap(), "");
}
}
}
pub enum VerbosityLevel {
Warn,
Info,
Debug,
}
impl Default for VerbosityLevel {
fn default() -> Self {
Self::Warn
}
}
impl ToString for VerbosityLevel {
fn to_string(&self) -> String {
use VerbosityLevel::*;
match self {
Warn => "".to_string(),
Info => "-v".to_string(),
Debug => "-vv".to_string(),
}
} }
} }
@@ -1176,29 +1186,22 @@ pub struct GuestCommand<'a> {
guest: &'a Guest, guest: &'a Guest,
capture_output: bool, capture_output: bool,
print_cmd: bool, print_cmd: bool,
verbosity: VerbosityLevel,
} }
impl<'a> GuestCommand<'a> { impl<'a> GuestCommand<'a> {
pub fn new(guest: &'a Guest) -> Self { pub fn new(guest: &'a Guest) -> Self {
Self::new_with_binary_path(guest, &clh_command("cloud-hypervisor")) Self::new_with_binary_name(guest, "cloud-hypervisor")
} }
pub fn new_with_binary_path(guest: &'a Guest, binary_path: &str) -> Self { pub fn new_with_binary_name(guest: &'a Guest, binary_name: &str) -> Self {
Self { Self {
command: Command::new(binary_path), command: Command::new(clh_command(binary_name)),
guest, guest,
capture_output: false, capture_output: false,
print_cmd: true, print_cmd: true,
verbosity: VerbosityLevel::Info,
} }
} }
pub fn verbosity(&mut self, verbosity: VerbosityLevel) -> &mut Self {
self.verbosity = verbosity;
self
}
pub fn capture_output(&mut self) -> &mut Self { pub fn capture_output(&mut self) -> &mut Self {
self.capture_output = true; self.capture_output = true;
self self
@@ -1210,17 +1213,6 @@ impl<'a> GuestCommand<'a> {
} }
pub fn spawn(&mut self) -> io::Result<Child> { pub fn spawn(&mut self) -> io::Result<Child> {
use VerbosityLevel::*;
match &self.verbosity {
Warn => {}
Info => {
self.command.arg("-v");
}
Debug => {
self.command.arg("-vv");
}
};
if self.print_cmd { if self.print_cmd {
println!( println!(
"\n\n==== Start cloud-hypervisor command-line ====\n\n\ "\n\n==== Start cloud-hypervisor command-line ====\n\n\
@@ -1233,6 +1225,7 @@ impl<'a> GuestCommand<'a> {
if self.capture_output { if self.capture_output {
let child = self let child = self
.command .command
.arg("-v")
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn() .spawn()
@@ -1252,7 +1245,7 @@ impl<'a> GuestCommand<'a> {
)) ))
} }
} else { } else {
self.command.spawn() self.command.arg("-v").spawn()
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -5,14 +5,14 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.58" anyhow = "1.0.56"
libc = "0.2.126" libc = "0.2.123"
log = "0.4.17" log = "0.4.16"
serde = {version = ">=1.0.27", features = ["rc"] } serde = {version = ">=1.0.27", features = ["rc"] }
serde_derive = ">=1.0.27" serde_derive = ">=1.0.27"
serde_json = ">=1.0.9" serde_json = ">=1.0.9"
thiserror = "1.0.31" thiserror = "1.0.30"
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic"] } vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic"] }
vmm-sys-util = ">=0.3.1" vmm-sys-util = ">=0.3.1"
[dependencies.vfio-bindings] [dependencies.vfio-bindings]

View File

@@ -4,9 +4,7 @@
// //
use std::ffi::CString; use std::ffi::CString;
use std::fs::File;
use std::io::{IoSlice, Read, Write}; use std::io::{IoSlice, Read, Write};
use std::mem::size_of;
use std::num::Wrapping; use std::num::Wrapping;
use std::os::unix::net::UnixStream; use std::os::unix::net::UnixStream;
use std::os::unix::prelude::RawFd; use std::os::unix::prelude::RawFd;
@@ -51,7 +49,7 @@ impl Default for Command {
#[allow(dead_code)] #[allow(dead_code)]
#[repr(u32)] #[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq)]
enum HeaderFlags { enum HeaderFlags {
Command = 0, Command = 0,
Reply = 1, Reply = 1,
@@ -236,7 +234,6 @@ pub struct Region {
pub index: u32, pub index: u32,
pub size: u64, pub size: u64,
pub file_offset: Option<FileOffset>, pub file_offset: Option<FileOffset>,
pub sparse_areas: Vec<vfio_region_sparse_mmap_area>,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -297,7 +294,7 @@ impl Client {
message_id: self.next_message_id.0, message_id: self.next_message_id.0,
command: Command::Version, command: Command::Version,
flags: HeaderFlags::Command as u32, flags: HeaderFlags::Command as u32,
message_size: (size_of::<Version>() + version_data.len() + 1) as u32, message_size: (std::mem::size_of::<Version>() + version_data.len() + 1) as u32,
..Default::default() ..Default::default()
}, },
major: 0, major: 0,
@@ -333,7 +330,7 @@ impl Client {
let mut server_version_data = Vec::new(); let mut server_version_data = Vec::new();
server_version_data.resize( server_version_data.resize(
server_version.header.message_size as usize - size_of::<Version>(), server_version.header.message_size as usize - std::mem::size_of::<Version>(),
0, 0,
); );
self.stream self.stream
@@ -364,10 +361,10 @@ impl Client {
message_id: self.next_message_id.0, message_id: self.next_message_id.0,
command: Command::DmaMap, command: Command::DmaMap,
flags: HeaderFlags::Command as u32, flags: HeaderFlags::Command as u32,
message_size: size_of::<DmaMap>() as u32, message_size: std::mem::size_of::<DmaMap>() as u32,
..Default::default() ..Default::default()
}, },
argsz: (size_of::<DmaMap>() - size_of::<Header>()) as u32, argsz: (std::mem::size_of::<DmaMap>() - std::mem::size_of::<Header>()) as u32,
flags: DmaMapFlags::ReadWrite, flags: DmaMapFlags::ReadWrite,
offset, offset,
address, address,
@@ -394,10 +391,10 @@ impl Client {
message_id: self.next_message_id.0, message_id: self.next_message_id.0,
command: Command::DmaUnmap, command: Command::DmaUnmap,
flags: HeaderFlags::Command as u32, flags: HeaderFlags::Command as u32,
message_size: size_of::<DmaUnmap>() as u32, message_size: std::mem::size_of::<DmaUnmap>() as u32,
..Default::default() ..Default::default()
}, },
argsz: (size_of::<DmaUnmap>() - size_of::<Header>()) as u32, argsz: (std::mem::size_of::<DmaUnmap>() - std::mem::size_of::<Header>()) as u32,
flags: 0, flags: 0,
address, address,
size, size,
@@ -423,7 +420,7 @@ impl Client {
message_id: self.next_message_id.0, message_id: self.next_message_id.0,
command: Command::DeviceReset, command: Command::DeviceReset,
flags: HeaderFlags::Command as u32, flags: HeaderFlags::Command as u32,
message_size: size_of::<DeviceReset>() as u32, message_size: std::mem::size_of::<DeviceReset>() as u32,
..Default::default() ..Default::default()
}, },
}; };
@@ -448,10 +445,10 @@ impl Client {
message_id: self.next_message_id.0, message_id: self.next_message_id.0,
command: Command::DeviceGetInfo, command: Command::DeviceGetInfo,
flags: HeaderFlags::Command as u32, flags: HeaderFlags::Command as u32,
message_size: size_of::<DeviceGetInfo>() as u32, message_size: std::mem::size_of::<DeviceGetInfo>() as u32,
..Default::default() ..Default::default()
}, },
argsz: size_of::<DeviceGetInfo>() as u32, argsz: std::mem::size_of::<DeviceGetInfo>() as u32,
..Default::default() ..Default::default()
}; };
debug!("Command: {:?}", get_info); debug!("Command: {:?}", get_info);
@@ -477,62 +474,20 @@ impl Client {
let num_regions = reply.num_regions; let num_regions = reply.num_regions;
let mut regions = Vec::new(); let mut regions = Vec::new();
for index in 0..num_regions { for index in 0..num_regions {
let (region_info, fd, sparse_areas) = self.get_region_info(index)?; let get_region_info = DeviceGetRegionInfo {
regions.push(Region { header: Header {
flags: region_info.flags, message_id: self.next_message_id.0,
index: region_info.index, command: Command::DeviceGetRegionInfo,
size: region_info.size, flags: HeaderFlags::Command as u32,
file_offset: fd.map(|fd| FileOffset::new(fd, region_info.offset)), message_size: std::mem::size_of::<DeviceGetRegionInfo>() as u32,
sparse_areas, ..Default::default()
}); },
} region_info: vfio_region_info {
argsz: 1024, // Arbitrary max size
Ok(regions) index,
} ..Default::default()
},
fn get_region_info( };
&mut self,
index: u32,
) -> Result<
(
vfio_region_info,
Option<File>,
Vec<vfio_region_sparse_mmap_area>,
),
Error,
> {
// Retrieve the region info without capability
let mut get_region_info = DeviceGetRegionInfo {
header: Header {
message_id: self.next_message_id.0,
command: Command::DeviceGetRegionInfo,
flags: HeaderFlags::Command as u32,
message_size: std::mem::size_of::<DeviceGetRegionInfo>() as u32,
..Default::default()
},
region_info: vfio_region_info {
argsz: size_of::<vfio_region_info>() as u32,
index,
..Default::default()
},
};
debug!("Command: {:?}", get_region_info);
self.next_message_id += Wrapping(1);
self.stream
.write_all(get_region_info.as_slice())
.map_err(Error::StreamWrite)?;
let mut reply = DeviceGetRegionInfo::default();
let (_, fd) = self
.stream
.recv_with_fd(reply.as_mut_slice())
.map_err(Error::ReceiveWithFd)?;
debug!("Reply: {:?}", reply);
// Retrieve the region info again with capabilities if needed
if reply.region_info.argsz > std::mem::size_of::<vfio_region_info>() as u32 {
get_region_info.region_info.argsz = reply.region_info.argsz;
debug!("Command: {:?}", get_region_info); debug!("Command: {:?}", get_region_info);
self.next_message_id += Wrapping(1); self.next_message_id += Wrapping(1);
@@ -547,94 +502,24 @@ impl Client {
.map_err(Error::ReceiveWithFd)?; .map_err(Error::ReceiveWithFd)?;
debug!("Reply: {:?}", reply); debug!("Reply: {:?}", reply);
let cap_size = reply.region_info.argsz - std::mem::size_of::<vfio_region_info>() as u32; regions.push(Region {
assert_eq!( flags: reply.region_info.flags,
cap_size, index: reply.region_info.index,
reply.header.message_size - size_of::<DeviceGetRegionInfo>() as u32 size: reply.region_info.size,
file_offset: fd.map(|fd| FileOffset::new(fd, reply.region_info.offset)),
});
// TODO: Handle region with capabilities
let mut _cap_data = Vec::with_capacity(
reply.header.message_size as usize - std::mem::size_of::<DeviceGetRegionInfo>(),
); );
let mut cap_data = Vec::with_capacity(cap_size as usize); _cap_data.resize(_cap_data.capacity(), 0u8);
cap_data.resize(cap_data.capacity(), 0u8);
self.stream self.stream
.read_exact(cap_data.as_mut_slice()) .read_exact(_cap_data.as_mut_slice())
.map_err(Error::StreamRead)?; .map_err(Error::StreamRead)?;
let sparse_areas = Self::parse_region_caps(&cap_data, &reply.region_info)?;
Ok((reply.region_info, fd, sparse_areas))
} else {
Ok((reply.region_info, fd, Vec::new()))
}
}
fn parse_region_caps(
cap_data: &[u8],
region_info: &vfio_region_info,
) -> Result<Vec<vfio_region_sparse_mmap_area>, Error> {
let mut sparse_areas: Vec<vfio_region_sparse_mmap_area> = Vec::new();
let cap_size = cap_data.len() as u32;
let cap_header_size = size_of::<vfio_info_cap_header>() as u32;
let mmap_cap_size = size_of::<vfio_region_info_cap_sparse_mmap>() as u32;
let mmap_area_size = size_of::<vfio_region_sparse_mmap_area>() as u32;
let cap_data_ptr = cap_data.as_ptr() as *const u8;
let mut region_info_offset = region_info.cap_offset;
while region_info_offset != 0 {
// calculate the offset from the begining of the cap_data based on the offset
// that is relative to the begining of the VFIO region info structure
let cap_offset = region_info_offset - size_of::<vfio_region_info>() as u32;
if cap_offset + cap_header_size > cap_size {
warn!(
"Unexpected end of cap data: 'cap_offset + cap_header_size > cap_size' \
cap_offset = {}, cap_header_size = {}, cap_size = {}",
cap_offset, cap_header_size, cap_size
);
break;
}
// Safe because the `cap_data_ptr` is valid and the `cap_offset` is checked above
let cap_ptr = unsafe { cap_data_ptr.offset(cap_offset as isize) };
let cap_header = unsafe { &*(cap_ptr as *const vfio_info_cap_header) };
match cap_header.id as u32 {
VFIO_REGION_INFO_CAP_SPARSE_MMAP => {
if cap_offset + mmap_cap_size > cap_size {
warn!(
"Unexpected end of cap data: 'cap_offset + mmap_cap_size > cap_size' \
cap_offset = {}, mmap_cap_size = {}, cap_size = {}",
cap_offset, mmap_cap_size, cap_size
);
break;
}
// Safe because the `cap_ptr` is valid and its size is also checked above
let sparse_mmap = unsafe {
&*(cap_ptr as *mut u8 as *const vfio_region_info_cap_sparse_mmap)
};
let area_num = sparse_mmap.nr_areas;
if cap_offset + mmap_cap_size + area_num * mmap_area_size > cap_size {
warn!("Unexpected end of cap data: 'cap_offset + mmap_cap_size + area_num * mmap_area_size > cap_size' \
cap_offset = {}, mmap_cap_size = {}, area_num = {}, mmap_area_size = {}, cap_size = {}",
cap_offset, mmap_cap_size, area_num, mmap_area_size, cap_size);
break;
}
// Safe because the `sparse_mmap` is valid and its size is also checked above
let areas =
unsafe { sparse_mmap.areas.as_slice(sparse_mmap.nr_areas as usize) };
for area in areas.iter() {
sparse_areas.push(*area);
}
}
_ => {
warn!(
"Ignoring unsupported vfio region capability (id = '{}')",
cap_header.id
);
}
}
region_info_offset = cap_header.next;
} }
Ok(sparse_areas) Ok(regions)
} }
pub fn region_read(&mut self, region: u32, offset: u64, data: &mut [u8]) -> Result<(), Error> { pub fn region_read(&mut self, region: u32, offset: u64, data: &mut [u8]) -> Result<(), Error> {
@@ -643,7 +528,7 @@ impl Client {
message_id: self.next_message_id.0, message_id: self.next_message_id.0,
command: Command::RegionRead, command: Command::RegionRead,
flags: HeaderFlags::Command as u32, flags: HeaderFlags::Command as u32,
message_size: size_of::<RegionAccess>() as u32, message_size: std::mem::size_of::<RegionAccess>() as u32,
..Default::default() ..Default::default()
}, },
offset, offset,
@@ -671,7 +556,7 @@ impl Client {
message_id: self.next_message_id.0, message_id: self.next_message_id.0,
command: Command::RegionWrite, command: Command::RegionWrite,
flags: HeaderFlags::Command as u32, flags: HeaderFlags::Command as u32,
message_size: (size_of::<RegionAccess>() + data.len()) as u32, message_size: (std::mem::size_of::<RegionAccess>() + data.len()) as u32,
..Default::default() ..Default::default()
}, },
offset, offset,
@@ -703,10 +588,10 @@ impl Client {
message_id: self.next_message_id.0, message_id: self.next_message_id.0,
command: Command::GetIrqInfo, command: Command::GetIrqInfo,
flags: HeaderFlags::Command as u32, flags: HeaderFlags::Command as u32,
message_size: size_of::<GetIrqInfo>() as u32, message_size: std::mem::size_of::<GetIrqInfo>() as u32,
..Default::default() ..Default::default()
}, },
argsz: (size_of::<GetIrqInfo>() - size_of::<Header>()) as u32, argsz: (std::mem::size_of::<GetIrqInfo>() - std::mem::size_of::<Header>()) as u32,
flags: 0, flags: 0,
index, index,
count: 0, count: 0,
@@ -744,10 +629,10 @@ impl Client {
message_id: self.next_message_id.0, message_id: self.next_message_id.0,
command: Command::SetIrqs, command: Command::SetIrqs,
flags: HeaderFlags::Command as u32, flags: HeaderFlags::Command as u32,
message_size: size_of::<SetIrqs>() as u32, message_size: std::mem::size_of::<SetIrqs>() as u32,
..Default::default() ..Default::default()
}, },
argsz: (size_of::<SetIrqs>() - size_of::<Header>()) as u32, argsz: (std::mem::size_of::<SetIrqs>() - std::mem::size_of::<Header>()) as u32,
flags, flags,
start, start,
index, index,

View File

@@ -8,9 +8,9 @@ license = "Apache-2.0"
[dependencies] [dependencies]
byteorder = "1.4.3" byteorder = "1.4.3"
crc32c = "0.6.3" crc32c = "0.6.3"
libc = "0.2.126" libc = "0.2.123"
log = "0.4.17" log = "0.4.16"
remain = "0.2.3" remain = "0.2.2"
thiserror = "1.0" thiserror = "1.0"
uuid = { version = "1.1.2", features = ["v4"] } uuid = { version = "0.8.2", features = ["v4"] }
vmm-sys-util = ">=0.3.1" vmm-sys-util = ">=0.3.1"

View File

@@ -3,6 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
use std::result::Result;
use uuid::Uuid; use uuid::Uuid;
macro_rules! div_round_up { macro_rules! div_round_up {
@@ -17,7 +18,7 @@ mod vhdx_header;
mod vhdx_io; mod vhdx_io;
mod vhdx_metadata; mod vhdx_metadata;
pub(crate) fn uuid_from_guid(buf: &[u8]) -> Uuid { pub(crate) fn uuid_from_guid(buf: &[u8]) -> Result<Uuid, uuid::Error> {
// The first 3 fields of UUID are stored in Big Endian format, and // The first 3 fields of UUID are stored in Big Endian format, and
// the last 8 bytes are stored as byte array. Therefore, we read the // the last 8 bytes are stored as byte array. Therefore, we read the
// first 3 fields in Big Endian format instead of Little Endian. // first 3 fields in Big Endian format instead of Little Endian.
@@ -25,6 +26,6 @@ pub(crate) fn uuid_from_guid(buf: &[u8]) -> Uuid {
BigEndian::read_u32(&buf[0..4]), BigEndian::read_u32(&buf[0..4]),
BigEndian::read_u16(&buf[4..6]), BigEndian::read_u16(&buf[4..6]),
BigEndian::read_u16(&buf[6..8]), BigEndian::read_u16(&buf[6..8]),
buf[8..16].try_into().unwrap(), &buf[8..16],
) )
} }

Some files were not shown because too many files have changed in this diff Show More