Compare commits

...

171 Commits
v24.0 ... v25.0

Author SHA1 Message Date
Rob Bradford
b132cd2145 build: Release v25.0
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-07-07 15:18:55 +01:00
Sebastien Boeuf
a650b8645f deps: bump virtio-queue from 0.3.0 to 0.4.0
And along with virtio-queue, we must also bump vhost-user-backend from
0.3.0 to 0.5.0 (since it relies on virtio-queue 0.4.0).

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-07-06 16:57:09 +02:00
Sebastien Boeuf
f94a5fb4e3 virtio-devices: Pass negotiated queue size to vhost-user backend
The vhost-user backend was always provided the maximum queue size but
this is incorrect. Instead it must be informed of the actual queue size
that has been negotiated with the virtio driver running in the guest.

This ensures proper functioning of vhost-user-block with the Rust
Hypervisor Firmware, which uses a hardcoded queue size of 16.

Partially fixes #4285

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-07-06 14:45:46 +01:00
Sebastien Boeuf
00800b8499 virtio-devices: Remove deprecated call to VHOST_USER_RESET_OWNER
The latest vhost-user specification describes VHOST_USER_RESET_OWNER
command as deprecated with the following explanation:

  This is no longer used. Used to be sent to request disabling all
  rings, but some back-ends interpreted it to also discard connection
  state (this interpretation would lead to bugs). It is recommended that
  back-ends either ignore this message, or use it to disable all rings.

Also, it's been observed that when using either Rust Hypervisor Firmware
or EDK2 OVMF firmware with SPDK (using the block device as the boot
disk), the virtio reset that happens when the firmware no longer needs
to access the block device caused a failure by triggering the command
VHOST_USER_RESET_OWNER.

For all these reasons, this patch simplifies the virtio reset
implementation by simply disabling the virtqueues and no longer calling
into VHOST_USER_RESET_OWNER.

Partially fixes #4285

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-07-06 14:45:46 +01:00
dependabot[bot]
0b311f6c4c build: bump once_cell from 1.12.1 to 1.13.0
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.12.1 to 1.13.0.
- [Release notes](https://github.com/matklad/once_cell/releases)
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.12.1...v1.13.0)

---
updated-dependencies:
- dependency-name: once_cell
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-06 02:35:11 +00:00
dependabot[bot]
8063c00e67 build: bump openssl-src from 111.21.0+1.1.1p to 111.22.0+1.1.1q
Bumps [openssl-src](https://github.com/alexcrichton/openssl-src-rs) from 111.21.0+1.1.1p to 111.22.0+1.1.1q.
- [Release notes](https://github.com/alexcrichton/openssl-src-rs/releases)
- [Commits](https://github.com/alexcrichton/openssl-src-rs/commits)

---
updated-dependencies:
- dependency-name: openssl-src
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-06 01:47:30 +00:00
dependabot[bot]
4f611c8654 build: bump serde from 1.0.137 to 1.0.138
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.137 to 1.0.138.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.137...v1.0.138)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-06 00:56:48 +00:00
dependabot[bot]
d291b87288 build: bump regex from 1.5.6 to 1.6.0
Bumps [regex](https://github.com/rust-lang/regex) from 1.5.6 to 1.6.0.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.5.6...1.6.0)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-06 00:02:30 +00:00
dependabot[bot]
51787d30da build: bump once_cell from 1.12.1 to 1.13.0 in /fuzz
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.12.1 to 1.13.0.
- [Release notes](https://github.com/matklad/once_cell/releases)
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.12.1...v1.13.0)

---
updated-dependencies:
- dependency-name: once_cell
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-05 23:47:51 +00:00
Sebastien Boeuf
63579341e1 net_util: Don't expect the interface to be IFF_RUNNING
Enabling the TAP interface is only about the IFF_UP flag, meaning we
shouldn't be testing the presence of IFF_RUNNING, and therefore we
shouldn't set it when not present.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-07-05 16:35:58 +01:00
dependabot[bot]
9c0872def7 build: bump once_cell from 1.12.0 to 1.12.1
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.12.0 to 1.12.1.
- [Release notes](https://github.com/matklad/once_cell/releases)
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.12.0...v1.12.1)

---
updated-dependencies:
- dependency-name: once_cell
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-05 11:39:42 +00:00
Rob Bradford
5dfc49c9fa build: Update development container to Rust 1.62
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-07-05 11:50:46 +01:00
dependabot[bot]
65f8c3682f build: bump serde from 1.0.137 to 1.0.138 in /fuzz
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.137 to 1.0.138.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.137...v1.0.138)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-05 00:04:25 +00:00
dependabot[bot]
c87466eea2 build: bump once_cell from 1.12.0 to 1.12.1 in /fuzz
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.12.0 to 1.12.1.
- [Release notes](https://github.com/matklad/once_cell/releases)
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.12.0...v1.12.1)

---
updated-dependencies:
- dependency-name: once_cell
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-04 23:36:34 +00:00
Rob Bradford
6c365617ee Revert "scripts, README.md: Bump reference kernel to 5.18.8"
This reverts commit 1999ab5707.

See: #4273

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-07-04 10:55:28 +01:00
Rob Bradford
30da293d8f tests: Report stderr on ch-remote command failure
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-07-04 09:18:18 +02:00
Rob Bradford
67bfd4e234 tests: tests_api_create_boot: Use ch-remote for creating and booting vm
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-07-04 09:18:18 +02:00
Rob Bradford
46bbe0e612 ch-remote: Simplify ch-remote create from config file
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-07-04 09:18:18 +02:00
dependabot[bot]
216f330f4e build: bump semver from 1.0.11 to 1.0.12
Bumps [semver](https://github.com/dtolnay/semver) from 1.0.11 to 1.0.12.
- [Release notes](https://github.com/dtolnay/semver/releases)
- [Commits](https://github.com/dtolnay/semver/compare/1.0.11...1.0.12)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-02 00:51:37 +00:00
dependabot[bot]
bd075872d4 build: bump mshv-bindings from d94c305 to 7ac1b80
Bumps [mshv-bindings](https://github.com/rust-vmm/mshv) from `d94c305` to `7ac1b80`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](d94c30583f...7ac1b80bff)

---
updated-dependencies:
- dependency-name: mshv-bindings
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 23:57:38 +00:00
dependabot[bot]
7fd5f41623 build: bump semver from 1.0.11 to 1.0.12 in /fuzz
Bumps [semver](https://github.com/dtolnay/semver) from 1.0.11 to 1.0.12.
- [Release notes](https://github.com/dtolnay/semver/releases)
- [Commits](https://github.com/dtolnay/semver/compare/1.0.11...1.0.12)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 23:44:45 +00:00
Rob Bradford
93237f0106 vmm: Set MADT "Online Capable" flag
The Linux kernel now checks for this before marking CPUs as
hotpluggable:

commit aa06e20f1be628186f0c2dcec09ea0009eb69778
Author: Mario Limonciello <mario.limonciello@amd.com>
Date:   Wed Sep 8 16:41:46 2021 -0500

    x86/ACPI: Don't add CPUs that are not online capable

    A number of systems are showing "hotplug capable" CPUs when they
    are not really hotpluggable.  This is because the MADT has extra
    CPU entries to support different CPUs that may be inserted into
    the socket with different numbers of cores.

    Starting with ACPI 6.3 the spec has an Online Capable bit in the
    MADT used to determine whether or not a CPU is hotplug capable
    when the enabled bit is not set.

    Link: https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html?#local-apic-flags
    Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
    Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-07-01 18:45:05 +01:00
Rob Bradford
0c82e7593d tests: Remove test on available entropy bits
As far as I can tell this always reports 256 for us now:
https://lore.kernel.org/lkml/YmlMGx6+uigkGiZ0@zx2c4.com/

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-07-01 18:45:05 +01:00
Rob Bradford
1999ab5707 scripts, README.md: Bump reference kernel to 5.18.8
This marginally reduced the number of patches in the fork.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-07-01 18:45:05 +01:00
dependabot[bot]
5c22f02f32 build: bump clap from 3.2.7 to 3.2.8
Bumps [clap](https://github.com/clap-rs/clap) from 3.2.7 to 3.2.8.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.2.7...v3.2.8)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-30 22:07:39 +00:00
dependabot[bot]
c7afb44c5a build: bump smallvec from 1.8.1 to 1.9.0
Bumps [smallvec](https://github.com/servo/rust-smallvec) from 1.8.1 to 1.9.0.
- [Release notes](https://github.com/servo/rust-smallvec/releases)
- [Commits](https://github.com/servo/rust-smallvec/compare/v1.8.1...v1.9.0)

---
updated-dependencies:
- dependency-name: smallvec
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-30 22:00:55 +01:00
Rob Bradford
b0afeeeb65 ch-remote: Add "create" command to ch-remote
Tested by:
1. Path: ch-remote --api-socket .. create test-config.json
2. stdin with "-" path: ch-remote --api-socket .. create - < test-config.json
2. stding with implicit "-": ch-remote --api-socket .. create < test-config.json

Fixes: #4250

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-30 21:29:54 +01:00
dependabot[bot]
cb53a8b40c build: bump semver from 1.0.10 to 1.0.11
Bumps [semver](https://github.com/dtolnay/semver) from 1.0.10 to 1.0.11.
- [Release notes](https://github.com/dtolnay/semver/releases)
- [Commits](https://github.com/dtolnay/semver/compare/1.0.10...1.0.11)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-30 20:51:02 +01:00
Rob Bradford
adf5881757 build: #[allow(clippy::significant_drop_in_scrutinee) in some crates
This check is new in the beta version of clippy and exists to avoid
potential deadlocks by highlighting when the test in an if or for loop
is something that holds a lock. In many cases we would need to make
significant refactorings to be able to pass this check so disable in the
affected crates.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-30 20:50:45 +01:00
Rob Bradford
44eca31642 build: Fix beta clippy issue (needless_return)
warning: accessing first element with `data.get(0)`
    --> virtio-devices/src/transport/pci_device.rs:1055:34
     |
1055 |                 if let Some(v) = data.get(0) {
     |                                  ^^^^^^^^^^^ help: try: `data.first()`
     |
     = note: `#[warn(clippy::get_first)]` on by default
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#get_first

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-30 20:50:45 +01:00
Rob Bradford
b57d7b258d build: Fix beta clippy issue (needless_return)
warning: unneeded `return` statement
   --> pci/src/vfio_user.rs:627:13
    |
627 | /             return Err(std::io::Error::new(
628 | |                 std::io::ErrorKind::Other,
629 | |                 format!("Region not found for 0x{:x}", gpa),
630 | |             ));
    | |_______________^
    |
    = note: `#[warn(clippy::needless_return)]` on by default
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
help: remove `return`
    |
627 ~             Err(std::io::Error::new(
628 +                 std::io::ErrorKind::Other,
629 +                 format!("Region not found for 0x{:x}", gpa),
630 +             ))
    |

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-30 20:50:45 +01:00
Rob Bradford
d7decfd525 build: Fix beta clippy issue (unnecessary_to_owned)
warning: unnecessary use of `to_vec`
  --> acpi_tables/src/aml.rs:71:37
   |
71 |             bytes.extend_from_slice(&part.to_vec());
   |                                     ^^^^^^^^^^^^^^ help: use: `part.as_ref()`
   |
   = note: `#[warn(clippy::unnecessary_to_owned)]` on by default
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-30 20:50:45 +01:00
Rob Bradford
2716bc3311 build: Fix beta clippy issue (derive_partial_eq_without_eq)
warning: you are deriving `PartialEq` and can implement `Eq`
  --> vmm/src/serial_manager.rs:59:30
   |
59 | #[derive(Debug, Clone, Copy, PartialEq)]
   |                              ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-30 20:50:45 +01:00
dependabot[bot]
9cf0dee264 build: bump mshv-ioctls from 27477b7 to d94c305
Bumps [mshv-ioctls](https://github.com/rust-vmm/mshv) from `27477b7` to `d94c305`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](27477b713d...d94c30583f)

---
updated-dependencies:
- dependency-name: mshv-ioctls
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-30 18:22:23 +01:00
dependabot[bot]
d8b3d07825 build: bump clap from 3.2.7 to 3.2.8 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 3.2.7 to 3.2.8.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.2.7...v3.2.8)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-30 17:57:04 +01:00
dependabot[bot]
3d66e86604 build: bump serde_json from 1.0.81 to 1.0.82
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.81 to 1.0.82.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.81...v1.0.82)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-30 17:56:47 +01:00
dependabot[bot]
a2164873ac build: bump semver from 1.0.10 to 1.0.11 in /fuzz
Bumps [semver](https://github.com/dtolnay/semver) from 1.0.10 to 1.0.11.
- [Release notes](https://github.com/dtolnay/semver/releases)
- [Commits](https://github.com/dtolnay/semver/compare/1.0.10...1.0.11)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-30 17:37:28 +01:00
dependabot[bot]
7f8cf4f8e7 build: bump serde_json from 1.0.81 to 1.0.82 in /fuzz
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.81 to 1.0.82.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.81...v1.0.82)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-30 17:05:29 +01:00
dependabot[bot]
aedbd7ae27 build: bump clap_lex from 0.2.3 to 0.2.4 in /fuzz
Bumps [clap_lex](https://github.com/clap-rs/clap) from 0.2.3 to 0.2.4.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_lex-v0.2.3...clap_lex-v0.2.4)

---
updated-dependencies:
- dependency-name: clap_lex
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-30 16:20:56 +01:00
dependabot[bot]
bb4461e951 build: bump clap_lex from 0.2.3 to 0.2.4
Bumps [clap_lex](https://github.com/clap-rs/clap) from 0.2.3 to 0.2.4.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_lex-v0.2.3...clap_lex-v0.2.4)

---
updated-dependencies:
- dependency-name: clap_lex
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-29 01:23:11 +00:00
dependabot[bot]
54fe5fb9f5 build: bump clap from 3.2.6 to 3.2.7
Bumps [clap](https://github.com/clap-rs/clap) from 3.2.6 to 3.2.7.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.2.6...v3.2.7)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-29 00:26:54 +00:00
dependabot[bot]
5a9e7ee7fe build: bump clap from 3.2.6 to 3.2.7 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 3.2.6 to 3.2.7.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.2.6...v3.2.7)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-28 23:39:43 +00:00
Rob Bradford
2e664dca64 vmm: Always reset the console mode on VMM exit
Tested:

1. SIGTERM based
2. VM shutdown/poweroff
3. Injected VM boot failure after calling Vm::setup_tty()

Fixes: #4248

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-28 16:45:27 +01:00
dependabot[bot]
a26f86f8ad build: bump smallvec from 1.8.0 to 1.8.1
Bumps [smallvec](https://github.com/servo/rust-smallvec) from 1.8.0 to 1.8.1.
- [Release notes](https://github.com/servo/rust-smallvec/releases)
- [Commits](https://github.com/servo/rust-smallvec/compare/v1.8.0...v1.8.1)

---
updated-dependencies:
- dependency-name: smallvec
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-27 23:56:42 +00:00
dependabot[bot]
fde13889f4 build: bump arbitrary from 1.1.2 to 1.1.3 in /fuzz
Bumps [arbitrary](https://github.com/rust-fuzz/arbitrary) from 1.1.2 to 1.1.3.
- [Release notes](https://github.com/rust-fuzz/arbitrary/releases)
- [Changelog](https://github.com/rust-fuzz/arbitrary/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-fuzz/arbitrary/compare/v1.1.2...v1.1.3)

---
updated-dependencies:
- dependency-name: arbitrary
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-27 23:43:02 +00:00
Rob Bradford
65ec6631fb vmm: cpu: Store the vCPU snapshots in ascending order
The snapshots are stored in a BTree which is ordered however as the ids
are strings lexical ordering places "11" ahead of "2". So encode the
vCPU id with zero padding so it is lexically sorted.

This fixes issues with CPU restore on aarch64.

See: #4239

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-27 16:20:57 +01:00
Dylan Bargatze
6ac8dc8745 Change to .
Signed-off-by: Dylan Bargatze <dbargatz@users.noreply.github.com>
2022-06-27 11:24:57 +01:00
Wei Liu
2f514523dd hypervisor: emulator: use matches!
No functional change. Just make the code a bit nicer to read.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-06-23 17:30:21 +02:00
dependabot[bot]
92f559f6f2 build: bump vfio-ioctls from f75a77c to 38272d3
Bumps [vfio-ioctls](https://github.com/rust-vmm/vfio) from `f75a77c` to `38272d3`.
- [Release notes](https://github.com/rust-vmm/vfio/releases)
- [Commits](f75a77c1ab...38272d3f06)

---
updated-dependencies:
- dependency-name: vfio-ioctls
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-23 06:19:10 +00:00
dependabot[bot]
3972e38371 build: bump mshv-bindings from bec9eba to 27477b7
Bumps [mshv-bindings](https://github.com/rust-vmm/mshv) from `bec9eba` to `27477b7`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](bec9ebaac3...27477b713d)

---
updated-dependencies:
- dependency-name: mshv-bindings
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-23 05:32:24 +00:00
dependabot[bot]
a1a016526f build: bump clap from 3.2.5 to 3.2.6
Bumps [clap](https://github.com/clap-rs/clap) from 3.2.5 to 3.2.6.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.2.5...v3.2.6)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-22 04:35:13 +00:00
dependabot[bot]
a5692a95c1 build: bump quote from 1.0.19 to 1.0.20
Bumps [quote](https://github.com/dtolnay/quote) from 1.0.19 to 1.0.20.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.19...1.0.20)

---
updated-dependencies:
- dependency-name: quote
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-22 03:28:22 +00:00
dependabot[bot]
0fd25b3246 build: bump clap_lex from 0.2.2 to 0.2.3 in /fuzz
Bumps [clap_lex](https://github.com/clap-rs/clap) from 0.2.2 to 0.2.3.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_lex-v0.2.2...clap_lex-v0.2.3)

---
updated-dependencies:
- dependency-name: clap_lex
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-22 02:55:23 +00:00
dependabot[bot]
e6127df703 build: bump clap_lex from 0.2.2 to 0.2.3
Bumps [clap_lex](https://github.com/clap-rs/clap) from 0.2.2 to 0.2.3.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_lex-v0.2.2...clap_lex-v0.2.3)

---
updated-dependencies:
- dependency-name: clap_lex
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-22 02:23:56 +00:00
dependabot[bot]
559657eecc build: bump indexmap from 1.9.0 to 1.9.1 in /fuzz
Bumps [indexmap](https://github.com/bluss/indexmap) from 1.9.0 to 1.9.1.
- [Release notes](https://github.com/bluss/indexmap/releases)
- [Changelog](https://github.com/bluss/indexmap/blob/master/RELEASES.md)
- [Commits](https://github.com/bluss/indexmap/compare/1.9.0...1.9.1)

---
updated-dependencies:
- dependency-name: indexmap
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-22 01:52:44 +00:00
dependabot[bot]
66f1ec0063 build: bump indexmap from 1.9.0 to 1.9.1
Bumps [indexmap](https://github.com/bluss/indexmap) from 1.9.0 to 1.9.1.
- [Release notes](https://github.com/bluss/indexmap/releases)
- [Changelog](https://github.com/bluss/indexmap/blob/master/RELEASES.md)
- [Commits](https://github.com/bluss/indexmap/compare/1.9.0...1.9.1)

---
updated-dependencies:
- dependency-name: indexmap
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-22 01:19:00 +00:00
dependabot[bot]
13d081ac47 build: bump quote from 1.0.19 to 1.0.20 in /fuzz
Bumps [quote](https://github.com/dtolnay/quote) from 1.0.19 to 1.0.20.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.19...1.0.20)

---
updated-dependencies:
- dependency-name: quote
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-22 00:49:19 +00:00
dependabot[bot]
b12f4ccade build: bump openssl-src from 111.20.0+1.1.1o to 111.21.0+1.1.1p
Bumps [openssl-src](https://github.com/alexcrichton/openssl-src-rs) from 111.20.0+1.1.1o to 111.21.0+1.1.1p.
- [Release notes](https://github.com/alexcrichton/openssl-src-rs/releases)
- [Commits](https://github.com/alexcrichton/openssl-src-rs/commits)

---
updated-dependencies:
- dependency-name: openssl-src
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-22 00:27:48 +00:00
dependabot[bot]
1f8bca4840 build: bump clap from 3.2.5 to 3.2.6 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 3.2.5 to 3.2.6.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.2.5...v3.2.6)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-22 00:13:52 +00:00
dependabot[bot]
833eb2ebe6 build: bump proc-macro2 from 1.0.39 to 1.0.40
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.39 to 1.0.40.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.39...1.0.40)

---
updated-dependencies:
- dependency-name: proc-macro2
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-21 11:50:46 +00:00
dependabot[bot]
7c7f0f1f5f build: bump proc-macro2 from 1.0.39 to 1.0.40 in /fuzz
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.39 to 1.0.40.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.39...1.0.40)

---
updated-dependencies:
- dependency-name: proc-macro2
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-21 11:42:40 +01:00
dependabot[bot]
d445ec7633 build: bump syn from 1.0.96 to 1.0.98
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.96 to 1.0.98.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.96...1.0.98)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-21 11:42:30 +01:00
dependabot[bot]
039e758f15 build: bump syn from 1.0.96 to 1.0.98 in /fuzz
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.96 to 1.0.98.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.96...1.0.98)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-21 01:05:33 +00:00
dependabot[bot]
eb55d0809e build: bump anyhow from 1.0.57 to 1.0.58
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.57 to 1.0.58.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.57...1.0.58)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-21 00:46:25 +00:00
dependabot[bot]
ecde44617b build: bump quote from 1.0.18 to 1.0.19 in /fuzz
Bumps [quote](https://github.com/dtolnay/quote) from 1.0.18 to 1.0.19.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.18...1.0.19)

---
updated-dependencies:
- dependency-name: quote
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-21 00:31:52 +00:00
dependabot[bot]
58e567b309 build: bump quote from 1.0.18 to 1.0.19
Bumps [quote](https://github.com/dtolnay/quote) from 1.0.18 to 1.0.19.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.18...1.0.19)

---
updated-dependencies:
- dependency-name: quote
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-20 23:58:53 +00:00
dependabot[bot]
fa0140a183 build: bump anyhow from 1.0.57 to 1.0.58 in /fuzz
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.57 to 1.0.58.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.57...1.0.58)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-20 23:40:45 +00:00
Wei Liu
c6c5e4ee87 vhost_user_block: drop Sync bound for DiskFile
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-06-20 23:28:57 +01:00
Wei Liu
a64bdcf3f5 hypervisor: drop Send+Sync bounds for PlatformEmulator
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-06-20 23:28:57 +01:00
Wei Liu
439823e7ea virtio-devices: drop Send+Sync bounds for DmaRemapping
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-06-20 23:28:57 +01:00
Wei Liu
9019086625 block_util: drop Sync bound for DiskFile and AsyncIo
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-06-20 23:28:57 +01:00
Wei Liu
bccd7c7e48 vmm: drop Sync+Send bounds for EndpointHandler
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-06-20 23:28:57 +01:00
Wei Liu
f1dc7f442a net_util: switch from lazy_static to once_cell
Once_cell does not require using macro and is slated to become part of
Rust std at some point.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-06-20 16:03:07 +01:00
Wei Liu
32b855df3a tests: switch from lazy_static to once_cell
Once_cell does not require using macro and is slated to become part of
Rust std at some point.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-06-20 16:03:07 +01:00
Wei Liu
8fa1098629 vmm: switch from lazy_static to once_cell
Once_cell does not require using macro and is slated to become part of
Rust std at some point.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-06-20 16:03:07 +01:00
dependabot[bot]
41cec53bb8 build: bump indexmap from 1.8.2 to 1.9.0
Bumps [indexmap](https://github.com/bluss/indexmap) from 1.8.2 to 1.9.0.
- [Release notes](https://github.com/bluss/indexmap/releases)
- [Changelog](https://github.com/bluss/indexmap/blob/master/RELEASES.md)
- [Commits](https://github.com/bluss/indexmap/compare/1.8.2...1.9.0)

---
updated-dependencies:
- dependency-name: indexmap
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-18 00:40:57 +00:00
dependabot[bot]
fd9f14893b build: bump indexmap from 1.8.2 to 1.9.0 in /fuzz
Bumps [indexmap](https://github.com/bluss/indexmap) from 1.8.2 to 1.9.0.
- [Release notes](https://github.com/bluss/indexmap/releases)
- [Changelog](https://github.com/bluss/indexmap/blob/master/RELEASES.md)
- [Commits](https://github.com/bluss/indexmap/compare/1.8.2...1.9.0)

---
updated-dependencies:
- dependency-name: indexmap
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-17 23:52:48 +00:00
Rob Bradford
7c8719b4ea tests: Unify API based boot across architectures
Use direct kernel boot for all the tests that create the VM via API.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-17 16:52:56 +01:00
Sebastien Boeuf
335a4e1cc0 vmm: api: Expose kvm_hyperv parameter in OpenAPI description
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-06-17 15:11:53 +01:00
dependabot[bot]
6dbbd0363f build: bump mshv-bindings from cda9d65 to bec9eba
Bumps [mshv-bindings](https://github.com/rust-vmm/mshv) from `cda9d65` to `bec9eba`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](cda9d658f4...bec9ebaac3)

---
updated-dependencies:
- dependency-name: mshv-bindings
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-17 13:11:28 +00:00
dependabot[bot]
40e1ad3f62 build: bump arbitrary from 1.1.1 to 1.1.2 in /fuzz
Bumps [arbitrary](https://github.com/rust-fuzz/arbitrary) from 1.1.1 to 1.1.2.
- [Release notes](https://github.com/rust-fuzz/arbitrary/releases)
- [Changelog](https://github.com/rust-fuzz/arbitrary/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-fuzz/arbitrary/compare/1.1.1...v1.1.2)

---
updated-dependencies:
- dependency-name: arbitrary
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-16 23:43:08 +00:00
Rob Bradford
094625242d tests: Add tests for vm.delete and vm.shutdown
Fixes: #1295

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-16 11:29:33 +01:00
Rob Bradford
b3569f084d ch-remote: Add missing boot and delete commands
These are simple commands so require no further enabling than adding to
the list of commands.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-16 11:29:33 +01:00
dependabot[bot]
3800212def build: bump clap from 3.2.4 to 3.2.5
Bumps [clap](https://github.com/clap-rs/clap) from 3.2.4 to 3.2.5.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.2.4...v3.2.5)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-16 10:09:02 +00:00
dependabot[bot]
e9f5052fcd build: bump mshv-ioctls from 82be857 to cda9d65
Bumps [mshv-ioctls](https://github.com/rust-vmm/mshv) from `82be857` to `cda9d65`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](82be8577d1...cda9d658f4)

---
updated-dependencies:
- dependency-name: mshv-ioctls
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-16 10:08:50 +01:00
Rob Bradford
a583b055f5 docs: Add LBR profiling instructions to profiling.md
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-16 07:43:36 +01:00
dependabot[bot]
2b33e66bb4 build: bump clap from 3.2.4 to 3.2.5 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 3.2.4 to 3.2.5.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.2.4...v3.2.5)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-15 23:41:07 +00:00
dependabot[bot]
92ceef52c8 build: bump mshv-ioctls from ae24471 to 82be857
Bumps [mshv-ioctls](https://github.com/rust-vmm/mshv) from `ae24471` to `82be857`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](ae244716b3...82be8577d1)

---
updated-dependencies:
- dependency-name: mshv-ioctls
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-15 03:09:04 +00:00
dependabot[bot]
d7baa58e11 build: bump unicode-ident from 1.0.0 to 1.0.1
Bumps [unicode-ident](https://github.com/dtolnay/unicode-ident) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/dtolnay/unicode-ident/releases)
- [Commits](https://github.com/dtolnay/unicode-ident/compare/1.0.0...1.0.1)

---
updated-dependencies:
- dependency-name: unicode-ident
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-15 02:04:21 +00:00
dependabot[bot]
2d39b6ed06 build: bump getrandom from 0.2.6 to 0.2.7 in /fuzz
Bumps [getrandom](https://github.com/rust-random/getrandom) from 0.2.6 to 0.2.7.
- [Release notes](https://github.com/rust-random/getrandom/releases)
- [Changelog](https://github.com/rust-random/getrandom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/getrandom/compare/v0.2.6...v0.2.7)

---
updated-dependencies:
- dependency-name: getrandom
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-15 01:09:41 +00:00
dependabot[bot]
ed31ca9041 build: bump gdbstub_arch from 0.2.2 to 0.2.3
Bumps [gdbstub_arch](https://github.com/daniel5151/gdbstub) from 0.2.2 to 0.2.3.
- [Release notes](https://github.com/daniel5151/gdbstub/releases)
- [Changelog](https://github.com/daniel5151/gdbstub/blob/master/CHANGELOG.md)
- [Commits](https://github.com/daniel5151/gdbstub/commits)

---
updated-dependencies:
- dependency-name: gdbstub_arch
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-15 00:59:21 +00:00
dependabot[bot]
06b880e99f build: bump clap from 3.2.1 to 3.2.4 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 3.2.1 to 3.2.4.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v3.2.1...v3.2.4)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-15 00:39:46 +00:00
dependabot[bot]
742ca68070 build: bump clap from 3.1.18 to 3.2.4
Bumps [clap](https://github.com/clap-rs/clap) from 3.1.18 to 3.2.4.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.1.18...v3.2.4)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-14 23:58:30 +00:00
dependabot[bot]
f950cb1fdb build: bump arbitrary from 1.1.0 to 1.1.1 in /fuzz
Bumps [arbitrary](https://github.com/rust-fuzz/arbitrary) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/rust-fuzz/arbitrary/releases)
- [Changelog](https://github.com/rust-fuzz/arbitrary/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-fuzz/arbitrary/commits/1.1.1)

---
updated-dependencies:
- dependency-name: arbitrary
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-14 23:50:22 +00:00
dependabot[bot]
c6c5dca651 build: bump micro_http from a730d86 to 863b037
Bumps [micro_http](https://github.com/firecracker-microvm/micro-http) from `a730d86` to `863b037`.
- [Release notes](https://github.com/firecracker-microvm/micro-http/releases)
- [Commits](a730d86940...863b0370ba)

---
updated-dependencies:
- dependency-name: micro_http
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-14 14:59:13 +00:00
dependabot[bot]
d646e10079 build: bump clap_lex from 0.2.0 to 0.2.2
Bumps [clap_lex](https://github.com/clap-rs/clap) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_lex-v0.2.0...clap_lex-v0.2.2)

---
updated-dependencies:
- dependency-name: clap_lex
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-14 09:44:39 +00:00
dependabot[bot]
efe0429a9a build: bump getrandom from 0.2.6 to 0.2.7
Bumps [getrandom](https://github.com/rust-random/getrandom) from 0.2.6 to 0.2.7.
- [Release notes](https://github.com/rust-random/getrandom/releases)
- [Changelog](https://github.com/rust-random/getrandom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/getrandom/compare/v0.2.6...v0.2.7)

---
updated-dependencies:
- dependency-name: getrandom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-14 08:57:32 +00:00
dependabot[bot]
1f3321c50e build: bump gdbstub from 0.6.1 to 0.6.2
Bumps [gdbstub](https://github.com/daniel5151/gdbstub) from 0.6.1 to 0.6.2.
- [Release notes](https://github.com/daniel5151/gdbstub/releases)
- [Changelog](https://github.com/daniel5151/gdbstub/blob/master/CHANGELOG.md)
- [Commits](https://github.com/daniel5151/gdbstub/compare/0.6.1...0.6.2)

---
updated-dependencies:
- dependency-name: gdbstub
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-14 08:09:13 +00:00
dependabot[bot]
c0d51eecf1 build: bump unicode-ident from 1.0.0 to 1.0.1 in /fuzz
Bumps [unicode-ident](https://github.com/dtolnay/unicode-ident) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/dtolnay/unicode-ident/releases)
- [Commits](https://github.com/dtolnay/unicode-ident/compare/1.0.0...1.0.1)

---
updated-dependencies:
- dependency-name: unicode-ident
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-14 00:13:03 +00:00
dependabot[bot]
1b9dc80469 build: bump clap from 3.1.18 to 3.2.1 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 3.1.18 to 3.2.1.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.1.18...clap_complete-v3.2.1)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-13 23:46:23 +00:00
dependabot[bot]
43d32a7288 build: bump semver from 1.0.9 to 1.0.10 in /fuzz
Bumps [semver](https://github.com/dtolnay/semver) from 1.0.9 to 1.0.10.
- [Release notes](https://github.com/dtolnay/semver/releases)
- [Commits](https://github.com/dtolnay/semver/compare/1.0.9...1.0.10)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-11 01:49:02 +00:00
dependabot[bot]
27e04e41bf build: bump semver from 1.0.9 to 1.0.10
Bumps [semver](https://github.com/dtolnay/semver) from 1.0.9 to 1.0.10.
- [Release notes](https://github.com/dtolnay/semver/releases)
- [Commits](https://github.com/dtolnay/semver/compare/1.0.9...1.0.10)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-11 01:13:07 +00:00
dependabot[bot]
41ac48d332 build: bump uuid from 1.1.1 to 1.1.2
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.1.1 to 1.1.2.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.1.1...1.1.2)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-11 00:25:45 +00:00
dependabot[bot]
2afaed9111 build: bump uuid from 1.1.1 to 1.1.2 in /fuzz
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.1.1 to 1.1.2.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.1.1...1.1.2)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-10 23:39:30 +00:00
Rob Bradford
f1ea69474d scripts: Mark git repository as safe
Git will refuse to generate information for the report if the repository
is owned by a different user (root in the container vs the real owner
outside).

e.g:

Error generating human readable git reference: fatal: unsafe repository ('/cloud-hypervisor' is owned by someone else)
To add an exception for this directory, call:

	git config --global --add safe.directory /cloud-hypervisor

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-10 17:20:13 +01:00
Rob Bradford
cac42301f8 performance-metrics: Produce some error messages if git commands fail
It is reasonable for these to fail as it the tool could be run outside
of a git repository but by not giving any error message we cannot see
issues when we expect the report to have the git details.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-10 17:20:13 +01:00
Jinank Jain
ada85f68f6 hypervisor: mshv: Override hypervisor R/W behavior for unknown MSR
By default Microsoft Hypervisor send a GP to the guest if it tries
read/write an unimplemented MSR from the hypervisor prospective. Instead
change this behavior to ignore read/write operations for unimplemented
MSRs

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2022-06-09 20:53:58 +01:00
Rob Bradford
64b4b7205e Revert "build: Temporarily disable VFIO, SGX and metrics build steps"
This reverts commit d96614fe42.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-09 10:30:07 +01:00
dependabot[bot]
4a4352f9d9 build: bump mshv-ioctls from 67e13fa to ae24471
Bumps [mshv-ioctls](https://github.com/rust-vmm/mshv) from `67e13fa` to `ae24471`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](67e13faa36...ae244716b3)

---
updated-dependencies:
- dependency-name: mshv-ioctls
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-09 08:46:46 +00:00
Sebastien Boeuf
81ba70a497 pci, vmm: Defer mapping VFIO MMIO regions on restore
When restoring a VM, the restore codepath will take care of mapping the
MMIO regions based on the information from the snapshot, rather than
having the mapping being performed during device creation.

When the device is created, information such as which BARs contain the
MSI-X tables are missing, preventing to perform the mapping of the MMIO
regions.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-06-09 09:19:58 +02:00
Sebastien Boeuf
7df7061610 pci, vmm: Add migratable support to vfio-user devices
Based on recent changes to VfioUserPciDevice, the vfio-user devices can
now be migrated.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-06-09 09:19:58 +02:00
Sebastien Boeuf
c021dda267 pci, vmm: Add migratable support to VFIO devices
Based on recent changes to VfioPciDevice, the VFIO devices can now be
migrated.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-06-09 09:19:58 +02:00
Sebastien Boeuf
f48b05eee6 pci: vfio_user: Implement Migratable for VfioUserPciDevice
Based on the VfioCommon implementation, the VfioUserPciDevice now
implements the Migratable trait.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-06-09 09:19:58 +02:00
Sebastien Boeuf
3b59e57001 pci: vfio: Implement Migratable for VfioPciDevice
Based on the VfioCommon implementation, the VfioPciDevice now implements
the Migratable trait.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-06-09 09:19:58 +02:00
Sebastien Boeuf
49069d8474 pci: Implement Migratable for VfioCommon
Introduces the common code to handle one aspect of the migration
support. Particularly, the ability to store VMM internal states related
to such device. The internal state of the device will happen later in a
dedicated patchset that will implement the VFIO migration API.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-06-09 09:19:58 +02:00
Sebastien Boeuf
8eaefa6e8e pci: msix: Derive Versionize for MsixCap
So that we can save and restore the whole structure through snapshot and
restore operations.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-06-09 09:19:58 +02:00
Sebastien Boeuf
a1b996ac37 pci: msi: Make MsiCap field public
So that it can be accessed during a VM snapshot to store its state.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-06-09 09:19:58 +02:00
Rob Bradford
4ddc6ffd73 .github: Add missing clippy check with "guest_debug" feature
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-08 11:40:56 +01:00
Rob Bradford
94fb9f817d vmm: Fix clippy issues under "guest_debug" feature
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-08 11:40:56 +01:00
Rob Bradford
133a5a858a vmm: Pull in gdb dependencies only when building with feature
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-08 11:30:20 +01:00
Jinank Jain
3a18860326 Reapply "Jenkinsfile: Bypass running CI for fuzzer Cargo file changes"
This reverts commit 0d0013c46e.

Grovvy shell script execution engine does not like backslash as the
escape character. So we need to put another backslash to escape the
backslash character. This would most likely fix the issue that we saw
with the CI.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2022-06-07 07:40:33 +01:00
Rob Bradford
0d0013c46e Revert "Jenkinsfile: Bypass running CI for fuzzer Cargo file changes"
This reverts commit 86d243938e.

Build error:

Obtained Jenkinsfile from 86d243938e
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 311: unexpected char: '\' @ line 311, column 88.
   _TARGET}... | grep -v -E 'fuzz\/Cargo.(t

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-06 15:38:18 +01:00
Jinank Jain
86d243938e Jenkinsfile: Bypass running CI for fuzzer Cargo file changes
In order to conserve resources it is better to not run CI, whenever there
are changes only in fuzz/Cargo.toml or fuzz/Cargo.lock.

Fixes #4148

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2022-06-06 15:29:19 +01:00
Michael Zhao
a7a15d56dd aarch64: Move setup_regs to hypervisor
`setup_regs` of AArch64 calls KVM sepecific code. Now move it to
`hypervisor` crate.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-06-06 11:07:46 +01:00
Sebastien Boeuf
65dc1c83a9 vmm: cpu: Save and restore CPU states during snapshot/restore
Based on recent KVM host patches (merged in Linux 5.16), it's forbidden
to call into KVM_SET_CPUID2 after the first successful KVM_RUN returned.
That means saving CPU states during the pause sequence, and restoring
these states during the resume sequence will not work with the current
design starting with kernel version 5.16.

In order to solve this problem, let's simply move the save/restore logic
to the snapshot/restore sequences rather than the pause/resume ones.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-06-06 11:07:29 +01:00
Sebastien Boeuf
3edaa8adb6 vmm: Ensure restore matches boot sequence
The vCPU is created and set after all the devices on a VM's boot.
There's no reason to follow a different order on the restore codepath as
this could cause some unexpected behaviors.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-06-06 11:07:17 +01:00
Michael Zhao
9260c3816e vmm: Update unit test for GIC refactoring
Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-06-06 10:17:26 +08:00
Michael Zhao
5d45d6d0fb vmm: Move GIC unit test to hypervisor crate
Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-06-06 10:17:26 +08:00
Michael Zhao
957d3a7443 aarch64: Simplify GIC related structs definition
Combined the `GicDevice` struct in `arch` crate and the `Gic` struct in
`devices` crate.

After moving the KVM specific code for GIC in `arch`, a very thin wapper
layer `GicDevice` was left in `arch` crate. It is easy to combine it
with the `Gic` in `devices` crate.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-06-06 10:17:26 +08:00
Michael Zhao
04949755c0 arch: Switch to new GIC interface
Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-06-06 10:17:26 +08:00
Michael Zhao
b8dbb26647 hypervisor: Refactor save_pending_tables of Vgic
Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-06-06 10:17:26 +08:00
Michael Zhao
3fe7d61a02 hypervisor: Remove some redundant parameters
Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-06-06 10:17:26 +08:00
Michael Zhao
c2862b6947 hypervisor: Move GitV3Its code from arch
Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-06-06 10:17:26 +08:00
Michael Zhao
03b01c02cd hypervisor: Define Vgic trait
Defined `Vgic` trait as the hypervisor agnostic interface for a virtual
GIC.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-06-06 10:17:26 +08:00
dependabot[bot]
435d769511 build: bump syn from 1.0.95 to 1.0.96
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.95 to 1.0.96.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.95...1.0.96)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-03 12:15:08 +00:00
dependabot[bot]
9ba6767a90 build: bump pnet from 0.30.0 to 0.31.0
Bumps [pnet](https://github.com/libpnet/libpnet) from 0.30.0 to 0.31.0.
- [Release notes](https://github.com/libpnet/libpnet/releases)
- [Commits](https://github.com/libpnet/libpnet/compare/v0.30.0...v0.31.0)

---
updated-dependencies:
- dependency-name: pnet
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
Signed-off-by: dependabot[bot] <support@github.com>
2022-06-03 08:59:43 +00:00
dependabot[bot]
3742cc42ae build: bump syn from 1.0.95 to 1.0.96 in /fuzz
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.95 to 1.0.96.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.95...1.0.96)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-03 01:57:33 +00:00
dependabot[bot]
e0dd2e41c2 build: bump openssl-sys from 0.9.73 to 0.9.74
Bumps [openssl-sys](https://github.com/sfackler/rust-openssl) from 0.9.73 to 0.9.74.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.73...openssl-sys-v0.9.74)

---
updated-dependencies:
- dependency-name: openssl-sys
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-02 09:41:05 +00:00
dependabot[bot]
f1495b5767 build: bump uuid from 1.1.0 to 1.1.1
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.1.0...1.1.1)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-02 00:48:36 +00:00
dependabot[bot]
6bd4bdfa26 build: bump uuid from 1.1.0 to 1.1.1 in /fuzz
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.1.0...1.1.1)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-02 00:02:36 +00:00
Rob Bradford
ade3a9c8f6 virtio-devices, vmm: Optimised async virtio device activation
In order to ensure that the virtio device thread is spawned from the vmm
thread we use an asynchronous activation mechanism for the virtio
devices. This change optimises that code so that we do not need to
iterate through all virtio devices on the platform in order to find the
one that requires activation. We solve this by creating a separate short
lived VirtioPciDeviceActivator that holds the required state for the
activation (e.g. the clones of the queues) this can then be stored onto
the device manager ready for asynchronous activation.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-06-01 09:42:02 +02:00
dependabot[bot]
15e2763753 build: bump indexmap from 1.8.1 to 1.8.2
Bumps [indexmap](https://github.com/bluss/indexmap) from 1.8.1 to 1.8.2.
- [Release notes](https://github.com/bluss/indexmap/releases)
- [Changelog](https://github.com/bluss/indexmap/blob/1.8.2/RELEASES.rst)
- [Commits](https://github.com/bluss/indexmap/compare/1.8.1...1.8.2)

---
updated-dependencies:
- dependency-name: indexmap
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-31 23:58:11 +00:00
dependabot[bot]
8b87b752b5 build: bump indexmap from 1.8.1 to 1.8.2 in /fuzz
Bumps [indexmap](https://github.com/bluss/indexmap) from 1.8.1 to 1.8.2.
- [Release notes](https://github.com/bluss/indexmap/releases)
- [Changelog](https://github.com/bluss/indexmap/blob/1.8.2/RELEASES.rst)
- [Commits](https://github.com/bluss/indexmap/compare/1.8.1...1.8.2)

---
updated-dependencies:
- dependency-name: indexmap
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 23:55:59 +00:00
dependabot[bot]
7864f91a2b build: bump libz-sys from 1.1.6 to 1.1.8
Bumps [libz-sys](https://github.com/rust-lang/libz-sys) from 1.1.6 to 1.1.8.
- [Release notes](https://github.com/rust-lang/libz-sys/releases)
- [Commits](https://github.com/rust-lang/libz-sys/commits)

---
updated-dependencies:
- dependency-name: libz-sys
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 23:50:20 +00:00
Yi Wang
6ab93a08ec build: Add GitHub action to build test guest_debug feature
Add guest_debug feature test for github workflows.

Signed-off-by: Yi Wang <wang.yi59@zte.com.cn>
2022-05-30 13:41:40 +02:00
Yi Wang
fd41892065 tests: Add integration test for coredump
As coredump function is to make a vmcore for crash tool to analyze,
in order not to introduce a big thing in integration, we just check
if ch-remote command runs no error report here.

Signed-off-by: Yi Wang <wang.yi59@zte.com.cn>
2022-05-30 13:41:40 +02:00
Yi Wang
dbeb922882 doc: add vm coredump support
Signed-off-by: Yi Wang <wang.yi59@zte.com.cn>
Co-authored-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-05-30 13:41:40 +02:00
Yi Wang
0bb2060ca7 ch-remote: add support for coredump
Adding the wrapping layer to be able to coredump the guest
from the ch-remote tool.

Signed-off-by: Yi Wang <wang.yi59@zte.com.cn>
2022-05-30 13:41:40 +02:00
Yi Wang
8b585b96c1 vmm: enable coredump
Based on the newly added guest_debug feature, this patch adds http
endpoint support.

Signed-off-by: Yi Wang <wang.yi59@zte.com.cn>
Co-authored-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-05-30 13:41:40 +02:00
Yi Wang
ccb604e1e1 vmm: add cpu segment note for coredump
The crash tool use a special note segment which named 'QEMU' to
analyze kaslr info and so on. If we don't add the 'QEMU' note
segment, crash tool can't find linux version to move on.

For now, the most convenient way is to add 'QEMU' note segment to
make crash tool happy.

Signed-off-by: Yi Wang <wang.yi59@zte.com.cn>
2022-05-30 13:41:40 +02:00
Yi Wang
0e65ca4a6c vmm: save guest memory for coredump
Guest memory is needed for analysis in crash tool, so save it
for coredump.

Signed-off-by: Yi Wang <wang.yi59@zte.com.cn>
Co-authored-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-05-30 13:41:40 +02:00
Yi Wang
7e280b6f70 vmm: save elf header for coredump
The vmcore file of guest is an elf format, so the first step of coredump
is to save the elf header.

Signed-off-by: Yi Wang <wang.yi59@zte.com.cn>
2022-05-30 13:41:40 +02:00
Yi Wang
90034fd6ba vmm: add GuestDebuggable trait
It's useful to dump the guest, which named coredump so that crash
tool can be used to analysize it when guest hung up.

Let's add GuestDebuggable trait and Coredumpxxx error to support
coredump firstly.

Signed-off-by: Yi Wang <wang.yi59@zte.com.cn>
Co-authored-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-05-30 13:41:40 +02:00
Rob Bradford
642309f141 deps: Bump version of kvm-ioctls
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-27 16:36:02 +02:00
Rob Bradford
5da8a1c08e tests: Use smaller hotplug size for live migration tests
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-27 11:30:27 +02:00
Rob Bradford
465db7f08c vmm: config: Remove mergeable option from PmemConfig
Fixes: #3968

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-27 09:48:49 +02:00
Rob Bradford
55c5961f43 vmm: config: Remove dax & cache_size options from FsConfig
Fixes: #3889

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-27 09:47:13 +02:00
Rob Bradford
7c3582b4a8 vmm: config: Fix error message regarding use of cache size without dax
The error message incorrectly said that the user was trying to combine
cache_size without dax whereas it is only usuable with dax.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-27 09:47:13 +02:00
Rob Bradford
979797786d vmm: Remove DAX cache setup for virtio-fs devices
Remove the code from the DeviceManager that prepares the DAX cache since
the functionality has now been removed.

Fixes: #3889

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-27 09:47:13 +02:00
Rob Bradford
62120f9afe tests: Remove testing of virtio-fs DAX cache
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-27 09:47:13 +02:00
Rob Bradford
56c11600db tests: Rename test_virtio_fs helper
This is so we can have a test called test_virtio_fs

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-27 09:47:13 +02:00
Rob Bradford
f2336413be tests: Simplify virtiofsd spawning
The cache methodology is never changed so it can be hardcoded.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-05-27 09:47:13 +02:00
Michael Zhao
0fd6521759 aarch64: Avoid depending on layout in GIC code
Removing the dependency on `layout` helps moving GIC code into
`hypervisor` crate.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-05-27 10:57:50 +08:00
Michael Zhao
4a2d3cb4f5 aarch64: Refactor KvmGicV3Its::new()
Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-05-27 10:57:50 +08:00
Michael Zhao
3fe20cc09a aarch64: Remove GicDevice trait
`GicDevice` trait was defined for the common part of GicV3 and ITS.
Now that the standalone GicV3 do not exist, `GicDevice` is not needed.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-05-27 10:57:50 +08:00
Michael Zhao
fd581b1afb aarch64: Combine the code of GicV3 and GicV3Its
Why combine:
- GicV3 is not required alone
- GicV3 and GicV3Its has separate snapshot/pause code. But the code of
  GicV3 was never used.
- Reduce the code complexity of GIC related traits and structs.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-05-27 10:57:50 +08:00
Michael Zhao
1e732bf532 aarch64: Remove versionize & versionize_derive
Remove the not-mandatory dependencies in gic source code.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-05-27 10:57:50 +08:00
dependabot[bot]
ad8295e11d build: bump os_str_bytes from 6.0.1 to 6.1.0
Bumps [os_str_bytes](https://github.com/dylni/os_str_bytes) from 6.0.1 to 6.1.0.
- [Release notes](https://github.com/dylni/os_str_bytes/releases)
- [Commits](https://github.com/dylni/os_str_bytes/compare/6.0.1...6.1.0)

---
updated-dependencies:
- dependency-name: os_str_bytes
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-27 00:36:04 +00:00
dependabot[bot]
fe1f0ef49e build: bump os_str_bytes from 6.0.1 to 6.1.0 in /fuzz
Bumps [os_str_bytes](https://github.com/dylni/os_str_bytes) from 6.0.1 to 6.1.0.
- [Release notes](https://github.com/dylni/os_str_bytes/releases)
- [Commits](https://github.com/dylni/os_str_bytes/compare/6.0.1...6.1.0)

---
updated-dependencies:
- dependency-name: os_str_bytes
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-26 23:48:45 +00:00
dependabot[bot]
f9fcc3722f build: bump uuid from 1.0.0 to 1.1.0 in /fuzz
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.0.0 to 1.1.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.0.0...1.1.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-26 01:13:18 +00:00
dependabot[bot]
c0cbaff519 build: bump uuid from 1.0.0 to 1.1.0
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.0.0 to 1.1.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.0.0...1.1.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-26 00:27:34 +00:00
107 changed files with 3351 additions and 2335 deletions

View File

@@ -53,6 +53,9 @@ jobs:
- name: Build (default features + gdb) - name: Build (default features + gdb)
run: cargo rustc --locked --bin cloud-hypervisor --features "gdb" -- -D warnings run: cargo rustc --locked --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 --locked --bin cloud-hypervisor --no-default-features --features "common,mshv" -- -D warnings

View File

@@ -45,6 +45,9 @@ jobs:
- 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 --locked --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 --locked --all --all-targets --no-default-features --tests --features "common,mshv" -- -D warnings

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.60" toolchain: "1.62"
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.60" toolchain: "1.62"
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.60" toolchain: "1.62"
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.60" toolchain: "1.62"
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.60" toolchain: "1.62"
target: aarch64-unknown-linux-musl target: aarch64-unknown-linux-musl
override: true override: true
- name: Static Build (AArch64) - name: Static Build (AArch64)

186
Cargo.lock generated
View File

@@ -20,9 +20,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.57" version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
[[package]] [[package]]
name = "api_client" name = "api_client"
@@ -130,15 +130,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.1.18" version = "3.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83"
dependencies = [ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
"clap_lex", "clap_lex",
"indexmap", "indexmap",
"lazy_static", "once_cell",
"strsim", "strsim",
"termcolor", "termcolor",
"terminal_size", "terminal_size",
@@ -147,16 +147,16 @@ dependencies = [
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.2.0" version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [ dependencies = [
"os_str_bytes", "os_str_bytes",
] ]
[[package]] [[package]]
name = "cloud-hypervisor" name = "cloud-hypervisor"
version = "24.0.0" version = "25.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"api_client", "api_client",
@@ -165,10 +165,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,6 +206,7 @@ dependencies = [
"bitflags", "bitflags",
"byteorder", "byteorder",
"epoll", "epoll",
"hypervisor",
"libc", "libc",
"log", "log",
"versionize", "versionize",
@@ -276,9 +277,9 @@ checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
[[package]] [[package]]
name = "gdbstub" name = "gdbstub"
version = "0.6.1" version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa2ca5d6b045de372cef3991f873389b421b4cabcfbe52f7787fae8b8b37906" checksum = "1c1f9371c87c11642ee94dcf92cb48b1484ba250b8e8bff3df71c28651f3f4e7"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if", "cfg-if",
@@ -290,9 +291,9 @@ dependencies = [
[[package]] [[package]]
name = "gdbstub_arch" name = "gdbstub_arch"
version = "0.2.2" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51dc4b5718ac76d21e8605c0966dd32d80273b89b11e6cfef467b04e45934d37" checksum = "c24f469ba9556c5a063d6df35a8a338025fccf96ecae44f330a156b686f7a268"
dependencies = [ dependencies = [
"gdbstub", "gdbstub",
"num-traits", "num-traits",
@@ -300,9 +301,9 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.6" version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@@ -317,9 +318,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.11.2" version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
@@ -369,9 +370,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.8.1" version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@@ -396,15 +397,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "ipnetwork"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4088d739b183546b239688ddbc79891831df421773df95e236daf7867866d355"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "ipnetwork" name = "ipnetwork"
version = "0.19.0" version = "0.19.0"
@@ -433,7 +425,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#1e03e29cdfbb0cb108a98de7a78045a5a517f18e" source = "git+https://github.com/rust-vmm/kvm-ioctls?branch=main#ccf0bda07485b2433616de998c000aa5f04ce806"
dependencies = [ dependencies = [
"kvm-bindings", "kvm-bindings",
"libc", "libc",
@@ -468,9 +460,9 @@ dependencies = [
[[package]] [[package]]
name = "libz-sys" name = "libz-sys"
version = "1.1.6" version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92e7e15d7610cce1d9752e137625f14e61a28cd45929b6e12e47b50fe154ee2e" checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@@ -521,7 +513,7 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[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#a730d86940081ad044cdfbc1285c1db6d3048392" source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#863b0370ba7e57f7df5b908ada9e5b44809ccae9"
dependencies = [ dependencies = [
"libc", "libc",
"vmm-sys-util", "vmm-sys-util",
@@ -530,7 +522,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#67e13faa36989a9226ad21c9ff3947e1d5738a54" source = "git+https://github.com/rust-vmm/mshv?branch=main#7ac1b80bff7220171c9a626b23b51620ca774468"
dependencies = [ dependencies = [
"libc", "libc",
"serde", "serde",
@@ -542,7 +534,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#67e13faa36989a9226ad21c9ff3947e1d5738a54" source = "git+https://github.com/rust-vmm/mshv?branch=main#7ac1b80bff7220171c9a626b23b51620ca774468"
dependencies = [ dependencies = [
"libc", "libc",
"mshv-bindings", "mshv-bindings",
@@ -562,11 +554,12 @@ 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",
@@ -595,19 +588,25 @@ dependencies = [
] ]
[[package]] [[package]]
name = "openssl-src" name = "once_cell"
version = "111.20.0+1.1.1o" version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92892c4f87d56e376e469ace79f1128fdaded07646ddf73aa0be4706ff712dec" checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
[[package]]
name = "openssl-src"
version = "111.22.0+1.1.1q"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f31f0d509d1c1ae9cada2f9539ff8f37933831fd5098879e482aa687d659853"
dependencies = [ dependencies = [
"cc", "cc",
] ]
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.73" version = "0.9.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d5fd19fb3e0a8191c1e34935718976a3e70c112ab9a24af6d7cadccd9d90bc0" checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cc", "cc",
@@ -623,9 +622,9 @@ version = "0.1.0"
[[package]] [[package]]
name = "os_str_bytes" name = "os_str_bytes"
version = "6.0.1" version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435" checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
@@ -702,34 +701,32 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]] [[package]]
name = "pnet" name = "pnet"
version = "0.30.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5cc57672f576f6b95370277fb445738d4887195c6cf4192bdf4f44697e2389b" checksum = "0caaf5b11fd907ff15cf14a4477bfabca4b37ab9e447a4f8dead969a59cdafad"
dependencies = [ dependencies = [
"ipnetwork 0.19.0",
"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.30.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e88341c6c842f89bdc7287f7b1e26b6fa64fa11c7ea3756971e6f18cd2510c4" checksum = "f9d3a993d49e5fd5d4d854d6999d4addca1f72d86c65adf224a36757161c02b6"
dependencies = [ dependencies = [
"no-std-net", "no-std-net",
] ]
[[package]] [[package]]
name = "pnet_datalink" name = "pnet_datalink"
version = "0.30.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc6e55d71c51db73372db35bc54f43abd8460adff1c3a9b717804ca6416d5df2" checksum = "e466faf03a98ad27f6e15cd27a2b7cc89e73e640a43527742977bc503c37f8aa"
dependencies = [ dependencies = [
"ipnetwork 0.18.0", "ipnetwork",
"libc", "libc",
"pnet_base", "pnet_base",
"pnet_sys", "pnet_sys",
@@ -738,9 +735,9 @@ dependencies = [
[[package]] [[package]]
name = "pnet_macros" name = "pnet_macros"
version = "0.30.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebfcdc9c072966723026b3596a1f655fb8bbfe0142f9770f8d481aee4459d6b9" checksum = "48dd52a5211fac27e7acb14cfc9f30ae16ae0e956b7b779c8214c74559cef4c3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -750,18 +747,18 @@ dependencies = [
[[package]] [[package]]
name = "pnet_macros_support" name = "pnet_macros_support"
version = "0.30.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bba532f5a4b320c029d89e612671fb621851b3b07e972c53850d34130033a5cd" checksum = "89de095dc7739349559913aed1ef6a11e73ceade4897dadc77c5e09de6740750"
dependencies = [ dependencies = [
"pnet_base", "pnet_base",
] ]
[[package]] [[package]]
name = "pnet_packet" name = "pnet_packet"
version = "0.30.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7009716ac86091c1b6e2cdec95a2b028c880f516054c1ec11edd02f9f463cbde" checksum = "bc3b5111e697c39c8b9795b9fdccbc301ab696699e88b9ea5a4e4628978f495f"
dependencies = [ dependencies = [
"glob", "glob",
"pnet_base", "pnet_base",
@@ -771,9 +768,9 @@ dependencies = [
[[package]] [[package]]
name = "pnet_sys" name = "pnet_sys"
version = "0.30.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2a05efbc55c22f664c0ea475fbc4ffc4d09346aff9068438279d7e3d431f6f" checksum = "328e231f0add6d247d82421bf3790b4b33b39c8930637f428eef24c4c6a90805"
dependencies = [ dependencies = [
"libc", "libc",
"winapi", "winapi",
@@ -781,9 +778,9 @@ dependencies = [
[[package]] [[package]]
name = "pnet_transport" name = "pnet_transport"
version = "0.30.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b8ff06f37863f7590183f7044ab2e8d4dae991ecea0c791e3c6dd61ed2913d" checksum = "ff597185e6f1f5671b3122e4dba892a1c73e17c17e723d7669bd9299cbe7f124"
dependencies = [ dependencies = [
"libc", "libc",
"pnet_base", "pnet_base",
@@ -793,9 +790,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.39" version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@@ -813,9 +810,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.18" version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -851,9 +848,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.5.6" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -862,9 +859,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.26" version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]] [[package]]
name = "remain" name = "remain"
@@ -909,24 +906,24 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.9" version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.137" version = "1.0.138"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.137" version = "1.0.138"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -935,9 +932,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.81" version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@@ -965,9 +962,9 @@ dependencies = [
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.8.0" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
[[package]] [[package]]
name = "ssh2" name = "ssh2"
@@ -995,9 +992,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.95" version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1041,8 +1038,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",
@@ -1079,9 +1076,9 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.0" 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 = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
@@ -1091,9 +1088,9 @@ checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.0.0" version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cfcd319456c4d6ea10087ed423473267e1a071f3bc0aa89f80d60997843c6f0" checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
dependencies = [ dependencies = [
"getrandom", "getrandom",
] ]
@@ -1143,7 +1140,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#f75a77c1ab6349c105bc1462a65508726b4c2e0f" source = "git+https://github.com/rust-vmm/vfio?branch=main#38272d3f06bbc0b4b3cfa3f5da07fd1c1c89e4d1"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"kvm-bindings", "kvm-bindings",
@@ -1202,8 +1199,9 @@ dependencies = [
[[package]] [[package]]
name = "vhost-user-backend" name = "vhost-user-backend"
version = "0.3.0" version = "0.5.0"
source = "git+https://github.com/rust-vmm/vhost-user-backend?rev=14f58eda14076e973704d4f904850be1146fbb05#14f58eda14076e973704d4f904850be1146fbb05" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eeb6723bbee20dbc2db95c575941922fb96e77eb41786ecd1c8c03348709c4c"
dependencies = [ dependencies = [
"libc", "libc",
"log", "log",
@@ -1293,9 +1291,9 @@ dependencies = [
[[package]] [[package]]
name = "virtio-queue" name = "virtio-queue"
version = "0.3.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88f2d73c184c18f8acc32dab77fcb6e3af92d53262538d3a68aa474810d6863c" checksum = "519c0a333c871650269cba303bc108075d52a0c0d64f9b91fae61829b53725af"
dependencies = [ dependencies = [
"log", "log",
"vm-memory", "vm-memory",
@@ -1381,12 +1379,12 @@ 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",
@@ -1434,9 +1432,9 @@ dependencies = [
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.10.2+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "winapi" name = "winapi"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "cloud-hypervisor" name = "cloud-hypervisor"
version = "24.0.0" version = "25.0.0"
authors = ["The Cloud Hypervisor Authors"] authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
default-run = "cloud-hypervisor" default-run = "cloud-hypervisor"
@@ -16,9 +16,9 @@ rust-version = "1.60"
lto = true lto = true
[dependencies] [dependencies]
anyhow = "1.0.57" anyhow = "1.0.58"
api_client = { path = "api_client" } api_client = { path = "api_client" }
clap = { version = "3.1.18", features = ["wrap_help","cargo"] } clap = { version = "3.2.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" }
@@ -26,7 +26,7 @@ libc = "0.2.126"
log = { version = "0.4.17", features = ["std"] } log = { version = "0.4.17", features = ["std"] }
option_parser = { path = "option_parser" } option_parser = { path = "option_parser" }
seccompiler = "0.2.0" seccompiler = "0.2.0"
serde_json = "1.0.81" serde_json = "1.0.82"
signal-hook = "0.3.14" signal-hook = "0.3.14"
thiserror = "1.0.31" thiserror = "1.0.31"
vmm = { path = "vmm" } vmm = { path = "vmm" }
@@ -34,7 +34,7 @@ vmm-sys-util = "0.9.0"
vm-memory = "0.8.0" vm-memory = "0.8.0"
[build-dependencies] [build-dependencies]
clap = { version = "3.1.18", features = ["cargo"] } clap = { version = "3.2.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" }
serde_json = "1.0.81" once_cell = "1.13.0"
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,6 +58,7 @@ 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"]

139
Jenkinsfile vendored
View File

@@ -23,6 +23,19 @@ 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).*'
@@ -153,6 +166,88 @@ pipeline{
} }
} }
} }
stage ('Worker build SGX') {
agent { node { label 'bionic-sgx' } }
when {
beforeAgent true
allOf {
branch 'main'
expression {
return runWorkers
}
}
}
stages {
stage ('Checkout') {
steps {
checkout scm
}
}
stage ('Run SGX integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh "scripts/dev_cli.sh tests --integration-sgx"
}
}
stage ('Run SGX integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh "scripts/dev_cli.sh tests --integration-sgx --libc musl"
}
}
}
post {
always {
sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
deleteDir()
}
}
}
stage ('Worker build VFIO') {
agent { node { label 'bionic-vfio' } }
when {
beforeAgent true
allOf {
branch 'main'
expression {
return runWorkers
}
}
}
stages {
stage ('Checkout') {
steps {
checkout scm
}
}
stage ('Run VFIO integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh "scripts/dev_cli.sh tests --integration-vfio"
}
}
stage ('Run VFIO integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh "scripts/dev_cli.sh tests --integration-vfio --libc musl"
}
}
}
post {
always {
sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
deleteDir()
}
}
}
stage ('Worker build - Windows guest') { stage ('Worker build - Windows guest') {
agent { node { label 'focal' } } agent { node { label 'focal' } }
when { when {
@@ -233,6 +328,39 @@ pipeline{
} }
} }
} }
stage ('Worker build - Metrics') {
agent { node { label 'focal-metrics' } }
when {
branch 'main'
beforeAgent true
expression {
return runWorkers
}
}
environment {
METRICS_PUBLISH_KEY = credentials('52e0945f-ce7a-43d1-87af-67d1d87cc40f')
}
stages {
stage ('Checkout') {
steps {
checkout scm
}
}
stage ('Run metrics tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --metrics -- -- --report-file /root/workloads/metrics.json'
}
}
stage ('Upload metrics report') {
steps {
sh 'curl -X PUT https://cloud-hypervisor-metrics.azurewebsites.net/api/publishmetrics -H "x-functions-key: $METRICS_PUBLISH_KEY" -T ~/workloads/metrics.json'
}
}
}
}
} }
} }
} }
@@ -287,3 +415,14 @@ 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

@@ -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.to_vec()); bytes.extend_from_slice(part.as_ref());
} }
} }
} }

View File

@@ -10,13 +10,13 @@ tdx = []
[dependencies] [dependencies]
acpi_tables = { path = "../acpi_tables" } acpi_tables = { path = "../acpi_tables" }
anyhow = "1.0.57" anyhow = "1.0.58"
byteorder = "1.4.3" byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
libc = "0.2.126" libc = "0.2.126"
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.17"
serde = { version = "1.0.137", features = ["rc", "derive"] } serde = { version = "1.0.138", features = ["rc", "derive"] }
thiserror = "1.0.31" thiserror = "1.0.31"
versionize = "0.1.6" versionize = "0.1.6"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"

View File

@@ -8,17 +8,18 @@
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,
@@ -90,7 +91,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: &dyn GicDevice, gic_device: &Arc<Mutex<dyn Vgic>>,
initrd: &Option<InitramfsConfig>, initrd: &Option<InitramfsConfig>,
pci_space_info: &[PciSpaceInfo], pci_space_info: &[PciSpaceInfo],
numa_nodes: &NumaNodes, numa_nodes: &NumaNodes,
@@ -315,18 +316,18 @@ fn create_chosen_node(
Ok(()) Ok(())
} }
fn create_gic_node(fdt: &mut FdtWriter, gic_device: &dyn GicDevice) -> FdtWriterResult<()> { fn create_gic_node(fdt: &mut FdtWriter, gic_device: &Arc<Mutex<dyn Vgic>>) -> FdtWriterResult<()> {
let gic_reg_prop = gic_device.device_properties(); let gic_reg_prop = gic_device.lock().unwrap().device_properties();
let intc_node = fdt.begin_node("intc")?; let intc_node = fdt.begin_node("intc")?;
fdt.property_string("compatible", gic_device.fdt_compatibility())?; fdt.property_string("compatible", gic_device.lock().unwrap().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)?;
@@ -334,18 +335,18 @@ fn create_gic_node(fdt: &mut FdtWriter, gic_device: &dyn GicDevice) -> FdtWriter
let gic_intr_prop = [ let gic_intr_prop = [
GIC_FDT_IRQ_TYPE_PPI, GIC_FDT_IRQ_TYPE_PPI,
gic_device.fdt_maint_irq(), gic_device.lock().unwrap().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.msi_compatible() { if gic_device.lock().unwrap().msi_compatible() {
let msic_node = fdt.begin_node("msic")?; let msic_node = fdt.begin_node("msic")?;
fdt.property_string("compatible", gic_device.msi_compatibility())?; fdt.property_string("compatible", gic_device.lock().unwrap().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.msi_properties(); let msi_reg_prop = gic_device.lock().unwrap().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,262 +0,0 @@
// 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

@@ -1,514 +0,0 @@
// 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,220 +0,0 @@
// 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

@@ -4,23 +4,19 @@
/// 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 gic::GicDevice; use hypervisor::arch::aarch64::gic::Vgic;
use log::{log_enabled, Level}; use log::{log_enabled, Level};
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryInto; use std::convert::TryInto;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc; use std::sync::{Arc, Mutex};
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.
@@ -33,13 +29,13 @@ pub enum Error {
WriteFdtToMemory(fdt::Error), WriteFdtToMemory(fdt::Error),
/// Failed to create a GIC. /// Failed to create a GIC.
SetupGic(gic::Error), SetupGic,
/// 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(regs::Error), RegsConfiguration(hypervisor::HypervisorCpuError),
/// Error configuring the MPIDR register /// Error configuring the MPIDR register
VcpuRegMpidr(hypervisor::HypervisorCpuError), VcpuRegMpidr(hypervisor::HypervisorCpuError),
@@ -69,8 +65,12 @@ pub fn configure_vcpu(
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 {
regs::setup_regs(vcpu, id, kernel_entry_point.entry_addr.raw_value()) vcpu.setup_regs(
.map_err(Error::RegsConfiguration)?; id,
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 = vcpu.read_mpidr().map_err(Error::VcpuRegMpidr)?;
@@ -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: &dyn GicDevice, gic_device: &Arc<Mutex<dyn Vgic>>,
numa_nodes: &NumaNodes, numa_nodes: &NumaNodes,
pmu_supported: bool, pmu_supported: bool,
) -> super::Result<()> { ) -> super::Result<()> {

View File

@@ -1,75 +0,0 @@
// 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

@@ -54,7 +54,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, Debug, Serialize, Deserialize, Versionize)] #[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize, Versionize)]
pub enum RegionType { pub enum RegionType {
/// RAM type /// RAM type
Ram, Ram,

View File

@@ -17,7 +17,7 @@ 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.3.0" virtio-queue = "0.4.0"
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-memory = { version = "0.8.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 + Sync { pub trait DiskFile: Send {
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 + Sync { pub trait AsyncIo: Send {
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)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RequestType { pub enum RequestType {
In, In,
Out, Out,

View File

@@ -6,11 +6,12 @@ edition = "2021"
[dependencies] [dependencies]
acpi_tables = { path = "../acpi_tables" } acpi_tables = { path = "../acpi_tables" }
anyhow = "1.0.57" anyhow = "1.0.58"
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.126" libc = "0.2.126"
log = "0.4.17" log = "0.4.17"
versionize = "0.1.6" versionize = "0.1.6"

View File

@@ -4,30 +4,34 @@
use super::interrupt_controller::{Error, InterruptController}; use super::interrupt_controller::{Error, InterruptController};
extern crate arch; extern crate arch;
use arch::aarch64::gic::GicDevice; use anyhow::anyhow;
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 device. // Reserve 32 IRQs for legacy devices.
pub const IRQ_LEGACY_BASE: usize = arch::layout::IRQ_BASE as usize; pub const IRQ_LEGACY_BASE: usize = layout::IRQ_BASE as usize;
pub const IRQ_LEGACY_COUNT: usize = 32; pub const IRQ_LEGACY_COUNT: usize = 32;
// This Gic struct implements InterruptController to provide interrupt delivery service. // Gic (Generic Interupt Controller) struct provides all the functionality of a
// The Gic source files in arch/ folder maintain the Aarch64 specific Gic device. // GIC device. It wraps a hypervisor-emulated GIC device (Vgic) provided by the
// The 2 Gic instances could be merged together. // `hypervisor` crate.
// Leave this refactoring to future. Two options may be considered: // Gic struct also implements InterruptController to provide interrupt delivery
// 1. Move Gic*.rs from arch/ folder here. // service.
// 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>,
gic_device: Option<Arc<Mutex<Box<dyn GicDevice>>>>, // The hypervisor agnostic virtual GIC
vgic: Option<Arc<Mutex<dyn Vgic>>>,
} }
impl Gic { impl Gic {
@@ -44,16 +48,32 @@ impl Gic {
Ok(Gic { Ok(Gic {
interrupt_source_group, interrupt_source_group,
gic_device: None, vgic: None,
}) })
} }
pub fn set_gic_device(&mut self, gic_device: Arc<Mutex<Box<dyn GicDevice>>>) { pub fn create_vgic(
self.gic_device = Some(gic_device); &mut self,
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 get_gic_device(&self) -> Option<&Arc<Mutex<Box<dyn GicDevice>>>> { pub fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
self.gic_device.as_ref() let vgic = self.vgic.as_ref().unwrap().clone();
vgic.lock().unwrap().set_gicr_typers(vcpu_states);
} }
} }
@@ -97,3 +117,43 @@ 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,6 +24,8 @@ 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

@@ -89,6 +89,7 @@ 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 | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: | | Serial port | :x: | :x: | :heavy_check_mark: |
| RTC/CMOS | :heavy_check_mark: | :heavy_check_mark: | :negative_squared_cross_mark: | | RTC/CMOS | :heavy_check_mark: | :heavy_check_mark: | :x: |
| I/O APIC | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: | | I/O APIC | :x: | :x: | :heavy_check_mark: |
| i8042 shutdown/reboot | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :negative_squared_cross_mark: | | i8042 shutdown/reboot | :x: | :x: | :x: |
| ACPI shutdown/reboot | :negative_squared_cross_mark: | :heavy_check_mark: | :negative_squared_cross_mark: | | ACPI shutdown/reboot | :x: | :heavy_check_mark: | :x: |
| virtio-blk | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: | | virtio-blk | :x: | :x: | :heavy_check_mark: |
| virtio-console | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: | | virtio-console | :x: | :x: | :heavy_check_mark: |
| virtio-iommu | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: | | virtio-iommu | :x: | :x: | :heavy_check_mark: |
| virtio-net | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: | | virtio-net | :x: | :x: | :heavy_check_mark: |
| virtio-pmem | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: | | virtio-pmem | :x: | :x: | :heavy_check_mark: |
| virtio-rng | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: | | virtio-rng | :x: | :x: | :heavy_check_mark: |
| virtio-vsock | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: | | virtio-vsock | :x: | :x: | :heavy_check_mark: |
| vhost-user-blk | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: | | vhost-user-blk | :x: | :x: | :heavy_check_mark: |
| vhost-user-fs | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: | | vhost-user-fs | :x: | :x: | :heavy_check_mark: |
| vhost-user-net | :negative_squared_cross_mark: | :negative_squared_cross_mark: | :heavy_check_mark: | | vhost-user-net | :x: | :x: | :heavy_check_mark: |
| VFIO | :heavy_check_mark: | :negative_squared_cross_mark: | :heavy_check_mark: | | VFIO | :heavy_check_mark: | :x: | :heavy_check_mark: |
## Legacy devices ## Legacy devices

View File

@@ -43,3 +43,22 @@ $ 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

@@ -6,5 +6,5 @@ edition = "2021"
[dependencies] [dependencies]
libc = "0.2.126" libc = "0.2.126"
serde = { version = "1.0.137", features = ["rc", "derive"] } serde = { version = "1.0.138", features = ["rc", "derive"] }
serde_json = "1.0.81" serde_json = "1.0.82"

130
fuzz/Cargo.lock generated
View File

@@ -11,9 +11,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.57" version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
[[package]] [[package]]
name = "api_client" name = "api_client"
@@ -24,9 +24,9 @@ dependencies = [
[[package]] [[package]]
name = "arbitrary" name = "arbitrary"
version = "1.1.0" version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c38b6b6b79f671c25e1a3e785b7b82d7562ffc9cd3efdc98627e5668a2472490" checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60"
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
@@ -127,15 +127,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.1.18" version = "3.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83"
dependencies = [ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
"clap_lex", "clap_lex",
"indexmap", "indexmap",
"lazy_static", "once_cell",
"strsim", "strsim",
"termcolor", "termcolor",
"terminal_size", "terminal_size",
@@ -144,16 +144,16 @@ dependencies = [
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.2.0" version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [ dependencies = [
"os_str_bytes", "os_str_bytes",
] ]
[[package]] [[package]]
name = "cloud-hypervisor" name = "cloud-hypervisor"
version = "23.0.0" version = "24.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"api_client", "api_client",
@@ -216,6 +216,7 @@ dependencies = [
"bitflags", "bitflags",
"byteorder", "byteorder",
"epoll", "epoll",
"hypervisor",
"libc", "libc",
"log", "log",
"versionize", "versionize",
@@ -251,35 +252,11 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e" checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
[[package]]
name = "gdbstub"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.6" version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@@ -288,9 +265,9 @@ dependencies = [
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.11.2" version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
@@ -331,9 +308,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.8.1" version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@@ -416,12 +393,6 @@ 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]] [[package]]
name = "micro_http" name = "micro_http"
version = "0.1.0" version = "0.1.0"
@@ -458,20 +429,11 @@ dependencies = [
"vmm-sys-util", "vmm-sys-util",
] ]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.12.0" version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
[[package]] [[package]]
name = "option_parser" name = "option_parser"
@@ -479,15 +441,9 @@ version = "0.1.0"
[[package]] [[package]]
name = "os_str_bytes" name = "os_str_bytes"
version = "6.0.1" version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435" checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
[[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"
@@ -514,9 +470,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.39" version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@@ -534,9 +490,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.18" version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -587,24 +543,24 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.9" version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.137" version = "1.0.138"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.137" version = "1.0.138"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -613,9 +569,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.81" version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@@ -655,9 +611,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.95" version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -714,15 +670,15 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.0" 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 = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.0.0" version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cfcd319456c4d6ea10087ed423473267e1a071f3bc0aa89f80d60997843c6f0" checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
dependencies = [ dependencies = [
"getrandom", "getrandom",
] ]
@@ -948,15 +904,13 @@ 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",
@@ -995,9 +949,9 @@ dependencies = [
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.10.2+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "winapi" name = "winapi"

View File

@@ -16,7 +16,7 @@ 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.3.0" virtio-queue = "0.4.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.8.0"

View File

@@ -11,7 +11,7 @@ mshv = ["mshv-ioctls", "mshv-bindings"]
tdx = [] tdx = []
[dependencies] [dependencies]
anyhow = "1.0.57" anyhow = "1.0.58"
epoll = "4.3.1" epoll = "4.3.1"
thiserror = "1.0.31" thiserror = "1.0.31"
libc = "0.2.126" libc = "0.2.126"
@@ -20,8 +20,8 @@ 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.137", features = ["rc", "derive"] } serde = { version = "1.0.138", features = ["rc", "derive"] }
serde_json = "1.0.81" serde_json = "1.0.82"
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic"] } vm-memory = { version = "0.8.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"] }

View File

@@ -0,0 +1,59 @@
// 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

@@ -0,0 +1,3 @@
// 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: Send + Sync { pub trait PlatformEmulator {
type CpuState: Clone; type CpuState: Clone;
/// Read guest memory into a u8 slice. /// Read guest memory into a u8 slice.

View File

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

View File

@@ -16,7 +16,7 @@ use iced_x86::*;
mod instructions; mod instructions;
/// x86 CPU modes /// x86 CPU modes
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Eq)]
pub enum CpuMode { pub enum CpuMode {
/// Real mode /// Real mode
Real, Real,

View File

@@ -453,6 +453,11 @@ 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

@@ -66,6 +66,11 @@ 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,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 super::{Error, Result}; use crate::arch::aarch64::gic::{Error, Result};
use crate::layout::IRQ_BASE; use crate::kvm::kvm_bindings::{
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,12 +77,7 @@ static VGIC_DIST_REGS: &[DistReg] = &[
VGIC_DIST_REG!(GICD_IPRIORITYR, 8, 0), VGIC_DIST_REG!(GICD_IPRIORITYR, 8, 0),
]; ];
fn dist_attr_access( fn dist_attr_access(gic: &Arc<dyn Device>, offset: u32, val: &u32, set: bool) -> Result<()> {
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,
@@ -100,18 +95,18 @@ fn dist_attr_access(
} }
/// Get the distributor control register. /// Get the distributor control register.
pub fn read_ctlr(gic: &Arc<dyn hypervisor::Device>) -> Result<u32> { pub fn read_ctlr(gic: &Arc<dyn 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 hypervisor::Device>, val: u32) -> Result<()> { pub fn write_ctlr(gic: &Arc<dyn 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 hypervisor::Device>) -> Result<u32> { fn get_interrupts_num(gic: &Arc<dyn 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 {
@@ -125,7 +120,12 @@ fn get_interrupts_num(gic: &Arc<dyn hypervisor::Device>) -> Result<u32> {
Ok(num_irq) Ok(num_irq)
} }
fn compute_reg_len(gic: &Arc<dyn hypervisor::Device>, reg: &DistReg, base: u32) -> Result<u32> { fn compute_reg_len(gic: &Arc<dyn 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 hypervisor::Device>, reg: &DistReg, base: u32)
// 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 - IRQ_BASE) / 8); end = base + (reg.bpi as u32 * (num_irq - LAYOUT_IRQ_BASE) / 8);
if reg.bpi as u32 * (num_irq - IRQ_BASE) % 8 > 0 { if reg.bpi as u32 * (num_irq - LAYOUT_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 hypervisor::Device>, reg: &DistReg, base: u32)
} }
/// Set distributor registers of the GIC. /// Set distributor registers of the GIC.
pub fn set_dist_regs(gic: &Arc<dyn hypervisor::Device>, state: &[u32]) -> Result<()> { pub fn set_dist_regs(gic: &Arc<dyn 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 hypervisor::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 hypervisor::Device>) -> Result<Vec<u32>> { pub fn get_dist_regs(gic: &Arc<dyn 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

@@ -1,13 +1,15 @@
// 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 super::{Error, Result}; use crate::arch::aarch64::gic::{Error, Result};
use hypervisor::kvm::kvm_bindings::{ use crate::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;
@@ -78,7 +80,7 @@ static VGIC_ICC_REGS: &[u64] = &[
]; ];
fn icc_attr_access( fn icc_attr_access(
gic: &Arc<dyn hypervisor::Device>, gic: &Arc<dyn Device>,
offset: u64, offset: u64,
typer: u64, typer: u64,
val: &u32, val: &u32,
@@ -101,7 +103,7 @@ fn icc_attr_access(
} }
/// Get ICC registers. /// Get ICC registers.
pub fn get_icc_regs(gic: &Arc<dyn hypervisor::Device>, gicr_typer: &[u64]) -> Result<Vec<u32>> { pub fn get_icc_regs(gic: &Arc<dyn 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;
@@ -154,11 +156,7 @@ pub fn get_icc_regs(gic: &Arc<dyn hypervisor::Device>, gicr_typer: &[u64]) -> Re
} }
/// Set ICC registers. /// Set ICC registers.
pub fn set_icc_regs( pub fn set_icc_regs(gic: &Arc<dyn Device>, gicr_typer: &[u64], state: &[u32]) -> Result<()> {
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 {

View File

@@ -0,0 +1,615 @@
// 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

@@ -1,9 +1,10 @@
// 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 super::{Error, Result}; use crate::arch::aarch64::gic::{Error, Result};
use hypervisor::kvm::kvm_bindings::{kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS}; use crate::kvm::kvm_bindings::{kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS};
use hypervisor::CpuState; use crate::{CpuState, Device};
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.
@@ -83,7 +84,7 @@ static VGIC_SGI_REGS: &[RdistReg] = &[
]; ];
fn redist_attr_access( fn redist_attr_access(
gic: &Arc<dyn hypervisor::Device>, gic: &Arc<dyn Device>,
offset: u32, offset: u32,
typer: u64, typer: u64,
val: &u32, val: &u32,
@@ -106,7 +107,7 @@ fn redist_attr_access(
} }
fn access_redists_aux( fn access_redists_aux(
gic: &Arc<dyn hypervisor::Device>, gic: &Arc<dyn Device>,
gicr_typer: &[u64], gicr_typer: &[u64],
state: &mut Vec<u32>, state: &mut Vec<u32>,
reg_list: &[RdistReg], reg_list: &[RdistReg],
@@ -136,7 +137,7 @@ fn access_redists_aux(
} }
/// Get redistributor registers. /// Get redistributor registers.
pub fn get_redist_regs(gic: &Arc<dyn hypervisor::Device>, gicr_typer: &[u64]) -> Result<Vec<u32>> { pub fn get_redist_regs(gic: &Arc<dyn 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(
@@ -153,11 +154,7 @@ pub fn get_redist_regs(gic: &Arc<dyn hypervisor::Device>, gicr_typer: &[u64]) ->
} }
/// Set redistributor registers. /// Set redistributor registers.
pub fn set_redist_regs( pub fn set_redist_regs(gic: &Arc<dyn Device>, gicr_typer: &[u64], state: &[u32]) -> Result<()> {
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

@@ -8,9 +8,8 @@
// //
// //
/// 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,

View File

@@ -8,11 +8,15 @@
// //
// //
#[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, is_system_register, VcpuInit, VcpuKvmState as CpuState, check_required_kvm_extensions, gic::Gicv3ItsState as GicState, is_system_register, VcpuInit,
MPIDR_EL1, VcpuKvmState as CpuState, 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;
@@ -31,6 +35,8 @@ 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
@@ -154,7 +160,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, Deserialize, Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct KvmVmState {} pub struct KvmVmState {}
pub use KvmVmState as VmState; pub use KvmVmState as VmState;
@@ -250,6 +256,31 @@ impl vm::Vm for KvmVm {
}; };
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.
/// ///
@@ -1535,6 +1566,51 @@ 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

@@ -18,6 +18,8 @@
//! - 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")]
@@ -51,10 +53,10 @@ mod device;
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}; pub use hypervisor::{Hypervisor, HypervisorError};
#[cfg(all(feature = "kvm", target_arch = "aarch64"))]
pub use kvm::aarch64;
#[cfg(all(feature = "kvm", target_arch = "x86_64"))] #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
pub use kvm::x86_64; pub use kvm::x86_64;
#[cfg(all(feature = "kvm", target_arch = "aarch64"))]
pub use kvm::{aarch64, GicState};
// Aliased types exposed from both hypervisors // Aliased types exposed from both hypervisors
#[cfg(feature = "kvm")] #[cfg(feature = "kvm")]
pub use kvm::{ pub use kvm::{

View File

@@ -108,6 +108,17 @@ 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();

View File

@@ -10,6 +10,8 @@
#[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")] #[cfg(feature = "kvm")]
@@ -27,6 +29,8 @@ 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;
@@ -210,6 +214,11 @@ 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
@@ -269,6 +278,17 @@ pub trait Vm: Send + Sync {
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, vm_ops: Option<Arc<dyn VmOps>>) -> 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,

View File

@@ -11,16 +11,17 @@ libc = "0.2.126"
log = "0.4.17" log = "0.4.17"
net_gen = { path = "../net_gen" } net_gen = { path = "../net_gen" }
rate_limiter = { path = "../rate_limiter" } rate_limiter = { path = "../rate_limiter" }
serde = "1.0.137" serde = "1.0.138"
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.3.0" virtio-queue = "0.4.0"
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-memory = { version = "0.8.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]
lazy_static = "1.4.0" once_cell = "1.13.0"
pnet = "0.30.0" pnet = "0.31.0"
serde_json = "1.0.81" pnet_datalink = "0.31.0"
serde_json = "1.0.82"

View File

@@ -5,11 +5,6 @@
// 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)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MacAddr { pub struct MacAddr {
bytes: [u8; MAC_ADDR_LEN], bytes: [u8; MAC_ADDR_LEN],
} }

View File

@@ -321,15 +321,13 @@ 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 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 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 = ifreq.ifr_ifru.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;
// 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 =
@@ -395,38 +393,35 @@ 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 self::pnet::datalink::Channel::Ethernet; use once_cell::sync::Lazy;
use self::pnet::datalink::{self, DataLinkReceiver, DataLinkSender, NetworkInterface};
use self::pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket}; use pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket};
use self::pnet::packet::ip::IpNextHeaderProtocols; use pnet::packet::ip::IpNextHeaderProtocols;
use self::pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet}; use pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet};
use self::pnet::packet::udp::{MutableUdpPacket, UdpPacket}; use pnet::packet::udp::{MutableUdpPacket, UdpPacket};
use self::pnet::packet::{MutablePacket, Packet}; use pnet::packet::{MutablePacket, Packet};
use self::pnet::util::MacAddr; use 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 the crate that provides the // We needed to have a mutex as a global variable, so we used once_cell for testing. The main
// lazy_static! macro for testing. The main potential problem, caused by tests being run in // potential problem, caused by tests being run in parallel by cargo, is creating different
// parallel by cargo, is creating different TAPs and trying to associate the same address, // TAPs and trying to associate the same address, so we hide the IP address &str behind this
// so we hide the IP address &str behind this mutex, more as a convention to remember to lock // mutex, more as a convention to remember to lock it at the very beginning of each function
// it at the very beginning of each function susceptible to this issue. Another variant is // susceptible to this issue. Another variant is to use a different IP address per function,
// to use a different IP address per function, but we must remember to pick an unique one // but we must remember to pick an unique one each time.
// each time. static TAP_IP_LOCK: Lazy<Mutex<&'static str>> = Lazy::new(|| Mutex::new("192.168.241.1"));
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).
@@ -543,10 +538,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 = datalink::interfaces(); let interfaces = pnet_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)) = datalink::channel(&interface, Default::default()) { if let Ok(Ethernet(tx, rx)) = pnet_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

@@ -10,7 +10,7 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"] mshv = ["vfio-ioctls/mshv"]
[dependencies] [dependencies]
anyhow = "1.0.57" anyhow = "1.0.58"
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 }
@@ -18,7 +18,7 @@ vfio_user = { path = "../vfio_user" }
vmm-sys-util = "0.9.0" vmm-sys-util = "0.9.0"
libc = "0.2.126" libc = "0.2.126"
log = "0.4.17" log = "0.4.17"
serde = { version="1.0.137", features=["derive"] } serde = { version="1.0.138", features=["derive"] }
thiserror = "1.0.31" thiserror = "1.0.31"
versionize = "0.1.6" versionize = "0.1.6"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"

View File

@@ -187,7 +187,7 @@ pub trait PciProgrammingInterface {
} }
/// Types of PCI capabilities. /// Types of PCI capabilities.
#[derive(PartialEq, Copy, Clone)] #[derive(PartialEq, Eq, Copy, Clone)]
#[allow(dead_code)] #[allow(dead_code)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[repr(C)] #[repr(C)]
@@ -321,7 +321,7 @@ pub struct PciConfiguration {
} }
/// See pci_regs.h in kernel /// See pci_regs.h in kernel
#[derive(Copy, Clone, PartialEq, Versionize, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Versionize, Debug)]
pub enum PciBarRegionType { pub enum PciBarRegionType {
Memory32BitRegion = 0, Memory32BitRegion = 0,
IoRegion = 0x01, IoRegion = 0x01,

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, PartialOrd)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd)]
pub struct PciBdf(u32); pub struct PciBdf(u32);
struct PciBdfVisitor; struct PciBdfVisitor;

View File

@@ -179,7 +179,7 @@ struct MsiConfigState {
impl VersionMapped for MsiConfigState {} impl VersionMapped for MsiConfigState {}
pub struct MsiConfig { pub struct MsiConfig {
cap: MsiCap, pub cap: MsiCap,
interrupt_source_group: Arc<dyn InterruptSourceGroup>, interrupt_source_group: Arc<dyn InterruptSourceGroup>,
} }

View File

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

View File

@@ -4,10 +4,11 @@
// //
use crate::{ use crate::{
msi_num_enabled_vectors, BarReprogrammingParams, MsiConfig, MsixCap, MsixConfig, msi_num_enabled_vectors, BarReprogrammingParams, MsiCap, MsiConfig, MsixCap, MsixConfig,
PciBarConfiguration, PciBarRegionType, PciBdf, PciCapabilityId, PciClassCode, PciConfiguration, PciBarConfiguration, PciBarRegionType, PciBdf, PciCapabilityId, PciClassCode, PciConfiguration,
PciDevice, PciDeviceError, PciHeaderType, PciSubclass, MSIX_TABLE_ENTRY_SIZE, PciDevice, PciDeviceError, PciHeaderType, PciSubclass, MSIX_TABLE_ENTRY_SIZE,
}; };
use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use hypervisor::HypervisorVmError; use hypervisor::HypervisorVmError;
use std::any::Any; use std::any::Any;
@@ -17,6 +18,8 @@ use std::os::unix::io::AsRawFd;
use std::ptr::null_mut; use std::ptr::null_mut;
use std::sync::{Arc, Barrier, Mutex}; use std::sync::{Arc, Barrier, Mutex};
use thiserror::Error; use thiserror::Error;
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vfio_bindings::bindings::vfio::*; use vfio_bindings::bindings::vfio::*;
use vfio_ioctls::{ use vfio_ioctls::{
VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap, VfioRegionSparseMmapArea, VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap, VfioRegionSparseMmapArea,
@@ -27,6 +30,9 @@ use vm_device::interrupt::{
}; };
use vm_device::{BusDevice, Resource}; use vm_device::{BusDevice, Resource};
use vm_memory::{Address, GuestAddress, GuestUsize}; use vm_memory::{Address, GuestAddress, GuestUsize};
use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
#[derive(Debug, Error)] #[derive(Debug, Error)]
@@ -71,11 +77,22 @@ enum InterruptUpdateAction {
DisableMsix, DisableMsix,
} }
#[derive(Versionize)]
struct IntxState {
enabled: bool,
}
pub(crate) struct VfioIntx { pub(crate) struct VfioIntx {
interrupt_source_group: Arc<dyn InterruptSourceGroup>, interrupt_source_group: Arc<dyn InterruptSourceGroup>,
enabled: bool, enabled: bool,
} }
#[derive(Versionize)]
struct MsiState {
cap: MsiCap,
cap_offset: u32,
}
pub(crate) struct VfioMsi { pub(crate) struct VfioMsi {
pub(crate) cfg: MsiConfig, pub(crate) cfg: MsiConfig,
cap_offset: u32, cap_offset: u32,
@@ -102,6 +119,13 @@ impl VfioMsi {
} }
} }
#[derive(Versionize)]
struct MsixState {
cap: MsixCap,
cap_offset: u32,
bdf: u32,
}
pub(crate) struct VfioMsix { pub(crate) struct VfioMsix {
pub(crate) bar: MsixConfig, pub(crate) bar: MsixConfig,
cap: MsixCap, cap: MsixCap,
@@ -356,6 +380,15 @@ impl Vfio for VfioDeviceWrapper {
} }
} }
#[derive(Versionize)]
struct VfioCommonState {
intx_state: Option<IntxState>,
msi_state: Option<MsiState>,
msix_state: Option<MsixState>,
}
impl VersionMapped for VfioCommonState {}
pub(crate) struct VfioCommon { pub(crate) struct VfioCommon {
pub(crate) configuration: PciConfiguration, pub(crate) configuration: PciConfiguration,
pub(crate) mmio_regions: Vec<MmioRegion>, pub(crate) mmio_regions: Vec<MmioRegion>,
@@ -970,6 +1003,127 @@ impl VfioCommon {
// The config register read comes from the VFIO device itself. // The config register read comes from the VFIO device itself.
self.vfio_wrapper.read_config_dword((reg_idx * 4) as u32) & mask self.vfio_wrapper.read_config_dword((reg_idx * 4) as u32) & mask
} }
fn state(&self) -> VfioCommonState {
let intx_state = self.interrupt.intx.as_ref().map(|intx| IntxState {
enabled: intx.enabled,
});
let msi_state = self.interrupt.msi.as_ref().map(|msi| MsiState {
cap: msi.cfg.cap,
cap_offset: msi.cap_offset,
});
let msix_state = self.interrupt.msix.as_ref().map(|msix| MsixState {
cap: msix.cap,
cap_offset: msix.cap_offset,
bdf: msix.bar.devid,
});
VfioCommonState {
intx_state,
msi_state,
msix_state,
}
}
fn set_state(&mut self, state: &VfioCommonState) -> Result<(), VfioPciError> {
if let (Some(intx), Some(interrupt_source_group)) =
(&state.intx_state, self.legacy_interrupt_group.clone())
{
self.interrupt.intx = Some(VfioIntx {
interrupt_source_group,
enabled: false,
});
if intx.enabled {
self.enable_intx()?;
}
}
if let Some(msi) = &state.msi_state {
self.initialize_msi(msi.cap.msg_ctl, msi.cap_offset);
}
if let Some(msix) = &state.msix_state {
self.initialize_msix(msix.cap, msix.cap_offset, msix.bdf.into());
}
Ok(())
}
}
impl Pausable for VfioCommon {}
impl Snapshottable for VfioCommon {
fn id(&self) -> String {
String::from("vfio_common")
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let mut vfio_common_snapshot =
Snapshot::new_from_versioned_state(&self.id(), &self.state())?;
// Snapshot PciConfiguration
vfio_common_snapshot.add_snapshot(self.configuration.snapshot()?);
// Snapshot MSI
if let Some(msi) = &mut self.interrupt.msi {
vfio_common_snapshot.add_snapshot(msi.cfg.snapshot()?);
}
// Snapshot MSI-X
if let Some(msix) = &mut self.interrupt.msix {
vfio_common_snapshot.add_snapshot(msix.bar.snapshot()?);
}
Ok(vfio_common_snapshot)
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
if let Some(vfio_common_section) = snapshot
.snapshot_data
.get(&format!("{}-section", self.id()))
{
// It has to be invoked first as we want Interrupt to be initialized
// correctly before we try to restore MSI and MSI-X configurations.
self.set_state(&vfio_common_section.to_versioned_state()?)
.map_err(|e| {
MigratableError::Restore(anyhow!("Could not restore VFIO_COMMON state {:?}", e))
})?;
// Restore PciConfiguration
if let Some(pci_config_snapshot) = snapshot.snapshots.get(&self.configuration.id()) {
self.configuration.restore(*pci_config_snapshot.clone())?;
}
// Restore MSI
if let Some(msi) = &mut self.interrupt.msi {
if let Some(msi_snapshot) = snapshot.snapshots.get(&msi.cfg.id()) {
msi.cfg.restore(*msi_snapshot.clone())?;
}
if msi.cfg.enabled() {
self.enable_msi().unwrap();
}
}
// Restore MSI-X
if let Some(msix) = &mut self.interrupt.msix {
if let Some(msix_snapshot) = snapshot.snapshots.get(&msix.bar.id()) {
msix.bar.restore(*msix_snapshot.clone())?;
}
if msix.bar.enabled() {
self.enable_msix().unwrap();
}
}
return Ok(());
}
Err(MigratableError::Restore(anyhow!(
"Could not find VFIO_COMMON snapshot section"
)))
}
} }
/// VfioPciDevice represents a VFIO PCI device. /// VfioPciDevice represents a VFIO PCI device.
@@ -985,6 +1139,7 @@ pub struct VfioPciDevice {
container: Arc<VfioContainer>, container: Arc<VfioContainer>,
common: VfioCommon, common: VfioCommon,
iommu_attached: bool, iommu_attached: bool,
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
} }
impl VfioPciDevice { impl VfioPciDevice {
@@ -999,6 +1154,8 @@ impl VfioPciDevice {
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>, legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
iommu_attached: bool, iommu_attached: bool,
bdf: PciBdf, bdf: PciBdf,
restoring: bool,
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
) -> Result<Self, VfioPciError> { ) -> Result<Self, VfioPciError> {
let device = Arc::new(device); let device = Arc::new(device);
device.reset(); device.reset();
@@ -1031,8 +1188,13 @@ impl VfioPciDevice {
vfio_wrapper: Arc::new(vfio_wrapper) as Arc<dyn Vfio>, vfio_wrapper: Arc::new(vfio_wrapper) as Arc<dyn Vfio>,
}; };
common.parse_capabilities(bdf); // No need to parse capabilities from the device if on the restore path.
common.initialize_legacy_interrupt()?; // The initialization will be performed later when restore() will be
// called.
if !restoring {
common.parse_capabilities(bdf);
common.initialize_legacy_interrupt()?;
}
let vfio_pci_device = VfioPciDevice { let vfio_pci_device = VfioPciDevice {
id, id,
@@ -1041,6 +1203,7 @@ impl VfioPciDevice {
container, container,
common, common,
iommu_attached, iommu_attached,
memory_slot,
}; };
Ok(vfio_pci_device) Ok(vfio_pci_device)
@@ -1150,14 +1313,7 @@ impl VfioPciDevice {
/// * `vm` - The VM object. It is used to set the VFIO MMIO regions /// * `vm` - The VM object. It is used to set the VFIO MMIO regions
/// as user memory regions. /// as user memory regions.
/// * `mem_slot` - The closure to return a memory slot. /// * `mem_slot` - The closure to return a memory slot.
pub fn map_mmio_regions<F>( pub fn map_mmio_regions(&mut self) -> Result<(), VfioPciError> {
&mut self,
vm: &Arc<dyn hypervisor::Vm>,
mem_slot: F,
) -> Result<(), VfioPciError>
where
F: Fn() -> u32,
{
let fd = self.device.as_raw_fd(); let fd = self.device.as_raw_fd();
for region in self.common.mmio_regions.iter_mut() { for region in self.common.mmio_regions.iter_mut() {
@@ -1223,7 +1379,7 @@ impl VfioPciDevice {
} }
let user_memory_region = UserMemoryRegion { let user_memory_region = UserMemoryRegion {
slot: mem_slot(), slot: (self.memory_slot)(),
start: region.start.0 + area.offset, start: region.start.0 + area.offset,
size: area.size, size: area.size,
host_addr: host_addr as u64, host_addr: host_addr as u64,
@@ -1231,7 +1387,7 @@ impl VfioPciDevice {
region.user_memory_regions.push(user_memory_region); region.user_memory_regions.push(user_memory_region);
let mem_region = vm.make_user_memory_region( let mem_region = self.vm.make_user_memory_region(
user_memory_region.slot, user_memory_region.slot,
user_memory_region.start, user_memory_region.start,
user_memory_region.size, user_memory_region.size,
@@ -1240,7 +1396,8 @@ impl VfioPciDevice {
false, false,
); );
vm.create_user_memory_region(mem_region) self.vm
.create_user_memory_region(mem_region)
.map_err(VfioPciError::CreateUserMemoryRegion)?; .map_err(VfioPciError::CreateUserMemoryRegion)?;
} }
} }
@@ -1464,3 +1621,37 @@ impl PciDevice for VfioPciDevice {
Some(self.id.clone()) Some(self.id.clone())
} }
} }
impl Pausable for VfioPciDevice {}
impl Snapshottable for VfioPciDevice {
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 VfioPciDevice on restore {:?}",
e
))
})?;
}
Ok(())
}
}
impl Transportable for VfioPciDevice {}
impl Migratable for VfioPciDevice {}

View File

@@ -8,6 +8,7 @@ use crate::{BarReprogrammingParams, PciBarConfiguration, 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;
@@ -26,6 +27,7 @@ use vm_memory::bitmap::AtomicBitmap;
use vm_memory::{ use vm_memory::{
Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryRegion, GuestRegionMmap, Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryRegion, GuestRegionMmap,
}; };
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 {
@@ -33,6 +35,7 @@ pub struct VfioUserPciDevice {
vm: Arc<dyn hypervisor::Vm>, vm: Arc<dyn hypervisor::Vm>,
client: Arc<Mutex<Client>>, client: Arc<Mutex<Client>>,
common: VfioCommon, common: VfioCommon,
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]
@@ -61,6 +64,7 @@ impl PciSubclass for PciVfioUserSubclass {
} }
impl VfioUserPciDevice { impl VfioUserPciDevice {
#[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
id: String, id: String,
vm: &Arc<dyn hypervisor::Vm>, vm: &Arc<dyn hypervisor::Vm>,
@@ -68,6 +72,8 @@ impl VfioUserPciDevice {
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(
@@ -108,27 +114,26 @@ impl VfioUserPciDevice {
vfio_wrapper: Arc::new(vfio_wrapper) as Arc<dyn Vfio>, vfio_wrapper: Arc::new(vfio_wrapper) as Arc<dyn Vfio>,
}; };
common.parse_capabilities(bdf); // No need to parse capabilities from the device if on the restore path.
common // The initialization will be performed later when restore() will be
.initialize_legacy_interrupt() // called.
.map_err(VfioUserPciDeviceError::InitializeLegacyInterrupts)?; if !restoring {
common.parse_capabilities(bdf);
common
.initialize_legacy_interrupt()
.map_err(VfioUserPciDeviceError::InitializeLegacyInterrupts)?;
}
Ok(Self { Ok(Self {
id, id,
vm: vm.clone(), vm: vm.clone(),
client, client,
common, common,
memory_slot,
}) })
} }
pub fn map_mmio_regions<F>( pub fn map_mmio_regions(&mut self) -> Result<(), VfioUserPciDeviceError> {
&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
@@ -195,7 +200,7 @@ impl VfioUserPciDevice {
} }
let user_memory_region = UserMemoryRegion { let user_memory_region = UserMemoryRegion {
slot: mem_slot(), slot: (self.memory_slot)(),
start: mmio_region.start.0 + s.offset, start: mmio_region.start.0 + s.offset,
size: s.size, size: s.size,
host_addr: host_addr as u64, host_addr: host_addr as u64,
@@ -203,7 +208,7 @@ impl VfioUserPciDevice {
mmio_region.user_memory_regions.push(user_memory_region); mmio_region.user_memory_regions.push(user_memory_region);
let mem_region = vm.make_user_memory_region( let mem_region = self.vm.make_user_memory_region(
user_memory_region.slot, user_memory_region.slot,
user_memory_region.start, user_memory_region.start,
user_memory_region.size, user_memory_region.size,
@@ -212,7 +217,8 @@ impl VfioUserPciDevice {
false, false,
); );
vm.create_user_memory_region(mem_region) self.vm
.create_user_memory_region(mem_region)
.map_err(VfioUserPciDeviceError::MapRegionGuest)?; .map_err(VfioUserPciDeviceError::MapRegionGuest)?;
} }
} }
@@ -551,6 +557,40 @@ 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>,
@@ -584,10 +624,10 @@ impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioUserDmaMappi
) )
}) })
} else { } else {
return Err(std::io::Error::new( 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,13 @@ edition = "2021"
build = "build.rs" build = "build.rs"
[dependencies] [dependencies]
clap = { version = "3.1.18", features = ["wrap_help","cargo"] } clap = { version = "3.2.8", features = ["wrap_help","cargo"] }
dirs = "4.0.0" dirs = "4.0.0"
serde = { version = "1.0.137", features = ["rc", "derive"] } serde = { version = "1.0.138", features = ["rc", "derive"] }
serde_json = "1.0.81" serde_json = "1.0.82"
test_infra = { path = "../test_infra" } test_infra = { path = "../test_infra" }
thiserror = "1.0.31" thiserror = "1.0.31"
wait-timeout = "0.2.0" wait-timeout = "0.2.0"
[build-dependencies] [build-dependencies]
clap = { version = "3.1.18", features = ["cargo"] } clap = { version = "3.2.8", features = ["cargo"] }

View File

@@ -53,18 +53,30 @@ 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() {
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) { git_human_readable = String::from_utf8(git_out.stdout)
git_human_readable = git_out_str.trim().to_string(); .unwrap()
} .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() {
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) { git_revision = String::from_utf8(git_out.stdout)
git_revision = git_out_str.trim().to_string(); .unwrap()
} .trim()
.to_string();
} else {
eprintln!(
"Error generating git reference: {}",
String::from_utf8(git_out.stderr).unwrap()
);
} }
} }
@@ -74,9 +86,15 @@ impl Default for MetricsReport {
.output() .output()
{ {
if git_out.status.success() { if git_out.status.success() {
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) { git_commit_date = String::from_utf8(git_out.stdout)
git_commit_date = git_out_str.trim().to_string(); .unwrap()
} .trim()
.to_string();
} else {
eprintln!(
"Error generating git commit date: {}",
String::from_utf8(git_out.stderr).unwrap()
);
} }
} }

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)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct TokenBucket { pub struct TokenBucket {
// Bucket defining traits. // Bucket defining traits.
size: u64, size: u64,

View File

@@ -1,22 +1,28 @@
- [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) - [v24.0](#v240)
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu) - [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness) - [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
- [Sparse Mmap support](#sparse-mmap-support) - [Sparse Mmap support](#sparse-mmap-support)
- [Expose Platform Serial Number](#expose-platform-serial-number) - [Expose Platform Serial Number](#expose-platform-serial-number)
- [Notable Bug Fixes](#notable-bug-fixes) - [Notable Bug Fixes](#notable-bug-fixes-1)
- [Notable Improvements](#notable-improvements) - [Notable Improvements](#notable-improvements)
- [Deprecations](#deprecations) - [Deprecations](#deprecations)
- [New on the Website](#new-on-the-website) - [New on the Website](#new-on-the-website)
- [Contributors](#contributors) - [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-1) - [Notable Bug Fixes](#notable-bug-fixes-2)
- [Deprecations](#deprecations-1) - [Deprecations](#deprecations-1)
- [Contributors](#contributors-1) - [Contributors](#contributors-2)
- [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)
@@ -27,13 +33,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-2) - [Notable Bug Fixes](#notable-bug-fixes-3)
- [Contributors](#contributors-2) - [Contributors](#contributors-3)
- [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-3) - [Notable Bug fixes](#notable-bug-fixes-4)
- [Contributors](#contributors-3) - [Contributors](#contributors-4)
- [v20.2](#v202) - [v20.2](#v202)
- [v20.1](#v201) - [v20.1](#v201)
- [v20.0](#v200) - [v20.0](#v200)
@@ -42,8 +48,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-4) - [Notable bug fixes](#notable-bug-fixes-5)
- [Contributors](#contributors-4) - [Contributors](#contributors-5)
- [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)
@@ -51,8 +57,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-5) - [Notable bug fixes](#notable-bug-fixes-6)
- [Contributors](#contributors-5) - [Contributors](#contributors-6)
- [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)
@@ -62,23 +68,23 @@
- [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-6) - [Notable bug fixes](#notable-bug-fixes-7)
- [Contributors](#contributors-6) - [Contributors](#contributors-7)
- [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-7) - [Notable bug fixes](#notable-bug-fixes-8)
- [Contributors](#contributors-7) - [Contributors](#contributors-8)
- [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-8) - [Notable bug fixes](#notable-bug-fixes-9)
- [Removed functionality](#removed-functionality) - [Removed functionality](#removed-functionality)
- [Contributors](#contributors-8) - [Contributors](#contributors-9)
- [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)
@@ -86,7 +92,7 @@
- [`--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-2)
- [Contributors](#contributors-9) - [Contributors](#contributors-10)
- [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)
@@ -96,7 +102,7 @@
- [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-3)
- [Contributors](#contributors-10) - [Contributors](#contributors-11)
- [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)
@@ -104,13 +110,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-11) - [Contributors](#contributors-12)
- [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-12) - [Contributors](#contributors-13)
- [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)
@@ -122,15 +128,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-9) - [Notable Bug Fixes](#notable-bug-fixes-10)
- [Contributors](#contributors-13) - [Contributors](#contributors-14)
- [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-10) - [Notable Bug Fixes](#notable-bug-fixes-11)
- [Contributors](#contributors-14) - [Contributors](#contributors-15)
- [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)
@@ -143,17 +149,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-11) - [Notable Bug Fixes](#notable-bug-fixes-12)
- [Contributors](#contributors-15) - [Contributors](#contributors-16)
- [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-12) - [Notable Bug Fixes](#notable-bug-fixes-13)
- [Command Line and API Changes](#command-line-and-api-changes) - [Command Line and API Changes](#command-line-and-api-changes)
- [Contributors](#contributors-16) - [Contributors](#contributors-17)
- [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)
@@ -163,14 +169,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-17) - [Contributors](#contributors-18)
- [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-18) - [Contributors](#contributors-19)
- [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)
@@ -178,7 +184,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-19) - [Contributors](#contributors-20)
- [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)
@@ -187,7 +193,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-20) - [Contributors](#contributors-21)
- [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)
@@ -214,6 +220,52 @@
- [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 # v24.0
This release has been tracked through the [v24.0 This release has been tracked through the [v24.0

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.60.0" ARG RUST_TOOLCHAIN="1.62.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

@@ -11,7 +11,7 @@
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: 24.0 Version: 25.0
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
@@ -145,6 +145,9 @@ rm -rf %{buildroot}
%changelog %changelog
* Thu Jul 07 2022 Rob Bradford <robert.bradford@intel.com> 25.0-0
- Update to 25.0
* Wed May 25 2022 Sebastien Boeuf <sebastien.boeuf@intel.com> 24.0-0 * Wed May 25 2022 Sebastien Boeuf <sebastien.boeuf@intel.com> 24.0-0
- Update to 24.0 - Update to 24.0

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="20220524-0" CTR_IMAGE_VERSION="20220705-0"
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}" CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
DOCKER_RUNTIME="docker" DOCKER_RUNTIME="docker"

View File

@@ -113,6 +113,9 @@ 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

@@ -12,6 +12,7 @@ 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;
@@ -31,6 +32,8 @@ 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 {
@@ -51,6 +54,8 @@ 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),
} }
} }
} }
@@ -264,6 +269,20 @@ 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(),
@@ -295,6 +314,19 @@ 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)?;
@@ -422,6 +454,14 @@ 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
@@ -442,6 +482,14 @@ 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!(),
} }
@@ -576,6 +624,8 @@ 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")
@@ -595,6 +645,11 @@ 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")
@@ -617,6 +672,11 @@ 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,6 +23,7 @@ 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 {
@@ -623,6 +624,13 @@ 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);
} }
@@ -1323,40 +1331,6 @@ 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"
lazy_static = "1.4.0"
libc = "0.2.126" libc = "0.2.126"
once_cell = "1.13.0"
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,9 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
#[macro_use] use once_cell::sync::Lazy;
extern crate lazy_static;
use ssh2::Session; use ssh2::Session;
use std::env; use std::env;
use std::ffi::OsStr; use std::ffi::OsStr;
@@ -52,7 +50,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 = 80; pub const DEFAULT_TCP_LISTENER_TIMEOUT: i32 = 120;
#[derive(Debug)] #[derive(Debug)]
pub enum WaitForBootError { pub enum WaitForBootError {
@@ -722,9 +720,7 @@ pub fn exec_host_command_output(command: &str) -> Output {
pub const PIPE_SIZE: i32 = 32 << 20; pub const PIPE_SIZE: i32 = 32 << 20;
lazy_static! { static NEXT_VM_ID: Lazy<Mutex<u8>> = Lazy::new(|| Mutex::new(1));
static ref NEXT_VM_ID: Mutex<u8> = Mutex::new(1);
}
pub struct Guest { pub struct Guest {
pub tmp_dir: TempDir, pub tmp_dir: TempDir,
@@ -832,30 +828,12 @@ impl Guest {
) )
} }
pub fn api_create_body( pub fn api_create_body(&self, cpu_count: u8, kernel_path: &str, kernel_cmd: &str) -> String {
&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(),
@@ -985,13 +963,6 @@ 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")?
@@ -1037,50 +1008,6 @@ 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>

View File

@@ -8,10 +8,6 @@
// related warnings for our quality workflow to pass. // related warnings for our quality workflow to pass.
#![allow(dead_code)] #![allow(dead_code)]
#[cfg(target_arch = "x86_64")]
#[macro_use]
extern crate lazy_static;
extern crate test_infra; extern crate test_infra;
use net_util::MacAddr; use net_util::MacAddr;
@@ -75,11 +71,7 @@ const DIRECT_KERNEL_BOOT_CMDLINE: &str =
const CONSOLE_TEST_STRING: &str = "Started OpenBSD Secure Shell server"; const CONSOLE_TEST_STRING: &str = "Started OpenBSD Secure Shell server";
fn prepare_virtiofsd( fn prepare_virtiofsd(tmp_dir: &TempDir, shared_dir: &str) -> (std::process::Child, String) {
tmp_dir: &TempDir,
shared_dir: &str,
cache: &str,
) -> (std::process::Child, String) {
let mut workload_path = dirs::home_dir().unwrap(); let mut workload_path = dirs::home_dir().unwrap();
workload_path.push("workloads"); workload_path.push("workloads");
@@ -94,7 +86,7 @@ fn prepare_virtiofsd(
let child = Command::new(virtiofsd_path.as_str()) let child = Command::new(virtiofsd_path.as_str())
.args(&["--shared-dir", shared_dir]) .args(&["--shared-dir", shared_dir])
.args(&["--socket-path", virtiofsd_socket_path.as_str()]) .args(&["--socket-path", virtiofsd_socket_path.as_str()])
.args(&["--cache", cache]) .args(&["--cache", "never"])
.spawn() .spawn()
.unwrap(); .unwrap();
@@ -162,6 +154,11 @@ fn temp_snapshot_dir_path(tmp_dir: &TempDir) -> String {
snapshot_dir snapshot_dir
} }
fn temp_vmcore_file_path(tmp_dir: &TempDir) -> String {
let vmcore_file = String::from(tmp_dir.as_path().join("vmcore").to_str().unwrap());
vmcore_file
}
// Creates the path for direct kernel boot and return the path. // Creates the path for direct kernel boot and return the path.
// For x86_64, this function returns the vmlinux kernel path. // For x86_64, this function returns the vmlinux kernel path.
// For AArch64, this function returns the PE kernel path. // For AArch64, this function returns the PE kernel path.
@@ -256,8 +253,15 @@ fn remote_command(api_socket: &str, command: &str, arg: Option<&str>) -> bool {
if let Some(arg) = arg { if let Some(arg) = arg {
cmd.arg(arg); cmd.arg(arg);
} }
let output = cmd.output().unwrap();
cmd.status().expect("Failed to launch ch-remote").success() if output.status.success() {
true
} else {
eprintln!("Error running ch-remote command: {:?}", &cmd);
let stderr = String::from_utf8_lossy(&output.stderr);
eprintln!("stderr: {}", stderr);
false
}
} }
fn remote_command_w_output(api_socket: &str, command: &str, arg: Option<&str>) -> (bool, Vec<u8>) { fn remote_command_w_output(api_socket: &str, command: &str, arg: Option<&str>) -> (bool, Vec<u8>) {
@@ -1126,11 +1130,8 @@ fn test_boot_from_vhost_user_blk(
handle_child_output(r, &output); handle_child_output(r, &output);
} }
fn test_virtio_fs( fn _test_virtio_fs(
dax: bool, prepare_daemon: &dyn Fn(&TempDir, &str) -> (std::process::Child, String),
cache_size: Option<u64>,
virtiofsd_cache: &str,
prepare_daemon: &dyn Fn(&TempDir, &str, &str) -> (std::process::Child, String),
hotplug: bool, hotplug: bool,
pci_segment: Option<u16>, pci_segment: Option<u16>,
) { ) {
@@ -1161,18 +1162,8 @@ fn test_virtio_fs(
direct_kernel_boot_path() direct_kernel_boot_path()
}; };
let (dax_vmm_param, dax_mount_param) = if dax { ("on", "-o dax") } else { ("off", "") }; let (mut daemon_child, virtiofsd_socket_path) =
let cache_size_vmm_param = if let Some(cache) = cache_size { prepare_daemon(&guest.tmp_dir, shared_dir.to_str().unwrap());
format!(",cache_size={}", cache)
} else {
"".to_string()
};
let (mut daemon_child, virtiofsd_socket_path) = prepare_daemon(
&guest.tmp_dir,
shared_dir.to_str().unwrap(),
virtiofsd_cache,
);
let mut guest_command = GuestCommand::new(&guest); let mut guest_command = GuestCommand::new(&guest);
guest_command guest_command
@@ -1188,10 +1179,8 @@ fn test_virtio_fs(
} }
let fs_params = format!( let fs_params = format!(
"id=myfs0,tag=myfs,socket={},num_queues=1,queue_size=1024,dax={}{}{}", "id=myfs0,tag=myfs,socket={},num_queues=1,queue_size=1024{}",
virtiofsd_socket_path, virtiofsd_socket_path,
dax_vmm_param,
cache_size_vmm_param,
if let Some(pci_segment) = pci_segment { if let Some(pci_segment) = pci_segment {
format!(",pci_segment={}", pci_segment) format!(",pci_segment={}", pci_segment)
} else { } else {
@@ -1228,16 +1217,9 @@ fn test_virtio_fs(
} }
// Mount shared directory through virtio_fs filesystem // Mount shared directory through virtio_fs filesystem
let mount_cmd = format!( guest
"mkdir -p mount_dir && \ .ssh_command("mkdir -p mount_dir && sudo mount -t virtiofs myfs mount_dir/")
sudo mount -t virtiofs {} myfs mount_dir/", .unwrap();
dax_mount_param
);
guest.ssh_command(&mount_cmd).unwrap();
assert!(guest
.valid_virtio_fs_cache_size(dax, cache_size)
.unwrap_or_default());
// Check file1 exists and its content is "foo" // Check file1 exists and its content is "foo"
assert_eq!( assert_eq!(
@@ -1284,19 +1266,14 @@ fn test_virtio_fs(
let (r, hotplug_daemon_child) = if r.is_ok() && hotplug { let (r, hotplug_daemon_child) = if r.is_ok() && hotplug {
thread::sleep(std::time::Duration::new(10, 0)); thread::sleep(std::time::Duration::new(10, 0));
let (daemon_child, virtiofsd_socket_path) = prepare_daemon( let (daemon_child, virtiofsd_socket_path) =
&guest.tmp_dir, prepare_daemon(&guest.tmp_dir, shared_dir.to_str().unwrap());
shared_dir.to_str().unwrap(),
virtiofsd_cache,
);
let r = std::panic::catch_unwind(|| { let r = std::panic::catch_unwind(|| {
thread::sleep(std::time::Duration::new(10, 0)); thread::sleep(std::time::Duration::new(10, 0));
let fs_params = format!( let fs_params = format!(
"id=myfs0,tag=myfs,socket={},num_queues=1,queue_size=1024,dax={}{}{}", "id=myfs0,tag=myfs,socket={},num_queues=1,queue_size=1024{}",
virtiofsd_socket_path, virtiofsd_socket_path,
dax_vmm_param,
cache_size_vmm_param,
if let Some(pci_segment) = pci_segment { if let Some(pci_segment) = pci_segment {
format!(",pci_segment={}", pci_segment) format!(",pci_segment={}", pci_segment)
} else { } else {
@@ -1320,12 +1297,10 @@ fn test_virtio_fs(
thread::sleep(std::time::Duration::new(10, 0)); thread::sleep(std::time::Duration::new(10, 0));
// Mount shared directory through virtio_fs filesystem // Mount shared directory through virtio_fs filesystem
let mount_cmd = format!( guest
"mkdir -p mount_dir && \ .ssh_command("mkdir -p mount_dir && sudo mount -t virtiofs myfs mount_dir/")
sudo mount -t virtiofs {} myfs mount_dir/", .unwrap();
dax_mount_param
);
guest.ssh_command(&mount_cmd).unwrap();
// Check file1 exists and its content is "foo" // Check file1 exists and its content is "foo"
assert_eq!( assert_eq!(
guest.ssh_command("cat mount_dir/file1").unwrap().trim(), guest.ssh_command("cat mount_dir/file1").unwrap().trim(),
@@ -1646,7 +1621,7 @@ fn process_rss_kib(pid: u32) -> usize {
// 10MB is our maximum accepted overhead. // 10MB is our maximum accepted overhead.
const MAXIMUM_VMM_OVERHEAD_KB: u32 = 10 * 1024; const MAXIMUM_VMM_OVERHEAD_KB: u32 = 10 * 1024;
#[derive(PartialEq, PartialOrd)] #[derive(PartialEq, Eq, PartialOrd)]
struct Counters { struct Counters {
rx_bytes: u64, rx_bytes: u64,
rx_frames: u64, rx_frames: u64,
@@ -2028,7 +2003,6 @@ mod parallel {
assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1); assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1);
assert_eq!(guest.get_initial_apicid().unwrap_or(1), 0); assert_eq!(guest.get_initial_apicid().unwrap_or(1), 0);
assert!(guest.get_total_memory().unwrap_or_default() > 480_000); assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
assert!(guest.get_entropy().unwrap_or_default() >= 900);
assert_eq!(guest.get_pci_bridge_class().unwrap_or_default(), "0x060000"); assert_eq!(guest.get_pci_bridge_class().unwrap_or_default(), "0x060000");
let expected_sequential_events = [ let expected_sequential_events = [
@@ -2654,7 +2628,6 @@ mod parallel {
assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1); assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1);
assert!(guest.get_total_memory().unwrap_or_default() > 480_000); assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
assert!(guest.get_entropy().unwrap_or_default() >= 900);
let grep_cmd = if cfg!(target_arch = "x86_64") { let grep_cmd = if cfg!(target_arch = "x86_64") {
"grep -c PCI-MSI /proc/interrupts" "grep -c PCI-MSI /proc/interrupts"
@@ -3119,25 +3092,25 @@ mod parallel {
} }
#[test] #[test]
fn test_virtio_fs_dax_off() { fn test_virtio_fs() {
test_virtio_fs(false, None, "never", &prepare_virtiofsd, false, None) _test_virtio_fs(&prepare_virtiofsd, false, None)
} }
#[test] #[test]
fn test_virtio_fs_hotplug_dax_off() { fn test_virtio_fs_hotplug() {
test_virtio_fs(false, None, "never", &prepare_virtiofsd, true, None) _test_virtio_fs(&prepare_virtiofsd, true, None)
} }
#[test] #[test]
#[cfg(not(feature = "mshv"))] #[cfg(not(feature = "mshv"))]
fn test_virtio_fs_multi_segment_hotplug() { fn test_virtio_fs_multi_segment_hotplug() {
test_virtio_fs(false, None, "never", &prepare_virtiofsd, true, Some(15)) _test_virtio_fs(&prepare_virtiofsd, true, Some(15))
} }
#[test] #[test]
#[cfg(not(feature = "mshv"))] #[cfg(not(feature = "mshv"))]
fn test_virtio_fs_multi_segment() { fn test_virtio_fs_multi_segment() {
test_virtio_fs(false, None, "never", &prepare_virtiofsd, false, Some(15)) _test_virtio_fs(&prepare_virtiofsd, false, Some(15))
} }
#[test] #[test]
@@ -3984,7 +3957,6 @@ mod parallel {
assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1); assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1);
assert!(guest.get_total_memory().unwrap_or_default() > 480_000); assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
assert!(guest.get_entropy().unwrap_or_default() >= 900);
}); });
let _ = child.kill(); let _ = child.kill();
@@ -4073,7 +4045,60 @@ mod parallel {
let cpu_count: u8 = 4; let cpu_count: u8 = 4;
let http_body = guest.api_create_body( let http_body = guest.api_create_body(
cpu_count, cpu_count,
fw_path(FwType::RustHypervisorFirmware).as_str(), direct_kernel_boot_path().to_str().unwrap(),
DIRECT_KERNEL_BOOT_CMDLINE,
);
let temp_config_path = guest.tmp_dir.as_path().join("config");
std::fs::write(&temp_config_path, http_body).unwrap();
remote_command(
&api_socket,
"create",
Some(temp_config_path.as_os_str().to_str().unwrap()),
);
// Then boot it
remote_command(&api_socket, "boot", None);
thread::sleep(std::time::Duration::new(20, 0));
let r = std::panic::catch_unwind(|| {
// Check that the VM booted as expected
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
});
let _ = child.kill();
let output = child.wait_with_output().unwrap();
handle_child_output(r, &output);
}
#[test]
// Start cloud-hypervisor with no VM parameters, only the API server running.
// From the API: Create a VM, boot it and check it can be shutdown and then
// booted again
fn test_api_shutdown() {
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = Guest::new(Box::new(focal));
let api_socket = temp_api_path(&guest.tmp_dir);
let mut child = GuestCommand::new(&guest)
.args(&["--api-socket", &api_socket])
.capture_output()
.spawn()
.unwrap();
thread::sleep(std::time::Duration::new(1, 0));
// Verify API server is running
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
// Create the VM first
let cpu_count: u8 = 4;
let http_body = guest.api_create_body(
cpu_count,
direct_kernel_boot_path().to_str().unwrap(), direct_kernel_boot_path().to_str().unwrap(),
DIRECT_KERNEL_BOOT_CMDLINE, DIRECT_KERNEL_BOOT_CMDLINE,
); );
@@ -4087,13 +4112,113 @@ mod parallel {
// Then boot it // Then boot it
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None); curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
thread::sleep(std::time::Duration::new(20, 0));
let r = std::panic::catch_unwind(|| { let r = std::panic::catch_unwind(|| {
guest.wait_vm_boot(None).unwrap();
// Check that the VM booted as expected
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
// Shutdown without powering off to prevent filesystem corruption
guest.ssh_command("sudo shutdown -H now").unwrap();
// Then shut it down
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.shutdown",
None,
);
// Then boot it again
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
guest.wait_vm_boot(None).unwrap();
// Check that the VM booted as expected
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
});
let _ = child.kill();
let output = child.wait_with_output().unwrap();
handle_child_output(r, &output);
}
#[test]
// Start cloud-hypervisor with no VM parameters, only the API server running.
// From the API: Create a VM, boot it and check it can be deleted and then recreated
// booted again.
fn test_api_delete() {
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = Guest::new(Box::new(focal));
let api_socket = temp_api_path(&guest.tmp_dir);
let mut child = GuestCommand::new(&guest)
.args(&["--api-socket", &api_socket])
.capture_output()
.spawn()
.unwrap();
thread::sleep(std::time::Duration::new(1, 0));
// Verify API server is running
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
// Create the VM first
let cpu_count: u8 = 4;
let http_body = guest.api_create_body(
cpu_count,
direct_kernel_boot_path().to_str().unwrap(),
DIRECT_KERNEL_BOOT_CMDLINE,
);
let r = std::panic::catch_unwind(|| {
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.create",
Some(&http_body),
);
// Then boot it
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
guest.wait_vm_boot(None).unwrap();
// Check that the VM booted as expected
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
// Shutdown without powering off to prevent filesystem corruption
guest.ssh_command("sudo shutdown -H now").unwrap();
// Then delete it
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.delete",
None,
);
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.create",
Some(&http_body),
);
// Then boot it again
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
guest.wait_vm_boot(None).unwrap();
// Check that the VM booted as expected // Check that the VM booted as expected
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count); assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
assert!(guest.get_total_memory().unwrap_or_default() > 480_000); assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
assert!(guest.get_entropy().unwrap_or_default() >= 900);
}); });
let _ = child.kill(); let _ = child.kill();
@@ -4128,7 +4253,6 @@ mod parallel {
let cpu_count: u8 = 4; let cpu_count: u8 = 4;
let http_body = guest.api_create_body( let http_body = guest.api_create_body(
cpu_count, cpu_count,
fw_path(FwType::RustHypervisorFirmware).as_str(),
direct_kernel_boot_path().to_str().unwrap(), direct_kernel_boot_path().to_str().unwrap(),
DIRECT_KERNEL_BOOT_CMDLINE, DIRECT_KERNEL_BOOT_CMDLINE,
); );
@@ -4147,7 +4271,6 @@ mod parallel {
// Check that the VM booted as expected // Check that the VM booted as expected
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count); assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
assert!(guest.get_total_memory().unwrap_or_default() > 480_000); assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
assert!(guest.get_entropy().unwrap_or_default() >= 900);
// We now pause the VM // We now pause the VM
assert!(remote_command(&api_socket, "pause", None)); assert!(remote_command(&api_socket, "pause", None));
@@ -5664,6 +5787,56 @@ mod parallel {
handle_child_output(r, &output); handle_child_output(r, &output);
} }
#[test]
#[cfg(feature = "guest_debug")]
fn test_coredump() {
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = Guest::new(Box::new(focal));
let api_socket = temp_api_path(&guest.tmp_dir);
let mut cmd = GuestCommand::new(&guest);
cmd.args(&["--cpus", "boot=4"])
.args(&["--memory", "size=4G"])
.args(&["--kernel", fw_path(FwType::RustHypervisorFirmware).as_str()])
.default_disks()
.args(&["--net", guest.default_net_string().as_str()])
.args(&["--api-socket", &api_socket])
.capture_output();
let mut child = cmd.spawn().unwrap();
let vmcore_file = temp_vmcore_file_path(&guest.tmp_dir);
let r = std::panic::catch_unwind(|| {
guest.wait_vm_boot(None).unwrap();
assert!(remote_command(&api_socket, "pause", None));
assert!(remote_command(
&api_socket,
"coredump",
Some(format!("file://{}", vmcore_file).as_str()),
));
// the num of CORE notes should equals to vcpu
let readelf_core_num_cmd = format!(
"readelf --all {} |grep CORE |grep -v Type |wc -l",
vmcore_file
);
let core_num_in_elf = exec_host_command_output(&readelf_core_num_cmd);
assert_eq!(String::from_utf8_lossy(&core_num_in_elf.stdout).trim(), "4");
// the num of QEMU notes should equals to vcpu
let readelf_vmm_num_cmd = format!("readelf --all {} |grep QEMU |wc -l", vmcore_file);
let vmm_num_in_elf = exec_host_command_output(&readelf_vmm_num_cmd);
assert_eq!(String::from_utf8_lossy(&vmm_num_in_elf.stdout).trim(), "4");
});
let _ = child.kill();
let output = child.wait_with_output().unwrap();
handle_child_output(r, &output);
}
#[test] #[test]
fn test_watchdog() { fn test_watchdog() {
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string()); let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
@@ -6388,10 +6561,9 @@ mod sequential {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
mod windows { mod windows {
use crate::*; use crate::*;
use once_cell::sync::Lazy;
lazy_static! { static NEXT_DISK_ID: Lazy<Mutex<u8>> = Lazy::new(|| Mutex::new(1));
static ref NEXT_DISK_ID: Mutex<u8> = Mutex::new(1);
}
struct WindowsGuest { struct WindowsGuest {
guest: Guest, guest: Guest,
@@ -7619,9 +7791,9 @@ mod live_migration {
"--memory", "--memory",
"size=0,hotplug_method=virtio-mem", "size=0,hotplug_method=virtio-mem",
"--memory-zone", "--memory-zone",
"id=mem0,size=1G,hotplug_size=32G", "id=mem0,size=1G,hotplug_size=4G",
"id=mem1,size=1G,hotplug_size=32G", "id=mem1,size=1G,hotplug_size=4G",
"id=mem2,size=2G,hotplug_size=32G", "id=mem2,size=2G,hotplug_size=4G",
"--numa", "--numa",
"guest_numa_id=0,cpus=[0-2,9],distances=[1@15,2@20],memory_zones=mem0", "guest_numa_id=0,cpus=[0-2,9],distances=[1@15,2@20],memory_zones=mem0",
"guest_numa_id=1,cpus=[3-4,6-8],distances=[0@20,2@25],memory_zones=mem1", "guest_numa_id=1,cpus=[3-4,6-8],distances=[0@20,2@25],memory_zones=mem1",
@@ -7632,9 +7804,9 @@ mod live_migration {
"--memory", "--memory",
"size=0,hotplug_method=virtio-mem,shared=on", "size=0,hotplug_method=virtio-mem,shared=on",
"--memory-zone", "--memory-zone",
"id=mem0,size=1G,hotplug_size=32G,shared=on", "id=mem0,size=1G,hotplug_size=4G,shared=on",
"id=mem1,size=1G,hotplug_size=32G,shared=on", "id=mem1,size=1G,hotplug_size=4G,shared=on",
"id=mem2,size=2G,hotplug_size=32G,shared=on", "id=mem2,size=2G,hotplug_size=4G,shared=on",
"--numa", "--numa",
"guest_numa_id=0,cpus=[0-2,9],distances=[1@15,2@20],memory_zones=mem0", "guest_numa_id=0,cpus=[0-2,9],distances=[1@15,2@20],memory_zones=mem0",
"guest_numa_id=1,cpus=[3-4,6-8],distances=[0@20,2@25],memory_zones=mem1", "guest_numa_id=1,cpus=[3-4,6-8],distances=[0@20,2@25],memory_zones=mem1",
@@ -8346,7 +8518,6 @@ mod aarch64_acpi {
assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1); assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1);
assert!(guest.get_total_memory().unwrap_or_default() > 400_000); assert!(guest.get_total_memory().unwrap_or_default() > 400_000);
assert!(guest.get_entropy().unwrap_or_default() >= 900);
assert_eq!(guest.get_pci_bridge_class().unwrap_or_default(), "0x060000"); assert_eq!(guest.get_pci_bridge_class().unwrap_or_default(), "0x060000");
}); });

View File

@@ -5,7 +5,7 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.57" anyhow = "1.0.58"
libc = "0.2.126" libc = "0.2.126"
log = "0.4.17" log = "0.4.17"
serde = {version = ">=1.0.27", features = ["rc"] } serde = {version = ">=1.0.27", features = ["rc"] }

View File

@@ -51,7 +51,7 @@ impl Default for Command {
#[allow(dead_code)] #[allow(dead_code)]
#[repr(u32)] #[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum HeaderFlags { enum HeaderFlags {
Command = 0, Command = 0,
Reply = 1, Reply = 1,

View File

@@ -12,5 +12,5 @@ libc = "0.2.126"
log = "0.4.17" log = "0.4.17"
remain = "0.2.3" remain = "0.2.3"
thiserror = "1.0" thiserror = "1.0"
uuid = { version = "1.0.0", features = ["v4"] } uuid = { version = "1.1.2", features = ["v4"] }
vmm-sys-util = ">=0.3.1" vmm-sys-util = ">=0.3.1"

View File

@@ -6,7 +6,7 @@ edition = "2021"
[dependencies] [dependencies]
block_util = { path = "../block_util" } block_util = { path = "../block_util" }
clap = { version = "3.1.18", features = ["wrap_help","cargo"] } clap = { version = "3.2.8", features = ["wrap_help","cargo"] }
env_logger = "0.9.0" env_logger = "0.9.0"
epoll = "4.3.1" epoll = "4.3.1"
libc = "0.2.126" libc = "0.2.126"
@@ -14,10 +14,10 @@ log = "0.4.17"
option_parser = { path = "../option_parser" } option_parser = { path = "../option_parser" }
qcow = { path = "../qcow" } qcow = { path = "../qcow" }
vhost = { version = "0.4.0", features = ["vhost-user-slave"] } vhost = { version = "0.4.0", features = ["vhost-user-slave"] }
vhost-user-backend = { git = "https://github.com/rust-vmm/vhost-user-backend", rev = "14f58eda14076e973704d4f904850be1146fbb05" } vhost-user-backend = "0.5.0"
virtio-bindings = "0.1.0" virtio-bindings = "0.1.0"
vm-memory = "0.8.0" vm-memory = "0.8.0"
vmm-sys-util = "0.9.0" vmm-sys-util = "0.9.0"
[build-dependencies] [build-dependencies]
clap = { version = "3.1.18", features = ["cargo"] } clap = { version = "3.2.8", features = ["cargo"] }

View File

@@ -8,6 +8,8 @@
// //
// SPDX-License-Identifier: (Apache-2.0 AND BSD-3-Clause) // SPDX-License-Identifier: (Apache-2.0 AND BSD-3-Clause)
#![allow(clippy::significant_drop_in_scrutinee)]
use block_util::{build_disk_image_id, Request, VirtioBlockConfig}; use block_util::{build_disk_image_id, Request, VirtioBlockConfig};
use libc::EFD_NONBLOCK; use libc::EFD_NONBLOCK;
use log::*; use log::*;
@@ -45,8 +47,8 @@ const BLK_SIZE: u32 = 512;
// and the overhead of the emulation layer. // and the overhead of the emulation layer.
const POLL_QUEUE_US: u128 = 50; const POLL_QUEUE_US: u128 = 50;
trait DiskFile: Read + Seek + Write + Send + Sync {} trait DiskFile: Read + Seek + Write + Send {}
impl<D: Read + Seek + Write + Send + Sync> DiskFile for D {} impl<D: Read + Seek + Write + Send> DiskFile for D {}
type Result<T> = std::result::Result<T, Error>; type Result<T> = std::result::Result<T, Error>;
type VhostUserBackendResult<T> = std::result::Result<T, std::io::Error>; type VhostUserBackendResult<T> = std::result::Result<T, std::io::Error>;

View File

@@ -5,7 +5,7 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
clap = { version = "3.1.18", features = ["wrap_help","cargo"] } clap = { version = "3.2.8", features = ["wrap_help","cargo"] }
env_logger = "0.9.0" env_logger = "0.9.0"
epoll = "4.3.1" epoll = "4.3.1"
libc = "0.2.126" libc = "0.2.126"
@@ -13,10 +13,10 @@ log = "0.4.17"
net_util = { path = "../net_util" } net_util = { path = "../net_util" }
option_parser = { path = "../option_parser" } option_parser = { path = "../option_parser" }
vhost = { version = "0.4.0", features = ["vhost-user-slave"] } vhost = { version = "0.4.0", features = ["vhost-user-slave"] }
vhost-user-backend = { git = "https://github.com/rust-vmm/vhost-user-backend", rev = "14f58eda14076e973704d4f904850be1146fbb05" } vhost-user-backend = "0.5.0"
virtio-bindings = "0.1.0" virtio-bindings = "0.1.0"
vm-memory = "0.8.0" vm-memory = "0.8.0"
vmm-sys-util = "0.9.0" vmm-sys-util = "0.9.0"
[build-dependencies] [build-dependencies]
clap = { version = "3.1.18", features = ["cargo"] } clap = { version = "3.2.8", features = ["cargo"] }

View File

@@ -6,6 +6,8 @@
// //
// SPDX-License-Identifier: (Apache-2.0 AND BSD-3-Clause) // SPDX-License-Identifier: (Apache-2.0 AND BSD-3-Clause)
#![allow(clippy::significant_drop_in_scrutinee)]
use libc::{self, EFD_NONBLOCK}; use libc::{self, EFD_NONBLOCK};
use log::*; use log::*;
use net_util::{ use net_util::{

View File

@@ -9,7 +9,7 @@ default = []
mshv = [] mshv = []
[dependencies] [dependencies]
anyhow = "1.0.57" anyhow = "1.0.58"
arc-swap = "1.5.0" arc-swap = "1.5.0"
block_util = { path = "../block_util" } block_util = { path = "../block_util" }
byteorder = "1.4.3" byteorder = "1.4.3"
@@ -23,14 +23,14 @@ net_util = { path = "../net_util" }
pci = { path = "../pci" } pci = { path = "../pci" }
rate_limiter = { path = "../rate_limiter" } rate_limiter = { path = "../rate_limiter" }
seccompiler = "0.2.0" seccompiler = "0.2.0"
serde = { version="1.0.137", features=["derive"] } serde = { version="1.0.138", features=["derive"] }
serde_json = "1.0.81" serde_json = "1.0.82"
thiserror = "1.0.31" thiserror = "1.0.31"
versionize = "0.1.6" versionize = "0.1.6"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"
vhost = { version = "0.4.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern", "vhost-vdpa"] } vhost = { version = "0.4.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern", "vhost-vdpa"] }
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.3.0" virtio-queue = "0.4.0"
vm-allocator = { path = "../vm-allocator" } vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" } vm-device = { path = "../vm-device" }
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }

View File

@@ -206,7 +206,7 @@ pub trait VirtioDevice: Send {
/// address translation before they try to read from the guest physical address. /// address translation before they try to read from the guest physical address.
/// On the other side, the implementation itself should be provided by the code /// On the other side, the implementation itself should be provided by the code
/// emulating the IOMMU for the guest. /// emulating the IOMMU for the guest.
pub trait DmaRemapping: Send + Sync { pub trait DmaRemapping {
/// Provide a way to translate GVA address ranges into GPAs. /// Provide a way to translate GVA address ranges into GPAs.
fn translate_gva(&self, id: u32, addr: u64) -> std::result::Result<u64, std::io::Error>; fn translate_gva(&self, id: u32, addr: u64) -> std::result::Result<u64, std::io::Error>;
/// Provide a way to translate GPA address ranges into GVAs. /// Provide a way to translate GPA address ranges into GVAs.

View File

@@ -10,6 +10,8 @@
//! Implements virtio devices, queues, and transport mechanisms. //! Implements virtio devices, queues, and transport mechanisms.
#![allow(clippy::significant_drop_in_scrutinee)]
#[macro_use] #[macro_use]
extern crate event_monitor; extern crate event_monitor;
#[macro_use] #[macro_use]
@@ -123,14 +125,14 @@ pub enum Error {
QueueIterator(virtio_queue::Error), QueueIterator(virtio_queue::Error),
} }
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq)] #[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
pub struct TokenBucketConfig { pub struct TokenBucketConfig {
pub size: u64, pub size: u64,
pub one_time_burst: Option<u64>, pub one_time_burst: Option<u64>,
pub refill_time: u64, pub refill_time: u64,
} }
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq)] #[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct RateLimiterConfig { pub struct RateLimiterConfig {
pub bandwidth: Option<TokenBucketConfig>, pub bandwidth: Option<TokenBucketConfig>,

View File

@@ -106,7 +106,7 @@ impl Display for Error {
} }
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Eq)]
enum RequestType { enum RequestType {
Flush, Flush,
} }

View File

@@ -6,7 +6,7 @@ use vmm_sys_util::eventfd::EventFd;
mod pci_common_config; mod pci_common_config;
mod pci_device; mod pci_device;
pub use pci_common_config::VirtioPciCommonConfig; pub use pci_common_config::VirtioPciCommonConfig;
pub use pci_device::VirtioPciDevice; pub use pci_device::{VirtioPciDevice, VirtioPciDeviceActivator};
pub trait VirtioTransport { pub trait VirtioTransport {
fn ioeventfds(&self, base_addr: u64) -> Vec<(&EventFd, u64)>; fn ioeventfds(&self, base_addr: u64) -> Vec<(&EventFd, u64)>;

View File

@@ -287,6 +287,37 @@ struct VirtioPciDeviceState {
impl VersionMapped for VirtioPciDeviceState {} impl VersionMapped for VirtioPciDeviceState {}
pub struct VirtioPciDeviceActivator {
interrupt: Option<Arc<dyn VirtioInterrupt>>,
memory: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
device: Arc<Mutex<dyn VirtioDevice>>,
device_activated: Arc<AtomicBool>,
queues: Option<Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>>,
queue_evts: Option<Vec<EventFd>>,
barrier: Option<Arc<Barrier>>,
id: String,
}
impl VirtioPciDeviceActivator {
pub fn activate(&mut self) -> ActivateResult {
self.device.lock().unwrap().activate(
self.memory.take().unwrap(),
self.interrupt.take().unwrap(),
self.queues.take().unwrap(),
self.queue_evts.take().unwrap(),
)?;
self.device_activated.store(true, Ordering::SeqCst);
if let Some(barrier) = self.barrier.take() {
info!("{}: Waiting for barrier", self.id);
barrier.wait();
info!("{}: Barrier released", self.id);
}
Ok(())
}
}
pub struct VirtioPciDevice { pub struct VirtioPciDevice {
id: String, id: String,
@@ -338,11 +369,11 @@ pub struct VirtioPciDevice {
// EventFd to signal on to request activation // EventFd to signal on to request activation
activate_evt: EventFd, activate_evt: EventFd,
// Barrier that is used to wait on for activation
activate_barrier: Arc<Barrier>,
// Optional DMA handler // Optional DMA handler
dma_handler: Option<Arc<dyn ExternalDmaMapping>>, dma_handler: Option<Arc<dyn ExternalDmaMapping>>,
// Pending activations
pending_activations: Arc<Mutex<Vec<VirtioPciDeviceActivator>>>,
} }
impl VirtioPciDevice { impl VirtioPciDevice {
@@ -359,6 +390,7 @@ impl VirtioPciDevice {
activate_evt: EventFd, activate_evt: EventFd,
use_64bit_bar: bool, use_64bit_bar: bool,
dma_handler: Option<Arc<dyn ExternalDmaMapping>>, dma_handler: Option<Arc<dyn ExternalDmaMapping>>,
pending_activations: Arc<Mutex<Vec<VirtioPciDeviceActivator>>>,
) -> Result<Self> { ) -> Result<Self> {
let device_clone = device.clone(); let device_clone = device.clone();
let mut locked_device = device_clone.lock().unwrap(); let mut locked_device = device_clone.lock().unwrap();
@@ -458,8 +490,8 @@ impl VirtioPciDevice {
cap_pci_cfg_info: VirtioPciCfgCapInfo::default(), cap_pci_cfg_info: VirtioPciCfgCapInfo::default(),
bar_regions: vec![], bar_regions: vec![],
activate_evt, activate_evt,
activate_barrier: Arc::new(Barrier::new(2)),
dma_handler, dma_handler,
pending_activations,
}; };
if let Some(msix_config) = &virtio_pci_device.msix_config { if let Some(msix_config) = &virtio_pci_device.msix_config {
@@ -666,37 +698,37 @@ impl VirtioPciDevice {
self.device.clone() self.device.clone()
} }
fn activate(&mut self) -> ActivateResult { fn prepare_activator(&mut self, barrier: Option<Arc<Barrier>>) -> VirtioPciDeviceActivator {
if let Some(virtio_interrupt) = self.virtio_interrupt.take() { let mut queue_evts = Vec::new();
if self.memory.is_some() { let mut queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>> =
let mem = self.memory.as_ref().unwrap().clone(); self.queues.iter().map(vm_virtio::clone_queue).collect();
let mut device = self.device.lock().unwrap(); queues.retain(|q| q.state.ready);
let mut queue_evts = Vec::new(); for (i, queue) in queues.iter().enumerate() {
let mut queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>> = queue_evts.push(self.queue_evts[i].try_clone().unwrap());
self.queues.iter().map(vm_virtio::clone_queue).collect(); if !queue.is_valid() {
queues.retain(|q| q.state.ready); error!("Queue {} is not valid", i);
for (i, queue) in queues.iter().enumerate() {
queue_evts.push(self.queue_evts[i].try_clone().unwrap());
if !queue.is_valid() {
error!("Queue {} is not valid", i);
}
}
return device.activate(mem, virtio_interrupt, queues, queue_evts);
} }
} }
Ok(())
VirtioPciDeviceActivator {
interrupt: self.virtio_interrupt.take(),
memory: self.memory.clone(),
device: self.device.clone(),
queues: Some(queues),
device_activated: self.device_activated.clone(),
queue_evts: Some(
queue_evts
.iter()
.map(|fd| fd.try_clone().unwrap())
.collect(),
),
barrier,
id: self.id.clone(),
}
} }
pub fn maybe_activate(&mut self) { fn activate(&mut self) -> ActivateResult {
if self.needs_activation() { self.prepare_activator(None).activate()
self.activate().expect("Failed to activate device");
self.device_activated.store(true, Ordering::SeqCst);
info!("{}: Waiting for barrier", self.id);
self.activate_barrier.wait();
info!("{}: Barrier released", self.id);
} else {
info!("{}: Device does not need activation", self.id)
}
} }
fn needs_activation(&self) -> bool { fn needs_activation(&self) -> bool {
@@ -1020,7 +1052,7 @@ impl PciDevice for VirtioPciDevice {
self.device.clone(), self.device.clone(),
), ),
o if (ISR_CONFIG_BAR_OFFSET..ISR_CONFIG_BAR_OFFSET + ISR_CONFIG_SIZE).contains(&o) => { o if (ISR_CONFIG_BAR_OFFSET..ISR_CONFIG_BAR_OFFSET + ISR_CONFIG_SIZE).contains(&o) => {
if let Some(v) = data.get(0) { if let Some(v) = data.first() {
self.interrupt_status self.interrupt_status
.fetch_and(!(*v as usize), Ordering::AcqRel); .fetch_and(!(*v as usize), Ordering::AcqRel);
} }
@@ -1058,13 +1090,16 @@ impl PciDevice for VirtioPciDevice {
// Try and activate the device if the driver status has changed // Try and activate the device if the driver status has changed
if self.needs_activation() { if self.needs_activation() {
let barrier = Arc::new(Barrier::new(2));
let activator = self.prepare_activator(Some(barrier.clone()));
self.pending_activations.lock().unwrap().push(activator);
info!( info!(
"{}: Needs activation; writing to activate event fd", "{}: Needs activation; writing to activate event fd",
self.id self.id
); );
self.activate_evt.write(1).ok(); self.activate_evt.write(1).ok();
info!("{}: Needs activation; returning barrier", self.id); info!("{}: Needs activation; returning barrier", self.id);
return Some(self.activate_barrier.clone()); return Some(barrier);
} }
// Device has been reset by the driver // Device has been reset by the driver

View File

@@ -173,7 +173,7 @@ impl VhostUserHandle {
// at early stage. // at early stage.
for (queue_index, queue) in queues.iter().enumerate() { for (queue_index, queue) in queues.iter().enumerate() {
self.vu self.vu
.set_vring_num(queue_index, queue.max_size()) .set_vring_num(queue_index, queue.state.size)
.map_err(Error::VhostUserSetVringNum)?; .map_err(Error::VhostUserSetVringNum)?;
} }
@@ -184,7 +184,7 @@ impl VhostUserHandle {
mmap_size: 0, mmap_size: 0,
mmap_offset: 0, mmap_offset: 0,
num_queues: queues.len() as u16, num_queues: queues.len() as u16,
queue_size: queues[0].max_size(), queue_size: queues[0].state.size,
}; };
let (info, fd) = self let (info, fd) = self
.vu .vu
@@ -203,11 +203,11 @@ impl VhostUserHandle {
let mut vrings_info = Vec::new(); let mut vrings_info = Vec::new();
for (queue_index, queue) in queues.into_iter().enumerate() { for (queue_index, queue) in queues.into_iter().enumerate() {
let actual_size: usize = queue.max_size().try_into().unwrap(); let actual_size: usize = queue.state.size.try_into().unwrap();
let config_data = VringConfigData { let config_data = VringConfigData {
queue_max_size: queue.max_size(), queue_max_size: queue.max_size(),
queue_size: queue.max_size(), queue_size: queue.state.size,
flags: 0u32, flags: 0u32,
desc_table_addr: get_host_address_range( desc_table_addr: get_host_address_range(
mem, mem,
@@ -290,10 +290,7 @@ impl VhostUserHandle {
} }
pub fn reset_vhost_user(&mut self, num_queues: usize) -> Result<()> { pub fn reset_vhost_user(&mut self, num_queues: usize) -> Result<()> {
self.enable_vhost_user_vrings(num_queues, false)?; self.enable_vhost_user_vrings(num_queues, false)
// Reset the owner.
self.vu.reset_owner().map_err(Error::VhostUserResetOwner)
} }
pub fn set_protocol_features_vhost_user( pub fn set_protocol_features_vhost_user(

View File

@@ -38,7 +38,7 @@ type Result<T> = std::result::Result<T, Error>;
/// A vsock connection state. /// A vsock connection state.
/// ///
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ConnState { pub enum ConnState {
/// The connection has been initiated by the host end, but is yet to be confirmed by the guest. /// The connection has been initiated by the host end, but is yet to be confirmed by the guest.
LocalInit, LocalInit,
@@ -61,7 +61,7 @@ pub enum ConnState {
/// (via `notify()`), the connection will store a `PendingRx::Rw` to be later inspected by /// (via `notify()`), the connection will store a `PendingRx::Rw` to be later inspected by
/// `recv_pkt()`. /// `recv_pkt()`.
/// ///
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq, Eq)]
enum PendingRx { enum PendingRx {
/// We need to yield a connection request packet (VSOCK_OP_REQUEST). /// We need to yield a connection request packet (VSOCK_OP_REQUEST).
Request = 0, Request = 0,

View File

@@ -10,11 +10,11 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"] mshv = ["vfio-ioctls/mshv"]
[dependencies] [dependencies]
anyhow = "1.0.57" anyhow = "1.0.58"
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
thiserror = "1.0.31" thiserror = "1.0.31"
serde = { version = "1.0.137", features = ["rc", "derive"] } serde = { version = "1.0.138", features = ["rc", "derive"] }
serde_json = "1.0.81" serde_json = "1.0.82"
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false } vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
vm-memory = { version = "0.8.0", features = ["backend-mmap"] } vm-memory = { version = "0.8.0", features = ["backend-mmap"] }
vmm-sys-util = "0.9.0" vmm-sys-util = "0.9.0"

View File

@@ -7,7 +7,7 @@
//! Handles routing to devices in an address space. //! Handles routing to devices in an address space.
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd}; use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::collections::btree_map::BTreeMap; use std::collections::btree_map::BTreeMap;
use std::sync::{Arc, Barrier, Mutex, RwLock, Weak}; use std::sync::{Arc, Barrier, Mutex, RwLock, Weak};
use std::{convert, error, fmt, io, result}; use std::{convert, error, fmt, io, result};

View File

@@ -3,6 +3,8 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
#![allow(clippy::significant_drop_in_scrutinee)]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
mod bus; mod bus;
@@ -12,7 +14,7 @@ pub mod interrupt;
pub use self::bus::{Bus, BusDevice, Error as BusError}; pub use self::bus::{Bus, BusDevice, Error as BusError};
/// Type of Message Signalled Interrupt /// Type of Message Signalled Interrupt
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum MsiIrqType { pub enum MsiIrqType {
/// PCI MSI IRQ numbers. /// PCI MSI IRQ numbers.
PciMsi, PciMsi,
@@ -22,7 +24,7 @@ pub enum MsiIrqType {
GenericMsi, GenericMsi,
} }
#[derive(Copy, Clone, PartialEq, Serialize, Deserialize, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum PciBarType { pub enum PciBarType {
Io, Io,
Mmio32, Mmio32,

View File

@@ -5,10 +5,10 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.57" anyhow = "1.0.58"
thiserror = "1.0.31" thiserror = "1.0.31"
serde = { version = "1.0.137", features = ["rc", "derive"] } serde = { version = "1.0.138", features = ["rc", "derive"] }
serde_json = "1.0.81" serde_json = "1.0.82"
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-atomic"] } vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic"] }

View File

@@ -12,7 +12,7 @@ use versionize::{VersionMap, Versionize};
pub mod protocol; pub mod protocol;
/// Global VMM version for versioning /// Global VMM version for versioning
const MAJOR_VERSION: u16 = 24; const MAJOR_VERSION: u16 = 25;
const MINOR_VERSION: u16 = 0; const MINOR_VERSION: u16 = 0;
const VMM_VERSION: u16 = MAJOR_VERSION << 12 | MINOR_VERSION & 0b1111; const VMM_VERSION: u16 = MAJOR_VERSION << 12 | MINOR_VERSION & 0b1111;

View File

@@ -139,7 +139,7 @@ impl Request {
} }
#[repr(u16)] #[repr(u16)]
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq, Eq)]
pub enum Status { pub enum Status {
Invalid, Invalid,
Ok, Ok,

View File

@@ -10,5 +10,5 @@ default = []
[dependencies] [dependencies]
log = "0.4.17" log = "0.4.17"
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.3.0" virtio-queue = "0.4.0"
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }

View File

@@ -9,47 +9,48 @@ default = []
amx = [] amx = []
cmos = ["devices/cmos"] cmos = ["devices/cmos"]
fwdebug = ["devices/fwdebug"] fwdebug = ["devices/fwdebug"]
gdb = ["kvm"] gdb = ["kvm", "gdbstub", "gdbstub_arch"]
guest_debug = ["kvm"]
kvm = ["hypervisor/kvm", "vfio-ioctls/kvm", "vm-device/kvm", "pci/kvm"] kvm = ["hypervisor/kvm", "vfio-ioctls/kvm", "vm-device/kvm", "pci/kvm"]
mshv = ["hypervisor/mshv", "virtio-devices/mshv", "vfio-ioctls/mshv", "vm-device/mshv", "pci/mshv"] mshv = ["hypervisor/mshv", "virtio-devices/mshv", "vfio-ioctls/mshv", "vm-device/mshv", "pci/mshv"]
tdx = ["arch/tdx", "hypervisor/tdx"] tdx = ["arch/tdx", "hypervisor/tdx"]
[dependencies] [dependencies]
acpi_tables = { path = "../acpi_tables" } acpi_tables = { path = "../acpi_tables" }
anyhow = "1.0.57" anyhow = "1.0.58"
arc-swap = "1.5.0" arc-swap = "1.5.0"
arch = { path = "../arch" } arch = { path = "../arch" }
bitflags = "1.3.2" bitflags = "1.3.2"
block_util = { path = "../block_util" } block_util = { path = "../block_util" }
clap = "3.1.18" clap = "3.2.8"
devices = { path = "../devices" } devices = { path = "../devices" }
epoll = "4.3.1" epoll = "4.3.1"
event_monitor = { path = "../event_monitor" } event_monitor = { path = "../event_monitor" }
gdbstub = "0.6.1" gdbstub = { version = "0.6.2", optional = true }
gdbstub_arch = "0.2.2" gdbstub_arch = { version = "0.2.3", optional = true }
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
lazy_static = "1.4.0"
libc = "0.2.126" libc = "0.2.126"
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.17"
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" } micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
net_util = { path = "../net_util" } net_util = { path = "../net_util" }
once_cell = "1.13.0"
option_parser = { path = "../option_parser" } option_parser = { path = "../option_parser" }
pci = { path = "../pci" } pci = { path = "../pci" }
qcow = { path = "../qcow" } qcow = { path = "../qcow" }
seccompiler = "0.2.0" seccompiler = "0.2.0"
serde = { version = "1.0.137", features = ["rc", "derive"] } serde = { version = "1.0.138", features = ["rc", "derive"] }
serde_json = "1.0.81" serde_json = "1.0.82"
signal-hook = "0.3.14" signal-hook = "0.3.14"
thiserror = "1.0.31" thiserror = "1.0.31"
uuid = "1.0.0" uuid = "1.1.2"
versionize = "0.1.6" versionize = "0.1.6"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"
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" }
vhdx = { path = "../vhdx" } vhdx = { path = "../vhdx" }
virtio-devices = { path = "../virtio-devices" } virtio-devices = { path = "../virtio-devices" }
virtio-queue = "0.3.0" virtio-queue = "0.4.0"
vm-allocator = { path = "../vm-allocator" } vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" } vm-device = { path = "../vm-device" }
vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] } vm-memory = { version = "0.8.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }

View File

@@ -8,6 +8,7 @@ use crate::api::{ApiError, ApiRequest, VmAction};
use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::{Error as VmmError, Result}; use crate::{Error as VmmError, Result};
use micro_http::{Body, HttpServer, MediaType, Method, Request, Response, StatusCode, Version}; use micro_http::{Body, HttpServer, MediaType, Method, Request, Response, StatusCode, Version};
use once_cell::sync::Lazy;
use seccompiler::{apply_filter, SeccompAction}; use seccompiler::{apply_filter, SeccompAction};
use serde_json::Error as SerdeError; use serde_json::Error as SerdeError;
use std::collections::HashMap; use std::collections::HashMap;
@@ -56,7 +57,7 @@ pub fn error_response(error: HttpError, status: StatusCode) -> Response {
} }
/// An HTTP endpoint handler interface /// An HTTP endpoint handler interface
pub trait EndpointHandler: Sync + Send { pub trait EndpointHandler {
/// Handles an HTTP request. /// Handles an HTTP request.
/// After parsing the request, the handler could decide to send an /// After parsing the request, the handler could decide to send an
/// associated API request down to the VMM API server to e.g. create /// associated API request down to the VMM API server to e.g. create
@@ -129,44 +130,125 @@ macro_rules! endpoint {
}; };
} }
lazy_static! { /// HTTP_ROUTES contain all the cloud-hypervisor HTTP routes.
/// HTTP_ROUTES contain all the cloud-hypervisor HTTP routes. pub static HTTP_ROUTES: Lazy<HttpRoutes> = Lazy::new(|| {
pub static ref HTTP_ROUTES: HttpRoutes = { let mut r = HttpRoutes {
let mut r = HttpRoutes { routes: HashMap::new(),
routes: HashMap::new(),
};
r.routes.insert(endpoint!("/vm.add-device"), Box::new(VmActionHandler::new(VmAction::AddDevice(Arc::default()))));
r.routes.insert(endpoint!("/vm.add-user-device"), Box::new(VmActionHandler::new(VmAction::AddUserDevice(Arc::default()))));
r.routes.insert(endpoint!("/vm.add-disk"), Box::new(VmActionHandler::new(VmAction::AddDisk(Arc::default()))));
r.routes.insert(endpoint!("/vm.add-fs"), Box::new(VmActionHandler::new(VmAction::AddFs(Arc::default()))));
r.routes.insert(endpoint!("/vm.add-net"), Box::new(VmActionHandler::new(VmAction::AddNet(Arc::default()))));
r.routes.insert(endpoint!("/vm.add-pmem"), Box::new(VmActionHandler::new(VmAction::AddPmem(Arc::default()))));
r.routes.insert(endpoint!("/vm.add-vdpa"), Box::new(VmActionHandler::new(VmAction::AddVdpa(Arc::default()))));
r.routes.insert(endpoint!("/vm.add-vsock"), Box::new(VmActionHandler::new(VmAction::AddVsock(Arc::default()))));
r.routes.insert(endpoint!("/vm.boot"), Box::new(VmActionHandler::new(VmAction::Boot)));
r.routes.insert(endpoint!("/vm.counters"), Box::new(VmActionHandler::new(VmAction::Counters)));
r.routes.insert(endpoint!("/vm.create"), Box::new(VmCreate {}));
r.routes.insert(endpoint!("/vm.delete"), Box::new(VmActionHandler::new(VmAction::Delete)));
r.routes.insert(endpoint!("/vm.info"), Box::new(VmInfo {}));
r.routes.insert(endpoint!("/vm.pause"), Box::new(VmActionHandler::new(VmAction::Pause)));
r.routes.insert(endpoint!("/vm.power-button"), Box::new(VmActionHandler::new(VmAction::PowerButton)));
r.routes.insert(endpoint!("/vm.reboot"), Box::new(VmActionHandler::new(VmAction::Reboot)));
r.routes.insert(endpoint!("/vm.receive-migration"), Box::new(VmActionHandler::new(VmAction::ReceiveMigration(Arc::default()))));
r.routes.insert(endpoint!("/vm.remove-device"), Box::new(VmActionHandler::new(VmAction::RemoveDevice(Arc::default()))));
r.routes.insert(endpoint!("/vm.resize"), Box::new(VmActionHandler::new(VmAction::Resize(Arc::default()))));
r.routes.insert(endpoint!("/vm.resize-zone"), Box::new(VmActionHandler::new(VmAction::ResizeZone(Arc::default()))));
r.routes.insert(endpoint!("/vm.restore"), Box::new(VmActionHandler::new(VmAction::Restore(Arc::default()))));
r.routes.insert(endpoint!("/vm.resume"), Box::new(VmActionHandler::new(VmAction::Resume)));
r.routes.insert(endpoint!("/vm.send-migration"), Box::new(VmActionHandler::new(VmAction::SendMigration(Arc::default()))));
r.routes.insert(endpoint!("/vm.shutdown"), Box::new(VmActionHandler::new(VmAction::Shutdown)));
r.routes.insert(endpoint!("/vm.snapshot"), Box::new(VmActionHandler::new(VmAction::Snapshot(Arc::default()))));
r.routes.insert(endpoint!("/vmm.ping"), Box::new(VmmPing {}));
r.routes.insert(endpoint!("/vmm.shutdown"), Box::new(VmmShutdown {}));
r
}; };
}
r.routes.insert(
endpoint!("/vm.add-device"),
Box::new(VmActionHandler::new(VmAction::AddDevice(Arc::default()))),
);
r.routes.insert(
endpoint!("/vm.add-user-device"),
Box::new(VmActionHandler::new(
VmAction::AddUserDevice(Arc::default()),
)),
);
r.routes.insert(
endpoint!("/vm.add-disk"),
Box::new(VmActionHandler::new(VmAction::AddDisk(Arc::default()))),
);
r.routes.insert(
endpoint!("/vm.add-fs"),
Box::new(VmActionHandler::new(VmAction::AddFs(Arc::default()))),
);
r.routes.insert(
endpoint!("/vm.add-net"),
Box::new(VmActionHandler::new(VmAction::AddNet(Arc::default()))),
);
r.routes.insert(
endpoint!("/vm.add-pmem"),
Box::new(VmActionHandler::new(VmAction::AddPmem(Arc::default()))),
);
r.routes.insert(
endpoint!("/vm.add-vdpa"),
Box::new(VmActionHandler::new(VmAction::AddVdpa(Arc::default()))),
);
r.routes.insert(
endpoint!("/vm.add-vsock"),
Box::new(VmActionHandler::new(VmAction::AddVsock(Arc::default()))),
);
r.routes.insert(
endpoint!("/vm.boot"),
Box::new(VmActionHandler::new(VmAction::Boot)),
);
r.routes.insert(
endpoint!("/vm.counters"),
Box::new(VmActionHandler::new(VmAction::Counters)),
);
r.routes
.insert(endpoint!("/vm.create"), Box::new(VmCreate {}));
r.routes.insert(
endpoint!("/vm.delete"),
Box::new(VmActionHandler::new(VmAction::Delete)),
);
r.routes.insert(endpoint!("/vm.info"), Box::new(VmInfo {}));
r.routes.insert(
endpoint!("/vm.pause"),
Box::new(VmActionHandler::new(VmAction::Pause)),
);
r.routes.insert(
endpoint!("/vm.power-button"),
Box::new(VmActionHandler::new(VmAction::PowerButton)),
);
r.routes.insert(
endpoint!("/vm.reboot"),
Box::new(VmActionHandler::new(VmAction::Reboot)),
);
r.routes.insert(
endpoint!("/vm.receive-migration"),
Box::new(VmActionHandler::new(VmAction::ReceiveMigration(
Arc::default(),
))),
);
r.routes.insert(
endpoint!("/vm.remove-device"),
Box::new(VmActionHandler::new(VmAction::RemoveDevice(Arc::default()))),
);
r.routes.insert(
endpoint!("/vm.resize"),
Box::new(VmActionHandler::new(VmAction::Resize(Arc::default()))),
);
r.routes.insert(
endpoint!("/vm.resize-zone"),
Box::new(VmActionHandler::new(VmAction::ResizeZone(Arc::default()))),
);
r.routes.insert(
endpoint!("/vm.restore"),
Box::new(VmActionHandler::new(VmAction::Restore(Arc::default()))),
);
r.routes.insert(
endpoint!("/vm.resume"),
Box::new(VmActionHandler::new(VmAction::Resume)),
);
r.routes.insert(
endpoint!("/vm.send-migration"),
Box::new(VmActionHandler::new(
VmAction::SendMigration(Arc::default()),
)),
);
r.routes.insert(
endpoint!("/vm.shutdown"),
Box::new(VmActionHandler::new(VmAction::Shutdown)),
);
r.routes.insert(
endpoint!("/vm.snapshot"),
Box::new(VmActionHandler::new(VmAction::Snapshot(Arc::default()))),
);
#[cfg(feature = "guest_debug")]
r.routes.insert(
endpoint!("/vm.coredump"),
Box::new(VmActionHandler::new(VmAction::Coredump(Arc::default()))),
);
r.routes
.insert(endpoint!("/vmm.ping"), Box::new(VmmPing {}));
r.routes
.insert(endpoint!("/vmm.shutdown"), Box::new(VmmShutdown {}));
r
});
fn handle_http_request( fn handle_http_request(
request: &Request, request: &Request,

View File

@@ -4,6 +4,8 @@
// //
use crate::api::http::{error_response, EndpointHandler, HttpError}; use crate::api::http::{error_response, EndpointHandler, HttpError};
#[cfg(feature = "guest_debug")]
use crate::api::vm_coredump;
use crate::api::{ use crate::api::{
vm_add_device, vm_add_disk, vm_add_fs, vm_add_net, vm_add_pmem, vm_add_user_device, vm_add_device, vm_add_disk, vm_add_fs, vm_add_net, vm_add_pmem, vm_add_user_device,
vm_add_vdpa, vm_add_vsock, vm_boot, vm_counters, vm_create, vm_delete, vm_info, vm_pause, vm_add_vdpa, vm_add_vsock, vm_boot, vm_counters, vm_create, vm_delete, vm_info, vm_pause,
@@ -151,6 +153,12 @@ impl EndpointHandler for VmActionHandler {
api_sender, api_sender,
Arc::new(serde_json::from_slice(body.raw())?), Arc::new(serde_json::from_slice(body.raw())?),
), ),
#[cfg(feature = "guest_debug")]
Coredump(_) => vm_coredump(
api_notifier,
api_sender,
Arc::new(serde_json::from_slice(body.raw())?),
),
ReceiveMigration(_) => vm_receive_migration( ReceiveMigration(_) => vm_receive_migration(
api_notifier, api_notifier,
api_sender, api_sender,

View File

@@ -99,6 +99,9 @@ pub enum ApiError {
/// The VM could not restored. /// The VM could not restored.
VmRestore(VmError), VmRestore(VmError),
/// The VM could not be coredumped.
VmCoredump(VmError),
/// The VMM could not shutdown. /// The VMM could not shutdown.
VmmShutdown(VmError), VmmShutdown(VmError),
@@ -189,6 +192,12 @@ pub struct VmSnapshotConfig {
pub destination_url: String, pub destination_url: String,
} }
#[derive(Clone, Deserialize, Serialize, Default, Debug)]
pub struct VmCoredumpData {
/// The coredump destination file
pub destination_url: String,
}
#[derive(Clone, Deserialize, Serialize, Default, Debug)] #[derive(Clone, Deserialize, Serialize, Default, Debug)]
pub struct VmReceiveMigrationData { pub struct VmReceiveMigrationData {
/// URL for the reception of migration state /// URL for the reception of migration state
@@ -310,6 +319,10 @@ pub enum ApiRequest {
/// Restore from a VM snapshot /// Restore from a VM snapshot
VmRestore(Arc<RestoreConfig>, Sender<ApiResponse>), VmRestore(Arc<RestoreConfig>, Sender<ApiResponse>),
/// Take a VM coredump
#[cfg(feature = "guest_debug")]
VmCoredump(Arc<VmCoredumpData>, Sender<ApiResponse>),
/// Incoming migration /// Incoming migration
VmReceiveMigration(Arc<VmReceiveMigrationData>, Sender<ApiResponse>), VmReceiveMigration(Arc<VmReceiveMigrationData>, Sender<ApiResponse>),
@@ -402,6 +415,10 @@ pub enum VmAction {
/// Snapshot VM /// Snapshot VM
Snapshot(Arc<VmSnapshotConfig>), Snapshot(Arc<VmSnapshotConfig>),
/// Coredump VM
#[cfg(feature = "guest_debug")]
Coredump(Arc<VmCoredumpData>),
/// Incoming migration /// Incoming migration
ReceiveMigration(Arc<VmReceiveMigrationData>), ReceiveMigration(Arc<VmReceiveMigrationData>),
@@ -441,6 +458,8 @@ fn vm_action(
ResizeZone(v) => ApiRequest::VmResizeZone(v, response_sender), ResizeZone(v) => ApiRequest::VmResizeZone(v, response_sender),
Restore(v) => ApiRequest::VmRestore(v, response_sender), Restore(v) => ApiRequest::VmRestore(v, response_sender),
Snapshot(v) => ApiRequest::VmSnapshot(v, response_sender), Snapshot(v) => ApiRequest::VmSnapshot(v, response_sender),
#[cfg(feature = "guest_debug")]
Coredump(v) => ApiRequest::VmCoredump(v, response_sender),
ReceiveMigration(v) => ApiRequest::VmReceiveMigration(v, response_sender), ReceiveMigration(v) => ApiRequest::VmReceiveMigration(v, response_sender),
SendMigration(v) => ApiRequest::VmSendMigration(v, response_sender), SendMigration(v) => ApiRequest::VmSendMigration(v, response_sender),
PowerButton => ApiRequest::VmPowerButton(response_sender), PowerButton => ApiRequest::VmPowerButton(response_sender),
@@ -526,6 +545,15 @@ pub fn vm_restore(
vm_action(api_evt, api_sender, VmAction::Restore(data)) vm_action(api_evt, api_sender, VmAction::Restore(data))
} }
#[cfg(feature = "guest_debug")]
pub fn vm_coredump(
api_evt: EventFd,
api_sender: Sender<ApiRequest>,
data: Arc<VmCoredumpData>,
) -> ApiResult<Option<Body>> {
vm_action(api_evt, api_sender, VmAction::Coredump(data))
}
pub fn vm_info(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<VmInfo> { pub fn vm_info(api_evt: EventFd, api_sender: Sender<ApiRequest>) -> ApiResult<VmInfo> {
let (response_sender, response_receiver) = channel(); let (response_sender, response_receiver) = channel();

View File

@@ -366,6 +366,24 @@ paths:
405: 405:
description: The VM instance could not be snapshotted because it is not booted. description: The VM instance could not be snapshotted because it is not booted.
/vm.coredump:
put:
summary: Takes a VM coredump.
requestBody:
description: The coredump configuration
content:
application/json:
schema:
$ref: '#/components/schemas/VmCoredumpData'
required: true
responses:
204:
description: The VM instance was successfully coredumped.
404:
description: The VM instance could not be coredumped because it is not created.
405:
description: The VM instance could not be coredumped because it is not booted.
/vm.restore: /vm.restore:
put: put:
summary: Restore a VM from a snapshot. summary: Restore a VM from a snapshot.
@@ -596,6 +614,9 @@ components:
type: integer type: integer
topology: topology:
$ref: '#/components/schemas/CpuTopology' $ref: '#/components/schemas/CpuTopology'
kvm_hyperv:
type: boolean
default: false
max_phys_bits: max_phys_bits:
type: integer type: integer
affinity: affinity:
@@ -870,8 +891,6 @@ components:
FsConfig: FsConfig:
required: required:
- cache_size
- dax
- num_queues - num_queues
- queue_size - queue_size
- socket - socket
@@ -888,13 +907,6 @@ components:
queue_size: queue_size:
type: integer type: integer
default: 1024 default: 1024
dax:
type: boolean
default: true
cache_size:
type: integer
format: int64
default: 8589934592
pci_segment: pci_segment:
type: integer type: integer
format: int16 format: int16
@@ -914,9 +926,6 @@ components:
iommu: iommu:
type: boolean type: boolean
default: false default: false
mergeable:
type: boolean
default: false
discard_writes: discard_writes:
type: boolean type: boolean
default: false default: false
@@ -1110,6 +1119,12 @@ components:
destination_url: destination_url:
type: string type: string
VmCoredumpData:
type: object
properties:
destination_url:
type: string
RestoreConfig: RestoreConfig:
required: required:
- source_url - source_url

View File

@@ -43,8 +43,6 @@ pub enum Error {
ParseFsTagMissing, ParseFsTagMissing,
/// Filesystem socket is missing /// Filesystem socket is missing
ParseFsSockMissing, ParseFsSockMissing,
/// Cannot have dax=off along with cache_size parameter.
InvalidCacheSizeWithDaxOff,
/// Missing persistent memory file parameter. /// Missing persistent memory file parameter.
ParsePmemFileMissing, ParsePmemFileMissing,
/// Missing vsock socket path parameter. /// Missing vsock socket path parameter.
@@ -115,7 +113,7 @@ pub enum Error {
ParseVdpaPathMissing, ParseVdpaPathMissing,
} }
#[derive(Debug, PartialEq, Error)] #[derive(Debug, PartialEq, Eq, Error)]
pub enum ValidationError { pub enum ValidationError {
/// Both console and serial are tty. /// Both console and serial are tty.
DoubleTtyMode, DoubleTtyMode,
@@ -291,9 +289,6 @@ impl fmt::Display for Error {
ParseFileSystem(o) => write!(f, "Error parsing --fs: {}", o), ParseFileSystem(o) => write!(f, "Error parsing --fs: {}", o),
ParseFsSockMissing => write!(f, "Error parsing --fs: socket missing"), ParseFsSockMissing => write!(f, "Error parsing --fs: socket missing"),
ParseFsTagMissing => write!(f, "Error parsing --fs: tag missing"), ParseFsTagMissing => write!(f, "Error parsing --fs: tag missing"),
InvalidCacheSizeWithDaxOff => {
write!(f, "Error parsing --fs: cache_size used with dax=on")
}
ParsePersistentMemory(o) => write!(f, "Error parsing --pmem: {}", o), ParsePersistentMemory(o) => write!(f, "Error parsing --pmem: {}", o),
ParsePmemFileMissing => write!(f, "Error parsing --pmem: file missing"), ParsePmemFileMissing => write!(f, "Error parsing --pmem: file missing"),
ParseVsock(o) => write!(f, "Error parsing --vsock: {}", o), ParseVsock(o) => write!(f, "Error parsing --vsock: {}", o),
@@ -435,7 +430,7 @@ impl<'a> VmParams<'a> {
} }
} }
#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum HotplugMethod { pub enum HotplugMethod {
Acpi, Acpi,
VirtioMem, VirtioMem,
@@ -464,13 +459,13 @@ impl FromStr for HotplugMethod {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct CpuAffinity { pub struct CpuAffinity {
pub vcpu: u8, pub vcpu: u8,
pub host_cpus: Vec<u8>, pub host_cpus: Vec<u8>,
} }
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
pub struct CpuFeatures { pub struct CpuFeatures {
#[cfg(all(feature = "amx", target_arch = "x86_64"))] #[cfg(all(feature = "amx", target_arch = "x86_64"))]
pub amx: bool, pub amx: bool,
@@ -480,7 +475,7 @@ pub enum CpuTopologyParseError {
InvalidValue(String), InvalidValue(String),
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct CpuTopology { pub struct CpuTopology {
pub threads_per_core: u8, pub threads_per_core: u8,
pub cores_per_die: u8, pub cores_per_die: u8,
@@ -521,7 +516,7 @@ fn default_cpuconfig_max_phys_bits() -> u8 {
DEFAULT_MAX_PHYS_BITS DEFAULT_MAX_PHYS_BITS
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct CpusConfig { pub struct CpusConfig {
pub boot_vcpus: u8, pub boot_vcpus: u8,
pub max_vcpus: u8, pub max_vcpus: u8,
@@ -631,7 +626,7 @@ fn default_platformconfig_num_pci_segments() -> u16 {
DEFAULT_NUM_PCI_SEGMENTS DEFAULT_NUM_PCI_SEGMENTS
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct PlatformConfig { pub struct PlatformConfig {
#[serde(default = "default_platformconfig_num_pci_segments")] #[serde(default = "default_platformconfig_num_pci_segments")]
pub num_pci_segments: u16, pub num_pci_segments: u16,
@@ -696,7 +691,7 @@ impl Default for PlatformConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct MemoryZoneConfig { pub struct MemoryZoneConfig {
pub id: String, pub id: String,
pub size: u64, pub size: u64,
@@ -718,7 +713,7 @@ pub struct MemoryZoneConfig {
pub prefault: bool, pub prefault: bool,
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct MemoryConfig { pub struct MemoryConfig {
pub size: u64, pub size: u64,
#[serde(default)] #[serde(default)]
@@ -923,17 +918,17 @@ impl Default for MemoryConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct KernelConfig { pub struct KernelConfig {
pub path: PathBuf, pub path: PathBuf,
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct InitramfsConfig { pub struct InitramfsConfig {
pub path: PathBuf, pub path: PathBuf,
} }
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
pub struct CmdlineConfig { pub struct CmdlineConfig {
pub args: String, pub args: String,
} }
@@ -948,7 +943,7 @@ impl CmdlineConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct DiskConfig { pub struct DiskConfig {
pub path: Option<PathBuf>, pub path: Option<PathBuf>,
#[serde(default)] #[serde(default)]
@@ -1183,7 +1178,7 @@ impl DiskConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum VhostMode { pub enum VhostMode {
Client, Client,
Server, Server,
@@ -1212,7 +1207,7 @@ impl FromStr for VhostMode {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct NetConfig { pub struct NetConfig {
#[serde(default = "default_netconfig_tap")] #[serde(default = "default_netconfig_tap")]
pub tap: Option<String>, pub tap: Option<String>,
@@ -1483,7 +1478,7 @@ impl NetConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct RngConfig { pub struct RngConfig {
pub src: PathBuf, pub src: PathBuf,
#[serde(default)] #[serde(default)]
@@ -1520,7 +1515,7 @@ impl Default for RngConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct BalloonConfig { pub struct BalloonConfig {
pub size: u64, pub size: u64,
/// Option to deflate the balloon in case the guest is out of memory. /// Option to deflate the balloon in case the guest is out of memory.
@@ -1569,7 +1564,7 @@ impl BalloonConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct FsConfig { pub struct FsConfig {
pub tag: String, pub tag: String,
pub socket: PathBuf, pub socket: PathBuf,
@@ -1577,10 +1572,6 @@ pub struct FsConfig {
pub num_queues: usize, pub num_queues: usize,
#[serde(default = "default_fsconfig_queue_size")] #[serde(default = "default_fsconfig_queue_size")]
pub queue_size: u16, pub queue_size: u16,
#[serde(default = "default_fsconfig_dax")]
pub dax: bool,
#[serde(default = "default_fsconfig_cache_size")]
pub cache_size: u64,
#[serde(default)] #[serde(default)]
pub id: Option<String>, pub id: Option<String>,
#[serde(default)] #[serde(default)]
@@ -1595,14 +1586,6 @@ fn default_fsconfig_queue_size() -> u16 {
1024 1024
} }
fn default_fsconfig_dax() -> bool {
false
}
fn default_fsconfig_cache_size() -> u64 {
0x0002_0000_0000
}
impl Default for FsConfig { impl Default for FsConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
@@ -1610,8 +1593,6 @@ impl Default for FsConfig {
socket: PathBuf::new(), socket: PathBuf::new(),
num_queues: default_fsconfig_num_queues(), num_queues: default_fsconfig_num_queues(),
queue_size: default_fsconfig_queue_size(), queue_size: default_fsconfig_queue_size(),
dax: default_fsconfig_dax(),
cache_size: default_fsconfig_cache_size(),
id: None, id: None,
pci_segment: 0, pci_segment: 0,
} }
@@ -1621,15 +1602,12 @@ impl Default for FsConfig {
impl FsConfig { impl FsConfig {
pub const SYNTAX: &'static str = "virtio-fs parameters \ pub const SYNTAX: &'static str = "virtio-fs parameters \
\"tag=<tag_name>,socket=<socket_path>,num_queues=<number_of_queues>,\ \"tag=<tag_name>,socket=<socket_path>,num_queues=<number_of_queues>,\
queue_size=<size_of_each_queue>,dax=on|off,cache_size=<DAX cache size: \ queue_size=<size_of_each_queue>,id=<device_id>,pci_segment=<segment_id>\"";
default 8Gib>,id=<device_id>,pci_segment=<segment_id>\"";
pub fn parse(fs: &str) -> Result<Self> { pub fn parse(fs: &str) -> Result<Self> {
let mut parser = OptionParser::new(); let mut parser = OptionParser::new();
parser parser
.add("tag") .add("tag")
.add("dax")
.add("cache_size")
.add("queue_size") .add("queue_size")
.add("num_queues") .add("num_queues")
.add("socket") .add("socket")
@@ -1649,22 +1627,6 @@ impl FsConfig {
.map_err(Error::ParseFileSystem)? .map_err(Error::ParseFileSystem)?
.unwrap_or_else(default_fsconfig_num_queues); .unwrap_or_else(default_fsconfig_num_queues);
let dax = parser
.convert::<Toggle>("dax")
.map_err(Error::ParseFileSystem)?
.unwrap_or_else(|| Toggle(default_fsconfig_dax()))
.0;
if parser.is_set("cache_size") && !dax {
return Err(Error::InvalidCacheSizeWithDaxOff);
}
let cache_size = parser
.convert::<ByteSized>("cache_size")
.map_err(Error::ParseFileSystem)?
.unwrap_or_else(|| ByteSized(default_fsconfig_cache_size()))
.0;
let id = parser.get("id"); let id = parser.get("id");
let pci_segment = parser let pci_segment = parser
@@ -1677,8 +1639,6 @@ impl FsConfig {
socket, socket,
num_queues, num_queues,
queue_size, queue_size,
dax,
cache_size,
id, id,
pci_segment, pci_segment,
}) })
@@ -1703,20 +1663,11 @@ impl FsConfig {
} }
} }
if self.dax {
// TODO: Remove the dax parameter.
// Tracked by https://github.com/cloud-hypervisor/cloud-hypervisor/issues/3889
warn!(
"The experimental DAX feature is deprecated and will be \
removed in a future release. A request to enable it is ignored."
);
}
Ok(()) Ok(())
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct PmemConfig { pub struct PmemConfig {
pub file: PathBuf, pub file: PathBuf,
#[serde(default)] #[serde(default)]
@@ -1724,8 +1675,6 @@ pub struct PmemConfig {
#[serde(default)] #[serde(default)]
pub iommu: bool, pub iommu: bool,
#[serde(default)] #[serde(default)]
pub mergeable: bool,
#[serde(default)]
pub discard_writes: bool, pub discard_writes: bool,
#[serde(default)] #[serde(default)]
pub id: Option<String>, pub id: Option<String>,
@@ -1742,7 +1691,6 @@ impl PmemConfig {
parser parser
.add("size") .add("size")
.add("file") .add("file")
.add("mergeable")
.add("iommu") .add("iommu")
.add("discard_writes") .add("discard_writes")
.add("id") .add("id")
@@ -1754,11 +1702,6 @@ impl PmemConfig {
.convert::<ByteSized>("size") .convert::<ByteSized>("size")
.map_err(Error::ParsePersistentMemory)? .map_err(Error::ParsePersistentMemory)?
.map(|v| v.0); .map(|v| v.0);
let mergeable = parser
.convert::<Toggle>("mergeable")
.map_err(Error::ParsePersistentMemory)?
.unwrap_or(Toggle(false))
.0;
let iommu = parser let iommu = parser
.convert::<Toggle>("iommu") .convert::<Toggle>("iommu")
.map_err(Error::ParsePersistentMemory)? .map_err(Error::ParsePersistentMemory)?
@@ -1779,7 +1722,6 @@ impl PmemConfig {
file, file,
size, size,
iommu, iommu,
mergeable,
discard_writes, discard_writes,
id, id,
pci_segment, pci_segment,
@@ -1787,10 +1729,6 @@ impl PmemConfig {
} }
pub fn validate(&self, vm_config: &VmConfig) -> ValidationResult<()> { pub fn validate(&self, vm_config: &VmConfig) -> ValidationResult<()> {
if self.mergeable {
warn!("Enabling mergable pages for PMEM devices is ineffectual. This option is deprecated and will be removed in a later release");
}
if let Some(platform_config) = vm_config.platform.as_ref() { if let Some(platform_config) = vm_config.platform.as_ref() {
if self.pci_segment >= platform_config.num_pci_segments { if self.pci_segment >= platform_config.num_pci_segments {
return Err(ValidationError::InvalidPciSegment(self.pci_segment)); return Err(ValidationError::InvalidPciSegment(self.pci_segment));
@@ -1807,7 +1745,7 @@ impl PmemConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum ConsoleOutputMode { pub enum ConsoleOutputMode {
Off, Off,
Pty, Pty,
@@ -1816,7 +1754,7 @@ pub enum ConsoleOutputMode {
Null, Null,
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct ConsoleConfig { pub struct ConsoleConfig {
#[serde(default = "default_consoleconfig_file")] #[serde(default = "default_consoleconfig_file")]
pub file: Option<PathBuf>, pub file: Option<PathBuf>,
@@ -1886,7 +1824,7 @@ impl ConsoleConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct DeviceConfig { pub struct DeviceConfig {
pub path: PathBuf, pub path: PathBuf,
#[serde(default)] #[serde(default)]
@@ -1945,7 +1883,7 @@ impl DeviceConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct UserDeviceConfig { pub struct UserDeviceConfig {
pub socket: PathBuf, pub socket: PathBuf,
#[serde(default)] #[serde(default)]
@@ -1998,7 +1936,7 @@ impl UserDeviceConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct VdpaConfig { pub struct VdpaConfig {
pub path: PathBuf, pub path: PathBuf,
#[serde(default = "default_vdpaconfig_num_queues")] #[serde(default = "default_vdpaconfig_num_queues")]
@@ -2074,7 +2012,7 @@ impl VdpaConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct VsockConfig { pub struct VsockConfig {
pub cid: u64, pub cid: u64,
pub socket: PathBuf, pub socket: PathBuf,
@@ -2145,7 +2083,7 @@ impl VsockConfig {
} }
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct TdxConfig { pub struct TdxConfig {
pub firmware: PathBuf, pub firmware: PathBuf,
} }
@@ -2165,7 +2103,7 @@ impl TdxConfig {
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct SgxEpcConfig { pub struct SgxEpcConfig {
pub id: String, pub id: String,
#[serde(default)] #[serde(default)]
@@ -2199,7 +2137,7 @@ impl SgxEpcConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct NumaDistance { pub struct NumaDistance {
#[serde(default)] #[serde(default)]
pub destination: u32, pub destination: u32,
@@ -2207,7 +2145,7 @@ pub struct NumaDistance {
pub distance: u8, pub distance: u8,
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct NumaConfig { pub struct NumaConfig {
#[serde(default)] #[serde(default)]
pub guest_numa_id: u32, pub guest_numa_id: u32,
@@ -2276,7 +2214,7 @@ impl NumaConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
pub struct RestoreConfig { pub struct RestoreConfig {
pub source_url: PathBuf, pub source_url: PathBuf,
#[serde(default)] #[serde(default)]
@@ -2310,7 +2248,7 @@ impl RestoreConfig {
} }
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct VmConfig { pub struct VmConfig {
#[serde(default)] #[serde(default)]
pub cpus: CpusConfig, pub cpus: CpusConfig,
@@ -3116,29 +3054,7 @@ mod tests {
..Default::default() ..Default::default()
} }
); );
// DAX on -> default cache size
assert_eq!(
FsConfig::parse("tag=mytag,socket=/tmp/sock,dax=on")?,
FsConfig {
socket: PathBuf::from("/tmp/sock"),
tag: "mytag".to_owned(),
dax: true,
cache_size: default_fsconfig_cache_size(),
..Default::default()
}
);
assert_eq!(
FsConfig::parse("tag=mytag,socket=/tmp/sock,dax=on,cache_size=4G")?,
FsConfig {
socket: PathBuf::from("/tmp/sock"),
tag: "mytag".to_owned(),
dax: true,
cache_size: 4 << 30,
..Default::default()
}
);
// Cache size without DAX is an error
assert!(FsConfig::parse("tag=mytag,socket=/tmp/sock,dax=off,cache_size=4G").is_err());
Ok(()) Ok(())
} }
@@ -3165,11 +3081,10 @@ mod tests {
} }
); );
assert_eq!( assert_eq!(
PmemConfig::parse("file=/tmp/pmem,size=128M,iommu=on,mergeable=on,discard_writes=on")?, PmemConfig::parse("file=/tmp/pmem,size=128M,iommu=on,discard_writes=on")?,
PmemConfig { PmemConfig {
file: PathBuf::from("/tmp/pmem"), file: PathBuf::from("/tmp/pmem"),
size: Some(128 << 20), size: Some(128 << 20),
mergeable: true,
discard_writes: true, discard_writes: true,
iommu: true, iommu: true,
..Default::default() ..Default::default()

348
vmm/src/coredump.rs Normal file
View File

@@ -0,0 +1,348 @@
// Copyright © 2022 ZTE Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
#[cfg(target_arch = "x86_64")]
use hypervisor::kvm::kvm_bindings::kvm_dtable as DTableRegister;
#[cfg(target_arch = "x86_64")]
use hypervisor::x86_64::SegmentRegister;
use linux_loader::elf;
use std::fs::File;
use std::io::Write;
use vm_memory::ByteValued;
#[derive(Clone)]
pub struct CoredumpMemoryRegion {
pub mem_offset_in_elf: u64,
pub mem_size: u64,
}
#[derive(Clone)]
pub struct CoredumpMemoryRegions {
pub ram_maps: std::collections::BTreeMap<u64, CoredumpMemoryRegion>,
}
/// Platform information
#[derive(Default)]
pub struct DumpState {
pub elf_note_size: isize,
pub elf_phdr_num: u16,
pub elf_sh_info: u32,
pub mem_offset: u64,
pub mem_info: Option<CoredumpMemoryRegions>,
pub file: Option<File>,
}
#[derive(Debug)]
pub enum GuestDebuggableError {
Coredump(anyhow::Error),
CoredumpFile(std::io::Error),
}
pub trait GuestDebuggable: vm_migration::Pausable {
fn coredump(
&mut self,
_destination_url: &str,
) -> std::result::Result<(), GuestDebuggableError> {
Ok(())
}
}
#[macro_export]
macro_rules! div_round_up {
($n:expr,$d:expr) => {
($n + $d - 1) / $d
};
}
#[repr(C)]
#[derive(Default, Copy, Clone)]
pub struct X86_64UserRegs {
/// r15, r14, r13, r12, rbp, rbx, r11, r10;
pub regs1: [u64; 8],
/// r9, r8, rax, rcx, rdx, rsi, rdi, orig_rax;
pub regs2: [u64; 8],
pub rip: u64,
pub cs: u64,
pub eflags: u64,
pub rsp: u64,
pub ss: u64,
pub fs_base: u64,
pub gs_base: u64,
pub ds: u64,
pub es: u64,
pub fs: u64,
pub gs: u64,
}
unsafe impl ByteValued for X86_64UserRegs {}
#[repr(C)]
pub struct X86_64ElfPrStatus {
pub pad1: [u8; 32],
pub pid: u32,
pub pads2: [u8; 76],
pub regs: X86_64UserRegs,
pub pad3: [u8; 8],
}
#[repr(C)]
#[derive(Default, Copy, Clone)]
pub struct CpuSegment {
pub selector: u32,
pub limit: u32,
pub flags: u32,
pub pad: u32,
pub base: u64,
}
const DESC_TYPE_SHIFT: u32 = 8;
const DESC_S_SHIFT: u32 = 12;
const DESC_DPL_SHIFT: u32 = 13;
const DESC_P_SHIFT: u32 = 15;
const DESC_P_MASK: u32 = 1 << DESC_P_SHIFT;
const DESC_AVL_SHIFT: u32 = 20;
const DESC_AVL_MASK: u32 = 1 << DESC_AVL_SHIFT;
const DESC_L_SHIFT: u32 = 21;
const DESC_B_SHIFT: u32 = 22;
const DESC_S_MASK: u32 = 1 << DESC_S_SHIFT;
const DESC_G_SHIFT: u32 = 23;
const DESC_G_MASK: u32 = 1 << DESC_G_SHIFT;
impl CpuSegment {
pub fn new(reg: SegmentRegister) -> Self {
let p_mask = if (reg.present > 0) && (reg.unusable == 0) {
DESC_P_MASK
} else {
0
};
let flags = ((reg.type_ as u32) << DESC_TYPE_SHIFT)
| p_mask
| ((reg.dpl as u32) << DESC_DPL_SHIFT)
| ((reg.db as u32) << DESC_B_SHIFT)
| ((reg.s as u32) * DESC_S_MASK)
| ((reg.l as u32) << DESC_L_SHIFT)
| ((reg.g as u32) * DESC_G_MASK)
| ((reg.avl as u32) * DESC_AVL_MASK);
CpuSegment {
selector: reg.selector as u32,
limit: reg.limit as u32,
flags,
pad: 0,
base: reg.base,
}
}
pub fn new_from_table(reg: DTableRegister) -> Self {
CpuSegment {
selector: 0,
limit: reg.limit as u32,
flags: 0,
pad: 0,
base: reg.base,
}
}
}
#[repr(C)]
#[derive(Default, Copy, Clone)]
pub struct CpuState {
pub version: u32,
pub size: u32,
/// rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp
pub regs1: [u64; 8],
/// r8, r9, r10, r11, r12, r13, r14, r15
pub regs2: [u64; 8],
pub rip: u64,
pub rflags: u64,
pub cs: CpuSegment,
pub ds: CpuSegment,
pub es: CpuSegment,
pub fs: CpuSegment,
pub gs: CpuSegment,
pub ss: CpuSegment,
pub ldt: CpuSegment,
pub tr: CpuSegment,
pub gdt: CpuSegment,
pub idt: CpuSegment,
pub cr: [u64; 5],
pub kernel_gs_base: u64,
}
unsafe impl ByteValued for CpuState {}
pub enum NoteDescType {
Elf = 0,
Vmm = 1,
ElfAndVmm = 2,
}
// "CORE" or "QEMU"
pub const COREDUMP_NAME_SIZE: u32 = 5;
pub const NT_PRSTATUS: u32 = 1;
/// Core file.
const ET_CORE: u16 = 4;
/// 64-bit object.
const ELFCLASS64: u8 = 2;
/// Current ELF version.
const EV_CURRENT: u8 = 1;
/// AMD x86-64 architecture
const EM_X86_64: u16 = 62;
pub trait Elf64Writable {
fn write_header(
&mut self,
dump_state: &DumpState,
) -> std::result::Result<(), GuestDebuggableError> {
let e_ident = [
elf::ELFMAG0 as u8, // magic
elf::ELFMAG1,
elf::ELFMAG2,
elf::ELFMAG3,
ELFCLASS64, // class
elf::ELFDATA2LSB as u8, //data
EV_CURRENT, // version
0, // os_abi
0, // abi_version
0, // padding
0,
0,
0,
0,
0,
0,
];
let elf64_ehdr_size = std::mem::size_of::<elf::Elf64_Ehdr>();
let elf64_phdr_size = std::mem::size_of::<elf::Elf64_Phdr>();
let mut elf64_ehdr = elf::Elf64_Ehdr {
e_ident,
e_type: ET_CORE,
e_machine: EM_X86_64,
e_version: EV_CURRENT as u32,
e_entry: 0,
e_phoff: elf64_ehdr_size as u64,
e_shoff: 0,
e_flags: 0,
e_ehsize: 0,
e_phentsize: elf64_phdr_size as u16,
e_phnum: dump_state.elf_phdr_num,
e_shentsize: 0,
e_shnum: 0,
e_shstrndx: 0,
};
elf64_ehdr.e_ehsize = std::mem::size_of_val(&elf64_ehdr) as u16;
let mut coredump_file = dump_state.file.as_ref().unwrap();
let bytes: &[u8] = elf64_ehdr.as_slice();
coredump_file
.write(bytes)
.map_err(GuestDebuggableError::CoredumpFile)?;
Ok(())
}
fn write_note(
&mut self,
dump_state: &DumpState,
) -> std::result::Result<(), GuestDebuggableError> {
let begin = dump_state.mem_offset - dump_state.elf_note_size as u64;
let elf64_phdr = elf::Elf64_Phdr {
p_type: elf::PT_NOTE,
p_flags: 0,
p_offset: begin,
p_vaddr: 0,
p_paddr: 0,
p_filesz: dump_state.elf_note_size as u64,
p_memsz: dump_state.elf_note_size as u64,
p_align: 0,
};
let mut coredump_file = dump_state.file.as_ref().unwrap();
let bytes: &[u8] = elf64_phdr.as_slice();
coredump_file
.write(bytes)
.map_err(GuestDebuggableError::CoredumpFile)?;
Ok(())
}
fn write_load(
&mut self,
offset: u64,
phys_addr: u64,
length: u64,
virt_addr: u64,
dump_state: &DumpState,
) -> std::result::Result<(), GuestDebuggableError> {
let elf64_load = elf::Elf64_Phdr {
p_type: elf::PT_LOAD,
p_flags: 0,
p_offset: offset,
p_vaddr: virt_addr,
p_paddr: phys_addr,
p_filesz: length,
p_memsz: length,
p_align: 0,
};
let mut coredump_file = dump_state.file.as_ref().unwrap();
let bytes: &[u8] = elf64_load.as_slice();
coredump_file
.write(bytes)
.map_err(GuestDebuggableError::CoredumpFile)?;
Ok(())
}
fn write_loads(
&mut self,
dump_state: &DumpState,
) -> std::result::Result<(), GuestDebuggableError> {
let mem_info = dump_state.mem_info.as_ref().unwrap();
for (gpa, load) in &mem_info.ram_maps {
self.write_load(load.mem_offset_in_elf, *gpa, load.mem_size, 0, dump_state)?;
}
Ok(())
}
fn elf_note_size(&self, hdr_size: u32, name_size: u32, desc_size: u32) -> u32 {
(div_round_up!(hdr_size, 4) + div_round_up!(name_size, 4) + div_round_up!(desc_size, 4)) * 4
}
fn get_note_size(&self, desc_type: NoteDescType, nr_cpus: u32) -> u32 {
let note_head_size = std::mem::size_of::<elf::Elf64_Nhdr>() as u32;
let elf_desc_size = std::mem::size_of::<X86_64ElfPrStatus>() as u32;
let cpu_state_desc_size = std::mem::size_of::<CpuState>() as u32;
let elf_note_size = self.elf_note_size(note_head_size, COREDUMP_NAME_SIZE, elf_desc_size);
let vmm_note_size =
self.elf_note_size(note_head_size, COREDUMP_NAME_SIZE, cpu_state_desc_size);
match desc_type {
NoteDescType::Elf => elf_note_size * nr_cpus,
NoteDescType::Vmm => vmm_note_size * nr_cpus,
NoteDescType::ElfAndVmm => (elf_note_size + vmm_note_size) * nr_cpus,
}
}
}
pub trait CpuElf64Writable {
fn cpu_write_elf64_note(
&mut self,
_dump_state: &DumpState,
) -> std::result::Result<(), GuestDebuggableError> {
Ok(())
}
fn cpu_write_vmm_note(
&mut self,
_dump_state: &DumpState,
) -> std::result::Result<(), GuestDebuggableError> {
Ok(())
}
}

View File

@@ -12,6 +12,12 @@
// //
use crate::config::CpusConfig; use crate::config::CpusConfig;
#[cfg(feature = "guest_debug")]
use crate::coredump::{
CpuElf64Writable, CpuSegment, CpuState as DumpCpusState, DumpState, Elf64Writable,
GuestDebuggableError, NoteDescType, X86_64ElfPrStatus, X86_64UserRegs, COREDUMP_NAME_SIZE,
NT_PRSTATUS,
};
use crate::device_manager::DeviceManager; use crate::device_manager::DeviceManager;
#[cfg(feature = "gdb")] #[cfg(feature = "gdb")]
use crate::gdb::{get_raw_tid, Debuggable, DebuggableError}; use crate::gdb::{get_raw_tid, Debuggable, DebuggableError};
@@ -28,24 +34,36 @@ use arch::NumaNodes;
use devices::interrupt_controller::InterruptController; use devices::interrupt_controller::InterruptController;
#[cfg(all(target_arch = "x86_64", feature = "gdb"))] #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
use gdbstub_arch::x86::reg::{X86SegmentRegs, X86_64CoreRegs}; use gdbstub_arch::x86::reg::{X86SegmentRegs, X86_64CoreRegs};
#[cfg(feature = "guest_debug")]
use hypervisor::arch::x86::msr_index;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use hypervisor::kvm::kvm_bindings; use hypervisor::kvm::kvm_bindings;
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
use hypervisor::kvm::{TdxExitDetails, TdxExitStatus}; use hypervisor::kvm::{TdxExitDetails, TdxExitStatus};
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use hypervisor::x86_64::CpuId; use hypervisor::x86_64::CpuId;
#[cfg(feature = "guest_debug")]
use hypervisor::x86_64::{MsrEntries, MsrEntry};
#[cfg(all(target_arch = "x86_64", feature = "gdb"))] #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
use hypervisor::x86_64::{SpecialRegisters, StandardRegisters}; use hypervisor::x86_64::{SpecialRegisters, StandardRegisters};
use hypervisor::{CpuState, HypervisorCpuError, VmExit, VmOps}; use hypervisor::{CpuState, HypervisorCpuError, VmExit, VmOps};
use libc::{c_void, siginfo_t}; use libc::{c_void, siginfo_t};
#[cfg(feature = "guest_debug")]
use linux_loader::elf::Elf64_Nhdr;
use seccompiler::{apply_filter, SeccompAction}; use seccompiler::{apply_filter, SeccompAction};
use std::collections::BTreeMap; use std::collections::BTreeMap;
#[cfg(feature = "guest_debug")]
use std::io::Write;
#[cfg(feature = "guest_debug")]
use std::mem::size_of;
use std::os::unix::thread::JoinHandleExt; use std::os::unix::thread::JoinHandleExt;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Barrier, Mutex}; use std::sync::{Arc, Barrier, Mutex};
use std::{cmp, io, result, thread}; use std::{cmp, io, result, thread};
use thiserror::Error; use thiserror::Error;
use vm_device::BusDevice; use vm_device::BusDevice;
#[cfg(feature = "guest_debug")]
use vm_memory::ByteValued;
#[cfg(feature = "gdb")] #[cfg(feature = "gdb")]
use vm_memory::{Bytes, GuestAddressSpace}; use vm_memory::{Bytes, GuestAddressSpace};
use vm_memory::{GuestAddress, GuestMemoryAtomic}; use vm_memory::{GuestAddress, GuestMemoryAtomic};
@@ -238,6 +256,13 @@ struct InterruptSourceOverride {
pub flags: u16, pub flags: u16,
} }
#[cfg(feature = "guest_debug")]
macro_rules! round_up {
($n:expr,$d:expr) => {
(($n / ($d + 1)) + 1) * $d
};
}
/// A wrapper around creating and using a kvm-based VCPU. /// A wrapper around creating and using a kvm-based VCPU.
pub struct Vcpu { pub struct Vcpu {
// The hypervisor abstracted CPU. // The hypervisor abstracted CPU.
@@ -350,43 +375,38 @@ impl Vcpu {
} }
const VCPU_SNAPSHOT_ID: &str = "vcpu"; const VCPU_SNAPSHOT_ID: &str = "vcpu";
impl Pausable for Vcpu { impl Pausable for Vcpu {}
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
self.saved_state =
Some(self.vcpu.state().map_err(|e| {
MigratableError::Pause(anyhow!("Could not get vCPU state {:?}", e))
})?);
Ok(())
}
fn resume(&mut self) -> std::result::Result<(), MigratableError> {
if let Some(vcpu_state) = &self.saved_state {
self.vcpu.set_state(vcpu_state).map_err(|e| {
MigratableError::Pause(anyhow!("Could not set the vCPU state {:?}", e))
})?;
}
Ok(())
}
}
impl Snapshottable for Vcpu { impl Snapshottable for Vcpu {
fn id(&self) -> String { fn id(&self) -> String {
VCPU_SNAPSHOT_ID.to_string() VCPU_SNAPSHOT_ID.to_string()
} }
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let mut vcpu_snapshot = Snapshot::new(&format!("{}", self.id)); let saved_state = self
.vcpu
.state()
.map_err(|e| MigratableError::Pause(anyhow!("Could not get vCPU state {:?}", e)))?;
let mut vcpu_snapshot = Snapshot::new(&format!("{:03}", self.id));
vcpu_snapshot.add_data_section(SnapshotDataSection::new_from_state( vcpu_snapshot.add_data_section(SnapshotDataSection::new_from_state(
VCPU_SNAPSHOT_ID, VCPU_SNAPSHOT_ID,
&self.saved_state, &saved_state,
)?); )?);
self.saved_state = Some(saved_state);
Ok(vcpu_snapshot) Ok(vcpu_snapshot)
} }
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
self.saved_state = Some(snapshot.to_state(VCPU_SNAPSHOT_ID)?); let saved_state: CpuState = snapshot.to_state(VCPU_SNAPSHOT_ID)?;
self.vcpu
.set_state(&saved_state)
.map_err(|e| MigratableError::Pause(anyhow!("Could not set the vCPU state {:?}", e)))?;
self.saved_state = Some(saved_state);
Ok(()) Ok(())
} }
} }
@@ -1251,7 +1271,7 @@ impl CpuManager {
1 << MADT_CPU_ENABLE_FLAG 1 << MADT_CPU_ENABLE_FLAG
} else { } else {
0 0
}, } | 1 << MADT_CPU_ONLINE_CAPABLE_FLAG,
}; };
madt.append(lapic); madt.append(lapic);
} }
@@ -1504,6 +1524,9 @@ struct Cpu {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
const MADT_CPU_ENABLE_FLAG: usize = 0; const MADT_CPU_ENABLE_FLAG: usize = 0;
#[cfg(target_arch = "x86_64")]
const MADT_CPU_ONLINE_CAPABLE_FLAG: usize = 1;
impl Cpu { impl Cpu {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn generate_mat(&self) -> Vec<u8> { fn generate_mat(&self) -> Vec<u8> {
@@ -2097,6 +2120,217 @@ impl Debuggable for CpuManager {
} }
} }
#[cfg(feature = "guest_debug")]
impl Elf64Writable for CpuManager {}
#[cfg(feature = "guest_debug")]
impl CpuElf64Writable for CpuManager {
fn cpu_write_elf64_note(
&mut self,
dump_state: &DumpState,
) -> std::result::Result<(), GuestDebuggableError> {
let mut coredump_file = dump_state.file.as_ref().unwrap();
for vcpu in &self.vcpus {
let note_size = self.get_note_size(NoteDescType::Elf, 1);
let mut pos: usize = 0;
let mut buf = vec![0; note_size as usize];
let descsz = size_of::<X86_64ElfPrStatus>();
let vcpu_id = vcpu.lock().unwrap().id;
let note = Elf64_Nhdr {
n_namesz: COREDUMP_NAME_SIZE,
n_descsz: descsz as u32,
n_type: NT_PRSTATUS,
};
let bytes: &[u8] = note.as_slice();
buf.splice(0.., bytes.to_vec());
pos += round_up!(size_of::<Elf64_Nhdr>(), 4);
buf.resize(pos + 4, 0);
buf.splice(pos.., "CORE".to_string().into_bytes());
pos += round_up!(COREDUMP_NAME_SIZE as usize, 4);
buf.resize(pos + 32 + 4, 0);
let pid = vcpu_id as u64;
let bytes: &[u8] = pid.as_slice();
buf.splice(pos + 32.., bytes.to_vec()); /* pr_pid */
pos += descsz - size_of::<X86_64UserRegs>() - size_of::<u64>();
let orig_rax: u64 = 0;
let gregs = self.vcpus[usize::from(vcpu_id)]
.lock()
.unwrap()
.vcpu
.get_regs()
.map_err(|_e| GuestDebuggableError::Coredump(anyhow!("get regs failed")))?;
let regs1 = [
gregs.r15, gregs.r14, gregs.r13, gregs.r12, gregs.rbp, gregs.rbx, gregs.r11,
gregs.r10,
];
let regs2 = [
gregs.r9, gregs.r8, gregs.rax, gregs.rcx, gregs.rdx, gregs.rsi, gregs.rdi, orig_rax,
];
let sregs = self.vcpus[usize::from(vcpu_id)]
.lock()
.unwrap()
.vcpu
.get_sregs()
.map_err(|_e| GuestDebuggableError::Coredump(anyhow!("get sregs failed")))?;
debug!(
"rip 0x{:x} rsp 0x{:x} gs 0x{:x} cs 0x{:x} ss 0x{:x} ds 0x{:x}",
gregs.rip,
gregs.rsp,
sregs.gs.base,
sregs.cs.selector,
sregs.ss.selector,
sregs.ds.selector,
);
let regs = X86_64UserRegs {
regs1,
regs2,
rip: gregs.rip,
cs: sregs.cs.selector as u64,
eflags: gregs.rflags,
rsp: gregs.rsp,
ss: sregs.ss.selector as u64,
fs_base: sregs.fs.base as u64,
gs_base: sregs.gs.base as u64,
ds: sregs.ds.selector as u64,
es: sregs.es.selector as u64,
fs: sregs.fs.selector as u64,
gs: sregs.gs.selector as u64,
};
// let bytes: &[u8] = unsafe { any_as_u8_slice(&regs) };
let bytes: &[u8] = regs.as_slice();
buf.resize(note_size as usize, 0);
buf.splice(pos.., bytes.to_vec());
buf.resize(note_size as usize, 0);
coredump_file
.write(&buf)
.map_err(GuestDebuggableError::CoredumpFile)?;
}
Ok(())
}
fn cpu_write_vmm_note(
&mut self,
dump_state: &DumpState,
) -> std::result::Result<(), GuestDebuggableError> {
let mut coredump_file = dump_state.file.as_ref().unwrap();
for vcpu in &self.vcpus {
let note_size = self.get_note_size(NoteDescType::Vmm, 1);
let mut pos: usize = 0;
let mut buf = vec![0; note_size as usize];
let descsz = size_of::<DumpCpusState>();
let vcpu_id = vcpu.lock().unwrap().id;
let note = Elf64_Nhdr {
n_namesz: COREDUMP_NAME_SIZE,
n_descsz: descsz as u32,
n_type: 0,
};
let bytes: &[u8] = note.as_slice();
buf.splice(0.., bytes.to_vec());
pos += round_up!(size_of::<Elf64_Nhdr>(), 4);
buf.resize(pos + 4, 0);
buf.splice(pos.., "QEMU".to_string().into_bytes());
pos += round_up!(COREDUMP_NAME_SIZE as usize, 4);
let gregs = self.vcpus[usize::from(vcpu_id)]
.lock()
.unwrap()
.vcpu
.get_regs()
.map_err(|_e| GuestDebuggableError::Coredump(anyhow!("get regs failed")))?;
let regs1 = [
gregs.rax, gregs.rbx, gregs.rcx, gregs.rdx, gregs.rsi, gregs.rdi, gregs.rsp,
gregs.rbp,
];
let regs2 = [
gregs.r8, gregs.r9, gregs.r10, gregs.r11, gregs.r12, gregs.r13, gregs.r14,
gregs.r15,
];
let sregs = self.vcpus[usize::from(vcpu_id)]
.lock()
.unwrap()
.vcpu
.get_sregs()
.map_err(|_e| GuestDebuggableError::Coredump(anyhow!("get sregs failed")))?;
let mut msrs = MsrEntries::from_entries(&[MsrEntry {
index: msr_index::MSR_KERNEL_GS_BASE,
..Default::default()
}])
.map_err(|_e| GuestDebuggableError::Coredump(anyhow!("get msr failed")))?;
self.vcpus[vcpu_id as usize]
.lock()
.unwrap()
.vcpu
.get_msrs(&mut msrs)
.map_err(|_e| GuestDebuggableError::Coredump(anyhow!("get msr failed")))?;
let kernel_gs_base = msrs.as_slice()[0].data;
let cs = CpuSegment::new(sregs.cs);
let ds = CpuSegment::new(sregs.ds);
let es = CpuSegment::new(sregs.es);
let fs = CpuSegment::new(sregs.fs);
let gs = CpuSegment::new(sregs.gs);
let ss = CpuSegment::new(sregs.ss);
let ldt = CpuSegment::new(sregs.ldt);
let tr = CpuSegment::new(sregs.tr);
let gdt = CpuSegment::new_from_table(sregs.gdt);
let idt = CpuSegment::new_from_table(sregs.idt);
let cr = [sregs.cr0, sregs.cr8, sregs.cr2, sregs.cr3, sregs.cr4];
let regs = DumpCpusState {
version: 1,
size: size_of::<DumpCpusState>() as u32,
regs1,
regs2,
rip: gregs.rip,
rflags: gregs.rflags,
cs,
ds,
es,
fs,
gs,
ss,
ldt,
tr,
gdt,
idt,
cr,
kernel_gs_base,
};
let bytes: &[u8] = regs.as_slice();
buf.resize(note_size as usize, 0);
buf.splice(pos.., bytes.to_vec());
buf.resize(note_size as usize, 0);
coredump_file
.write(&buf)
.map_err(GuestDebuggableError::CoredumpFile)?;
}
Ok(())
}
}
#[cfg(all(feature = "kvm", target_arch = "x86_64"))] #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@@ -2205,7 +2439,7 @@ mod tests {
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use arch::aarch64::regs::*; use arch::layout;
use hypervisor::kvm::aarch64::{is_system_register, MPIDR_EL1}; use hypervisor::kvm::aarch64::{is_system_register, MPIDR_EL1};
use hypervisor::kvm::kvm_bindings::{ use hypervisor::kvm::kvm_bindings::{
kvm_one_reg, kvm_regs, kvm_vcpu_init, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG, kvm_one_reg, kvm_regs, kvm_vcpu_init, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG,
@@ -2220,7 +2454,7 @@ mod tests {
let vm = hv.create_vm().unwrap(); let vm = hv.create_vm().unwrap();
let vcpu = vm.create_vcpu(0, None).unwrap(); let vcpu = vm.create_vcpu(0, None).unwrap();
let res = setup_regs(&vcpu, 0, 0x0); let res = vcpu.setup_regs(0, 0x0, layout::FDT_START.0);
// Must fail when vcpu is not initialized yet. // Must fail when vcpu is not initialized yet.
assert!(res.is_err()); assert!(res.is_err());
@@ -2228,7 +2462,7 @@ mod tests {
vm.get_preferred_target(&mut kvi).unwrap(); vm.get_preferred_target(&mut kvi).unwrap();
vcpu.vcpu_init(&kvi).unwrap(); vcpu.vcpu_init(&kvi).unwrap();
assert!(setup_regs(&vcpu, 0, 0x0).is_ok()); assert!(vcpu.setup_regs(0, 0x0, layout::FDT_START.0).is_ok());
} }
#[test] #[test]

View File

@@ -16,8 +16,7 @@ use crate::config::{
use crate::device_tree::{DeviceNode, DeviceTree}; use crate::device_tree::{DeviceNode, DeviceTree};
use crate::interrupt::LegacyUserspaceInterruptManager; use crate::interrupt::LegacyUserspaceInterruptManager;
use crate::interrupt::MsiInterruptManager; use crate::interrupt::MsiInterruptManager;
use crate::memory_manager::MEMORY_MANAGER_ACPI_SIZE; use crate::memory_manager::{Error as MemoryManagerError, MemoryManager, MEMORY_MANAGER_ACPI_SIZE};
use crate::memory_manager::{Error as MemoryManagerError, MemoryManager};
use crate::pci_segment::PciSegment; use crate::pci_segment::PciSegment;
use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::serial_manager::{Error as SerialManagerError, SerialManager}; use crate::serial_manager::{Error as SerialManagerError, SerialManager};
@@ -29,8 +28,6 @@ use crate::PciDeviceInfo;
use crate::{device_node, DEVICE_MANAGER_SNAPSHOT_ID}; use crate::{device_node, DEVICE_MANAGER_SNAPSHOT_ID};
use acpi_tables::{aml, aml::Aml}; use acpi_tables::{aml, aml::Aml};
use anyhow::anyhow; use anyhow::anyhow;
#[cfg(target_arch = "aarch64")]
use arch::aarch64::gic::gicv3_its::kvm::KvmGicV3Its;
use arch::layout; use arch::layout;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use arch::layout::{APIC_START, IOAPIC_SIZE, IOAPIC_START}; use arch::layout::{APIC_START, IOAPIC_SIZE, IOAPIC_START};
@@ -79,12 +76,13 @@ use std::result;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::Instant; use std::time::Instant;
use vfio_ioctls::{VfioContainer, VfioDevice}; use vfio_ioctls::{VfioContainer, VfioDevice};
use virtio_devices::transport::VirtioPciDevice;
use virtio_devices::transport::VirtioTransport; use virtio_devices::transport::VirtioTransport;
use virtio_devices::transport::{VirtioPciDevice, VirtioPciDeviceActivator};
use virtio_devices::vhost_user::VhostUserConfig; use virtio_devices::vhost_user::VhostUserConfig;
use virtio_devices::{AccessPlatformMapping, VdpaDmaMapping, VirtioMemMappingSource}; use virtio_devices::{
AccessPlatformMapping, ActivateError, VdpaDmaMapping, VirtioMemMappingSource,
};
use virtio_devices::{Endpoint, IommuMapping}; use virtio_devices::{Endpoint, IommuMapping};
use virtio_devices::{VirtioSharedMemory, VirtioSharedMemoryList};
use vm_allocator::{AddressAllocator, SystemAllocator}; use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_device::dma_mapping::vfio::VfioDmaMapping; use vm_device::dma_mapping::vfio::VfioDmaMapping;
use vm_device::dma_mapping::ExternalDmaMapping; use vm_device::dma_mapping::ExternalDmaMapping;
@@ -359,9 +357,6 @@ pub enum DeviceManagerError {
/// Could not give the PCI device ID back. /// Could not give the PCI device ID back.
PutPciDeviceId(pci::PciRootError), PutPciDeviceId(pci::PciRootError),
/// Incorrect device ID as it is already used by another device.
DeviceIdAlreadyInUse,
/// No disk path was specified when one was expected /// No disk path was specified when one was expected
NoDiskPath, NoDiskPath,
@@ -476,6 +471,9 @@ pub enum DeviceManagerError {
/// Invalid identifier /// Invalid identifier
InvalidIdentifier(String), InvalidIdentifier(String),
/// Error activating virtio device
VirtioActivate(ActivateError),
} }
pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>; pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
@@ -939,6 +937,9 @@ pub struct DeviceManager {
// Start time of the VM // Start time of the VM
timestamp: Instant, timestamp: Instant,
// Pending activations
pending_activations: Arc<Mutex<Vec<VirtioPciDeviceActivator>>>,
} }
impl DeviceManager { impl DeviceManager {
@@ -1080,6 +1081,7 @@ impl DeviceManager {
io_uring_supported: None, io_uring_supported: None,
boot_id_list, boot_id_list,
timestamp, timestamp,
pending_activations: Arc::new(Mutex::new(Vec::default())),
}; };
let device_manager = Arc::new(Mutex::new(device_manager)); let device_manager = Arc::new(Mutex::new(device_manager));
@@ -2394,109 +2396,7 @@ impl DeviceManager {
let mut node = device_node!(id); let mut node = device_node!(id);
// Look for the id in the device tree. If it can be found, that means
// the device is being restored, otherwise it's created from scratch.
let cache_range = if let Some(node) = self.device_tree.lock().unwrap().get(&id) {
info!("Restoring virtio-fs {} resources", id);
let mut cache_range: Option<(u64, u64)> = None;
for resource in node.resources.iter() {
match resource {
Resource::MmioAddressRange { base, size } => {
if cache_range.is_some() {
return Err(DeviceManagerError::ResourceAlreadyExists);
}
cache_range = Some((*base, *size));
}
_ => {
error!("Unexpected resource {:?} for {}", resource, id);
}
}
}
cache_range
} else {
None
};
// DAX is not supported, we override the config by disabling the option.
fs_cfg.dax = false;
if let Some(fs_socket) = fs_cfg.socket.to_str() { if let Some(fs_socket) = fs_cfg.socket.to_str() {
let cache = if fs_cfg.dax {
let (cache_base, cache_size) = if let Some((base, size)) = cache_range {
// The memory needs to be 2MiB aligned in order to support
// hugepages.
self.pci_segments[fs_cfg.pci_segment as usize]
.allocator
.lock()
.unwrap()
.allocate(
Some(GuestAddress(base)),
size as GuestUsize,
Some(0x0020_0000),
)
.ok_or(DeviceManagerError::FsRangeAllocation)?;
(base, size)
} else {
let size = fs_cfg.cache_size;
// The memory needs to be 2MiB aligned in order to support
// hugepages.
let base = self.pci_segments[fs_cfg.pci_segment as usize]
.allocator
.lock()
.unwrap()
.allocate(None, size as GuestUsize, Some(0x0020_0000))
.ok_or(DeviceManagerError::FsRangeAllocation)?;
(base.raw_value(), size)
};
// Update the node with correct resource information.
node.resources.push(Resource::MmioAddressRange {
base: cache_base,
size: cache_size,
});
let mmap_region = MmapRegion::build(
None,
cache_size as usize,
libc::PROT_NONE,
libc::MAP_ANONYMOUS | libc::MAP_PRIVATE,
)
.map_err(DeviceManagerError::NewMmapRegion)?;
let host_addr: u64 = mmap_region.as_ptr() as u64;
let mem_slot = self
.memory_manager
.lock()
.unwrap()
.create_userspace_mapping(
cache_base, cache_size, host_addr, false, false, false,
)
.map_err(DeviceManagerError::MemoryManager)?;
let region_list = vec![VirtioSharedMemory {
offset: 0,
len: cache_size,
}];
Some((
VirtioSharedMemoryList {
host_addr,
mem_slot,
addr: GuestAddress(cache_base),
len: cache_size as GuestUsize,
region_list,
},
mmap_region,
))
} else {
None
};
let virtio_fs_device = Arc::new(Mutex::new( let virtio_fs_device = Arc::new(Mutex::new(
virtio_devices::vhost_user::Fs::new( virtio_devices::vhost_user::Fs::new(
id.clone(), id.clone(),
@@ -2504,7 +2404,7 @@ impl DeviceManager {
&fs_cfg.tag, &fs_cfg.tag,
fs_cfg.num_queues, fs_cfg.num_queues,
fs_cfg.queue_size, fs_cfg.queue_size,
cache, None,
self.seccomp_action.clone(), self.seccomp_action.clone(),
self.restoring, self.restoring,
self.exit_evt self.exit_evt
@@ -3074,10 +2974,6 @@ impl DeviceManager {
device_cfg: &mut DeviceConfig, device_cfg: &mut DeviceConfig,
) -> DeviceManagerResult<(PciBdf, String)> { ) -> DeviceManagerResult<(PciBdf, String)> {
let vfio_name = if let Some(id) = &device_cfg.id { let vfio_name = if let Some(id) = &device_cfg.id {
if self.device_tree.lock().unwrap().contains_key(id) {
return Err(DeviceManagerError::DeviceIdAlreadyInUse);
}
id.clone() id.clone()
} else { } else {
let id = self.next_device_name(VFIO_DEVICE_NAME_PREFIX)?; let id = self.next_device_name(VFIO_DEVICE_NAME_PREFIX)?;
@@ -3177,6 +3073,8 @@ impl DeviceManager {
None None
}; };
let memory_manager = self.memory_manager.clone();
let vfio_pci_device = VfioPciDevice::new( let vfio_pci_device = VfioPciDevice::new(
vfio_name.clone(), vfio_name.clone(),
&self.address_manager.vm, &self.address_manager.vm,
@@ -3186,6 +3084,8 @@ impl DeviceManager {
legacy_interrupt_group, legacy_interrupt_group,
device_cfg.iommu, device_cfg.iommu,
pci_device_bdf, pci_device_bdf,
self.restoring,
Arc::new(move || memory_manager.lock().unwrap().allocate_memory_slot()),
) )
.map_err(DeviceManagerError::VfioPciCreate)?; .map_err(DeviceManagerError::VfioPciCreate)?;
@@ -3199,15 +3099,17 @@ impl DeviceManager {
resources, resources,
)?; )?;
vfio_pci_device // When restoring a VM, the restore codepath will take care of mapping
.lock() // the MMIO regions based on the information from the snapshot.
.unwrap() if !self.restoring {
.map_mmio_regions(&self.address_manager.vm, || { vfio_pci_device
self.memory_manager.lock().unwrap().allocate_memory_slot() .lock()
}) .unwrap()
.map_err(DeviceManagerError::VfioMapRegion)?; .map_mmio_regions()
.map_err(DeviceManagerError::VfioMapRegion)?;
}
let mut node = device_node!(vfio_name); let mut node = device_node!(vfio_name, vfio_pci_device);
// Update the device tree with correct resource information. // Update the device tree with correct resource information.
node.resources = new_resources; node.resources = new_resources;
@@ -3302,10 +3204,6 @@ impl DeviceManager {
device_cfg: &mut UserDeviceConfig, device_cfg: &mut UserDeviceConfig,
) -> DeviceManagerResult<(PciBdf, String)> { ) -> DeviceManagerResult<(PciBdf, String)> {
let vfio_user_name = if let Some(id) = &device_cfg.id { let vfio_user_name = if let Some(id) = &device_cfg.id {
if self.device_tree.lock().unwrap().contains_key(id) {
return Err(DeviceManagerError::DeviceIdAlreadyInUse);
}
id.clone() id.clone()
} else { } else {
let id = self.next_device_name(VFIO_USER_DEVICE_NAME_PREFIX)?; let id = self.next_device_name(VFIO_USER_DEVICE_NAME_PREFIX)?;
@@ -3336,6 +3234,8 @@ impl DeviceManager {
.map_err(DeviceManagerError::VfioUserCreateClient)?, .map_err(DeviceManagerError::VfioUserCreateClient)?,
)); ));
let memory_manager = self.memory_manager.clone();
let mut vfio_user_pci_device = VfioUserPciDevice::new( let mut vfio_user_pci_device = VfioUserPciDevice::new(
vfio_user_name.clone(), vfio_user_name.clone(),
&self.address_manager.vm, &self.address_manager.vm,
@@ -3343,6 +3243,8 @@ impl DeviceManager {
self.msi_interrupt_manager.clone(), self.msi_interrupt_manager.clone(),
legacy_interrupt_group, legacy_interrupt_group,
pci_device_bdf, pci_device_bdf,
self.restoring,
Arc::new(move || memory_manager.lock().unwrap().allocate_memory_slot()),
) )
.map_err(DeviceManagerError::VfioUserCreate)?; .map_err(DeviceManagerError::VfioUserCreate)?;
@@ -3377,17 +3279,19 @@ impl DeviceManager {
resources, resources,
)?; )?;
// Note it is required to call 'add_pci_device()' in advance to have the list of // When restoring a VM, the restore codepath will take care of mapping
// mmio regions provisioned correctly // the MMIO regions based on the information from the snapshot.
vfio_user_pci_device if !self.restoring {
.lock() // Note it is required to call 'add_pci_device()' in advance to have the list of
.unwrap() // mmio regions provisioned correctly
.map_mmio_regions(&self.address_manager.vm, || { vfio_user_pci_device
self.memory_manager.lock().unwrap().allocate_memory_slot() .lock()
}) .unwrap()
.map_err(DeviceManagerError::VfioUserMapRegion)?; .map_mmio_regions()
.map_err(DeviceManagerError::VfioUserMapRegion)?;
}
let mut node = device_node!(vfio_user_name); let mut node = device_node!(vfio_user_name, vfio_user_pci_device);
// Update the device tree with correct resource information. // Update the device tree with correct resource information.
node.resources = new_resources; node.resources = new_resources;
@@ -3520,6 +3424,7 @@ impl DeviceManager {
// The exception being if not on the default PCI segment. // The exception being if not on the default PCI segment.
pci_segment_id > 0 || device_type != VirtioDeviceType::Block as u32, pci_segment_id > 0 || device_type != VirtioDeviceType::Block as u32,
dma_handler, dma_handler,
self.pending_activations.clone(),
) )
.map_err(DeviceManagerError::VirtioDevice)?, .map_err(DeviceManagerError::VirtioDevice)?,
)); ));
@@ -3674,17 +3579,10 @@ impl DeviceManager {
} }
pub fn activate_virtio_devices(&self) -> DeviceManagerResult<()> { pub fn activate_virtio_devices(&self) -> DeviceManagerResult<()> {
// Find virtio pci devices and activate any pending ones for mut activator in self.pending_activations.lock().unwrap().drain(..) {
let device_tree = self.device_tree.lock().unwrap(); activator
for pci_device_node in device_tree.pci_devices() { .activate()
#[allow(irrefutable_let_patterns)] .map_err(DeviceManagerError::VirtioActivate)?;
if let PciDeviceHandle::Virtio(virtio_pci_device) = &pci_device_node
.pci_device_handle
.as_ref()
.ok_or(DeviceManagerError::MissingPciDevice)?
{
virtio_pci_device.lock().unwrap().maybe_activate();
}
} }
Ok(()) Ok(())
} }
@@ -4427,26 +4325,11 @@ impl Pausable for DeviceManager {
// and ITS tables to guest RAM. // and ITS tables to guest RAM.
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
{ {
let gic_device = Arc::clone( self.get_interrupt_controller()
self.get_interrupt_controller() .unwrap()
.unwrap()
.lock()
.unwrap()
.get_gic_device()
.unwrap(),
);
if let Some(gicv3_its) = gic_device
.lock() .lock()
.unwrap() .unwrap()
.as_any_concrete_mut() .pause()?;
.downcast_mut::<KvmGicV3Its>()
{
gicv3_its.pause()?;
} else {
return Err(MigratableError::Pause(anyhow!(
"GicDevice downcast to KvmGicV3Its failed when pausing device manager!"
)));
};
}; };
Ok(()) Ok(())

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