Compare commits

...

237 Commits
v28.4 ... v29.0

Author SHA1 Message Date
Rob Bradford
6e9172bf6f .github: Re-order release steps to ensure binaries are available
Since we run "cargo clean" before running the aarch64 build we need to
create the release and upload the x86-64 assets before the clean.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-14 12:12:11 +00:00
Rob Bradford
22cf8c97e5 build: Release v29.0
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-13 17:10:35 +00:00
Wei Liu
9e6301be70 Reland: build: drop clap from dev-dependencies
Some crates don't need it at all.

Some crates are using it for a simple functionality which can be
replaced easily.

Signed-off-by: Wei Liu <liuwe@microsoft.com>

This was causing issues with the release build process but we now have a
fix to clean residual build assets.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-13 16:44:59 +00:00
Rob Bradford
547230bb77 .github: Clean source tree before cross building release assets
This address issues with leaking symbols into the cross build.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-13 16:44:59 +00:00
Rob Bradford
ef7e177df2 .github: Run release style builds on all PRs
Adjust the release workflow to move the conditional check on the tag
creation into the steps that create the release/upload the assets.

This allows us to ensure we're always in a releaseable state.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-13 14:38:15 +00:00
Rob Bradford
375e094c77 Revert "build: drop clap from dev-dependencies"
This reverts commit 998fb48ff2.

This is breaking the release build process (cross build for aarch64
musl) so temporarily reverting until we can identify the cause to allow
the release proceeed.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-13 14:38:15 +00:00
dependabot[bot]
3df82337f1 build: Bump thiserror from 1.0.37 to 1.0.38
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.37 to 1.0.38.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/1.0.37...1.0.38)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-13 01:34:59 +00:00
dependabot[bot]
0e273e8b0d build: Bump once_cell from 1.16.0 to 1.17.0 in /fuzz
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.16.0 to 1.17.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.16.0...v1.17.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>
2023-01-13 00:34:13 +00:00
Philipp Schuster
ad6c0ee52b virtio-devices: properly join all threads on Drop
This change is important to do a proper resource cleanup. We decided
to do this repetitive approach as VirtioCommon can't implement Drop
without major changes to the corresponding code. Also, devices such as
Net can't easily use the epoll_threads-abstraction from VirtioCommon as
it has multiple threads with different semantics.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
2023-01-12 18:03:33 +00:00
dependabot[bot]
b1f6a59579 build: Bump semver from 1.0.14 to 1.0.16
Bumps [semver](https://github.com/dtolnay/semver) from 1.0.14 to 1.0.16.
- [Release notes](https://github.com/dtolnay/semver/releases)
- [Commits](https://github.com/dtolnay/semver/compare/1.0.14...1.0.16)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-12 12:54:36 +00:00
Yong He
3494080e2f vmm: add configuration for network offloading features
Add new configuration for offloading features, including
Checksum/TSO/UFO, and set these offloading features as
enabled by default.

Fixes: #4792.

Signed-off-by: Yong He <alexyonghe@tencent.com>
2023-01-12 09:05:45 +00:00
Muminul Islam
06e583c9ab vmm: move kvm feature gate right before the if condition
This change uses the kvm feature gate cleaner way
in the handling of PIO/MMIO exits.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2023-01-12 09:03:28 +01:00
Muminul Islam
7d8f795430 hypervisor: remove unnecessary derive of HypervisorType
There was an unnecessary change in previous PR #5077.
This is the follow-up clean up patch.

Right now there is no use case of the drive of
Eq and PartialEq.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2023-01-12 09:03:28 +01:00
dependabot[bot]
f8c6d7fe37 build: Bump micro_http from 4b18a04 to fbef706 in /fuzz
Bumps [micro_http](https://github.com/firecracker-microvm/micro-http) from `4b18a04` to `fbef706`.
- [Release notes](https://github.com/firecracker-microvm/micro-http/releases)
- [Commits](4b18a043e9...fbef706e28)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-11 23:19:57 +00:00
Yong He
0dc122a9a9 virto-device: add latency account for virtio-block
Add new latency counters for virtio-block device, including
minimal latency, maximal latency, and average latency for block
read and write.

The average latency is calculated based on cumulative average.

Signed-off-by: Yong He <alexyonghe@tencent.com>
2023-01-11 17:38:42 +00:00
Yong He
e2ea9e2821 block_util: add timestamp in request
Add timestamp per request, so that we could account
block process latency base request.

Signed-off-by: Yong He <alexyonghe@tencent.com>
2023-01-11 17:38:42 +00:00
Muminul Islam
4e3bc20f2c vmm: Ensure PIO/MMIO exits complete before pausing only for KVM
MSHV does not require to ensure MMIO/PIO exits complete
before pausing. This patch makes sure the above requirement
by checking the hypervisor type run-time.

Fixes #5037

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2023-01-11 17:15:56 +00:00
Rob Bradford
e661139e1e arch: Print details of host hypervisor status & address space size
e.g. on QEMU on KVM:

cloud-hypervisor: 17.079406ms: <vmm> INFO:arch/src/x86_64/mod.rs:565 -- Running under nested virtualisation. Hypervisor string: KVMKVMKVM

Or under Azure:

cloud-hypervisor: 3.881263ms: <vmm> INFO:arch/src/x86_64/mod.rs:565 -- Running under nested virtualisation. Hypervisor string: Microsoft Hv

Fixes: #5067

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-11 14:38:22 +00:00
dependabot[bot]
c99a5fc7a5 build: Bump io-uring from 0.5.9 to 0.5.11
Bumps [io-uring](https://github.com/tokio-rs/io-uring) from 0.5.9 to 0.5.11.
- [Release notes](https://github.com/tokio-rs/io-uring/releases)
- [Commits](https://github.com/tokio-rs/io-uring/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-10 23:41:07 +00:00
dependabot[bot]
5b2adb398a build: Bump serde_with_macros from 2.1.0 to 2.2.0 in /fuzz
Bumps [serde_with_macros](https://github.com/jonasbb/serde_with) from 2.1.0 to 2.2.0.
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v2.1.0...v2.2.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-10 23:18:05 +00:00
Rob Bradford
db5582f7d1 block_util: Preserve ordering of sync file backend completions
For the synchronous backends efficiently preserve the order for
completion requests through the use of VecDequeue. Preserving the order
is not required but is beneficial as it matches the existing
optimisation that looks to match completions and requests.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-10 17:30:25 +00:00
Rob Bradford
ce51755109 block_util: Avoid intermediate completion queue allocation
Rather than aggregate the completion list into an intermediate vector
instead adjust the API to provide one completion item at a time.

With DHAT this shows the number of heap allocations has decreased.

Before:

    dhat: Total:     623,852 bytes in 8,157 blocks

After:

    dhat: Total:     380,444 bytes in 3,469 blocks

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-10 17:30:25 +00:00
Rob Bradford
67ff0d7819 block_util: Use SmallVec for I/O requests
The number of buffers in the request is usually one so by using SmallVec
the number of heap allocations can be significantly reduced.

DHAT reports:

Before:

dhat: Total:     1,166,412 bytes in 40,383 blocks

After:

dhat: Total:     623,852 bytes in 8,157 blocks

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-10 17:30:25 +00:00
Rob Bradford
e7a51cde78 block_util: Pass a reference to the slice of iovecs
Rather than passing the vector of iovecs for the I/O to act on pass a
reference to the slice of values inside them. This removes the explicit
container type from the API allowing the use of e.g. SmallVec.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-10 17:30:25 +00:00
Rob Bradford
9ba06ce5f5 vmm: memory_manager: Deprecate directory backing for memory
This functionality has been obsoleted by our native support for
hugepages and shared memory.

See: #5082

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-10 15:08:34 +00:00
Sebastien Boeuf
0e7d5d2761 qcow: Fix number of refcount table entries
The number of entries in the refcount table was incorrectly calculated
given there was no need for dividing the number of refblock clusters.
The number of refblock clusters is the number of entries in the refcount
table.

Suggested-by: lv_mz <lv.mengzhao@zte.com.cn>
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2023-01-10 12:05:15 +00:00
Rob Bradford
ba9554389b virtio-devices: block: Replace use of HashMap for inflight requests
During analysis of the asynchrous block I/O handling it was observed
that the majority of the time the completion events occur in the same
order as submissions. Further the maximum number of inflight requests
during the boot time is much lower than the size of the queue.

Through the use of a double ended queue (VecDequeue) with a reasonable
pre-allocation capacity we can have O(1) allocation free addition of
items to the list of inflight requests and mostly O(1) matching of
completed requests to submissions.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-10 10:41:24 +00:00
Rob Bradford
c89b8e061f Revert "vmm: Deprecate MemoryZoneConfig::file"
This reverts commit 9fb0274479.

A user was identified of this functionality.

See: #4837
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-10 10:31:18 +00:00
Sebastien Boeuf
c2450bd055 tests: Remove unnecessary filename
Since SGX testing doesn't rely on a custom guest image anymore, there's
no need to keep the custom filename around as it's already not in use.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2023-01-10 09:22:59 +00:00
dependabot[bot]
bae9799259 build: Bump mshv-bindings from dda85d3 to fb19bb3
Bumps [mshv-bindings](https://github.com/rust-vmm/mshv) from `dda85d3` to `fb19bb3`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](dda85d32b9...fb19bb3011)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-09 23:45:35 +00:00
dependabot[bot]
3dd487c2cf build: Bump syn from 1.0.105 to 1.0.107 in /fuzz
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.105 to 1.0.107.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.105...1.0.107)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-09 23:24:11 +00:00
Rob Bradford
eb87538100 block_util: Avoid reallocation of Vec on push
When using DHAT[1] for analysis the amount heap allocations change from:

dhat: Total:     3,186,536 bytes in 41,452 blocks

 to

dhat: Total:     1,059,816 bytes in 34,747 blocks

When running against virtio-block; this still more allocations than
virtio-pmem but a significant improvement without any cost.

[1] https://docs.rs/dhat/latest/dhat/

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-09 10:41:56 -08:00
Philipp Schuster
9e8296b696 log: align log message timestamp
With this change, all log messages will have the same width for the
timestamp. The number of ms is rounded to 6 decimal places.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
2023-01-09 16:38:29 +01:00
Philipp Schuster
0dc3282ae0 lifecycle: align "KILL_EVENT received" messages across code-base
To align the logging messages with the rest of the code, this
message should be aligned with another similar occurrence in
epoll_helper.rs

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
2023-01-09 15:16:48 +00:00
dependabot[bot]
67340c5295 build: Bump clap from 4.0.29 to 4.0.32
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.29 to 4.0.32.
- [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/v4.0.29...v4.0.32)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-06 23:41:55 +00:00
dependabot[bot]
160ea00d6b build: Bump ryu from 1.0.11 to 1.0.12 in /fuzz
Bumps [ryu](https://github.com/dtolnay/ryu) from 1.0.11 to 1.0.12.
- [Release notes](https://github.com/dtolnay/ryu/releases)
- [Commits](https://github.com/dtolnay/ryu/compare/1.0.11...1.0.12)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-06 23:14:20 +00:00
Wei Liu
0389190c64 build: drop the need to import macros from Clap
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-06 13:06:16 -08:00
Wei Liu
998fb48ff2 build: drop clap from dev-dependencies
Some crates don't need it at all.

Some crates are using it for a simple functionality which can be
replaced easily.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-06 13:06:16 -08:00
Wei Liu
03d8a3ebcf performance-metrics: add metrics for UDP PPS
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-06 11:03:08 +00:00
Wei Liu
08e4d1f481 test_infra: make measure_virtio_net_throughput & co measure PPS too
While measuring UDP PPS, we saturate the link, so there are packets
lost. We only account for the packets that are not lost.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-06 11:03:08 +00:00
Wei Liu
d50a4cbb6b test_infra: do not output interval values for iperf3
We only care about the end result.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-06 11:03:08 +00:00
dependabot[bot]
28eeb8a492 build: Bump libc from 0.2.138 to 0.2.139
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.138 to 0.2.139.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.138...0.2.139)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-05 23:41:28 +00:00
dependabot[bot]
ec3520d8b2 build: Bump semver from 1.0.14 to 1.0.16 in /fuzz
Bumps [semver](https://github.com/dtolnay/semver) from 1.0.14 to 1.0.16.
- [Release notes](https://github.com/dtolnay/semver/releases)
- [Commits](https://github.com/dtolnay/semver/compare/1.0.14...1.0.16)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-05 23:14:59 +00:00
Rob Bradford
19661d36af build: Re-enable Jenkins bare metal workers
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-05 17:55:03 +00:00
dependabot[bot]
9747cd1059 build: Bump remain from 0.2.5 to 0.2.6
Bumps [remain](https://github.com/dtolnay/remain) from 0.2.5 to 0.2.6.
- [Release notes](https://github.com/dtolnay/remain/releases)
- [Commits](https://github.com/dtolnay/remain/compare/0.2.5...0.2.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-04 23:40:40 +00:00
dependabot[bot]
0bdc7dcc1c build: Bump proc-macro2 from 1.0.47 to 1.0.49 in /fuzz
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.47 to 1.0.49.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.47...1.0.49)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-04 23:18:36 +00:00
Wei Liu
e16817ea14 performance-metrics: add IOPS tests for FIO
Change fio_ops to fio_control and add a new field to indicate whether it
should report bandwidth or IOPS.

All existing tests are bandwidth tests. Adapt the code accordingly. Add
a set of new tests to report IOPS.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2023-01-04 09:47:44 +00:00
dependabot[bot]
3de0a6d401 build: Bump iced-x86 from 1.17.0 to 1.18.0
Bumps [iced-x86](https://github.com/icedland/iced) from 1.17.0 to 1.18.0.
- [Release notes](https://github.com/icedland/iced/releases)
- [Commits](https://github.com/icedland/iced/compare/v1.17.0...v1.18.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-03 23:41:28 +00:00
dependabot[bot]
bb9c5e5faf build: Bump serde from 1.0.151 to 1.0.152 in /fuzz
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.151 to 1.0.152.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.151...v1.0.152)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-03 23:12:47 +00:00
Rob Bradford
0036302fc9 tests: Remove support for Ubuntu Bionic
This OS is EOL this year and is well tested by the Rust Hypervisor
Firmware CI so there is no need to duplicate this effort.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2023-01-03 14:42:24 +01:00
dependabot[bot]
b4ec59cb0c build: Bump openssl-sys from 0.9.79 to 0.9.80
Bumps [openssl-sys](https://github.com/sfackler/rust-openssl) from 0.9.79 to 0.9.80.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.79...openssl-sys-v0.9.80)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-03 12:20:54 +00:00
dependabot[bot]
8511603fdb build: Bump io-uring from 0.5.9 to 0.5.11 in /fuzz
Bumps [io-uring](https://github.com/tokio-rs/io-uring) from 0.5.9 to 0.5.11.
- [Release notes](https://github.com/tokio-rs/io-uring/releases)
- [Commits](https://github.com/tokio-rs/io-uring/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-02 23:13:05 +00:00
dependabot[bot]
df6e17840a build: Bump remain from 0.2.5 to 0.2.6 in /fuzz
Bumps [remain](https://github.com/dtolnay/remain) from 0.2.5 to 0.2.6.
- [Release notes](https://github.com/dtolnay/remain/releases)
- [Commits](https://github.com/dtolnay/remain/compare/0.2.5...0.2.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-02 09:43:01 +00:00
dependabot[bot]
fdb2d673d3 build: Bump anyhow from 1.0.66 to 1.0.68
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.66 to 1.0.68.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.66...1.0.68)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-30 23:40:35 +00:00
dependabot[bot]
2d828121a6 build: Bump quote from 1.0.21 to 1.0.23
Bumps [quote](https://github.com/dtolnay/quote) from 1.0.21 to 1.0.23.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.21...1.0.23)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-29 23:41:08 +00:00
dependabot[bot]
55a8d3a0ea build: Bump paste from 1.0.10 to 1.0.11
Bumps [paste](https://github.com/dtolnay/paste) from 1.0.10 to 1.0.11.
- [Release notes](https://github.com/dtolnay/paste/releases)
- [Commits](https://github.com/dtolnay/paste/compare/1.0.10...1.0.11)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-28 23:41:07 +00:00
dependabot[bot]
8e373f52a9 build: Bump mshv-ioctls from 2852337 to dda85d3
Bumps [mshv-ioctls](https://github.com/rust-vmm/mshv) from `2852337` to `dda85d3`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](2852337bf4...dda85d32b9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-28 02:10:58 +00:00
dependabot[bot]
6eb0330bed build: Bump clap from 4.0.29 to 4.0.32 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.29 to 4.0.32.
- [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/v4.0.29...v4.0.32)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-26 23:13:24 +00:00
dependabot[bot]
c4c384bd1e build: Bump is-terminal from 0.4.1 to 0.4.2 in /fuzz
Bumps [is-terminal](https://github.com/sunfishcode/is-terminal) from 0.4.1 to 0.4.2.
- [Release notes](https://github.com/sunfishcode/is-terminal/releases)
- [Commits](https://github.com/sunfishcode/is-terminal/compare/v0.4.1...v0.4.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-23 23:18:08 +00:00
dependabot[bot]
180cc12b46 build: Bump is-terminal from 0.4.1 to 0.4.2
Bumps [is-terminal](https://github.com/sunfishcode/is-terminal) from 0.4.1 to 0.4.2.
- [Release notes](https://github.com/sunfishcode/is-terminal/releases)
- [Commits](https://github.com/sunfishcode/is-terminal/compare/v0.4.1...v0.4.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-22 23:40:50 +00:00
dependabot[bot]
ccb76fc19f build: Bump itoa from 1.0.4 to 1.0.5 in /fuzz
Bumps [itoa](https://github.com/dtolnay/itoa) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/dtolnay/itoa/releases)
- [Commits](https://github.com/dtolnay/itoa/compare/1.0.4...1.0.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-22 23:13:42 +00:00
dependabot[bot]
5668d7dfb7 build: Bump unicode-ident from 1.0.5 to 1.0.6
Bumps [unicode-ident](https://github.com/dtolnay/unicode-ident) from 1.0.5 to 1.0.6.
- [Release notes](https://github.com/dtolnay/unicode-ident/releases)
- [Commits](https://github.com/dtolnay/unicode-ident/compare/1.0.5...1.0.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-21 23:42:28 +00:00
dependabot[bot]
7ca2a771c2 build: Bump anyhow from 1.0.66 to 1.0.68 in /fuzz
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.66 to 1.0.68.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.66...1.0.68)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-21 23:13:54 +00:00
dependabot[bot]
09abb5b709 build: Bump mshv-bindings from ef01a5a to 2852337
Bumps [mshv-bindings](https://github.com/rust-vmm/mshv) from `ef01a5a` to `2852337`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](ef01a5abd0...2852337bf4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-20 23:40:27 +00:00
dependabot[bot]
7bac36bea4 build: Bump unicode-ident from 1.0.5 to 1.0.6 in /fuzz
Bumps [unicode-ident](https://github.com/dtolnay/unicode-ident) from 1.0.5 to 1.0.6.
- [Release notes](https://github.com/dtolnay/unicode-ident/releases)
- [Commits](https://github.com/dtolnay/unicode-ident/compare/1.0.5...1.0.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-20 23:19:44 +00:00
dependabot[bot]
0f5702f297 build: Bump itoa from 1.0.4 to 1.0.5
Bumps [itoa](https://github.com/dtolnay/itoa) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/dtolnay/itoa/releases)
- [Commits](https://github.com/dtolnay/itoa/compare/1.0.4...1.0.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-20 10:10:57 +00:00
Jinank Jain
8914ce9da8 build: Bump mshv-ioctls from 10d0c52 to ef01a5a
With this bump there was a change in one of the externally exposed
variable. Thus, the use of that variable in CLH must be adjusted
accordingly.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2022-12-20 10:10:34 +00:00
dependabot[bot]
1f191d8130 build: Bump serde_json from 1.0.89 to 1.0.91 in /fuzz
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.89 to 1.0.91.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.89...v1.0.91)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-19 23:18:39 +00:00
dependabot[bot]
129416de5c build: Bump serde from 1.0.150 to 1.0.151
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.150 to 1.0.151.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.150...v1.0.151)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-17 00:08:58 +00:00
dependabot[bot]
b3980f581b build: Bump serde from 1.0.150 to 1.0.151 in /fuzz
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.150 to 1.0.151.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.150...v1.0.151)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-16 23:24:12 +00:00
Wei Liu
3a232ef31a hypervisor: kvm: aarch64: remove repetition in offset_of
The repetition served no purpose.

No functional change.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-12-16 17:04:43 +00:00
Wei Liu
cd83d258b8 hypervisor: kvm: aarch64: rename offset__of to offset_of
The double underscore made it different from how other projects would
name this particular macro.

No functional change.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-12-16 17:04:43 +00:00
Hao Xu
1b0f35e42d virtio-devices: block: Remove duplicated code in handle_event()
There is duplicated code when handlin queue events in handle_event()
refactor and introduce a new helper function.

Signed-off-by: Hao Xu <howeyxu@tencent.com>
2022-12-16 14:52:48 +00:00
Rob Bradford
85f818421f build: Skip Jenkins build on .github only changes
Fixes: #4988

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-16 09:39:55 +00:00
Rob Bradford
0031dacd7b build: Consolidate touched file checks
This will make it easier to add more in the future.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-16 09:39:55 +00:00
dependabot[bot]
2f855c9a67 build: Bump cc from 1.0.77 to 1.0.78
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.0.77 to 1.0.78.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Commits](https://github.com/rust-lang/cc-rs/compare/1.0.77...1.0.78)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-16 00:04:51 +00:00
dependabot[bot]
b7e7455b49 build: Bump cc from 1.0.77 to 1.0.78 in /fuzz
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.0.77 to 1.0.78.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Commits](https://github.com/rust-lang/cc-rs/compare/1.0.77...1.0.78)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-15 23:23:12 +00:00
Rob Bradford
795f2a5558 vmm: memory_manager: Mark guest memory mappings as non-dumpable
Including the guest RAM (or other mapped memory) in a coredump is not
useful.

See: #5014

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-15 20:36:40 +01:00
dependabot[bot]
2b92a2778b build: Bump linux-raw-sys from 0.1.3 to 0.1.4
Bumps [linux-raw-sys](https://github.com/sunfishcode/linux-raw-sys) from 0.1.3 to 0.1.4.
- [Release notes](https://github.com/sunfishcode/linux-raw-sys/releases)
- [Commits](https://github.com/sunfishcode/linux-raw-sys/compare/v0.1.3...v0.1.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-14 23:43:43 +00:00
Rob Bradford
cbe988d33e .build: Add .vscode to .gitignore
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-14 14:27:32 +00:00
Rob Bradford
5e52729453 misc: Automatically fix cargo clippy issues added in 1.65 (stable)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-14 14:27:19 +00:00
Rob Bradford
8b59316718 build: Temporarily disable bare metal x86-64 workers
These machines are unreachable.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-14 10:47:15 +00:00
dependabot[bot]
6e8972372e build: Bump linux-raw-sys from 0.1.3 to 0.1.4 in /fuzz
Bumps [linux-raw-sys](https://github.com/sunfishcode/linux-raw-sys) from 0.1.3 to 0.1.4.
- [Release notes](https://github.com/sunfishcode/linux-raw-sys/releases)
- [Commits](https://github.com/sunfishcode/linux-raw-sys/compare/v0.1.3...v0.1.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-14 10:28:13 +01:00
dependabot[bot]
748ba1f50d build: Bump paste from 1.0.9 to 1.0.10
Bumps [paste](https://github.com/dtolnay/paste) from 1.0.9 to 1.0.10.
- [Release notes](https://github.com/dtolnay/paste/releases)
- [Commits](https://github.com/dtolnay/paste/compare/1.0.9...1.0.10)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-14 10:28:05 +01:00
Rob Bradford
a48d7c281e vmm: seccomp: Remove unreachable patterns
Make HypervisorType enum's members conditional on build time features.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-13 18:10:42 +00:00
Rob Bradford
aea1f7743b devices: Remove unnecessary clippy directives
Clippy passes fine without these and remove some genuinely unused code.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-13 18:10:42 +00:00
Rob Bradford
ab8e559343 block_util: Use anonymous case to handle ioctl signature difference
Between musl and glibc there is a difference in the signature of the
ioctl libc function. Use an anonymous cast to force the type coversion.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-13 18:10:42 +00:00
Rob Bradford
1b314cff5b acpi_tables: sdt: Implement Std::is_empty()
This allows the removal of [allow(clippy::len_without_is_empty)]

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-13 18:10:42 +00:00
Claudio Fontana
683d116416 docs: update UEFI.md to reference upstream tianocore EDK2 repository
after testing the build briefly, it seems upstream tianocore EDK2 works fine,
no need for the separate cloud-hypervisor edk2 repo.

Signed-off-by: Claudio Fontana <claudio.fontana@gmail.com>
2022-12-13 18:16:34 +01:00
Henry Wang
b93d50582d docs: Consolidate AArch64 guest booting doc into README
Take the opportunity to fix a bug in the `Booting the guest VM` doc
in README.

Signed-off-by: Henry Wang <Henry.Wang@arm.com>
2022-12-13 13:38:11 +00:00
Henry Wang
de4cd49c6d docs: Consolidate AArch64 kernel building doc into README
Signed-off-by: Henry Wang <Henry.Wang@arm.com>
2022-12-13 13:38:11 +00:00
Henry Wang
709545920e docs: Consolidate AArch64 cloud-img related doc into README
Signed-off-by: Henry Wang <Henry.Wang@arm.com>
2022-12-13 13:38:11 +00:00
Henry Wang
2b11966faa docs: Consolidate AArch64 UEFI doc into uefi.md
Signed-off-by: Henry Wang <Henry.Wang@arm.com>
2022-12-13 13:38:11 +00:00
Henry Wang
6835dfa5e9 docs: Consolidate building on AArch64 to building.md
Signed-off-by: Henry Wang <Henry.Wang@arm.com>
2022-12-13 13:38:11 +00:00
Henry Wang
d15e1f1a13 docs: Move AArch64 hardware requirements to README
Also drop the SWAP enabling requirements for AArch64 because this
is an AArch64 specific issue.

Signed-off-by: Henry Wang <Henry.Wang@arm.com>
2022-12-13 13:38:11 +00:00
dependabot[bot]
8ab15b9a98 build: Bump serde from 1.0.149 to 1.0.150
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.149 to 1.0.150.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.149...v1.0.150)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-13 00:08:23 +00:00
dependabot[bot]
287ec367d6 build: Bump serde from 1.0.149 to 1.0.150 in /fuzz
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.149 to 1.0.150.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.149...v1.0.150)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-12 23:27:28 +00:00
Rob Bradford
9fb0274479 vmm: Deprecate MemoryZoneConfig::file
Remove from the documentation and API definition but continue support
using the field (with a deprecation warning.)

See: #4837

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-12 16:44:04 +00:00
Bo Chen
51307dd509 fuzz: Add fuzzer for 'linux loader' cmdline
Signed-off-by: Bo Chen <chen.bo@intel.com>
2022-12-12 13:50:28 +00:00
Bo Chen
de06bf4aed vmm: Make "Vm::generate_cmdline()" public for fuzzing
Signed-off-by: Bo Chen <chen.bo@intel.com>
2022-12-12 13:50:28 +00:00
Bo Chen
32ded2c72b fuzz: Add fuzzer for 'linux loader'
Signed-off-by: Bo Chen <chen.bo@intel.com>
2022-12-12 13:50:28 +00:00
Sebastien Boeuf
8ecce8876e tests: Disable live upgrade testing
Since the refactoring of the vm-migration crate broke the backward
compatibility, we must disable the live upgrade tests until next
release.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-09 10:26:06 +01:00
Sebastien Boeuf
3931b99d4e vm-migration: Introduce new constructor for Snapshot
This simplifies the Snapshot creation as we expect a SnapshotData to be
provided most of the time.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-09 10:26:06 +01:00
Sebastien Boeuf
4ae6b595d7 vm-migration: Rename add_data_section() into add_data()
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-09 10:26:06 +01:00
Sebastien Boeuf
748018ace3 vm-migration: Don't store the id as part of Snapshot structure
The information about the identifier related to a Snapshot is only
relevant from the BTreeMap perspective, which is why we can get rid of
the duplicated identifier in every Snapshot structure.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-09 10:26:06 +01:00
Sebastien Boeuf
426ee39972 vm-migration: Simplify SnapshotData implementation
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-09 10:26:06 +01:00
Sebastien Boeuf
1d1043316b vm-migration: Don't store snapshots through a Box
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-09 10:26:06 +01:00
Sebastien Boeuf
4517b76a23 vm-migration: Rename SnapshotDataSection into SnapshotData
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-09 10:26:06 +01:00
Sebastien Boeuf
1b32e2f8b2 vm-migration: Simplify SnapshotDataSection structure
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-09 10:26:06 +01:00
Sebastien Boeuf
5b3bcfa233 vm-migration: Snapshot should have a unique SnapshotDataSection
There's no reason to carry a HashMap of SnapshotDataSection per
Snapshot. And given we now provide at most one SnapshotDataSection per
Snapshot, there's no need to keep the id part of the SnapshotDataSection
structure.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-09 10:26:06 +01:00
Sebastien Boeuf
0489b6314e tdx: Support new way of declaring memory resources
Without breaking the former way of declaring them. This is simply based
on the presence of the GUID TDX Metadata offset. If not present, we
consider the firmware is quite old and therefore we fallback onto the
previous way to expose memory resources.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-08 10:13:12 -08:00
Rob Bradford
2c367bdde8 misc: Bulk update dependencies
In particular update to latest linux-loader release and point to latest
vfio repository for both crates hosted there.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-07 18:24:58 +00:00
Sebastien Boeuf
4f3f36fe5f tdx: Add support for new method of TDVF descriptor discovery
The preferred way of retrieving the offset where to find the TDVF
descriptor structure is by going through a table of GUIDs that can be
found at a specific offset in the firmware file. If the expected GUIDs
can't be found, we can fallback onto the former way, which is to read
directly the value at a specific offset in the file.

This patch implements the new mechanism without breaking compatibility
for older firmwares as it keeps supporting the previous mechanism.

As a reference, here is the documentation from the EDK2 code, and
particularly from the OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm file:

```
GUIDed structure.  To traverse this you should first verify the
presence of the table footer guid
(96b582de-1fb2-45f7-baea-a366c55a082d) at 0xffffffd0.  If that
is found, the two bytes at 0xffffffce are the entire table length.

The table is composed of structures with the form:

Data (arbitrary bytes identified by guid)
length from start of data to end of guid (2 bytes)
guid (16 bytes)

so work back from the footer using the length to traverse until you
either find the guid you're looking for or run off the beginning of
the table.
```

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-07 17:55:54 +00:00
Rob Bradford
4b08142117 misc: Remove #![allow(clippy::significant_drop_in_scrutinee)]
This isn't supported by clippy on Rust 1.60 but also no longer seems to
be required.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-07 17:50:48 +00:00
Rob Bradford
b3e3a5fdd7 vmm: Fix clippy on musl toolchains
The datatype used for the ioctl() C library call is different between it
and the glibc toolchains. The easiest solution is to have the compiler
type cast to type of the parameter.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-07 17:50:48 +00:00
Rob Bradford
a1c6ef8385 .github: Add musl variants to quality (clippy) checks
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-07 17:50:48 +00:00
dependabot[bot]
16d0906dfd build: Bump mshv-ioctls from 0983996 to 10d0c52
Bumps [mshv-ioctls](https://github.com/rust-vmm/mshv) from `0983996` to `10d0c52`.
- [Release notes](https://github.com/rust-vmm/mshv/releases)
- [Commits](098399606d...10d0c5208c)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-06 23:44:44 +00:00
dependabot[bot]
3e9ce6012c build: Bump rustix from 0.36.4 to 0.36.5 in /fuzz
Bumps [rustix](https://github.com/bytecodealliance/rustix) from 0.36.4 to 0.36.5.
- [Release notes](https://github.com/bytecodealliance/rustix/releases)
- [Commits](https://github.com/bytecodealliance/rustix/compare/v0.36.4...v0.36.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-06 23:21:09 +00:00
Shuaiyi Zhang
389264351e ch-remote: Add support for vmm.shutdown
Signed-off-by: Shuaiyi Zhang <zhangsy28@lenovo.com>
2022-12-06 13:21:55 -08:00
Rob Bradford
00becda899 README: Use consistent path to cloud-hypervisor binary
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-06 17:30:34 +00:00
dependabot[bot]
fe5bde236a build: Bump libc from 0.2.137 to 0.2.138
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.137 to 0.2.138.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.137...0.2.138)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-06 00:10:07 +00:00
dependabot[bot]
80cc2b6ef8 build: Bump libc from 0.2.137 to 0.2.138 in /fuzz
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.137 to 0.2.138.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.137...0.2.138)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-05 23:25:56 +00:00
Rob Bradford
c37dadcc9a .github: Enable "guest_debug" clippy on aarch64
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-05 17:23:52 +00:00
Rob Bradford
cefbf6b4a3 vmm: guest_debug: Mark coredump functionality x86_64 only
The coredump functionality is only implemented for x86_64 so it should
only be compiled in there.

Fixes: #4964

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-05 17:23:52 +00:00
Sebastien Boeuf
31209474b3 vmm: Move TDX initialization before vCPUs creation
TDX was broken by the recent refactoring moving the vCPU creation
earlier than before. The simple and correct way to fix this problem is
by moving the TDX initialization right before the vCPUs creation. The
rest of the TDX setup can remain where it is.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-05 07:49:40 -08:00
Shuaiyi Zhang
0e09b537e3 ch-remote: Add support for vmm.ping
Signed-off-by: Shuaiyi Zhang <zhangsy28@lenovo.com>
2022-12-05 07:45:01 -08:00
dependabot[bot]
ca6d338ffa build: Bump clap from 4.0.27 to 4.0.29
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.27 to 4.0.29.
- [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/v4.0.27...v4.0.29)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-02 23:45:26 +00:00
dependabot[bot]
166b73e106 build: Bump io-lifetimes from 1.0.2 to 1.0.3 in /fuzz
Bumps [io-lifetimes](https://github.com/sunfishcode/io-lifetimes) from 1.0.2 to 1.0.3.
- [Release notes](https://github.com/sunfishcode/io-lifetimes/releases)
- [Commits](https://github.com/sunfishcode/io-lifetimes/compare/v1.0.2...v1.0.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-02 23:21:11 +00:00
dependabot[bot]
9398a0bd80 build: Bump syn from 1.0.104 to 1.0.105
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.104 to 1.0.105.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.104...1.0.105)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-02 00:00:29 +00:00
dependabot[bot]
55f7df2e21 build: Bump syn from 1.0.104 to 1.0.105 in /fuzz
Bumps [syn](https://github.com/dtolnay/syn) from 1.0.104 to 1.0.105.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.104...1.0.105)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-01 23:16:35 +00:00
Rob Bradford
7fb1280666 devices: gic: Pass slice rather than &Vec
This addresses a clippy issue

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-01 22:41:01 +00:00
Rob Bradford
bfa31f9c56 vmm: Propagate vCPU configure error correctly
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-01 22:41:01 +00:00
Rob Bradford
725e388684 vmm: Seperate the CPUID setup from the CpuManager::new()
This allows the decoupling of CpuManager and MemoryManager.

See: #4761

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-01 22:41:01 +00:00
Rob Bradford
c5eac2e822 vmm: Don't store GuestMemoryMmap for "guest_debug" functionality
This removes the storage of the GuestMemoryMmap on the CpuManager
further allowing the decoupling of the CpuManager from the
MemoryManager.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-01 22:41:01 +00:00
Rob Bradford
c7b22156da aarch, vmm: Reduce requirement for guest memory to vCPU boot only
When configuring the vCPUs it is only necessary to provide the guest
memory when booting fresh (for populating the guest memory). As such
refactor the vCPU configuration to remove the use of the
GuestMemoryMmap stored on the CpuManager.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-01 22:41:01 +00:00
Rob Bradford
e5e5a89e65 vmm: cpu: Rename "vm_memory" parameter/member to "guest_memory"
This gives consistency across the file.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-01 22:41:01 +00:00
Sebastien Boeuf
d98f2618bd vmm: Create restored Vm as paused
Thanks to the new way of restoring Vm, we can now create the Vm object
directly with the appropriate VmState rather than having to patch it at
a later time.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-01 10:16:44 -08:00
Sebastien Boeuf
2e01bf7f74 vmm: Provide an owned Snapshot rather than a reference
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-01 10:16:44 -08:00
Sebastien Boeuf
a4160c1fef vmm: Simplify list of parameters to Vm::new()
No need to provide a boolean to know if the VM is being restored given
we already have this information from the Option<Snapshot>.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-01 10:16:44 -08:00
Sebastien Boeuf
d0c53a5357 vmm: Move Vm to the new restore design
Now the entire codebase has been moved to the new restore design, we can
complete the work by creating a dedicated restore() function for the Vm
object and get rid of the method restore() from the Snapshottable trait.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-01 10:16:44 -08:00
Rob Bradford
3888f57600 aarch64: Remove unnecessary casts (beta clippy check)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-01 17:02:30 +00:00
Rob Bradford
7fd2022e8e .github: Ensure target used for clippy tests
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-01 17:02:30 +00:00
Rob Bradford
1b6dd597b2 .github: Remove build testing for aarch64 with guest_debug feature
See: #4964

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-01 17:02:30 +00:00
Rob Bradford
ad817f19b5 main: Allow the use of let ahead and immediate return
On aarch64 there is no modification of the app struct however
refactoring to remove this would be very intrusive.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-12-01 17:02:30 +00:00
Michael Zhao
a8839c4a4e tests: Disable live_upgrade test on AArch64
The `live_upgrade` test was broken when the Gic snapshot moved from `Vm`
to `DeviceManager`.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-12-01 17:07:25 +01:00
Michael Zhao
b173f6f654 vmm,devices: Change Gic snapshot and restore path
The snapshot and restore of AArch64 Gic was done in Vm. Now it is moved
to DeviceManager.

The benefit is that the restore can be done while the Gic is created in
DeviceManager.

While the moving of state data from Vm snapshot to DeviceManager
snapshot breaks the compatability of migration from older versions.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-12-01 17:07:25 +01:00
Michael Zhao
def1d7cf86 vmm: Remove GICR typers in snapshot on AArch64
The GICR typers are also set in restoring the GIC. Saving them in
snapshot is not needed.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-12-01 17:07:25 +01:00
Sebastien Boeuf
e8c6d83f3f vmm: Merge Vm::new_from_snapshot with Vm::new
Given the recent factorization that happened in vm.rs, we're now able to
merge Vm::new_from_snapshot with Vm::new.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-01 13:46:31 +01:00
Sebastien Boeuf
1c36065754 vmm: Move devices creation to Vm creation
This moves the devices creation out of the dedicated restore function
which will be eventually removed.

This factorizes the creation of all devices into a single location.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-01 13:46:31 +01:00
Sebastien Boeuf
bccfa81368 vmm: Restore clock from Vm creation (x86_64 only)
This allows the clock restoration to be moved out of the dedicated
restore function, which will eventually be removed.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-01 13:46:31 +01:00
Sebastien Boeuf
a6959a7469 vmm: Move DeviceManager to new restore design
Based on all the work that has already been merged, it is now possible
to fully move DeviceManager out of the previous restore model, meaning
there's no need for a dedicated restore() function to be implemented
there.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-01 13:46:31 +01:00
Sebastien Boeuf
4487c8376b vmm: Move CpuManager and Vcpu to the new restore design
Every Vcpu is now created with the right state if there's an available
snapshot associated with it. This simplifies the restore logic.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-01 09:27:00 +01:00
Sebastien Boeuf
b62a40efae virtio-devices, vmm: Always restore virtio devices in paused state
Following the new restore design, it is not appropriate to set every
virtio device threads into a paused state after they've been started.

This is why we remove the line of code pausing the devices only after
they've been restored, and replace it with a small patch in every virtio
device implementation. When a virtio device is created as part of a
restored VM, the associated "paused" boolean is set to true. This
ensures the corresponding thread will be directly parked when being
started, avoiding the thread to be in a different state than the one it
was on the source VM during the snapshot.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-12-01 09:27:00 +01:00
dependabot[bot]
8f1e03fcf4 build: Bump terminal_size from 0.2.2 to 0.2.3
Bumps [terminal_size](https://github.com/eminence/terminal-size) from 0.2.2 to 0.2.3.
- [Release notes](https://github.com/eminence/terminal-size/releases)
- [Commits](https://github.com/eminence/terminal-size/compare/v0.2.2...v0.2.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-01 00:08:19 +00:00
dependabot[bot]
5ee68b1ee3 build: Bump terminal_size from 0.2.2 to 0.2.3 in /fuzz
Bumps [terminal_size](https://github.com/eminence/terminal-size) from 0.2.2 to 0.2.3.
- [Release notes](https://github.com/eminence/terminal-size/releases)
- [Commits](https://github.com/eminence/terminal-size/compare/v0.2.2...v0.2.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-30 23:23:46 +00:00
Bo Chen
e2e02c8f69 fuzz: Add fuzzer for virtio-net
To synthesize the interactions between the virtio-net device and the tap
interface, the fuzzer utilizes a pair of unix domain sockets: one socket
(e.g. the dummy tap frontend) is used to construct the 'net_util::Tap'
instance for creating a virtio-net device; the other socket (e.g. the
dummy tap backend) is used in a epoll loop for handling the tx and rx
requests from the virtio-net device.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2022-11-30 12:13:14 +00:00
Bo Chen
ec94ae31ee vmm: EpollContext: Allow to add custom epoll events for fuzzing
Signed-off-by: Bo Chen <chen.bo@intel.com>
2022-11-30 12:13:14 +00:00
Bo Chen
83ab5ea528 virtio-devices: net: Provide custom functions for fuzzing
Three functions are added:
* 'Tap::new_for_fuzzing()' a custom constructor that creates a dummy
`Tap` interface directly from `File` backed by Unix domain socket;
* 'Tap::mtu()' a custom function that returns hard-coded mtu;
* 'Net::wait_for_epoll_threads()'.

Two functions are reused with modifications to work with the dummy 'Tap'
interface:
* 'Net::new_with_tap()' is made public for fuzzing;
* 'Net::activate()' is modified to not call into 'Tap::set_offload()'
for fuzzing.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2022-11-30 12:13:14 +00:00
Rob Bradford
30a7a8033e build: Move to released versions of vhost and vhost-user-backend crates
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-30 12:12:34 +00:00
dependabot[bot]
fc43a50f34 build: Bump vfio-ioctls from ad86d84 to 3d82543
Bumps [vfio-ioctls](https://github.com/rust-vmm/vfio) from `ad86d84` to `3d82543`.
- [Release notes](https://github.com/rust-vmm/vfio/releases)
- [Commits](ad86d843a2...3d82543586)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-29 23:46:48 +00:00
dependabot[bot]
105c6cfc5a build: Bump clap from 4.0.27 to 4.0.29 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.27 to 4.0.29.
- [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/v4.0.27...v4.0.29)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-29 23:15:39 +00:00
Rob Bradford
ee5792c0bb build: Document the project's MSRV policy
To me the most logical place to document the policy is right next to the
version itself.

Fixes: #4318

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-29 18:09:11 +00:00
Sebastien Boeuf
30e421d2e5 pci: Remove unused restore() implementations
Now that VirtioPciDevice, VfioPciDevice and VfioUserPciDevice have all
been moved to the new restore design, there's no need to keep the old
way around, therefore the restore() implementations for MsiConfig,
MsixConfig and PciConfiguration can be removed.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-29 13:46:30 +01:00
Sebastien Boeuf
90b5014a50 vmm: device_manager: Remove 'restoring' attribute
Given 'restoring' isn't needed anymore from the DeviceManager structure,
let's simplify it.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-29 13:46:30 +01:00
Sebastien Boeuf
cc3706afe1 pci, vmm: Move VfioPciDevice and VfioUserPciDevice to new restore design
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-29 13:46:30 +01:00
Sebastien Boeuf
1eac37bd5f pci: msi: Move MsiConfig to the new restore design
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-29 13:46:30 +01:00
Sebastien Boeuf
d6bf1f5eb0 pci: Move VfioCommon creation to a dedicated function
This is some preliminatory work for moving both VfioUser and Vfio to the
new restore design.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-29 13:46:30 +01:00
Bo Chen
559faa272a net_util: queue_pair: Avoid integer overflow
This integer overflow was triggered with fuzzing on the virtio-net
device. The integer overflow is from the wrong assumption that the
packets read from or written to the tap device is always larger than the
size of a virtio-net header.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2022-11-28 17:19:53 +00:00
Rob Bradford
6f8bd27cf7 build: Bulk update dependencies
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-28 16:57:49 +00:00
Yuji Hagiwara
47a7ebe434 docs: Fix a typo on the doc for tpm
swtpm accepts --tpmstate option

Signed-off-by: Yuji Hagiwara <yuuzi41@gmail.com>
2022-11-27 18:55:07 +00:00
dependabot[bot]
1fd5384062 build: Bump regex-syntax from 0.6.27 to 0.6.28
Bumps [regex-syntax](https://github.com/rust-lang/regex) from 0.6.27 to 0.6.28.
- [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/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-25 23:46:39 +00:00
Sebastien Boeuf
81862e8ed3 devices, vmm: Move Gpio to new restore design
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-25 17:37:29 +00:00
Sebastien Boeuf
9fbf52b998 devices, vmm: Move Pl011 to new restore design
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-25 17:37:29 +00:00
Sebastien Boeuf
0bd910e8b0 devices, vmm: Move Serial to new restore design
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-25 17:37:29 +00:00
Sebastien Boeuf
ef92e55998 devices, vmm: Move Ioapic to new restore design
Moving the Ioapic object to the new restore design, meaning the Ioapic
is created directly with the right state, and it shares the same
codepath as when it's created from scratch.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-25 17:18:21 +01:00
Sebastien Boeuf
9f7ccb34cd docs: Provide documentation for creating custom image for VFIO CI
Extend the existing `custom-image.md` document with a new section on how
to create a custom image that contains NVIDIA drivers that are required
for our VFIO baremetal CI.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-25 13:39:25 +01:00
Sebastien Boeuf
e23f4e0783 tests: Enable VFIO integration tests
Re-enable the VFIO integration now the machine is back online.

The image has been updated to rely on Ubuntu 22.04 (Jammy) and it's
smaller given only the NVIDIA drivers along with the nvidia-smi tool are
installed.

The test to verify the GPU is functional has been simplified given it
only relies on nvidia-smi to validate it has been able to find the Tesla
T4 card, meaning the associated driver was loaded correctly.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-25 08:55:14 +00:00
dependabot[bot]
6a29eba69e build: Bump regex from 1.6.0 to 1.7.0
Bumps [regex](https://github.com/rust-lang/regex) from 1.6.0 to 1.7.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.6.0...1.7.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-24 23:44:40 +00:00
dependabot[bot]
98e10062e8 build: Bump clap from 4.0.26 to 4.0.27 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.26 to 4.0.27.
- [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/v4.0.26...v4.0.27)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-24 23:13:36 +00:00
Rob Bradford
c95b82d975 scripts: Build dual kvm/mshv binary (like release.yaml) for integration testing
This means we are testing the same binary as we use in our releases.

Fixes: #4915

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-24 17:06:56 +00:00
Rob Bradford
d83fc7f663 scripts: Make --hypervisor=mshv only affect features used by tests
This uncouples it from the features used for building the binary under
test allowing it to use the default build features.

This change also removes the feature control from the test scripts where
it was never used (e.g. run_integration_tests_sgx.sh)

This allows the combined binary to be used for all testing but allows
the disabling of tests known not to work under mshv.

Fixes: #4915

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-24 17:06:56 +00:00
Rob Bradford
e3a5102f85 net_util: tap: Include ioctl code in failure errors
This will help with debugging issues like #4917 since we can find which
ioctl causes the error.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-24 16:18:39 +00:00
Rob Bradford
ea39fcca3f net_util: tap: Refactor TAP ioctl calls
Consolidate the identical code that tests the return values of the ioctl
into helper functions

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-24 16:18:39 +00:00
dependabot[bot]
7e10b236d4 build: Bump serde_json from 1.0.87 to 1.0.89 in /fuzz
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.87 to 1.0.89.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.87...v1.0.89)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-23 23:15:07 +00:00
Sebastien Boeuf
405b4a6829 tests: Increase time for proper shutdown in test_simple_launch()
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-23 18:37:40 +00:00
Sebastien Boeuf
a50b3784fe virtio-devices: Create a proper result type for VirtioPciDevice
Creating a dedicated Result type for VirtioPciDevice, associated with
the new VirtioPciDeviceError enum. This allows for a clearer handling of
the errors generated through VirtioPciDevice::new().

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-23 18:37:40 +00:00
Sebastien Boeuf
eae8043890 pci, virtio-devices: Move VirtioPciDevice to the new restore design
The code for restoring a VirtioPciDevice has been updated, including the
dependencies VirtioPciCommonConfig, MsixConfig and PciConfiguration.

It's important to note that both PciConfiguration and MsixConfig still
have restore() implementations because Vfio and VfioUser devices still
rely on the old way for restore.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-23 18:37:40 +00:00
Rob Bradford
8868c9c950 tests: Use Ubuntu Jammy for test_multi_cpu
This allows the unification of the same testing methodology with aarch64
and removes a user of the Bionic image.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-23 18:02:03 +00:00
Michael Zhao
7d16c74020 vmm: Refactor AArch64 GIC initialization process
In the new process, `device::Gic::new()` covers additional actions:
1. Creating `hypervisor::vGic`
2. Initializing interrupt routings

The change makes the vGic device ready in the beginning of
`DeviceManager::create_devices()`. This can unblock the GIC related
devices initialization in the `DeviceManager`.

Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-11-23 11:49:57 +01:00
Sebastien Boeuf
86e7f07485 vmm: cpu: Create vCPUs before the DeviceManager
Moving the creation of the vCPUs before the DeviceManager gets created
will allow for the aarch64 vGIC to be created before the DeviceManager
as well in a follow up patch. The end goal being to adopt the same
creation sequence for both x86_64 and aarch64, and keeping in mind that
the vGIC requires every vCPU to be created.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-23 11:49:57 +01:00
Sebastien Boeuf
578780ed0c vmm: cpu: Split vCPU creation
Split the vCPU creation into two distincts parts. On the one hand we
create the actual Vcpu object with the creation of the hypervisor::Vcpu.
And on the other hand, we configure the existing Vcpu, setting registers
to proper values (such as setting the entry point).

This will allow for further work to move the creation earlier in the
boot, so that the hypervisor::Vcpu will be already created when the
DeviceManager gets created.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
Signed-off-by: Michael Zhao <michael.zhao@arm.com>
2022-11-23 11:49:57 +01:00
Sebastien Boeuf
ec01062ada vmm: Switch order between DeviceManager and CpuManager creation
The CpuManager is now created before the DeviceManager. This is required
as preliminary work for creating the vCPUs before the DeviceManager,
which is required to ensure both x86_64 and aarch64 follow the same
sequence.

It's important to note the optimization for faster PIO accesses on the
PCI config space had to be removed given the VmOps was required by the
CpuManager and by the Vcpu by extension. But given the PciConfigIo is
created as part of the DeviceManager, there was no proper way of moving
things around so that we could provide PciConfigIo early enough.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
2022-11-23 11:49:57 +01:00
dependabot[bot]
d828fcd4ed build: Bump cc from 1.0.76 to 1.0.77
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.0.76 to 1.0.77.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Commits](https://github.com/rust-lang/cc-rs/compare/1.0.76...1.0.77)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-23 00:21:21 +00:00
dependabot[bot]
d330f5389e build: Bump cc from 1.0.73 to 1.0.77 in /fuzz
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.0.73 to 1.0.77.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Commits](https://github.com/rust-lang/cc-rs/compare/1.0.73...1.0.77)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-22 23:36:54 +00:00
Rob Bradford
e37ec26ccf vmm: Remove PCI PIO optimisation
This optimisation provided some peformance improvement when measured by
perf however when considered in terms of boot time peformance this
optimisation doesn't have any impact measurable using our
peformance-metrics tooling.

Removing this optimisation helps simplify the VMM internals as it allows
the reordering of the VM creation process permitting refactoring of the
restore code path.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-22 19:47:53 +00:00
Bo Chen
4d9a2b17a7 net_util: queue_pair: Avoid panic and handle error properly
This panic was triggered with fuzzing on the virtio-net device. This
commits handles the error explicitly to avoid the panic, which also
makes the fuzzer happy (as panic is treated as bugs).

Signed-off-by: Bo Chen <chen.bo@intel.com>
2022-11-22 09:31:50 +00:00
Rob Bradford
7c3110e6d5 arch: x86_64: Use host cpuid information for L2 cache for older KVM
If the KVM version is too old (pre Linux 5.7) then fetch the CPUID
information from the host and use that in the guest. We prefer the KVM
version over the host version as that would use the CPUID for the
running CPU vs the CPU that runs this code which might be different due
to a hybrid topology.

Fixes: #4918

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-22 09:32:30 +01:00
dependabot[bot]
1c25d71127 build: Bump os_str_bytes from 6.4.0 to 6.4.1 in /fuzz
Bumps [os_str_bytes](https://github.com/dylni/os_str_bytes) from 6.4.0 to 6.4.1.
- [Release notes](https://github.com/dylni/os_str_bytes/releases)
- [Commits](https://github.com/dylni/os_str_bytes/compare/6.4.0...6.4.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-22 00:47:55 +00:00
Rob Bradford
8724ac1fe6 scripts: Remove stripping from testing scripts
The binary stripping is now done by the toolchain for release builds.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-21 07:54:39 -08:00
Henry Wang
1ff0191b30 github,Cargo.toml: Strip release binaries using toolchain
From Rust 1.59, the cargo command is now able to strip a binary [1].
This can be enabled in Cargo.toml by adding a `strip = "true"` to
the `[profile.release]` section.

Adding such binary stripping support in Cargo.toml of the project,
also change the stripping process in the release workflow to the one
using toolchain, so that the AArch64 release binaries can also
be stripped.

Fixes: https://github.com/cloud-hypervisor/cloud-hypervisor/issues/4916

[1] https://doc.rust-lang.org/beta/cargo/reference/profiles.html#strip

Signed-off-by: Henry Wang <Henry.Wang@arm.com>
2022-11-21 13:39:29 +00:00
dependabot[bot]
464ead57ec build: Bump cc from 1.0.73 to 1.0.76
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.0.73 to 1.0.76.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Commits](https://github.com/rust-lang/cc-rs/compare/1.0.73...1.0.76)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-19 00:27:00 +00:00
dependabot[bot]
cee2d6627d build: Bump clap from 4.0.18 to 4.0.26 in /fuzz
Bumps [clap](https://github.com/clap-rs/clap) from 4.0.18 to 4.0.26.
- [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/v4.0.18...v4.0.26)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 23:44:01 +00:00
Muminul Islam
bfeab9f69f .github: do release build with both KVM and MSHV enabled
Fixes: #4678

Currently release build is done on kvm feature only,
that makes live upgrade test on MSHV failing since
it does not find /dev/kvm. As Cloud-Hypervisor
supports both kvm and mshv in a single binary we should
make the release build with both KVM/MSHV feature enabled.
That way live upgrade test does not fail on MSHV.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2022-11-18 19:15:25 +00:00
Rob Bradford
3504947f0e Jenkinsfile: Re-enable SGX CI testing
With the modernised testing of SGX the testing can be re-enabled on the
CI.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-18 18:31:55 +00:00
Rob Bradford
d2442d39a8 tests: Update version of jammy image in use
This version has the cpuid binary installed which can be used for SGX
integration testing.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-18 18:31:55 +00:00
Rob Bradford
1e87a409c7 docs: Add cpuid to custom disk image instructions
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-18 18:31:55 +00:00
Rob Bradford
1a2185ea96 tests: Modernise SGX testing
The jammy disk image has a new enough kernel to support SGX and if we
rely on just the CPUid information (which is sufficient) then we can use
the regular jammy test image for testing.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-18 18:31:55 +00:00
Rob Bradford
8cea5db955 Jenkinsfile: Re-enable rate limiter CI
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-18 07:48:07 -08:00
Wei Liu
3ca6c29e28 github: do not allow undocumented unsafe blocks
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
d05586f520 vmm: modify or provide safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
d5f294b326 main: add safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
145df4b689 tests: allow undocumented unsafe blocks in integration test
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
c45d24df16 virtio-devices: modify or provide safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
f110029acf block_util: modify or provide safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
8a7f4b47cb net_util: modify or provide safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
c5bd8cabc4 pci: add safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
d1b9d9d7f7 test_infra: allow undocumented unsafe blocks
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
9806d83e7c devices: modify safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
f16b57716d arch: modify or add safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
3edf12accf block_util: modify and add safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
7f2723d9c6 hypervisor: x86: add two safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
6c89c541da hypervisor: kvm: add two safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
d272113d0c hypervisor: mshv: modify two safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
93883681be tracer: add safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
ca02a69fdf qcow: add a safety comment
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
c4ffdad4bc vfio_user: modify the style of safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
2a5c248f32 vm-migration: add two safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
926d149881 net_gen: add a safety comment
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
7f4b5dfae5 tpm: change the style of safety comments
To satisfy clippy's check.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
58b7057c7f rate_limiter: add a safety comment
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
b1efa5b26b event_monitor: add safety comments
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
b9ad3eda27 vhdx: add some safety comments
Also add some assertions to some places along side the safety comments.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
1d9050dbe3 acpi_tables: add a safety comment for the write function
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
3d08a0fba9 vm-allocator: fix a clippy warning on missing safety comments
There is already a comment but Clippy isn't happy with its form.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
Wei Liu
d274fe9cb8 vmm: fix tdx check
The field has been moved in 3793ffe888.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2022-11-18 12:50:01 +00:00
dependabot[bot]
cd24f470f4 build: Bump getrandom from 0.2.7 to 0.2.8
Bumps [getrandom](https://github.com/rust-random/getrandom) from 0.2.7 to 0.2.8.
- [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.7...v0.2.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-17 23:46:30 +00:00
dependabot[bot]
2e22f950b7 build: Bump serde_with from 2.0.1 to 2.1.0 in /fuzz
Bumps [serde_with](https://github.com/jonasbb/serde_with) from 2.0.1 to 2.1.0.
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v2.0.1...v2.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-17 23:14:56 +00:00
180 changed files with 4930 additions and 3835 deletions

View File

@@ -34,22 +34,22 @@ jobs:
override: true
- name: Build (default features)
run: cargo rustc --locked --bin cloud-hypervisor -- -D warnings
run: cargo rustc --locked --bin cloud-hypervisor -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Build (kvm)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "kvm" -- -D warnings
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Build (default features + tdx)
run: cargo rustc --locked --bin cloud-hypervisor --features "tdx" -- -D warnings
run: cargo rustc --locked --bin cloud-hypervisor --features "tdx" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Build (default features + guest_debug)
run: cargo rustc --locked --bin cloud-hypervisor --features "guest_debug" -- -D warnings
run: cargo rustc --locked --bin cloud-hypervisor --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Build (mshv)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "mshv" -- -D warnings
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "mshv" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Build (mshv + kvm)
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "mshv,kvm" -- -D warnings
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Release Build (default features)
run: cargo build --locked --all --release --target=${{ matrix.target }}

View File

@@ -13,15 +13,24 @@ jobs:
rust:
- stable
target:
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
- aarch64-unknown-linux-musl
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl
experimental: [false]
include:
- rust: beta
target: aarch64-unknown-linux-gnu
experimental: true
- rust: beta
target: aarch64-unknown-linux-musl
experimental: true
- rust: beta
target: x86_64-unknown-linux-gnu
experimental: true
- rust: beta
target: aarch64-unknown-linux-gnu
target: x86_64-unknown-linux-musl
experimental: true
steps:
- name: Code checkout
@@ -53,28 +62,28 @@ jobs:
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --locked --all --all-targets --no-default-features --tests --features "kvm" -- -D warnings
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Clippy (default features)
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --locked --all --all-targets --tests -- -D warnings
args: --target=${{ matrix.target }} --locked --all --all-targets --tests -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Clippy (default features + guest_debug)
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --locked --all --all-targets --tests --features "guest_debug" -- -D warnings
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Clippy (default features + tracing)
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --locked --all --all-targets --tests --features "tracing" -- -D warnings
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --features "tracing" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Clippy (mshv)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
@@ -82,7 +91,7 @@ jobs:
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --locked --all --all-targets --no-default-features --tests --features "mshv" -- -D warnings
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --features "mshv" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Clippy (mshv + kvm)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
@@ -90,7 +99,7 @@ jobs:
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --locked --all --all-targets --no-default-features --tests --features "mshv,kvm" -- -D warnings
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Clippy (kvm + tdx)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
@@ -98,7 +107,7 @@ jobs:
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --locked --all --all-targets --no-default-features --tests --features "tdx,kvm" -- -D warnings
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --features "tdx,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
- name: Check build did not modify any files
run: test -z "$(git status --porcelain)"

View File

@@ -1,62 +1,47 @@
name: Cloud Hypervisor Release
on: [create]
on: [pull_request, create]
jobs:
release:
if: github.event_name == 'create' && github.event.ref_type == 'tag'
name: Release
runs-on: ubuntu-latest
steps:
- name: Code checkout
uses: actions/checkout@v2
- name: Install musl-gcc
run: sudo apt install -y musl-tools
run: sudo apt install -y musl-tools
- name: Create release directory
run: rsync -rv --exclude=.git . ../cloud-hypervisor-${{ github.event.ref }}
- name: Install Rust toolchain (x86_64-unknown-linux-gnu)
uses: actions-rs/toolchain@v1
with:
toolchain: "1.62"
target: x86_64-unknown-linux-gnu
toolchain: "1.62"
target: x86_64-unknown-linux-gnu
- name: Install Rust toolchain (x86_64-unknown-linux-musl)
uses: actions-rs/toolchain@v1
with:
toolchain: "1.62"
target: x86_64-unknown-linux-musl
toolchain: "1.62"
target: x86_64-unknown-linux-musl
- name: Build
uses: actions-rs/cargo@v1
with:
toolchain: "1.62"
command: build
args: --all --release --target=x86_64-unknown-linux-gnu
toolchain: "1.62"
command: build
args: --all --release --no-default-features --features "kvm,mshv" --target=x86_64-unknown-linux-gnu
- name: Static Build
uses: actions-rs/cargo@v1
with:
toolchain: "1.62"
command: build
args: --all --release --target=x86_64-unknown-linux-musl
- name: Strip cloud-hypervisor binaries
run: strip target/*/release/cloud-hypervisor
toolchain: "1.62"
command: build
args: --all --release --no-default-features --features "kvm,mshv" --target=x86_64-unknown-linux-musl
- name: Install Rust toolchain (aarch64-unknown-linux-musl)
uses: actions-rs/toolchain@v1
with:
toolchain: "1.62"
target: aarch64-unknown-linux-musl
override: true
- name: Static Build (AArch64)
uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --all --release --target=aarch64-unknown-linux-musl
- name: Vendor
working-directory: ../cloud-hypervisor-${{ github.event.ref }}
run: |
mkdir ../vendor-cargo-home
export CARGO_HOME=$(realpath ../vendor-cargo-home)
mkdir .cargo
cargo vendor > .cargo/config.toml
toolchain: "1.62"
target: aarch64-unknown-linux-musl
override: true
- name: Create Release
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: create_release
uses: actions/create-release@v1
env:
@@ -66,20 +51,8 @@ jobs:
release_name: ${{ github.ref }}
draft: true
prerelease: true
- name: Create vendored source archive
working-directory: ../
run: tar cJf cloud-hypervisor-${{ github.event.ref }}.tar.xz cloud-hypervisor-${{ github.event.ref }}
- name: Upload cloud-hypervisor vendored source archive
id: upload-release-cloud-hypervisor-vendored-sources
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ../cloud-hypervisor-${{ github.event.ref }}.tar.xz
asset_name: cloud-hypervisor-${{ github.event.ref }}.tar.xz
asset_content_type: application/x-xz
- name: Upload cloud-hypervisor
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: upload-release-cloud-hypervisor
uses: actions/upload-release-asset@v1
env:
@@ -90,6 +63,7 @@ jobs:
asset_name: cloud-hypervisor
asset_content_type: application/octet-stream
- name: Upload static cloud-hypervisor
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: upload-release-static-cloud-hypervisor
uses: actions/upload-release-asset@v1
env:
@@ -100,6 +74,7 @@ jobs:
asset_name: cloud-hypervisor-static
asset_content_type: application/octet-stream
- name: Upload ch-remote
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: upload-release-ch-remote
uses: actions/upload-release-asset@v1
env:
@@ -110,6 +85,7 @@ jobs:
asset_name: ch-remote
asset_content_type: application/octet-stream
- name: Upload static-ch-remote
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: upload-release-static-ch-remote
uses: actions/upload-release-asset@v1
env:
@@ -119,7 +95,18 @@ jobs:
asset_path: target/x86_64-unknown-linux-musl/release/ch-remote
asset_name: ch-remote-static
asset_content_type: application/octet-stream
- name: Clean build tree ahead of cross build
uses: actions-rs/cargo@v1
with:
command: clean
- name: Static Build (AArch64)
uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --all --release --target=aarch64-unknown-linux-musl
- name: Upload static AArch64 cloud-hypervisor
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: upload-release-static-aarch64-cloud-hypervisor
uses: actions/upload-release-asset@v1
env:
@@ -130,6 +117,7 @@ jobs:
asset_name: cloud-hypervisor-static-aarch64
asset_content_type: application/octet-stream
- name: Upload static AArch64 ch-remote
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: upload-release-static-aarch64-ch-remote
uses: actions/upload-release-asset@v1
env:
@@ -139,3 +127,24 @@ jobs:
asset_path: target/aarch64-unknown-linux-musl/release/ch-remote
asset_name: ch-remote-static-aarch64
asset_content_type: application/octet-stream
- name: Vendor
working-directory: ../cloud-hypervisor-${{ github.event.ref }}
run: |
mkdir ../vendor-cargo-home
export CARGO_HOME=$(realpath ../vendor-cargo-home)
mkdir .cargo
cargo vendor > .cargo/config.toml
- name: Create vendored source archive
working-directory: ../
run: tar cJf cloud-hypervisor-${{ github.event.ref }}.tar.xz cloud-hypervisor-${{ github.event.ref }}
- name: Upload cloud-hypervisor vendored source archive
if: github.event_name == 'create' && github.event.ref_type == 'tag'
id: upload-release-cloud-hypervisor-vendored-sources
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ../cloud-hypervisor-${{ github.event.ref }}.tar.xz
asset_name: cloud-hypervisor-${{ github.event.ref }}.tar.xz
asset_content_type: application/x-xz

1
.gitignore vendored
View File

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

287
Cargo.lock generated
View File

@@ -11,18 +11,18 @@ dependencies = [
[[package]]
name = "aho-corasick"
version = "0.7.19"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.66"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
[[package]]
name = "api_client"
@@ -59,17 +59,6 @@ dependencies = [
"vmm-sys-util",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@@ -99,6 +88,7 @@ dependencies = [
"libc",
"log",
"qcow",
"smallvec",
"thiserror",
"versionize",
"versionize_derive",
@@ -118,9 +108,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.73"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
[[package]]
name = "cfg-if"
@@ -130,13 +120,13 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.0.18"
version = "4.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b"
checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
dependencies = [
"atty",
"bitflags",
"clap_lex",
"is-terminal",
"once_cell",
"strsim",
"termcolor",
@@ -154,7 +144,7 @@ dependencies = [
[[package]]
name = "cloud-hypervisor"
version = "28.0.0"
version = "29.0.0"
dependencies = [
"anyhow",
"api_client",
@@ -276,12 +266,12 @@ dependencies = [
[[package]]
name = "env_logger"
version = "0.9.3"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
dependencies = [
"atty",
"humantime",
"is-terminal",
"log",
"regex",
"termcolor",
@@ -365,9 +355,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.7"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
"libc",
@@ -382,9 +372,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "hermit-abi"
version = "0.1.20"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7a30908dbce072eca83216eab939d2290080e00ca71611b96a09e5cdce5f3fa"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
@@ -419,12 +409,11 @@ dependencies = [
[[package]]
name = "iced-x86"
version = "1.17.0"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "158f5204401d08f91d19176112146d75e99b3cf745092e268fa7be33e09adcec"
checksum = "1dd04b950d75b3498320253b17fb92745b2cc79ead8814aede2f7c1bab858bec"
dependencies = [
"lazy_static",
"static_assertions",
]
[[package]]
@@ -444,15 +433,19 @@ dependencies = [
[[package]]
name = "io-lifetimes"
version = "0.7.4"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e481ccbe3dea62107216d0d1138bb8ad8e5e5c43009a098bd1990272c497b0"
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "io-uring"
version = "0.5.8"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00d78c9f2db2a9800dfd15c69543896dae2135112dde0d1944442e83da8ce23a"
checksum = "c9ddf18110cedc09617f5a965bdb51adb0c0fb02c791e4ab22f7a21bb25269b0"
dependencies = [
"bitflags",
"libc",
@@ -468,15 +461,27 @@ dependencies = [
]
[[package]]
name = "itoa"
version = "1.0.4"
name = "is-terminal"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys",
]
[[package]]
name = "itoa"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "kvm-bindings"
version = "0.5.0"
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.5.0-tdx#52e56d0e8ef0f6ea32fc0492e6a175b73617a49f"
version = "0.6.0"
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.6.0-tdx#7d9ffb47e5b9b1989577258800a0f57c93f1445f"
dependencies = [
"serde",
"serde_derive",
@@ -485,8 +490,9 @@ dependencies = [
[[package]]
name = "kvm-ioctls"
version = "0.11.0"
source = "git+https://github.com/rust-vmm/kvm-ioctls?branch=main#e6739aeebcc56dfea62216b2cc4cddd13d0a1182"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3a321cabd827642499c77e27314f388dd83a717a5ca716b86476fb947f73ae4"
dependencies = [
"kvm-bindings",
"libc",
@@ -501,9 +507,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.137"
version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "libssh2-sys"
@@ -533,18 +539,18 @@ dependencies = [
[[package]]
name = "linux-loader"
version = "0.7.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8242360c7d79a7713a28043c994b815e9820b0e97e44b228ec9bd913c16bdfe"
checksum = "b9259ddbfbb52cc918f6bbc60390004ddd0228cf1d85f402009ff2b3d95de83f"
dependencies = [
"vm-memory",
]
[[package]]
name = "linux-raw-sys"
version = "0.0.46"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]]
name = "lock_api"
@@ -580,7 +586,7 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "micro_http"
version = "0.1.0"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#863b0370ba7e57f7df5b908ada9e5b44809ccae9"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#4b18a043e997da5b5f679e3defc279fec908753e"
dependencies = [
"libc",
"vmm-sys-util",
@@ -589,7 +595,7 @@ dependencies = [
[[package]]
name = "mshv-bindings"
version = "0.1.1"
source = "git+https://github.com/rust-vmm/mshv?branch=main#1a9ca01801e78f8ddc2630660cbab3bc3300e39e"
source = "git+https://github.com/rust-vmm/mshv?branch=main#fb19bb30110c3a3268ad815897bba407fce1843c"
dependencies = [
"libc",
"serde",
@@ -601,7 +607,7 @@ dependencies = [
[[package]]
name = "mshv-ioctls"
version = "0.1.1"
source = "git+https://github.com/rust-vmm/mshv?branch=main#1a9ca01801e78f8ddc2630660cbab3bc3300e39e"
source = "git+https://github.com/rust-vmm/mshv?branch=main#fb19bb30110c3a3268ad815897bba407fce1843c"
dependencies = [
"libc",
"mshv-bindings",
@@ -672,9 +678,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
version = "0.9.77"
version = "0.9.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a"
checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7"
dependencies = [
"autocfg",
"cc",
@@ -690,9 +696,9 @@ version = "0.1.0"
[[package]]
name = "os_str_bytes"
version = "6.3.0"
version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
name = "parking_lot"
@@ -721,9 +727,9 @@ dependencies = [
[[package]]
name = "paste"
version = "1.0.9"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
[[package]]
name = "pci"
@@ -920,9 +926,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.21"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
@@ -973,9 +979,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.6.0"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"aho-corasick",
"memchr",
@@ -984,15 +990,15 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.6.27"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "remain"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a81bc6a3aaeb180f767bd2bda8c03bac5b93b3b69a783c66f35d16a4df276cf"
checksum = "5704e2cda92fd54202f05430725317ba0ea7d0c96b246ca0a92e45177127ba3b"
dependencies = [
"proc-macro2",
"quote",
@@ -1010,16 +1016,16 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.35.12"
version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "985947f9b6423159c4726323f373be0a21bdb514c5af06a849cb3d2dce2d01e8"
checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys 0.36.1",
"windows-sys",
]
[[package]]
@@ -1045,24 +1051,24 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.14"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
[[package]]
name = "serde"
version = "1.0.147"
version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.147"
version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
dependencies = [
"proc-macro2",
"quote",
@@ -1071,9 +1077,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.87"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
dependencies = [
"itoa",
"ryu",
@@ -1082,9 +1088,9 @@ dependencies = [
[[package]]
name = "serde_with"
version = "2.0.1"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368f2d60d049ea019a84dcd6687b0d1e0030fe663ae105039bdf967ed5e6a9a7"
checksum = "25bf4a5a814902cd1014dbccfa4d4560fb8432c779471e96e035602519f82eef"
dependencies = [
"serde",
"serde_with_macros",
@@ -1092,9 +1098,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
version = "2.0.1"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ccadfacf6cf10faad22bbadf55986bdd0856edfb5d9210aa1dcf1f516e84e93"
checksum = "e3452b4c0f6c1e357f73fdb87cd1efabaa12acf328c7a528e252893baeb3f4aa"
dependencies = [
"darling",
"proc-macro2",
@@ -1149,12 +1155,6 @@ dependencies = [
"parking_lot",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
version = "0.10.0"
@@ -1163,9 +1163,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.103"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
dependencies = [
"proc-macro2",
"quote",
@@ -1183,12 +1183,12 @@ dependencies = [
[[package]]
name = "terminal_size"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ca90c434fd12083d1a6bdcbe9f92a14f96c8a1ba600ba451734ac334521f7a"
checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
dependencies = [
"rustix",
"windows-sys 0.42.0",
"windows-sys",
]
[[package]]
@@ -1208,18 +1208,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.37"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.37"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
@@ -1251,15 +1251,15 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.5"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "uuid"
version = "1.2.1"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "feb41e78f93363bb2df8b0e86a2ca30eed7806ea16ea0c790d757cf93f79be83"
checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
dependencies = [
"getrandom",
]
@@ -1272,9 +1272,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "versionize"
version = "0.1.6"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7429cf68de8f091b667d27323ed323afd39584a56d533995b12ddd748e5e6ca9"
checksum = "d6e2495726cf917e7ba7ec8bf0f0fceab543dd38d0a4195ed6bef331e38a290f"
dependencies = [
"bincode",
"crc64",
@@ -1299,17 +1299,16 @@ dependencies = [
[[package]]
name = "vfio-bindings"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43449b404c488f70507dca193debd4bea361fe8089869b947adc19720e464bce"
version = "0.4.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#7ef33f6759ae6d37a54cd66f749aa47c1c81509c"
dependencies = [
"vmm-sys-util",
]
[[package]]
name = "vfio-ioctls"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#ad86d843a22fbf98efa9c02a5689fe2bf17ed54a"
version = "0.2.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#7ef33f6759ae6d37a54cd66f749aa47c1c81509c"
dependencies = [
"byteorder",
"kvm-bindings",
@@ -1354,8 +1353,9 @@ dependencies = [
[[package]]
name = "vhost"
version = "0.5.0"
source = "git+https://github.com/rust-vmm/vhost?branch=main#f87156b77662af63b9fc9f116a213dd69e16007b"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9b791c5b0717a0558888a4cf7240cea836f39a99cb342e12ce633dcaa078072"
dependencies = [
"bitflags",
"libc",
@@ -1365,9 +1365,9 @@ dependencies = [
[[package]]
name = "vhost-user-backend"
version = "0.7.0"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a0fc7d5f8e2943cd9f2ecd58be3f2078add863a49573d14dd9d64e1ab26544c"
checksum = "9f237b91db4ac339d639fb43398b52d785fa51e3c7760ac9425148863c1f4303"
dependencies = [
"libc",
"log",
@@ -1459,9 +1459,9 @@ dependencies = [
[[package]]
name = "virtio-queue"
version = "0.6.1"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435dd49c7b38419729afd43675850c7b5dc4728f2fabd70c7a9079a331e4f8c6"
checksum = "19e927d93d54c365034fd7f31a5f458a1f540de4a37c52e892670dad9692173c"
dependencies = [
"log",
"virtio-bindings",
@@ -1494,13 +1494,13 @@ dependencies = [
[[package]]
name = "vm-fdt"
version = "0.2.0"
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#d9425907389e1fbbfb803017d01824a4bb16e6a8"
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#c5a99ab71b130435927d19b50c85fcd5ce904a8c"
[[package]]
name = "vm-memory"
version = "0.9.0"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "583f213899e8a5eea23d9c507252d4bed5bc88f0ecbe0783262f80034630744b"
checksum = "688a70366615b45575a424d9c665561c1b5ab2224d494f706b6a6812911a827c"
dependencies = [
"arc-swap",
"libc",
@@ -1580,9 +1580,9 @@ dependencies = [
[[package]]
name = "vmm-sys-util"
version = "0.10.0"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08604d7be03eb26e33b3cee3ed4aef2bf550b305d1cca60e84da5d28d3790b62"
checksum = "cc06a16ee8ebf0d9269aed304030b0d20a866b8b3dd3d4ce532596ac567a0d24"
dependencies = [
"bitflags",
"libc",
@@ -1636,19 +1636,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
dependencies = [
"windows_aarch64_msvc 0.36.1",
"windows_i686_gnu 0.36.1",
"windows_i686_msvc 0.36.1",
"windows_x86_64_gnu 0.36.1",
"windows_x86_64_msvc 0.36.1",
]
[[package]]
name = "windows-sys"
version = "0.42.0"
@@ -1656,12 +1643,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.42.0",
"windows_i686_gnu 0.42.0",
"windows_i686_msvc 0.42.0",
"windows_x86_64_gnu 0.42.0",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.42.0",
"windows_x86_64_msvc",
]
[[package]]
@@ -1670,48 +1657,24 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
[[package]]
name = "windows_i686_gnu"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
[[package]]
name = "windows_i686_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.0"
@@ -1724,12 +1687,6 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.0"

View File

@@ -1,6 +1,6 @@
[package]
name = "cloud-hypervisor"
version = "28.0.0"
version = "29.0.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
default-run = "cloud-hypervisor"
@@ -10,48 +10,49 @@ description = "Open source Virtual Machine Monitor (VMM) that runs on top of KVM
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
# Minimum buildable version:
# Keep in sync with version in .github/workflows/build.yaml
# Policy on MSRV (see #4318):
# Can only be bumped by:
# a.) A dependency requires it,
# b.) If we want to use a new feature and that MSRV is at least 6 months old,
# c.) There is a security issue that is addressed by the toolchain update.
rust-version = "1.60"
[profile.release]
lto = true
codegen-units = 1
opt-level = "s"
strip = true
[dependencies]
anyhow = "1.0.66"
anyhow = "1.0.68"
api_client = { path = "api_client" }
clap = { version = "4.0.18", features = ["wrap_help","cargo","string"] }
clap = { version = "4.0.32", features = ["wrap_help","cargo","string"] }
epoll = "4.3.1"
event_monitor = { path = "event_monitor" }
hypervisor = { path = "hypervisor" }
libc = "0.2.137"
libc = "0.2.139"
log = { version = "0.4.17", features = ["std"] }
option_parser = { path = "option_parser" }
seccompiler = "0.3.0"
serde_json = "1.0.87"
serde_json = "1.0.89"
signal-hook = "0.3.14"
thiserror = "1.0.37"
thiserror = "1.0.38"
tpm = { path = "tpm"}
tracer = { path = "tracer" }
vmm = { path = "vmm" }
vmm-sys-util = "0.10.0"
vm-memory = "0.9.0"
[build-dependencies]
clap = { version = "4.0.18", features = ["cargo"] }
vmm-sys-util = "0.11.0"
vm-memory = "0.10.0"
# List of patched crates
[patch.crates-io]
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx" }
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" }
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
vhost = { git = "https://github.com/rust-vmm/vhost", branch = "main" }
[dev-dependencies]
dirs = "4.0.0"
net_util = { path = "net_util" }
once_cell = "1.16.0"
serde_json = "1.0.87"
serde_json = "1.0.89"
test_infra = { path = "test_infra" }
wait-timeout = "0.2.0"

153
Jenkinsfile vendored
View File

@@ -10,29 +10,16 @@ pipeline {
checkout scm
}
}
stage('Check for documentation only changes') {
stage('Check if worker build can be skipped') {
when {
expression {
return docsFileOnly()
return skipWorkerBuild()
}
}
steps {
script {
runWorkers = false
echo 'Documentation only changes, no need to run the CI'
}
}
}
stage('Check for fuzzer files only changes') {
when {
expression {
return fuzzFileOnly()
}
}
steps {
script {
runWorkers = false
echo 'Fuzzer cargo files only changes, no need to run the CI'
echo 'No changes requring a build'
}
}
}
@@ -281,6 +268,113 @@ pipeline {
}
}
}
stage('Worker build - Rate Limiter') {
agent { node { label 'focal-metrics' } }
when {
branch 'main'
beforeAgent true
expression {
return runWorkers
}
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Run rate-limiter integration tests') {
options {
timeout(time: 10, unit: 'MINUTES')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-rate-limiter'
}
}
}
}
stage('Worker build - SGX') {
agent { node { label 'jammy-sgx' } }
when {
beforeAgent true
allOf {
branch 'main'
expression {
return runWorkers
}
}
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Run SGX integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-sgx'
}
}
stage('Run SGX integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'scripts/dev_cli.sh tests --integration-sgx --libc musl'
}
}
}
post {
always {
sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
deleteDir()
}
}
}
stage('Worker build - VFIO') {
agent { node { label 'jammy-vfio' } }
when {
beforeAgent true
allOf {
branch 'main'
expression {
return runWorkers
}
}
}
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()
}
}
}
}
}
}
@@ -325,24 +419,31 @@ def installAzureCli(distro, arch) {
sh 'sudo apt install -y azure-cli'
}
def boolean docsFileOnly() {
def boolean skipWorkerBuild() {
if (env.CHANGE_TARGET == null) {
return false
}
return sh(
if (sh(
returnStatus: true,
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v '\\.md'"
) != 0
}
def boolean fuzzFileOnly() {
if (env.CHANGE_TARGET == null) {
return false
) != 0) {
return true
}
return sh(
if (sh(
returnStatus: true,
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v -E 'fuzz/'"
) != 0
) != 0) {
return true
}
if (sh(
returnStatus: true,
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v -E '.github/'"
) != 0) {
return true
}
return false
}

View File

@@ -69,10 +69,12 @@ Cloud Hypervisor supports `64-bit Linux` and Windows 10/Windows Server 2019.
# 2. Getting Started
The following sections describe how to build and run Cloud Hypervisor on the
`x86-64` platform. For getting started on the `AArch64` platform, please refer
to the
[AArch64 documentation](docs/arm64.md).
The following sections describe how to build and run Cloud Hypervisor.
## Prerequisites for AArch64
- AArch64 servers (recommended) or development boards equipped with the GICv3
interrupt controller.
## Host OS
@@ -105,13 +107,10 @@ do not wish to use the pre-built binaries.
## Booting Linux
The instructions below are for the `x86-64` platform. For `AArch64` please see
the [AArch64 specific documentation](docs/arm64.md).
Cloud Hypervisor supports direct kernel boot (if the kernel is built with PVH
support) or booting via a firmware (either [Rust Hypervisor
Cloud Hypervisor supports direct kernel boot (the x86-64 kernel requires the kernel
built with PVH support) or booting via a firmware (either [Rust Hypervisor
Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) or an
edk2 UEFI firmware called `CLOUDHV`.)
edk2 UEFI firmware called `CLOUDHV` / `CLOUDHV_EFI`.)
Binary builds of the firmware files are available for the latest release of
[Rust Hyperivor
@@ -173,7 +172,7 @@ $ ./cloud-hypervisor \
#### Building your Kernel
Cloud Hypervisor also supports direct kernel boot into a `vmlinux` ELF kernel (compiled with PVH support). In order to support development there is a custom branch; however provided the required options are enabled any recent kernel will suffice.
Cloud Hypervisor also supports direct kernel boot. For x86-64, a `vmlinux` ELF kernel (compiled with PVH support) is needed. In order to support development there is a custom branch; however provided the required options are enabled any recent kernel will suffice.
To build the kernel:
@@ -181,15 +180,23 @@ To build the kernel:
# Clone the Cloud Hypervisor Linux branch
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-5.15.12 linux-cloud-hypervisor
$ pushd linux-cloud-hypervisor
# Use the cloud-hypervisor kernel config to build your kernel
# Use the x86-64 cloud-hypervisor kernel config to build your kernel for x86-64
$ wget https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/main/resources/linux-config-x86_64
$ cp linux-config-x86_64 .config
# Use the AArch64 cloud-hypervisor kernel config to build your kernel for AArch64
$ wget https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/main/resources/linux-config-aarch64
$ cp linux-config-x86_64 .config # x86-64
$ cp linux-config-aarch64 .config # AArch64
# Do native build of the x86-64 kernel
$ KCFLAGS="-Wa,-mx86-used-note=no" make bzImage -j `nproc`
# Do native build of the AArch64 kernel
$ make -j `nproc`
$ popd
```
The `vmlinux` kernel image will then be located at
For x86-64, the `vmlinux` kernel image will then be located at
`linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin`.
For AArch64, the `Image` kernel image will then be located at
`linux-cloud-hypervisor/arch/arm64/boot/Image`.
#### Disk image
@@ -197,8 +204,10 @@ For the disk image the same Ubuntu image as before can be used. This contains
an `ext4` root filesystem.
```shell
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-server-cloudimg-amd64.raw
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img # x86-64
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-arm64.img # AArch64
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-server-cloudimg-amd64.raw # x86-64
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-arm64.img focal-server-cloudimg-arm64.raw # AArch64
```
#### Booting the guest VM
@@ -206,6 +215,8 @@ $ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-serv
These sample commands boot the disk image using the custom kernel whilst also
supplying the desired kernel command line.
- x86-64
```shell
$ sudo setcap cap_net_admin+ep ./cloud-hypervisor
$ ./create-cloud-init.sh
@@ -218,9 +229,26 @@ $ ./cloud-hypervisor \
--net "tap=,mac=,ip=,mask="
```
- AArch64
```shell
$ sudo setcap cap_net_admin+ep ./cloud-hypervisor
$ ./create-cloud-init.sh
$ ./cloud-hypervisor \
--kernel ./linux-cloud-hypervisor/arch/arm64/boot/Image \
--disk path=focal-server-cloudimg-arm64.raw path=/tmp/ubuntu-cloudinit.img \
--cmdline "console=hvc0 root=/dev/vda1 rw" \
--cpus boot=4 \
--memory size=1024M \
--net "tap=,mac=,ip=,mask="
```
If earlier kernel messages are required the serial console should be used instead of `virtio-console`.
```cloud-hypervisor \
- x86-64
```shell
$ ./cloud-hypervisor \
--kernel ./linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin \
--console off \
--serial tty \
@@ -231,6 +259,20 @@ If earlier kernel messages are required the serial console should be used instea
--net "tap=,mac=,ip=,mask="
```
- AArch64
```shell
$ ./cloud-hypervisor \
--kernel ./linux-cloud-hypervisor/arch/arm64/boot/Image \
--console off \
--serial tty \
--disk path=focal-server-cloudimg-arm64.raw \
--cmdline "console=ttyAMA0 root=/dev/vda1 rw" \
--cpus boot=4 \
--memory size=1024M \
--net "tap=,mac=,ip=,mask="
```
# 3. Status
Cloud Hypervisor is under active development. The following stability
@@ -254,12 +296,11 @@ Currently the following items are **not** guaranteed across updates:
Further details can be found in the [release documentation](docs/releases.md).
As of 2022-10-13, the following cloud images are supported:
As of 2023-01-03, the following cloud images are supported:
- [Ubuntu Bionic](https://cloud-images.ubuntu.com/bionic/current/) (bionic-server-cloudimg-amd64.img)
- [Ubuntu Focal](https://cloud-images.ubuntu.com/focal/current/) (focal-server-cloudimg-amd64.img)
- [Ubuntu Jammy](https://cloud-images.ubuntu.com/jammy/current/) (jammy-server-cloudimg-amd64.img )
- [Fedora 36](https://fedora.mirrorservice.org/fedora/linux/releases/36/Cloud/x86_64/images/) (Fedora-Cloud-Base-36-1.5.x86_64.raw.xz)
- [Ubuntu Focal](https://cloud-images.ubuntu.com/focal/current/) (focal-server-cloudimg-{amd64,arm64}.img)
- [Ubuntu Jammy](https://cloud-images.ubuntu.com/jammy/current/) (jammy-server-cloudimg-{amd64,arm64}.img )
- [Fedora 36](https://fedora.mirrorservice.org/fedora/linux/releases/36/Cloud/) ([Fedora-Cloud-Base-36-1.5.x86_64.raw.xz](https://fedora.mirrorservice.org/fedora/linux/releases/36/Cloud/x86_64/images/) / [Fedora-Cloud-Base-36-1.5.aarch64.raw.xz](https://fedora.mirrorservice.org/fedora/linux/releases/36/Cloud/aarch64/images/))
Direct kernel boot to userspace should work with a rootfs from most
distributions although you may need to enable exotic filesystem types in the

View File

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

View File

@@ -38,7 +38,6 @@ pub struct Sdt {
data: Vec<u8>,
}
#[allow(clippy::len_without_is_empty)]
impl Sdt {
pub fn new(
signature: [u8; 4],
@@ -98,6 +97,7 @@ impl Sdt {
/// Write a value at the given offset
pub fn write<T>(&mut self, offset: usize, value: T) {
assert!((offset + (std::mem::size_of::<T>() - 1)) < self.data.len());
// SAFETY: The assertion above makes sure we don't do out of bounds write.
unsafe {
*(((self.data.as_mut_ptr() as usize) + offset) as *mut T) = value;
}
@@ -123,6 +123,10 @@ impl Sdt {
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
}
#[cfg(test)]

View File

@@ -5,4 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
[dependencies]
vmm-sys-util = "0.10.0"
vmm-sys-util = "0.11.0"

View File

@@ -22,16 +22,16 @@ impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
match self {
Socket(e) => write!(f, "Error writing to or reading from HTTP socket: {}", e),
SocketSendFds(e) => write!(f, "Error writing to or reading from HTTP socket: {}", e),
StatusCodeParsing(e) => write!(f, "Error parsing HTTP status code: {}", e),
Socket(e) => write!(f, "Error writing to or reading from HTTP socket: {e}"),
SocketSendFds(e) => write!(f, "Error writing to or reading from HTTP socket: {e}"),
StatusCodeParsing(e) => write!(f, "Error parsing HTTP status code: {e}"),
MissingProtocol => write!(f, "HTTP output is missing protocol statement"),
ContentLengthParsing(e) => write!(f, "Error parsing HTTP Content-Length field: {}", e),
ContentLengthParsing(e) => write!(f, "Error parsing HTTP Content-Length field: {e}"),
ServerResponse(s, o) => {
if let Some(o) = o {
write!(f, "Server responded with an error: {:?}: {}", s, o)
write!(f, "Server responded with an error: {s:?}: {o}")
} else {
write!(f, "Server responded with an error: {:?}", s)
write!(f, "Server responded with an error: {s:?}")
}
}
}
@@ -79,7 +79,7 @@ impl StatusCode {
}
fn get_header<'a>(res: &'a str, header: &'a str) -> Option<&'a str> {
let header_str = format!("{}: ", header);
let header_str = format!("{header}: ");
res.find(&header_str)
.map(|o| &res[o + header_str.len()..o + res[o..].find('\r').unwrap()])
}
@@ -153,8 +153,7 @@ pub fn simple_api_full_command_with_fds_and_response<T: Read + Write + ScmSocket
socket
.send_with_fds(
&[format!(
"{} /api/v1/{} HTTP/1.1\r\nHost: localhost\r\nAccept: */*\r\n",
method, full_command
"{method} /api/v1/{full_command} HTTP/1.1\r\nHost: localhost\r\nAccept: */*\r\n"
)
.as_bytes()],
&request_fds,
@@ -235,7 +234,7 @@ pub fn simple_api_command_with_fds<T: Read + Write + ScmSocket>(
) -> Result<(), Error> {
// Create the full VM command. For VMM commands, use
// simple_api_full_command().
let full_command = format!("vm.{}", c);
let full_command = format!("vm.{c}");
simple_api_full_command_with_fds(socket, method, &full_command, request_body, request_fds)
}

View File

@@ -9,20 +9,20 @@ default = []
tdx = []
[dependencies]
anyhow = "1.0.66"
anyhow = "1.0.68"
byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" }
libc = "0.2.137"
linux-loader = { version = "0.7.0", features = ["elf", "bzimage", "pe"] }
libc = "0.2.139"
linux-loader = { version = "0.8.1", features = ["elf", "bzimage", "pe"] }
log = "0.4.17"
serde = { version = "1.0.147", features = ["rc", "derive"] }
thiserror = "1.0.37"
uuid = "1.2.1"
versionize = "0.1.6"
serde = { version = "1.0.151", features = ["rc", "derive"] }
thiserror = "1.0.38"
uuid = "1.2.2"
versionize = "0.1.9"
versionize_derive = "0.1.4"
vm-memory = { version = "0.9.0", features = ["backend-mmap", "backend-bitmap"] }
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-bitmap"] }
vm-migration = { path = "../vm-migration" }
vmm-sys-util = { version = "0.10.0", features = ["with-serde"] }
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
[target.'cfg(target_arch = "aarch64")'.dependencies]
fdt_parser = { version = "0.1.4", package = "fdt" }

View File

@@ -160,7 +160,7 @@ fn create_cpu_nodes(
let num_cpus = vcpu_mpidr.len();
for (cpu_id, mpidr) in vcpu_mpidr.iter().enumerate().take(num_cpus) {
let cpu_name = format!("cpu@{:x}", cpu_id);
let cpu_name = format!("cpu@{cpu_id:x}");
let cpu_node = fdt.begin_node(&cpu_name)?;
fdt.property_string("device_type", "cpu")?;
fdt.property_string("compatible", "arm,arm-v8")?;
@@ -192,15 +192,15 @@ fn create_cpu_nodes(
// Create device tree nodes with regard of above mapping.
for cluster_idx in 0..packages {
let cluster_name = format!("cluster{:x}", cluster_idx);
let cluster_name = format!("cluster{cluster_idx:x}");
let cluster_node = fdt.begin_node(&cluster_name)?;
for core_idx in 0..cores_per_package {
let core_name = format!("core{:x}", core_idx);
let core_name = format!("core{core_idx:x}");
let core_node = fdt.begin_node(&core_name)?;
for thread_idx in 0..threads_per_core {
let thread_name = format!("thread{:x}", thread_idx);
let thread_name = format!("thread{thread_idx:x}");
let thread_node = fdt.begin_node(&thread_name)?;
let cpu_idx = threads_per_core * cores_per_package * cluster_idx
+ threads_per_core * core_idx
@@ -247,7 +247,7 @@ fn create_memory_node(
node_memory_addr = memory_region_start_addr;
}
}
let memory_node_name = format!("memory@{:x}", node_memory_addr);
let memory_node_name = format!("memory@{node_memory_addr:x}");
let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;
@@ -259,7 +259,7 @@ fn create_memory_node(
if last_addr < super::layout::MEM_32BIT_RESERVED_START.raw_value() {
// Case 1: all RAM is under the hole
let mem_size = last_addr - super::layout::RAM_START.raw_value() + 1;
let mem_reg_prop = [super::layout::RAM_START.raw_value() as u64, mem_size as u64];
let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
let memory_node = fdt.begin_node("memory")?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;
@@ -269,7 +269,7 @@ fn create_memory_node(
// Region 1: RAM before the hole
let mem_size = super::layout::MEM_32BIT_RESERVED_START.raw_value()
- super::layout::RAM_START.raw_value();
let mem_reg_prop = [super::layout::RAM_START.raw_value() as u64, mem_size as u64];
let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
let memory_node_name = format!("memory@{:x}", super::layout::RAM_START.raw_value());
let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?;
@@ -278,10 +278,7 @@ fn create_memory_node(
// Region 2: RAM after the hole
let mem_size = last_addr - super::layout::RAM_64BIT_START.raw_value() + 1;
let mem_reg_prop = [
super::layout::RAM_64BIT_START.raw_value() as u64,
mem_size as u64,
];
let mem_reg_prop = [super::layout::RAM_64BIT_START.raw_value(), mem_size];
let memory_node_name =
format!("memory@{:x}", super::layout::RAM_64BIT_START.raw_value());
let memory_node = fdt.begin_node(&memory_node_name)?;
@@ -303,7 +300,7 @@ fn create_chosen_node(
fdt.property_string("bootargs", cmdline)?;
if let Some(initrd_config) = initrd {
let initrd_start = initrd_config.address.raw_value() as u64;
let initrd_start = initrd_config.address.raw_value();
let initrd_end = initrd_config.address.raw_value() + initrd_config.size as u64;
fdt.property_u64("linux,initrd-start", initrd_start)?;
fdt.property_u64("linux,initrd-end", initrd_end)?;
@@ -670,7 +667,7 @@ fn create_pci_nodes(
// See kernel document Documentation/devicetree/bindings/virtio/iommu.txt
// for virtio-iommu node settings.
let virtio_iommu_node_name = format!("virtio_iommu@{:x}", virtio_iommu_bdf);
let virtio_iommu_node_name = format!("virtio_iommu@{virtio_iommu_bdf:x}");
let virtio_iommu_node = fdt.begin_node(&virtio_iommu_node_name)?;
fdt.property_u32("#iommu-cells", 1)?;
fdt.property_string("compatible", "virtio,pci-iommu")?;

View File

@@ -19,7 +19,7 @@ use std::collections::HashMap;
use std::convert::TryInto;
use std::fmt::Debug;
use std::sync::{Arc, Mutex};
use vm_memory::{Address, GuestAddress, GuestMemory, GuestUsize};
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic, GuestUsize};
/// Errors thrown while configuring aarch64 system.
#[derive(Debug)]
@@ -64,9 +64,9 @@ pub struct EntryPoint {
pub fn configure_vcpu(
vcpu: &Arc<dyn hypervisor::Vcpu>,
id: u8,
kernel_entry_point: Option<EntryPoint>,
boot_setup: Option<(EntryPoint, &GuestMemoryAtomic<GuestMemoryMmap>)>,
) -> super::Result<u64> {
if let Some(kernel_entry_point) = kernel_entry_point {
if let Some((kernel_entry_point, _guest_memory)) = boot_setup {
vcpu.setup_regs(
id,
kernel_entry_point.entry_addr.raw_value(),
@@ -108,7 +108,7 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
// RAM space
// Case1: guest memory fits before the gap
if size as u64 <= ram_32bit_space_size {
if size <= ram_32bit_space_size {
regions.push((layout::RAM_START, size as usize, RegionType::Ram));
// Case2: guest memory extends beyond the gap
} else {
@@ -231,7 +231,7 @@ mod tests {
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize;
assert_eq!(6, regions.len());
assert_eq!(layout::RAM_START, regions[3].0);
assert_eq!(ram_32bit_space_size as usize, regions[3].1);
assert_eq!(ram_32bit_space_size, regions[3].1);
assert_eq!(RegionType::Ram, regions[3].2);
assert_eq!(RegionType::Reserved, regions[5].2);
assert_eq!(RegionType::Ram, regions[4].2);

View File

@@ -34,9 +34,7 @@ where
if uefi_size > 0x300000 {
return Err(Error::UefiTooBig);
}
uefi_image
.seek(SeekFrom::Start(0))
.map_err(|_| Error::SeekUefiStart)?;
uefi_image.rewind().map_err(|_| Error::SeekUefiStart)?;
guest_mem
.read_exact_from(guest_addr, uefi_image, uefi_size)
.map_err(|_| Error::ReadUefiImage)

View File

@@ -99,7 +99,7 @@ pub use x86_64::{
#[cfg(target_arch = "x86_64")]
#[inline(always)]
fn pagesize() -> usize {
// Trivially safe
// SAFETY: Trivially safe
unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
}
@@ -145,7 +145,7 @@ pub const PAGE_SIZE: usize = 4096;
impl fmt::Display for DeviceType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
write!(f, "{self:?}")
}
}

View File

@@ -125,9 +125,11 @@ struct MemmapTableEntryWrapper(hvm_memmap_table_entry);
#[derive(Copy, Clone, Default)]
struct ModlistEntryWrapper(hvm_modlist_entry);
// SAFETY: These data structures only contain a series of integers
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for StartInfoWrapper {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for MemmapTableEntryWrapper {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for ModlistEntryWrapper {}
// This is a workaround to the Rust enforcement specifying that any implementation of a foreign
@@ -545,13 +547,30 @@ impl CpuidFeatureEntry {
}
pub fn generate_common_cpuid(
hypervisor: Arc<dyn hypervisor::Hypervisor>,
hypervisor: &Arc<dyn hypervisor::Hypervisor>,
topology: Option<(u8, u8, u8)>,
sgx_epc_sections: Option<Vec<SgxEpcSection>>,
phys_bits: u8,
kvm_hyperv: bool,
#[cfg(feature = "tdx")] tdx_enabled: bool,
) -> super::Result<Vec<CpuIdEntry>> {
// SAFETY: cpuid called with valid leaves
if unsafe { x86_64::__cpuid(1) }.ecx & 1 << HYPERVISOR_ECX_BIT == 1 << HYPERVISOR_ECX_BIT {
// SAFETY: cpuid called with valid leaves
let hypervisor_cpuid = unsafe { x86_64::__cpuid(0x4000_0000) };
let mut identifier: [u8; 12] = [0; 12];
identifier[0..4].copy_from_slice(&hypervisor_cpuid.ebx.to_le_bytes()[..]);
identifier[4..8].copy_from_slice(&hypervisor_cpuid.ecx.to_le_bytes()[..]);
identifier[8..12].copy_from_slice(&hypervisor_cpuid.edx.to_le_bytes()[..]);
info!(
"Running under nested virtualisation. Hypervisor string: {}",
String::from_utf8_lossy(&identifier)
);
}
info!("Generating guest CPUID for with physical address size: {phys_bits}");
let cpuid_patches = vec![
// Patch tsc deadline timer bit
CpuidPatch {
@@ -631,6 +650,20 @@ pub fn generate_common_cpuid(
}
}
}
// Copy host L2 cache details if not populated by KVM
0x8000_0006 => {
if entry.eax == 0 && entry.ebx == 0 && entry.ecx == 0 && entry.edx == 0 {
// SAFETY: cpuid called with valid leaves
if unsafe { std::arch::x86_64::__cpuid(0x8000_0000).eax } >= 0x8000_0006 {
// SAFETY: cpuid called with valid leaves
let leaf = unsafe { std::arch::x86_64::__cpuid(0x8000_0006) };
entry.eax = leaf.eax;
entry.ebx = leaf.ebx;
entry.ecx = leaf.ecx;
entry.edx = leaf.edx;
}
}
}
// Set CPU physical bits
0x8000_0008 => {
entry.eax = (entry.eax & 0xffff_ff00) | (phys_bits as u32 & 0xff);
@@ -661,6 +694,7 @@ pub fn generate_common_cpuid(
// Copy CPU identification string
for i in 0x8000_0002..=0x8000_0004 {
cpuid.retain(|c| c.function != i);
// SAFETY: call cpuid with valid leaves
let leaf = unsafe { std::arch::x86_64::__cpuid(i) };
cpuid.push(CpuIdEntry {
function: i,
@@ -725,8 +759,7 @@ pub fn generate_common_cpuid(
pub fn configure_vcpu(
vcpu: &Arc<dyn hypervisor::Vcpu>,
id: u8,
kernel_entry_point: Option<EntryPoint>,
vm_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
boot_setup: Option<(EntryPoint, &GuestMemoryAtomic<GuestMemoryMmap>)>,
cpuid: Vec<CpuIdEntry>,
kvm_hyperv: bool,
) -> super::Result<()> {
@@ -743,12 +776,12 @@ pub fn configure_vcpu(
}
regs::setup_msrs(vcpu).map_err(Error::MsrsConfiguration)?;
if let Some(kernel_entry_point) = kernel_entry_point {
if let Some((kernel_entry_point, guest_memory)) = boot_setup {
if let Some(entry_addr) = kernel_entry_point.entry_addr {
// Safe to unwrap because this method is called after the VM is configured
regs::setup_regs(vcpu, entry_addr.raw_value()).map_err(Error::RegsConfiguration)?;
regs::setup_fpu(vcpu).map_err(Error::FpuConfiguration)?;
regs::setup_sregs(&vm_memory.memory(), vcpu).map_err(Error::SregsConfiguration)?;
regs::setup_sregs(&guest_memory.memory(), vcpu).map_err(Error::SregsConfiguration)?;
}
}
interrupts::set_lint(vcpu).map_err(|e| Error::LocalIntConfiguration(e.into()))?;
@@ -1011,6 +1044,7 @@ pub fn initramfs_load_addr(
}
pub fn get_host_cpu_phys_bits() -> u8 {
// SAFETY: call cpuid with valid leaves
unsafe {
let leaf = x86_64::__cpuid(0x8000_0000);
@@ -1121,6 +1155,7 @@ fn update_cpuid_sgx(
// Get host CPUID for leaf 0x12, subleaf 0x2. This is to retrieve EPC
// properties such as confidentiality and integrity.
// SAFETY: call cpuid with valid leaves
let leaf = unsafe { std::arch::x86_64::__cpuid_count(0x12, 0x2) };
for (i, epc_section) in epc_sections.iter().enumerate() {
@@ -1302,6 +1337,6 @@ mod tests {
add_memmap_entry(&mut memmap, 0, 0x1000, E820_RAM);
add_memmap_entry(&mut memmap, 0x10000, 0xa000, E820_RESERVED);
assert_eq!(format!("{:?}", memmap), format!("{:?}", expected_memmap));
assert_eq!(format!("{memmap:?}"), format!("{expected_memmap:?}"));
}
}

View File

@@ -37,11 +37,17 @@ struct MpfIntelWrapper(mpspec::mpf_intel);
// SAFETY: These `mpspec` wrapper types are only data, reading them from data is a safe initialization.
unsafe impl ByteValued for MpcBusWrapper {}
// SAFETY: see above
unsafe impl ByteValued for MpcCpuWrapper {}
// SAFETY: see above
unsafe impl ByteValued for MpcIntsrcWrapper {}
// SAFETY: see above
unsafe impl ByteValued for MpcIoapicWrapper {}
// SAFETY: see above
unsafe impl ByteValued for MpcTableWrapper {}
// SAFETY: see above
unsafe impl ByteValued for MpcLintsrcWrapper {}
// SAFETY: see above
unsafe impl ByteValued for MpfIntelWrapper {}
#[derive(Debug)]
@@ -95,7 +101,7 @@ const CPU_FEATURE_APIC: u32 = 0x200;
const CPU_FEATURE_FPU: u32 = 0x001;
fn compute_checksum<T: Copy>(v: &T) -> u8 {
// Safe because we are only reading the bytes within the size of the `T` reference `v`.
// SAFETY: we are only reading the bytes within the size of the `T` reference `v`.
let v_slice = unsafe { slice::from_raw_parts(v as *const T as *const u8, mem::size_of::<T>()) };
let mut checksum: u8 = 0;
for i in v_slice.iter() {
@@ -294,7 +300,7 @@ mod tests {
mpspec::MP_IOAPIC => mem::size_of::<MpcIoapicWrapper>(),
mpspec::MP_INTSRC => mem::size_of::<MpcIntsrcWrapper>(),
mpspec::MP_LINTSRC => mem::size_of::<MpcLintsrcWrapper>(),
_ => panic!("unrecognized mpc table entry type: {}", type_),
_ => panic!("unrecognized mpc table entry type: {type_}"),
}
}

View File

@@ -48,10 +48,10 @@ impl Display for Error {
Clear => "Failure while zeroing out the memory for the SMBIOS table".to_string(),
WriteSmbiosEp => "Failure to write SMBIOS entrypoint structure".to_string(),
WriteData => "Failure to write additional data to memory".to_string(),
ParseUuid(e) => format!("Failure to parse uuid: {}", e),
ParseUuid(e) => format!("Failure to parse uuid: {e}"),
};
write!(f, "SMBIOS error: {}", description)
write!(f, "SMBIOS error: {description}")
}
}
@@ -67,7 +67,7 @@ const PCI_SUPPORTED: u64 = 1 << 7;
const IS_VIRTUAL_MACHINE: u8 = 1 << 4;
fn compute_checksum<T: Copy>(v: &T) -> u8 {
// Safe because we are only reading the bytes within the size of the `T` reference `v`.
// SAFETY: we are only reading the bytes within the size of the `T` reference `v`.
let v_slice = unsafe { slice::from_raw_parts(v as *const T as *const u8, mem::size_of::<T>()) };
let mut checksum: u8 = 0;
for i in v_slice.iter() {
@@ -145,11 +145,15 @@ struct SmbiosEndOfTable {
handle: u16,
}
// SAFETY: These data structures only contain a series of integers
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for Smbios30Entrypoint {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for SmbiosBiosInfo {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for SmbiosSysInfo {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for SmbiosOemStrings {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for SmbiosEndOfTable {}
fn write_and_incr<T: ByteValued>(

View File

@@ -4,7 +4,9 @@
use crate::GuestMemoryMmap;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::str::FromStr;
use thiserror::Error;
use uuid::Uuid;
use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemoryError};
#[derive(Error, Debug)]
@@ -13,6 +15,8 @@ pub enum TdvfError {
ReadDescriptor(#[source] std::io::Error),
#[error("Failed read TDVF descriptor offset: {0}")]
ReadDescriptorOffset(#[source] std::io::Error),
#[error("Failed read GUID table: {0}")]
ReadGuidTable(#[source] std::io::Error),
#[error("Invalid descriptor signature")]
InvalidDescriptorSignature,
#[error("Invalid descriptor size")]
@@ -21,8 +25,13 @@ pub enum TdvfError {
InvalidDescriptorVersion,
#[error("Failed to write HOB details to guest memory: {0}")]
GuestMemoryWriteHob(#[source] GuestMemoryError),
#[error("Failed to create Uuid: {0}")]
UuidCreation(#[source] uuid::Error),
}
const TABLE_FOOTER_GUID: &str = "96b582de-1fb2-45f7-baea-a366c55a082d";
const TDVF_METADATA_OFFSET_GUID: &str = "e47a6535-984a-4798-865e-4685a7bf8ec2";
// TDVF_DESCRIPTOR
#[repr(packed)]
#[derive(Default)]
@@ -64,7 +73,72 @@ impl Default for TdvfSectionType {
}
}
pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfError> {
fn tdvf_descriptor_offset(file: &mut File) -> Result<(SeekFrom, bool), TdvfError> {
// Let's first try to identify the presence of the table footer GUID
file.seek(SeekFrom::End(-0x30))
.map_err(TdvfError::ReadGuidTable)?;
let mut table_footer_guid: [u8; 16] = [0; 16];
file.read_exact(&mut table_footer_guid)
.map_err(TdvfError::ReadGuidTable)?;
let uuid =
Uuid::from_slice_le(table_footer_guid.as_slice()).map_err(TdvfError::UuidCreation)?;
let expected_uuid = Uuid::from_str(TABLE_FOOTER_GUID).map_err(TdvfError::UuidCreation)?;
if uuid == expected_uuid {
// Retrieve the table size
file.seek(SeekFrom::End(-0x32))
.map_err(TdvfError::ReadGuidTable)?;
let mut table_size: [u8; 2] = [0; 2];
file.read_exact(&mut table_size)
.map_err(TdvfError::ReadGuidTable)?;
let table_size = u16::from_le_bytes(table_size) as usize;
let mut table: Vec<u8> = vec![0; table_size];
// Read the entire table
file.seek(SeekFrom::End(-(table_size as i64 + 0x20)))
.map_err(TdvfError::ReadGuidTable)?;
file.read_exact(table.as_mut_slice())
.map_err(TdvfError::ReadGuidTable)?;
// Let's start from the top and go backward down the table.
// We start after the footer GUID and the table length.
let mut offset = table_size - 18;
debug!("Parsing GUIDed structure");
while offset >= 18 {
let entry_uuid = Uuid::from_slice_le(&table[offset - 16..offset])
.map_err(TdvfError::UuidCreation)?;
let entry_size =
u16::from_le_bytes(table[offset - 18..offset - 16].try_into().unwrap()) as usize;
debug!(
"Entry GUID = {}, size = {}",
entry_uuid.hyphenated().to_string(),
entry_size
);
// Avoid going through an infinite loop if the entry size is 0
if entry_size == 0 {
break;
}
offset -= entry_size;
let expected_uuid =
Uuid::from_str(TDVF_METADATA_OFFSET_GUID).map_err(TdvfError::UuidCreation)?;
if entry_uuid == expected_uuid && entry_size == 22 {
return Ok((
SeekFrom::End(
-(u32::from_le_bytes(table[offset..offset + 4].try_into().unwrap()) as i64),
),
true,
));
}
}
}
// If we end up here, this means the firmware doesn't support the new way
// of exposing the TDVF descriptor offset through the table of GUIDs.
// That's why we fallback onto the deprecated method.
// The 32-bit offset to the TDVF metadata is located 32 bytes from
// the end of the file.
// See "TDVF Metadata Pointer" in "TDX Virtual Firmware Design Guide
@@ -74,13 +148,21 @@ pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfErro
let mut descriptor_offset: [u8; 4] = [0; 4];
file.read_exact(&mut descriptor_offset)
.map_err(TdvfError::ReadDescriptorOffset)?;
let descriptor_offset = u32::from_le_bytes(descriptor_offset) as u64;
file.seek(SeekFrom::Start(descriptor_offset))
Ok((
SeekFrom::Start(u32::from_le_bytes(descriptor_offset) as u64),
false,
))
}
pub fn parse_tdvf_sections(file: &mut File) -> Result<(Vec<TdvfSection>, bool), TdvfError> {
let (descriptor_offset, guid_found) = tdvf_descriptor_offset(file)?;
file.seek(descriptor_offset)
.map_err(TdvfError::ReadDescriptor)?;
let mut descriptor: TdvfDescriptor = Default::default();
// Safe as we read exactly the size of the descriptor header
// SAFETY: we read exactly the size of the descriptor header
file.read_exact(unsafe {
std::slice::from_raw_parts_mut(
&mut descriptor as *mut _ as *mut u8,
@@ -107,7 +189,7 @@ pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfErro
let mut sections = Vec::new();
sections.resize_with(descriptor.num_sections as usize, TdvfSection::default);
// Safe as we read exactly the advertised sections
// SAFETY: we read exactly the advertised sections
file.read_exact(unsafe {
std::slice::from_raw_parts_mut(
sections.as_mut_ptr() as *mut u8,
@@ -116,7 +198,7 @@ pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfErro
})
.map_err(TdvfError::ReadDescriptor)?;
Ok(sections)
Ok((sections, guid_found))
}
#[repr(u16)]
@@ -211,12 +293,17 @@ struct TdPayload {
payload_info: PayloadInfo,
}
// SAFETY: These data structures only contain a series of integers
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for HobHeader {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for HobHandoffInfoTable {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for HobResourceDescriptor {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for HobGuidType {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for PayloadInfo {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for TdPayload {}
pub struct TdHob {
@@ -312,12 +399,19 @@ impl TdHob {
physical_start: u64,
resource_length: u64,
ram: bool,
guid_found: bool,
) -> Result<(), TdvfError> {
self.add_resource(
mem,
physical_start,
resource_length,
if ram {
if guid_found {
0x7 /* EFI_RESOURCE_MEMORY_UNACCEPTED */
} else {
0 /* EFI_RESOURCE_SYSTEM_MEMORY */
}
} else if guid_found {
0 /* EFI_RESOURCE_SYSTEM_MEMORY */
} else {
0x5 /*EFI_RESOURCE_MEMORY_RESERVED */
@@ -445,9 +539,9 @@ mod tests {
#[ignore]
fn test_parse_tdvf_sections() {
let mut f = std::fs::File::open("tdvf.fd").unwrap();
let sections = parse_tdvf_sections(&mut f).unwrap();
let (sections, _) = parse_tdvf_sections(&mut f).unwrap();
for section in sections {
eprintln!("{:x?}", section)
eprintln!("{section:x?}")
}
}
}

View File

@@ -8,17 +8,18 @@ edition = "2021"
default = []
[dependencies]
io-uring = "0.5.8"
libc = "0.2.137"
io-uring = "0.5.11"
libc = "0.2.139"
log = "0.4.17"
qcow = { path = "../qcow" }
thiserror = "1.0.37"
versionize = "0.1.6"
smallvec = "1.10.0"
thiserror = "1.0.38"
versionize = "0.1.9"
versionize_derive = "0.1.4"
vhdx = { path = "../vhdx" }
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
virtio-queue = "0.6.1"
vm-memory = { version = "0.9.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
virtio-queue = "0.7.0"
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.10.0"
vmm-sys-util = "0.11.0"

View File

@@ -3,7 +3,6 @@
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use libc::{ioctl, S_IFBLK, S_IFMT};
use std::convert::TryInto;
use std::fs::File;
use std::os::unix::io::AsRawFd;
use thiserror::Error;
@@ -54,19 +53,21 @@ enum BlockSize {
impl DiskTopology {
fn is_block_device(f: &mut File) -> std::io::Result<bool> {
let mut stat = std::mem::MaybeUninit::<libc::stat>::uninit();
// SAFETY: FFI call with a valid fd and buffer
let ret = unsafe { libc::fstat(f.as_raw_fd(), stat.as_mut_ptr()) };
if ret != 0 {
return Err(std::io::Error::last_os_error());
}
// SAFETY: stat is valid at this point
let is_block = unsafe { (*stat.as_ptr()).st_mode & S_IFMT == S_IFBLK };
Ok(is_block)
}
// libc::ioctl() takes different types on different architectures
#[allow(clippy::useless_conversion)]
fn query_block_size(f: &mut File, block_size_type: BlockSize) -> std::io::Result<u64> {
let mut block_size = 0;
// SAFETY: FFI call with correct arguments
let ret = unsafe {
ioctl(
f.as_raw_fd(),
@@ -75,9 +76,7 @@ impl DiskTopology {
BlockSize::PhysicalBlock => BLKPBSZGET(),
BlockSize::MinimumIo => BLKIOMIN(),
BlockSize::OptimalIo => BLKIOOPT(),
}
.try_into()
.unwrap(),
} as _,
&mut block_size,
)
};
@@ -132,15 +131,15 @@ pub trait AsyncIo: Send {
fn read_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()>;
fn write_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()>;
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()>;
fn complete(&mut self) -> Vec<(u64, i32)>;
fn next_completed_request(&mut self) -> Option<(u64, i32)>;
}

View File

@@ -64,7 +64,7 @@ impl AsyncIo for FixedVhdAsync {
fn read_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
if offset as u64 >= self.size {
@@ -83,7 +83,7 @@ impl AsyncIo for FixedVhdAsync {
fn write_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
if offset as u64 >= self.size {
@@ -104,7 +104,7 @@ impl AsyncIo for FixedVhdAsync {
self.raw_file_async.fsync(user_data)
}
fn complete(&mut self) -> Vec<(u64, i32)> {
self.raw_file_async.complete()
fn next_completed_request(&mut self) -> Option<(u64, i32)> {
self.raw_file_async.next_completed_request()
}
}

View File

@@ -62,7 +62,7 @@ impl AsyncIo for FixedVhdSync {
fn read_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
if offset as u64 >= self.size {
@@ -81,7 +81,7 @@ impl AsyncIo for FixedVhdSync {
fn write_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
if offset as u64 >= self.size {
@@ -101,7 +101,7 @@ impl AsyncIo for FixedVhdSync {
self.raw_file_sync.fsync(user_data)
}
fn complete(&mut self) -> Vec<(u64, i32)> {
self.raw_file_sync.complete()
fn next_completed_request(&mut self) -> Option<(u64, i32)> {
self.raw_file_sync.next_completed_request()
}
}

View File

@@ -22,8 +22,10 @@ pub mod vhdx_sync;
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult};
use io_uring::{opcode, IoUring, Probe};
use smallvec::SmallVec;
use std::alloc::{alloc_zeroed, dealloc, Layout};
use std::cmp;
use std::collections::VecDeque;
use std::convert::TryInto;
use std::fs::File;
use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
@@ -32,6 +34,7 @@ use std::path::Path;
use std::result;
use std::sync::Arc;
use std::sync::MutexGuard;
use std::time::Instant;
use thiserror::Error;
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
@@ -195,10 +198,11 @@ pub struct AlignedOperation {
pub struct Request {
pub request_type: RequestType,
pub sector: u64,
pub data_descriptors: Vec<(GuestAddress, u32)>,
pub data_descriptors: SmallVec<[(GuestAddress, u32); 1]>,
pub status_addr: GuestAddress,
pub writeback: bool,
pub aligned_operations: Vec<AlignedOperation>,
pub start: Instant,
}
impl Request {
@@ -226,10 +230,11 @@ impl Request {
let mut req = Request {
request_type: request_type(desc_chain.memory(), hdr_desc_addr)?,
sector: sector(desc_chain.memory(), hdr_desc_addr)?,
data_descriptors: Vec::new(),
data_descriptors: SmallVec::with_capacity(1),
status_addr: GuestAddress(0),
writeback: true,
aligned_operations: Vec::new(),
start: Instant::now(),
};
let status_desc;
@@ -249,6 +254,7 @@ impl Request {
return Err(Error::DescriptorChainTooShort);
}
} else {
req.data_descriptors.reserve_exact(1);
while desc.has_next() {
if desc.is_write_only() && req.request_type == RequestType::Out {
return Err(Error::UnexpectedWriteOnlyDescriptor);
@@ -353,7 +359,8 @@ impl Request {
let request_type = self.request_type;
let offset = (sector << SECTOR_SHIFT) as libc::off_t;
let mut iovecs = Vec::new();
let mut iovecs: SmallVec<[libc::iovec; 1]> =
SmallVec::with_capacity(self.data_descriptors.len());
for (data_addr, data_len) in &self.data_descriptors {
if *data_len == 0 {
continue;
@@ -381,7 +388,7 @@ impl Request {
let iov_base = if (origin_ptr as u64) % SECTOR_SIZE != 0 {
let layout =
Layout::from_size_align(*data_len as usize, SECTOR_SIZE as usize).unwrap();
// Safe because layout has non-zero size
// SAFETY: layout has non-zero size
let aligned_ptr = unsafe { alloc_zeroed(layout) };
if aligned_ptr.is_null() {
return Err(ExecuteError::TemporaryBufferAllocation(
@@ -392,7 +399,7 @@ impl Request {
// We need to perform the copy beforehand in case we're writing
// data out.
if request_type == RequestType::Out {
// Safe because destination buffer has been allocated with
// SAFETY: destination buffer has been allocated with
// the proper size.
unsafe {
std::ptr::copy(origin_ptr as *const u8, aligned_ptr, *data_len as usize)
@@ -430,12 +437,12 @@ impl Request {
.mark_dirty(0, *data_len as usize);
}
disk_image
.read_vectored(offset, iovecs, user_data)
.read_vectored(offset, &iovecs, user_data)
.map_err(ExecuteError::AsyncRead)?;
}
RequestType::Out => {
disk_image
.write_vectored(offset, iovecs, user_data)
.write_vectored(offset, &iovecs, user_data)
.map_err(ExecuteError::AsyncWrite)?;
}
RequestType::Flush => {
@@ -467,7 +474,7 @@ impl Request {
// We need to perform the copy after the data has been read inside
// the aligned buffer in case we're reading data in.
if self.request_type == RequestType::In {
// Safe because origin buffer has been allocated with the
// SAFETY: origin buffer has been allocated with the
// proper size.
unsafe {
std::ptr::copy(
@@ -479,7 +486,7 @@ impl Request {
}
// Free the temporary aligned buffer.
// Safe because aligned_ptr was allocated by alloc_zeroed with the same
// SAFETY: aligned_ptr was allocated by alloc_zeroed with the same
// layout
unsafe {
dealloc(
@@ -528,8 +535,9 @@ pub struct VirtioBlockGeometry {
pub sectors: u8,
}
// SAFETY: these data structures only contain a series of integers
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for VirtioBlockConfig {}
// SAFETY: data structure only contain a series of integers
unsafe impl ByteValued for VirtioBlockGeometry {}
/// Check if io_uring for block device can be used on the current system, as
@@ -588,14 +596,15 @@ where
fn read_vectored_sync(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
eventfd: &EventFd,
completion_list: &mut Vec<(u64, i32)>,
completion_list: &mut VecDeque<(u64, i32)>,
) -> AsyncIoResult<()> {
// Convert libc::iovec into IoSliceMut
let mut slices = Vec::new();
for iovec in iovecs.iter() {
// SAFETY: on Linux IoSliceMut wraps around libc::iovec
slices.push(IoSliceMut::new(unsafe { std::mem::transmute(*iovec) }));
}
@@ -611,7 +620,7 @@ where
.map_err(AsyncIoError::ReadVectored)?
};
completion_list.push((user_data, result as i32));
completion_list.push_back((user_data, result as i32));
eventfd.write(1).unwrap();
Ok(())
@@ -620,14 +629,15 @@ where
fn write_vectored_sync(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
eventfd: &EventFd,
completion_list: &mut Vec<(u64, i32)>,
completion_list: &mut VecDeque<(u64, i32)>,
) -> AsyncIoResult<()> {
// Convert libc::iovec into IoSlice
let mut slices = Vec::new();
for iovec in iovecs.iter() {
// SAFETY: on Linux IoSliceMut wraps around libc::iovec
slices.push(IoSlice::new(unsafe { std::mem::transmute(*iovec) }));
}
@@ -643,7 +653,7 @@ where
.map_err(AsyncIoError::WriteVectored)?
};
completion_list.push((user_data, result as i32));
completion_list.push_back((user_data, result as i32));
eventfd.write(1).unwrap();
Ok(())
@@ -653,7 +663,7 @@ where
&mut self,
user_data: Option<u64>,
eventfd: &EventFd,
completion_list: &mut Vec<(u64, i32)>,
completion_list: &mut VecDeque<(u64, i32)>,
) -> AsyncIoResult<()> {
let result: i32 = {
let mut file = self.file();
@@ -665,7 +675,7 @@ where
};
if let Some(user_data) = user_data {
completion_list.push((user_data, result));
completion_list.push_back((user_data, result));
eventfd.write(1).unwrap();
}

View File

@@ -5,6 +5,7 @@
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
use crate::AsyncAdaptor;
use qcow::{QcowFile, RawFile, Result as QcowResult};
use std::collections::VecDeque;
use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::sync::{Arc, Mutex, MutexGuard};
@@ -37,7 +38,7 @@ impl DiskFile for QcowDiskSync {
pub struct QcowSync {
qcow_file: Arc<Mutex<QcowFile>>,
eventfd: EventFd,
completion_list: Vec<(u64, i32)>,
completion_list: VecDeque<(u64, i32)>,
}
impl QcowSync {
@@ -46,7 +47,7 @@ impl QcowSync {
qcow_file,
eventfd: EventFd::new(libc::EFD_NONBLOCK)
.expect("Failed creating EventFd for QcowSync"),
completion_list: Vec::new(),
completion_list: VecDeque::new(),
}
}
}
@@ -65,7 +66,7 @@ impl AsyncIo for QcowSync {
fn read_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
self.qcow_file.read_vectored_sync(
@@ -80,7 +81,7 @@ impl AsyncIo for QcowSync {
fn write_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
self.qcow_file.write_vectored_sync(
@@ -97,7 +98,7 @@ impl AsyncIo for QcowSync {
.fsync_sync(user_data, &self.eventfd, &mut self.completion_list)
}
fn complete(&mut self) -> Vec<(u64, i32)> {
self.completion_list.drain(..).collect()
fn next_completed_request(&mut self) -> Option<(u64, i32)> {
self.completion_list.pop_front()
}
}

View File

@@ -76,12 +76,12 @@ impl AsyncIo for RawFileAsync {
fn read_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
let (submitter, mut sq, _) = self.io_uring.split();
// Safe because we know the file descriptor is valid and we
// SAFETY: we know the file descriptor is valid and we
// relied on vm-memory to provide the buffer address.
let _ = unsafe {
sq.push(
@@ -104,12 +104,12 @@ impl AsyncIo for RawFileAsync {
fn write_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
let (submitter, mut sq, _) = self.io_uring.split();
// Safe because we know the file descriptor is valid and we
// SAFETY: we know the file descriptor is valid and we
// relied on vm-memory to provide the buffer address.
let _ = unsafe {
sq.push(
@@ -133,7 +133,7 @@ impl AsyncIo for RawFileAsync {
if let Some(user_data) = user_data {
let (submitter, mut sq, _) = self.io_uring.split();
// Safe because we know the file descriptor is valid.
// SAFETY: we know the file descriptor is valid.
let _ = unsafe {
sq.push(
&opcode::Fsync::new(types::Fd(self.fd))
@@ -148,20 +148,17 @@ impl AsyncIo for RawFileAsync {
sq.sync();
submitter.submit().map_err(AsyncIoError::Fsync)?;
} else {
// SAFETY: FFI call with a valid fd
unsafe { libc::fsync(self.fd) };
}
Ok(())
}
fn complete(&mut self) -> Vec<(u64, i32)> {
let mut completion_list = Vec::new();
let cq = self.io_uring.completion();
for cq_entry in cq {
completion_list.push((cq_entry.user_data(), cq_entry.result()));
}
completion_list
fn next_completed_request(&mut self) -> Option<(u64, i32)> {
self.io_uring
.completion()
.next()
.map(|entry| (entry.user_data(), entry.result()))
}
}

View File

@@ -5,6 +5,7 @@
use crate::async_io::{
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult, DiskTopology,
};
use std::collections::VecDeque;
use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::os::unix::io::{AsRawFd, RawFd};
@@ -44,7 +45,7 @@ impl DiskFile for RawFileDiskSync {
pub struct RawFileSync {
fd: RawFd,
eventfd: EventFd,
completion_list: Vec<(u64, i32)>,
completion_list: VecDeque<(u64, i32)>,
}
impl RawFileSync {
@@ -52,7 +53,7 @@ impl RawFileSync {
RawFileSync {
fd,
eventfd: EventFd::new(libc::EFD_NONBLOCK).expect("Failed creating EventFd for RawFile"),
completion_list: Vec::new(),
completion_list: VecDeque::new(),
}
}
}
@@ -65,9 +66,10 @@ impl AsyncIo for RawFileSync {
fn read_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
// SAFETY: FFI call with valid arguments
let result = unsafe {
libc::preadv(
self.fd as libc::c_int,
@@ -80,7 +82,7 @@ impl AsyncIo for RawFileSync {
return Err(AsyncIoError::ReadVectored(std::io::Error::last_os_error()));
}
self.completion_list.push((user_data, result as i32));
self.completion_list.push_back((user_data, result as i32));
self.eventfd.write(1).unwrap();
Ok(())
@@ -89,9 +91,10 @@ impl AsyncIo for RawFileSync {
fn write_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
// SAFETY: FFI call with valid arguments
let result = unsafe {
libc::pwritev(
self.fd as libc::c_int,
@@ -104,27 +107,28 @@ impl AsyncIo for RawFileSync {
return Err(AsyncIoError::WriteVectored(std::io::Error::last_os_error()));
}
self.completion_list.push((user_data, result as i32));
self.completion_list.push_back((user_data, result as i32));
self.eventfd.write(1).unwrap();
Ok(())
}
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
// SAFETY: FFI call
let result = unsafe { libc::fsync(self.fd as libc::c_int) };
if result < 0 {
return Err(AsyncIoError::Fsync(std::io::Error::last_os_error()));
}
if let Some(user_data) = user_data {
self.completion_list.push((user_data, result));
self.completion_list.push_back((user_data, result));
self.eventfd.write(1).unwrap();
}
Ok(())
}
fn complete(&mut self) -> Vec<(u64, i32)> {
self.completion_list.drain(..).collect()
fn next_completed_request(&mut self) -> Option<(u64, i32)> {
self.completion_list.pop_front()
}
}

View File

@@ -4,6 +4,7 @@
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
use crate::AsyncAdaptor;
use std::collections::VecDeque;
use std::fs::File;
use std::sync::{Arc, Mutex, MutexGuard};
use vhdx::vhdx::{Result as VhdxResult, Vhdx};
@@ -37,7 +38,7 @@ impl DiskFile for VhdxDiskSync {
pub struct VhdxSync {
vhdx_file: Arc<Mutex<Vhdx>>,
eventfd: EventFd,
completion_list: Vec<(u64, i32)>,
completion_list: VecDeque<(u64, i32)>,
}
impl VhdxSync {
@@ -45,7 +46,7 @@ impl VhdxSync {
Ok(VhdxSync {
vhdx_file,
eventfd: EventFd::new(libc::EFD_NONBLOCK)?,
completion_list: Vec::new(),
completion_list: VecDeque::new(),
})
}
}
@@ -64,7 +65,7 @@ impl AsyncIo for VhdxSync {
fn read_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
self.vhdx_file.read_vectored_sync(
@@ -79,7 +80,7 @@ impl AsyncIo for VhdxSync {
fn write_vectored(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
iovecs: &[libc::iovec],
user_data: u64,
) -> AsyncIoResult<()> {
self.vhdx_file.write_vectored_sync(
@@ -96,7 +97,7 @@ impl AsyncIo for VhdxSync {
.fsync_sync(user_data, &self.eventfd, &mut self.completion_list)
}
fn complete(&mut self) -> Vec<(u64, i32)> {
self.completion_list.drain(..).collect()
fn next_completed_request(&mut self) -> Option<(u64, i32)> {
self.completion_list.pop_front()
}
}

View File

@@ -3,13 +3,10 @@
// SPDX-License-Identifier: Apache-2.0
//
#[macro_use(crate_version)]
extern crate clap;
use std::process::Command;
fn main() {
let mut version = "v".to_owned() + crate_version!();
let mut version = "v".to_owned() + env!("CARGO_PKG_VERSION");
if let Ok(git_out) = Command::new("git").args(["describe", "--dirty"]).output() {
if git_out.status.success() {
@@ -23,5 +20,5 @@ fn main() {
// variable BUILT_VERSION, so that it can be reused from the binary.
// Particularly, this is used from src/main.rs to display the exact
// version.
println!("cargo:rustc-env=BUILT_VERSION={}", version);
println!("cargo:rustc-env=BUILT_VERSION={version}");
}

View File

@@ -6,22 +6,22 @@ edition = "2021"
[dependencies]
acpi_tables = { path = "../acpi_tables" }
anyhow = "1.0.66"
anyhow = "1.0.68"
arch = { path = "../arch" }
bitflags = "1.3.2"
byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" }
libc = "0.2.137"
libc = "0.2.139"
log = "0.4.17"
phf = { version = "0.11", features = ["macros"] }
thiserror = "1.0.30"
phf = { version = "0.11.1", features = ["macros"] }
thiserror = "1.0.38"
tpm = { path = "../tpm" }
versionize = "0.1.6"
versionize = "0.1.9"
versionize_derive = "0.1.4"
vm-device = { path = "../vm-device" }
vm-memory = "0.9.0"
vm-memory = "0.10.0"
vm-migration = { path = "../vm-migration" }
vmm-sys-util = "0.10.0"
vmm-sys-util = "0.11.0"
[target.'cfg(target_arch = "aarch64")'.dependencies]
arch = { path = "../arch" }

View File

@@ -8,7 +8,7 @@ use anyhow::anyhow;
use arch::layout;
use hypervisor::{
arch::aarch64::gic::{Vgic, VgicConfig},
CpuState,
CpuState, GicState,
};
use std::result;
use std::sync::{Arc, Mutex};
@@ -25,6 +25,7 @@ type Result<T> = result::Result<T, Error>;
// Reserve 32 IRQs for legacy devices.
pub const IRQ_LEGACY_BASE: usize = layout::IRQ_BASE as usize;
pub const IRQ_LEGACY_COUNT: usize = 32;
pub const GIC_SNAPSHOT_ID: &str = "gic-v3-its";
// Gic (Generic Interupt Controller) struct provides all the functionality of a
// GIC device. It wraps a hypervisor-emulated GIC device (Vgic) provided by the
@@ -39,8 +40,9 @@ pub struct Gic {
impl Gic {
pub fn new(
_vcpu_count: u8,
vcpu_count: u8,
interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
vm: Arc<dyn hypervisor::Vm>,
) -> Result<Gic> {
let interrupt_source_group = interrupt_manager
.create_group(MsiIrqGroupConfig {
@@ -49,45 +51,34 @@ impl Gic {
})
.map_err(Error::CreateInterruptSourceGroup)?;
Ok(Gic {
let vgic = vm
.create_vgic(Gic::create_default_config(vcpu_count as u64))
.map_err(Error::CreateGic)?;
let gic = Gic {
interrupt_source_group,
vgic: None,
})
vgic: Some(vgic),
};
gic.enable()?;
Ok(gic)
}
/// Default config implied by arch::layout
pub fn create_default_config(vcpu_count: u64) -> VgicConfig {
let redists_size = layout::GIC_V3_REDIST_SIZE * vcpu_count;
let redists_addr = layout::GIC_V3_DIST_START.raw_value() - redists_size;
VgicConfig {
vcpu_count,
dist_addr: layout::GIC_V3_DIST_START.raw_value(),
dist_size: layout::GIC_V3_DIST_SIZE,
redists_addr,
redists_size,
msi_addr: redists_addr - layout::GIC_V3_ITS_SIZE,
msi_size: layout::GIC_V3_ITS_SIZE,
nr_irqs: layout::IRQ_NUM,
}
}
pub fn create_vgic(
pub fn restore_vgic(
&mut self,
vm: &Arc<dyn hypervisor::Vm>,
config: VgicConfig,
) -> Result<Arc<Mutex<dyn Vgic>>> {
let vgic = vm.create_vgic(config).map_err(Error::CreateGic)?;
self.vgic = Some(vgic.clone());
Ok(vgic.clone())
state: Option<GicState>,
saved_vcpu_states: &[CpuState],
) -> Result<()> {
self.set_gicr_typers(saved_vcpu_states);
self.vgic
.clone()
.unwrap()
.lock()
.unwrap()
.set_state(&state.unwrap())
.map_err(Error::RestoreGic)
}
pub fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
let vgic = self.vgic.as_ref().unwrap().clone();
vgic.lock().unwrap().set_gicr_typers(vcpu_states);
}
}
impl InterruptController for Gic {
fn enable(&self) -> Result<()> {
// Set irqfd for legacy interrupts
self.interrupt_source_group
@@ -113,6 +104,33 @@ impl InterruptController for Gic {
Ok(())
}
/// Default config implied by arch::layout
pub fn create_default_config(vcpu_count: u64) -> VgicConfig {
let redists_size = layout::GIC_V3_REDIST_SIZE * vcpu_count;
let redists_addr = layout::GIC_V3_DIST_START.raw_value() - redists_size;
VgicConfig {
vcpu_count,
dist_addr: layout::GIC_V3_DIST_START.raw_value(),
dist_size: layout::GIC_V3_DIST_SIZE,
redists_addr,
redists_size,
msi_addr: redists_addr - layout::GIC_V3_ITS_SIZE,
msi_size: layout::GIC_V3_ITS_SIZE,
nr_irqs: layout::IRQ_NUM,
}
}
pub fn get_vgic(&mut self) -> Result<Arc<Mutex<dyn Vgic>>> {
Ok(self.vgic.clone().unwrap())
}
pub fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) {
let vgic = self.vgic.as_ref().unwrap().clone();
vgic.lock().unwrap().set_gicr_typers(vcpu_states);
}
}
impl InterruptController for Gic {
// This should be called anytime an interrupt needs to be injected into the
// running guest.
fn service_irq(&mut self, irq: usize) -> Result<()> {
@@ -128,27 +146,15 @@ impl InterruptController for Gic {
}
}
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()
GIC_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(())
Snapshot::new_from_state(&state)
}
}

View File

@@ -24,8 +24,12 @@ pub enum Error {
UpdateInterrupt(io::Error),
/// Failed enabling the interrupt.
EnableInterrupt(io::Error),
#[cfg(target_arch = "aarch64")]
/// Failed creating GIC device.
CreateGic(hypervisor::HypervisorVmError),
#[cfg(target_arch = "aarch64")]
/// Failed restoring GIC device.
RestoreGic(hypervisor::arch::aarch64::gic::Error),
}
type Result<T> = result::Result<T, Error>;
@@ -55,8 +59,6 @@ pub struct MsiMessage {
// IOAPIC (X86) or GIC (Arm).
pub trait InterruptController: Send {
fn service_irq(&mut self, irq: usize) -> Result<()>;
#[cfg(target_arch = "aarch64")]
fn enable(&self) -> Result<()>;
#[cfg(target_arch = "x86_64")]
fn end_of_interrupt(&mut self, vec: u8);
fn notifier(&self, irq: usize) -> Option<EventFd>;

View File

@@ -10,7 +10,6 @@
// See https://pdos.csail.mit.edu/6.828/2016/readings/ia32/ioapic.pdf for a specification.
use super::interrupt_controller::{Error, InterruptController};
use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian};
use std::result;
use std::sync::{Arc, Barrier};
@@ -194,6 +193,7 @@ impl Ioapic {
id: String,
apic_address: GuestAddress,
interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
state: Option<IoapicState>,
) -> Result<Ioapic> {
let interrupt_source_group = interrupt_manager
.create_group(MsiIrqGroupConfig {
@@ -202,17 +202,47 @@ impl Ioapic {
})
.map_err(Error::CreateInterruptSourceGroup)?;
let (id_reg, reg_sel, reg_entries, used_entries, apic_address) = if let Some(state) = &state
{
(
state.id_reg,
state.reg_sel,
state.reg_entries,
state.used_entries,
GuestAddress(state.apic_address),
)
} else {
(
0,
0,
[0x10000; NUM_IOAPIC_PINS],
[false; NUM_IOAPIC_PINS],
apic_address,
)
};
// The IOAPIC is created with entries already masked. The guest will be
// in charge of unmasking them if/when necessary.
Ok(Ioapic {
let ioapic = Ioapic {
id,
id_reg: 0,
reg_sel: 0,
reg_entries: [0x10000; NUM_IOAPIC_PINS],
used_entries: [false; NUM_IOAPIC_PINS],
id_reg,
reg_sel,
reg_entries,
used_entries,
apic_address,
interrupt_source_group,
})
};
// When restoring the Ioapic, we must enable used entries.
if state.is_some() {
for (irq, entry) in ioapic.used_entries.iter().enumerate() {
if *entry {
ioapic.update_entry(irq)?;
}
}
}
Ok(ioapic)
}
fn ioapic_write(&mut self, val: u32) {
@@ -299,21 +329,6 @@ impl Ioapic {
}
}
fn set_state(&mut self, state: &IoapicState) -> Result<()> {
self.id_reg = state.id_reg;
self.reg_sel = state.reg_sel;
self.reg_entries = state.reg_entries;
self.used_entries = state.used_entries;
self.apic_address = GuestAddress(state.apic_address);
for (irq, entry) in self.used_entries.iter().enumerate() {
if *entry {
self.update_entry(irq)?;
}
}
Ok(())
}
fn update_entry(&self, irq: usize) -> Result<()> {
let entry = self.reg_entries[irq];
@@ -423,18 +438,7 @@ impl Snapshottable for Ioapic {
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_versioned_state(&self.id, &self.state())
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
self.set_state(&snapshot.to_versioned_state(&self.id)?)
.map_err(|e| {
MigratableError::Restore(anyhow!(
"Could not restore state for {}: {:?}",
self.id,
e
))
})
Snapshot::new_from_versioned_state(&self.state())
}
}

View File

@@ -97,7 +97,7 @@ impl BusDevice for Cmos {
let day;
let month;
let year;
// The clock_gettime and gmtime_r calls are safe as long as the structs they are
// SAFETY: The clock_gettime and gmtime_r calls are safe as long as the structs they are
// given are large enough, and neither of them fail. It is safe to zero initialize
// the tm and timespec struct because it contains only plain data.
let update_in_progress = unsafe {

View File

@@ -40,11 +40,11 @@ impl DebugIoPortRange {
impl fmt::Display for DebugIoPortRange {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DebugIoPortRange::Firmware => write!(f, "{}: Firmware", DEBUG_IOPORT_PREFIX),
DebugIoPortRange::Bootloader => write!(f, "{}: Bootloader", DEBUG_IOPORT_PREFIX),
DebugIoPortRange::Kernel => write!(f, "{}: Kernel", DEBUG_IOPORT_PREFIX),
DebugIoPortRange::Userspace => write!(f, "{}: Userspace", DEBUG_IOPORT_PREFIX),
DebugIoPortRange::Custom => write!(f, "{}: Custom", DEBUG_IOPORT_PREFIX),
DebugIoPortRange::Firmware => write!(f, "{DEBUG_IOPORT_PREFIX}: Firmware"),
DebugIoPortRange::Bootloader => write!(f, "{DEBUG_IOPORT_PREFIX}: Bootloader"),
DebugIoPortRange::Kernel => write!(f, "{DEBUG_IOPORT_PREFIX}: Kernel"),
DebugIoPortRange::Userspace => write!(f, "{DEBUG_IOPORT_PREFIX}: Userspace"),
DebugIoPortRange::Custom => write!(f, "{DEBUG_IOPORT_PREFIX}: Custom"),
}
}
}

View File

@@ -51,13 +51,13 @@ pub enum Error {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::BadWriteOffset(offset) => write!(f, "Bad Write Offset: {}", offset),
Error::BadWriteOffset(offset) => write!(f, "Bad Write Offset: {offset}"),
Error::GpioInterruptDisabled => write!(f, "GPIO interrupt disabled by guest driver.",),
Error::GpioInterruptFailure(ref e) => {
write!(f, "Could not trigger GPIO interrupt: {}.", e)
write!(f, "Could not trigger GPIO interrupt: {e}.")
}
Error::GpioTriggerKeyFailure(key) => {
write!(f, "Invalid GPIO Input key triggerd: {}.", key)
write!(f, "Invalid GPIO Input key triggerd: {key}.")
}
}
}
@@ -106,18 +106,39 @@ impl VersionMapped for GpioState {}
impl Gpio {
/// Constructs an PL061 GPIO device.
pub fn new(id: String, interrupt: Arc<dyn InterruptSourceGroup>) -> Self {
pub fn new(
id: String,
interrupt: Arc<dyn InterruptSourceGroup>,
state: Option<GpioState>,
) -> Self {
let (data, old_in_data, dir, isense, ibe, iev, im, istate, afsel) =
if let Some(state) = state {
(
state.data,
state.old_in_data,
state.dir,
state.isense,
state.ibe,
state.iev,
state.im,
state.istate,
state.afsel,
)
} else {
(0, 0, 0, 0, 0, 0, 0, 0, 0)
};
Self {
id,
data: 0,
old_in_data: 0,
dir: 0,
isense: 0,
ibe: 0,
iev: 0,
im: 0,
istate: 0,
afsel: 0,
data,
old_in_data,
dir,
isense,
ibe,
iev,
im,
istate,
afsel,
interrupt,
}
}
@@ -136,24 +157,12 @@ impl Gpio {
}
}
fn set_state(&mut self, state: &GpioState) {
self.data = state.data;
self.old_in_data = state.old_in_data;
self.dir = state.dir;
self.isense = state.isense;
self.ibe = state.ibe;
self.iev = state.iev;
self.im = state.im;
self.istate = state.istate;
self.afsel = state.afsel;
}
fn pl061_internal_update(&mut self) {
// FIXME:
// Missing Output Interrupt Emulation.
// Input Edging Interrupt Emulation.
let changed = ((self.old_in_data ^ self.data) & !self.dir) as u32;
let changed = (self.old_in_data ^ self.data) & !self.dir;
if changed > 0 {
self.old_in_data = self.data;
for i in 0..N_GPIOS {
@@ -319,12 +328,7 @@ impl Snapshottable for Gpio {
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_versioned_state(&self.id, &self.state())
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
self.set_state(&snapshot.to_versioned_state(&self.id)?);
Ok(())
Snapshot::new_from_versioned_state(&self.state())
}
}
@@ -378,6 +382,7 @@ mod tests {
let mut gpio = Gpio::new(
String::from(GPIO_NAME),
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
None,
);
let mut data = [0; 4];

View File

@@ -48,8 +48,8 @@ pub enum Error {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::BadWriteOffset(offset) => write!(f, "Bad Write Offset: {}", offset),
Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {}", e),
Error::BadWriteOffset(offset) => write!(f, "Bad Write Offset: {offset}"),
Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {e}"),
}
}
}
@@ -61,12 +61,10 @@ pub enum ClockType {
/// Equivalent to `libc::CLOCK_MONOTONIC`.
Monotonic,
/// Equivalent to `libc::CLOCK_REALTIME`.
#[allow(dead_code)]
Real,
/// Equivalent to `libc::CLOCK_PROCESS_CPUTIME_ID`.
ProcessCpu,
/// Equivalent to `libc::CLOCK_THREAD_CPUTIME_ID`.
#[allow(dead_code)]
ThreadCpu,
}
@@ -101,7 +99,7 @@ pub struct LocalTime {
impl LocalTime {
/// Returns the [LocalTime](struct.LocalTime.html) structure for the calling moment.
#[allow(dead_code)]
#[cfg(test)]
pub fn now() -> LocalTime {
let mut timespec = libc::timespec {
tv_sec: 0,
@@ -121,7 +119,7 @@ impl LocalTime {
tm_zone: std::ptr::null(),
};
// Safe because the parameters are valid.
// SAFETY: the parameters are valid.
unsafe {
libc::clock_gettime(libc::CLOCK_REALTIME, &mut timespec);
libc::localtime_r(&timespec.tv_sec, &mut tm);
@@ -173,22 +171,6 @@ impl Default for TimestampUs {
}
}
/// Returns a timestamp in nanoseconds from a monotonic clock.
///
/// Uses `_rdstc` on `x86_64` and [`get_time`](fn.get_time.html) on other architectures.
#[allow(dead_code)]
pub fn timestamp_cycles() -> u64 {
#[cfg(target_arch = "x86_64")]
// Safe because there's nothing that can go wrong with this call.
unsafe {
std::arch::x86_64::_rdtsc() as u64
}
#[cfg(not(target_arch = "x86_64"))]
{
get_time(ClockType::Monotonic)
}
}
/// Returns a timestamp in nanoseconds based on the provided clock type.
///
/// # Arguments
@@ -199,7 +181,7 @@ pub fn get_time(clock_type: ClockType) -> u64 {
tv_sec: 0,
tv_nsec: 0,
};
// Safe because the parameters are valid.
// SAFETY: the parameters are valid.
unsafe { libc::clock_gettime(clock_type.into(), &mut time_struct) };
seconds_to_nanoseconds(time_struct.tv_sec).unwrap() as u64 + (time_struct.tv_nsec as u64)
}
@@ -525,7 +507,6 @@ mod tests {
($test_name: ident, $write_fn_name: ident, $read_fn_name: ident, $is_be: expr, $data_type: ty) => {
#[test]
fn $test_name() {
#[allow(overflowing_literals)]
let test_cases = [
(
0x0123_4567_89AB_CDEF as u64,

View File

@@ -63,7 +63,6 @@ pub struct Serial {
id: String,
interrupt_enable: u8,
interrupt_identification: u8,
interrupt: Arc<dyn InterruptSourceGroup>,
line_control: u8,
line_status: u8,
modem_control: u8,
@@ -71,6 +70,7 @@ pub struct Serial {
scratch: u8,
baud_divisor: u16,
in_buffer: VecDeque<u8>,
interrupt: Arc<dyn InterruptSourceGroup>,
out: Option<Box<dyn io::Write + Send>>,
}
@@ -93,19 +93,56 @@ impl Serial {
id: String,
interrupt: Arc<dyn InterruptSourceGroup>,
out: Option<Box<dyn io::Write + Send>>,
state: Option<SerialState>,
) -> Serial {
let (
interrupt_enable,
interrupt_identification,
line_control,
line_status,
modem_control,
modem_status,
scratch,
baud_divisor,
in_buffer,
) = if let Some(state) = state {
(
state.interrupt_enable,
state.interrupt_identification,
state.line_control,
state.line_status,
state.modem_control,
state.modem_status,
state.scratch,
state.baud_divisor,
state.in_buffer.into(),
)
} else {
(
0,
DEFAULT_INTERRUPT_IDENTIFICATION,
DEFAULT_LINE_CONTROL,
DEFAULT_LINE_STATUS,
DEFAULT_MODEM_CONTROL,
DEFAULT_MODEM_STATUS,
0,
DEFAULT_BAUD_DIVISOR,
VecDeque::new(),
)
};
Serial {
id,
interrupt_enable: 0,
interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION,
interrupt_enable,
interrupt_identification,
line_control,
line_status,
modem_control,
modem_status,
scratch,
baud_divisor,
in_buffer,
interrupt,
line_control: DEFAULT_LINE_CONTROL,
line_status: DEFAULT_LINE_STATUS,
modem_control: DEFAULT_MODEM_CONTROL,
modem_status: DEFAULT_MODEM_STATUS,
scratch: 0,
baud_divisor: DEFAULT_BAUD_DIVISOR,
in_buffer: VecDeque::new(),
out,
}
}
@@ -115,13 +152,18 @@ impl Serial {
id: String,
interrupt: Arc<dyn InterruptSourceGroup>,
out: Box<dyn io::Write + Send>,
state: Option<SerialState>,
) -> Serial {
Self::new(id, interrupt, Some(out))
Self::new(id, interrupt, Some(out), state)
}
/// Constructs a Serial port with no connected output.
pub fn new_sink(id: String, interrupt: Arc<dyn InterruptSourceGroup>) -> Serial {
Self::new(id, interrupt, None)
pub fn new_sink(
id: String,
interrupt: Arc<dyn InterruptSourceGroup>,
state: Option<SerialState>,
) -> Serial {
Self::new(id, interrupt, None, state)
}
pub fn set_out(&mut self, out: Box<dyn io::Write + Send>) {
@@ -242,18 +284,6 @@ impl Serial {
in_buffer: self.in_buffer.clone().into(),
}
}
fn set_state(&mut self, state: &SerialState) {
self.interrupt_enable = state.interrupt_enable;
self.interrupt_identification = state.interrupt_identification;
self.line_control = state.line_control;
self.line_status = state.line_status;
self.modem_control = state.modem_control;
self.modem_status = state.modem_status;
self.scratch = state.scratch;
self.baud_divisor = state.baud_divisor;
self.in_buffer = state.in_buffer.clone().into();
}
}
impl BusDevice for Serial {
@@ -304,12 +334,7 @@ impl Snapshottable for Serial {
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_versioned_state(&self.id, &self.state())
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
self.set_state(&snapshot.to_versioned_state(&self.id)?);
Ok(())
Snapshot::new_from_versioned_state(&self.state())
}
}
@@ -384,6 +409,7 @@ mod tests {
String::from(SERIAL_NAME),
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
Box::new(serial_out.clone()),
None,
);
serial.write(0, DATA as u64, &[b'x', b'y']);
@@ -404,6 +430,7 @@ mod tests {
String::from(SERIAL_NAME),
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
Box::new(serial_out),
None,
);
// write 1 to the interrupt event fd, so that read doesn't block in case the event fd
@@ -440,6 +467,7 @@ mod tests {
let mut serial = Serial::new_sink(
String::from(SERIAL_NAME),
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
None,
);
// write 1 to the interrupt event fd, so that read doesn't block in case the event fd
@@ -462,6 +490,7 @@ mod tests {
let mut serial = Serial::new_sink(
String::from(SERIAL_NAME),
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
None,
);
serial.write(0, LCR as u64, &[LCR_DLAB_BIT]);
@@ -483,6 +512,7 @@ mod tests {
let mut serial = Serial::new_sink(
String::from(SERIAL_NAME),
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
None,
);
serial.write(0, MCR as u64, &[MCR_LOOP_BIT]);
@@ -509,6 +539,7 @@ mod tests {
let mut serial = Serial::new_sink(
String::from(SERIAL_NAME),
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
None,
);
serial.write(0, SCR as u64, &[0x12]);

View File

@@ -60,11 +60,11 @@ pub enum Error {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::BadWriteOffset(offset) => write!(f, "pl011_write: Bad Write Offset: {}", offset),
Error::BadWriteOffset(offset) => write!(f, "pl011_write: Bad Write Offset: {offset}"),
Error::DmaNotImplemented => write!(f, "pl011: DMA not implemented."),
Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {}", e),
Error::WriteAllFailure(e) => write!(f, "Failed to write: {}", e),
Error::FlushFailure(e) => write!(f, "Failed to flush: {}", e),
Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {e}"),
Error::WriteAllFailure(e) => write!(f, "Failed to write: {e}"),
Error::FlushFailure(e) => write!(f, "Failed to flush: {e}"),
}
}
}
@@ -122,24 +122,79 @@ impl Pl011 {
irq: Arc<dyn InterruptSourceGroup>,
out: Option<Box<dyn io::Write + Send>>,
timestamp: Instant,
state: Option<Pl011State>,
) -> Self {
let (
flags,
lcr,
rsr,
cr,
dmacr,
debug,
int_enabled,
int_level,
read_fifo,
ilpr,
ibrd,
fbrd,
ifl,
read_count,
read_trigger,
) = if let Some(state) = state {
(
state.flags,
state.lcr,
state.rsr,
state.cr,
state.dmacr,
state.debug,
state.int_enabled,
state.int_level,
state.read_fifo.into(),
state.ilpr,
state.ibrd,
state.fbrd,
state.ifl,
state.read_count,
state.read_trigger,
)
} else {
(
0x90,
0,
0,
0x300,
0,
0,
0,
0,
VecDeque::new(),
0,
0,
0,
0x12,
0,
1,
)
};
Self {
id,
flags: 0x90u32,
lcr: 0u32,
rsr: 0u32,
cr: 0x300u32,
dmacr: 0u32,
debug: 0u32,
int_enabled: 0u32,
int_level: 0u32,
read_fifo: VecDeque::new(),
ilpr: 0u32,
ibrd: 0u32,
fbrd: 0u32,
ifl: 0x12u32,
read_count: 0u32,
read_trigger: 1u32,
flags,
lcr,
rsr,
cr,
dmacr,
debug,
int_enabled,
int_level,
read_fifo,
ilpr,
ibrd,
fbrd,
ifl,
read_count,
read_trigger,
irq,
out,
timestamp,
@@ -170,24 +225,6 @@ impl Pl011 {
}
}
fn set_state(&mut self, state: &Pl011State) {
self.flags = state.flags;
self.lcr = state.lcr;
self.rsr = state.rsr;
self.cr = state.cr;
self.dmacr = state.dmacr;
self.debug = state.debug;
self.int_enabled = state.int_enabled;
self.int_level = state.int_level;
self.read_fifo = state.read_fifo.clone().into();
self.ilpr = state.ilpr;
self.ibrd = state.ibrd;
self.fbrd = state.fbrd;
self.ifl = state.ifl;
self.read_count = state.read_count;
self.read_trigger = state.read_trigger;
}
/// Queues raw bytes for the guest to read and signals the interrupt
pub fn queue_input_bytes(&mut self, c: &[u8]) -> vmm_sys_util::errno::Result<()> {
self.read_fifo.extend(c);
@@ -417,12 +454,7 @@ impl Snapshottable for Pl011 {
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_versioned_state(&self.id, &self.state())
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
self.set_state(&snapshot.to_versioned_state(&self.id)?);
Ok(())
Snapshot::new_from_versioned_state(&self.state())
}
}
@@ -498,12 +530,13 @@ mod tests {
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
Some(Box::new(pl011_out.clone())),
Instant::now(),
None,
);
pl011.write(0, UARTDR as u64, &[b'x', b'y']);
pl011.write(0, UARTDR as u64, &[b'a']);
pl011.write(0, UARTDR as u64, &[b'b']);
pl011.write(0, UARTDR as u64, &[b'c']);
pl011.write(0, UARTDR, &[b'x', b'y']);
pl011.write(0, UARTDR, &[b'a']);
pl011.write(0, UARTDR, &[b'b']);
pl011.write(0, UARTDR, &[b'c']);
assert_eq!(
pl011_out.buf.lock().unwrap().as_slice(),
&[b'x', b'a', b'b', b'c']
@@ -519,6 +552,7 @@ mod tests {
Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
Some(Box::new(pl011_out)),
Instant::now(),
None,
);
// write 1 to the interrupt event fd, so that read doesn't block in case the event fd
@@ -529,11 +563,11 @@ mod tests {
assert_eq!(intr_evt.read().unwrap(), 2);
let mut data = [0u8];
pl011.read(0, UARTDR as u64, &mut data);
pl011.read(0, UARTDR, &mut data);
assert_eq!(data[0], b'a');
pl011.read(0, UARTDR as u64, &mut data);
pl011.read(0, UARTDR, &mut data);
assert_eq!(data[0], b'b');
pl011.read(0, UARTDR as u64, &mut data);
pl011.read(0, UARTDR, &mut data);
assert_eq!(data[0], b'c');
}
}

View File

@@ -33,11 +33,9 @@ bitflags! {
}
}
#[allow(unused_macros)]
#[cfg(target_arch = "aarch64")]
macro_rules! generate_read_fn {
($fn_name: ident, $data_type: ty, $byte_type: ty, $type_size: expr, $endian_type: ident) => {
#[allow(dead_code)]
pub fn $fn_name(input: &[$byte_type]) -> $data_type {
assert!($type_size == std::mem::size_of::<$data_type>());
let mut array = [0u8; $type_size];
@@ -49,11 +47,9 @@ macro_rules! generate_read_fn {
};
}
#[allow(unused_macros)]
#[cfg(target_arch = "aarch64")]
macro_rules! generate_write_fn {
($fn_name: ident, $data_type: ty, $byte_type: ty, $endian_type: ident) => {
#[allow(dead_code)]
pub fn $fn_name(buf: &mut [$byte_type], n: $data_type) {
for (byte, read) in buf
.iter_mut()

View File

@@ -117,10 +117,7 @@ fn get_fields_map(reg: u32) -> phf::Map<&'static str, [u32; 2]> {
CRB_INTF_ID2 => CRB_INTF_ID2_FIELDS,
CRB_CTRL_STS => CRB_CTRL_STS_FIELDS,
_ => {
panic!(
"Fields in '{:?}' register were accessed which are Invalid",
reg
);
panic!("Fields in '{reg:?}' register were accessed which are Invalid");
}
}
}

View File

@@ -1,152 +0,0 @@
# How to build and test Cloud Hypervisor on AArch64
This document introduces how to build and test Cloud Hypervisor on AArch64.
Currently, Cloud Hypervisor supports 2 methods of booting on AArch64: UEFI
booting and direct-kernel booting. The document covers both methods.
All the steps are based on Ubuntu. We use the Ubuntu cloud image for guest VM
disk.
## Hardware requirements
- AArch64 servers (recommended) or development boards equipped with the GICv3
interrupt controller.
- On development boards that have constrained RAM resources, if the creation of
a VM consumes a large portion of the free memory on the host, it may be required
to enable swap. For example, this was required on a board with 3 GB of RAM
booting a 2 GB VM at a point in time when 2.8 GB were free. Without enabling
swap the `cloud-hypervisor` process was terminated by the OOM killer. In this
situation memory was allocated for the virtual machine using memfd while the
page cache was filled, leading to a situation where the kernel could not even
drop caches. Making a small section of swap available (observably, 1 to 15 MB),
this situation can be resolved and the resulting memory footprint of
`cloud-hypervisor` is as expected.
## Getting started
We create a folder to build and run Cloud Hypervisor at `$HOME/cloud-hypervisor`
```shell
$ export CLOUDH=$HOME/cloud-hypervisor
$ mkdir $CLOUDH
```
## Prerequisites
You need to install some prerequisite packages to build and test Cloud Hypervisor.
### Tools
```bash
# Install rust tool chain
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Install the tools used for building guest kernel, EDK2 and converting guest disk
$ sudo apt-get update
$ sudo apt-get install git build-essential m4 bison flex uuid-dev qemu-utils
```
### Building Cloud Hypervisor
```bash
$ pushd $CLOUDH
$ git clone https://github.com/cloud-hypervisor/cloud-hypervisor.git
$ cd cloud-hypervisor
$ cargo build
$ popd
```
### Disk image
Download the Ubuntu cloud image and convert the image type.
```bash
$ pushd $CLOUDH
$ wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-arm64.img
$ qemu-img convert -p -f qcow2 -O raw focal-server-cloudimg-arm64.img focal-server-cloudimg-arm64.raw
$ popd
```
## UEFI booting
This part introduces how to build EDK2 firmware and boot Cloud Hypervisor with it.
### Building EDK2
```bash
$ pushd $CLOUDH
# Clone source code repos
$ git clone --depth 1 https://github.com/tianocore/edk2.git -b master
$ cd edk2
$ git submodule update --init
$ cd ..
$ git clone --depth 1 https://github.com/tianocore/edk2-platforms.git -b master
$ git clone --depth 1 https://github.com/acpica/acpica.git -b master
# Build tools
$ export PACKAGES_PATH="$PWD/edk2:$PWD/edk2-platforms"
$ export IASL_PREFIX="$PWD/acpica/generate/unix/bin/"
$ make -C acpica
$ cd edk2/
$ . edksetup.sh
$ cd ..
$ make -C edk2/BaseTools
# Build EDK2
$ build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtCloudHv.dsc -b RELEASE
$ popd
```
If the build goes well, the EDK2 binary is available at
`edk2/Build/ArmVirtCloudHv-AARCH64/RELEASE_GCC5/FV/CLOUDHV_EFI.fd`.
### Booting the guest VM
```bash
$ pushd $CLOUDH
$ sudo RUST_BACKTRACE=1 $CLOUDH/cloud-hypervisor/target/debug/cloud-hypervisor \
--api-socket /tmp/cloud-hypervisor.sock \
--kernel $CLOUDH/edk2/Build/ArmVirtCloudHv-AARCH64/RELEASE_GCC5/FV/CLOUDHV_EFI.fd \
--disk path=$CLOUDH/focal-server-cloudimg-arm64.raw \
--cpus boot=4 \
--memory size=4096M \
--net tap=,mac=12:34:56:78:90:01,ip=192.168.1.1,mask=255.255.255.0 \
--serial tty \
--console off
$ popd
```
## Direct-kernel booting
Alternativelly, you can build your own kernel for guest VM. This way, UEFI is
not involved and ACPI cannot be enabled.
### Building kernel
```bash
$ pushd $CLOUDH
$ git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b ch-5.12
$ cd linux
$ cp $CLOUDH/cloud-hypervisor/resources/linux-config-aarch64 .config
$ make -j `nproc`
$ popd
```
### Booting the guest VM
```bash
$ pushd $CLOUDH
$ sudo $CLOUDH/cloud-hypervisor/target/debug/cloud-hypervisor \
--api-socket /tmp/cloud-hypervisor.sock \
--kernel $CLOUDH/linux/arch/arm64/boot/Image \
--disk path=focal-server-cloudimg-arm64.raw \
--cmdline "keep_bootcon console=ttyAMA0 reboot=k panic=1 root=/dev/vda1 rw" \
--cpus boot=4 \
--memory size=4096M \
--net tap=,mac=12:34:56:78:90:01,ip=192.168.1.1,mask=255.255.255.0 \
--serial tty \
--console off
$ popd
```

View File

@@ -24,12 +24,15 @@ Hypervisor. Here, all the steps are based on Ubuntu, for other Linux
distributions please replace the package manager and package name.
```shell
# Install build-essential, git, and qemu-utils
$ sudo apt install git build-essential qemu-utils
# Install basic packages needed. For a package list targeting for more
# functionalities for example the test, please see resources/Dockerfile.
$ sudo apt-get update
$ sudo apt install git build-essential m4 bison flex uuid-dev qemu-utils
# Install rust tool chain
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# If you want to build statically linked binary please add musl target
$ rustup target add x86_64-unknown-linux-musl
$ rustup target add x86_64-unknown-linux-musl # x86-64
$ rustup target add aarch64-unknown-linux-musl # AArch64
```
## Clone and build
@@ -46,7 +49,8 @@ $ cargo build --release
$ sudo setcap cap_net_admin+ep ./target/release/cloud-hypervisor
# If you want to build statically linked binary
$ cargo build --release --target=x86_64-unknown-linux-musl --all
$ cargo build --release --target=x86_64-unknown-linux-musl --all # x86-64
$ cargo build --release --target=aarch64-unknown-linux-musl --all # AArch64
$ popd
```

View File

@@ -88,7 +88,7 @@ Ubuntu distributions.
```bash
apt update
apt install fio iperf iperf3 socat stress
apt install fio iperf iperf3 socat stress cpuid
```
### Remove counterproductive packages
@@ -158,3 +158,172 @@ as we might need to update the direct kernel boot command line, replacing
`/dev/vda1` with the appropriate partition number.
Update all references to the previous image name to the new one.
## NVIDIA image for VFIO baremetal CI
Here we are going to describe how to create a cloud image that contains the
necessary NVIDIA drivers for our VFIO baremetal CI.
### Download base image
We usually start from one of the custom cloud image we have previously created
but we can use a stock cloud image as well.
```bash
wget https://cloud-hypervisor.azureedge.net/jammy-server-cloudimg-amd64-custom-20221118-1.raw
mv jammy-server-cloudimg-amd64-custom-20221118-1.raw jammy-server-cloudimg-amd64-nvidia.raw
```
### Extend the image size
The NVIDIA drivers consume lots of space, which is why we must resize the image
before we proceed any further.
```bash
qemu-img resize jammy-server-cloudimg-amd64-nvidia.raw 5G
```
### Resize the partition
We use `parted` for fixing the GPT after the image was resized, as well as for
resizing the `Linux` partition.
```bash
sudo parted jammy-server-cloudimg-amd64-nvidia.raw
(parted) print
Warning: Not all of the space available to jammy-server-cloudimg-amd64-nvidia.raw
appears to be used, you can fix the GPT to use all of the space (an extra 5873664
blocks) or continue with the current setting?
Fix/Ignore? Fix
Model: (file)
Disk jammy-server-cloudimg-amd64-nvidia.raw: 5369MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
14 1049kB 5243kB 4194kB bios_grub
15 5243kB 116MB 111MB fat32 boot, esp
1 116MB 2361MB 2245MB ext4
(parted) resizepart 1 5369MB
(parted) print
Model: (file)
Disk jammy-server-cloudimg-amd64-nvidia.raw: 5369MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
14 1049kB 5243kB 4194kB bios_grub
15 5243kB 116MB 111MB fat32 boot, esp
1 116MB 5369MB 5252MB ext4
(parted) quit
```
### Create a macvtap interface
Rely on the following [documentation](docs/macvtap-bridge.md) to set up a
macvtap interface to provide your VM with proper connectivity.
### Boot the image
It is particularly important to boot with a `cloud-init` disk attached to the
VM as it will automatically resize the Linux `ext4` filesystem based on the
partition that we have previously resized.
```bash
./cloud-hypervisor \
--kernel hypervisor-fw \
--disk path=focal-server-cloudimg-amd64-nvidia.raw path=/tmp/ubuntu-cloudinit.img \
--cpus boot=4 \
--memory size=4G \
--net fd=3,mac=$mac 3<>$"$tapdevice"
```
### Bring up connectivity
If your network has a DHCP server, run the following from your VM
```bash
sudo dhclient
```
But if that's not the case, let's give it an IP manually (the IP addresses
depend on your actual network) and set the DNS server IP address as well.
```bash
sudo ip addr add 192.168.2.10/24 dev ens4
sudo ip link set up dev ens4
sudo ip route add default via 192.168.2.1
sudo resolvectl dns ens4 8.8.8.8
```
#### Check connectivity and update the image
```bash
sudo apt update
sudo apt upgrade
```
### Install NVIDIA drivers
The following steps and commands are referenced from the
[NVIDIA official documentation](https://docs.nvidia.com/datacenter/tesla/tesla-installation-notes/index.html#ubuntu-lts)
about Tesla compute cards.
```bash
distribution=$(. /etc/os-release;echo $ID$VERSION_ID | sed -e 's/\.//g')
wget https://developer.download.nvidia.com/compute/cuda/repos/$distribution/x86_64/cuda-keyring_1.0-1_all.deb
sudo dpkg -i cuda-keyring_1.0-1_all.deb
sudo apt-key del 7fa2af80
sudo apt update
sudo apt -y install cuda-drivers
```
### Check the `nvidia-smi` tool
Quickly validate that you can find and run the `nvidia-smi` command from your
VM. At this point it should fail given no NVIDIA card has been passed through
the VM, therefore no NVIDIA driver is loaded.
### Workaround LA57 reboot issue
Add `reboot=a` to `GRUB_CMDLINE_LINUX` in `etc/default/grub` so that the VM
will be booted with the ACPI reboot type. This resolves a reboot issue when
running on 5-level paging systems.
```bash
sudo vim /etc/default/grub
sudo update-grub
sudo reboot
```
### Remove previous logins
Since our integration tests rely on past logins to count the number of reboots,
we must ensure to clear the list.
```bash
>/var/log/lastlog
>/var/log/wtmp
>/var/log/btmp
```
### Clear history
```
history -c
rm /home/cloud/.bash_history
```
### Reset cloud-init
This is mandatory as we want `cloud-init` provisioning to work again when a new
VM will be booted with this image.
```
sudo cloud-init clean
```

View File

@@ -30,7 +30,7 @@ process should be started to listen at the input socket. Below is an
example invocation of swtpm process.
```
swtpm socket --tmpstate dir=/var/run/swtpm \
swtpm socket --tpmstate dir=/var/run/swtpm \
--ctrl type=unixio,path="/var/run/swtpm.socket" \
--flags startup-clear \
--tpm2

View File

@@ -2,17 +2,19 @@
Cloud Hypervisor supports UEFI boot through the utilization of the EDK II based UEFI firmware.
## Building UEFI Firmware
## Building UEFI Firmware for x86-64
To avoid any unnecessary issues, it is recommended to use Ubuntu 18.04 and its default toolset. Any other compatible Linux distribution is otherwise suitable, however it is suggested to use a temporary Docker container with Ubuntu 18.04 for a quick build on an existing Linux machine.
Please note that nasm-2.15 is required for the build to succeed.
The commands below will compile an OVMF firmware suitable for Cloud Hypervisor.
```shell
sudo apt-get update
sudo apt-get install uuid-dev nasm iasl build-essential python3-distutils git
git clone https://github.com/cloud-hypervisor/edk2 -b ch
git clone https://github.com/tianocore/edk2
cd edk2
. edksetup.sh
git submodule update --init
@@ -27,11 +29,40 @@ build
After the successful build, the resulting firmware binaries are available under `Build/CloudHvX64/DEBUG_GCC5/FV` underneath the edk2 checkout.
## Building UEFI Firmware for AArch64
```shell
# On an AArch64 machine:
$ sudo apt-get update
$ sudo apt-get install uuid-dev nasm iasl build-essential python3-distutils git
$ git clone --depth 1 https://github.com/tianocore/edk2.git -b master
$ cd edk2
$ git submodule update --init
$ cd ..
$ git clone --depth 1 https://github.com/tianocore/edk2-platforms.git -b master
$ git clone --depth 1 https://github.com/acpica/acpica.git -b master
# Build tools
$ export PACKAGES_PATH="$PWD/edk2:$PWD/edk2-platforms"
$ export IASL_PREFIX="$PWD/acpica/generate/unix/bin/"
$ make -C acpica
$ cd edk2/
$ . edksetup.sh
$ cd ..
$ make -C edk2/BaseTools
# Build EDK2
$ build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtCloudHv.dsc -b RELEASE
```
If the build goes well, the EDK2 binary is available at
`edk2/Build/ArmVirtCloudHv-AARCH64/RELEASE_GCC5/FV/CLOUDHV_EFI.fd`.
## Using OVMF Binaries
Any UEFI capable image can be booted using the Cloud Hypervisor specific firmware. Windows guests under Cloud Hypervisor only support UEFI boot, therefore OVMF is mandatory there.
To make Cloud Hypervisor use UEFI boot, pass the `CLOUDHV.fd` file path as an argument to the `--kernel` option. The firmware file will be opened in read only mode.
To make Cloud Hypervisor use UEFI boot, pass the `CLOUDHV.fd` (for x86-64) / `CLOUDHV_EFI.fd` (for AArch64) file path as an argument to the `--kernel` option. The firmware file will be opened in read only mode.
# Links

View File

@@ -5,6 +5,6 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
[dependencies]
libc = "0.2.137"
serde = { version = "1.0.147", features = ["rc", "derive"] }
serde_json = "1.0.87"
libc = "0.2.139"
serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.89"

View File

@@ -16,8 +16,10 @@ static mut MONITOR: Option<(File, Instant)> = None;
/// This function must only be called once from the main process before any threads
/// are created to avoid race conditions
pub fn set_monitor(file: File) -> Result<(), std::io::Error> {
// SAFETY: there is only one caller of this function, so MONITOR is written to only once
assert!(unsafe { MONITOR.is_none() });
let fd = file.as_raw_fd();
// SAFETY: FFI call to configure the fd
let ret = unsafe {
let mut flags = libc::fcntl(fd, libc::F_GETFL);
flags |= libc::O_NONBLOCK;
@@ -26,6 +28,7 @@ pub fn set_monitor(file: File) -> Result<(), std::io::Error> {
if ret < 0 {
return Err(std::io::Error::last_os_error());
}
// SAFETY: MONITOR is None. Nobody else can hold a reference to it.
unsafe {
MONITOR = Some((file, Instant::now()));
};
@@ -41,6 +44,7 @@ struct Event<'a> {
}
pub fn event_log(source: &str, event: &str, properties: Option<&HashMap<Cow<str>, Cow<str>>>) {
// SAFETY: MONITOR is always in a valid state (None or Some).
if let Some((file, start)) = unsafe { MONITOR.as_ref() } {
let e = Event {
timestamp: start.elapsed(),

192
fuzz/Cargo.lock generated
View File

@@ -11,9 +11,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.66"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
[[package]]
name = "api_client"
@@ -56,17 +56,6 @@ dependencies = [
"vmm-sys-util",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "bincode"
version = "1.3.3"
@@ -90,6 +79,7 @@ dependencies = [
"libc",
"log",
"qcow",
"smallvec",
"thiserror",
"versionize",
"versionize_derive",
@@ -109,9 +99,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.73"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
dependencies = [
"jobserver",
]
@@ -124,13 +114,13 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.0.18"
version = "4.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b"
checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
dependencies = [
"atty",
"bitflags",
"clap_lex",
"is-terminal",
"once_cell",
"strsim",
"termcolor",
@@ -148,7 +138,7 @@ dependencies = [
[[package]]
name = "cloud-hypervisor"
version = "27.0.0"
version = "28.0.0"
dependencies = [
"anyhow",
"api_client",
@@ -180,7 +170,9 @@ dependencies = [
"epoll",
"libc",
"libfuzzer-sys",
"linux-loader",
"micro_http",
"net_util",
"once_cell",
"qcow",
"seccompiler",
@@ -332,9 +324,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.1.20"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7a30908dbce072eca83216eab939d2290080e00ca71611b96a09e5cdce5f3fa"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
@@ -360,12 +352,11 @@ dependencies = [
[[package]]
name = "iced-x86"
version = "1.17.0"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "158f5204401d08f91d19176112146d75e99b3cf745092e268fa7be33e09adcec"
checksum = "1dd04b950d75b3498320253b17fb92745b2cc79ead8814aede2f7c1bab858bec"
dependencies = [
"lazy_static",
"static_assertions",
]
[[package]]
@@ -376,25 +367,41 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "io-lifetimes"
version = "0.7.5"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074"
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "io-uring"
version = "0.5.9"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ba34abb5175052fc1a2227a10d2275b7386c9990167de9786c0b88d8b062330"
checksum = "c9ddf18110cedc09617f5a965bdb51adb0c0fb02c791e4ab22f7a21bb25269b0"
dependencies = [
"bitflags",
"libc",
]
[[package]]
name = "itoa"
version = "1.0.4"
name = "is-terminal"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys",
]
[[package]]
name = "itoa"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "jobserver"
@@ -407,8 +414,8 @@ dependencies = [
[[package]]
name = "kvm-bindings"
version = "0.5.0"
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.5.0-tdx#52e56d0e8ef0f6ea32fc0492e6a175b73617a49f"
version = "0.6.0"
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.6.0-tdx#7d9ffb47e5b9b1989577258800a0f57c93f1445f"
dependencies = [
"serde",
"serde_derive",
@@ -417,8 +424,9 @@ dependencies = [
[[package]]
name = "kvm-ioctls"
version = "0.11.0"
source = "git+https://github.com/rust-vmm/kvm-ioctls?branch=main#1e03e29cdfbb0cb108a98de7a78045a5a517f18e"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3a321cabd827642499c77e27314f388dd83a717a5ca716b86476fb947f73ae4"
dependencies = [
"kvm-bindings",
"libc",
@@ -433,9 +441,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.137"
version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "libfuzzer-sys"
@@ -450,18 +458,18 @@ dependencies = [
[[package]]
name = "linux-loader"
version = "0.7.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8242360c7d79a7713a28043c994b815e9820b0e97e44b228ec9bd913c16bdfe"
checksum = "b9259ddbfbb52cc918f6bbc60390004ddd0228cf1d85f402009ff2b3d95de83f"
dependencies = [
"vm-memory",
]
[[package]]
name = "linux-raw-sys"
version = "0.0.46"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]]
name = "log"
@@ -475,7 +483,7 @@ dependencies = [
[[package]]
name = "micro_http"
version = "0.1.0"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#863b0370ba7e57f7df5b908ada9e5b44809ccae9"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#fbef706e28c7ca7cce8dfec7ca073f3b359879d3"
dependencies = [
"libc",
"vmm-sys-util",
@@ -511,9 +519,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.16.0"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
[[package]]
name = "option_parser"
@@ -521,9 +529,9 @@ version = "0.1.0"
[[package]]
name = "os_str_bytes"
version = "6.4.0"
version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5bf27447411e9ee3ff51186bf7a08e16c341efdde93f4d823e8844429bed7e"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
name = "pci"
@@ -592,9 +600,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.47"
version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
dependencies = [
"unicode-ident",
]
@@ -645,9 +653,9 @@ dependencies = [
[[package]]
name = "remain"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a81bc6a3aaeb180f767bd2bda8c03bac5b93b3b69a783c66f35d16a4df276cf"
checksum = "5704e2cda92fd54202f05430725317ba0ea7d0c96b246ca0a92e45177127ba3b"
dependencies = [
"proc-macro2",
"quote",
@@ -665,9 +673,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.35.13"
version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9"
checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
dependencies = [
"bitflags",
"errno",
@@ -679,9 +687,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.11"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "seccompiler"
@@ -694,24 +702,24 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.14"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
[[package]]
name = "serde"
version = "1.0.147"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.147"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
@@ -720,9 +728,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.87"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
dependencies = [
"itoa",
"ryu",
@@ -731,9 +739,9 @@ dependencies = [
[[package]]
name = "serde_with"
version = "2.0.1"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368f2d60d049ea019a84dcd6687b0d1e0030fe663ae105039bdf967ed5e6a9a7"
checksum = "25bf4a5a814902cd1014dbccfa4d4560fb8432c779471e96e035602519f82eef"
dependencies = [
"serde",
"serde_with_macros",
@@ -741,9 +749,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
version = "2.0.1"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ccadfacf6cf10faad22bbadf55986bdd0856edfb5d9210aa1dcf1f516e84e93"
checksum = "a1966009f3c05f095697c537312f5415d1e3ed31ce0a56942bac4c771c5c335e"
dependencies = [
"darling",
"proc-macro2",
@@ -781,10 +789,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
[[package]]
name = "static_assertions"
version = "1.1.0"
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "strsim"
@@ -794,9 +802,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.103"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
@@ -814,9 +822,9 @@ dependencies = [
[[package]]
name = "terminal_size"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ca90c434fd12083d1a6bdcbe9f92a14f96c8a1ba600ba451734ac334521f7a"
checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
dependencies = [
"rustix",
"windows-sys",
@@ -867,9 +875,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.5"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "uuid"
@@ -882,9 +890,9 @@ dependencies = [
[[package]]
name = "versionize"
version = "0.1.6"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7429cf68de8f091b667d27323ed323afd39584a56d533995b12ddd748e5e6ca9"
checksum = "d6e2495726cf917e7ba7ec8bf0f0fceab543dd38d0a4195ed6bef331e38a290f"
dependencies = [
"bincode",
"crc64",
@@ -909,17 +917,16 @@ dependencies = [
[[package]]
name = "vfio-bindings"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43449b404c488f70507dca193debd4bea361fe8089869b947adc19720e464bce"
version = "0.4.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#7ef33f6759ae6d37a54cd66f749aa47c1c81509c"
dependencies = [
"vmm-sys-util",
]
[[package]]
name = "vfio-ioctls"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#bf7c9b997b4ad0ca1ab4bfe96dc1b10d4bc5be24"
version = "0.2.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#7ef33f6759ae6d37a54cd66f749aa47c1c81509c"
dependencies = [
"byteorder",
"kvm-bindings",
@@ -962,8 +969,9 @@ dependencies = [
[[package]]
name = "vhost"
version = "0.5.0"
source = "git+https://github.com/rust-vmm/vhost?branch=main#f87156b77662af63b9fc9f116a213dd69e16007b"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9b791c5b0717a0558888a4cf7240cea836f39a99cb342e12ce633dcaa078072"
dependencies = [
"bitflags",
"libc",
@@ -1014,9 +1022,9 @@ dependencies = [
[[package]]
name = "virtio-queue"
version = "0.6.1"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435dd49c7b38419729afd43675850c7b5dc4728f2fabd70c7a9079a331e4f8c6"
checksum = "19e927d93d54c365034fd7f31a5f458a1f540de4a37c52e892670dad9692173c"
dependencies = [
"log",
"virtio-bindings",
@@ -1048,14 +1056,14 @@ dependencies = [
[[package]]
name = "vm-fdt"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#720e48e435b791ec6cbe8d2b229448b71dcb1ab9"
version = "0.2.0"
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#c5a99ab71b130435927d19b50c85fcd5ce904a8c"
[[package]]
name = "vm-memory"
version = "0.9.0"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "583f213899e8a5eea23d9c507252d4bed5bc88f0ecbe0783262f80034630744b"
checksum = "688a70366615b45575a424d9c665561c1b5ab2224d494f706b6a6812911a827c"
dependencies = [
"arc-swap",
"libc",
@@ -1133,9 +1141,9 @@ dependencies = [
[[package]]
name = "vmm-sys-util"
version = "0.10.0"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08604d7be03eb26e33b3cee3ed4aef2bf550b305d1cca60e84da5d28d3790b62"
checksum = "cc06a16ee8ebf0d9269aed304030b0d20a866b8b3dd3d4ce532596ac567a0d24"
dependencies = [
"bitflags",
"libc",

View File

@@ -12,18 +12,20 @@ cargo-fuzz = true
block_util = { path = "../block_util" }
devices = { path = "../devices" }
epoll = "4.3.1"
libc = "0.2.135"
libc = "0.2.138"
libfuzzer-sys = "0.4.5"
linux-loader = { version = "0.8.1", features = ["elf", "bzimage", "pe"] }
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
once_cell = "1.16.0"
net_util = { path = "../net_util" }
once_cell = "1.17.0"
qcow = { path = "../qcow" }
seccompiler = "0.3.0"
vhdx = { path = "../vhdx" }
virtio-devices = { path = "../virtio-devices" }
virtio-queue = "0.6.1"
virtio-queue = "0.7.0"
vmm = { path = "../vmm" }
vmm-sys-util = "0.10.0"
vm-memory = "0.9.0"
vmm-sys-util = "0.11.0"
vm-memory = "0.10.0"
vm-device = { path = "../vm-device" }
vm-virtio = { path = "../vm-virtio" }
@@ -31,10 +33,8 @@ vm-virtio = { path = "../vm-virtio" }
path = ".."
[patch.crates-io]
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx" }
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" }
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
vhost = { git = "https://github.com/rust-vmm/vhost", branch = "main" }
# Prevent this from interfering with workspaces
[workspace]
@@ -76,12 +76,30 @@ path = "fuzz_targets/iommu.rs"
test = false
doc = false
[[bin]]
name = "linux_loader"
path = "fuzz_targets/linux_loader.rs"
test = false
doc = false
[[bin]]
name = "linux_loader_cmdline"
path = "fuzz_targets/linux_loader_cmdline.rs"
test = false
doc = false
[[bin]]
name = "mem"
path = "fuzz_targets/mem.rs"
test = false
doc = false
[[bin]]
name = "net"
path = "fuzz_targets/net.rs"
test = false
doc = false
[[bin]]
name = "pmem"
path = "fuzz_targets/pmem.rs"

View File

@@ -0,0 +1,50 @@
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Copyright © 2022 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
#![no_main]
use libfuzzer_sys::fuzz_target;
use linux_loader::loader::KernelLoader;
use std::ffi;
use std::fs::File;
use std::io;
use std::io::{Seek, SeekFrom, Write};
use std::os::unix::io::{FromRawFd, RawFd};
use vm_memory::{bitmap::AtomicBitmap, GuestAddress};
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
const MEM_SIZE: usize = 256 * 1024 * 1024;
// From 'arch::x86_64::layout::HIGH_RAM_START'
const HIGH_RAM_START: GuestAddress = GuestAddress(0x100000);
fuzz_target!(|bytes| {
let shm = memfd_create(&ffi::CString::new("fuzz_load_kernel").unwrap(), 0).unwrap();
let mut kernel_file: File = unsafe { File::from_raw_fd(shm) };
kernel_file.write_all(&bytes).unwrap();
kernel_file.seek(SeekFrom::Start(0)).unwrap();
let guest_memory = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM_SIZE)]).unwrap();
linux_loader::loader::elf::Elf::load(
&guest_memory,
None,
&mut kernel_file,
Some(HIGH_RAM_START),
)
.ok();
});
fn memfd_create(name: &ffi::CStr, flags: u32) -> Result<RawFd, io::Error> {
let res = unsafe { libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags) };
if res < 0 {
Err(io::Error::last_os_error())
} else {
Ok(res as RawFd)
}
}

View File

@@ -0,0 +1,34 @@
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Copyright © 2022 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
#![no_main]
use libfuzzer_sys::fuzz_target;
use vm_memory::{bitmap::AtomicBitmap, GuestAddress};
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
const MEM_SIZE: usize = 256 * 1024 * 1024;
// From 'arch::x86_64::layout::CMDLINE_START'
const CMDLINE_START: GuestAddress = GuestAddress(0x20000);
fuzz_target!(|bytes| {
let payload_config = vmm::config::PayloadConfig {
firmware: None,
kernel: None,
cmdline: Some(String::from_utf8_lossy(&bytes).to_string()),
initramfs: None,
};
let kernel_cmdline = match vmm::vm::Vm::generate_cmdline(&payload_config) {
Ok(cmdline) => cmdline,
_ => return,
};
let guest_memory = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM_SIZE)]).unwrap();
linux_loader::loader::load_cmdline(&guest_memory, CMDLINE_START, &kernel_cmdline).ok();
});

285
fuzz/fuzz_targets/net.rs Normal file
View File

@@ -0,0 +1,285 @@
// Copyright © 2022 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
#![no_main]
use libfuzzer_sys::fuzz_target;
use seccompiler::SeccompAction;
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::Arc;
use virtio_devices::{VirtioDevice, VirtioInterrupt, VirtioInterruptType};
use virtio_queue::{Queue, QueueT};
use vm_memory::{bitmap::AtomicBitmap, Bytes, GuestAddress, GuestMemoryAtomic};
use vmm::EpollContext;
use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
macro_rules! align {
($n:expr, $align:expr) => {{
(($n + $align - 1) / $align) * $align
}};
}
const TAP_INPUT_SIZE: usize = 128;
const QUEUE_DATA_SIZE: usize = 4;
const MEM_SIZE: usize = 32 * 1024 * 1024;
// Guest memory gap
const GUEST_MEM_GAP: u64 = 1 * 1024 * 1024;
// Guest physical address for the first virt queue
const BASE_VIRT_QUEUE_ADDR: u64 = MEM_SIZE as u64 + GUEST_MEM_GAP;
// Number of queues
const QUEUE_NUM: usize = 2;
// Max entries in the queue.
const QUEUE_SIZE: u16 = 256;
// Descriptor table alignment
const DESC_TABLE_ALIGN_SIZE: u64 = 16;
// Used ring alignment
const USED_RING_ALIGN_SIZE: u64 = 4;
// Descriptor table size
const DESC_TABLE_SIZE: u64 = 16_u64 * QUEUE_SIZE as u64;
// Available ring size
const AVAIL_RING_SIZE: u64 = 6_u64 + 2 * QUEUE_SIZE as u64;
// Padding size before used ring
const PADDING_SIZE: u64 = align!(AVAIL_RING_SIZE, USED_RING_ALIGN_SIZE) - AVAIL_RING_SIZE;
// Used ring size
const USED_RING_SIZE: u64 = 6_u64 + 8 * QUEUE_SIZE as u64;
// Virtio-queue size in bytes
const QUEUE_BYTES_SIZE: usize = align!(
DESC_TABLE_SIZE + AVAIL_RING_SIZE + PADDING_SIZE + USED_RING_SIZE,
DESC_TABLE_ALIGN_SIZE
) as usize;
fuzz_target!(|bytes| {
if bytes.len() < TAP_INPUT_SIZE + (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE) * QUEUE_NUM
|| bytes.len()
> TAP_INPUT_SIZE + (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE) * QUEUE_NUM + MEM_SIZE
{
return;
}
let (dummy_tap_frontend, dummy_tap_backend) = create_socketpair().unwrap();
let if_name = "fuzzer_tap_name".as_bytes().to_vec();
let tap = net_util::Tap::new_for_fuzzing(dummy_tap_frontend, if_name);
let mut net = virtio_devices::Net::new_with_tap(
"fuzzer_net".to_owned(),
vec![tap],
None, // guest_mac
false, // iommu
QUEUE_NUM,
QUEUE_SIZE,
SeccompAction::Allow,
None,
EventFd::new(EFD_NONBLOCK).unwrap(),
None,
true,
true,
true,
)
.unwrap();
let tap_input_bytes = &bytes[..TAP_INPUT_SIZE];
let queue_data = &bytes[TAP_INPUT_SIZE..TAP_INPUT_SIZE + QUEUE_DATA_SIZE * QUEUE_NUM];
let queue_bytes = &bytes[TAP_INPUT_SIZE + QUEUE_DATA_SIZE * QUEUE_NUM
..TAP_INPUT_SIZE + (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE) * QUEUE_NUM];
let mem_bytes = &bytes[TAP_INPUT_SIZE + (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE) * QUEUE_NUM..];
// Setup the virt queues with the input bytes
let mut queues = setup_virt_queues(
&[
&queue_data[..QUEUE_DATA_SIZE].try_into().unwrap(),
&queue_data[QUEUE_DATA_SIZE..QUEUE_DATA_SIZE * 2]
.try_into()
.unwrap(),
],
BASE_VIRT_QUEUE_ADDR,
);
// Setup the guest memory with the input bytes
let mem = GuestMemoryMmap::from_ranges(&[
(GuestAddress(0), MEM_SIZE),
(GuestAddress(BASE_VIRT_QUEUE_ADDR), queue_bytes.len()),
])
.unwrap();
if mem
.write_slice(queue_bytes, GuestAddress(BASE_VIRT_QUEUE_ADDR))
.is_err()
{
return;
}
if mem.write_slice(mem_bytes, GuestAddress(0 as u64)).is_err() {
return;
}
let guest_memory = GuestMemoryAtomic::new(mem);
let input_queue = queues.remove(0);
let input_evt = EventFd::new(0).unwrap();
let input_queue_evt = unsafe { EventFd::from_raw_fd(libc::dup(input_evt.as_raw_fd())) };
let output_queue = queues.remove(0);
let output_evt = EventFd::new(0).unwrap();
let output_queue_evt = unsafe { EventFd::from_raw_fd(libc::dup(output_evt.as_raw_fd())) };
// Start the thread of dummy tap backend to handle the rx and tx from the virtio-net
let exit_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let tap_backend_thread = {
let dummy_tap_backend = dummy_tap_backend.try_clone().unwrap();
let tap_input_bytes: [u8; TAP_INPUT_SIZE] = tap_input_bytes[..].try_into().unwrap();
let exit_evt = exit_evt.try_clone().unwrap();
std::thread::Builder::new()
.name("dummy_tap_backend".to_string())
.spawn(move || {
tap_backend_stub(dummy_tap_backend, &tap_input_bytes, exit_evt);
})
.unwrap()
};
// Kick the 'queue' events and endpoint event before activate the net device
input_queue_evt.write(1).unwrap();
output_queue_evt.write(1).unwrap();
net.activate(
guest_memory,
Arc::new(NoopVirtioInterrupt {}),
vec![(0, input_queue, input_evt), (1, output_queue, output_evt)],
)
.unwrap();
// Wait for the events to finish and net device worker thread to return
net.wait_for_epoll_threads();
// Terminate the thread for the dummy tap backend
exit_evt.write(1).ok();
tap_backend_thread.join().unwrap();
});
pub struct NoopVirtioInterrupt {}
impl VirtioInterrupt for NoopVirtioInterrupt {
fn trigger(&self, _int_type: VirtioInterruptType) -> std::result::Result<(), std::io::Error> {
Ok(())
}
}
fn setup_virt_queues(bytes: &[&[u8; QUEUE_DATA_SIZE]], base_addr: u64) -> Vec<Queue> {
let mut queues = Vec::new();
for (i, b) in bytes.iter().enumerate() {
let mut q = Queue::new(QUEUE_SIZE).unwrap();
let desc_table_addr = base_addr + (QUEUE_BYTES_SIZE * i) as u64;
let avail_ring_addr = desc_table_addr + DESC_TABLE_SIZE;
let used_ring_addr = avail_ring_addr + PADDING_SIZE + AVAIL_RING_SIZE;
q.try_set_desc_table_address(GuestAddress(desc_table_addr))
.unwrap();
q.try_set_avail_ring_address(GuestAddress(avail_ring_addr))
.unwrap();
q.try_set_used_ring_address(GuestAddress(used_ring_addr))
.unwrap();
q.set_next_avail(b[0] as u16); // 'u8' is enough given the 'QUEUE_SIZE' is small
q.set_next_used(b[1] as u16);
q.set_event_idx(b[2] % 2 != 0);
q.set_size(b[3] as u16 % QUEUE_SIZE);
q.set_ready(true);
queues.push(q);
}
queues
}
fn create_socketpair() -> Result<(File, File), std::io::Error> {
let mut fds = [-1, -1];
unsafe {
let ret = libc::socketpair(
libc::AF_UNIX,
libc::SOCK_STREAM | libc::SOCK_NONBLOCK,
0,
fds.as_mut_ptr(),
);
if ret == -1 {
return Err(std::io::Error::last_os_error());
}
}
let socket1 = unsafe { File::from_raw_fd(fds[0]) };
let socket2 = unsafe { File::from_raw_fd(fds[1]) };
Ok((socket1, socket2))
}
enum EpollEvent {
Exit = 0,
Rx = 1,
Tx = 2,
Unknown,
}
impl From<u64> for EpollEvent {
fn from(v: u64) -> Self {
use EpollEvent::*;
match v {
0 => Exit,
1 => Rx,
2 => Tx,
_ => Unknown,
}
}
}
// Handle the rx and tx requests from the virtio-net device
fn tap_backend_stub(
mut dummy_tap: File,
tap_input_bytes: &[u8; TAP_INPUT_SIZE],
exit_evt: EventFd,
) {
let mut epoll = EpollContext::new().unwrap();
epoll
.add_event_custom(&exit_evt, EpollEvent::Exit as u64, epoll::Events::EPOLLIN)
.unwrap();
let dummy_tap_write = dummy_tap.try_clone().unwrap();
epoll
.add_event_custom(
&dummy_tap_write,
EpollEvent::Rx as u64,
epoll::Events::EPOLLOUT,
)
.unwrap();
epoll
.add_event_custom(&dummy_tap, EpollEvent::Tx as u64, epoll::Events::EPOLLIN)
.unwrap();
let epoll_fd = epoll.as_raw_fd();
let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); 3];
loop {
let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) {
Ok(num_events) => num_events,
Err(e) => match e.raw_os_error() {
Some(libc::EAGAIN) | Some(libc::EINTR) => continue,
_ => panic!("Unexpected epoll::wait error!"),
},
};
for event in events.iter().take(num_events) {
let dispatch_event: EpollEvent = event.data.into();
match dispatch_event {
EpollEvent::Exit => {
return;
}
EpollEvent::Rx => {
dummy_tap.write_all(tap_input_bytes).unwrap();
break;
}
EpollEvent::Tx => {
let mut buffer = Vec::new();
dummy_tap.read_to_end(&mut buffer).ok();
break;
}
_ => {
panic!("Unexpected Epoll event");
}
}
}
}
}

View File

@@ -15,6 +15,7 @@ fuzz_target!(|bytes| {
let mut serial = Serial::new_sink(
"serial".into(),
Arc::new(TestInterrupt::new(EventFd::new(EFD_NONBLOCK).unwrap())),
None,
);
let mut i = 0;

View File

@@ -11,25 +11,25 @@ mshv = ["mshv-ioctls", "mshv-bindings"]
tdx = []
[dependencies]
anyhow = "1.0.66"
anyhow = "1.0.68"
byteorder = "1.4.3"
thiserror = "1.0.37"
libc = "0.2.137"
thiserror = "1.0.38"
libc = "0.2.139"
log = "0.4.17"
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-ioctls = { version = "0.12.0", optional = true }
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
serde = { version = "1.0.147", features = ["rc", "derive"] }
serde_with = { version = "2.0.1", default-features = false, features = ["macros"] }
serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_with = { version = "2.1.0", default-features = false, features = ["macros"] }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
vm-memory = { version = "0.9.0", features = ["backend-mmap", "backend-atomic"] }
vmm-sys-util = { version = "0.10.0", features = ["with-serde"] }
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic"] }
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
version = "1.17.0"
version = "1.18.0"
default-features = false
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
[dev-dependencies]
env_logger = "0.9.3"
env_logger = "0.10.0"

View File

@@ -24,10 +24,10 @@ impl<T: Debug> Display for Exception<T> {
self.vector,
self.ip,
self.error
.map(|e| format!(": error {:x}", e))
.map(|e| format!(": error {e:x}"))
.unwrap_or_else(|| "".to_owned()),
self.payload
.map(|payload| format!(": payload {:x}", payload))
.map(|payload| format!(": payload {payload:x}"))
.unwrap_or_else(|| "".to_owned())
)
}

View File

@@ -272,6 +272,7 @@ impl LapicState {
use std::io::Cursor;
use std::mem;
// SAFETY: plain old data type
let sliceu8 = unsafe {
// This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
// Cursors are only readable on arrays of u8, not i8(c_char).
@@ -290,6 +291,7 @@ impl LapicState {
use std::io::Cursor;
use std::mem;
// SAFETY: plain old data type
let sliceu8 = unsafe {
// This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
// Cursors are only readable on arrays of u8, not i8(c_char).

View File

@@ -39,8 +39,8 @@ const GICR_ICFGR0: u32 = GICR_SGI_OFFSET + 0x0C00;
const KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT: u32 = 32;
const KVM_DEV_ARM_VGIC_V3_MPIDR_MASK: u64 = 0xffffffff << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT as u64;
const KVM_ARM64_SYSREG_MPIDR_EL1: u64 = KVM_REG_ARM64 as u64
| KVM_REG_SIZE_U64 as u64
const KVM_ARM64_SYSREG_MPIDR_EL1: u64 = KVM_REG_ARM64
| KVM_REG_SIZE_U64
| KVM_REG_ARM64_SYSREG as u64
| (((3_u64) << KVM_REG_ARM64_SYSREG_OP0_SHIFT) & KVM_REG_ARM64_SYSREG_OP0_MASK as u64)
| (((5_u64) << KVM_REG_ARM64_SYSREG_OP2_SHIFT) & KVM_REG_ARM64_SYSREG_OP2_MASK as u64);

View File

@@ -24,8 +24,8 @@ pub use {kvm_ioctls::Cap, kvm_ioctls::Kvm};
// This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having
// an instance of that structure.
#[macro_export]
macro_rules! offset__of {
($str:ty, $($field:ident)+) => ({
macro_rules! offset_of {
($str:ty, $field:ident) => {{
let tmp: std::mem::MaybeUninit<$str> = std::mem::MaybeUninit::uninit();
let base = tmp.as_ptr();
@@ -34,14 +34,16 @@ macro_rules! offset__of {
// SAFETY: The pointer is valid and aligned, just not initialised. Using `addr_of` ensures
// that we don't actually read from `base` (which would be UB) nor create an intermediate
// reference.
let member = unsafe { core::ptr::addr_of!((*base).$($field)*) } as *const u8;
let member = unsafe { core::ptr::addr_of!((*base).$field) } as *const u8;
// Avoid warnings when nesting `unsafe` blocks.
#[allow(unused_unsafe)]
// SAFETY: The two pointers are within the same allocated object `tmp`. All requirements
// from offset_from are upheld.
unsafe { member.offset_from(base as *const u8) as usize }
});
unsafe {
member.offset_from(base as *const u8) as usize
}
}};
}
// Following are macros that help with getting the ID of a aarch64 core register.
@@ -97,8 +99,7 @@ pub fn is_system_register(regid: u64) -> bool {
assert!(
!(size != KVM_REG_SIZE_U32 && size != KVM_REG_SIZE_U64),
"Unexpected register size for system register {}",
size
"Unexpected register size for system register {size}"
);
true

View File

@@ -23,7 +23,7 @@ use crate::vec_with_array_field;
use crate::vm::{self, InterruptSourceConfig, VmOps};
use crate::HypervisorType;
#[cfg(target_arch = "aarch64")]
use crate::{arm64_core_reg_id, offset__of};
use crate::{arm64_core_reg_id, offset_of};
use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd};
use std::any::Any;
use std::collections::HashMap;
@@ -1114,7 +1114,7 @@ impl cpu::Vcpu for KvmVcpu {
#[cfg(target_arch = "aarch64")]
fn get_regs(&self) -> cpu::Result<StandardRegisters> {
let mut state: StandardRegisters = kvm_regs::default();
let mut off = offset__of!(user_pt_regs, regs);
let mut off = offset_of!(user_pt_regs, regs);
// There are 31 user_pt_regs:
// https://elixir.free-electrons.com/linux/v4.14.174/source/arch/arm64/include/uapi/asm/ptrace.h#L72
// These actually are the general-purpose registers of the Armv8-a
@@ -1131,7 +1131,7 @@ impl cpu::Vcpu for KvmVcpu {
// We are now entering the "Other register" section of the ARMv8-a architecture.
// First one, stack pointer.
let off = offset__of!(user_pt_regs, sp);
let off = offset_of!(user_pt_regs, sp);
state.regs.sp = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
@@ -1140,7 +1140,7 @@ impl cpu::Vcpu for KvmVcpu {
.unwrap();
// Second one, the program counter.
let off = offset__of!(user_pt_regs, pc);
let off = offset_of!(user_pt_regs, pc);
state.regs.pc = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
@@ -1149,7 +1149,7 @@ impl cpu::Vcpu for KvmVcpu {
.unwrap();
// Next is the processor state.
let off = offset__of!(user_pt_regs, pstate);
let off = offset_of!(user_pt_regs, pstate);
state.regs.pstate = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
@@ -1158,7 +1158,7 @@ impl cpu::Vcpu for KvmVcpu {
.unwrap();
// The stack pointer associated with EL1
let off = offset__of!(kvm_regs, sp_el1);
let off = offset_of!(kvm_regs, sp_el1);
state.sp_el1 = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
@@ -1168,7 +1168,7 @@ impl cpu::Vcpu for KvmVcpu {
// Exception Link Register for EL1, when taking an exception to EL1, this register
// holds the address to which to return afterwards.
let off = offset__of!(kvm_regs, elr_el1);
let off = offset_of!(kvm_regs, elr_el1);
state.elr_el1 = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
@@ -1177,7 +1177,7 @@ impl cpu::Vcpu for KvmVcpu {
.unwrap();
// Saved Program Status Registers, there are 5 of them used in the kernel.
let mut off = offset__of!(kvm_regs, spsr);
let mut off = offset_of!(kvm_regs, spsr);
for i in 0..KVM_NR_SPSR as usize {
state.spsr[i] = self
.fd
@@ -1190,7 +1190,7 @@ impl cpu::Vcpu for KvmVcpu {
// Now moving on to floting point registers which are stored in the user_fpsimd_state in the kernel:
// https://elixir.free-electrons.com/linux/v4.9.62/source/arch/arm64/include/uapi/asm/kvm.h#L53
let mut off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, vregs);
let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs);
for i in 0..32 {
state.fp_regs.vregs[i] = self
.fd
@@ -1200,7 +1200,7 @@ impl cpu::Vcpu for KvmVcpu {
}
// Floating-point Status Register
let off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, fpsr);
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
state.fp_regs.fpsr = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off))
@@ -1209,7 +1209,7 @@ impl cpu::Vcpu for KvmVcpu {
.unwrap();
// Floating-point Control Register
let off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, fpcr);
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
state.fp_regs.fpcr = self
.fd
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off))
@@ -1238,7 +1238,7 @@ impl cpu::Vcpu for KvmVcpu {
fn set_regs(&self, state: &StandardRegisters) -> cpu::Result<()> {
// The function follows the exact identical order from `state`. Look there
// for some additional info on registers.
let mut off = offset__of!(user_pt_regs, regs);
let mut off = offset_of!(user_pt_regs, regs);
for i in 0..31 {
self.fd
.set_one_reg(
@@ -1249,7 +1249,7 @@ impl cpu::Vcpu for KvmVcpu {
off += std::mem::size_of::<u64>();
}
let off = offset__of!(user_pt_regs, sp);
let off = offset_of!(user_pt_regs, sp);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
@@ -1257,7 +1257,7 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
let off = offset__of!(user_pt_regs, pc);
let off = offset_of!(user_pt_regs, pc);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
@@ -1265,7 +1265,7 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
let off = offset__of!(user_pt_regs, pstate);
let off = offset_of!(user_pt_regs, pstate);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
@@ -1273,7 +1273,7 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
let off = offset__of!(kvm_regs, sp_el1);
let off = offset_of!(kvm_regs, sp_el1);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
@@ -1281,7 +1281,7 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
let off = offset__of!(kvm_regs, elr_el1);
let off = offset_of!(kvm_regs, elr_el1);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
@@ -1289,7 +1289,7 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
let mut off = offset__of!(kvm_regs, spsr);
let mut off = offset_of!(kvm_regs, spsr);
for i in 0..KVM_NR_SPSR as usize {
self.fd
.set_one_reg(
@@ -1300,7 +1300,7 @@ impl cpu::Vcpu for KvmVcpu {
off += std::mem::size_of::<u64>();
}
let mut off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, vregs);
let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs);
for i in 0..32 {
self.fd
.set_one_reg(
@@ -1311,7 +1311,7 @@ impl cpu::Vcpu for KvmVcpu {
off += mem::size_of::<u128>();
}
let off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, fpsr);
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
@@ -1319,7 +1319,7 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
let off = offset__of!(kvm_regs, fp_regs) + offset__of!(user_fpsimd_state, fpcr);
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
@@ -1700,8 +1700,8 @@ impl cpu::Vcpu for KvmVcpu {
// it to the corresponding KVM ID, and call `KVM_GET_ONE_REG` API to
// get the value of the system parameter.
//
let id: u64 = KVM_REG_ARM64 as u64
| KVM_REG_SIZE_U64 as u64
let id: u64 = KVM_REG_ARM64
| KVM_REG_SIZE_U64
| KVM_REG_ARM64_SYSREG as u64
| ((((sys_reg) >> 5)
& (KVM_REG_ARM64_SYSREG_OP0_MASK
@@ -1733,10 +1733,10 @@ impl cpu::Vcpu for KvmVcpu {
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);
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;
let pstate = offset_of!(user_pt_regs, pstate) + kreg_off;
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate),
@@ -1747,7 +1747,7 @@ impl cpu::Vcpu for KvmVcpu {
// 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;
let pc = offset_of!(user_pt_regs, pc) + kreg_off;
self.fd
.set_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), boot_ip.into())
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
@@ -1756,7 +1756,7 @@ impl cpu::Vcpu for KvmVcpu {
// "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;
let regs0 = offset_of!(user_pt_regs, regs) + kreg_off;
self.fd
.set_one_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
@@ -2066,6 +2066,7 @@ impl cpu::Vcpu for KvmVcpu {
#[cfg(feature = "tdx")]
fn get_tdx_exit_details(&mut self) -> cpu::Result<TdxExitDetails> {
let kvm_run = self.fd.get_kvm_run();
// SAFETY: accessing a union field in a valid structure
let tdx_vmcall = unsafe { &mut kvm_run.__bindgen_anon_1.tdx.u.vmcall };
tdx_vmcall.status_code = TDG_VP_VMCALL_INVALID_OPERAND;
@@ -2089,6 +2090,7 @@ impl cpu::Vcpu for KvmVcpu {
#[cfg(feature = "tdx")]
fn set_tdx_status(&mut self, status: TdxExitStatus) {
let kvm_run = self.fd.get_kvm_run();
// SAFETY: accessing a union field in a valid structure
let tdx_vmcall = unsafe { &mut kvm_run.__bindgen_anon_1.tdx.u.vmcall };
tdx_vmcall.status_code = match status {

View File

@@ -18,8 +18,6 @@
//! - arm64
//!
#![allow(clippy::significant_drop_in_scrutinee)]
#[macro_use]
extern crate anyhow;
#[cfg(target_arch = "x86_64")]
@@ -63,7 +61,9 @@ pub use vm::{
#[derive(Debug, Copy, Clone)]
pub enum HypervisorType {
#[cfg(feature = "kvm")]
Kvm,
#[cfg(feature = "mshv")]
Mshv,
}

View File

@@ -446,10 +446,10 @@ impl cpu::Vcpu for MshvVcpu {
/* Advance RIP and update RAX */
let arr_reg_name_value = [
(
hv_register_name::HV_X64_REGISTER_RIP,
hv_x64_register_name_HV_X64_REGISTER_RIP,
info.header.rip + insn_len,
),
(hv_register_name::HV_X64_REGISTER_RAX, ret_rax),
(hv_x64_register_name_HV_X64_REGISTER_RAX, ret_rax),
];
set_registers_64!(self.fd, arr_reg_name_value)
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
@@ -458,12 +458,13 @@ impl cpu::Vcpu for MshvVcpu {
_ => {}
}
// SAFETY: access_info is valid, otherwise we won't be here
assert!(
// SAFETY: access_info is valid, otherwise we won't be here
(unsafe { access_info.__bindgen_anon_1.string_op() } != 1),
"String IN/OUT not supported"
);
assert!(
// SAFETY: access_info is valid, otherwise we won't be here
(unsafe { access_info.__bindgen_anon_1.rep_prefix() } != 1),
"Rep IN/OUT not supported"
);
@@ -494,10 +495,10 @@ impl cpu::Vcpu for MshvVcpu {
/* Advance RIP and update RAX */
let arr_reg_name_value = [
(
hv_register_name::HV_X64_REGISTER_RIP,
hv_x64_register_name_HV_X64_REGISTER_RIP,
info.header.rip + insn_len,
),
(hv_register_name::HV_X64_REGISTER_RAX, ret_rax),
(hv_x64_register_name_HV_X64_REGISTER_RAX, ret_rax),
];
set_registers_64!(self.fd, arr_reg_name_value)
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;

View File

@@ -5,4 +5,4 @@ authors = ["The Chromium OS Authors"]
edition = "2021"
[dependencies]
vmm-sys-util = "0.10.0"
vmm-sys-util = "0.11.0"

View File

@@ -1187,6 +1187,7 @@ pub struct ifreq {
impl Default for ifreq {
fn default() -> Self {
// SAFETY: all zeros is a valid pattern for this data type
unsafe { std::mem::zeroed() }
}
}

View File

@@ -6,23 +6,23 @@ edition = "2021"
[dependencies]
epoll = "4.3.1"
getrandom = "0.2.7"
libc = "0.2.137"
getrandom = "0.2.8"
libc = "0.2.139"
log = "0.4.17"
net_gen = { path = "../net_gen" }
rate_limiter = { path = "../rate_limiter" }
serde = "1.0.147"
thiserror = "1.0.37"
versionize = "0.1.6"
serde = "1.0.151"
thiserror = "1.0.38"
versionize = "0.1.9"
versionize_derive = "0.1.4"
virtio-bindings = "0.1.0"
virtio-queue = "0.6.1"
vm-memory = { version = "0.9.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
virtio-queue = "0.7.0"
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.10.0"
vmm-sys-util = "0.11.0"
[dev-dependencies]
once_cell = "1.16.0"
pnet = "0.31.0"
pnet_datalink = "0.31.0"
serde_json = "1.0.87"
serde_json = "1.0.89"

View File

@@ -66,32 +66,34 @@ fn create_sockaddr(ip_addr: net::Ipv4Addr) -> net_gen::sockaddr {
let addr_in = net_gen::sockaddr_in {
sin_family: net_gen::AF_INET as u16,
sin_port: 0,
// SAFETY: ip_addr can be safely transmute to in_addr
sin_addr: unsafe { mem::transmute(ip_addr.octets()) },
__pad: [0; 8usize],
};
// SAFETY: addr_in can be safely transmute to sockaddr
unsafe { mem::transmute(addr_in) }
}
fn create_inet_socket() -> Result<net::UdpSocket> {
// This is safe since we check the return value.
// SAFETY: we check the return value.
let sock = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
if sock < 0 {
return Err(Error::CreateSocket(IoError::last_os_error()));
}
// This is safe; nothing else will use or hold onto the raw sock fd.
// SAFETY: nothing else will use or hold onto the raw sock fd.
Ok(unsafe { net::UdpSocket::from_raw_fd(sock) })
}
fn create_unix_socket() -> Result<net::UdpSocket> {
// This is safe since we check the return value.
// SAFETY: we check the return value.
let sock = unsafe { libc::socket(libc::AF_UNIX, libc::SOCK_DGRAM, 0) };
if sock < 0 {
return Err(Error::CreateSocket(IoError::last_os_error()));
}
// This is safe; nothing else will use or hold onto the raw sock fd.
// SAFETY: nothing else will use or hold onto the raw sock fd.
Ok(unsafe { net::UdpSocket::from_raw_fd(sock) })
}

View File

@@ -125,7 +125,7 @@ impl<'de> Deserialize<'de> for MacAddr {
{
let s = String::deserialize(deserializer)?;
MacAddr::parse_str(&s)
.map_err(|e| D::Error::custom(format!("The provided MAC address is invalid: {}", e)))
.map_err(|e| D::Error::custom(format!("The provided MAC address is invalid: {e}")))
}
}
@@ -161,7 +161,7 @@ mod tests {
let mac = MacAddr::parse_str("12:34:56:78:9a:BC").unwrap();
println!("parsed MAC address: {}", mac);
println!("parsed MAC address: {mac}");
let bytes = mac.get_bytes();
assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]);

View File

@@ -41,7 +41,7 @@ type Result<T> = std::result::Result<T, Error>;
fn check_mq_support(if_name: &Option<&str>, queue_pairs: usize) -> Result<()> {
if let Some(tap_name) = if_name {
let mq = queue_pairs > 1;
let path = format!("/sys/class/net/{}/tun_flags", tap_name);
let path = format!("/sys/class/net/{tap_name}/tun_flags");
// interface does not exist, check is not required
if !Path::new(&path).exists() {
return Ok(());

View File

@@ -83,6 +83,7 @@ impl TxVirtio {
}
let len = if !iovecs.is_empty() {
// SAFETY: FFI call with correct arguments
let result = unsafe {
libc::writev(
tap.as_raw_fd() as libc::c_int,
@@ -104,6 +105,10 @@ impl TxVirtio {
return Err(NetQueuePairError::WriteTap(e));
}
if (result as usize) < vnet_hdr_len() {
return Err(NetQueuePairError::InvalidVirtioNetHeader);
}
self.counter_bytes += Wrapping(result as u64 - vnet_hdr_len() as u64);
self.counter_frames += Wrapping(1);
@@ -185,7 +190,7 @@ impl RxVirtio {
.translate_gva(access_platform, desc.len() as usize),
10,
)
.unwrap();
.ok_or(NetQueuePairError::DescriptorInvalidHeader)?;
let mut next_desc = Some(desc);
let mut iovecs = Vec::new();
@@ -217,6 +222,7 @@ impl RxVirtio {
}
let len = if !iovecs.is_empty() {
// SAFETY: FFI call with correct arguments
let result = unsafe {
libc::readv(
tap.as_raw_fd() as libc::c_int,
@@ -238,6 +244,10 @@ impl RxVirtio {
return Err(NetQueuePairError::ReadTap(e));
}
if (result as usize) < vnet_hdr_len() {
return Err(NetQueuePairError::InvalidVirtioNetHeader);
}
// Write num_buffers to guest memory. We simply write 1 as we
// never spread the frame over more than one descriptor chain.
desc_chain
@@ -312,6 +322,10 @@ pub enum NetQueuePairError {
QueueEnableNotification(virtio_queue::Error),
#[error("Failed to add used index to the queue: {0}")]
QueueAddUsed(virtio_queue::Error),
#[error("Descriptor with invalid virtio-net header")]
DescriptorInvalidHeader,
#[error("Invalid virtio-net header")]
InvalidVirtioNetHeader,
}
pub struct NetQueuePair {

View File

@@ -28,8 +28,8 @@ pub enum Error {
GetFeatures(IoError),
#[error("Missing multiqueue support in the kernel")]
MultiQueueKernelSupport,
#[error("ioctl failed: {0}")]
IoctlError(IoError),
#[error("ioctl ({0}) failed: {1}")]
IoctlError(c_ulong, IoError),
#[error("Failed to create a socket: {0}")]
NetUtil(NetUtilError),
#[error("Invalid interface name")]
@@ -87,9 +87,37 @@ fn build_terminated_if_name(if_name: &str) -> Result<Vec<u8>> {
}
impl Tap {
unsafe fn ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: &mut T) -> Result<()> {
let ret = ioctl_with_mut_ref(fd, req, arg);
if ret < 0 {
return Err(Error::IoctlError(req, IoError::last_os_error()));
}
Ok(())
}
unsafe fn ioctl_with_ref<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: &T) -> Result<()> {
let ret = ioctl_with_ref(fd, req, arg);
if ret < 0 {
return Err(Error::IoctlError(req, IoError::last_os_error()));
}
Ok(())
}
unsafe fn ioctl_with_val<F: AsRawFd>(fd: &F, req: c_ulong, arg: c_ulong) -> Result<()> {
let ret = ioctl_with_val(fd, req, arg);
if ret < 0 {
return Err(Error::IoctlError(req, IoError::last_os_error()));
}
Ok(())
}
pub fn open_named(if_name: &str, num_queue_pairs: usize, flags: Option<i32>) -> Result<Tap> {
let terminated_if_name = build_terminated_if_name(if_name)?;
// SAFETY: FFI call
let fd = unsafe {
// Open calls are safe because we give a constant null-terminated
// string and verify the result.
@@ -102,13 +130,14 @@ impl Tap {
return Err(Error::OpenTun(IoError::last_os_error()));
}
// We just checked that the fd is valid.
// SAFETY: We just checked that the fd is valid.
let tuntap = unsafe { File::from_raw_fd(fd) };
// Let's validate some features before going any further.
// ioctl is safe since we call it with a valid tap fd and check the return
// value.
let mut features = 0;
// SAFETY: IOCTL with correct arguments
let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_gen::TUNGETFEATURES(), &mut features) };
if ret < 0 {
return Err(Error::GetFeatures(IoError::last_os_error()));
@@ -123,6 +152,7 @@ impl Tap {
// don't call as_mut on the same union field more than once, this block
// is safe.
let mut ifreq: net_gen::ifreq = Default::default();
// SAFETY: see the comment above.
unsafe {
let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
let name_slice = &mut ifrn_name[..terminated_if_name.len()];
@@ -134,16 +164,16 @@ impl Tap {
}
}
// ioctl is safe since we call it with a valid tap fd and check the return
// SAFETY: ioctl is safe since we call it with a valid tap fd and check the return
// value.
let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_gen::TUNSETIFF(), &mut ifreq) };
if ret < 0 {
return Err(Error::ConfigureTap(IoError::last_os_error()));
}
// SAFETY: only the name is accessed, and it's cloned out.
let mut if_name = unsafe { ifreq.ifr_ifrn.ifrn_name }.to_vec();
if_name.truncate(terminated_if_name.len() - 1);
// Safe since only the name is accessed, and it's cloned out.
Ok(Tap {
tap_file: tuntap,
if_name,
@@ -158,6 +188,7 @@ impl Tap {
pub fn from_tap_fd(fd: RawFd, num_queue_pairs: usize) -> Result<Tap> {
// Ensure that the file is opened non-blocking, this is particularly
// needed when opened via the shell for macvtap.
// SAFETY: FFI call
let ret = unsafe {
let mut flags = libc::fcntl(fd, libc::F_GETFL);
flags |= libc::O_NONBLOCK;
@@ -167,19 +198,20 @@ impl Tap {
return Err(Error::ConfigureTap(IoError::last_os_error()));
}
// SAFETY: fd is a tap fd
let tap_file = unsafe { File::from_raw_fd(fd) };
let mut ifreq: net_gen::ifreq = Default::default();
// Get current config including name
let ret = unsafe { ioctl_with_mut_ref(&tap_file, net_gen::TUNGETIFF(), &mut ifreq) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
// We only access one field of the ifru union, hence this is safe.
// SAFETY: IOCTL with correct arugments
unsafe { Self::ioctl_with_mut_ref(&tap_file, net_gen::TUNGETIFF(), &mut ifreq)? };
// SAFETY: We only access one field of the ifru union
let if_name = unsafe { ifreq.ifr_ifrn.ifrn_name }.to_vec();
// Try and update flags. Depending on how the tap was created (macvtap
// or via open_named()) this might return -EEXIST so we just ignore that.
// SAFETY: access union fields
unsafe {
ifreq.ifr_ifru.ifru_flags =
(net_gen::IFF_TAP | net_gen::IFF_NO_PI | net_gen::IFF_VNET_HDR) as c_short;
@@ -187,6 +219,7 @@ impl Tap {
ifreq.ifr_ifru.ifru_flags |= net_gen::IFF_MULTI_QUEUE as c_short;
}
}
// SAFETY: IOCTL with correct arguments
let ret = unsafe { ioctl_with_mut_ref(&tap_file, net_gen::TUNSETIFF(), &mut ifreq) };
if ret < 0 && IoError::last_os_error().raw_os_error().unwrap() != libc::EEXIST {
return Err(Error::ConfigureTap(IoError::last_os_error()));
@@ -208,14 +241,8 @@ impl Tap {
ifreq.ifr_ifru.ifru_addr = addr;
// ioctl is safe. Called with a valid sock fd, and we check the return.
let ret =
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFADDR as c_ulong, &ifreq) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
Ok(())
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFADDR as c_ulong, &ifreq) }
}
/// Set mac addr for tap interface.
@@ -233,13 +260,10 @@ impl Tap {
let mut ifreq = self.get_ifreq();
// ioctl is safe. Called with a valid sock fd, and we check the return.
let ret =
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
// We only access one field of the ifru union, hence this is safe.
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq)? };
// SAFETY: We only access one field of the ifru union
unsafe {
let ifru_hwaddr = &mut ifreq.ifr_ifru.ifru_hwaddr;
for (i, v) in addr.get_bytes().iter().enumerate() {
@@ -247,14 +271,8 @@ impl Tap {
}
}
// ioctl is safe. Called with a valid sock fd, and we check the return.
let ret =
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFHWADDR as c_ulong, &ifreq) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
Ok(())
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFHWADDR as c_ulong, &ifreq) }
}
/// Get mac addr for tap interface.
@@ -263,14 +281,10 @@ impl Tap {
let ifreq = self.get_ifreq();
// ioctl is safe. Called with a valid sock fd, and we check the return.
let ret =
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq)? };
// We only access one field of the ifru union, hence this is safe.
// SAFETY: We only access one field of the ifru union
let addr = unsafe {
MacAddr::from_bytes(&ifreq.ifr_ifru.ifru_hwaddr.sa_data[0..MAC_ADDR_LEN])
.map_err(Error::MacParsing)?
@@ -287,57 +301,45 @@ impl Tap {
ifreq.ifr_ifru.ifru_addr = addr;
// ioctl is safe. Called with a valid sock fd, and we check the return.
let ret =
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFNETMASK as c_ulong, &ifreq) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
Ok(())
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFNETMASK as c_ulong, &ifreq) }
}
#[cfg(not(fuzzing))]
pub fn mtu(&self) -> Result<i32> {
let sock = create_unix_socket().map_err(Error::NetUtil)?;
let ifreq = self.get_ifreq();
// ioctl is safe. Called with a valid sock fd, and we check the return.
let ret = unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFMTU as c_ulong, &ifreq) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFMTU as c_ulong, &ifreq)? };
// SAFETY: access a union field
let mtu = unsafe { ifreq.ifr_ifru.ifru_mtu };
Ok(mtu)
}
#[cfg(fuzzing)]
pub fn mtu(&self) -> Result<i32> {
// Consistent with the `virtio_devices::net::MIN_MTU`
Ok(1280)
}
pub fn set_mtu(&self, mtu: i32) -> Result<()> {
let sock = create_unix_socket().map_err(Error::NetUtil)?;
let mut ifreq = self.get_ifreq();
ifreq.ifr_ifru.ifru_mtu = mtu;
// ioctl is safe. Called with a valid sock fd, and we check the return.
let ret = unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFMTU as c_ulong, &ifreq) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
Ok(())
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFMTU as c_ulong, &ifreq) }
}
/// Set the offload flags for the tap interface.
pub fn set_offload(&self, flags: c_uint) -> Result<()> {
// ioctl is safe. Called with a valid tap fd, and we check the return.
let ret =
unsafe { ioctl_with_val(&self.tap_file, net_gen::TUNSETOFFLOAD(), flags as c_ulong) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
Ok(())
// SAFETY: ioctl is safe. Called with a valid tap fd, and we check the return.
unsafe { Self::ioctl_with_val(&self.tap_file, net_gen::TUNSETOFFLOAD(), flags as c_ulong) }
}
/// Enable the tap interface.
@@ -346,13 +348,11 @@ impl Tap {
let mut ifreq = self.get_ifreq();
let ret =
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFFLAGS as c_ulong, &ifreq) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
// SAFETY: IOCTL with correct arguments
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFFLAGS as c_ulong, &ifreq)? };
// If TAP device is already up don't try and enable it
// SAFETY: access a union field
let ifru_flags = unsafe { ifreq.ifr_ifru.ifru_flags };
if ifru_flags & net_gen::net_device_flags_IFF_UP as i16
== net_gen::net_device_flags_IFF_UP as i16
@@ -362,25 +362,14 @@ impl Tap {
ifreq.ifr_ifru.ifru_flags = net_gen::net_device_flags_IFF_UP as i16;
// ioctl is safe. Called with a valid sock fd, and we check the return.
let ret =
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFFLAGS as c_ulong, &ifreq) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
Ok(())
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFFLAGS as c_ulong, &ifreq) }
}
/// Set the size of the vnet hdr.
pub fn set_vnet_hdr_size(&self, size: c_int) -> Result<()> {
// ioctl is safe. Called with a valid tap fd, and we check the return.
let ret = unsafe { ioctl_with_ref(&self.tap_file, net_gen::TUNSETVNETHDRSZ(), &size) };
if ret < 0 {
return Err(Error::IoctlError(IoError::last_os_error()));
}
Ok(())
// SAFETY: ioctl is safe. Called with a valid tap fd, and we check the return.
unsafe { Self::ioctl_with_ref(&self.tap_file, net_gen::TUNSETVNETHDRSZ(), &size) }
}
fn get_ifreq(&self) -> net_gen::ifreq {
@@ -388,6 +377,7 @@ impl Tap {
// This sets the name of the interface, which is the only entry
// in a single-field union.
// SAFETY: access union fields and we're sure the copy is okay.
unsafe {
let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
let name_slice = &mut ifrn_name[..self.if_name.len()];
@@ -400,6 +390,11 @@ impl Tap {
pub fn get_if_name(&self) -> Vec<u8> {
self.if_name.clone()
}
#[cfg(fuzzing)]
pub fn new_for_fuzzing(tap_file: File, if_name: Vec<u8>) -> Self {
Tap { tap_file, if_name }
}
}
impl Read for Tap {
@@ -586,7 +581,7 @@ mod tests {
let _tap_ip_guard = TAP_IP_LOCK.lock().unwrap();
let t = Tap::new(1).unwrap();
println!("created tap: {:?}", t);
println!("created tap: {t:?}");
}
#[test]

View File

@@ -28,10 +28,10 @@ pub enum OptionParserError {
impl fmt::Display for OptionParserError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
OptionParserError::UnknownOption(s) => write!(f, "unknown option: {}", s),
OptionParserError::InvalidSyntax(s) => write!(f, "invalid syntax:{}", s),
OptionParserError::UnknownOption(s) => write!(f, "unknown option: {s}"),
OptionParserError::InvalidSyntax(s) => write!(f, "invalid syntax:{s}"),
OptionParserError::Conversion(field, value) => {
write!(f, "unable to convert {} for {}", value, field)
write!(f, "unable to convert {value} for {field}")
}
}
}

View File

@@ -10,23 +10,20 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"]
[dependencies]
anyhow = "1.0.66"
anyhow = "1.0.68"
byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" }
vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main", features = ["fam-wrappers"] }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
vfio_user = { path = "../vfio_user" }
vmm-sys-util = "0.10.0"
libc = "0.2.137"
vmm-sys-util = "0.11.0"
libc = "0.2.139"
log = "0.4.17"
serde = { version = "1.0.147", features = ["derive"] }
thiserror = "1.0.37"
versionize = "0.1.6"
serde = { version = "1.0.151", features = ["derive"] }
thiserror = "1.0.38"
versionize = "0.1.9"
versionize_derive = "0.1.4"
vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" }
vm-memory = "0.9.0"
vm-memory = "0.10.0"
vm-migration = { path = "../vm-migration" }
[dependencies.vfio-bindings]
version = "0.3.1"
features = ["fam-wrappers"]

View File

@@ -62,6 +62,7 @@ impl PciRoot {
0,
0,
None,
None,
),
}
}

View File

@@ -32,6 +32,8 @@ const CAPABILITY_MAX_OFFSET: usize = 192;
const INTERRUPT_LINE_PIN_REG: usize = 15;
pub const PCI_CONFIGURATION_ID: &str = "pci_configuration";
/// Represents the types of PCI headers allowed in the configuration registers.
#[derive(Copy, Clone)]
pub enum PciHeaderType {
@@ -394,7 +396,7 @@ fn decode_64_bits_bar_size(bar_size_hi: u32, bar_size_lo: u32) -> Option<u64> {
None
}
#[derive(Default, Clone, Copy, Versionize)]
#[derive(Debug, Default, Clone, Copy, Versionize)]
struct PciBar {
addr: u32,
size: u32,
@@ -403,7 +405,7 @@ struct PciBar {
}
#[derive(Versionize)]
struct PciConfigurationState {
pub struct PciConfigurationState {
registers: Vec<u32>,
writable_bits: Vec<u32>,
bars: Vec<PciBar>,
@@ -514,9 +516,9 @@ impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;
match self {
BarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s),
BarInUse(b) => write!(f, "bar {} already used", b),
BarInUse64(b) => write!(f, "64bit bar {} already used(requires two regs)", b),
BarAddressInvalid(a, s) => write!(f, "address {a} size {s} too big"),
BarInUse(b) => write!(f, "bar {b} already used"),
BarInUse64(b) => write!(f, "64bit bar {b} already used(requires two regs)"),
BarInvalid(b) => write!(f, "bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
BarInvalid64(b) => write!(
f,
@@ -524,18 +526,18 @@ impl Display for Error {
b,
NUM_BAR_REGS - 1
),
BarSizeInvalid(s) => write!(f, "bar address {} not a power of two", s),
BarSizeInvalid(s) => write!(f, "bar address {s} not a power of two"),
CapabilityEmpty => write!(f, "empty capabilities are invalid"),
CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {}", l),
CapabilitySpaceFull(s) => write!(f, "capability of size {} doesn't fit", s),
CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {l}"),
CapabilitySpaceFull(s) => write!(f, "capability of size {s} doesn't fit"),
Decode32BarSize => write!(f, "failed to decode 32 bits BAR size"),
Decode64BarSize => write!(f, "failed to decode 64 bits BAR size"),
Encode32BarSize => write!(f, "failed to encode 32 bits BAR size"),
Encode64BarSize => write!(f, "failed to encode 64 bits BAR size"),
RomBarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s),
RomBarInUse(b) => write!(f, "rom bar {} already used", b),
RomBarAddressInvalid(a, s) => write!(f, "address {a} size {s} too big"),
RomBarInUse(b) => write!(f, "rom bar {b} already used"),
RomBarInvalid(b) => write!(f, "rom bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
RomBarSizeInvalid(s) => write!(f, "rom bar address {} not a power of two", s),
RomBarSizeInvalid(s) => write!(f, "rom bar address {s} not a power of two"),
}
}
}
@@ -553,46 +555,78 @@ impl PciConfiguration {
subsystem_vendor_id: u16,
subsystem_id: u16,
msix_config: Option<Arc<Mutex<MsixConfig>>>,
state: Option<PciConfigurationState>,
) -> Self {
let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
// TODO(dverkamp): Status should be write-1-to-clear
writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
let pi = if let Some(pi) = programming_interface {
pi.get_register_value()
let (
registers,
writable_bits,
bars,
rom_bar_addr,
rom_bar_size,
rom_bar_used,
last_capability,
msix_cap_reg_idx,
) = if let Some(state) = state {
(
state.registers.try_into().unwrap(),
state.writable_bits.try_into().unwrap(),
state.bars.try_into().unwrap(),
state.rom_bar_addr,
state.rom_bar_size,
state.rom_bar_used,
state.last_capability,
state.msix_cap_reg_idx,
)
} else {
0
};
registers[2] = u32::from(class_code.get_register_value()) << 24
| u32::from(subclass.get_register_value()) << 16
| u32::from(pi) << 8
| u32::from(revision_id);
writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
match header_type {
PciHeaderType::Device => {
registers[3] = 0x0000_0000; // Header type 0 (device)
writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
}
PciHeaderType::Bridge => {
registers[3] = 0x0001_0000; // Header type 1 (bridge)
writable_bits[9] = 0xfff0_fff0; // Memory base and limit
writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
}
};
registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
// TODO(dverkamp): Status should be write-1-to-clear
writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
let pi = if let Some(pi) = programming_interface {
pi.get_register_value()
} else {
0
};
registers[2] = u32::from(class_code.get_register_value()) << 24
| u32::from(subclass.get_register_value()) << 16
| u32::from(pi) << 8
| u32::from(revision_id);
writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
match header_type {
PciHeaderType::Device => {
registers[3] = 0x0000_0000; // Header type 0 (device)
writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
}
PciHeaderType::Bridge => {
registers[3] = 0x0001_0000; // Header type 1 (bridge)
writable_bits[9] = 0xfff0_fff0; // Memory base and limit
writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
}
};
registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
let bars = [PciBar::default(); NUM_BAR_REGS];
(
registers,
writable_bits,
[PciBar::default(); NUM_BAR_REGS],
0,
0,
false,
None,
None,
)
};
PciConfiguration {
registers,
writable_bits,
bars,
rom_bar_addr: 0,
rom_bar_size: 0,
rom_bar_used: false,
last_capability: None,
msix_cap_reg_idx: None,
rom_bar_addr,
rom_bar_size,
rom_bar_used,
last_capability,
msix_cap_reg_idx,
msix_config,
}
}
@@ -610,18 +644,6 @@ impl PciConfiguration {
}
}
fn set_state(&mut self, state: &PciConfigurationState) {
self.registers.clone_from_slice(state.registers.as_slice());
self.writable_bits
.clone_from_slice(state.writable_bits.as_slice());
self.bars.clone_from_slice(state.bars.as_slice());
self.rom_bar_addr = state.rom_bar_addr;
self.rom_bar_size = state.rom_bar_size;
self.rom_bar_used = state.rom_bar_used;
self.last_capability = state.last_capability;
self.msix_cap_reg_idx = state.msix_cap_reg_idx;
}
/// Reads a 32bit register from `reg_idx` in the register map.
pub fn read_reg(&self, reg_idx: usize) -> u32 {
*(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff))
@@ -1046,16 +1068,11 @@ impl Pausable for PciConfiguration {}
impl Snapshottable for PciConfiguration {
fn id(&self) -> String {
String::from("pci_configuration")
String::from(PCI_CONFIGURATION_ID)
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_versioned_state(&self.id(), &self.state())
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
self.set_state(&snapshot.to_versioned_state(&self.id())?);
Ok(())
Snapshot::new_from_versioned_state(&self.state())
}
}
@@ -1178,6 +1195,7 @@ mod tests {
0xABCD,
0x2468,
None,
None,
);
// Add two capabilities with different contents.
@@ -1234,6 +1252,7 @@ mod tests {
0xABCD,
0x2468,
None,
None,
);
let class_reg = cfg.read_reg(2);

View File

@@ -31,15 +31,15 @@ impl Display for Error {
use self::Error::*;
match self {
CapabilitiesSetup(e) => write!(f, "failed to add capability {}", e),
CapabilitiesSetup(e) => write!(f, "failed to add capability {e}"),
IoAllocationFailed(size) => {
write!(f, "failed to allocate space for an IO BAR, size={}", size)
write!(f, "failed to allocate space for an IO BAR, size={size}")
}
IoRegistrationFailed(addr, e) => {
write!(f, "failed to register an IO BAR, addr={} err={}", addr, e)
write!(f, "failed to register an IO BAR, addr={addr} err={e}")
}
MissingResource => write!(f, "failed to find expected resource"),
InvalidResource(r) => write!(f, "invalid resource {:?}", r),
InvalidResource(r) => write!(f, "invalid resource {r:?}"),
}
}
}

View File

@@ -19,12 +19,13 @@ pub use self::configuration::{
PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, PciCapability, PciCapabilityId,
PciClassCode, PciConfiguration, PciExpressCapabilityId, PciHeaderType, PciMassStorageSubclass,
PciNetworkControllerSubclass, PciProgrammingInterface, PciSerialBusSubClass, PciSubclass,
PCI_CONFIGURATION_ID,
};
pub use self::device::{
BarReprogrammingParams, DeviceRelocation, Error as PciDeviceError, PciDevice,
};
pub use self::msi::{msi_num_enabled_vectors, MsiCap, MsiConfig};
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_TABLE_ENTRY_SIZE};
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_CONFIG_ID, MSIX_TABLE_ENTRY_SIZE};
pub use self::vfio::{VfioPciDevice, VfioPciError};
pub use self::vfio_user::{VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError};
use serde::de::Visitor;

View File

@@ -3,7 +3,6 @@
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
//
use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian};
use std::io;
use std::sync::Arc;
@@ -39,13 +38,15 @@ pub fn msi_num_enabled_vectors(msg_ctl: u16) -> usize {
}
#[derive(Error, Debug)]
enum Error {
pub enum Error {
#[error("Failed enabling the interrupt route: {0}")]
EnableInterruptRoute(io::Error),
#[error("Failed updating the interrupt route: {0}")]
UpdateInterruptRoute(io::Error),
}
pub const MSI_CONFIG_ID: &str = "msi_config";
#[derive(Clone, Copy, Default, Versionize)]
pub struct MsiCap {
// Message Control Register
@@ -172,7 +173,7 @@ impl MsiCap {
}
#[derive(Versionize)]
struct MsiConfigState {
pub struct MsiConfigState {
cap: MsiCap,
}
@@ -184,51 +185,53 @@ pub struct MsiConfig {
}
impl MsiConfig {
pub fn new(msg_ctl: u16, interrupt_source_group: Arc<dyn InterruptSourceGroup>) -> Self {
let cap = MsiCap {
msg_ctl,
..Default::default()
pub fn new(
msg_ctl: u16,
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
state: Option<MsiConfigState>,
) -> Result<Self, Error> {
let cap = if let Some(state) = state {
if state.cap.enabled() {
for idx in 0..state.cap.num_enabled_vectors() {
let config = MsiIrqSourceConfig {
high_addr: state.cap.msg_addr_hi,
low_addr: state.cap.msg_addr_lo,
data: state.cap.msg_data as u32,
devid: 0,
};
interrupt_source_group
.update(
idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
state.cap.vector_masked(idx),
)
.map_err(Error::UpdateInterruptRoute)?;
}
interrupt_source_group
.enable()
.map_err(Error::EnableInterruptRoute)?;
}
state.cap
} else {
MsiCap {
msg_ctl,
..Default::default()
}
};
MsiConfig {
Ok(MsiConfig {
cap,
interrupt_source_group,
}
})
}
fn state(&self) -> MsiConfigState {
MsiConfigState { cap: self.cap }
}
fn set_state(&mut self, state: &MsiConfigState) -> Result<(), Error> {
self.cap = state.cap;
if self.enabled() {
for idx in 0..self.num_enabled_vectors() {
let config = MsiIrqSourceConfig {
high_addr: self.cap.msg_addr_hi,
low_addr: self.cap.msg_addr_lo,
data: self.cap.msg_data as u32,
devid: 0,
};
self.interrupt_source_group
.update(
idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
self.cap.vector_masked(idx),
)
.map_err(Error::UpdateInterruptRoute)?;
}
self.interrupt_source_group
.enable()
.map_err(Error::EnableInterruptRoute)?;
}
Ok(())
}
pub fn enabled(&self) -> bool {
self.cap.enabled()
}
@@ -281,21 +284,10 @@ impl Pausable for MsiConfig {}
impl Snapshottable for MsiConfig {
fn id(&self) -> String {
String::from("msi_config")
String::from(MSI_CONFIG_ID)
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_versioned_state(&self.id(), &self.state())
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
self.set_state(&snapshot.to_versioned_state(&self.id())?)
.map_err(|e| {
MigratableError::Restore(anyhow!(
"Could not restore state for {}: {:?}",
self.id(),
e
))
})
Snapshot::new_from_versioned_state(&self.state())
}
}

View File

@@ -4,7 +4,6 @@
//
use crate::{PciCapability, PciCapabilityId};
use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian};
use std::io;
use std::result;
@@ -26,9 +25,10 @@ const MSIX_ENABLE_BIT: u8 = 15;
const FUNCTION_MASK_MASK: u16 = (1 << FUNCTION_MASK_BIT) as u16;
const MSIX_ENABLE_MASK: u16 = (1 << MSIX_ENABLE_BIT) as u16;
pub const MSIX_TABLE_ENTRY_SIZE: usize = 16;
pub const MSIX_CONFIG_ID: &str = "msix_config";
#[derive(Debug)]
enum Error {
pub enum Error {
/// Failed enabling the interrupt route.
EnableInterruptRoute(io::Error),
/// Failed updating the interrupt route.
@@ -61,7 +61,7 @@ impl Default for MsixTableEntry {
}
#[derive(Versionize)]
struct MsixConfigState {
pub struct MsixConfigState {
table_entries: Vec<MsixTableEntry>,
pba_entries: Vec<u64>,
masked: bool,
@@ -84,23 +84,62 @@ impl MsixConfig {
msix_vectors: u16,
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
devid: u32,
) -> Self {
state: Option<MsixConfigState>,
) -> result::Result<Self, Error> {
assert!(msix_vectors <= MAX_MSIX_VECTORS_PER_DEVICE);
let mut table_entries: Vec<MsixTableEntry> = Vec::new();
table_entries.resize_with(msix_vectors as usize, Default::default);
let mut pba_entries: Vec<u64> = Vec::new();
let num_pba_entries: usize = ((msix_vectors as usize) / BITS_PER_PBA_ENTRY) + 1;
pba_entries.resize_with(num_pba_entries, Default::default);
let (table_entries, pba_entries, masked, enabled) = if let Some(state) = state {
if state.enabled && !state.masked {
for (idx, table_entry) in state.table_entries.iter().enumerate() {
if table_entry.masked() {
continue;
}
MsixConfig {
let config = MsiIrqSourceConfig {
high_addr: table_entry.msg_addr_hi,
low_addr: table_entry.msg_addr_lo,
data: table_entry.msg_data,
devid,
};
interrupt_source_group
.update(
idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
state.masked,
)
.map_err(Error::UpdateInterruptRoute)?;
interrupt_source_group
.enable()
.map_err(Error::EnableInterruptRoute)?;
}
}
(
state.table_entries,
state.pba_entries,
state.masked,
state.enabled,
)
} else {
let mut table_entries: Vec<MsixTableEntry> = Vec::new();
table_entries.resize_with(msix_vectors as usize, Default::default);
let mut pba_entries: Vec<u64> = Vec::new();
let num_pba_entries: usize = ((msix_vectors as usize) / BITS_PER_PBA_ENTRY) + 1;
pba_entries.resize_with(num_pba_entries, Default::default);
(table_entries, pba_entries, true, false)
};
Ok(MsixConfig {
table_entries,
pba_entries,
devid,
interrupt_source_group,
masked: true,
enabled: false,
}
masked,
enabled,
})
}
fn state(&self) -> MsixConfigState {
@@ -112,42 +151,6 @@ impl MsixConfig {
}
}
fn set_state(&mut self, state: &MsixConfigState) -> result::Result<(), Error> {
self.table_entries = state.table_entries.clone();
self.pba_entries = state.pba_entries.clone();
self.masked = state.masked;
self.enabled = state.enabled;
if self.enabled && !self.masked {
for (idx, table_entry) in self.table_entries.iter().enumerate() {
if table_entry.masked() {
continue;
}
let config = MsiIrqSourceConfig {
high_addr: table_entry.msg_addr_hi,
low_addr: table_entry.msg_addr_lo,
data: table_entry.msg_data,
devid: self.devid,
};
self.interrupt_source_group
.update(
idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
self.masked,
)
.map_err(Error::UpdateInterruptRoute)?;
self.interrupt_source_group
.enable()
.map_err(Error::EnableInterruptRoute)?;
}
}
Ok(())
}
pub fn masked(&self) -> bool {
self.masked
}
@@ -426,22 +429,11 @@ impl Pausable for MsixConfig {}
impl Snapshottable for MsixConfig {
fn id(&self) -> String {
String::from("msix_config")
String::from(MSIX_CONFIG_ID)
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
Snapshot::new_from_versioned_state(&self.id(), &self.state())
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
self.set_state(&snapshot.to_versioned_state(&self.id())?)
.map_err(|e| {
MigratableError::Restore(anyhow!(
"Could not restore state for {}: {:?}",
self.id(),
e
))
})
Snapshot::new_from_versioned_state(&self.state())
}
}

View File

@@ -3,11 +3,13 @@
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
//
use crate::msi::{MsiConfigState, MSI_CONFIG_ID};
use crate::msix::MsixConfigState;
use crate::{
msi_num_enabled_vectors, BarReprogrammingParams, MsiCap, MsiConfig, MsixCap, MsixConfig,
PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, PciBdf, PciCapabilityId,
PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciExpressCapabilityId,
PciHeaderType, PciSubclass, MSIX_TABLE_ENTRY_SIZE,
PciHeaderType, PciSubclass, MSIX_CONFIG_ID, MSIX_TABLE_ENTRY_SIZE, PCI_CONFIGURATION_ID,
};
use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian};
@@ -36,6 +38,8 @@ use vm_migration::{
};
use vmm_sys_util::eventfd::EventFd;
pub(crate) const VFIO_COMMON_ID: &str = "vfio_common";
#[derive(Debug, Error)]
pub enum VfioPciError {
#[error("Failed to create user memory region: {0}")]
@@ -58,6 +62,14 @@ pub enum VfioPciError {
RegionAlignment,
#[error("Invalid region size")]
RegionSize,
#[error("Failed to retrieve MsiConfigState: {0}")]
RetrieveMsiConfigState(#[source] anyhow::Error),
#[error("Failed to retrieve MsixConfigState: {0}")]
RetrieveMsixConfigState(#[source] anyhow::Error),
#[error("Failed to retrieve PciConfigurationState: {0}")]
RetrievePciConfigurationState(#[source] anyhow::Error),
#[error("Failed to retrieve VfioCommonState: {0}")]
RetrieveVfioCommonState(#[source] anyhow::Error),
}
#[derive(Copy, Clone)]
@@ -406,6 +418,86 @@ pub(crate) struct VfioCommon {
}
impl VfioCommon {
pub(crate) fn new(
msi_interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
vfio_wrapper: Arc<dyn Vfio>,
subclass: &dyn PciSubclass,
bdf: PciBdf,
snapshot: Option<Snapshot>,
) -> Result<Self, VfioPciError> {
let pci_configuration_state =
vm_migration::versioned_state_from_id(snapshot.as_ref(), PCI_CONFIGURATION_ID)
.map_err(|e| {
VfioPciError::RetrievePciConfigurationState(anyhow!(
"Failed to get PciConfigurationState from Snapshot: {}",
e
))
})?;
let configuration = PciConfiguration::new(
0,
0,
0,
PciClassCode::Other,
subclass,
None,
PciHeaderType::Device,
0,
0,
None,
pci_configuration_state,
);
let mut vfio_common = VfioCommon {
mmio_regions: Vec::new(),
configuration,
interrupt: Interrupt {
intx: None,
msi: None,
msix: None,
},
msi_interrupt_manager,
legacy_interrupt_group,
vfio_wrapper,
patches: HashMap::new(),
};
let state: Option<VfioCommonState> = snapshot
.as_ref()
.map(|s| s.to_versioned_state())
.transpose()
.map_err(|e| {
VfioPciError::RetrieveVfioCommonState(anyhow!(
"Failed to get VfioCommonState from Snapshot: {}",
e
))
})?;
let msi_state = vm_migration::versioned_state_from_id(snapshot.as_ref(), MSI_CONFIG_ID)
.map_err(|e| {
VfioPciError::RetrieveMsiConfigState(anyhow!(
"Failed to get MsiConfigState from Snapshot: {}",
e
))
})?;
let msix_state = vm_migration::versioned_state_from_id(snapshot.as_ref(), MSIX_CONFIG_ID)
.map_err(|e| {
VfioPciError::RetrieveMsixConfigState(anyhow!(
"Failed to get MsixConfigState from Snapshot: {}",
e
))
})?;
if let Some(state) = state.as_ref() {
vfio_common.set_state(state, msi_state, msix_state)?;
} else {
vfio_common.parse_capabilities(bdf);
vfio_common.initialize_legacy_interrupt()?;
}
Ok(vfio_common)
}
pub(crate) fn allocate_bars(
&mut self,
allocator: &Arc<Mutex<SystemAllocator>>,
@@ -650,7 +742,13 @@ impl VfioCommon {
}
}
pub(crate) fn initialize_msix(&mut self, msix_cap: MsixCap, cap_offset: u32, bdf: PciBdf) {
pub(crate) fn initialize_msix(
&mut self,
msix_cap: MsixCap,
cap_offset: u32,
bdf: PciBdf,
state: Option<MsixConfigState>,
) {
let interrupt_source_group = self
.msi_interrupt_manager
.create_group(MsiIrqGroupConfig {
@@ -663,7 +761,9 @@ impl VfioCommon {
msix_cap.table_size(),
interrupt_source_group.clone(),
bdf.into(),
);
state,
)
.unwrap();
self.interrupt.msix = Some(VfioMsix {
bar: msix_config,
@@ -677,7 +777,12 @@ impl VfioCommon {
self.vfio_wrapper.read_config_word((cap + 2).into())
}
pub(crate) fn initialize_msi(&mut self, msg_ctl: u16, cap_offset: u32) {
pub(crate) fn initialize_msi(
&mut self,
msg_ctl: u16,
cap_offset: u32,
state: Option<MsiConfigState>,
) {
let interrupt_source_group = self
.msi_interrupt_manager
.create_group(MsiIrqGroupConfig {
@@ -686,7 +791,7 @@ impl VfioCommon {
})
.unwrap();
let msi_config = MsiConfig::new(msg_ctl, interrupt_source_group.clone());
let msi_config = MsiConfig::new(msg_ctl, interrupt_source_group.clone(), state).unwrap();
self.interrupt.msi = Some(VfioMsi {
cfg: msi_config,
@@ -713,7 +818,7 @@ impl VfioCommon {
// Parse capability only if the VFIO device
// supports MSI.
let msg_ctl = self.parse_msi_capabilities(cap_next);
self.initialize_msi(msg_ctl, cap_next as u32);
self.initialize_msi(msg_ctl, cap_next as u32, None);
}
}
}
@@ -724,7 +829,7 @@ impl VfioCommon {
// Parse capability only if the VFIO device
// supports MSI-X.
let msix_cap = self.parse_msix_capabilities(cap_next);
self.initialize_msix(msix_cap, cap_next as u32, bdf);
self.initialize_msix(msix_cap, cap_next as u32, bdf, None);
}
}
}
@@ -1091,7 +1196,12 @@ impl VfioCommon {
}
}
fn set_state(&mut self, state: &VfioCommonState) -> Result<(), VfioPciError> {
fn set_state(
&mut self,
state: &VfioCommonState,
msi_state: Option<MsiConfigState>,
msix_state: Option<MsixConfigState>,
) -> Result<(), VfioPciError> {
if let (Some(intx), Some(interrupt_source_group)) =
(&state.intx_state, self.legacy_interrupt_group.clone())
{
@@ -1106,11 +1216,11 @@ impl VfioCommon {
}
if let Some(msi) = &state.msi_state {
self.initialize_msi(msi.cap.msg_ctl, msi.cap_offset);
self.initialize_msi(msi.cap.msg_ctl, msi.cap_offset, msi_state);
}
if let Some(msix) = &state.msix_state {
self.initialize_msix(msix.cap, msix.cap_offset, msix.bdf.into());
self.initialize_msix(msix.cap, msix.cap_offset, msix.bdf.into(), msix_state);
}
Ok(())
@@ -1121,73 +1231,27 @@ impl Pausable for VfioCommon {}
impl Snapshottable for VfioCommon {
fn id(&self) -> String {
String::from("vfio_common")
String::from(VFIO_COMMON_ID)
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let mut vfio_common_snapshot =
Snapshot::new_from_versioned_state(&self.id(), &self.state())?;
let mut vfio_common_snapshot = Snapshot::new_from_versioned_state(&self.state())?;
// Snapshot PciConfiguration
vfio_common_snapshot.add_snapshot(self.configuration.snapshot()?);
vfio_common_snapshot.add_snapshot(self.configuration.id(), self.configuration.snapshot()?);
// Snapshot MSI
if let Some(msi) = &mut self.interrupt.msi {
vfio_common_snapshot.add_snapshot(msi.cfg.snapshot()?);
vfio_common_snapshot.add_snapshot(msi.cfg.id(), msi.cfg.snapshot()?);
}
// Snapshot MSI-X
if let Some(msix) = &mut self.interrupt.msix {
vfio_common_snapshot.add_snapshot(msix.bar.snapshot()?);
vfio_common_snapshot.add_snapshot(msix.bar.id(), 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.
@@ -1218,48 +1282,22 @@ impl VfioPciDevice {
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
iommu_attached: bool,
bdf: PciBdf,
restoring: bool,
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
snapshot: Option<Snapshot>,
) -> Result<Self, VfioPciError> {
let device = Arc::new(device);
device.reset();
let configuration = PciConfiguration::new(
0,
0,
0,
PciClassCode::Other,
&PciVfioSubclass::VfioSubclass,
None,
PciHeaderType::Device,
0,
0,
None,
);
let vfio_wrapper = VfioDeviceWrapper::new(Arc::clone(&device));
let mut common = VfioCommon {
mmio_regions: Vec::new(),
configuration,
interrupt: Interrupt {
intx: None,
msi: None,
msix: None,
},
let common = VfioCommon::new(
msi_interrupt_manager,
legacy_interrupt_group,
vfio_wrapper: Arc::new(vfio_wrapper) as Arc<dyn Vfio>,
patches: HashMap::new(),
};
// No need to parse capabilities from the device if on the restore path.
// The initialization will be performed later when restore() will be
// called.
if !restoring {
common.parse_capabilities(bdf);
common.initialize_legacy_interrupt()?;
}
Arc::new(vfio_wrapper) as Arc<dyn Vfio>,
&PciVfioSubclass::VfioSubclass,
bdf,
vm_migration::snapshot_from_id(snapshot.as_ref(), VFIO_COMMON_ID),
)?;
let vfio_pci_device = VfioPciDevice {
id,
@@ -1422,6 +1460,7 @@ impl VfioPciDevice {
)?;
for area in sparse_areas.iter() {
// SAFETY: FFI call with correct arguments
let host_addr = unsafe {
libc::mmap(
null_mut(),
@@ -1488,6 +1527,7 @@ impl VfioPciDevice {
error!("Could not remove the userspace memory region: {}", e);
}
// SAFETY: FFI call with correct arguments
let ret = unsafe {
libc::munmap(
user_memory_region.host_addr as *mut libc::c_void,
@@ -1699,28 +1739,13 @@ impl Snapshottable for VfioPciDevice {
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let mut vfio_pci_dev_snapshot = Snapshot::new(&self.id);
let mut vfio_pci_dev_snapshot = Snapshot::default();
// Snapshot VfioCommon
vfio_pci_dev_snapshot.add_snapshot(self.common.snapshot()?);
vfio_pci_dev_snapshot.add_snapshot(self.common.id(), 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

@@ -3,15 +3,11 @@
// SPDX-License-Identifier: Apache-2.0
//
use crate::vfio::{Interrupt, UserMemoryRegion, Vfio, VfioCommon, VfioError};
use crate::vfio::{UserMemoryRegion, Vfio, VfioCommon, VfioError, VFIO_COMMON_ID};
use crate::{BarReprogrammingParams, PciBarConfiguration, VfioPciError};
use crate::{
PciBdf, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
};
use anyhow::anyhow;
use crate::{PciBdf, PciDevice, PciDeviceError, PciSubclass};
use hypervisor::HypervisorVmError;
use std::any::Any;
use std::collections::HashMap;
use std::os::unix::prelude::AsRawFd;
use std::ptr::null_mut;
use std::sync::{Arc, Barrier, Mutex};
@@ -51,6 +47,8 @@ pub enum VfioUserPciDeviceError {
DmaUnmap(#[source] VfioUserError),
#[error("Failed to initialize legacy interrupts: {0}")]
InitializeLegacyInterrupts(#[source] VfioPciError),
#[error("Failed to create VfioCommon: {0}")]
CreateVfioCommon(#[source] VfioPciError),
}
#[derive(Copy, Clone)]
@@ -73,22 +71,9 @@ impl VfioUserPciDevice {
msi_interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
bdf: PciBdf,
restoring: bool,
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
snapshot: Option<Snapshot>,
) -> Result<Self, VfioUserPciDeviceError> {
// This is used for the BAR and capabilities only
let configuration = PciConfiguration::new(
0,
0,
0,
PciClassCode::Other,
&PciVfioUserSubclass::VfioUserSubclass,
None,
PciHeaderType::Device,
0,
0,
None,
);
let resettable = client.lock().unwrap().resettable();
if resettable {
client
@@ -102,29 +87,15 @@ impl VfioUserPciDevice {
client: client.clone(),
};
let mut common = VfioCommon {
mmio_regions: Vec::new(),
configuration,
interrupt: Interrupt {
intx: None,
msi: None,
msix: None,
},
let common = VfioCommon::new(
msi_interrupt_manager,
legacy_interrupt_group,
vfio_wrapper: Arc::new(vfio_wrapper) as Arc<dyn Vfio>,
patches: HashMap::new(),
};
// No need to parse capabilities from the device if on the restore path.
// The initialization will be performed later when restore() will be
// called.
if !restoring {
common.parse_capabilities(bdf);
common
.initialize_legacy_interrupt()
.map_err(VfioUserPciDeviceError::InitializeLegacyInterrupts)?;
}
Arc::new(vfio_wrapper) as Arc<dyn Vfio>,
&PciVfioUserSubclass::VfioUserSubclass,
bdf,
vm_migration::snapshot_from_id(snapshot.as_ref(), VFIO_COMMON_ID),
)
.map_err(VfioUserPciDeviceError::CreateVfioCommon)?;
Ok(Self {
id,
@@ -181,6 +152,7 @@ impl VfioUserPciDevice {
};
for s in mmaps.iter() {
// SAFETY: FFI call with correct arguments
let host_addr = unsafe {
libc::mmap(
null_mut(),
@@ -247,6 +219,7 @@ impl VfioUserPciDevice {
}
// Remove mmaps
// SAFETY: FFI call with correct arguments
let ret = unsafe {
libc::munmap(
user_memory_region.host_addr as *mut libc::c_void,
@@ -562,28 +535,13 @@ impl Snapshottable for VfioUserPciDevice {
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let mut vfio_pci_dev_snapshot = Snapshot::new(&self.id);
let mut vfio_pci_dev_snapshot = Snapshot::default();
// Snapshot VfioCommon
vfio_pci_dev_snapshot.add_snapshot(self.common.snapshot()?);
vfio_pci_dev_snapshot.add_snapshot(self.common.id(), 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 {}
@@ -617,13 +575,13 @@ impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioUserDmaMappi
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Error mapping region: {}", e),
format!("Error mapping region: {e}"),
)
})
} else {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Region not found for 0x{:x}", gpa),
format!("Region not found for 0x{gpa:x}"),
))
}
}
@@ -636,7 +594,7 @@ impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioUserDmaMappi
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Error unmapping region: {}", e),
format!("Error unmapping region: {e}"),
)
})
}

View File

@@ -6,13 +6,10 @@ edition = "2021"
build = "build.rs"
[dependencies]
clap = { version = "4.0.18", features = ["wrap_help","cargo"] }
clap = { version = "4.0.32", features = ["wrap_help"] }
dirs = "4.0.0"
serde = { version = "1.0.147", features = ["rc", "derive"] }
serde_json = "1.0.87"
serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.89"
test_infra = { path = "../test_infra" }
thiserror = "1.0.37"
thiserror = "1.0.38"
wait-timeout = "0.2.0"
[build-dependencies]
clap = { version = "4.0.18", features = ["cargo"] }

View File

@@ -3,13 +3,11 @@
// SPDX-License-Identifier: Apache-2.0
//
#[macro_use(crate_version)]
extern crate clap;
use std::process::Command;
fn main() {
let mut git_human_readable = "v".to_owned() + crate_version!();
let mut git_human_readable = "v".to_owned() + env!("CARGO_PKG_VERSION");
if let Ok(git_out) = Command::new("git").args(["describe", "--dirty"]).output() {
if git_out.status.success() {
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
@@ -22,5 +20,5 @@ fn main() {
// variable GIT_HUMAN_READABLE, so that it can be reused from the binary.
// Particularly, this is used from the main.rs to display the exact
// version information.
println!("cargo:rustc-env=GIT_HUMAN_READABLE={}", git_human_readable);
println!("cargo:rustc-env=GIT_HUMAN_READABLE={git_human_readable}");
}

View File

@@ -5,8 +5,6 @@
// Custom harness to run performance tests
extern crate test_infra;
#[macro_use(crate_authors)]
extern crate clap;
mod performance_tests;
@@ -117,7 +115,7 @@ pub struct PerformanceTestOverrides {
impl fmt::Display for PerformanceTestOverrides {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(test_iterations) = self.test_iterations {
write!(f, "test_iterations = {}", test_iterations)?;
write!(f, "test_iterations = {test_iterations}")?;
}
Ok(())
@@ -129,8 +127,8 @@ pub struct PerformanceTestControl {
test_iterations: u32,
num_queues: Option<u32>,
queue_size: Option<u32>,
net_rx: Option<bool>,
fio_ops: Option<FioOps>,
net_control: Option<(bool, bool)>, // First bool is for RX(true)/TX(false), second bool is for bandwidth or PPS
fio_control: Option<(FioOps, bool)>, // Second parameter controls whether we want bandwidth or IOPS
num_boot_vcpus: Option<u8>,
}
@@ -141,19 +139,21 @@ impl fmt::Display for PerformanceTestControl {
self.test_timeout, self.test_iterations
);
if let Some(o) = self.num_queues {
output = format!("{}, num_queues = {}", output, o);
output = format!("{output}, num_queues = {o}");
}
if let Some(o) = self.queue_size {
output = format!("{}, queue_size = {}", output, o);
output = format!("{output}, queue_size = {o}");
}
if let Some(o) = self.net_rx {
output = format!("{}, net_rx = {}", output, o);
if let Some(o) = self.net_control {
let (rx, bw) = o;
output = format!("{output}, rx = {rx}, bandwidth = {bw}");
}
if let Some(o) = &self.fio_ops {
output = format!("{}, fio_ops = {}", output, o);
if let Some(o) = &self.fio_control {
let (ops, bw) = o;
output = format!("{output}, fio_ops = {ops}, bandwidth = {bw}");
}
write!(f, "{}", output)
write!(f, "{output}")
}
}
@@ -164,8 +164,8 @@ impl PerformanceTestControl {
test_iterations: 5,
num_queues: None,
queue_size: None,
net_rx: None,
fio_ops: None,
net_control: None,
fio_control: None,
num_boot_vcpus: Some(1),
}
}
@@ -262,7 +262,7 @@ mod adjuster {
}
}
const TEST_LIST: [PerformanceTest; 17] = [
const TEST_LIST: [PerformanceTest; 29] = [
PerformanceTest {
name: "boot_time_ms",
func_ptr: performance_boot_time,
@@ -321,7 +321,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(256),
net_rx: Some(true),
net_control: Some((true, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::bps_to_gbps,
@@ -332,7 +332,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(256),
net_rx: Some(false),
net_control: Some((false, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::bps_to_gbps,
@@ -343,7 +343,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(4),
queue_size: Some(256),
net_rx: Some(true),
net_control: Some((true, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::bps_to_gbps,
@@ -354,18 +354,62 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(4),
queue_size: Some(256),
net_rx: Some(false),
net_control: Some((false, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::bps_to_gbps,
},
PerformanceTest {
name: "virtio_net_throughput_single_queue_rx_pps",
func_ptr: performance_net_throughput,
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(256),
net_control: Some((true, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "virtio_net_throughput_single_queue_tx_pps",
func_ptr: performance_net_throughput,
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(256),
net_control: Some((false, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "virtio_net_throughput_multi_queue_rx_pps",
func_ptr: performance_net_throughput,
control: PerformanceTestControl {
num_queues: Some(4),
queue_size: Some(256),
net_control: Some((true, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "virtio_net_throughput_multi_queue_tx_pps",
func_ptr: performance_net_throughput,
control: PerformanceTestControl {
num_queues: Some(4),
queue_size: Some(256),
net_control: Some((false, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_read_MiBps",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_ops: Some(FioOps::Read),
fio_control: Some((FioOps::Read, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -376,7 +420,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_ops: Some(FioOps::Write),
fio_control: Some((FioOps::Write, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -387,7 +431,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_ops: Some(FioOps::RandomRead),
fio_control: Some((FioOps::RandomRead, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -398,7 +442,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_ops: Some(FioOps::RandomWrite),
fio_control: Some((FioOps::RandomWrite, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -409,7 +453,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_ops: Some(FioOps::Read),
fio_control: Some((FioOps::Read, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -420,7 +464,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_ops: Some(FioOps::Write),
fio_control: Some((FioOps::Write, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -431,7 +475,7 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_ops: Some(FioOps::RandomRead),
fio_control: Some((FioOps::RandomRead, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
@@ -442,11 +486,99 @@ const TEST_LIST: [PerformanceTest; 17] = [
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_ops: Some(FioOps::RandomWrite),
fio_control: Some((FioOps::RandomWrite, true)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
},
PerformanceTest {
name: "block_read_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_control: Some((FioOps::Read, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_write_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_control: Some((FioOps::Write, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_random_read_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_control: Some((FioOps::RandomRead, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_random_write_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
queue_size: Some(128),
fio_control: Some((FioOps::RandomWrite, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_multi_queue_read_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_control: Some((FioOps::Read, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_multi_queue_write_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_control: Some((FioOps::Write, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_multi_queue_random_read_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_control: Some((FioOps::RandomRead, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "block_multi_queue_random_write_IOPS",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(2),
queue_size: Some(128),
fio_control: Some((FioOps::RandomWrite, false)),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
];
fn run_test_with_timeout(
@@ -497,7 +629,7 @@ fn date() -> String {
fn main() {
let cmd_arguments = ClapCommand::new("performance-metrics")
.version(env!("GIT_HUMAN_READABLE"))
.author(crate_authors!())
.author(env!("CARGO_PKG_AUTHORS"))
.about("Generate the performance metrics data for Cloud Hypervisor")
.arg(
Arg::new("test-filter")
@@ -569,7 +701,7 @@ fn main() {
metrics_report.results.push(r);
}
Err(e) => {
eprintln!("Aborting test due to error: '{:?}'", e);
eprintln!("Aborting test due to error: '{e:?}'");
std::process::exit(1);
}
};
@@ -583,7 +715,7 @@ fn main() {
Box::new(
std::fs::File::create(std::path::Path::new(file))
.map_err(|e| {
eprintln!("Error opening report file: {}: {}", file, e);
eprintln!("Error opening report file: {file}: {e}");
std::process::exit(1);
})
.unwrap(),
@@ -599,7 +731,7 @@ fn main() {
.as_bytes(),
)
.map_err(|e| {
eprintln!("Error writing report file: {}", e);
eprintln!("Error writing report file: {e}");
std::process::exit(1);
})
.unwrap();

View File

@@ -37,8 +37,7 @@ pub fn init_tests() {
// The test image can not be created on tmpfs (e.g. /tmp) filesystem,
// as tmpfs does not support O_DIRECT
assert!(exec_host_command_output(&format!(
"dd if=/dev/zero of={} bs=1M count=4096",
BLK_IO_TEST_IMG
"dd if=/dev/zero of={BLK_IO_TEST_IMG} bs=1M count=4096"
))
.status
.success());
@@ -46,7 +45,7 @@ pub fn init_tests() {
pub fn cleanup_tests() {
fs::remove_file(BLK_IO_TEST_IMG)
.unwrap_or_else(|_| panic!("Failed to remove file '{}'.", BLK_IO_TEST_IMG));
.unwrap_or_else(|_| panic!("Failed to remove file '{BLK_IO_TEST_IMG}'."));
}
// Performance tests are expected to be executed sequentially, so we can
@@ -79,7 +78,7 @@ fn direct_kernel_boot_path() -> PathBuf {
pub fn performance_net_throughput(control: &PerformanceTestControl) -> f64 {
let test_timeout = control.test_timeout;
let rx = control.net_rx.unwrap();
let (rx, bandwidth) = control.net_control.unwrap();
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = performance_test_new_guest(Box::new(focal));
@@ -92,7 +91,7 @@ pub fn performance_net_throughput(control: &PerformanceTestControl) -> f64 {
);
let mut child = GuestCommand::new(&guest)
.args(["--cpus", &format!("boot={}", num_queues)])
.args(["--cpus", &format!("boot={num_queues}")])
.args(["--memory", "size=4G"])
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
@@ -106,7 +105,7 @@ pub fn performance_net_throughput(control: &PerformanceTestControl) -> f64 {
let r = std::panic::catch_unwind(|| {
guest.wait_vm_boot(None).unwrap();
measure_virtio_net_throughput(test_timeout, num_queues / 2, &guest, rx).unwrap()
measure_virtio_net_throughput(test_timeout, num_queues / 2, &guest, rx, bandwidth).unwrap()
});
let _ = child.kill();
@@ -133,7 +132,7 @@ pub fn performance_net_latency(control: &PerformanceTestControl) -> f64 {
);
let mut child = GuestCommand::new(&guest)
.args(["--cpus", &format!("boot={}", num_queues)])
.args(["--cpus", &format!("boot={num_queues}")])
.args(["--memory", "size=4G"])
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
@@ -336,7 +335,7 @@ pub fn performance_boot_time_pmem(control: &PerformanceTestControl) -> f64 {
pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
let test_timeout = control.test_timeout;
let num_queues = control.num_queues.unwrap();
let fio_ops = control.fio_ops.as_ref().unwrap();
let (fio_ops, bandwidth) = control.fio_control.as_ref().unwrap();
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = performance_test_new_guest(Box::new(focal));
@@ -349,7 +348,7 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
.to_string();
let mut child = GuestCommand::new(&guest)
.args(["--cpus", &format!("boot={}", num_queues)])
.args(["--cpus", &format!("boot={num_queues}")])
.args(["--memory", "size=4G"])
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
@@ -365,7 +364,7 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
guest.disk_config.disk(DiskType::CloudInit).unwrap()
)
.as_str(),
format!("path={}", BLK_IO_TEST_IMG).as_str(),
format!("path={BLK_IO_TEST_IMG}").as_str(),
])
.default_net()
.args(["--api-socket", &api_socket])
@@ -381,8 +380,7 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
let fio_command = format!(
"sudo fio --filename=/dev/vdc --name=test --output-format=json \
--direct=1 --bs=4k --ioengine=io_uring --iodepth=64 \
--rw={} --runtime={} --numjobs={}",
fio_ops, test_timeout, num_queues
--rw={fio_ops} --runtime={test_timeout} --numjobs={num_queues}"
);
let output = guest
.ssh_command(&fio_command)
@@ -390,7 +388,11 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
.unwrap();
// Parse fio output
parse_fio_output(&output, fio_ops, num_queues).unwrap()
if *bandwidth {
parse_fio_output(&output, fio_ops, num_queues).unwrap()
} else {
parse_fio_output_iops(&output, fio_ops, num_queues).unwrap()
}
});
let _ = child.kill();
@@ -427,7 +429,7 @@ mod tests {
}
"#;
assert_eq!(
parse_iperf3_output(output.as_bytes(), true).unwrap(),
parse_iperf3_output(output.as_bytes(), true, true).unwrap(),
23957198874.604115
);
@@ -446,9 +448,31 @@ mod tests {
}
"#;
assert_eq!(
parse_iperf3_output(output.as_bytes(), false).unwrap(),
parse_iperf3_output(output.as_bytes(), false, true).unwrap(),
39520744482.79
);
let output = r#"
{
"end": {
"sum": {
"start": 0,
"end": 5.000036,
"seconds": 5.000036,
"bytes": 29944971264,
"bits_per_second": 47911877363.396217,
"jitter_ms": 0.0038609822983198556,
"lost_packets": 16,
"packets": 913848,
"lost_percent": 0.0017508382137948542,
"sender": true
}
}
}
"#;
assert_eq!(
parse_iperf3_output(output.as_bytes(), true, false).unwrap(),
182765.08409139456
);
}
#[test]

View File

@@ -10,7 +10,7 @@ path = "src/qcow.rs"
[dependencies]
byteorder = "1.4.3"
libc = "0.2.137"
libc = "0.2.139"
log = "0.4.17"
remain = "0.2.5"
vmm-sys-util = "0.10.0"
remain = "0.2.6"
vmm-sys-util = "0.11.0"

View File

@@ -80,45 +80,41 @@ impl Display for Error {
match self {
BackingFilesNotSupported => write!(f, "backing files not supported"),
CompressedBlocksNotSupported => write!(f, "compressed blocks not supported"),
EvictingCache(e) => write!(f, "failed to evict cache: {}", e),
FileTooBig(size) => write!(
f,
"file larger than max of {}: {}",
MAX_QCOW_FILE_SIZE, size
),
GettingFileSize(e) => write!(f, "failed to get file size: {}", e),
GettingRefcount(e) => write!(f, "failed to get refcount: {}", e),
EvictingCache(e) => write!(f, "failed to evict cache: {e}"),
FileTooBig(size) => write!(f, "file larger than max of {MAX_QCOW_FILE_SIZE}: {size}"),
GettingFileSize(e) => write!(f, "failed to get file size: {e}"),
GettingRefcount(e) => write!(f, "failed to get refcount: {e}"),
InvalidClusterIndex => write!(f, "invalid cluster index"),
InvalidClusterSize => write!(f, "invalid cluster size"),
InvalidIndex => write!(f, "invalid index"),
InvalidL1TableOffset => write!(f, "invalid L1 table offset"),
InvalidL1TableSize(size) => write!(f, "invalid L1 table size {}", size),
InvalidL1TableSize(size) => write!(f, "invalid L1 table size {size}"),
InvalidMagic => write!(f, "invalid magic"),
InvalidOffset(_) => write!(f, "invalid offset"),
InvalidRefcountTableOffset => write!(f, "invalid refcount table offset"),
InvalidRefcountTableSize(size) => write!(f, "invalid refcount table size: {}", size),
InvalidRefcountTableSize(size) => write!(f, "invalid refcount table size: {size}"),
NoFreeClusters => write!(f, "no free clusters"),
NoRefcountClusters => write!(f, "no refcount clusters"),
NotEnoughSpaceForRefcounts => write!(f, "not enough space for refcounts"),
OpeningFile(e) => write!(f, "failed to open file: {}", e),
ReadingData(e) => write!(f, "failed to read data: {}", e),
ReadingHeader(e) => write!(f, "failed to read header: {}", e),
ReadingPointers(e) => write!(f, "failed to read pointers: {}", e),
ReadingRefCountBlock(e) => write!(f, "failed to read ref count block: {}", e),
ReadingRefCounts(e) => write!(f, "failed to read ref counts: {}", e),
RebuildingRefCounts(e) => write!(f, "failed to rebuild ref counts: {}", e),
OpeningFile(e) => write!(f, "failed to open file: {e}"),
ReadingData(e) => write!(f, "failed to read data: {e}"),
ReadingHeader(e) => write!(f, "failed to read header: {e}"),
ReadingPointers(e) => write!(f, "failed to read pointers: {e}"),
ReadingRefCountBlock(e) => write!(f, "failed to read ref count block: {e}"),
ReadingRefCounts(e) => write!(f, "failed to read ref counts: {e}"),
RebuildingRefCounts(e) => write!(f, "failed to rebuild ref counts: {e}"),
RefcountTableOffEnd => write!(f, "refcount table offset past file end"),
RefcountTableTooLarge => write!(f, "too many clusters specified for refcount table"),
SeekingFile(e) => write!(f, "failed to seek file: {}", e),
SettingFileSize(e) => write!(f, "failed to set file size: {}", e),
SettingRefcountRefcount(e) => write!(f, "failed to set refcount refcount: {}", e),
SeekingFile(e) => write!(f, "failed to seek file: {e}"),
SettingFileSize(e) => write!(f, "failed to set file size: {e}"),
SettingRefcountRefcount(e) => write!(f, "failed to set refcount refcount: {e}"),
SizeTooSmallForNumberOfClusters => write!(f, "size too small for number of clusters"),
TooManyL1Entries(count) => write!(f, "l1 entry table too large: {}", count),
TooManyRefcounts(count) => write!(f, "ref count table too large: {}", count),
TooManyL1Entries(count) => write!(f, "l1 entry table too large: {count}"),
TooManyRefcounts(count) => write!(f, "ref count table too large: {count}"),
UnsupportedRefcountOrder => write!(f, "unsupported refcount order"),
UnsupportedVersion(v) => write!(f, "unsupported version: {}", v),
WritingData(e) => write!(f, "failed to write data: {}", e),
WritingHeader(e) => write!(f, "failed to write header: {}", e),
UnsupportedVersion(v) => write!(f, "unsupported version: {v}"),
WritingData(e) => write!(f, "failed to write data: {e}"),
WritingHeader(e) => write!(f, "failed to write header: {e}"),
}
}
}
@@ -190,7 +186,7 @@ pub struct QcowHeader {
impl QcowHeader {
/// Creates a QcowHeader from a reference to a file.
pub fn new(f: &mut RawFile) -> Result<QcowHeader> {
f.seek(SeekFrom::Start(0)).map_err(Error::ReadingHeader)?;
f.rewind().map_err(Error::ReadingHeader)?;
let magic = f.read_u32::<BigEndian>().map_err(Error::ReadingHeader)?;
if magic != QCOW_MAGIC {
return Err(Error::InvalidMagic);
@@ -559,7 +555,7 @@ impl QcowFile {
/// Creates a new QcowFile at the given path.
pub fn new(mut file: RawFile, version: u32, virtual_size: u64) -> Result<QcowFile> {
let header = QcowHeader::create_for_size(version, virtual_size);
file.seek(SeekFrom::Start(0)).map_err(Error::SeekingFile)?;
file.rewind().map_err(Error::SeekingFile)?;
header.write_to(&mut file)?;
let mut qcow = Self::from(file)?;
@@ -777,10 +773,8 @@ impl QcowFile {
refcounts: &mut [u16],
cluster_size: u64,
refblock_clusters: u64,
pointers_per_cluster: u64,
) -> Result<Vec<u64>> {
let refcount_table_entries = div_round_up_u64(refblock_clusters, pointers_per_cluster);
let mut ref_table = vec![0; refcount_table_entries as usize];
let mut ref_table = vec![0; refblock_clusters as usize];
let mut first_free_cluster: u64 = 0;
for refblock_addr in &mut ref_table {
loop {
@@ -812,10 +806,7 @@ impl QcowFile {
) -> Result<()> {
// Rewrite the header with lazy refcounts enabled while we are rebuilding the tables.
header.compatible_features |= COMPATIBLE_FEATURES_LAZY_REFCOUNTS;
raw_file
.file_mut()
.seek(SeekFrom::Start(0))
.map_err(Error::SeekingFile)?;
raw_file.file_mut().rewind().map_err(Error::SeekingFile)?;
header.write_to(raw_file.file_mut())?;
for (i, refblock_addr) in ref_table.iter().enumerate() {
@@ -850,10 +841,7 @@ impl QcowFile {
// Rewrite the header again, now with lazy refcounts disabled.
header.compatible_features &= !COMPATIBLE_FEATURES_LAZY_REFCOUNTS;
raw_file
.file_mut()
.seek(SeekFrom::Start(0))
.map_err(Error::SeekingFile)?;
raw_file.file_mut().rewind().map_err(Error::SeekingFile)?;
header.write_to(raw_file.file_mut())?;
Ok(())
@@ -907,12 +895,7 @@ impl QcowFile {
set_refcount_table_refcounts(&mut refcounts, header, cluster_size)?;
// Allocate clusters to store the new reference count blocks.
let ref_table = alloc_refblocks(
&mut refcounts,
cluster_size,
refblock_clusters,
pointers_per_cluster,
)?;
let ref_table = alloc_refblocks(&mut refcounts, cluster_size, refblock_clusters)?;
// Write updated reference counts and point the reftable at them.
write_refblocks(
@@ -1240,7 +1223,7 @@ impl QcowFile {
.map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("failed to get cluster refcount: {}", e),
format!("failed to get cluster refcount: {e}"),
)
})?;
if refcount == 0 {
@@ -1656,9 +1639,7 @@ where
R: Read + Seek + SeekHole,
{
let src_size = reader.seek(SeekFrom::End(0)).map_err(Error::SeekingFile)?;
reader
.seek(SeekFrom::Start(0))
.map_err(Error::SeekingFile)?;
reader.rewind().map_err(Error::SeekingFile)?;
// Ensure the destination file is empty before writing to it.
dst_file.set_len(0).map_err(Error::SettingFileSize)?;
@@ -1700,10 +1681,8 @@ pub fn convert(mut src_file: RawFile, dst_file: RawFile, dst_type: ImageType) ->
/// Detect the type of an image file by checking for a valid qcow2 header.
pub fn detect_image_type(file: &mut RawFile) -> Result<ImageType> {
let orig_seek = file
.seek(SeekFrom::Current(0))
.map_err(Error::SeekingFile)?;
file.seek(SeekFrom::Start(0)).map_err(Error::SeekingFile)?;
let orig_seek = file.stream_position().map_err(Error::SeekingFile)?;
file.rewind().map_err(Error::SeekingFile)?;
let magic = file.read_u32::<BigEndian>().map_err(Error::ReadingHeader)?;
let image_type = if magic == QCOW_MAGIC {
ImageType::Qcow2
@@ -1794,7 +1773,7 @@ mod tests {
let mut disk_file: RawFile = RawFile::new(TempFile::new().unwrap().into_file(), false);
disk_file.write_all(header).unwrap();
disk_file.set_len(0x1_0000_0000).unwrap();
disk_file.seek(SeekFrom::Start(0)).unwrap();
disk_file.rewind().unwrap();
testfn(disk_file); // File closed when the function exits.
}
@@ -1816,7 +1795,7 @@ mod tests {
header
.write_to(&mut disk_file)
.expect("Failed to write header to temporary file.");
disk_file.seek(SeekFrom::Start(0)).unwrap();
disk_file.rewind().unwrap();
QcowFile::from(disk_file).expect("Failed to create Qcow from default Header");
}
@@ -1827,7 +1806,7 @@ mod tests {
header
.write_to(&mut disk_file)
.expect("Failed to write header to temporary file.");
disk_file.seek(SeekFrom::Start(0)).unwrap();
disk_file.rewind().unwrap();
QcowFile::from(disk_file).expect("Failed to create Qcow from default Header");
}
@@ -1955,7 +1934,7 @@ mod tests {
q.write_all(b"test first bytes")
.expect("Failed to write test string.");
let mut buf = [0u8; 4];
q.seek(SeekFrom::Start(0)).expect("Failed to seek.");
q.rewind().expect("Failed to seek.");
q.read_exact(&mut buf).expect("Failed to read.");
assert_eq!(&buf, b"test");
});
@@ -2007,15 +1986,15 @@ mod tests {
let mut q = QcowFile::from(disk_file).unwrap();
// Write some test data.
let b = [0x55u8; CHUNK_SIZE];
q.seek(SeekFrom::Start(0)).expect("Failed to seek.");
q.rewind().expect("Failed to seek.");
q.write_all(&b).expect("Failed to write test string.");
// Overwrite the full cluster with zeroes.
q.seek(SeekFrom::Start(0)).expect("Failed to seek.");
q.rewind().expect("Failed to seek.");
let nwritten = q.write_zeroes(CHUNK_SIZE).expect("Failed to write zeroes.");
assert_eq!(nwritten, CHUNK_SIZE);
// Verify that the data was zeroed out.
let mut buf = [0u8; CHUNK_SIZE];
q.seek(SeekFrom::Start(0)).expect("Failed to seek.");
q.rewind().expect("Failed to seek.");
q.read_exact(&mut buf).expect("Failed to read.");
assert_eq!(buf[0], 0);
assert_eq!(buf[CHUNK_SIZE - 1], 0);
@@ -2457,7 +2436,7 @@ mod tests {
}
}
// Check that address 0 is still zeros.
qcow_file.seek(SeekFrom::Start(0)).expect("Failed to seek.");
qcow_file.rewind().expect("Failed to seek.");
let nread = qcow_file.read(&mut readback).expect("Failed to read.");
assert_eq!(nread, BLOCK_SIZE);
for read in readback.iter() {
@@ -2481,7 +2460,7 @@ mod tests {
}
fn seek_cur(file: &mut QcowFile) -> u64 {
file.seek(SeekFrom::Current(0)).unwrap()
file.stream_position().unwrap()
}
#[test]
@@ -2545,7 +2524,7 @@ mod tests {
assert_eq!(seek_cur(&mut file), 0xFFFF);
// seek_hole at or after the end of the file should return None
file.seek(SeekFrom::Start(0)).unwrap();
file.rewind().unwrap();
assert_eq!(file.seek_hole(0x30000).unwrap(), None);
assert_eq!(seek_cur(&mut file), 0);
assert_eq!(file.seek_hole(0x30001).unwrap(), None);
@@ -2563,33 +2542,33 @@ mod tests {
assert_eq!(seek_cur(&mut file), 0xFFFF);
// seek_hole within data should return the next hole
file.seek(SeekFrom::Start(0)).unwrap();
file.rewind().unwrap();
assert_eq!(file.seek_hole(0x10000).unwrap(), Some(0x20000));
assert_eq!(seek_cur(&mut file), 0x20000);
file.seek(SeekFrom::Start(0)).unwrap();
file.rewind().unwrap();
assert_eq!(file.seek_hole(0x10001).unwrap(), Some(0x20000));
assert_eq!(seek_cur(&mut file), 0x20000);
file.seek(SeekFrom::Start(0)).unwrap();
file.rewind().unwrap();
assert_eq!(file.seek_hole(0x1FFFF).unwrap(), Some(0x20000));
assert_eq!(seek_cur(&mut file), 0x20000);
file.seek(SeekFrom::Start(0)).unwrap();
file.rewind().unwrap();
assert_eq!(file.seek_hole(0xFFFF).unwrap(), Some(0xFFFF));
assert_eq!(seek_cur(&mut file), 0xFFFF);
file.seek(SeekFrom::Start(0)).unwrap();
file.rewind().unwrap();
assert_eq!(file.seek_hole(0x10000).unwrap(), Some(0x20000));
assert_eq!(seek_cur(&mut file), 0x20000);
file.seek(SeekFrom::Start(0)).unwrap();
file.rewind().unwrap();
assert_eq!(file.seek_hole(0x1FFFF).unwrap(), Some(0x20000));
assert_eq!(seek_cur(&mut file), 0x20000);
file.seek(SeekFrom::Start(0)).unwrap();
file.rewind().unwrap();
assert_eq!(file.seek_hole(0x20000).unwrap(), Some(0x20000));
assert_eq!(seek_cur(&mut file), 0x20000);
file.seek(SeekFrom::Start(0)).unwrap();
file.rewind().unwrap();
assert_eq!(file.seek_hole(0x20001).unwrap(), Some(0x20001));
assert_eq!(seek_cur(&mut file), 0x20001);
// seek_hole at EOF should return None
file.seek(SeekFrom::Start(0)).unwrap();
file.rewind().unwrap();
assert_eq!(file.seek_hole(0x30000).unwrap(), None);
assert_eq!(seek_cur(&mut file), 0);
@@ -2600,10 +2579,10 @@ mod tests {
// seek_hole within [0x20000, 0x30000) should now find the hole at EOF
assert_eq!(file.seek_hole(0x20000).unwrap(), Some(0x30000));
assert_eq!(seek_cur(&mut file), 0x30000);
file.seek(SeekFrom::Start(0)).unwrap();
file.rewind().unwrap();
assert_eq!(file.seek_hole(0x20001).unwrap(), Some(0x30000));
assert_eq!(seek_cur(&mut file), 0x30000);
file.seek(SeekFrom::Start(0)).unwrap();
file.rewind().unwrap();
assert_eq!(file.seek_hole(0x30000).unwrap(), None);
assert_eq!(seek_cur(&mut file), 0);
});

View File

@@ -231,6 +231,7 @@ impl Write for RawFile {
return Err(io::Error::last_os_error());
}
// SAFETY: tmp_ptr is at least rounded_len long
let tmp_buf = unsafe { slice::from_raw_parts_mut(tmp_ptr, rounded_len) };
// This can eventually replaced with read_at once its interface

View File

@@ -31,16 +31,14 @@ impl Display for Error {
use self::Error::*;
match self {
EvictingRefCounts(e) => write!(
f,
"failed to write a refblock from the cache to disk: {}",
e
),
EvictingRefCounts(e) => {
write!(f, "failed to write a refblock from the cache to disk: {e}")
}
InvalidIndex => write!(f, "address requested is not within the range of the disk"),
NeedCluster(addr) => write!(f, "cluster with addr={} needs to be read", addr),
NeedCluster(addr) => write!(f, "cluster with addr={addr} needs to be read"),
NeedNewCluster => write!(f, "new cluster needs to be allocated for refcounts"),
ReadingRefCounts(e) => {
write!(f, "failed to read the file into the refcount cache: {}", e)
write!(f, "failed to read the file into the refcount cache: {e}")
}
}
}

View File

@@ -4,6 +4,6 @@ version = "0.1.0"
edition = "2021"
[dependencies]
libc = "0.2.137"
libc = "0.2.139"
log = "0.4.17"
vmm-sys-util = "0.10.0"
vmm-sys-util = "0.11.0"

View File

@@ -343,6 +343,7 @@ impl RateLimiter {
let timer_fd = TimerFd::new()?;
// Note: vmm_sys_util::TimerFd::new() open the fd w/o O_NONBLOCK. We manually add this flag
// so that `Self::event_handler` won't be blocked with `vmm_sys_util::TimerFd::wait()`.
// SAFETY: FFI calls.
let ret = unsafe {
let fd = timer_fd.as_raw_fd();
let mut flags = libc::fcntl(fd, libc::F_GETFL);
@@ -888,7 +889,7 @@ pub(crate) mod tests {
fn test_rate_limiter_debug() {
let l = RateLimiter::new(1, 2, 3, 4, 5, 6).unwrap();
assert_eq!(
format!("{:?}", l),
format!("{l:?}"),
format!(
"RateLimiter {{ bandwidth: {:?}, ops: {:?} }}",
l.bandwidth(),

View File

@@ -1,12 +1,25 @@
- [v29.0](#v290)
- [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm)
- [Snapshot/Restore and Live Migration Improvements](#snapshotrestore-and-live-migration-improvements)
- [Heap Allocation Improvements](#heap-allocation-improvements)
- [`ch-remote` Improvements](#ch-remote-improvements)
- [`AArch64` Documentation Integration](#aarch64-documentation-integration)
- [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement)
- [TCP Offload Control](#tcp-offload-control)
- [Notable Bug Fixes](#notable-bug-fixes)
- [Removals](#removals)
- [Deprecations](#deprecations)
- [Contributors](#contributors)
- [v28.1](#v281)
- [v28.0](#v280)
- [Community Engagement (Reminder)](#community-engagement-reminder)
- [Long Term Support (LTS) Release](#long-term-support-lts-release)
- [Virtualised TPM Support](#virtualised-tpm-support)
- [Transparent Huge Page Support](#transparent-huge-page-support)
- [README Quick Start Improved](#readme-quick-start-improved)
- [Notable Bug Fixes](#notable-bug-fixes)
- [Removals](#removals)
- [Contributors](#contributors)
- [Notable Bug Fixes](#notable-bug-fixes-1)
- [Removals](#removals-1)
- [Contributors](#contributors-1)
- [v27.0](#v270)
- [Community Engagement](#community-engagement)
- [Prebuilt Packages](#prebuilt-packages)
@@ -15,41 +28,41 @@
- [Simplified Build Feature Flags](#simplified-build-feature-flags)
- [Asynchronous Kernel Loading](#asynchronous-kernel-loading)
- [GDB Support for AArch64](#gdb-support-for-aarch64)
- [Notable Bug Fixes](#notable-bug-fixes-1)
- [Deprecations](#deprecations)
- [Contributors](#contributors-1)
- [Notable Bug Fixes](#notable-bug-fixes-2)
- [Deprecations](#deprecations-1)
- [Contributors](#contributors-2)
- [v26.0](#v260)
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform)
- [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support)
- [Notable Bug Fixes](#notable-bug-fixes-2)
- [Deprecations](#deprecations-1)
- [Removals](#removals-1)
- [Contributors](#contributors-2)
- [v25.0](#v250)
- [`ch-remote` Improvements](#ch-remote-improvements)
- [VM "Coredump" Support](#vm-coredump-support)
- [Notable Bug Fixes](#notable-bug-fixes-3)
- [Deprecations](#deprecations-2)
- [Removals](#removals-2)
- [Contributors](#contributors-3)
- [v25.0](#v250)
- [`ch-remote` Improvements](#ch-remote-improvements-1)
- [VM "Coredump" Support](#vm-coredump-support)
- [Notable Bug Fixes](#notable-bug-fixes-4)
- [Removals](#removals-3)
- [Contributors](#contributors-4)
- [v24.0](#v240)
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
- [Sparse Mmap support](#sparse-mmap-support)
- [Expose Platform Serial Number](#expose-platform-serial-number)
- [Notable Bug Fixes](#notable-bug-fixes-4)
- [Notable Bug Fixes](#notable-bug-fixes-5)
- [Notable Improvements](#notable-improvements)
- [Deprecations](#deprecations-2)
- [Deprecations](#deprecations-3)
- [New on the Website](#new-on-the-website)
- [Contributors](#contributors-4)
- [Contributors](#contributors-5)
- [v23.1](#v231)
- [v23.0](#v230)
- [vDPA Support](#vdpa-support)
- [Updated OS Support list](#updated-os-support-list)
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
- [`AMX` Support](#amx-support)
- [Notable Bug Fixes](#notable-bug-fixes-5)
- [Deprecations](#deprecations-3)
- [Contributors](#contributors-5)
- [Notable Bug Fixes](#notable-bug-fixes-6)
- [Deprecations](#deprecations-4)
- [Contributors](#contributors-6)
- [v22.1](#v221)
- [v22.0](#v220)
- [GDB Debug Stub Support](#gdb-debug-stub-support)
@@ -60,13 +73,13 @@
- [PMU Support for AArch64](#pmu-support-for-aarch64)
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
- [Notable Bug Fixes](#notable-bug-fixes-6)
- [Contributors](#contributors-6)
- [Notable Bug Fixes](#notable-bug-fixes-7)
- [Contributors](#contributors-7)
- [v21.0](#v210)
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
- [Notable Bug fixes](#notable-bug-fixes-7)
- [Contributors](#contributors-7)
- [Notable Bug fixes](#notable-bug-fixes-8)
- [Contributors](#contributors-8)
- [v20.2](#v202)
- [v20.1](#v201)
- [v20.0](#v200)
@@ -75,8 +88,8 @@
- [Improved VFIO support](#improved-vfio-support)
- [Safer code](#safer-code)
- [Extended documentation](#extended-documentation)
- [Notable bug fixes](#notable-bug-fixes-8)
- [Contributors](#contributors-8)
- [Notable bug fixes](#notable-bug-fixes-9)
- [Contributors](#contributors-9)
- [v19.0](#v190)
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
- [PCI boot time optimisations](#pci-boot-time-optimisations)
@@ -84,8 +97,8 @@
- [Live migration enhancements](#live-migration-enhancements)
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
- [Notable bug fixes](#notable-bug-fixes-9)
- [Contributors](#contributors-9)
- [Notable bug fixes](#notable-bug-fixes-10)
- [Contributors](#contributors-10)
- [v18.0](#v180)
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
@@ -95,31 +108,31 @@
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
- [Power button support on AArch64](#power-button-support-on-aarch64)
- [Notable bug fixes](#notable-bug-fixes-10)
- [Contributors](#contributors-10)
- [Notable bug fixes](#notable-bug-fixes-11)
- [Contributors](#contributors-11)
- [v17.0](#v170)
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
- [Improved SGX support](#improved-sgx-support)
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
- [Notable bug fixes](#notable-bug-fixes-11)
- [Contributors](#contributors-11)
- [Notable bug fixes](#notable-bug-fixes-12)
- [Contributors](#contributors-12)
- [v16.0](#v160)
- [Improved live migration support](#improved-live-migration-support)
- [Improved `vhost-user` support](#improved-vhost-user-support)
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
- [Notable bug fixes](#notable-bug-fixes-12)
- [Notable bug fixes](#notable-bug-fixes-13)
- [Removed functionality](#removed-functionality)
- [Contributors](#contributors-12)
- [Contributors](#contributors-13)
- [v15.0](#v150)
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
- [Network device rate limiting](#network-device-rate-limiting)
- [Support for runtime control of `virtio-net` guest offload](#support-for-runtime-control-of-virtio-net-guest-offload)
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
- [Bug fixes](#bug-fixes)
- [Deprecations](#deprecations-4)
- [Contributors](#contributors-13)
- [Deprecations](#deprecations-5)
- [Contributors](#contributors-14)
- [v0.14.1](#v0141)
- [v0.14.0](#v0140)
- [Structured event monitoring](#structured-event-monitoring)
@@ -128,8 +141,8 @@
- [Updated hotplug documentation](#updated-hotplug-documentation)
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
- [Block device rate limiting](#block-device-rate-limiting)
- [Deprecations](#deprecations-5)
- [Contributors](#contributors-14)
- [Deprecations](#deprecations-6)
- [Contributors](#contributors-15)
- [v0.13.0](#v0130)
- [Wider VFIO device support](#wider-vfio-device-support)
- [Improved huge page support](#improved-huge-page-support)
@@ -137,13 +150,13 @@
- [VHD disk image support](#vhd-disk-image-support)
- [Improved Virtio device threading](#improved-virtio-device-threading)
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
- [Contributors](#contributors-15)
- [Contributors](#contributors-16)
- [v0.12.0](#v0120)
- [ARM64 enhancements](#arm64-enhancements)
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
- [Enhanced "info" API](#enhanced-info-api)
- [Contributors](#contributors-16)
- [Contributors](#contributors-17)
- [v0.11.0](#v0110)
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
- [Windows Guest Support](#windows-guest-support)
@@ -155,15 +168,15 @@
- [Default Log Level Changed](#default-log-level-changed)
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
- [Notable Bug Fixes](#notable-bug-fixes-13)
- [Contributors](#contributors-17)
- [Notable Bug Fixes](#notable-bug-fixes-14)
- [Contributors](#contributors-18)
- [v0.10.0](#v0100)
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
- [Memory Zones](#memory-zones)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
- [Notable Bug Fixes](#notable-bug-fixes-14)
- [Contributors](#contributors-18)
- [Notable Bug Fixes](#notable-bug-fixes-15)
- [Contributors](#contributors-19)
- [v0.9.0](#v090)
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
- [Block and Network Device Statistics](#block-and-network-device-statistics)
@@ -176,17 +189,17 @@
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
- [Intel SGX Support](#intel-sgx-support)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-15)
- [Contributors](#contributors-19)
- [Notable Bug Fixes](#notable-bug-fixes-16)
- [Contributors](#contributors-20)
- [v0.8.0](#v080)
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
- [Experimental ARM64 Support](#experimental-arm64-support)
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-16)
- [Notable Bug Fixes](#notable-bug-fixes-17)
- [Command Line and API Changes](#command-line-and-api-changes)
- [Contributors](#contributors-20)
- [Contributors](#contributors-21)
- [v0.7.0](#v070)
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
- [Alternative `libc` Support](#alternative-libc-support)
@@ -196,14 +209,14 @@
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
- [Updated Distribution Support](#updated-distribution-support)
- [Command Line and API Changes](#command-line-and-api-changes-1)
- [Contributors](#contributors-21)
- [Contributors](#contributors-22)
- [v0.6.0](#v060)
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
- [Command Line Interface](#command-line-interface)
- [PVH Boot](#pvh-boot)
- [Contributors](#contributors-22)
- [Contributors](#contributors-23)
- [v0.5.1](#v051)
- [v0.5.0](#v050)
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
@@ -211,7 +224,7 @@
- [New Interrupt Management Framework](#new-interrupt-management-framework)
- [Development Tools](#development-tools)
- [Kata Containers Integration](#kata-containers-integration)
- [Contributors](#contributors-23)
- [Contributors](#contributors-24)
- [v0.4.0](#v040)
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
@@ -220,7 +233,7 @@
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
- [PCI BAR reprogramming](#pci-bar-reprogramming)
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
- [Contributors](#contributors-24)
- [Contributors](#contributors-25)
- [v0.3.0](#v030)
- [Block device offloading](#block-device-offloading)
- [Network device backend](#network-device-backend)
@@ -247,6 +260,103 @@
- [Unit testing](#unit-testing)
- [Integration tests parallelization](#integration-tests-parallelization)
# v29.0
This release has been tracked in our [roadmap
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
v29.0. The following user visible changes have been made:
### Release Binary Supports Both MSHV and KVM
On `x86-64` the binary included in releases supports both the KVM and MSHV
hypervisor with runtime detection to identify the correct hypervisor to use.
### Snapshot/Restore and Live Migration Improvements
Improvements have been made to the data structures used for both live migration
and snapshot/restore. Unfortunately this has broken compatibility with older
versions (support for migrating between major versions is not yet officially
supported but has worked for some versions.)
### Heap Allocation Improvements
Improvements have been made to the volume of heap allocations when running with
`virtio-block` devices along with a reduction in the peak heap size.
### `ch-remote` Improvements
Support for "pinging" the VMM and shutting the VMM down have been added to
`ch-remote`.
### `AArch64` Documentation Integration
The documentation for `AArch64` support has been integrated into the main
README.
### `virtio-block` Counters Enhancement
The counters for the `virtio-block` device has extended to include min/mean/max
latency counters.
### TCP Offload Control
The `virtio-net` device has gained support for controlling the enabling of
checksum and offloading. This allows the device to be used in environments
where the hardware lacks support for the offloading.
### Notable Bug Fixes
* Update dependencies including a version of `linux-loader` that addresses an
infinite loop issue ([details](https://github.com/rust-vmm/linux-loader/security/advisories/GHSA-52h2-m2cf-9jh6))
* Fix bugs related to `virtio-net` including an integer overflow issue
(#4924, #4949)
* Use host `cpuid` information for L2 cache for older KVM on x86 (#4920)
* Memory mapped into the guest is now marked as non-dumpable which prevents large core files (#5016)
* Fix QCOW2 refcount table size (#5034)
* Fix unpause support on MSHV in dual binary (#5037)
* Threads inside `virtio` devices are now shutdown on reboot (#5095)
### Removals
No functionality has been removed in this release.
### Deprecations
* Support for specifying a directory with `MemoryZoneConfig::file` or
`MemoryConfig::file` has been deprecated. This was originally used for
supporting huge pages or shared memory backing which is now natively supported
(#5085)
### Contributors
Many thanks to everyone who has contributed to our release:
* Bo Chen <chen.bo@intel.com>
* Claudio Fontana <claudio.fontana@gmail.com>
* Hao Xu <howeyxu@tencent.com>
* Henry Wang <Henry.Wang@arm.com>
* Jinank Jain <jinankjain@microsoft.com>
* Michael Zhao <michael.zhao@arm.com>
* Muminul Islam <muislam@microsoft.com>
* Philipp Schuster <philipp.schuster@cyberus-technology.de>
* Rob Bradford <robert.bradford@intel.com>
* Sebastien Boeuf <sebastien.boeuf@intel.com>
* Shuaiyi Zhang <zhangsy28@lenovo.com>
* Wei Liu <liuwe@microsoft.com>
* Yong He <alexyonghe@tencent.com>
* Yuji Hagiwara <yuuzi41@gmail.com>
# v28.1
This is a bug fix release. The following issues have been addressed:
* Update dependencies including a version of `linux-loader` that
addresses an infinite loop issue ([details](https://github.com/rust-vmm/linux-loader/security/advisories/GHSA-52h2-m2cf-9jh6))
* Fix bugs related to `virtio-net` including an integer overflow issue
(#4924, #4949)
* Use host `cpuid` information for L2 cache for older KVM on x86 (#4920)
* Improve README and documentation
# v28.0
This release has been tracked in our new [roadmap

View File

@@ -208,8 +208,6 @@ if [[ "$hypervisor" = "mshv" ]]; then
exit 1
fi
# For now these values are deafult for kvm
features=""
# lock the workloads folder to avoid parallel updating by different containers
(
@@ -233,11 +231,7 @@ fi
export RUST_BACKTRACE=1
# Test without ACPI
cargo build --all --release $features --target $BUILD_TARGET
strip target/$BUILD_TARGET/release/cloud-hypervisor
strip target/$BUILD_TARGET/release/vhost_user_net
strip target/$BUILD_TARGET/release/ch-remote
cargo build --all --release --target $BUILD_TARGET
# Enable KSM with some reasonable parameters so that it won't take too long
# for the memory to be merged between two processes.
@@ -250,13 +244,13 @@ echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages
# Run all direct kernel boot (Device Tree) test cases in mod `parallel`
time cargo test $features "common_parallel::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
time cargo test "common_parallel::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
RES=$?
# Run some tests in sequence since the result could be affected by other tests
# running in parallel.
if [ $RES -eq 0 ]; then
time cargo test $features "common_sequential::$test_filter" --target $BUILD_TARGET -- --test-threads=1 ${test_binary_args[*]}
time cargo test "common_sequential::$test_filter" --target $BUILD_TARGET -- --test-threads=1 ${test_binary_args[*]}
RES=$?
else
exit $RES
@@ -264,7 +258,7 @@ fi
# Run all ACPI test cases
if [ $RES -eq 0 ]; then
time cargo test $features "aarch64_acpi::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
time cargo test "aarch64_acpi::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
RES=$?
else
exit $RES
@@ -272,14 +266,14 @@ fi
# Run all test cases related to live migration
if [ $RES -eq 0 ]; then
time cargo test $features "live_migration_parallel::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
time cargo test "live_migration_parallel::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
RES=$?
else
exit $RES
fi
if [ $RES -eq 0 ]; then
time cargo test $features "live_migration_sequential::$test_filter" --target $BUILD_TARGET -- --test-threads=1 ${test_binary_args[*]}
time cargo test "live_migration_sequential::$test_filter" --target $BUILD_TARGET -- --test-threads=1 ${test_binary_args[*]}
RES=$?
else
exit $RES

View File

@@ -12,10 +12,10 @@ mkdir -p "$WORKLOADS_DIR"
process_common_args "$@"
# For now these values are default for kvm
features=""
test_features=""
if [ "$hypervisor" = "mshv" ] ; then
features="--no-default-features --features mshv"
test_features="--no-default-features --features mshv"
fi
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
@@ -86,24 +86,21 @@ if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
fi
cargo build --all --release $features --target $BUILD_TARGET
strip target/$BUILD_TARGET/release/cloud-hypervisor
strip target/$BUILD_TARGET/release/vhost_user_net
strip target/$BUILD_TARGET/release/ch-remote
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
# Test ovs-dpdk relies on hugepages
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages
export RUST_BACKTRACE=1
time cargo test $features "live_migration_parallel::$test_filter" -- ${test_binary_args[*]}
time cargo test $test_features "live_migration_parallel::$test_filter" -- ${test_binary_args[*]}
RES=$?
# Run some tests in sequence since the result could be affected by other tests
# running in parallel.
if [ $RES -eq 0 ]; then
export RUST_BACKTRACE=1
time cargo test $features "live_migration_sequential::$test_filter" -- --test-threads=1 ${test_binary_args[*]}
time cargo test $test_features "live_migration_sequential::$test_filter" -- --test-threads=1 ${test_binary_args[*]}
RES=$?
fi

View File

@@ -12,10 +12,10 @@ mkdir -p "$WORKLOADS_DIR"
process_common_args "$@"
# For now these values are default for kvm
features=""
test_features=""
if [ "$hypervisor" = "mshv" ] ; then
features="--no-default-features --features mshv"
test_features="--no-default-features --features mshv"
fi
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
@@ -77,13 +77,10 @@ if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
fi
cargo build --all --release $features --target $BUILD_TARGET
strip target/$BUILD_TARGET/release/cloud-hypervisor
strip target/$BUILD_TARGET/release/vhost_user_net
strip target/$BUILD_TARGET/release/ch-remote
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
export RUST_BACKTRACE=1
time cargo test $features "rate_limiter::$test_filter" -- --test-threads=1 ${test_binary_args[*]}
time cargo test $test_features "rate_limiter::$test_filter" -- --test-threads=1 ${test_binary_args[*]}
RES=$?
exit $RES

View File

@@ -11,8 +11,32 @@ if [[ "$hypervisor" = "mshv" ]]; then
exit 1
fi
# For now these values are default for kvm
features=""
WORKLOADS_DIR="$HOME/workloads"
mkdir -p "$WORKLOADS_DIR"
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
FW="$WORKLOADS_DIR/hypervisor-fw"
pushd $WORKLOADS_DIR
rm -f $FW
time wget --quiet $FW_URL || exit 1
popd
JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20221118-1.qcow2"
JAMMY_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_IMAGE_NAME"
JAMMY_OS_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_IMAGE_NAME"
if [ ! -f "$JAMMY_OS_IMAGE" ]; then
pushd $WORKLOADS_DIR
time wget --quiet $JAMMY_OS_IMAGE_URL || exit 1
popd
fi
JAMMY_OS_RAW_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20221118-1.raw"
JAMMY_OS_RAW_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_RAW_IMAGE_NAME"
if [ ! -f "$JAMMY_OS_RAW_IMAGE" ]; then
pushd $WORKLOADS_DIR
time qemu-img convert -p -f qcow2 -O raw $JAMMY_OS_IMAGE_NAME $JAMMY_OS_RAW_IMAGE_NAME || exit 1
popd
fi
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
CFLAGS=""
@@ -22,12 +46,11 @@ TARGET_CC="musl-gcc"
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
fi
cargo build --all --release $features --target $BUILD_TARGET
strip target/$BUILD_TARGET/release/cloud-hypervisor
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
export RUST_BACKTRACE=1
time cargo test $features "sgx::$test_filter" -- ${test_binary_args[*]}
time cargo test "sgx::$test_filter" -- ${test_binary_args[*]}
RES=$?
exit $RES

View File

@@ -5,14 +5,16 @@ source $HOME/.cargo/env
source $(dirname "$0")/test-util.sh
process_common_args "$@"
# For now these values are default for kvm
features=""
WORKLOADS_DIR="$HOME/workloads"
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.raw"
FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
FW="$WORKLOADS_DIR/hypervisor-fw"
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
if [ ! -f "$VMLINUX_IMAGE" ]; then
build_custom_linux
fi
BLK_IMAGE="$WORKLOADS_DIR/blk.img"
MNT_DIR="mount_image"
@@ -43,9 +45,7 @@ TARGET_CC="musl-gcc"
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
fi
cargo build --all --release $features --target $BUILD_TARGET
strip target/$BUILD_TARGET/release/cloud-hypervisor
strip target/$BUILD_TARGET/release/ch-remote
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
# We always copy a fresh version of our binary for our L2 guest.
cp target/$BUILD_TARGET/release/cloud-hypervisor $VFIO_DIR
@@ -56,11 +56,11 @@ echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages
export RUST_BACKTRACE=1
time cargo test $features "vfio::test_vfio" -- ${test_binary_args[*]}
time cargo test "vfio::test_vfio" -- ${test_binary_args[*]}
RES=$?
if [ $RES -eq 0 ]; then
time cargo test $features "vfio::test_nvidia" -- --test-threads=1 ${test_binary_args[*]}
time cargo test "vfio::test_nvidia" -- --test-threads=1 ${test_binary_args[*]}
RES=$?
fi

View File

@@ -6,8 +6,6 @@ source $(dirname "$0")/test-util.sh
source $(dirname "$0")/common-aarch64.sh
process_common_args "$@"
# For now these values are default for kvm
features=""
# aarch64 not supported for MSHV
if [[ "$hypervisor" = "mshv" ]]; then
@@ -46,12 +44,11 @@ dmsetup mknodes
export RUST_BACKTRACE=1
cargo build --all --release $features --target $BUILD_TARGET
strip target/$BUILD_TARGET/release/cloud-hypervisor
cargo build --all --release --target $BUILD_TARGET
# Only run with 1 thread to avoid tests interfering with one another because
# Windows has a static IP configured
time cargo test $features "windows::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
time cargo test "windows::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
RES=$?
dmsetup remove_all -f

View File

@@ -6,10 +6,10 @@ source $(dirname "$0")/test-util.sh
process_common_args "$@"
# For now these values are default for kvm
features=""
test_features=""
if [ "$hypervisor" = "mshv" ] ; then
features="--no-default-features --features mshv"
test_features="--no-default-features --features mshv"
fi
WIN_IMAGE_FILE="/root/workloads/windows-server-2019.raw"
@@ -44,14 +44,13 @@ dmsetup mknodes
dmsetup create windows-snapshot-base --table "0 $img_blk_size snapshot-origin /dev/mapper/windows-base"
dmsetup mknodes
cargo build --all --release $features --target $BUILD_TARGET
strip target/$BUILD_TARGET/release/cloud-hypervisor
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
export RUST_BACKTRACE=1
# Only run with 1 thread to avoid tests interfering with one another because
# Windows has a static IP configured
time cargo test $features "windows::$test_filter" -- ${test_binary_args[*]}
time cargo test $test_features "windows::$test_filter" -- ${test_binary_args[*]}
RES=$?
dmsetup remove_all -f

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