Compare commits

..

113 Commits
v46.0 ... v47.0

Author SHA1 Message Date
Bo Chen
62001b65e9 build: Release v47.0
Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-07-22 21:06:54 +00:00
Wei Liu
4be2ca4c10 vhost_user_net: Use Mutex::get_mut() where possible
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-07-17 19:20:59 +00:00
Wei Liu
5716af09a5 vhost_user_block: Use Mutex::get_mut() where possible
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-07-17 19:20:59 +00:00
Wei Liu
4ea40b4bea rate_limiter: Use Mutex::get_mut() in update_buckets
There is no need to lock. That function already holds a mutable
reference to self.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-07-17 19:20:59 +00:00
Jean-Philippe Brucker
4528e2f1ea devices: rtc_pl031: Disable broken interrupt
The PL031 RTC provides two features: a real-time counter and an alarm
interrupt. To use the alarm, the driver normally writes a time value
into the match register RTCMR, and when the counter reaches that value
the device triggers the interrupt.

At the moment the implementation ignores programming of the alarm, as
the feature seems rarely used in VMs. However the interrupt is still
triggered arbitrarily when the guest writes to registers, and the line
is never cleared. This really confuses the Linux driver, which loops in
the interrupt handler until Linux realizes that no one is dealing with
the interrupt (200000 unanswered calls) and disables the handler.

One way to fix this would be implementing the alarm function properly,
which isn't too difficult but requires adding some async timer logic
which probably won't ever get used. In addition the device's interrupt
is level-triggered and we don't support level interrupts at the moment,
though we could probably get away with changing this interrupt to edge.

The simplest fix, though, is to just disable the interrupt logic
entirely, so that the alarm function still doesn't work but the guest
doesn't see spurious interrupts.

Add a default() implementation to satisfy clippy's new_without_default
check, since Rtc::new() doesn't take a parameter after this change.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
2025-07-17 17:21:05 +00:00
Bo Chen
987ad11c90 main: Report errors with 'error!()'
This was missed from #7183, likely because `eprint!` is used instead of
`eprintln!`.

Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-07-17 16:18:56 +00:00
Wei Liu
cea708deb9 performance-metrics: Fix the names of the kernels
In 2b05753716, the names of the reference kernels are changed.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-07-16 20:20:32 +00:00
Songqian Li
e32fa593e5 build: clean up unused dependencies
Signed-off-by: Songqian Li <sionli@tencent.com>
2025-07-15 07:16:36 +00:00
Alyssa Ross
ec8fceb4a6 virtio-devices: stop corrupting vsock commands
The read_exact() call was introduced in 82ac114b8 ("virtio-devices:
vsock: handle short read in muxer") to solve a crash when a connection
disconnected without sending any data, but it introduced a problem of
its own: because the socket is non-blocking, read_exact() may read
some data, then return ErrorKind::WouldBlock.  In that case, the data
it read will be discarded.  So for example if it read "CONNECT ",
and then nothing else was available to read yet, "CONNECT " would be
discarded, and so the next time this function was called, when epoll
triggered again for the socket, only the following data would end up
in command.buf, causing an error due to just a port number being an
invalid command.

Contrary to that commit message, this code was actually designed to
handle short reads just fine — in the case of a short read, it stores
the data it has read in command, and returns
Error::UnixRead(ErrorKind::WouldBlock), which is ignored by the
caller, and the function gets called again when there is more data to
read, building up command potentially over the course of several
reads.  The only thing it didn't handle correctly, as far as I can
tell, was a 0-byte read, which happens when a client disconnects from
the socket without writing anything.  All that's needed to fix this is
to avoid an invalid subtraction in that case, so this change reverts
82ac114b8, fixing the issue with partial commands being discarded, and
instead handles the 0-byte read by using slice::get, and treating an
empty command as an incomplete command, which of course it is.

Fixes: 82ac114b8 ("virtio-devices: vsock: handle short read in muxer")
Signed-off-by: Alyssa Ross <hi@alyssa.is>
2025-07-14 18:07:07 +00:00
Alyssa Ross
01aed9733c build: add missing dependency features
This makes it possible to run cargo test just for the virtio-devices
crate (as long as either KVM or MSHV is specified).

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2025-07-14 18:06:54 +00:00
Nuno Das Neves
a5cd1b4fbe build: Bump mshv-ioctls and mshv-bindings to v0.5.2
Also update the version in the fuzz crate.

Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
2025-07-12 01:17:26 +00:00
Muminul Islam
b268e88ba3 virtio-devices: remove unnecessary parentheses
Cargo fuzz build report an warning:

warning: unnecessary parentheses around closure body
--> virtio-devices/src/iommu.rs:578:41
|
578 |.retain(|&x, _| (x < req.virt_start || x > req.virt_end));
|                                         ^
|
= note: `#[warn(unused_parens)]` on by default
help: remove these parentheses
|
578 -.retain(|&x, _| (x < req.virt_start || x > req.virt_end));
578 +.retain(|&x, _| x < req.virt_start || x > req.virt_end);
|

warning: `virtio-devices` (lib) generated 1 warning
(run `cargo fix --lib -p virtio-devices` to apply 1 suggestion)

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-07-11 22:02:15 +00:00
dependabot[bot]
0659eaeba1 build: Bump async-signal from 0.2.10 to 0.2.11
Bumps [async-signal](https://github.com/smol-rs/async-signal) from 0.2.10 to 0.2.11.
- [Release notes](https://github.com/smol-rs/async-signal/releases)
- [Changelog](https://github.com/smol-rs/async-signal/blob/master/CHANGELOG.md)
- [Commits](https://github.com/smol-rs/async-signal/compare/v0.2.10...v0.2.11)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-11 00:38:49 +00:00
Bo Chen
96528f84f9 build: Bump gdbstub from 0.7.1 to 0.7.6
Bumps [gdbstub](https://github.com/daniel5151/gdbstub) from 0.7.1 to 0.7.6.
- [Release notes](https://github.com/daniel5151/gdbstub/releases)
- [Changelog](https://github.com/daniel5151/gdbstub/blob/master/CHANGELOG.md)
- [Commits](https://github.com/daniel5151/gdbstub/compare/0.7.1...0.7.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-07-10 19:46:28 +00:00
Ruoqing He
6da5c32fd9 hypervisor: aarch64: Use offset_of for nested fields
`std::mem::offset_of` could be used for calculating nested fields, use
this feature to shorten aarch64 reg offset calculation.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-07-10 16:39:39 +00:00
Ruoqing He
07cc1f6545 hypervisor: aarch64: Remove manually implemented offset_of
Manually implemented `offset_of` in `arch/aarch64/mod.rs` is not used
now, remove it.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-07-10 16:39:39 +00:00
Ruoqing He
008f259aff hypervisor: aarch64: Use offset_of from std::mem
`std::mem::offset_of` is stabilized since Rust 1.77, let's use
implementation provided by std instead of manual implementation.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-07-10 16:39:39 +00:00
Ruoqing He
aa6fefa80f hypervisor: riscv64: Remove manually implemented offset_of
Manually implemented `_offset_of` and `offset_of` in
`arch/riscv64/mod.rs` are not used now, remove them.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-07-10 16:39:39 +00:00
Ruoqing He
87e74719ec hypervisor: riscv64: Use offset_of from std::mem
`std::mem::offset_of` supports calculating offset of nested structures,
let's use implementation provided by std instead of manual
implementation.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-07-10 16:39:39 +00:00
Maximilian Güntner
072f06ff4c misc: vhost_user_net: replace eprintln with log::error
Other lines are already logged using `log::error!` and
`env_logger` is initialized before calling
`start_net_backend` in `main()`.

Signed-off-by: Maximilian Güntner <code@mguentner.de>
2025-07-10 16:36:54 +00:00
Maximilian Güntner
50b33db718 vmm: replace eprintln with log::error
Unify log formatting and printing as `eprintln!` and `log::error!`
would be used alongside each other.
When using e.g. `env_logger` lines printed with `eprintln!` would
lack formatting / colors.
Currently only relevant in `ch-remote` + `cli_print_error_chain`.

Note that the replaced messages now also end up in the logfile of
`cloud-hypervisor` when configured and not any longer in stderr.

Signed-off-by: Maximilian Güntner <code@mguentner.de>
2025-07-10 16:36:54 +00:00
Maximilian Güntner
19dc733267 ch-remote: add env_logger, log messages to stderr
Until now all messages generated using `log::level!`
(e.g., `warn!`) have not been printed as `ch-remote` did not
register a logger.
Furthermore, replace all `eprintln!` with `error!`
to align formatting for consistency.

Signed-off-by: Maximilian Güntner <code@mguentner.de>
2025-07-10 16:36:54 +00:00
Maximilian Güntner
6ba949d741 build: consolidate env_logger to workspace, update to 0.11.8
Signed-off-by: Maximilian Güntner <code@mguentner.de>
2025-07-10 16:36:54 +00:00
Philipp Schuster
9d4408ba76 vmm: add directory path to error message
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-07-10 16:24:50 +00:00
Maximilian Güntner
f9c134471a vmm: warn about deprecation of default IP address + mask
Issue: #7083

Signed-off-by: Maximilian Güntner <code@mguentner.de>
2025-07-08 19:05:45 +00:00
ninollei
3d5b4d0b0c vmm: acpi: Use correct table name in error message
Fix a copy-paste error using the wrong table name in the assertion

Signed-off-by: ninollei <ninollx@hotmail.com>
2025-07-08 09:02:40 +00:00
dependabot[bot]
ea32b67098 build: Bump proc-macro-crate from 3.2.0 to 3.3.0
Bumps [proc-macro-crate](https://github.com/bkchr/proc-macro-crate) from 3.2.0 to 3.3.0.
- [Release notes](https://github.com/bkchr/proc-macro-crate/releases)
- [Commits](https://github.com/bkchr/proc-macro-crate/compare/v3.2.0...v3.3.0)

---
updated-dependencies:
- dependency-name: proc-macro-crate
  dependency-version: 3.3.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 17:23:51 +00:00
Jinank Jain
190d90196f build: Bump vfio and all the dependent crates to latest version
Recently vfio crates have moved to crates.io, thus we should start
consuming the crate from crates.io instead git url.

This results in better versioning instead of tracking some git commit
sha.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-07-07 03:05:38 +00:00
Jinank Jain
fe422a45af build: Move away from actions-rs/cross
Since action-rs/cross is deprecrated, thus move to
houseabsolute/actions-rust-cross.

We should pin the cross-version to the latest version to fix the build
issues with virtio-bindings crate.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-07-07 03:05:38 +00:00
Wei Liu
da5fae3814 docs: Fix the chown command in macvtap-bridge.md
When invoking the script chown shows a warning.

    chown: warning: '.' should be ':': ‘1000.1000’

From `info coreutils 'chown invocation'`.

   Some older scripts may still use ‘.’ in place of the ‘:’ separator.
POSIX 1003.1-2001 (*note Standards conformance::) does not require
support for that, but for backward compatibility GNU ‘chown’ supports
‘.’ so long as no ambiguity results, although it issues a warning and
support may be removed in future versions.  New scripts should avoid the
use of ‘.’ because it is not portable, and because it has undesirable
results if the entire OWNER‘.’GROUP happens to identify a user whose
name contains ‘.’.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-07-01 15:12:03 +00:00
dependabot[bot]
8a78043e2f build: Bump crate-ci/typos from 1.33.1 to 1.34.0
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.33.1 to 1.34.0.
- [Release notes](https://github.com/crate-ci/typos/releases)
- [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crate-ci/typos/compare/v1.33.1...v1.34.0)

---
updated-dependencies:
- dependency-name: crate-ci/typos
  dependency-version: 1.34.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 02:50:46 +00:00
Wei Liu
fdeb778210 block: Add back UUID crate's v4 feature
That feature was dropped when consolidating the UUID dependency because
somehow building the whole project worked. The CI system was happy.

However, building the block crate alone is broken. The vhdx code uses
Uuid::new_v4, which requires `v4` to be enabled.

Add the feature back.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-06-30 10:54:54 +00:00
dependabot[bot]
13c222a879 build: Bump proc-macro2 from 1.0.93 to 1.0.95
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.93 to 1.0.95.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.93...1.0.95)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-28 00:18:30 +00:00
dependabot[bot]
b27d9ccfab build: Bump rustix from 0.38.34 to 0.38.44
Bumps [rustix](https://github.com/bytecodealliance/rustix) from 0.38.34 to 0.38.44.
- [Release notes](https://github.com/bytecodealliance/rustix/releases)
- [Changelog](https://github.com/bytecodealliance/rustix/blob/main/CHANGES.md)
- [Commits](https://github.com/bytecodealliance/rustix/compare/v0.38.34...v0.38.44)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-26 23:56:47 +00:00
Philipp Schuster
d580ed55c6 seccomp: add SYS_getcwd (79) to support proper Rust backtraces
When a proper Rust backtrace is printed, the Rust std wants to use the
SYS_getcwd(79) system call to prettify some paths while printing. In
Cloud Hypervisor, this is at least relevant for printing panics or if
a `anyhow::Error` value is printed using `{e:?}` (but not `{e:#?}`).

The syscall cause can be found in `impl fmt::Display for Backtrace {}`
in `library/std/src/backtrace.rs`.

Without this addition, the seccomp violation of the SYS_getcwd (79)
hinders the proper error message including a full backtrace from showing
up. This annoying behaviour already delayed many debugging efforts. With
this fix, things just work. The new syscall itself should be pretty
harmless for normal operation.

```
thread 'vmm' panicked at virtio-devices/src/rng.rs:224:9:
Yikes, things went horribly wrong!

==== Possible seccomp violation ====
Try running with `strace -ff` to identify the cause and open an issue: https://github.com/cloud-hypervisor/cloud-hypervisor/issues/new
[1]    287683 invalid system call (core dumped)  RUST_BACKTRACE=full cargo run --bin cloud-hypervisor -- --api-socket  --kerne
```

```
thread 'vmm' panicked at virtio-devices/src/rng.rs:224:9:
Yikes, things went horribly wrong!
stack backtrace:
   0:     0x557d91286b62 - std::backtrace_rs::backtrace::libunwind::trace::hc20b48b31ee52608
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/../../backtrace/src/backtrace/libunwind.rs:117:9
   1:     0x557d91286b62 - std::backtrace_rs::backtrace::trace_unsynchronized::h5d207cd20f193d88
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/../../backtrace/src/backtrace/mod.rs:66:14

...

  67:                0x0 - <unknown>
Error: Cloud Hypervisor exited with the following error:
  Failed to join on VMM thread: Any { .. }

Debug Info: ThreadJoin(Any { .. })
```

- add any panic, for example into the create or drop function of a
  device
- add --seccomp=true|log to analyze the situation

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-26 20:50:57 +00:00
dependabot[bot]
2cb8c41adc build: Bump remain from 0.2.14 to 0.2.15
Bumps [remain](https://github.com/dtolnay/remain) from 0.2.14 to 0.2.15.
- [Release notes](https://github.com/dtolnay/remain/releases)
- [Commits](https://github.com/dtolnay/remain/compare/0.2.14...0.2.15)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-26 00:37:52 +00:00
Philipp Schuster
48b67ed03b net_util: code readability improvements
Small cleanup to improve code readability.
Specifically, refactoring a huge loop body into
a function call.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-25 16:22:16 +00:00
Philipp Schuster
e0f0065cbd net_util: improve Error types
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-25 16:22:16 +00:00
dependabot[bot]
1866a85a3d build: Bump zerocopy from 0.8.24 to 0.8.26
Bumps [zerocopy](https://github.com/google/zerocopy) from 0.8.24 to 0.8.26.
- [Release notes](https://github.com/google/zerocopy/releases)
- [Changelog](https://github.com/google/zerocopy/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/zerocopy/compare/v0.8.24...v0.8.26)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-25 10:07:20 +00:00
Hengqi Chen
8338fa642f net_util: Drop duplicated virtio_features_to_tap_offload
The virtio_features_to_tap_offload() defined in ctrl_queue.rs
is duplicated. Remove it and use the one defined in lib.rs
instead.

Signed-off-by: Hengqi Chen <hengqi.chen@gmail.com>
2025-06-24 17:43:22 +00:00
Wei Liu
a5287c6f67 build: Consolidate UUID crate to workspace
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-06-24 16:50:35 +00:00
Philipp Schuster
fe07617f5d misc: add __pycache__ to gitignore
Running `gitlint` locally produces a __pycache__ directory in
`scripts/gitlint/rules/`. It makes sense to exclude this directory.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-24 11:22:00 +00:00
dependabot[bot]
1820c22ba4 build: Bump cc from 1.2.23 to 1.2.27
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.23 to 1.2.27.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.23...cc-v1.2.27)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-24 04:25:02 +00:00
dependabot[bot]
f828e16d62 build: Bump syn from 2.0.87 to 2.0.104
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.87 to 2.0.104.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.87...2.0.104)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-24 02:37:24 +00:00
Demi Marie Obenour
24998c1672 vmm: do not treat libc::MAP_FAILED as a pointer
It will likely be safely rejected by the kernel, but it's still wrong.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-06-23 09:06:32 +00:00
Wei Liu
821f7994fc build: Bump UUID crate to 1.17.0
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-06-21 14:27:19 +00:00
Philipp Schuster
4182ef91e0 misc: remove once_cell; superseded by std::*
We now have types in the Rust standard library.
Dropping the dependency.

I found this by using the `clippy::pedantic` group.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-21 14:25:20 +00:00
Demi Marie Obenour
100c6d8142 docs: SGX virt changes are upstream
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-06-20 10:21:04 +00:00
Demi Marie Obenour
269976c7b3 block: Remove unnecessary pointer indirection
No functional change intended.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-06-20 10:21:04 +00:00
Demi Marie Obenour
8769b78bf3 arch: x86_64: Require that types to be checksummed are ByteValued
Checksumming a type that has padding would use the padding in the
checksum, which is definitely wrong and is often unsound.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
2025-06-20 10:21:04 +00:00
Philipp Schuster
a991de9955 vmm: streamline Display impl of Error types
Streamlines the code base by using thiserror's #[error] attribute
consistently for implementing `Display`.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-20 10:19:35 +00:00
dependabot[bot]
47c9ddfa7e build: Bump hashbrown from 0.15.2 to 0.15.4
Bumps [hashbrown](https://github.com/rust-lang/hashbrown) from 0.15.2 to 0.15.4.
- [Release notes](https://github.com/rust-lang/hashbrown/releases)
- [Changelog](https://github.com/rust-lang/hashbrown/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/hashbrown/commits/v0.15.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-17 01:49:45 +00:00
Bo Chen
2b05753716 ci: Update reference kernel to 'v6.12.8-20250613'
This bump also includes another release 'ch-release-v6.12.8-20250422'
that changed the naming convention of the released kernel binaries
[1]. As a result, few changes are made to our integration tests and test
scripts.

[1] https://github.com/cloud-hypervisor/linux/releases/tag/ch-release-v6.12.8-20250422

Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-06-16 17:59:22 +00:00
Yi Wang
80f4bfac00 block: keep lifetime consistent from input to output
Cargo fuzz build report an error:
error: lifetime flowing from input to output with different syntax can be confusing
   --> /home/runner/work/cloud-hypervisor/cloud-hypervisor/block/src/lib.rs:747:13
    |
747 |     fn file(&mut self) -> MutexGuard<F>;
    |             ^^^^^^^^^     ------------- the lifetime gets resolved as `'_`
    |             |
    |             this lifetime flows to the output

error: lifetime flowing from input to output with different syntax can be confusing
  --> /home/runner/work/cloud-hypervisor/cloud-hypervisor/block/src/async_io.rs:68:11
   |
68 |     fn fd(&mut self) -> BorrowedDiskFd;
   |           ^^^^^^^^^     -------------- the lifetime gets resolved as `'_`
   |           |
   |           this lifetime flows to the output

Signed-off-by: Yi Wang <foxywang@tencent.com>
2025-06-16 06:25:57 +00:00
dependabot[bot]
b26b09ec0c build: Bump crate-ci/typos from 1.32.0 to 1.33.1
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.32.0 to 1.33.1.
- [Release notes](https://github.com/crate-ci/typos/releases)
- [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crate-ci/typos/compare/v1.32.0...v1.33.1)

---
updated-dependencies:
- dependency-name: crate-ci/typos
  dependency-version: 1.33.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-14 00:42:13 +00:00
dependabot[bot]
39a6664e62 build: Bump event-listener from 5.3.1 to 5.4.0
Bumps [event-listener](https://github.com/smol-rs/event-listener) from 5.3.1 to 5.4.0.
- [Release notes](https://github.com/smol-rs/event-listener/releases)
- [Changelog](https://github.com/smol-rs/event-listener/blob/master/CHANGELOG.md)
- [Commits](https://github.com/smol-rs/event-listener/compare/v5.3.1...v5.4.0)

---
updated-dependencies:
- dependency-name: event-listener
  dependency-version: 5.4.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-13 23:58:27 +00:00
Philipp Schuster
190a11f212 ch-remote: also pretty-print remote server errors
Remote server errors are transferred as raw HTTP body. This way,
we lose the nested structured error information.

This is an attempt to retrieve the errors from the HTTP response
and to align the output with the normal error output.

For example, this produces the following chain of errors. Note
that everything after level 0 was retrieved from the HTTP server
response:

```
Error: ch-remote exited with the following chain of errors:
  0: http client error
  1: Server responded with InternalServerError
  2: Error from API
  3: The disk could not be added to the VM
  4: Failed to validate config
  5: Identifier disk1 is not unique

Debug Info: HttpApiClient(ServerResponse(InternalServerError, Some("Error from API<br>The disk could not be added to the VM<br>Failed to validate config<br>Identifier disk1 is not unique")))
```

In case the JSON can't be parsed properly, ch-remote will print:

```
Error: ch-remote exited with the following chain of errors:
  0: http client error
  X: Can't get remote's error messages from JSON response: EOF while parsing a value at line 1 column 0: body=''

Debug Info: HttpApiClient(ServerResponse(InternalServerError, Some("")))
```

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
6ea132708c vmm: use Error trait directly with Note for compiler bug
While working on this, I found a subtle but severe compiler bug [0].
To fight the bug with explicitness rather than implicitness (to
prevent weird stuff in the future), this change is beneficial.

The bug is at least in Rust stable 1.34..1.87.

[0]: https://github.com/rust-lang/rust/issues/141673

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
060c9de07f vmm: introduce nice error messages on exit (CHV and ch-remote)
With the foundations of each error type implementing std::error::Error,
we can now nicely walk the `.source()` chain and print an error trace.

This commit introduces improved user-facing error printing when:
- Cloud Hypervisor fails with an error
- ch-remote fails (client error)
- ch-remote fails (remote error)

The additional context is a clear improvement in UX for both users and
developers. In the following example, the new behaviour is shown for
a direct invocation of Cloud Hypervisor leading to a failure. This
looks similar for ch-remote.

```
Old Style
`target/release/cloud-hypervisor --api-socket /tmp/chv2.sock --kernel /etc/bootitems/linux/kernel_minimal/stable.bzImage --cmdline console=ttyS0 --serial tty --console off --disk path=img.raw --initramfs /etc/bootitems/linux/initrd_minimal/default`

Error booting VM: VmBoot(LockingError(BlockError(LockDiskImage(AlreadyLocked)))
```

```
`target/release/cloud-hypervisor --api-socket /tmp/chv2.sock --kernel /etc/bootitems/linux/kernel_minimal/stable.bzImage --cmdline console=ttyS0 --serial tty --console off --disk path=img.raw --initramfs
/etc/bootitems/linux/initrd_minimal/default`

Error: Cloud Hypervisor exited with the following chain of errors:
  0: Error booting VM
  1: The VM could not boot
  2: Error locking disk images: Another instance likely holds a lock
  3: Cannot lock images of all block devices
  4: Failed to get Write lock for disk image: ./img.raw
  5: The file is already locked

Debug Info: VmBoot(VmBoot(LockingError(DiskLockError(LockDiskImage { error: AlreadyLocked, lock_type: Write, path: "./raw_disk.bin" })))
```

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
1433763d40 misc: virtio-devices: manual adjustment of special case
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
30ee2c129d misc: vm-migration: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
9bf15ed280 misc: vhost_user_net: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
ed63b352d1 misc: vhost_user_block: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
8e2973fe7c misc: virtio-devices: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
3541cebbf1 misc: tpm: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
1ede418dcc misc: test_infra: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
1b03e59152 misc: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
8f56de713b misc: rate_limiter: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
2100d8c30f misc: performance-metrics: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
a3692144f0 misc: pci: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
192b19c060 misc: option_parser: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
67896333e3 misc: net_util: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
72c8178335 misc: hypervisor: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
1b91aa8ef3 misc: devices: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
5711f31995 misc: ch-remote: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
aebbd1aecd misc: block: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
06a868cb85 misc: arch: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
3f3489e38e misc: api_client: streamline error Display::fmt()
The changes were mostly automatically applied using the Python
script mentioned in the first commit of this series.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
d7edd9d51f misc: vmm: streamline error Display::fmt()
The changes were mostly automatically applied using the following
Python script:

```python
import os, re

for root, _, files in os.walk("."):
    for f in files:
        if not f.endswith(".rs"):
            continue
        p = os.path.join(root, f)
        with open(p, "r", encoding="utf-8") as file:
            lines = file.readlines()
        changed = False
        for i in range(len(lines) - 1):
            if re.search(r'#\[error\(".*: \{0[^}]*\}"\)\]', lines[i]) and "#[source]" in lines[i + 1].strip():
                lines[i] = re.sub(r': \{0[^}]*\}"\)\]', '")]', lines[i])
                changed = True
        if changed:
            with open(p, "w", encoding="utf-8") as file:
                file.writelines(lines)
            print("Fixed:", p)
```

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com

# Conflicts:
#	vmm/src/api/http/mod.rs
2025-06-13 19:55:54 +00:00
Philipp Schuster
4987d63b6a vmm: fix typo
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:55:54 +00:00
Philipp Schuster
53e9c94e68 tests: cleanup test_util module
We can remove the `tests` module as the entire file is only
available when running tests.

Follow-up of #7130 / 1f13165fae.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-13 19:02:39 +00:00
dependabot[bot]
9d8bda20e5 build: Bump object from 0.36.5 to 0.36.7
Bumps [object](https://github.com/gimli-rs/object) from 0.36.5 to 0.36.7.
- [Changelog](https://github.com/gimli-rs/object/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gimli-rs/object/compare/0.36.5...0.36.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-13 00:25:40 +00:00
dependabot[bot]
63d7f562e5 build: Bump houseabsolute/actions-rust-cross from 0 to 1
Bumps [houseabsolute/actions-rust-cross](https://github.com/houseabsolute/actions-rust-cross) from 0 to 1.
- [Release notes](https://github.com/houseabsolute/actions-rust-cross/releases)
- [Changelog](https://github.com/houseabsolute/actions-rust-cross/blob/v1/Changes.md)
- [Commits](https://github.com/houseabsolute/actions-rust-cross/compare/v0...v1)

---
updated-dependencies:
- dependency-name: houseabsolute/actions-rust-cross
  dependency-version: '1'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-13 00:09:49 +00:00
Philipp Schuster
9bd9c0cb71 misc: replace manual From<T> for *Error with #[from]
This is a small simplification we can use since we use `thiserror`
anyway. Note that `#[from]` implies `#[source]` [0].

[0]: https://docs.rs/thiserror/2.0.12/thiserror/index.html

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-12 15:55:54 +00:00
Philipp Schuster
d594107c0d ch-remote: sort all commands and args alphabetically
Having them sorted alphabetically makes more sense since there are
already many, and the list is growing. This improves the UX for users
and developers.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-12 13:53:55 +00:00
Philipp Schuster
1f13165fae tests: prepare common test infrastructure for CLI args
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-12 13:53:55 +00:00
Philipp Schuster
12493db144 ch-remote: move Args and Commands creation to function
This enables to sort them alphabetically in a next step, similar
to #6988 / c37c639f3f.

[0] https://github.com/cloud-hypervisor/cloud-hypervisor/pull/6988

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-12 13:53:55 +00:00
Jinrong Liang
f151fdb16f vmm: config: Add tests for check block serial length
Signed-off-by: Jinrong Liang <cloudliang@tencent.com>
2025-06-12 13:51:52 +00:00
Jinrong Liang
bb6ca56fb0 vmm: config: Add DiskConfig check for device serial length
Signed-off-by: Jinrong Liang <cloudliang@tencent.com>
2025-06-12 13:51:52 +00:00
dependabot[bot]
a336533389 build: Bump actions/setup-python from 1 to 5
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 1 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v1...v5)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-12 00:17:53 +00:00
dependabot[bot]
c4b6ed1077 build: Bump getrandom from 0.3.1 to 0.3.3
Bumps [getrandom](https://github.com/rust-random/getrandom) from 0.3.1 to 0.3.3.
- [Changelog](https://github.com/rust-random/getrandom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/getrandom/compare/v0.3.1...v0.3.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-12 00:01:56 +00:00
dependabot[bot]
3e8dda4e7d build: Bump softprops/action-gh-release from 1 to 2
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: '2'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-11 00:57:58 +00:00
dependabot[bot]
e9edb2e51c build: Bump adler2 from 2.0.0 to 2.0.1
Bumps [adler2](https://github.com/oyvindln/adler2) from 2.0.0 to 2.0.1.
- [Changelog](https://github.com/oyvindln/adler2/blob/main/CHANGELOG.md)
- [Commits](https://github.com/oyvindln/adler2/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-10 23:48:15 +00:00
dependabot[bot]
0798effcc6 build: Bump async-io from 2.3.3 to 2.4.1
Bumps [async-io](https://github.com/smol-rs/async-io) from 2.3.3 to 2.4.1.
- [Release notes](https://github.com/smol-rs/async-io/releases)
- [Changelog](https://github.com/smol-rs/async-io/blob/master/CHANGELOG.md)
- [Commits](https://github.com/smol-rs/async-io/compare/v2.3.3...v2.4.1)

---
updated-dependencies:
- dependency-name: async-io
  dependency-version: 2.4.1
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-10 17:42:39 +00:00
dependabot[bot]
6079791bca build: Bump fsfe/reuse-action from 3 to 5
Bumps [fsfe/reuse-action](https://github.com/fsfe/reuse-action) from 3 to 5.
- [Release notes](https://github.com/fsfe/reuse-action/releases)
- [Commits](https://github.com/fsfe/reuse-action/compare/v3...v5)

---
updated-dependencies:
- dependency-name: fsfe/reuse-action
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-10 17:26:50 +00:00
Philipp Schuster
ff2330defe ci: activate dependabot for github-actions
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-10 15:52:12 +00:00
Philipp Schuster
12b72ba3c1 ci: bump typos
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-06-10 15:52:12 +00:00
dependabot[bot]
92f9e20f57 build: Bump itoa from 1.0.11 to 1.0.15
Bumps [itoa](https://github.com/dtolnay/itoa) from 1.0.11 to 1.0.15.
- [Release notes](https://github.com/dtolnay/itoa/releases)
- [Commits](https://github.com/dtolnay/itoa/compare/1.0.11...1.0.15)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-10 00:38:46 +00:00
Gauthier Jolly
3d78662498 block: virtio-blk: report IO errors to the guest
Instead of exiting on IO errors, report the errors to the guest with
VIRTIO_BLK_S_IOERR. For example, the guest kernel will log something
similar to this if the nbd behind /dev/vdc is unexpectedly disconnected:

[  166.033957] I/O error, dev vdc, sector 264 op 0x1:(WRITE) flags 0x9800 phys_seg 1 prio class 2
[  166.035083] Aborting journal on device vdc-8.
[  166.037307] Buffer I/O error on dev vdc, logical block 9, lost sync page write
[  166.038471] JBD2: I/O error when updating journal superblock for vdc-8.
[...]
[  174.234470] EXT4-fs (vdc): I/O error while writing superblock

In case the rootfs is not located on the affected block device, this
will not crash the guest.

Fixes: #6995

Signed-off-by: Gauthier Jolly <contact@gjolly.fr>
2025-06-09 16:48:07 +00:00
Jinank Jain
2bc8d51a60 misc: Fix missing lifetime syntax clippy warning
This was caught by the nightly compiler during cargo fuzz build.

error: lifetime flowing from input to output with different syntax can be confusing
   --> /home/runner/work/cloud-hypervisor/cloud-hypervisor/hypervisor/src/arch/x86/emulator/mod.rs:493:26
    |
493 |     pub fn new(platform: &mut dyn PlatformEmulator<CpuState = T>) -> Emulator<T> {
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^     ----------- the lifetime gets resolved as `'_`
    |                          |
    |                          this lifetime flows to the output
    |
    = note: `-D mismatched-lifetime-syntaxes` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(mismatched_lifetime_syntaxes)]`
help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
    |
493 |     pub fn new(platform: &mut dyn PlatformEmulator<CpuState = T>) -> Emulator<'_, T> {

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-06-09 11:19:11 +00:00
Jinank Jain
51002f2bae build: Bump zbus from 4.4.0 to 5.7.1
Along with this also fix some API incompatibilities issues.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-06-09 11:19:11 +00:00
Nuno Das Neves
59e11f1b0b hypervisor: mshv: fix advance_rip_update_rax() helper
The dirty bit for the GP registers must be set for the hypervisor to
update them.

Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
2025-06-05 20:23:30 +00:00
Jinank Jain
fc01e4cbec fuzz: Update Cargo.lock for fuzz build
It seems like multiple packages inside Cargo.lock are outdated.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-06-04 17:04:07 +00:00
Jinank Jain
3f8186f627 hypervisor: Fix issues with nightly compilers
cargo fuzz build complaints about some un-used function in the
instruction emultator. Silence the warning by allowing dead code
generation.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-06-04 17:04:07 +00:00
Jinank Jain
6f56ef9a36 misc: Move zerocopy to workspace dependencies
Since it is used by multiple components at this point, it is better to
move it to workspace level dependency.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-06-04 17:04:07 +00:00
Philipp Schuster
d6ed74b5b8 tests: fix vCPU test relying on specific Display formatting
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-30 19:07:15 +00:00
dependabot[bot]
7fbe94a227 build: Bump quote from 1.0.36 to 1.0.40
Bumps [quote](https://github.com/dtolnay/quote) from 1.0.36 to 1.0.40.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.36...1.0.40)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-30 00:37:50 +00:00
dependabot[bot]
4a1809f596 build: Bump glob from 0.3.1 to 0.3.2
Bumps [glob](https://github.com/rust-lang/glob) from 0.3.1 to 0.3.2.
- [Release notes](https://github.com/rust-lang/glob/releases)
- [Changelog](https://github.com/rust-lang/glob/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/glob/compare/0.3.1...v0.3.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-28 23:45:19 +00:00
Yi Wang
0a4169801b arch: x86_64: lower the cpuid log level
There are a little many cpuid logs now. When starting a vm with
64 vcpu, we can get more than four thousand INFO messages:

cat vm1.log |grep 'arch/src/x86_64/mod.rs:891' |wc -l
4352

Signed-off-by: Yi Wang <foxywang@tencent.com>
2025-05-28 17:32:22 +00:00
Philipp Schuster
20296e909a misc: streamline thiserror cargo dep
As almost every sub crate depends on thiserror, lets upgrade it to a
workspace dependency.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-28 17:24:34 +00:00
dependabot[bot]
24a6a1805b build: Bump crc-any from 2.4.4 to 2.5.0
Bumps [crc-any](https://github.com/magiclen/crc-any) from 2.4.4 to 2.5.0.
- [Commits](https://github.com/magiclen/crc-any/compare/v2.4.4...v2.5.0)

---
updated-dependencies:
- dependency-name: crc-any
  dependency-version: 2.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-28 00:18:12 +00:00
dependabot[bot]
dd7318e839 build: Bump crossbeam-utils from 0.8.20 to 0.8.21
Bumps [crossbeam-utils](https://github.com/crossbeam-rs/crossbeam) from 0.8.20 to 0.8.21.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-utils-0.8.20...crossbeam-utils-0.8.21)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-27 00:01:50 +00:00
dependabot[bot]
37444c4bab build: Bump backtrace from 0.3.74 to 0.3.75
Bumps [backtrace](https://github.com/rust-lang/backtrace-rs) from 0.3.74 to 0.3.75.
- [Release notes](https://github.com/rust-lang/backtrace-rs/releases)
- [Commits](https://github.com/rust-lang/backtrace-rs/compare/0.3.74...0.3.75)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-24 00:30:20 +00:00
160 changed files with 2448 additions and 2335 deletions

View File

@@ -16,3 +16,8 @@ updates:
allow:
- dependency-type: direct
- dependency-type: indirect
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 1

View File

@@ -8,7 +8,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.x
uses: actions/setup-python@v1
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Check DCO

View File

@@ -13,7 +13,7 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Set up Python 3.10
uses: actions/setup-python@v3
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install dependencies

View File

@@ -50,88 +50,97 @@ jobs:
git checkout ${{ github.sha }}
- name: Clippy (kvm)
uses: actions-rs/cargo@v1
uses: houseabsolute/actions-rust-cross@v1
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --no-default-features --tests --examples --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Clippy (mshv)
uses: actions-rs/cargo@v1
uses: houseabsolute/actions-rust-cross@v1
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "mshv" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --no-default-features --tests --examples --features "mshv" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Clippy (mshv + kvm)
uses: actions-rs/cargo@v1
uses: houseabsolute/actions-rust-cross@v1
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --no-default-features --tests --examples --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Clippy (default features)
uses: actions-rs/cargo@v1
uses: houseabsolute/actions-rust-cross@v1
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --examples -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --tests --examples -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Clippy (default features + guest_debug)
uses: actions-rs/cargo@v1
uses: houseabsolute/actions-rust-cross@v1
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --examples --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --tests --examples --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Clippy (default features + pvmemcontrol)
uses: actions-rs/cargo@v1
uses: houseabsolute/actions-rust-cross@v1
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --examples --features "pvmemcontrol" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --tests --examples --features "pvmemcontrol" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Clippy (default features + tracing)
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --tests --examples --features "tracing" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Clippy (mshv)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
uses: actions-rs/cargo@v1
uses: houseabsolute/actions-rust-cross@v1
with:
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "mshv" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Clippy (mshv + kvm)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
uses: actions-rs/cargo@v1
with:
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --tests --examples --features "tracing" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Clippy (sev_snp)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
uses: actions-rs/cargo@v1
uses: houseabsolute/actions-rust-cross@v1
with:
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "sev_snp" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --no-default-features --tests --examples --features "sev_snp" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Clippy (igvm)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
uses: actions-rs/cargo@v1
uses: houseabsolute/actions-rust-cross@v1
with:
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "igvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --no-default-features --tests --examples --features "igvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Clippy (kvm + tdx)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
uses: actions-rs/cargo@v1
uses: houseabsolute/actions-rust-cross@v1
with:
command: clippy
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "tdx,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
cross-version: 3e0957637b49b1bbced23ad909170650c5b70635
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
args: --locked --all --all-targets --no-default-features --tests --examples --features "tdx,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Check build did not modify any files
run: test -z "$(git status --porcelain)"
@@ -143,4 +152,4 @@ jobs:
steps:
- uses: actions/checkout@v4
# Executes "typos ."
- uses: crate-ci/typos@v1.16.11
- uses: crate-ci/typos@v1.34.0

View File

@@ -39,7 +39,7 @@ jobs:
matrix.platform.target == 'x86_64-unknown-linux-gnu'
run: rsync -rv --exclude=.git . ../cloud-hypervisor-${{ github.event.ref }}
- name: Build ${{ matrix.platform.target }}
uses: houseabsolute/actions-rust-cross@v0
uses: houseabsolute/actions-rust-cross@v1
with:
command: build
target: ${{ matrix.platform.target }}
@@ -86,7 +86,7 @@ jobs:
name: cloud-hypervisor-${{ github.event.ref }}.tar.xz
- name: Create GitHub Release
if: github.event_name == 'create' && github.event.ref_type == 'tag'
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
draft: true
files: |

View File

@@ -9,4 +9,4 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: REUSE Compliance Check
uses: fsfe/reuse-action@v3
uses: fsfe/reuse-action@v5

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@
/rpm/SOURCES
/.vscode
/vendor
__pycache__

View File

@@ -7,15 +7,17 @@ extend-exclude = [
]
[default.extend-words]
ba = "ba"
CLASSE = "CLASSE"
conectix = "conectix"
Dake = "Dake"
EXTINT = "EXTINT"
INOUT = "INOUT"
SME = "SME" # Secure Memory Encryption
THR = "THR" # Transmitter Holding Register
TRANSLATER = "TRANSLATER"
ba = "ba"
conectix = "conectix"
liness = "liness"
outout = "outout"
TRANSLATER = "TRANSLATER"
[default.extend-identifiers]
fo = "fo"

580
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ edition = "2021"
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
license = "Apache-2.0 AND BSD-3-Clause"
name = "cloud-hypervisor"
version = "46.0.0"
version = "47.0.0"
# Minimum buildable version:
# Keep in sync with version in .github/workflows/build.yaml
# Policy on MSRV (see #4318):
@@ -33,6 +33,7 @@ anyhow = "1.0.94"
api_client = { path = "api_client" }
clap = { version = "4.5.13", features = ["string"] }
dhat = { version = "0.3.3", optional = true }
env_logger = { workspace = true }
epoll = "4.3.3"
event_monitor = { path = "event_monitor" }
hypervisor = { path = "hypervisor" }
@@ -42,18 +43,17 @@ option_parser = { path = "option_parser" }
seccompiler = { workspace = true }
serde_json = { workspace = true }
signal-hook = "0.3.18"
thiserror = "2.0.6"
thiserror = { workspace = true }
tpm = { path = "tpm" }
tracer = { path = "tracer" }
vm-memory = { workspace = true }
vmm = { path = "vmm" }
vmm-sys-util = { workspace = true }
zbus = { version = "4.4.0", optional = true }
zbus = { version = "5.7.1", optional = true }
[dev-dependencies]
dirs = "6.0.0"
net_util = { path = "net_util" }
once_cell = "1.20.2"
serde_json = { workspace = true }
test_infra = { path = "test_infra" }
wait-timeout = "0.2.0"
@@ -104,22 +104,22 @@ members = [
[workspace.dependencies]
# rust-vmm crates
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
kvm-bindings = "0.10.0"
kvm-ioctls = "0.19.1"
kvm-bindings = "0.12.0"
kvm-ioctls = "0.22.0"
linux-loader = "0.13.0"
mshv-bindings = "0.5.1"
mshv-ioctls = "0.5.1"
mshv-bindings = "0.5.2"
mshv-ioctls = "0.5.2"
seccompiler = "0.5.0"
vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main" }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" }
vhost = { git = "https://github.com/rust-vmm/vhost", rev = "d983ae0" }
vhost-user-backend = { git = "https://github.com/rust-vmm/vhost", rev = "d983ae0" }
virtio-bindings = "0.2.4"
virtio-queue = "0.14.0"
vfio-bindings = { version = "0.5.0", default-features = false }
vfio-ioctls = { version = "0.5.0", default-features = false }
vfio_user = { version = "0.1.0", default-features = false }
vhost = { version = "0.14.0", default-features = false }
vhost-user-backend = { version = "0.20.0", default-features = false }
virtio-bindings = "0.2.6"
virtio-queue = "0.16.0"
vm-fdt = { git = "https://github.com/rust-vmm/vm-fdt", branch = "main" }
vm-memory = "0.16.1"
vmm-sys-util = "0.12.1"
vmm-sys-util = "0.14.0"
# igvm crates
# TODO: bump to 0.3.5 release
@@ -128,3 +128,9 @@ igvm_defs = { git = "https://github.com/microsoft/igvm", branch = "main" }
# serde crates
serde_json = "1.0.120"
# other crates
env_logger = "0.11.8"
thiserror = "2.0.12"
uuid = { version = "1.17.0" }
zerocopy = { version = "0.8.26", default-features = false }

View File

@@ -5,5 +5,5 @@ name = "api_client"
version = "0.1.0"
[dependencies]
thiserror = "2.0.6"
thiserror = { workspace = true }
vmm-sys-util = { workspace = true }

View File

@@ -11,18 +11,24 @@ use vmm_sys_util::sock_ctrl_msg::ScmSocket;
#[derive(Debug, Error)]
pub enum Error {
#[error("Error writing to or reading from HTTP socket: {0}")]
#[error("Error writing to or reading from HTTP socket")]
Socket(#[source] std::io::Error),
#[error("Error sending file descriptors: {0}")]
#[error("Error sending file descriptors")]
SocketSendFds(#[source] vmm_sys_util::errno::Error),
#[error("Error parsing HTTP status code: {0}")]
#[error("Error parsing HTTP status code")]
StatusCodeParsing(#[source] std::num::ParseIntError),
#[error("HTTP output is missing protocol statement")]
MissingProtocol,
#[error("Error parsing HTTP Content-Length field: {0}")]
#[error("Error parsing HTTP Content-Length field")]
ContentLengthParsing(#[source] std::num::ParseIntError),
#[error("Server responded with an error: {0:?}: {1:?}")]
ServerResponse(StatusCode, Option<String>),
#[error("Server responded with error {0:?}: {1:?}")]
ServerResponse(
StatusCode,
// TODO: Move `api` module from `vmm` to dedicated crate and use a common type definition
Option<
String, /* Untyped: Currently Vec<String> of error messages from top to root cause */
>,
),
}
#[derive(Clone, Copy, Debug)]

View File

@@ -18,10 +18,9 @@ libc = "0.2.167"
linux-loader = { workspace = true, features = ["bzimage", "elf", "pe"] }
log = "0.4.22"
serde = { version = "1.0.208", features = ["derive", "rc"] }
thiserror = "2.0.6"
uuid = "1.12.1"
thiserror = { workspace = true }
uuid = { workspace = true }
vm-memory = { workspace = true, features = ["backend-bitmap", "backend-mmap"] }
vm-migration = { path = "../vm-migration" }
vmm-sys-util = { workspace = true, features = ["with-serde"] }
[target.'cfg(any(target_arch = "aarch64", target_arch = "riscv64"))'.dependencies]

View File

@@ -81,7 +81,7 @@ pub trait DeviceInfoForFdt {
#[derive(Debug, Error)]
pub enum Error {
/// Failure in writing FDT in memory.
#[error("Failure in writing FDT in memory: {0}")]
#[error("Failure in writing FDT in memory")]
WriteFdtToMemory(#[source] GuestMemoryError),
}
type Result<T> = result::Result<T, Error>;

View File

@@ -32,7 +32,7 @@ pub enum Error {
SetupFdt,
/// Failed to write FDT to memory.
#[error("Failed to write FDT to memory: {0}")]
#[error("Failed to write FDT to memory")]
WriteFdtToMemory(#[source] fdt::Error),
/// Failed to create a GIC.
@@ -44,11 +44,11 @@ pub enum Error {
InitramfsAddress,
/// Error configuring the general purpose registers
#[error("Error configuring the general purpose registers: {0}")]
#[error("Error configuring the general purpose registers")]
RegsConfiguration(#[source] hypervisor::HypervisorCpuError),
/// Error configuring the MPIDR register
#[error("Error configuring the MPIDR register: {0}")]
#[error("Error configuring the MPIDR register")]
VcpuRegMpidr(#[source] hypervisor::HypervisorCpuError),
/// Error initializing PMU for vcpu
@@ -56,12 +56,6 @@ pub enum Error {
VcpuInitPmu,
}
impl From<Error> for super::Error {
fn from(e: Error) -> super::Error {
super::Error::PlatformSpecific(e)
}
}
#[derive(Debug, Copy, Clone)]
/// Specifies the entry point address where the guest must start
/// executing code.

View File

@@ -28,14 +28,14 @@ type GuestRegionMmap = vm_memory::GuestRegionMmap<vm_memory::bitmap::AtomicBitma
#[derive(Debug, Error)]
pub enum Error {
#[cfg(target_arch = "x86_64")]
#[error("Platform specific error (x86_64): {0}")]
PlatformSpecific(#[source] x86_64::Error),
#[error("Platform specific error (x86_64)")]
PlatformSpecific(#[from] x86_64::Error),
#[cfg(target_arch = "aarch64")]
#[error("Platform specific error (aarch64): {0:?}")]
PlatformSpecific(#[source] aarch64::Error),
#[error("Platform specific error (aarch64)")]
PlatformSpecific(#[from] aarch64::Error),
#[cfg(target_arch = "riscv64")]
#[error("Platform specific error (riscv64): {0:?}")]
PlatformSpecific(#[source] riscv64::Error),
#[error("Platform specific error (riscv64)")]
PlatformSpecific(#[from] riscv64::Error),
#[error("The memory map table extends past the end of guest memory")]
MemmapTablePastRamEnd,
#[error("Error writing memory map table to guest memory")]
@@ -46,7 +46,7 @@ pub enum Error {
StartInfoSetup,
#[error("Failed to compute initramfs address")]
InitramfsAddress,
#[error("Error writing module entry to guest memory: {0}")]
#[error("Error writing module entry to guest memory")]
ModlistSetup(#[source] vm_memory::GuestMemoryError),
#[error("RSDP extends past the end of guest memory")]
RsdpPastRamEnd,

View File

@@ -54,7 +54,7 @@ pub trait DeviceInfoForFdt {
#[derive(Debug, Error)]
pub enum Error {
/// Failure in writing FDT in memory.
#[error("Failure in writing FDT in memory: {0}")]
#[error("Failure in writing FDT in memory")]
WriteFdtToMemory(#[source] GuestMemoryError),
}
type Result<T> = result::Result<T, Error>;

View File

@@ -30,7 +30,7 @@ pub enum Error {
SetupFdt,
/// Failed to write FDT to memory.
#[error("Failed to write FDT to memory: {0}")]
#[error("Failed to write FDT to memory")]
WriteFdtToMemory(#[source] fdt::Error),
/// Failed to create a AIA.
@@ -42,16 +42,10 @@ pub enum Error {
InitramfsAddress,
/// Error configuring the general purpose registers
#[error("Error configuring the general purpose registers: {0}")]
#[error("Error configuring the general purpose registers")]
RegsConfiguration(#[source] hypervisor::HypervisorCpuError),
}
impl From<Error> for super::Error {
fn from(e: Error) -> super::Error {
super::Error::PlatformSpecific(e)
}
}
#[derive(Debug, Copy, Clone)]
/// Specifies the entry point address where the guest must start
/// executing code.

View File

@@ -132,35 +132,35 @@ pub struct CpuidConfig {
#[derive(Debug, Error)]
pub enum Error {
/// Error writing MP table to memory.
#[error("Error writing MP table to memory: {0}")]
#[error("Error writing MP table to memory")]
MpTableSetup(#[source] mptable::Error),
/// Error configuring the general purpose registers
#[error("Error configuring the general purpose registers: {0}")]
#[error("Error configuring the general purpose registers")]
RegsConfiguration(#[source] regs::Error),
/// Error configuring the special registers
#[error("Error configuring the special registers: {0}")]
#[error("Error configuring the special registers")]
SregsConfiguration(#[source] regs::Error),
/// Error configuring the floating point related registers
#[error("Error configuring the floating point related registers: {0}")]
#[error("Error configuring the floating point related registers")]
FpuConfiguration(#[source] regs::Error),
/// Error configuring the MSR registers
#[error("Error configuring the MSR registers: {0}")]
#[error("Error configuring the MSR registers")]
MsrsConfiguration(#[source] regs::Error),
/// Failed to set supported CPUs.
#[error("Failed to set supported CPUs: {0}")]
#[error("Failed to set supported CPUs")]
SetSupportedCpusFailed(#[source] anyhow::Error),
/// Cannot set the local interruption due to bad configuration.
#[error("Cannot set the local interruption due to bad configuration: {0}")]
#[error("Cannot set the local interruption due to bad configuration")]
LocalIntConfiguration(#[source] anyhow::Error),
/// Error setting up SMBIOS table
#[error("Error setting up SMBIOS table: {0}")]
#[error("Error setting up SMBIOS table")]
SmbiosSetup(#[source] smbios::Error),
/// Could not find any SGX EPC section
@@ -176,15 +176,15 @@ pub enum Error {
MissingSgxLaunchControlFeature,
/// Error getting supported CPUID through the hypervisor (kvm/mshv) API
#[error("Error getting supported CPUID through the hypervisor API: {0}")]
#[error("Error getting supported CPUID through the hypervisor API")]
CpuidGetSupported(#[source] HypervisorError),
/// Error populating CPUID with KVM HyperV emulation details
#[error("Error populating CPUID with KVM HyperV emulation details: {0}")]
#[error("Error populating CPUID with KVM HyperV emulation details")]
CpuidKvmHyperV(#[source] vmm_sys_util::fam::Error),
/// Error populating CPUID with CPU identification
#[error("Error populating CPUID with CPU identification: {0}")]
#[error("Error populating CPUID with CPU identification")]
CpuidIdentification(#[source] vmm_sys_util::fam::Error),
/// Error checking CPUID compatibility
@@ -192,16 +192,16 @@ pub enum Error {
CpuidCheckCompatibility,
// Error writing EBDA address
#[error("Error writing EBDA address: {0}")]
#[error("Error writing EBDA address")]
EbdaSetup(#[source] vm_memory::GuestMemoryError),
// Error getting CPU TSC frequency
#[error("Error getting CPU TSC frequency: {0}")]
#[error("Error getting CPU TSC frequency")]
GetTscFrequency(#[source] HypervisorCpuError),
/// Error retrieving TDX capabilities through the hypervisor (kvm/mshv) API
#[cfg(feature = "tdx")]
#[error("Error retrieving TDX capabilities through the hypervisor API: {0}")]
#[error("Error retrieving TDX capabilities through the hypervisor API")]
TdxCapabilities(#[source] HypervisorError),
/// Failed to configure E820 map for bzImage
@@ -209,12 +209,6 @@ pub enum Error {
E820Configuration,
}
impl From<Error> for super::Error {
fn from(e: Error) -> super::Error {
super::Error::PlatformSpecific(e)
}
}
pub fn get_x2apic_id(cpu_id: u32, topology: Option<(u8, u8, u8)>) -> u32 {
if let Some(t) = topology {
let thread_mask_width = u8::BITS - (t.0 - 1).leading_zeros();
@@ -888,7 +882,7 @@ pub fn configure_vcpu(
}
for c in &cpuid {
info!("{}", c);
debug!("{}", c);
}
vcpu.set_cpuid2(&cpuid)

View File

@@ -3,6 +3,8 @@
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file.
#![allow(non_camel_case_types)]
use vm_memory::ByteValued;
pub const MP_PROCESSOR: ::std::os::raw::c_uint = 0;
pub const MP_BUS: ::std::os::raw::c_uint = 1;
@@ -29,6 +31,13 @@ pub struct mpf_intel {
pub feature5: ::std::os::raw::c_uchar,
}
const _: () = assert!(::core::mem::size_of::<mpf_intel>() == 16);
// SAFETY: all members of this struct are plain integers
// and the sum of their sizes is the size of the struct, so
// padding and reserved values are not possible as there
// would be nowhere for them to exist.
unsafe impl ByteValued for mpf_intel {}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct mpc_table {
@@ -45,6 +54,19 @@ pub struct mpc_table {
pub reserved: ::std::os::raw::c_uint,
}
const _: () = {
assert!(::core::mem::size_of::<mpc_table>() == 4 + 2 + 1 + 1 + 8 + 12 + 4 + 2 + 2 + 4 + 4);
assert!(::core::mem::size_of::<::std::os::raw::c_uint>() == 4);
assert!(::core::mem::size_of::<::std::os::raw::c_ushort>() == 2);
assert!(::core::mem::size_of::<::std::os::raw::c_uchar>() == 1);
};
// SAFETY: all members of this struct are plain integers
// and the sum of their sizes is the size of the struct, so
// padding and reserved values are not possible as there
// would be nowhere for them to exist.
unsafe impl ByteValued for mpc_table {}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct mpc_cpu {
@@ -57,6 +79,13 @@ pub struct mpc_cpu {
pub reserved: [::std::os::raw::c_uint; 2usize],
}
const _: () = assert!(::core::mem::size_of::<mpc_cpu>() == 20);
// SAFETY: all members of this struct are plain integers
// and the sum of their sizes is the size of the struct, so
// padding and reserved values are not possible as there
// would be nowhere for them to exist.
unsafe impl ByteValued for mpc_cpu {}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct mpc_bus {
@@ -65,6 +94,13 @@ pub struct mpc_bus {
pub bustype: [::std::os::raw::c_uchar; 6usize],
}
const _: () = assert!(::core::mem::size_of::<mpc_bus>() == 8);
// SAFETY: all members of this struct are plain integers
// and the sum of their sizes is the size of the struct, so
// padding and reserved values are not possible as there
// would be nowhere for them to exist.
unsafe impl ByteValued for mpc_bus {}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct mpc_ioapic {
@@ -75,6 +111,13 @@ pub struct mpc_ioapic {
pub apicaddr: ::std::os::raw::c_uint,
}
const _: () = assert!(::core::mem::size_of::<mpc_ioapic>() == 8);
// SAFETY: all members of this struct are plain integers
// and the sum of their sizes is the size of the struct, so
// padding and reserved values are not possible as there
// would be nowhere for them to exist.
unsafe impl ByteValued for mpc_ioapic {}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct mpc_intsrc {
@@ -87,6 +130,13 @@ pub struct mpc_intsrc {
pub dstirq: ::std::os::raw::c_uchar,
}
const _: () = assert!(::core::mem::size_of::<mpc_intsrc>() == 8);
// SAFETY: all members of this struct are plain integers
// and the sum of their sizes is the size of the struct, so
// padding and reserved values are not possible as there
// would be nowhere for them to exist.
unsafe impl ByteValued for mpc_intsrc {}
pub const MP_IRQ_SOURCE_TYPES_MP_INT: ::std::os::raw::c_uint = 0;
pub const MP_IRQ_SOURCE_TYPES_MP_NMI: ::std::os::raw::c_uint = 1;
pub const MP_IRQ_SOURCE_TYPES_MP_EXT_INT: ::std::os::raw::c_uint = 3;
@@ -103,6 +153,13 @@ pub struct mpc_lintsrc {
pub destapiclint: ::std::os::raw::c_uchar,
}
const _: () = assert!(::core::mem::size_of::<mpc_lintsrc>() == 8);
// SAFETY: all members of this struct are plain integers
// and the sum of their sizes is the size of the struct, so
// padding and reserved values are not possible as there
// would be nowhere for them to exist.
unsafe impl ByteValued for mpc_lintsrc {}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct mpc_oemtable {
@@ -112,3 +169,10 @@ pub struct mpc_oemtable {
pub checksum: ::std::os::raw::c_uchar,
pub mpc: [::std::os::raw::c_uchar; 8usize],
}
const _: () = assert!(::core::mem::size_of::<mpc_oemtable>() == 16);
// SAFETY: all members of this struct are plain integers
// and the sum of their sizes is the size of the struct, so
// padding and reserved values are not possible as there
// would be nowhere for them to exist.
unsafe impl ByteValued for mpc_oemtable {}

View File

@@ -59,31 +59,31 @@ pub enum Error {
#[error("The MP table has too little address space to be stored")]
AddressOverflow,
/// Failure while zeroing out the memory for the MP table.
#[error("Failure while zeroing out the memory for the MP table: {0}")]
#[error("Failure while zeroing out the memory for the MP table")]
Clear(#[source] GuestMemoryError),
/// Number of CPUs exceeds the maximum supported CPUs
#[error("Number of CPUs exceeds the maximum supported CPUs")]
TooManyCpus,
/// Failure to write the MP floating pointer.
#[error("Failure to write the MP floating pointer: {0}")]
#[error("Failure to write the MP floating pointer")]
WriteMpfIntel(#[source] GuestMemoryError),
/// Failure to write MP CPU entry.
#[error("Failure to write MP CPU entry: {0}")]
#[error("Failure to write MP CPU entry")]
WriteMpcCpu(#[source] GuestMemoryError),
/// Failure to write MP ioapic entry.
#[error("Failure to write MP ioapic entry: {0}")]
#[error("Failure to write MP ioapic entry")]
WriteMpcIoapic(#[source] GuestMemoryError),
/// Failure to write MP bus entry.
#[error("Failure to write MP bus entry: {0}")]
#[error("Failure to write MP bus entry")]
WriteMpcBus(#[source] GuestMemoryError),
/// Failure to write MP interrupt source entry.
#[error("Failure to write MP interrupt source entry: {0}")]
#[error("Failure to write MP interrupt source entry")]
WriteMpcIntsrc(#[source] GuestMemoryError),
/// Failure to write MP local interrupt source entry.
#[error("Failure to write MP local interrupt source entry: {0}")]
#[error("Failure to write MP local interrupt source entry")]
WriteMpcLintsrc(#[source] GuestMemoryError),
/// Failure to write MP table header.
#[error("Failure to write MP table header: {0}")]
#[error("Failure to write MP table header")]
WriteMpcTable(#[source] GuestMemoryError),
}
@@ -106,7 +106,7 @@ const CPU_STEPPING: u32 = 0x600;
const CPU_FEATURE_APIC: u32 = 0x200;
const CPU_FEATURE_FPU: u32 = 0x001;
fn compute_checksum<T: Copy>(v: &T) -> u8 {
fn compute_checksum<T: Copy + ByteValued>(v: &T) -> u8 {
// 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;

View File

@@ -23,40 +23,40 @@ use crate::{EntryPoint, GuestMemoryMmap};
#[derive(Debug, Error)]
pub enum Error {
/// Failed to get SREGs for this CPU.
#[error("Failed to get SREGs for this CPU: {0}")]
#[error("Failed to get SREGs for this CPU")]
GetStatusRegisters(#[source] hypervisor::HypervisorCpuError),
/// Failed to set base registers for this CPU.
#[error("Failed to set base registers for this CPU: {0}")]
#[error("Failed to set base registers for this CPU")]
SetBaseRegisters(#[source] hypervisor::HypervisorCpuError),
/// Failed to configure the FPU.
#[error("Failed to configure the FPU: {0}")]
#[error("Failed to configure the FPU")]
SetFpuRegisters(#[source] hypervisor::HypervisorCpuError),
/// Setting up MSRs failed.
#[error("Setting up MSRs failed: {0}")]
#[error("Setting up MSRs failed")]
SetModelSpecificRegisters(#[source] hypervisor::HypervisorCpuError),
/// Failed to set SREGs for this CPU.
#[error("Failed to set SREGs for this CPU: {0}")]
#[error("Failed to set SREGs for this CPU")]
SetStatusRegisters(#[source] hypervisor::HypervisorCpuError),
/// Checking the GDT address failed.
#[error("Checking the GDT address failed")]
CheckGdtAddr,
/// Writing the GDT to RAM failed.
#[error("Writing the GDT to RAM failed: {0}")]
#[error("Writing the GDT to RAM failed")]
WriteGdt(#[source] GuestMemoryError),
/// Writing the IDT to RAM failed.
#[error("Writing the IDT to RAM failed: {0}")]
#[error("Writing the IDT to RAM failed")]
WriteIdt(#[source] GuestMemoryError),
/// Writing PDPTE to RAM failed.
#[error("Writing PDPTE to RAM failed: {0}")]
#[error("Writing PDPTE to RAM failed")]
WritePdpteAddress(#[source] GuestMemoryError),
/// Writing PDE to RAM failed.
#[error("Writing PDE to RAM failed: {0}")]
#[error("Writing PDE to RAM failed")]
WritePdeAddress(#[source] GuestMemoryError),
/// Writing PML4 to RAM failed.
#[error("Writing PML4 to RAM failed: {0}")]
#[error("Writing PML4 to RAM failed")]
WritePml4Address(#[source] GuestMemoryError),
/// Writing PML5 to RAM failed.
#[error("Writing PML5 to RAM failed: {0}")]
#[error("Writing PML5 to RAM failed")]
WritePml5Address(#[source] GuestMemoryError),
}

View File

@@ -33,7 +33,7 @@ pub enum Error {
#[error("Failure to write additional data to memory")]
WriteData,
/// Failure to parse uuid, uuid format may be error
#[error("Failure to parse uuid: {0}")]
#[error("Failure to parse uuid")]
ParseUuid(#[source] uuid::Error),
}

View File

@@ -13,11 +13,11 @@ use crate::GuestMemoryMmap;
#[derive(Error, Debug)]
pub enum TdvfError {
#[error("Failed read TDVF descriptor: {0}")]
#[error("Failed read TDVF descriptor")]
ReadDescriptor(#[source] std::io::Error),
#[error("Failed read TDVF descriptor offset: {0}")]
#[error("Failed read TDVF descriptor offset")]
ReadDescriptorOffset(#[source] std::io::Error),
#[error("Failed read GUID table: {0}")]
#[error("Failed read GUID table")]
ReadGuidTable(#[source] std::io::Error),
#[error("Invalid descriptor signature")]
InvalidDescriptorSignature,
@@ -25,9 +25,9 @@ pub enum TdvfError {
InvalidDescriptorSize,
#[error("Invalid descriptor version")]
InvalidDescriptorVersion,
#[error("Failed to write HOB details to guest memory: {0}")]
#[error("Failed to write HOB details to guest memory")]
GuestMemoryWriteHob(#[source] GuestMemoryError),
#[error("Failed to create Uuid: {0}")]
#[error("Failed to create Uuid")]
UuidCreation(#[source] uuid::Error),
}

View File

@@ -10,16 +10,16 @@ io_uring = ["dep:io-uring"]
[dependencies]
byteorder = "1.5.0"
crc-any = "2.4.4"
crc-any = "2.5.0"
io-uring = { version = "0.6.4", optional = true }
libc = "0.2.167"
log = "0.4.22"
remain = "0.2.14"
remain = "0.2.15"
serde = { version = "1.0.208", features = ["derive"] }
smallvec = "1.13.2"
thiserror = "2.0.6"
uuid = { version = "1.12.1", features = ["v4"] }
virtio-bindings = { workspace = true, features = ["virtio-v5_0_0"] }
thiserror = { workspace = true }
uuid = { workspace = true, features = ["v4"] }
virtio-bindings = { workspace = true }
virtio-queue = { workspace = true }
vm-memory = { workspace = true, features = [
"backend-atomic",

View File

@@ -13,10 +13,10 @@ use crate::DiskTopology;
#[derive(Error, Debug)]
pub enum DiskFileError {
/// Failed getting disk file size.
#[error("Failed getting disk file size: {0}")]
#[error("Failed getting disk file size")]
Size(#[source] std::io::Error),
/// Failed creating a new AsyncIo.
#[error("Failed creating a new AsyncIo: {0}")]
#[error("Failed creating a new AsyncIo")]
NewAsyncIo(#[source] std::io::Error),
}
@@ -65,19 +65,19 @@ pub trait DiskFile: Send {
///
/// The file descriptor is supposed to be used for `fcntl()` calls but no
/// other operation.
fn fd(&mut self) -> BorrowedDiskFd;
fn fd(&mut self) -> BorrowedDiskFd<'_>;
}
#[derive(Error, Debug)]
pub enum AsyncIoError {
/// Failed vectored reading from file.
#[error("Failed vectored reading from file: {0}")]
#[error("Failed vectored reading from file")]
ReadVectored(#[source] std::io::Error),
/// Failed vectored writing to file.
#[error("Failed vectored writing to file: {0}")]
#[error("Failed vectored writing to file")]
WriteVectored(#[source] std::io::Error),
/// Failed synchronizing file.
#[error("Failed synchronizing file: {0}")]
#[error("Failed synchronizing file")]
Fsync(#[source] std::io::Error),
}

View File

@@ -28,7 +28,7 @@ pub enum LockError {
#[error("The file is already locked")]
AlreadyLocked,
/// IO error.
#[error("The lock state could not be checked or set: {0}")]
#[error("The lock state could not be checked or set")]
Io(#[source] io::Error),
}

View File

@@ -34,7 +34,7 @@ impl DiskFile for FixedVhdDiskAsync {
) as Box<dyn AsyncIo>)
}
fn fd(&mut self) -> BorrowedDiskFd {
fn fd(&mut self) -> BorrowedDiskFd<'_> {
BorrowedDiskFd::new(self.0.as_raw_fd())
}
}

View File

@@ -34,7 +34,7 @@ impl DiskFile for FixedVhdDiskSync {
) as Box<dyn AsyncIo>)
}
fn fd(&mut self) -> BorrowedDiskFd {
fn fd(&mut self) -> BorrowedDiskFd<'_> {
BorrowedDiskFd::new(self.0.as_raw_fd())
}
}

View File

@@ -57,7 +57,7 @@ use vm_memory::{
};
use vm_virtio::{AccessPlatform, Translatable};
use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::{aio, ioctl_io_nr, ioctl_ioc_nr};
use vmm_sys_util::{aio, ioctl_io_nr};
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult};
use crate::vhdx::VhdxError;
@@ -79,21 +79,21 @@ pub enum Error {
DescriptorChainTooShort,
#[error("Guest gave us a descriptor that was too short to use")]
DescriptorLengthTooSmall,
#[error("Failed to detect image type: {0}")]
#[error("Failed to detect image type")]
DetectImageType(#[source] std::io::Error),
#[error("Failure in fixed vhd: {0}")]
#[error("Failure in fixed vhd")]
FixedVhdError(#[source] std::io::Error),
#[error("Getting a block's metadata fails for any reason")]
GetFileMetadata,
#[error("The requested operation would cause a seek beyond disk end")]
InvalidOffset,
#[error("Failure in qcow: {0}")]
#[error("Failure in qcow")]
QcowError(#[source] qcow::Error),
#[error("Failure in raw file: {0}")]
#[error("Failure in raw file")]
RawFileError(#[source] std::io::Error),
#[error("The requested operation does not support multiple descriptors")]
TooManyDescriptors,
#[error("Failure in vhdx: {0}")]
#[error("Failure in vhdx")]
VhdxError(#[source] VhdxError),
}
@@ -131,33 +131,33 @@ pub fn build_serial(disk_path: &Path) -> Vec<u8> {
#[derive(Error, Debug)]
pub enum ExecuteError {
#[error("Bad request: {0}")]
#[error("Bad request")]
BadRequest(#[source] Error),
#[error("Failed to flush: {0}")]
#[error("Failed to flush")]
Flush(#[source] io::Error),
#[error("Failed to read: {0}")]
#[error("Failed to read")]
Read(#[source] GuestMemoryError),
#[error("Failed to read_exact: {0}")]
#[error("Failed to read_exact")]
ReadExact(#[source] io::Error),
#[error("Failed to seek: {0}")]
#[error("Failed to seek")]
Seek(#[source] io::Error),
#[error("Failed to write: {0}")]
#[error("Failed to write")]
Write(#[source] GuestMemoryError),
#[error("Failed to write_all: {0}")]
#[error("Failed to write_all")]
WriteAll(#[source] io::Error),
#[error("Unsupported request: {0}")]
Unsupported(u32),
#[error("Failed to submit io uring: {0}")]
#[error("Failed to submit io uring")]
SubmitIoUring(#[source] io::Error),
#[error("Failed to get guest address: {0}")]
#[error("Failed to get guest address")]
GetHostAddress(#[source] GuestMemoryError),
#[error("Failed to async read: {0}")]
#[error("Failed to async read")]
AsyncRead(#[source] AsyncIoError),
#[error("Failed to async write: {0}")]
#[error("Failed to async write")]
AsyncWrite(#[source] AsyncIoError),
#[error("failed to async flush: {0}")]
#[error("failed to async flush")]
AsyncFlush(#[source] AsyncIoError),
#[error("Failed allocating a temporary buffer: {0}")]
#[error("Failed allocating a temporary buffer")]
TemporaryBufferAllocation(#[source] io::Error),
}
@@ -401,14 +401,20 @@ impl Request {
let mut iovecs: SmallVec<[libc::iovec; DEFAULT_DESCRIPTOR_VEC_SIZE]> =
SmallVec::with_capacity(self.data_descriptors.len());
for (data_addr, data_len) in &self.data_descriptors {
if *data_len == 0 {
for &(data_addr, data_len) in &self.data_descriptors {
let _: u32 = data_len; // compiler-checked documentation
const _: () = assert!(
core::mem::size_of::<u32>() <= core::mem::size_of::<usize>(),
"unsupported platform"
);
if data_len == 0 {
continue;
}
let mut top: u64 = u64::from(*data_len) / SECTOR_SIZE;
if u64::from(*data_len) % SECTOR_SIZE != 0 {
let mut top: u64 = u64::from(data_len) / SECTOR_SIZE;
if u64::from(data_len) % SECTOR_SIZE != 0 {
top += 1;
}
let data_len = data_len as usize;
top = top
.checked_add(sector)
.ok_or(ExecuteError::BadRequest(Error::InvalidOffset))?;
@@ -417,7 +423,7 @@ impl Request {
}
let origin_ptr = mem
.get_slice(*data_addr, *data_len as usize)
.get_slice(data_addr, data_len)
.map_err(ExecuteError::GetHostAddress)?
.ptr_guard();
@@ -426,8 +432,7 @@ impl Request {
// created with the correct alignment, and a copy from/to the
// origin buffer is performed, depending on the type of operation.
let iov_base = if (origin_ptr.as_ptr() as u64) % SECTOR_SIZE != 0 {
let layout =
Layout::from_size_align(*data_len as usize, SECTOR_SIZE as usize).unwrap();
let layout = Layout::from_size_align(data_len, SECTOR_SIZE as usize).unwrap();
// SAFETY: layout has non-zero size
let aligned_ptr = unsafe { alloc_zeroed(layout) };
if aligned_ptr.is_null() {
@@ -441,7 +446,7 @@ impl Request {
if request_type == RequestType::Out {
// SAFETY: destination buffer has been allocated with
// the proper size.
unsafe { std::ptr::copy(origin_ptr.as_ptr(), aligned_ptr, *data_len as usize) };
unsafe { std::ptr::copy(origin_ptr.as_ptr(), aligned_ptr, data_len) };
}
// Store both origin and aligned pointers for complete_async()
@@ -449,7 +454,7 @@ impl Request {
self.aligned_operations.push(AlignedOperation {
origin_ptr: origin_ptr.as_ptr() as u64,
aligned_ptr: aligned_ptr as u64,
size: *data_len as usize,
size: data_len,
layout,
});
@@ -460,7 +465,7 @@ impl Request {
let iovec = libc::iovec {
iov_base,
iov_len: *data_len as libc::size_t,
iov_len: data_len as libc::size_t,
};
iovecs.push(iovec);
}
@@ -744,7 +749,7 @@ where
Ok(())
}
fn file(&mut self) -> MutexGuard<F>;
fn file(&mut self) -> MutexGuard<'_, F>;
}
pub enum ImageType {

View File

@@ -36,23 +36,23 @@ const MAX_NESTING_DEPTH: u32 = 10;
#[sorted]
#[derive(Debug, Error)]
pub enum Error {
#[error("Backing file io error: {0}")]
#[error("Backing file io error")]
BackingFileIo(#[source] io::Error),
#[error("Backing file open error: {0}")]
#[error("Backing file open error")]
BackingFileOpen(#[source] Box<Error>),
#[error("Backing file name is too long: {0} bytes over")]
BackingFileTooLong(usize),
#[error("Compressed blocks not supported")]
CompressedBlocksNotSupported,
#[error("Failed to evict cache: {0}")]
#[error("Failed to evict cache")]
EvictingCache(#[source] io::Error),
#[error("File larger than max of {MAX_QCOW_FILE_SIZE}: {0}")]
FileTooBig(u64),
#[error("Failed to get file size: {0}")]
#[error("Failed to get file size")]
GettingFileSize(#[source] io::Error),
#[error("Failed to get refcount: {0}")]
#[error("Failed to get refcount")]
GettingRefcount(#[source] refcount::Error),
#[error("Failed to parse filename: {0}")]
#[error("Failed to parse filename")]
InvalidBackingFileName(#[source] str::Utf8Error),
#[error("Invalid cluster index")]
InvalidClusterIndex,
@@ -82,27 +82,27 @@ pub enum Error {
NotEnoughSpaceForRefcounts,
#[error("Failed to open file {0}")]
OpeningFile(#[source] io::Error),
#[error("Failed to read data: {0}")]
#[error("Failed to read data")]
ReadingData(#[source] io::Error),
#[error("Failed to read header: {0}")]
#[error("Failed to read header")]
ReadingHeader(#[source] io::Error),
#[error("Failed to read pointers: {0}")]
#[error("Failed to read pointers")]
ReadingPointers(#[source] io::Error),
#[error("Failed to read ref count block: {0}")]
#[error("Failed to read ref count block")]
ReadingRefCountBlock(#[source] refcount::Error),
#[error("Failed to read ref counts: {0}")]
#[error("Failed to read ref counts")]
ReadingRefCounts(#[source] io::Error),
#[error("Failed to rebuild ref counts: {0}")]
#[error("Failed to rebuild ref counts")]
RebuildingRefCounts(#[source] io::Error),
#[error("Refcount table offset past file end")]
RefcountTableOffEnd,
#[error("Too many clusters specified for refcount")]
RefcountTableTooLarge,
#[error("Failed to seek file: {0}")]
#[error("Failed to seek file")]
SeekingFile(#[source] io::Error),
#[error("Failed to set file size: {0}")]
#[error("Failed to set file size")]
SettingFileSize(#[source] io::Error),
#[error("Failed to set refcount refcount: {0}")]
#[error("Failed to set refcount refcount")]
SettingRefcountRefcount(#[source] io::Error),
#[error("Size too small for number of clusters")]
SizeTooSmallForNumberOfClusters,
@@ -114,9 +114,9 @@ pub enum Error {
UnsupportedRefcountOrder,
#[error("Unsupported version: {0}")]
UnsupportedVersion(u32),
#[error("Failed to write data: {0}")]
#[error("Failed to write data")]
WritingData(#[source] io::Error),
#[error("Failed to write header: {0}")]
#[error("Failed to write header")]
WritingHeader(#[source] io::Error),
}

View File

@@ -36,7 +36,7 @@ impl QcowRawFile {
}
/// Reads `count` 64 bit offsets and returns them as a vector.
/// `mask` optionally ands out some of the bits on the file.
/// `mask` optionally `&`s out some of the bits on the file.
pub fn read_pointer_table(
&mut self,
offset: u64,
@@ -55,7 +55,7 @@ impl QcowRawFile {
}
/// Reads a cluster's worth of 64 bit offsets and returns them as a vector.
/// `mask` optionally ands out some of the bits on the file.
/// `mask` optionally `&`s out some of the bits on the file.
pub fn read_pointer_cluster(&mut self, offset: u64, mask: Option<u64>) -> io::Result<Vec<u64>> {
let count = self.cluster_size / size_of::<u64>() as u64;
self.read_pointer_table(offset, count, mask)

View File

@@ -15,7 +15,7 @@ use crate::qcow::vec_cache::{CacheMap, Cacheable, VecCache};
#[derive(Debug, Error)]
pub enum Error {
/// `EvictingCache` - Error writing a refblock from the cache to disk.
#[error("Failed to write a refblock from the cache to disk: {0}")]
#[error("Failed to write a refblock from the cache to disk")]
EvictingRefCounts(#[source] io::Error),
/// `InvalidIndex` - Address requested isn't within the range of the disk.
#[error("Address requested is not within the range of the disk")]
@@ -27,7 +27,7 @@ pub enum Error {
#[error("New cluster needs to be allocated for refcounts")]
NeedNewCluster,
/// `ReadingRefCounts` - Error reading the file into the refcount cache.
#[error("Failed to read the file into the refcount cache: {0}")]
#[error("Failed to read the file into the refcount cache")]
ReadingRefCounts(#[source] io::Error),
}

View File

@@ -111,7 +111,7 @@ impl<T: Cacheable> CacheMap<T> {
self.map.get_mut(&index)
}
pub fn iter_mut(&mut self) -> IterMut<usize, T> {
pub fn iter_mut(&mut self) -> IterMut<'_, usize, T> {
self.map.iter_mut()
}

View File

@@ -39,7 +39,7 @@ impl DiskFile for QcowDiskSync {
Ok(Box::new(QcowSync::new(self.qcow_file.clone())) as Box<dyn AsyncIo>)
}
fn fd(&mut self) -> BorrowedDiskFd {
fn fd(&mut self) -> BorrowedDiskFd<'_> {
let lock = self.qcow_file.lock().unwrap();
BorrowedDiskFd::new(lock.as_raw_fd())
}
@@ -63,7 +63,7 @@ impl QcowSync {
}
impl AsyncAdaptor<QcowFile> for Arc<Mutex<QcowFile>> {
fn file(&mut self) -> MutexGuard<QcowFile> {
fn file(&mut self) -> MutexGuard<'_, QcowFile> {
self.lock().unwrap()
}
}

View File

@@ -47,7 +47,7 @@ impl DiskFile for RawFileDisk {
}
}
fn fd(&mut self) -> BorrowedDiskFd {
fn fd(&mut self) -> BorrowedDiskFd<'_> {
BorrowedDiskFd::new(self.file.as_raw_fd())
}
}

View File

@@ -50,7 +50,7 @@ impl DiskFile for RawFileDiskAio {
}
}
fn fd(&mut self) -> BorrowedDiskFd {
fn fd(&mut self) -> BorrowedDiskFd<'_> {
BorrowedDiskFd::new(self.file.as_raw_fd())
}
}

View File

@@ -44,7 +44,7 @@ impl DiskFile for RawFileDiskSync {
}
}
fn fd(&mut self) -> BorrowedDiskFd {
fn fd(&mut self) -> BorrowedDiskFd<'_> {
BorrowedDiskFd::new(self.file.as_raw_fd())
}
}

View File

@@ -26,19 +26,19 @@ mod vhdx_metadata;
#[sorted]
#[derive(Error, Debug)]
pub enum VhdxError {
#[error("Not a VHDx file: {0}")]
#[error("Not a VHDx file")]
NotVhdx(#[source] VhdxHeaderError),
#[error("Failed to parse VHDx header: {0}")]
#[error("Failed to parse VHDx header")]
ParseVhdxHeader(#[source] VhdxHeaderError),
#[error("Failed to parse VHDx metadata: {0}")]
#[error("Failed to parse VHDx metadata")]
ParseVhdxMetadata(#[source] VhdxMetadataError),
#[error("Failed to parse VHDx region entries: {0}")]
#[error("Failed to parse VHDx region entries")]
ParseVhdxRegionEntry(#[source] VhdxHeaderError),
#[error("Failed reading metadata: {0}")]
#[error("Failed reading metadata")]
ReadBatEntry(#[source] VhdxBatError),
#[error("Failed reading sector from disk: {0}")]
#[error("Failed reading sector from disk")]
ReadFailed(#[source] VhdxIoError),
#[error("Failed writing to sector on disk: {0}")]
#[error("Failed writing to sector on disk")]
WriteFailed(#[source] VhdxIoError),
}

View File

@@ -33,9 +33,9 @@ pub enum VhdxBatError {
InvalidBatEntry,
#[error("Invalid BAT entry count")]
InvalidEntryCount,
#[error("Failed to read BAT entry: {0}")]
#[error("Failed to read BAT entry")]
ReadBat(#[source] io::Error),
#[error("Failed to write BAT entry: {0}")]
#[error("Failed to write BAT entry")]
WriteBat(#[source] io::Error),
}

View File

@@ -39,7 +39,7 @@ impl DiskFile for VhdxDiskSync {
)
}
fn fd(&mut self) -> BorrowedDiskFd {
fn fd(&mut self) -> BorrowedDiskFd<'_> {
let lock = self.vhdx_file.lock().unwrap();
BorrowedDiskFd::new(lock.as_raw_fd())
}
@@ -62,7 +62,7 @@ impl VhdxSync {
}
impl AsyncAdaptor<Vhdx> for Arc<Mutex<Vhdx>> {
fn file(&mut self) -> MutexGuard<Vhdx> {
fn file(&mut self) -> MutexGuard<'_, Vhdx> {
self.lock().unwrap()
}
}

View File

@@ -17,7 +17,7 @@ log = "0.4.22"
num_enum = "0.7.2"
pci = { path = "../pci" }
serde = { version = "1.0.208", features = ["derive"] }
thiserror = "2.0.6"
thiserror = { workspace = true }
tpm = { path = "../tpm" }
vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" }

View File

@@ -17,38 +17,38 @@ pub enum Error {
#[error("Invalid delivery mode")]
InvalidDeliveryMode,
/// Failed creating the interrupt source group.
#[error("Failed creating the interrupt source group: {0}")]
#[error("Failed creating the interrupt source group")]
CreateInterruptSourceGroup(#[source] io::Error),
/// Failed triggering the interrupt.
#[error("Failed triggering the interrupt: {0}")]
#[error("Failed triggering the interrupt")]
TriggerInterrupt(#[source] io::Error),
/// Failed masking the interrupt.
#[error("Failed masking the interrupt: {0}")]
#[error("Failed masking the interrupt")]
MaskInterrupt(#[source] io::Error),
/// Failed unmasking the interrupt.
#[error("Failed unmasking the interrupt: {0}")]
#[error("Failed unmasking the interrupt")]
UnmaskInterrupt(#[source] io::Error),
/// Failed updating the interrupt.
#[error("Failed updating the interrupt: {0}")]
#[error("Failed updating the interrupt")]
UpdateInterrupt(#[source] io::Error),
/// Failed enabling the interrupt.
#[error("Failed enabling the interrupt: {0}")]
#[error("Failed enabling the interrupt")]
EnableInterrupt(#[source] io::Error),
#[cfg(target_arch = "aarch64")]
/// Failed creating GIC device.
#[error("Failed creating GIC device: {0}")]
#[error("Failed creating GIC device")]
CreateGic(#[source] hypervisor::HypervisorVmError),
#[cfg(target_arch = "aarch64")]
/// Failed restoring GIC device.
#[error("Failed restoring GIC device: {0}")]
#[error("Failed restoring GIC device")]
RestoreGic(#[source] hypervisor::arch::aarch64::gic::Error),
#[cfg(target_arch = "riscv64")]
/// Failed creating AIA device.
#[error("Failed creating AIA device: {0}")]
#[error("Failed creating AIA device")]
CreateAia(#[source] hypervisor::HypervisorVmError),
#[cfg(target_arch = "riscv64")]
/// Failed restoring AIA device.
#[error("Failed restoring AIA device: {0}")]
#[error("Failed restoring AIA device")]
RestoreAia(#[source] hypervisor::arch::riscv64::aia::Error),
}

View File

@@ -45,7 +45,7 @@ pub enum Error {
BadWriteOffset(u64),
#[error("GPIO interrupt disabled by guest driver")]
GpioInterruptDisabled,
#[error("Could not trigger GPIO interrupt: {0}")]
#[error("Could not trigger GPIO interrupt")]
GpioInterruptFailure(#[source] io::Error),
#[error("Invalid GPIO Input key triggered: {0}")]
GpioTriggerKeyFailure(u32),

View File

@@ -4,16 +4,18 @@
//! ARM PL031 Real Time Clock
//!
//! This module implements a PL031 Real Time Clock (RTC) that provides to provides long time base counter.
//! This is achieved by generating an interrupt signal after counting for a programmed number of cycles of
//! a real-time clock input.
//! This module implements part of a PL031 Real Time Clock (RTC):
//! * provide a clock value via RTCDR
//! * no alarm is implemented through the match register
//! * no interrupt is generated
//! * RTC cannot be disabled via RTCCR
//! * no test registers
//!
use std::result;
use std::sync::{Arc, Barrier};
use std::time::Instant;
use std::{io, result};
use thiserror::Error;
use vm_device::interrupt::InterruptSourceGroup;
use vm_device::BusDevice;
use crate::{read_le_u32, write_le_u32};
@@ -45,8 +47,6 @@ pub const NANOS_PER_SECOND: u64 = 1_000_000_000;
pub enum Error {
#[error("Bad Write Offset: {0}")]
BadWriteOffset(u64),
#[error("Failed to trigger interrupt: {0}")]
InterruptFailure(#[source] io::Error),
}
type Result<T> = result::Result<T, Error>;
@@ -107,31 +107,20 @@ pub struct Rtc {
match_value: u32,
// Writes to this register load an update value into the RTC.
load: u32,
imsc: u32,
ris: u32,
interrupt: Arc<dyn InterruptSourceGroup>,
}
impl Rtc {
/// Constructs an AMBA PL031 RTC device.
pub fn new(interrupt: Arc<dyn InterruptSourceGroup>) -> Self {
pub fn new() -> Self {
Self {
// This is used only for duration measuring purposes.
previous_now: Instant::now(),
tick_offset: get_time(ClockType::Real) as i64,
match_value: 0,
load: 0,
imsc: 0,
ris: 0,
interrupt,
}
}
fn trigger_interrupt(&mut self) -> Result<()> {
self.interrupt.trigger(0).map_err(Error::InterruptFailure)?;
Ok(())
}
fn get_time(&self) -> u32 {
let ts = (self.tick_offset as i128)
+ (Instant::now().duration_since(self.previous_now).as_nanos() as i128);
@@ -155,16 +144,8 @@ impl Rtc {
// we want to terminate the execution of the process.
self.tick_offset = seconds_to_nanoseconds(i64::from(val)).unwrap();
}
RTCIMSC => {
self.imsc = val & 1;
self.trigger_interrupt()?;
}
RTCICR => {
// As per above mentioned doc, the interrupt is cleared by writing any data value to
// the Interrupt Clear Register.
self.ris = 0;
self.trigger_interrupt()?;
}
RTCIMSC => (),
RTCICR => (),
RTCCR => (), // ignore attempts to turn off the timer.
o => {
return Err(Error::BadWriteOffset(o));
@@ -174,6 +155,12 @@ impl Rtc {
}
}
impl Default for Rtc {
fn default() -> Self {
Self::new()
}
}
impl BusDevice for Rtc {
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
let mut read_ok = true;
@@ -189,10 +176,10 @@ impl BusDevice for Rtc {
self.match_value
}
RTCLR => self.load,
RTCCR => 1, // RTC is always enabled.
RTCIMSC => self.imsc,
RTCRIS => self.ris,
RTCMIS => self.ris & self.imsc,
RTCCR => 1, // RTC is always enabled.
RTCIMSC => 0, // Interrupt is always disabled.
RTCRIS => 0,
RTCMIS => 0,
_ => {
read_ok = false;
0
@@ -230,9 +217,6 @@ impl BusDevice for Rtc {
#[cfg(test)]
mod tests {
use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
use vmm_sys_util::eventfd::EventFd;
use super::*;
use crate::{
read_be_u16, read_be_u32, read_le_i32, read_le_u16, read_le_u64, write_be_u16,
@@ -366,45 +350,9 @@ mod tests {
assert!(seconds_to_nanoseconds(9_223_372_037).is_none());
}
struct TestInterrupt {
event_fd: EventFd,
}
impl InterruptSourceGroup for TestInterrupt {
fn trigger(&self, _index: InterruptIndex) -> result::Result<(), std::io::Error> {
self.event_fd.write(1)
}
fn update(
&self,
_index: InterruptIndex,
_config: InterruptSourceConfig,
_masked: bool,
_set_gsi: bool,
) -> result::Result<(), std::io::Error> {
Ok(())
}
fn set_gsi(&self) -> result::Result<(), std::io::Error> {
Ok(())
}
fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
Some(self.event_fd.try_clone().unwrap())
}
}
impl TestInterrupt {
fn new(event_fd: EventFd) -> Self {
TestInterrupt { event_fd }
}
}
#[test]
fn test_rtc_read_write_and_event() {
let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let mut rtc = Rtc::new(Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())));
let mut rtc = Rtc::new();
let mut data = [0; 4];
// Read and write to the MR register.
@@ -427,15 +375,13 @@ mod tests {
assert_eq!((v / NANOS_PER_SECOND) as u32, v_read);
// Read and write to IMSC register.
// Test with non zero value.
// Test with non zero value. Our device ignores the write.
let non_zero = 1;
write_le_u32(&mut data, non_zero);
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &data);
// The interrupt line should be on.
assert!(rtc.interrupt.notifier(0).unwrap().read().unwrap() == 1);
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCIMSC, &mut data);
let v = read_le_u32(&data);
assert_eq!(non_zero & 1, v);
assert_eq!(0, v);
// Now test with 0.
write_le_u32(&mut data, 0);
@@ -447,8 +393,6 @@ mod tests {
// Read and write to the ICR register.
write_le_u32(&mut data, 1);
rtc.write(LEGACY_RTC_MAPPED_IO_START, RTCICR, &data);
// The interrupt line should be on.
assert!(rtc.interrupt.notifier(0).unwrap().read().unwrap() > 1);
let v_before = read_le_u32(&data);
rtc.read(LEGACY_RTC_MAPPED_IO_START, RTCICR, &mut data);

View File

@@ -53,11 +53,11 @@ pub enum Error {
BadWriteOffset(u64),
#[error("pl011: DMA not implemented")]
DmaNotImplemented,
#[error("Failed to trigger interrupt: {0}")]
#[error("Failed to trigger interrupt")]
InterruptFailure(#[source] io::Error),
#[error("Failed to write: {0}")]
#[error("Failed to write")]
WriteAllFailure(#[source] io::Error),
#[error("Failed to flush: {0}")]
#[error("Failed to flush")]
FlushFailure(#[source] io::Error),
}

View File

@@ -36,7 +36,7 @@ const MINOR_VERSION: u64 = 0;
#[derive(Error, Debug)]
pub enum Error {
// device errors
#[error("Guest gave us bad memory addresses: {0}")]
#[error("Guest gave us bad memory addresses")]
GuestMemory(#[source] GuestMemoryError),
#[error("Guest sent us invalid request")]
InvalidRequest,
@@ -51,7 +51,7 @@ pub enum Error {
InvalidArgument(u64),
#[error("Unknown function code: {0}")]
UnknownFunctionCode(u64),
#[error("Libc call fail: {0}")]
#[error("Libc call fail")]
LibcFail(#[source] std::io::Error),
}

View File

@@ -31,9 +31,9 @@ const PVPANIC_CRASH_LOADED: u8 = 1 << 1;
#[derive(Debug, Error)]
pub enum PvPanicError {
#[error("Failed creating PvPanicDevice: {0}")]
#[error("Failed creating PvPanicDevice")]
CreatePvPanicDevice(#[source] anyhow::Error),
#[error("Failed to retrieve PciConfigurationState: {0}")]
#[error("Failed to retrieve PciConfigurationState")]
RetrievePciConfigurationState(#[source] anyhow::Error),
}

View File

@@ -18,9 +18,9 @@ use vm_device::BusDevice;
#[derive(Error, Debug)]
pub enum Error {
#[error("Emulator doesn't implement min required capabilities: {0}")]
#[error("Emulator doesn't implement min required capabilities")]
CheckCaps(#[source] anyhow::Error),
#[error("Failed to initialize tpm: {0}")]
#[error("Failed to initialize tpm")]
Init(#[source] anyhow::Error),
}
type Result<T> = anyhow::Result<T, Error>;

View File

@@ -4,14 +4,12 @@ Intel® Software Guard Extensions (Intel® SGX) is an Intel technology designed
to increase the security of application code and data. Cloud Hypervisor supports
SGX virtualization through KVM. Because SGX is built on hardware features that
cannot be emulated in software, virtualizing SGX requires support in KVM and in
the host kernel. The required Linux and KVM changes can be found in the
[KVM SGX Tree](https://github.com/intel/kvm-sgx).
the host kernel. The required Linux and KVM changes can be found in Linux 5.13+.
Utilizing SGX in the guest requires a kernel/OS with SGX support, e.g. a kernel
since release 5.11, see
[here](https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/linux-overview.html)
or the [KVM SGX Tree](https://github.com/intel/kvm-sgx). Running KVM SGX as the
guest kernel allows nested virtualization of SGX.
[here](https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/linux-overview.html).
Running Linux 5.13+ as the guest kernel allows nested virtualization of SGX.
For more information about SGX, please refer to the [SGX Homepage](https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/linux-overview.html).

View File

@@ -18,7 +18,7 @@ tapindex=$(< /sys/class/net/macvtap0/ifindex)
tapdevice="/dev/tap$tapindex"
# Ensure that we can access this device
sudo chown "$UID.$UID" "$tapdevice"
sudo chown "$UID:$UID" "$tapdevice"
# Use --net fd=3 to point to fd 3 which the shell has opened to point to the /dev/tapN device
target/debug/cloud-hypervisor \

View File

@@ -7,6 +7,5 @@ version = "0.1.0"
[dependencies]
flume = "0.11.1"
libc = "0.2.167"
once_cell = "1.20.2"
serde = { version = "1.0.208", features = ["derive", "rc"] }
serde_json = { workspace = true }

View File

@@ -8,13 +8,12 @@ use std::collections::HashMap;
use std::fs::File;
use std::io;
use std::os::unix::io::AsRawFd;
use std::sync::Arc;
use std::sync::{Arc, OnceLock};
use std::time::{Duration, Instant};
use once_cell::sync::OnceCell;
use serde::Serialize;
static MONITOR: OnceCell<MonitorHandle> = OnceCell::new();
static MONITOR: OnceLock<MonitorHandle> = OnceLock::new();
#[derive(Serialize)]
struct Event<'a> {

212
fuzz/Cargo.lock generated
View File

@@ -7,7 +7,7 @@ name = "acpi_tables"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#e08a3f0b0a59b98859dbf59f5aa7fd4d2eb4018a"
dependencies = [
"zerocopy 0.8.24",
"zerocopy 0.8.26",
]
[[package]]
@@ -89,7 +89,7 @@ dependencies = [
"linux-loader",
"log",
"serde",
"thiserror 2.0.9",
"thiserror 2.0.12",
"uuid",
"vm-fdt",
"vm-memory",
@@ -137,7 +137,7 @@ dependencies = [
"remain",
"serde",
"smallvec",
"thiserror 2.0.9",
"thiserror 2.0.12",
"uuid",
"virtio-bindings",
"virtio-queue",
@@ -217,7 +217,6 @@ dependencies = [
"micro_http",
"mshv-bindings",
"net_util",
"once_cell",
"seccompiler",
"virtio-devices",
"virtio-queue",
@@ -311,7 +310,7 @@ dependencies = [
"num_enum",
"pci",
"serde",
"thiserror 2.0.9",
"thiserror 2.0.12",
"tpm",
"vm-allocator",
"vm-device",
@@ -362,7 +361,6 @@ version = "0.1.0"
dependencies = [
"flume",
"libc",
"once_cell",
"serde",
"serde_json",
]
@@ -405,9 +403,9 @@ checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
[[package]]
name = "gdbstub"
version = "0.7.2"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbcc892208d6998fb57e7c3e05883def66f8130924bba066beb0cfe71566a9f6"
checksum = "71d66e32caf5dd59f561be0143e413e01d651bd8498eb9aa0be8c482c81c8d31"
dependencies = [
"bitflags 2.9.0",
"cfg-if",
@@ -442,14 +440,14 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.3.1"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
"cfg-if",
"libc",
"wasi 0.13.3+wasi-0.2.2",
"windows-targets",
"r-efi",
"wasi 0.14.2+wasi-0.2.4",
]
[[package]]
@@ -478,11 +476,11 @@ dependencies = [
"serde",
"serde_json",
"serde_with",
"thiserror 2.0.9",
"thiserror 2.0.12",
"vfio-ioctls",
"vm-memory",
"vmm-sys-util",
"zerocopy 0.8.24",
"zerocopy 0.8.26",
]
[[package]]
@@ -533,29 +531,30 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.69"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "kvm-bindings"
version = "0.10.0"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4933174d0cc4b77b958578cd45784071cc5ae212c2d78fbd755aaaa6dfa71a"
checksum = "d4b153a59bb3ca930ff8148655b2ef68c34259a623ae08cf2fb9b570b2e45363"
dependencies = [
"serde",
"vmm-sys-util",
"zerocopy 0.7.35",
"zerocopy 0.8.26",
]
[[package]]
name = "kvm-ioctls"
version = "0.19.1"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e013ae7fcd2c6a8f384104d16afe7ea02969301ea2bb2a56e44b011ebc907cab"
checksum = "b702df98508cb63ad89dd9beb9f6409761b30edca10d48e57941d3f11513a006"
dependencies = [
"bitflags 2.9.0",
"kvm-bindings",
@@ -637,7 +636,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "micro_http"
version = "0.1.0"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#4f621532e81ee2ad096a9c9592fdacc40d19de48"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#bf5098916006912f8dd35aaa6daa5579c6c297b2"
dependencies = [
"libc",
"vmm-sys-util",
@@ -645,16 +644,16 @@ dependencies = [
[[package]]
name = "mshv-bindings"
version = "0.4.0"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "577073a0abbf515d17bfe96ca2ce49c44a68454d4179e95ce1244e858a9ebd4e"
checksum = "07f94f542c738f19317363222a7f415588c04cda964882479af41948ac3c3647"
dependencies = [
"libc",
"num_enum",
"serde",
"serde_derive",
"vmm-sys-util",
"zerocopy 0.8.24",
"zerocopy 0.8.26",
]
[[package]]
@@ -678,13 +677,13 @@ name = "net_util"
version = "0.1.0"
dependencies = [
"epoll",
"getrandom 0.3.1",
"getrandom 0.3.3",
"libc",
"log",
"net_gen",
"rate_limiter",
"serde",
"thiserror 2.0.9",
"thiserror 2.0.12",
"virtio-bindings",
"virtio-queue",
"vm-memory",
@@ -751,6 +750,9 @@ dependencies = [
[[package]]
name = "option_parser"
version = "0.1.0"
dependencies = [
"thiserror 2.0.12",
]
[[package]]
name = "paste"
@@ -768,7 +770,7 @@ dependencies = [
"libc",
"log",
"serde",
"thiserror 2.0.9",
"thiserror 2.0.12",
"vfio-bindings",
"vfio-ioctls",
"vfio_user",
@@ -815,6 +817,12 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
[[package]]
name = "rand"
version = "0.9.0"
@@ -823,7 +831,7 @@ checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [
"rand_chacha",
"rand_core",
"zerocopy 0.8.24",
"zerocopy 0.8.26",
]
[[package]]
@@ -842,7 +850,7 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom 0.3.1",
"getrandom 0.3.3",
]
[[package]]
@@ -852,21 +860,27 @@ dependencies = [
"epoll",
"libc",
"log",
"thiserror 2.0.9",
"thiserror 2.0.12",
"vmm-sys-util",
]
[[package]]
name = "remain"
version = "0.2.14"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46aef80f842736de545ada6ec65b81ee91504efd6853f4b96de7414c42ae7443"
checksum = "d7ef12e84481ab4006cb942f8682bba28ece7270743e649442027c5db87df126"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "rustversion"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
[[package]]
name = "ryu"
version = "1.0.18"
@@ -955,9 +969,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
dependencies = [
"libc",
"signal-hook-registry",
@@ -1015,11 +1029,11 @@ dependencies = [
[[package]]
name = "thiserror"
version = "2.0.9"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc"
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
dependencies = [
"thiserror-impl 2.0.9",
"thiserror-impl 2.0.12",
]
[[package]]
@@ -1035,9 +1049,9 @@ dependencies = [
[[package]]
name = "thiserror-impl"
version = "2.0.9"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
@@ -1070,7 +1084,7 @@ dependencies = [
"libc",
"log",
"net_gen",
"thiserror 2.0.9",
"thiserror 2.0.12",
"vmm-sys-util",
]
@@ -1080,7 +1094,6 @@ version = "0.1.0"
dependencies = [
"libc",
"log",
"once_cell",
"serde",
"serde_json",
]
@@ -1099,45 +1112,37 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.15.1"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587"
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
dependencies = [
"getrandom 0.3.1",
"getrandom 0.3.3",
"js-sys",
"rand",
"uuid-macro-internal",
]
[[package]]
name = "uuid-macro-internal"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9521621447c21497fac206ffe6e9f642f977c4f82eeba9201055f64884d9cb01"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen",
]
[[package]]
name = "vfio-bindings"
version = "0.4.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#b135b8305c2cc8ec333e0cf77a780445cc98dcee"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b565663f62e091ca47db9a674c8c95c9686a000e82970f391a3cacf6470ff060"
dependencies = [
"vmm-sys-util",
]
[[package]]
name = "vfio-ioctls"
version = "0.2.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#b135b8305c2cc8ec333e0cf77a780445cc98dcee"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61316b5e308faa8ed4a87c4130256f765e46de3442eb2e2e619840ef73456738"
dependencies = [
"byteorder",
"kvm-bindings",
"kvm-ioctls",
"libc",
"log",
"thiserror 1.0.64",
"thiserror 2.0.12",
"vfio-bindings",
"vm-memory",
"vmm-sys-util",
@@ -1146,15 +1151,16 @@ dependencies = [
[[package]]
name = "vfio_user"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#3febcdd3fa2531623865663ca1721e1962ed9979"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed81c5ed8224d468a322e923777ed0615cad433fe61177126098af995f89cecf"
dependencies = [
"bitflags 1.3.2",
"bitflags 2.9.0",
"libc",
"log",
"serde",
"serde_derive",
"serde_json",
"thiserror 1.0.64",
"thiserror 2.0.12",
"vfio-bindings",
"vm-memory",
"vmm-sys-util",
@@ -1162,8 +1168,9 @@ dependencies = [
[[package]]
name = "vhost"
version = "0.12.1"
source = "git+https://github.com/rust-vmm/vhost?rev=d983ae0#d983ae07f78663b7d24059667376992460b571a2"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a4dcad85a129d97d5d4b2f3c47a4affdeedd76bdcd02094bcb5d9b76cac2d05"
dependencies = [
"bitflags 2.9.0",
"libc",
@@ -1174,9 +1181,9 @@ dependencies = [
[[package]]
name = "virtio-bindings"
version = "0.2.4"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1711e61c00f8cb450bd15368152a1e37a12ef195008ddc7d0f4812f9e2b30a68"
checksum = "804f498a26d5a63be7bbb8bdcd3869c3f286c4c4a17108905276454da0caf8cb"
[[package]]
name = "virtio-devices"
@@ -1199,7 +1206,7 @@ dependencies = [
"serde_json",
"serde_with",
"serial_buffer",
"thiserror 2.0.9",
"thiserror 2.0.12",
"vhost",
"virtio-bindings",
"virtio-queue",
@@ -1213,9 +1220,9 @@ dependencies = [
[[package]]
name = "virtio-queue"
version = "0.14.0"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "872e2f3fbd70a7e6f01689720cce3d5c2c5efe52b484dd07b674246ada0e9a8d"
checksum = "fb0479158f863e59323771a1f684d843962f76960b86fecfec2bfa9c8f0f9180"
dependencies = [
"log",
"virtio-bindings",
@@ -1239,7 +1246,7 @@ dependencies = [
"anyhow",
"hypervisor",
"serde",
"thiserror 2.0.9",
"thiserror 2.0.12",
"vfio-ioctls",
"vm-memory",
"vmm-sys-util",
@@ -1252,9 +1259,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#ef5bd734f5f66fb0772
[[package]]
name = "vm-memory"
version = "0.16.1"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1720e7240cdc739f935456eb77f370d7e9b2a3909204da1e2b47bef1137a013"
checksum = "1fd5e56d48353c5f54ef50bd158a0452fc82f5383da840f7b8efc31695dd3b9d"
dependencies = [
"arc-swap",
"libc",
@@ -1269,7 +1276,7 @@ dependencies = [
"anyhow",
"serde",
"serde_json",
"thiserror 2.0.9",
"thiserror 2.0.12",
"vm-memory",
]
@@ -1307,7 +1314,6 @@ dependencies = [
"log",
"micro_http",
"net_util",
"once_cell",
"option_parser",
"pci",
"rate_limiter",
@@ -1316,11 +1322,12 @@ dependencies = [
"serde_json",
"serial_buffer",
"signal-hook",
"thiserror 2.0.9",
"thiserror 2.0.12",
"tracer",
"uuid",
"vfio-ioctls",
"vfio_user",
"virtio-bindings",
"virtio-devices",
"virtio-queue",
"vm-allocator",
@@ -1329,14 +1336,14 @@ dependencies = [
"vm-migration",
"vm-virtio",
"vmm-sys-util",
"zerocopy 0.8.24",
"zerocopy 0.8.26",
]
[[package]]
name = "vmm-sys-util"
version = "0.12.1"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede"
checksum = "d21f366bf22bfba3e868349978766a965cbe628c323d58e026be80b8357ab789"
dependencies = [
"bitflags 1.3.2",
"libc",
@@ -1352,33 +1359,33 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasi"
version = "0.13.3+wasi-0.2.2"
version = "0.14.2+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.93"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.93"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
@@ -1387,9 +1394,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.93"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1397,9 +1404,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.93"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
@@ -1410,9 +1417,12 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.93"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
[[package]]
name = "winapi"
@@ -1520,9 +1530,9 @@ dependencies = [
[[package]]
name = "wit-bindgen-rt"
version = "0.33.0"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags 2.9.0",
]
@@ -1539,11 +1549,11 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.24"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
dependencies = [
"zerocopy-derive 0.8.24",
"zerocopy-derive 0.8.26",
]
[[package]]
@@ -1559,9 +1569,9 @@ dependencies = [
[[package]]
name = "zerocopy-derive"
version = "0.8.24"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
dependencies = [
"proc-macro2",
"quote",

View File

@@ -24,18 +24,17 @@ libc = "0.2.155"
libfuzzer-sys = "0.4.7"
linux-loader = { version = "0.13.0", features = ["bzimage", "elf", "pe"] }
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
mshv-bindings = "0.5.0"
mshv-bindings = "0.5.2"
net_util = { path = "../net_util" }
once_cell = "1.19.0"
seccompiler = "0.5.0"
virtio-devices = { path = "../virtio-devices" }
virtio-queue = "0.14.0"
virtio-queue = "0.16.0"
vm-device = { path = "../vm-device" }
vm-memory = "0.16.0"
vm-migration = { path = "../vm-migration" }
vm-virtio = { path = "../vm-virtio" }
vmm = { path = "../vmm", features = ["guest_debug"] }
vmm-sys-util = "0.12.1"
vmm-sys-util = "0.14.0"
# Prevent this from interfering with workspaces
[workspace]

View File

@@ -6,11 +6,11 @@
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use std::sync::mpsc::{channel, Receiver};
use std::sync::LazyLock;
use std::thread;
use libfuzzer_sys::{fuzz_target, Corpus};
use micro_http::Request;
use once_cell::sync::Lazy;
use vm_migration::MigratableError;
use vmm::api::http::*;
use vmm::api::{
@@ -24,8 +24,8 @@ use vmm::{EpollContext, EpollDispatch};
use vmm_sys_util::eventfd::EventFd;
// Need to be ordered for test case reproducibility
static ROUTES: Lazy<Vec<&Box<dyn EndpointHandler + Sync + Send>>> =
Lazy::new(|| HTTP_ROUTES.routes.values().collect());
static ROUTES: LazyLock<Vec<&Box<dyn EndpointHandler + Sync + Send>>> =
LazyLock::new(|| HTTP_ROUTES.routes.values().collect());
fuzz_target!(|bytes: &[u8]| -> Corpus {
if bytes.len() < 2 {

View File

@@ -36,7 +36,7 @@ serde_json = { workspace = true }
serde_with = { version = "3.9.0", default-features = false, features = [
"macros",
] }
thiserror = "2.0.6"
thiserror = { workspace = true }
vfio-ioctls = { workspace = true, default-features = false }
vm-memory = { workspace = true, features = [
"backend-atomic",
@@ -44,7 +44,7 @@ vm-memory = { workspace = true, features = [
"backend-mmap",
] }
vmm-sys-util = { workspace = true, features = ["with-serde"] }
zerocopy = { version = "0.8.24", features = ["derive"] }
zerocopy = { workspace = true, features = ["derive"] }
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
default-features = false
@@ -62,4 +62,4 @@ optional = true
version = "1.21.0"
[dev-dependencies]
env_logger = "0.11.3"
env_logger = { workspace = true }

View File

@@ -16,13 +16,13 @@ use crate::{CpuState, HypervisorDeviceError, HypervisorVmError};
#[derive(Debug, Error)]
pub enum Error {
/// Error while calling KVM ioctl for setting up the global interrupt controller.
#[error("Failed creating GIC device: {0}")]
#[error("Failed creating GIC device")]
CreateGic(#[source] HypervisorVmError),
/// Error while setting device attributes for the GIC.
#[error("Failed setting device attributes for the GIC: {0}")]
#[error("Failed setting device attributes for the GIC")]
SetDeviceAttribute(#[source] HypervisorDeviceError),
/// Error while getting device attributes for the GIC.
#[error("Failed getting device attributes for the GIC: {0}")]
#[error("Failed getting device attributes for the GIC")]
GetDeviceAttribute(#[source] HypervisorDeviceError),
}
pub type Result<T> = result::Result<T, Error>;

View File

@@ -36,58 +36,58 @@ impl<T: Debug> Display for Exception<T> {
#[derive(Error, Debug)]
pub enum PlatformError {
#[error("Invalid address: {0}")]
#[error("Invalid address")]
InvalidAddress(#[source] anyhow::Error),
#[error("Invalid register: {0}")]
#[error("Invalid register")]
InvalidRegister(#[source] anyhow::Error),
#[error("Invalid state: {0}")]
#[error("Invalid state")]
InvalidState(#[source] anyhow::Error),
#[error("Memory read failure: {0}")]
#[error("Memory read failure")]
MemoryReadFailure(#[source] anyhow::Error),
#[error("Memory write failure: {0}")]
#[error("Memory write failure")]
MemoryWriteFailure(#[source] anyhow::Error),
#[error("Get CPU state failure: {0}")]
#[error("Get CPU state failure")]
GetCpuStateFailure(#[source] anyhow::Error),
#[error("Set CPU state failure: {0}")]
#[error("Set CPU state failure")]
SetCpuStateFailure(#[source] anyhow::Error),
#[error("Translate virtual address: {0}")]
#[error("Translate virtual address")]
TranslateVirtualAddress(#[source] anyhow::Error),
#[error("Unsupported CPU Mode: {0}")]
#[error("Unsupported CPU Mode")]
UnsupportedCpuMode(#[source] anyhow::Error),
#[error("Invalid instruction operand: {0}")]
#[error("Invalid instruction operand")]
InvalidOperand(#[source] anyhow::Error),
}
#[derive(Error, Debug)]
pub enum EmulationError<T: Debug> {
#[error("Unsupported instruction: {0}")]
#[error("Unsupported instruction")]
UnsupportedInstruction(#[source] anyhow::Error),
#[error("Unsupported memory size: {0}")]
#[error("Unsupported memory size")]
UnsupportedMemorySize(#[source] anyhow::Error),
#[error("Invalid operand: {0}")]
#[error("Invalid operand")]
InvalidOperand(#[source] anyhow::Error),
#[error("Wrong number of operands: {0}")]
#[error("Wrong number of operands")]
WrongNumberOperands(#[source] anyhow::Error),
#[error("Instruction Exception: {0}")]
#[error("Instruction Exception")]
InstructionException(#[source] Exception<T>),
#[error("Instruction fetching error: {0}")]
#[error("Instruction fetching error")]
InstructionFetchingError(#[source] anyhow::Error),
#[error("Platform emulation error: {0}")]
#[error("Platform emulation error")]
PlatformEmulationError(#[source] PlatformError),
#[error(transparent)]

View File

@@ -13,13 +13,13 @@ use crate::{AiaState, HypervisorDeviceError, HypervisorVmError};
#[derive(Debug, Error)]
pub enum Error {
/// Error while calling KVM ioctl for setting up the global interrupt controller.
#[error("Failed creating AIA device: {0}")]
#[error("Failed creating AIA device")]
CreateAia(#[source] HypervisorVmError),
/// Error while setting device attributes for the AIA.
#[error("Failed setting device attributes for the AIA: {0}")]
#[error("Failed setting device attributes for the AIA")]
SetDeviceAttribute(#[source] HypervisorDeviceError),
/// Error while getting device attributes for the AIA.
#[error("Failed getting device attributes for the AIA: {0}")]
#[error("Failed getting device attributes for the AIA")]
GetDeviceAttribute(#[source] HypervisorDeviceError),
}
pub type Result<T> = result::Result<T, Error>;

View File

@@ -4,7 +4,7 @@
// SPDX-License-Identifier: Apache-2.0
//
#![allow(non_camel_case_types, clippy::upper_case_acronyms)]
#![allow(non_camel_case_types, dead_code, clippy::upper_case_acronyms)]
//
// CMP-Compare Two Operands

View File

@@ -490,7 +490,7 @@ macro_rules! gen_handler_match {
}
impl<T: CpuStateManager> Emulator<'_, T> {
pub fn new(platform: &mut dyn PlatformEmulator<CpuState = T>) -> Emulator<T> {
pub fn new(platform: &mut dyn PlatformEmulator<CpuState = T>) -> Emulator<'_, T> {
Emulator { platform }
}

View File

@@ -43,171 +43,171 @@ pub enum HypervisorCpuError {
///
/// Setting standard registers error
///
#[error("Failed to set standard register: {0}")]
#[error("Failed to set standard register")]
SetStandardRegs(#[source] anyhow::Error),
///
/// Setting standard registers error
///
#[error("Failed to get standard registers: {0}")]
#[error("Failed to get standard registers")]
GetStandardRegs(#[source] anyhow::Error),
///
/// Setting special register error
///
#[error("Failed to set special registers: {0}")]
#[error("Failed to set special registers")]
SetSpecialRegs(#[source] anyhow::Error),
///
/// Getting standard register error
///
#[error("Failed to get special registers: {0}")]
#[error("Failed to get special registers")]
GetSpecialRegs(#[source] anyhow::Error),
///
/// Setting floating point registers error
///
#[error("Failed to set floating point registers: {0}")]
#[error("Failed to set floating point registers")]
SetFloatingPointRegs(#[source] anyhow::Error),
///
/// Getting floating point register error
///
#[error("Failed to get floating points registers: {0}")]
#[error("Failed to get floating points registers")]
GetFloatingPointRegs(#[source] anyhow::Error),
///
/// Setting Cpuid error
///
#[error("Failed to set Cpuid: {0}")]
#[error("Failed to set Cpuid")]
SetCpuid(#[source] anyhow::Error),
///
/// Getting Cpuid error
///
#[error("Failed to get Cpuid: {0}")]
#[error("Failed to get Cpuid")]
GetCpuid(#[source] anyhow::Error),
///
/// Setting lapic state error
///
#[error("Failed to set Lapic state: {0}")]
#[error("Failed to set Lapic state")]
SetLapicState(#[source] anyhow::Error),
///
/// Getting Lapic state error
///
#[error("Failed to get Lapic state: {0}")]
#[error("Failed to get Lapic state")]
GetlapicState(#[source] anyhow::Error),
///
/// Setting MSR entries error
///
#[error("Failed to set Msr entries: {0}")]
#[error("Failed to set Msr entries")]
SetMsrEntries(#[source] anyhow::Error),
///
/// Getting Msr entries error
///
#[error("Failed to get Msr entries: {0}")]
#[error("Failed to get Msr entries")]
GetMsrEntries(#[source] anyhow::Error),
///
/// Setting multi-processing state error
///
#[error("Failed to set MP state: {0}")]
#[error("Failed to set MP state")]
SetMpState(#[source] anyhow::Error),
///
/// Getting multi-processing state error
///
#[error("Failed to get MP state: {0}")]
#[error("Failed to get MP state")]
GetMpState(#[source] anyhow::Error),
///
/// Setting Saved Processor Extended States error
///
#[cfg(feature = "kvm")]
#[error("Failed to set Saved Processor Extended States: {0}")]
#[error("Failed to set Saved Processor Extended States")]
SetXsaveState(#[source] anyhow::Error),
///
/// Getting Saved Processor Extended States error
///
#[cfg(feature = "kvm")]
#[error("Failed to get Saved Processor Extended States: {0}")]
#[error("Failed to get Saved Processor Extended States")]
GetXsaveState(#[source] anyhow::Error),
///
/// Getting the VP state components error
///
#[cfg(feature = "mshv")]
#[error("Failed to get VP State Components: {0}")]
#[error("Failed to get VP State Components")]
GetAllVpStateComponents(#[source] anyhow::Error),
///
/// Setting the VP state components error
///
#[cfg(feature = "mshv")]
#[error("Failed to set VP State Components: {0}")]
#[error("Failed to set VP State Components")]
SetAllVpStateComponents(#[source] anyhow::Error),
///
/// Setting Extended Control Registers error
///
#[error("Failed to set Extended Control Registers: {0}")]
#[error("Failed to set Extended Control Registers")]
SetXcsr(#[source] anyhow::Error),
///
/// Getting Extended Control Registers error
///
#[error("Failed to get Extended Control Registers: {0}")]
#[error("Failed to get Extended Control Registers")]
GetXcsr(#[source] anyhow::Error),
///
/// Running Vcpu error
///
#[error("Failed to run vcpu: {0}")]
#[error("Failed to run vcpu")]
RunVcpu(#[source] anyhow::Error),
///
/// Getting Vcpu events error
///
#[error("Failed to get Vcpu events: {0}")]
#[error("Failed to get Vcpu events")]
GetVcpuEvents(#[source] anyhow::Error),
///
/// Setting Vcpu events error
///
#[error("Failed to set Vcpu events: {0}")]
#[error("Failed to set Vcpu events")]
SetVcpuEvents(#[source] anyhow::Error),
///
/// Vcpu Init error
///
#[error("Failed to init vcpu: {0}")]
#[error("Failed to init vcpu")]
VcpuInit(#[source] anyhow::Error),
///
/// Vcpu Finalize error
///
#[error("Failed to finalize vcpu: {0}")]
#[error("Failed to finalize vcpu")]
VcpuFinalize(#[source] anyhow::Error),
///
/// Setting one reg error
///
#[error("Failed to set one reg: {0}")]
#[error("Failed to set one reg")]
SetRegister(#[source] anyhow::Error),
///
/// Getting one reg error
///
#[error("Failed to get one reg: {0}")]
#[error("Failed to get one reg")]
GetRegister(#[source] anyhow::Error),
///
/// Getting guest clock paused error
///
#[error("Failed to notify guest its clock was paused: {0}")]
#[error("Failed to notify guest its clock was paused")]
NotifyGuestClockPaused(#[source] anyhow::Error),
///
/// Setting debug register error
///
#[error("Failed to set debug registers: {0}")]
#[error("Failed to set debug registers")]
SetDebugRegs(#[source] anyhow::Error),
///
/// Getting debug register error
///
#[error("Failed to get debug registers: {0}")]
#[error("Failed to get debug registers")]
GetDebugRegs(#[source] anyhow::Error),
///
/// Setting misc register error
///
#[error("Failed to set misc registers: {0}")]
#[error("Failed to set misc registers")]
SetMiscRegs(#[source] anyhow::Error),
///
/// Getting misc register error
///
#[error("Failed to get misc registers: {0}")]
#[error("Failed to get misc registers")]
GetMiscRegs(#[source] anyhow::Error),
///
/// Write to Guest Mem
///
#[error("Failed to write to Guest Mem at: {0}")]
#[error("Failed to write to Guest Mem at")]
GuestMemWrite(#[source] anyhow::Error),
/// Enabling HyperV SynIC error
///
@@ -216,68 +216,68 @@ pub enum HypervisorCpuError {
///
/// Getting AArch64 core register error
///
#[error("Failed to get aarch64 core register: {0}")]
#[error("Failed to get aarch64 core register")]
GetAarchCoreRegister(#[source] anyhow::Error),
///
/// Setting AArch64 core register error
///
#[error("Failed to set aarch64 core register: {0}")]
#[error("Failed to set aarch64 core register")]
SetAarchCoreRegister(#[source] anyhow::Error),
///
/// Getting RISC-V 64-bit core register error
///
#[error("Failed to get riscv64 core register: {0}")]
#[error("Failed to get riscv64 core register")]
GetRiscvCoreRegister(#[source] anyhow::Error),
///
/// Setting RISC-V 64-bit core register error
///
#[error("Failed to set riscv64 core register: {0}")]
#[error("Failed to set riscv64 core register")]
SetRiscvCoreRegister(#[source] anyhow::Error),
///
/// Getting registers list error
///
#[error("Failed to retrieve list of registers: {0}")]
#[error("Failed to retrieve list of registers")]
GetRegList(#[source] anyhow::Error),
///
/// Getting AArch64 system register error
///
#[error("Failed to get system register: {0}")]
#[error("Failed to get system register")]
GetSysRegister(#[source] anyhow::Error),
///
/// Setting AArch64 system register error
///
#[error("Failed to set system register: {0}")]
#[error("Failed to set system register")]
SetSysRegister(#[source] anyhow::Error),
///
/// Getting RISC-V 64-bit non-core register error
///
#[error("Failed to get non-core register: {0}")]
#[error("Failed to get non-core register")]
GetNonCoreRegister(#[source] anyhow::Error),
///
/// Setting RISC-V 64-bit non-core register error
///
#[error("Failed to set non-core register: {0}")]
#[error("Failed to set non-core register")]
SetNonCoreRegister(#[source] anyhow::Error),
///
/// GVA translation error
///
#[error("Failed to translate GVA: {0}")]
#[error("Failed to translate GVA")]
TranslateVirtualAddress(#[source] anyhow::Error),
///
/// Set cpu attribute error
///
#[error("Failed to set vcpu attribute: {0}")]
#[error("Failed to set vcpu attribute")]
SetVcpuAttribute(#[source] anyhow::Error),
///
/// Check if cpu has a certain attribute error
///
#[error("Failed to check if vcpu has attribute: {0}")]
#[error("Failed to check if vcpu has attribute")]
HasVcpuAttribute(#[source] anyhow::Error),
///
/// Failed to initialize TDX on CPU
///
#[cfg(feature = "tdx")]
#[error("Failed to initialize TDX: {0}")]
#[error("Failed to initialize TDX")]
InitializeTdx(#[source] std::io::Error),
///
/// Unknown TDX VM call
@@ -295,33 +295,33 @@ pub enum HypervisorCpuError {
///
/// Error getting TSC frequency
///
#[error("Failed to get TSC frequency: {0}")]
#[error("Failed to get TSC frequency")]
GetTscKhz(#[source] anyhow::Error),
///
/// Error setting TSC frequency
///
#[error("Failed to set TSC frequency: {0}")]
#[error("Failed to set TSC frequency")]
SetTscKhz(#[source] anyhow::Error),
///
/// Error reading value at given GPA
///
#[error("Failed to read from GPA: {0}")]
#[error("Failed to read from GPA")]
GpaRead(#[source] anyhow::Error),
///
/// Error writing value at given GPA
///
#[error("Failed to write to GPA: {0}")]
#[error("Failed to write to GPA")]
GpaWrite(#[source] anyhow::Error),
///
/// Error getting CPUID leaf
///
#[error("Failed to get CPUID entries: {0}")]
#[error("Failed to get CPUID entries")]
GetCpuidVales(#[source] anyhow::Error),
///
/// Setting SEV control register error
///
#[cfg(feature = "sev_snp")]
#[error("Failed to set sev control register: {0}")]
#[error("Failed to set sev control register")]
SetSevControlRegister(#[source] anyhow::Error),
///
/// Unsupported SysReg registers

View File

@@ -18,11 +18,11 @@ pub enum HypervisorDeviceError {
///
/// Set device attribute error
///
#[error("Failed to set device attribute: {0}")]
#[error("Failed to set device attribute")]
SetDeviceAttribute(#[source] anyhow::Error),
///
/// Get device attribute error
///
#[error("Failed to get device attribute: {0}")]
#[error("Failed to get device attribute")]
GetDeviceAttribute(#[source] anyhow::Error),
}

View File

@@ -27,37 +27,37 @@ pub enum HypervisorError {
///
/// Hypervisor availability check error
///
#[error("Failed to check availability of the hypervisor: {0}")]
#[error("Failed to check availability of the hypervisor")]
HypervisorAvailableCheck(#[source] anyhow::Error),
///
/// hypervisor creation error
///
#[error("Failed to create the hypervisor: {0}")]
#[error("Failed to create the hypervisor")]
HypervisorCreate(#[source] anyhow::Error),
///
/// Vm creation failure
///
#[error("Failed to create Vm: {0}")]
#[error("Failed to create Vm")]
VmCreate(#[source] anyhow::Error),
///
/// Vm setup failure
///
#[error("Failed to setup Vm: {0}")]
#[error("Failed to setup Vm")]
VmSetup(#[source] anyhow::Error),
///
/// API version error
///
#[error("Failed to get API Version: {0}")]
#[error("Failed to get API Version")]
GetApiVersion(#[source] anyhow::Error),
///
/// CpuId error
///
#[error("Failed to get cpuid: {0}")]
#[error("Failed to get cpuid")]
GetCpuId(#[source] anyhow::Error),
///
/// Failed to retrieve list of MSRs.
///
#[error("Failed to get the list of supported MSRs: {0}")]
#[error("Failed to get the list of supported MSRs")]
GetMsrList(#[source] anyhow::Error),
///
/// API version is not compatible
@@ -67,22 +67,22 @@ pub enum HypervisorError {
///
/// Checking extensions failed
///
#[error("Checking extensions: {0}")]
#[error("Checking extensions")]
CheckExtensions(#[source] anyhow::Error),
///
/// Failed to retrieve TDX capabilities
///
#[error("Failed to retrieve TDX capabilities: {0}")]
#[error("Failed to retrieve TDX capabilities")]
TdxCapabilities(#[source] anyhow::Error),
///
/// Failed to set partition property
///
#[error("Failed to set partition property: {0}")]
#[error("Failed to set partition property")]
SetPartitionProperty(#[source] anyhow::Error),
///
/// Running on an unsupported CPU
///
#[error("Unsupported CPU: {0}")]
#[error("Unsupported CPU")]
UnsupportedCpu(#[source] anyhow::Error),
///
/// Launching a VM with unsupported VM Type

View File

@@ -19,31 +19,6 @@ use serde::{Deserialize, Serialize};
use crate::kvm::{KvmError, KvmResult};
// 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) => {{
let tmp: std::mem::MaybeUninit<$str> = std::mem::MaybeUninit::uninit();
let base = tmp.as_ptr();
// Avoid warnings when nesting `unsafe` blocks.
#[allow(unused_unsafe)]
// 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;
// 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
}
}};
}
// Following are macros that help with getting the ID of a aarch64 core register.
// The core register are represented by the user_pt_regs structure. Look for it in
// arch/arm64/include/uapi/asm/ptrace.h.

View File

@@ -14,6 +14,8 @@ use std::any::Any;
use std::collections::HashMap;
#[cfg(target_arch = "x86_64")]
use std::fs::File;
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
use std::mem::offset_of;
#[cfg(target_arch = "x86_64")]
use std::os::unix::io::AsRawFd;
#[cfg(feature = "tdx")]
@@ -34,6 +36,8 @@ pub use crate::aarch64::{check_required_kvm_extensions, is_system_register, Vcpu
use crate::arch::aarch64::gic::{Vgic, VgicConfig};
#[cfg(target_arch = "riscv64")]
use crate::arch::riscv64::aia::{Vaia, VaiaConfig};
#[cfg(target_arch = "aarch64")]
use crate::arm64_core_reg_id;
#[cfg(target_arch = "riscv64")]
use crate::riscv64::aia::KvmAiaImsics;
#[cfg(target_arch = "riscv64")]
@@ -41,12 +45,10 @@ pub use crate::riscv64::{
aia::AiaImsicsState as AiaState, check_required_kvm_extensions, is_non_core_register,
VcpuKvmState,
};
use crate::vm::{self, InterruptSourceConfig, VmOps};
#[cfg(target_arch = "aarch64")]
use crate::{arm64_core_reg_id, offset_of};
use crate::{cpu, hypervisor, vec_with_array_field, HypervisorType};
#[cfg(target_arch = "riscv64")]
use crate::{offset_of, riscv64_reg_id};
use crate::riscv64_reg_id;
use crate::vm::{self, InterruptSourceConfig, VmOps};
use crate::{cpu, hypervisor, HypervisorType};
// x86_64 dependencies
#[cfg(target_arch = "x86_64")]
pub mod x86_64;
@@ -93,20 +95,20 @@ pub use kvm_bindings::{
};
#[cfg(target_arch = "aarch64")]
use kvm_bindings::{
kvm_regs, user_fpsimd_state, user_pt_regs, KVM_GUESTDBG_USE_HW, KVM_NR_SPSR, KVM_REG_ARM64,
KVM_REG_ARM64_SYSREG, KVM_REG_ARM64_SYSREG_CRM_MASK, KVM_REG_ARM64_SYSREG_CRN_MASK,
KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP2_MASK,
KVM_REG_ARM_CORE, KVM_REG_SIZE_U128, KVM_REG_SIZE_U32, KVM_REG_SIZE_U64,
kvm_regs, user_pt_regs, KVM_GUESTDBG_USE_HW, KVM_NR_SPSR, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG,
KVM_REG_ARM64_SYSREG_CRM_MASK, KVM_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_OP0_MASK,
KVM_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM_CORE,
KVM_REG_SIZE_U128, KVM_REG_SIZE_U32, KVM_REG_SIZE_U64,
};
#[cfg(target_arch = "riscv64")]
use kvm_bindings::{kvm_riscv_core, user_regs_struct, KVM_REG_RISCV_CORE};
use kvm_bindings::{kvm_riscv_core, KVM_REG_RISCV_CORE};
#[cfg(feature = "tdx")]
use kvm_bindings::{kvm_run__bindgen_ty_1, KVMIO};
pub use kvm_ioctls::{Cap, Kvm, VcpuExit};
use thiserror::Error;
use vfio_ioctls::VfioDeviceFd;
#[cfg(feature = "tdx")]
use vmm_sys_util::{ioctl::ioctl_with_val, ioctl_ioc_nr, ioctl_iowr_nr};
use vmm_sys_util::{ioctl::ioctl_with_val, ioctl_iowr_nr};
pub use {kvm_bindings, kvm_ioctls};
#[cfg(target_arch = "aarch64")]
@@ -119,8 +121,6 @@ const KVM_CAP_SGX_ATTRIBUTE: u32 = 196;
#[cfg(target_arch = "x86_64")]
use vmm_sys_util::ioctl_io_nr;
#[cfg(all(not(feature = "tdx"), target_arch = "x86_64"))]
use vmm_sys_util::ioctl_ioc_nr;
#[cfg(target_arch = "x86_64")]
ioctl_io_nr!(KVM_NMI, kvm_bindings::KVMIO, 0x9a);
@@ -693,10 +693,6 @@ impl vm::Vm for KvmVm {
/// entries, as per the `KVM_SET_GSI_ROUTING` ioctl.
///
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
let mut irq_routing =
vec_with_array_field::<kvm_irq_routing, kvm_irq_routing_entry>(entries.len());
irq_routing[0].nr = entries.len() as u32;
irq_routing[0].flags = 0;
let entries: Vec<kvm_irq_routing_entry> = entries
.iter()
.map(|entry| match entry {
@@ -706,17 +702,11 @@ impl vm::Vm for KvmVm {
})
.collect();
// SAFETY: irq_routing initialized with entries.len() and now it is being turned into
// entries_slice with entries.len() again. It is guaranteed to be large enough to hold
// everything from entries.
unsafe {
let entries_slice: &mut [kvm_irq_routing_entry] =
irq_routing[0].entries.as_mut_slice(entries.len());
entries_slice.copy_from_slice(&entries);
}
let irq_routing =
kvm_bindings::fam_wrappers::KvmIrqRouting::from_entries(&entries).unwrap();
self.fd
.set_gsi_routing(&irq_routing[0])
.set_gsi_routing(&irq_routing)
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
}
@@ -1450,7 +1440,7 @@ impl cpu::Vcpu for KvmVcpu {
// Now moving on to floating 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.vregs);
for i in 0..32 {
let mut bytes = [0_u8; 16];
self.fd
@@ -1463,7 +1453,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.fpsr);
let mut bytes = [0_u8; 4];
self.fd
.lock()
@@ -1473,7 +1463,7 @@ impl cpu::Vcpu for KvmVcpu {
state.fp_regs.fpsr = u32::from_le_bytes(bytes);
// 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.fpcr);
let mut bytes = [0_u8; 4];
self.fd
.lock()
@@ -1507,7 +1497,7 @@ impl cpu::Vcpu for KvmVcpu {
state.mode = u64::from_le_bytes(bytes);
};
($reg_name:ident) => {
let off = offset_of!(kvm_riscv_core, regs, user_regs_struct, $reg_name);
let off = offset_of!(kvm_riscv_core, regs.$reg_name);
let mut bytes = [0_u8; 8];
self.fd
.lock()
@@ -1654,7 +1644,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.vregs);
for i in 0..32 {
self.fd
.lock()
@@ -1667,7 +1657,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.fpsr);
self.fd
.lock()
.unwrap()
@@ -1677,7 +1667,7 @@ impl cpu::Vcpu for KvmVcpu {
)
.map_err(|e| cpu::HypervisorCpuError::SetAarchCoreRegister(e.into()))?;
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
let off = offset_of!(kvm_regs, fp_regs.fpcr);
self.fd
.lock()
.unwrap()
@@ -1715,7 +1705,7 @@ impl cpu::Vcpu for KvmVcpu {
.map_err(|e| cpu::HypervisorCpuError::SetRiscvCoreRegister(e.into()))?;
};
($reg_name:ident) => {
let off = offset_of!(kvm_riscv_core, regs, user_regs_struct, $reg_name);
let off = offset_of!(kvm_riscv_core, regs.$reg_name);
self.fd
.lock()
.unwrap()
@@ -2291,10 +2281,8 @@ impl cpu::Vcpu for KvmVcpu {
///
#[cfg(target_arch = "aarch64")]
fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> cpu::Result<()> {
let kreg_off = offset_of!(kvm_regs, regs);
// Get the register index of the PSTATE (Processor State) register.
let pstate = offset_of!(user_pt_regs, pstate) + kreg_off;
let pstate = offset_of!(kvm_regs, regs.pstate);
self.fd
.lock()
.unwrap()
@@ -2307,7 +2295,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!(kvm_regs, regs.pc);
self.fd
.lock()
.unwrap()
@@ -2321,7 +2309,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!(kvm_regs, regs.regs);
self.fd
.lock()
.unwrap()
@@ -2340,7 +2328,7 @@ impl cpu::Vcpu for KvmVcpu {
///
fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> cpu::Result<()> {
// Setting the A0 () to the hartid of this CPU.
let a0 = offset_of!(kvm_riscv_core, regs, user_regs_struct, a0);
let a0 = offset_of!(kvm_riscv_core, regs.a0);
self.fd
.lock()
.unwrap()
@@ -2351,7 +2339,7 @@ impl cpu::Vcpu for KvmVcpu {
.map_err(|e| cpu::HypervisorCpuError::SetRiscvCoreRegister(e.into()))?;
// Setting the PC (Processor Counter) to the current program address (kernel address).
let pc = offset_of!(kvm_riscv_core, regs, user_regs_struct, pc);
let pc = offset_of!(kvm_riscv_core, regs.pc);
self.fd
.lock()
.unwrap()
@@ -2364,7 +2352,7 @@ impl cpu::Vcpu for KvmVcpu {
// Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
// "The device tree blob (dtb) must be placed on an 8-byte boundary and must
// not exceed 64 kilobytes in size." -> https://www.kernel.org/doc/Documentation/arch/riscv/boot.txt.
let a1 = offset_of!(kvm_riscv_core, regs, user_regs_struct, a1);
let a1 = offset_of!(kvm_riscv_core, regs.a1);
self.fd
.lock()
.unwrap()
@@ -2956,11 +2944,15 @@ impl KvmVcpu {
///
fn set_xsave(&self, xsave: &XsaveState) -> cpu::Result<()> {
let xsave: kvm_bindings::kvm_xsave = (*xsave).clone().into();
self.fd
.lock()
.unwrap()
.set_xsave(&xsave)
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
// SAFETY: Here we trust the kernel not to read past the end of the kvm_xsave struct
// when calling the kvm-ioctl library function.
unsafe {
self.fd
.lock()
.unwrap()
.set_xsave(&xsave)
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
}
}
#[cfg(target_arch = "x86_64")]
@@ -3027,7 +3019,7 @@ mod tests {
let vcpu0 = vm.create_vcpu(0, None).unwrap();
let core_regs = StandardRegisters::from(kvm_riscv_core {
regs: user_regs_struct {
regs: kvm_bindings::user_regs_struct {
pc: 0x00,
ra: 0x01,
sp: 0x02,

View File

@@ -13,41 +13,6 @@ use serde::{Deserialize, Serialize};
use crate::kvm::{KvmError, KvmResult};
// 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) => {{
let tmp: std::mem::MaybeUninit<$str> = std::mem::MaybeUninit::uninit();
let base = tmp.as_ptr();
// Avoid warnings when nesting `unsafe` blocks.
#[allow(unused_unsafe)]
// 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;
// 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
}
}};
}
#[macro_export]
macro_rules! offset_of {
($reg_struct:ty, $field:ident) => {
$crate::_offset_of!($reg_struct, $field)
};
($outer_reg_struct:ty, $outer_field:ident, $($inner_reg_struct:ty, $inner_field:ident), +) => {
$crate::_offset_of!($outer_reg_struct, $outer_field) + offset_of!($($inner_reg_struct, $inner_field), +)
};
}
// Following are macros that help with getting the ID of a riscv64 register, including config registers, core registers and timer registers.
// The register of core registers are wrapped in the `user_regs_struct` structure. See:
// https://elixir.bootlin.com/linux/v6.10/source/arch/riscv/include/uapi/asm/kvm.h#L62

View File

@@ -1711,10 +1711,11 @@ impl MshvVcpu {
if let Some(reg_page) = self.fd.get_vp_reg_page() {
let vp_reg_page = reg_page.0;
set_gp_regs_field_ptr!(vp_reg_page, rax, ret_rax);
// SAFETY: access union fields
// SAFETY: access raw pointer to reg page, access union fields
unsafe {
(*vp_reg_page).__bindgen_anon_1.__bindgen_anon_1.rip = info.header.rip + insn_len;
(*vp_reg_page).dirty |= 1 << HV_X64_REGISTER_CLASS_IP;
(*vp_reg_page).dirty |= 1 << HV_X64_REGISTER_CLASS_GENERAL;
}
} else {
let arr_reg_name_value = [

View File

@@ -58,196 +58,196 @@ pub enum HypervisorVmError {
///
/// Create Vcpu error
///
#[error("Failed to create Vcpu: {0}")]
#[error("Failed to create Vcpu")]
CreateVcpu(#[source] anyhow::Error),
///
/// Identity map address error
///
#[error("Failed to set identity map address: {0}")]
#[error("Failed to set identity map address")]
SetIdentityMapAddress(#[source] anyhow::Error),
///
/// TSS address error
///
#[error("Failed to set TSS address: {0}")]
#[error("Failed to set TSS address")]
SetTssAddress(#[source] anyhow::Error),
///
/// Create interrupt controller error
///
#[error("Failed to create interrupt controller: {0}")]
#[error("Failed to create interrupt controller")]
CreateIrq(#[source] anyhow::Error),
///
/// Register interrupt event error
///
#[error("Failed to register interrupt event: {0}")]
#[error("Failed to register interrupt event")]
RegisterIrqFd(#[source] anyhow::Error),
///
/// Un register interrupt event error
///
#[error("Failed to unregister interrupt event: {0}")]
#[error("Failed to unregister interrupt event")]
UnregisterIrqFd(#[source] anyhow::Error),
///
/// Register IO event error
///
#[error("Failed to register IO event: {0}")]
#[error("Failed to register IO event")]
RegisterIoEvent(#[source] anyhow::Error),
///
/// Unregister IO event error
///
#[error("Failed to unregister IO event: {0}")]
#[error("Failed to unregister IO event")]
UnregisterIoEvent(#[source] anyhow::Error),
///
/// Set GSI routing error
///
#[error("Failed to set GSI routing: {0}")]
#[error("Failed to set GSI routing")]
SetGsiRouting(#[source] anyhow::Error),
///
/// Create user memory error
///
#[error("Failed to create user memory: {0}")]
#[error("Failed to create user memory")]
CreateUserMemory(#[source] anyhow::Error),
///
/// Remove user memory region error
///
#[error("Failed to remove user memory: {0}")]
#[error("Failed to remove user memory")]
RemoveUserMemory(#[source] anyhow::Error),
///
/// Create device error
///
#[error("Failed to set GSI routing: {0}")]
#[error("Failed to set GSI routing")]
CreateDevice(#[source] anyhow::Error),
///
/// Get preferred target error
///
#[error("Failed to get preferred target: {0}")]
#[error("Failed to get preferred target")]
GetPreferredTarget(#[source] anyhow::Error),
///
/// Enable split Irq error
///
#[error("Failed to enable split Irq: {0}")]
#[error("Failed to enable split Irq")]
EnableSplitIrq(#[source] anyhow::Error),
///
/// Enable SGX attribute error
///
#[error("Failed to enable SGX attribute: {0}")]
#[error("Failed to enable SGX attribute")]
EnableSgxAttribute(#[source] anyhow::Error),
///
/// Get clock error
///
#[error("Failed to get clock: {0}")]
#[error("Failed to get clock")]
GetClock(#[source] anyhow::Error),
///
/// Set clock error
///
#[error("Failed to set clock: {0}")]
#[error("Failed to set clock")]
SetClock(#[source] anyhow::Error),
///
/// Create passthrough device
///
#[error("Failed to create passthrough device: {0}")]
#[error("Failed to create passthrough device")]
CreatePassthroughDevice(#[source] anyhow::Error),
/// Write to Guest memory
///
#[error("Failed to write to guest memory: {0}")]
#[error("Failed to write to guest memory")]
GuestMemWrite(#[source] anyhow::Error),
///
/// Read Guest memory
///
#[error("Failed to read guest memory: {0}")]
#[error("Failed to read guest memory")]
GuestMemRead(#[source] anyhow::Error),
///
/// Read from MMIO Bus
///
#[error("Failed to read from MMIO Bus: {0}")]
#[error("Failed to read from MMIO Bus")]
MmioBusRead(#[source] anyhow::Error),
///
/// Write to MMIO Bus
///
#[error("Failed to write to MMIO Bus: {0}")]
#[error("Failed to write to MMIO Bus")]
MmioBusWrite(#[source] anyhow::Error),
///
/// Read from IO Bus
///
#[error("Failed to read from IO Bus: {0}")]
#[error("Failed to read from IO Bus")]
IoBusRead(#[source] anyhow::Error),
///
/// Write to IO Bus
///
#[error("Failed to write to IO Bus: {0}")]
#[error("Failed to write to IO Bus")]
IoBusWrite(#[source] anyhow::Error),
///
/// Start dirty log error
///
#[error("Failed to get dirty log: {0}")]
#[error("Failed to get dirty log")]
StartDirtyLog(#[source] anyhow::Error),
///
/// Stop dirty log error
///
#[error("Failed to get dirty log: {0}")]
#[error("Failed to get dirty log")]
StopDirtyLog(#[source] anyhow::Error),
///
/// Get dirty log error
///
#[error("Failed to get dirty log: {0}")]
#[error("Failed to get dirty log")]
GetDirtyLog(#[source] anyhow::Error),
///
/// Assert virtual interrupt error
///
#[error("Failed to assert virtual Interrupt: {0}")]
#[error("Failed to assert virtual Interrupt")]
AssertVirtualInterrupt(#[source] anyhow::Error),
#[cfg(feature = "sev_snp")]
///
/// Error initializing SEV-SNP on the VM
///
#[error("Failed to initialize SEV-SNP: {0}")]
#[error("Failed to initialize SEV-SNP")]
InitializeSevSnp(#[source] std::io::Error),
#[cfg(feature = "tdx")]
///
/// Error initializing TDX on the VM
///
#[error("Failed to initialize TDX: {0}")]
#[error("Failed to initialize TDX")]
InitializeTdx(#[source] std::io::Error),
#[cfg(feature = "tdx")]
///
/// Error finalizing the TDX configuration on the VM
///
#[error("Failed to finalize TDX: {0}")]
#[error("Failed to finalize TDX")]
FinalizeTdx(#[source] std::io::Error),
#[cfg(feature = "tdx")]
///
/// Error initializing the TDX memory region
///
#[error("Failed to initialize memory region TDX: {0}")]
#[error("Failed to initialize memory region TDX")]
InitMemRegionTdx(#[source] std::io::Error),
///
/// Create Vgic error
///
#[error("Failed to create Vgic: {0}")]
#[error("Failed to create Vgic")]
CreateVgic(#[source] anyhow::Error),
///
/// Create Vaia error
///
#[error("Failed to create Vaia: {0}")]
#[error("Failed to create Vaia")]
CreateVaia(#[source] anyhow::Error),
///
/// Import isolated pages error
///
#[error("Failed to import isolated pages: {0}")]
#[error("Failed to import isolated pages")]
ImportIsolatedPages(#[source] anyhow::Error),
/// Failed to complete isolated import
///
#[error("Failed to complete isolated import: {0}")]
#[error("Failed to complete isolated import")]
CompleteIsolatedImport(#[source] anyhow::Error),
/// Failed to set VM property
///
#[error("Failed to set VM property: {0}")]
#[error("Failed to set VM property")]
SetVmProperty(#[source] anyhow::Error),
///
/// Modify GPA host access error
///
#[cfg(feature = "sev_snp")]
#[error("Failed to modify GPA host access: {0}")]
#[error("Failed to modify GPA host access")]
ModifyGpaHostAccess(#[source] anyhow::Error),
///
/// Failed to mmap
@@ -258,7 +258,7 @@ pub enum HypervisorVmError {
///
/// Failed to initialize VM
///
#[error("Failed to initialize VM: {0}")]
#[error("Failed to initialize VM")]
InitializeVm(#[source] anyhow::Error),
}
///

View File

@@ -6,13 +6,13 @@ version = "0.1.0"
[dependencies]
epoll = "4.3.3"
getrandom = "0.3.1"
getrandom = "0.3.3"
libc = "0.2.167"
log = "0.4.22"
net_gen = { path = "../net_gen" }
rate_limiter = { path = "../rate_limiter" }
serde = { version = "1.0.208", features = ["derive"] }
thiserror = "2.0.6"
thiserror = { workspace = true }
virtio-bindings = { workspace = true }
virtio-queue = { workspace = true }
vm-memory = { workspace = true, features = [
@@ -24,7 +24,6 @@ vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = { workspace = true }
[dev-dependencies]
once_cell = "1.20.2"
pnet = "0.35.0"
pnet_datalink = "0.35.0"
serde_json = { workspace = true }

View File

@@ -4,19 +4,17 @@
use std::sync::Arc;
use libc::c_uint;
use thiserror::Error;
use virtio_bindings::virtio_net::{
VIRTIO_NET_CTRL_GUEST_OFFLOADS, VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, VIRTIO_NET_CTRL_MQ,
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN,
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, VIRTIO_NET_ERR, VIRTIO_NET_F_GUEST_CSUM,
VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_OK,
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, VIRTIO_NET_ERR, VIRTIO_NET_OK,
};
use virtio_queue::{Queue, QueueT};
use vm_memory::{ByteValued, Bytes, GuestMemoryError};
use vm_virtio::{AccessPlatform, Translatable};
use super::virtio_features_to_tap_offload;
use crate::{GuestMemoryMmap, Tap};
#[derive(Error, Debug)]
@@ -163,24 +161,3 @@ impl CtrlQueue {
Ok(())
}
}
pub fn virtio_features_to_tap_offload(features: u64) -> c_uint {
let mut tap_offloads: c_uint = 0;
if features & (1 << VIRTIO_NET_F_GUEST_CSUM) != 0 {
tap_offloads |= net_gen::TUN_F_CSUM;
}
if features & (1 << VIRTIO_NET_F_GUEST_TSO4) != 0 {
tap_offloads |= net_gen::TUN_F_TSO4;
}
if features & (1 << VIRTIO_NET_F_GUEST_TSO6) != 0 {
tap_offloads |= net_gen::TUN_F_TSO6;
}
if features & (1 << VIRTIO_NET_F_GUEST_ECN) != 0 {
tap_offloads |= net_gen::TUN_F_TSO_ECN;
}
if features & (1 << VIRTIO_NET_F_GUEST_UFO) != 0 {
tap_offloads |= net_gen::TUN_F_UFO;
}
tap_offloads
}

View File

@@ -40,7 +40,7 @@ pub use tap::{Error as TapError, Tap};
#[derive(Error, Debug)]
pub enum Error {
#[error("Failed to create a socket: {0}")]
#[error("Failed to create a socket")]
CreateSocket(#[source] IoError),
}

View File

@@ -12,27 +12,27 @@ use super::{vnet_hdr_len, MacAddr, Tap, TapError};
#[derive(Error, Debug)]
pub enum Error {
#[error("Failed to convert an hexadecimal string into an integer: {0}")]
#[error("Failed to convert an hexadecimal string into an integer")]
ConvertHexStringToInt(#[source] std::num::ParseIntError),
#[error("Error related to the multiqueue support (no support TAP side)")]
MultiQueueNoTapSupport,
#[error("Error related to the multiqueue support (no support device side)")]
MultiQueueNoDeviceSupport,
#[error("Failed to read the TAP flags from sysfs: {0}")]
#[error("Failed to read the TAP flags from sysfs")]
ReadSysfsTunFlags(#[source] io::Error),
#[error("Open tap device failed: {0}")]
#[error("Open tap device failed")]
TapOpen(#[source] TapError),
#[error("Setting tap IP and/or netmask failed: {0}")]
#[error("Setting tap IP and/or netmask failed")]
TapSetIpNetmask(#[source] TapError),
#[error("Setting MAC address failed: {0}")]
#[error("Setting MAC address failed")]
TapSetMac(#[source] TapError),
#[error("Getting MAC address failed: {0}")]
#[error("Getting MAC address failed")]
TapGetMac(#[source] TapError),
#[error("Setting vnet header size failed: {0}")]
#[error("Setting vnet header size failed")]
TapSetVnetHdrSize(#[source] TapError),
#[error("Setting MTU failed: {0}")]
#[error("Setting MTU failed")]
TapSetMtu(#[source] TapError),
#[error("Enabling tap interface failed: {0}")]
#[error("Enabling tap interface failed")]
TapEnable(#[source] TapError),
}
@@ -58,6 +58,54 @@ fn check_mq_support(if_name: &Option<&str>, queue_pairs: usize) -> Result<()> {
Ok(())
}
/// Opens a Tap device and configures it.
///
/// Afterward, further RX queues can be opened with a common config.
fn open_tap_rx_q_0(
if_name: Option<&str>,
ip_addr: Option<IpAddr>,
netmask: Option<IpAddr>,
host_mac: &mut Option<MacAddr>,
mtu: Option<u16>,
num_rx_q: usize,
flags: Option<i32>,
) -> Result<Tap> {
// Check if the given interface exists before we create it.
let tap_exists = if_name.is_some_and(|n| Path::new(&format!("/sys/class/net/{n}")).exists());
let tap = match if_name {
Some(name) => Tap::open_named(name, num_rx_q, flags).map_err(Error::TapOpen)?,
// Create a new Tap device in Linux, if none was specified.
None => Tap::new(num_rx_q).map_err(Error::TapOpen)?,
};
// Don't overwrite ip configuration of existing interfaces:
if !tap_exists {
if let Some(ip) = ip_addr {
tap.set_ip_addr(ip, netmask)
.map_err(Error::TapSetIpNetmask)?;
}
} else {
warn!(
"Tap {} already exists. IP configuration will not be overwritten.",
if_name.unwrap_or_default()
);
}
if let Some(mac) = host_mac {
tap.set_mac_addr(*mac).map_err(Error::TapSetMac)?
} else {
*host_mac = Some(tap.get_mac_addr().map_err(Error::TapGetMac)?)
}
if let Some(mtu) = mtu {
tap.set_mtu(mtu as i32).map_err(Error::TapSetMtu)?;
}
tap.enable().map_err(Error::TapEnable)?;
tap.set_vnet_hdr_size(vnet_hdr_len() as i32)
.map_err(Error::TapSetVnetHdrSize)?;
Ok(tap)
}
/// Create a new virtio network device with the given IP address and
/// netmask.
pub fn open_tap(
@@ -71,9 +119,6 @@ pub fn open_tap(
) -> Result<Vec<Tap>> {
let mut taps: Vec<Tap> = Vec::new();
let mut ifname: String = String::new();
let vnet_hdr_size = vnet_hdr_len() as i32;
// Check if the given interface exists before we create it.
let tap_existed = if_name.is_some_and(|n| Path::new(&format!("/sys/class/net/{n}")).exists());
// In case the tap interface already exists, check if the number of
// queues is appropriate. The tap might not support multiqueue while
@@ -85,40 +130,16 @@ pub fn open_tap(
for i in 0..num_rx_q {
let tap: Tap;
if i == 0 {
tap = match if_name {
Some(name) => Tap::open_named(name, num_rx_q, flags).map_err(Error::TapOpen)?,
None => Tap::new(num_rx_q).map_err(Error::TapOpen)?,
};
// Don't overwrite ip configuration of existing interfaces:
if !tap_existed {
if let Some(ip) = ip_addr {
tap.set_ip_addr(ip, netmask)
.map_err(Error::TapSetIpNetmask)?;
}
} else {
warn!(
"Tap {} already exists. IP configuration will not be overwritten.",
if_name.unwrap_or_default()
);
}
if let Some(mac) = host_mac {
tap.set_mac_addr(*mac).map_err(Error::TapSetMac)?
} else {
*host_mac = Some(tap.get_mac_addr().map_err(Error::TapGetMac)?)
}
if let Some(mtu) = mtu {
tap.set_mtu(mtu as i32).map_err(Error::TapSetMtu)?;
}
tap.enable().map_err(Error::TapEnable)?;
tap.set_vnet_hdr_size(vnet_hdr_size)
.map_err(Error::TapSetVnetHdrSize)?;
// Special handling is required for the first RX queue, such as
// configuring the device. Subsequent iterations will then use the
// same device.
tap = open_tap_rx_q_0(if_name, ip_addr, netmask, host_mac, mtu, num_rx_q, flags)?;
// Set the name of the tap device we open in subsequent iterations.
ifname = String::from_utf8(tap.get_if_name()).unwrap();
} else {
tap = Tap::open_named(ifname.as_str(), num_rx_q, flags).map_err(Error::TapOpen)?;
tap.set_vnet_hdr_size(vnet_hdr_size)
tap.set_vnet_hdr_size(vnet_hdr_len() as i32)
.map_err(Error::TapSetVnetHdrSize)?;
}
taps.push(tap);

View File

@@ -353,27 +353,27 @@ pub struct NetCounters {
pub enum NetQueuePairError {
#[error("No memory configured")]
NoMemoryConfigured,
#[error("Error registering listener: {0}")]
#[error("Error registering listener")]
RegisterListener(#[source] io::Error),
#[error("Error unregistering listener: {0}")]
#[error("Error unregistering listener")]
UnregisterListener(#[source] io::Error),
#[error("Error writing to the TAP device: {0}")]
#[error("Error writing to the TAP device")]
WriteTap(#[source] io::Error),
#[error("Error reading from the TAP device: {0}")]
#[error("Error reading from the TAP device")]
ReadTap(#[source] io::Error),
#[error("Error related to guest memory: {0}")]
#[error("Error related to guest memory")]
GuestMemory(#[source] vm_memory::GuestMemoryError),
#[error("Returned an error while iterating through the queue: {0}")]
#[error("Returned an error while iterating through the queue")]
QueueIteratorFailed(#[source] virtio_queue::Error),
#[error("Descriptor chain is too short")]
DescriptorChainTooShort,
#[error("Descriptor chain does not contain valid descriptors")]
DescriptorChainInvalid,
#[error("Failed to determine if queue needed notification: {0}")]
#[error("Failed to determine if queue needed notification")]
QueueNeedsNotification(#[source] virtio_queue::Error),
#[error("Failed to enable notification on the queue: {0}")]
#[error("Failed to enable notification on the queue")]
QueueEnableNotification(#[source] virtio_queue::Error),
#[error("Failed to add used index to the queue: {0}")]
#[error("Failed to add used index to the queue")]
QueueAddUsed(#[source] virtio_queue::Error),
#[error("Descriptor with invalid virtio-net header")]
DescriptorInvalidHeader,

View File

@@ -20,23 +20,32 @@ use super::{
};
use crate::mac::MAC_ADDR_LEN;
/// Maximum length of a network interface name in Linux, excluding any NUL byte.
///
/// This corresponds to `IFNAMSIZ` in Linux [[0]].
///
/// [0]: https://elixir.bootlin.com/linux/v6.12/source/include/uapi/linux/if.h#L33
const MAX_INTERFACE_NAME_LEN: usize = 15;
#[derive(Error, Debug)]
pub enum Error {
#[error("Couldn't open /dev/net/tun: {0}")]
#[error("Couldn't open /dev/net/tun")]
OpenTun(#[source] IoError),
#[error("Unable to configure tap interface: {0}")]
#[error("Unable to configure tap interface")]
ConfigureTap(#[source] IoError),
#[error("Unable to retrieve features: {0}")]
#[error("Unable to retrieve features")]
GetFeatures(#[source] IoError),
#[error("Missing multiqueue support in the kernel")]
MultiQueueKernelSupport,
#[error("ioctl ({0}) failed: {1}")]
IoctlError(c_ulong, #[source] IoError),
#[error("Failed to create a socket: {0}")]
#[error("Failed to create a socket")]
NetUtil(#[source] NetUtilError),
#[error("Invalid interface name")]
InvalidIfname,
#[error("Error parsing MAC data: {0}")]
#[error("Interface name too long (max length is {MAX_INTERFACE_NAME_LEN}): {0}")]
IfnameTooLong(String),
#[error("Invalid interface name (does it exist?): {0}")]
InvalidIfname(String),
#[error("Error parsing MAC data")]
MacParsing(#[source] IoError),
#[error("Invalid netmask")]
InvalidNetmask,
@@ -76,16 +85,14 @@ impl std::clone::Clone for Tap {
fn build_terminated_if_name(if_name: &str) -> Result<Vec<u8>> {
// Convert the string slice to bytes, and shadow the variable,
// since we no longer need the &str version.
let if_name = if_name.as_bytes();
let bytes = if_name.as_bytes();
// TODO: the 16usize limit of the if_name member from struct Tap is pretty arbitrary.
// We leave it as is for now, but this should be refactored at some point.
if if_name.len() > 15 {
return Err(Error::InvalidIfname);
if bytes.len() > MAX_INTERFACE_NAME_LEN {
return Err(Error::IfnameTooLong(if_name.to_string()));
}
let mut terminated_if_name = vec![b'\0'; if_name.len() + 1];
terminated_if_name[..if_name.len()].copy_from_slice(if_name);
let mut terminated_if_name = vec![b'\0'; bytes.len() + 1];
terminated_if_name[..bytes.len()].copy_from_slice(bytes);
Ok(terminated_if_name)
}
@@ -313,7 +320,10 @@ impl Tap {
// SAFETY: ifru_ivalue contains the ifindex and is set by the previous ioctl
unsafe {
match ifreq.ifr_ifru.ifru_ivalue {
0 => return Err(Error::InvalidIfname),
0 => {
let name = String::from_utf8_lossy(&self.if_name).to_string();
return Err(Error::InvalidIfname(name));
}
i => i,
}
}
@@ -506,11 +516,10 @@ impl AsRawFd for Tap {
#[cfg(test)]
mod tests {
use std::net::Ipv4Addr;
use std::sync::{mpsc, Mutex};
use std::sync::{mpsc, LazyLock, Mutex};
use std::time::Duration;
use std::{str, thread};
use once_cell::sync::Lazy;
use pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket};
use pnet::packet::ip::IpNextHeaderProtocols;
use pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet};
@@ -525,13 +534,14 @@ mod tests {
static DATA_STRING: &str = "test for tap";
static SUBNET_MASK: &str = "255.255.255.0";
// We needed to have a mutex as a global variable, so we used once_cell for testing. The main
// We needed to have a mutex as a global variable, so we use a once cell for testing. The main
// potential problem, caused by tests being run in parallel by cargo, is creating different
// TAPs and trying to associate the same address, so we hide the IP address &str behind this
// mutex, more as a convention to remember to lock it at the very beginning of each function
// susceptible to this issue. Another variant is to use a different IP address per function,
// but we must remember to pick an unique one each time.
static TAP_IP_LOCK: Lazy<Mutex<&'static str>> = Lazy::new(|| Mutex::new("192.168.241.1"));
static TAP_IP_LOCK: LazyLock<Mutex<&'static str>> =
LazyLock::new(|| Mutex::new("192.168.241.1"));
// Describes the outcomes we are currently interested in when parsing a packet (we use
// an UDP packet for testing).

View File

@@ -5,4 +5,4 @@ name = "option_parser"
version = "0.1.0"
[dependencies]
thiserror = "2.0.6"
thiserror = { workspace = true }

View File

@@ -306,11 +306,11 @@ pub struct Tuple<S, T>(pub Vec<(S, T)>);
pub enum TupleError {
#[error("invalid value: {0}")]
InvalidValue(String),
#[error("split outside brackets: {0}")]
#[error("split outside brackets")]
SplitOutsideBrackets(#[source] OptionParserError),
#[error("invalid integer list: {0}")]
#[error("invalid integer list")]
InvalidIntegerList(#[source] IntegerListParseError),
#[error("invalid integer: {0}")]
#[error("invalid integer")]
InvalidInteger(#[source] ParseIntError),
}

View File

@@ -6,8 +6,8 @@ version = "0.1.0"
[features]
default = []
kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"]
kvm = ["hypervisor/kvm", "vfio-ioctls/kvm"]
mshv = ["hypervisor/mshv", "vfio-ioctls/mshv"]
[dependencies]
anyhow = "1.0.94"
@@ -16,7 +16,7 @@ hypervisor = { path = "../hypervisor" }
libc = "0.2.167"
log = "0.4.22"
serde = { version = "1.0.208", features = ["derive"] }
thiserror = "2.0.6"
thiserror = { workspace = true }
vfio-bindings = { workspace = true, features = ["fam-wrappers"] }
vfio-ioctls = { workspace = true, default-features = false }
vfio_user = { workspace = true }

View File

@@ -27,16 +27,16 @@ const NUM_DEVICE_IDS: usize = 32;
#[derive(Error, Debug)]
pub enum PciRootError {
/// Could not allocate device address space for the device.
#[error("Could not allocate device address space for the device: {0}")]
#[error("Could not allocate device address space for the device")]
AllocateDeviceAddrs(#[source] PciDeviceError),
/// Could not allocate an IRQ number.
#[error("Could not allocate an IRQ number")]
AllocateIrq,
/// Could not add a device to the port io bus.
#[error("Could not add a device to the port io bus: {0}")]
#[error("Could not add a device to the port io bus")]
PioInsert(#[source] vm_device::BusError),
/// Could not add a device to the mmio bus.
#[error("Could not add a device to the mmio bus: {0}")]
#[error("Could not add a device to the mmio bus")]
MmioInsert(#[source] vm_device::BusError),
/// Could not find an available device slot on the PCI bus.
#[error("Could not find an available device slot on the PCI bus")]

View File

@@ -18,13 +18,13 @@ use crate::PciBarConfiguration;
#[derive(Error, Debug)]
pub enum Error {
/// Setup of the device capabilities failed.
#[error("Setup of the device capabilities failed: {0}")]
#[error("Setup of the device capabilities failed")]
CapabilitiesSetup(#[source] configuration::Error),
/// Allocating space for an IO BAR failed.
#[error("Allocating space for an IO BAR failed")]
IoAllocationFailed(u64),
/// Registering an IO BAR failed.
#[error("Registering an IO BAR failed: {0}")]
#[error("Registering an IO BAR failed")]
IoRegistrationFailed(u64, #[source] configuration::Error),
/// Expected resource not found.
#[error("Expected resource not found")]

View File

@@ -39,9 +39,9 @@ pub fn msi_num_enabled_vectors(msg_ctl: u16) -> usize {
#[derive(Error, Debug)]
pub enum Error {
#[error("Failed enabling the interrupt route: {0}")]
#[error("Failed enabling the interrupt route")]
EnableInterruptRoute(#[source] io::Error),
#[error("Failed updating the interrupt route: {0}")]
#[error("Failed updating the interrupt route")]
UpdateInterruptRoute(#[source] io::Error),
}

View File

@@ -31,10 +31,10 @@ pub const MSIX_CONFIG_ID: &str = "msix_config";
#[derive(Error, Debug)]
pub enum Error {
/// Failed enabling the interrupt route.
#[error("Failed enabling the interrupt route: {0}")]
#[error("Failed enabling the interrupt route")]
EnableInterruptRoute(#[source] io::Error),
/// Failed updating the interrupt route.
#[error("Failed updating the interrupt route: {0}")]
#[error("Failed updating the interrupt route")]
UpdateInterruptRoute(#[source] io::Error),
}

View File

@@ -47,17 +47,17 @@ pub(crate) const VFIO_COMMON_ID: &str = "vfio_common";
#[derive(Debug, Error)]
pub enum VfioPciError {
#[error("Failed to create user memory region: {0}")]
#[error("Failed to create user memory region")]
CreateUserMemoryRegion(#[source] HypervisorVmError),
#[error("Failed to DMA map: {0} for device {1} (guest BDF: {2})")]
DmaMap(#[source] vfio_ioctls::VfioError, PathBuf, PciBdf),
#[error("Failed to DMA unmap: {0} for device {1} (guest BDF: {2})")]
DmaUnmap(#[source] vfio_ioctls::VfioError, PathBuf, PciBdf),
#[error("Failed to enable INTx: {0}")]
#[error("Failed to enable INTx")]
EnableIntx(#[source] VfioError),
#[error("Failed to enable MSI: {0}")]
#[error("Failed to enable MSI")]
EnableMsi(#[source] VfioError),
#[error("Failed to enable MSI-x: {0}")]
#[error("Failed to enable MSI-x")]
EnableMsix(#[source] VfioError),
#[error("Failed to mmap the area")]
MmapArea,
@@ -67,13 +67,13 @@ pub enum VfioPciError {
RegionAlignment,
#[error("Invalid region size")]
RegionSize,
#[error("Failed to retrieve MsiConfigState: {0}")]
#[error("Failed to retrieve MsiConfigState")]
RetrieveMsiConfigState(#[source] anyhow::Error),
#[error("Failed to retrieve MsixConfigState: {0}")]
#[error("Failed to retrieve MsixConfigState")]
RetrieveMsixConfigState(#[source] anyhow::Error),
#[error("Failed to retrieve PciConfigurationState: {0}")]
#[error("Failed to retrieve PciConfigurationState")]
RetrievePciConfigurationState(#[source] anyhow::Error),
#[error("Failed to retrieve VfioCommonState: {0}")]
#[error("Failed to retrieve VfioCommonState")]
RetrieveVfioCommonState(#[source] anyhow::Error),
}
@@ -318,9 +318,9 @@ impl MmioRegionRange for Vec<MmioRegion> {
#[derive(Debug, Error)]
pub enum VfioError {
#[error("Kernel VFIO error: {0}")]
#[error("Kernel VFIO error")]
KernelVfio(#[source] vfio_ioctls::VfioError),
#[error("VFIO user error: {0}")]
#[error("VFIO user error")]
VfioUser(#[source] vfio_user::Error),
}

View File

@@ -40,17 +40,17 @@ pub struct VfioUserPciDevice {
#[derive(Error, Debug)]
pub enum VfioUserPciDeviceError {
#[error("Client error: {0}")]
#[error("Client error")]
Client(#[source] VfioUserError),
#[error("Failed to map VFIO PCI region into guest: {0}")]
#[error("Failed to map VFIO PCI region into guest")]
MapRegionGuest(#[source] HypervisorVmError),
#[error("Failed to DMA map: {0}")]
#[error("Failed to DMA map")]
DmaMap(#[source] VfioUserError),
#[error("Failed to DMA unmap: {0}")]
#[error("Failed to DMA unmap")]
DmaUnmap(#[source] VfioUserError),
#[error("Failed to initialize legacy interrupts: {0}")]
#[error("Failed to initialize legacy interrupts")]
InitializeLegacyInterrupts(#[source] VfioPciError),
#[error("Failed to create VfioCommon: {0}")]
#[error("Failed to create VfioCommon")]
CreateVfioCommon(#[source] VfioPciError),
}

View File

@@ -11,5 +11,4 @@ dirs = "6.0.0"
serde = { version = "1.0.208", features = ["derive", "rc"] }
serde_json = { workspace = true }
test_infra = { path = "../test_infra" }
thiserror = "2.0.6"
wait-timeout = "0.2.0"
thiserror = { workspace = true }

View File

@@ -24,18 +24,12 @@ pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-arm64-custom-20210929-
enum Error {
#[error("boot time could not be parsed")]
BootTimeParse,
#[error("infrastructure failure: {0}")]
Infra(#[source] InfraError),
#[error("infrastructure failure")]
Infra(#[from] InfraError),
#[error("restore time could not be parsed")]
RestoreTimeParse,
}
impl From<InfraError> for Error {
fn from(e: InfraError) -> Self {
Self::Infra(e)
}
}
const BLK_IO_TEST_IMG: &str = "/var/tmp/ch-blk-io-test.img";
pub fn init_tests() {
@@ -74,9 +68,9 @@ fn direct_kernel_boot_path() -> PathBuf {
let mut kernel_path = workload_path;
#[cfg(target_arch = "x86_64")]
kernel_path.push("vmlinux");
kernel_path.push("vmlinux-x86_64");
#[cfg(target_arch = "aarch64")]
kernel_path.push("Image");
kernel_path.push("Image-arm64");
kernel_path
}

View File

@@ -7,5 +7,5 @@ version = "0.1.0"
epoll = "4.3.3"
libc = "0.2.167"
log = "0.4.22"
thiserror = "2.0.6"
thiserror = { workspace = true }
vmm-sys-util = { workspace = true }

View File

@@ -23,23 +23,23 @@ pub enum Error {
ThreadSpawn(#[source] io::Error),
/// Cannot create epoll context.
#[error("Error creating epoll context: {0}")]
#[error("Error creating epoll context")]
Epoll(#[source] io::Error),
/// Cannot create EventFd.
#[error("Error creating EventFd: {0}")]
#[error("Error creating EventFd")]
EventFd(#[source] io::Error),
/// Cannot create RateLimiter.
#[error("Error creating RateLimiter: {0}")]
#[error("Error creating RateLimiter")]
RateLimiter(#[source] io::Error),
/// Cannot read from EventFd.
#[error("Error reading from EventFd: {0}")]
#[error("Error reading from EventFd")]
EventFdRead(#[source] io::Error),
/// Cannot write to EventFd.
#[error("Error writing to EventFd: {0}")]
#[error("Error writing to EventFd")]
EventFdWrite(#[source] io::Error),
}

View File

@@ -65,7 +65,7 @@ pub enum Error {
#[error("Event handler was called spuriously: {0}")]
SpuriousRateLimiterEvent(&'static str),
/// The event handler encounters while TimerFd::wait()
#[error("Failed to wait for the timer: {0}")]
#[error("Failed to wait for the timer")]
TimerFdWaitError(#[source] std::io::Error),
}
@@ -486,7 +486,7 @@ impl RateLimiter {
/// Updates the parameters of the token buckets associated with this RateLimiter.
// TODO: Please note that, right now, the buckets become full after being updated.
pub fn update_buckets(&mut self, bytes: BucketUpdate, ops: BucketUpdate) {
let mut guard = self.inner.lock().unwrap();
let guard = self.inner.get_mut().unwrap();
match bytes {
BucketUpdate::Disabled => guard.bandwidth = None,
BucketUpdate::Update(tb) => guard.bandwidth = Some(tb),

View File

@@ -1,50 +1,57 @@
- [v47.0](#v470)
- [Block Device Error Reporting to the Guest](#block-device-error-reporting-to-the-guest)
- [Nice Error Messages on Exit](#nice-error-messages-on-exit)
- [Alphabetically Sorted CLI Options for ch-remote](#alphabetically-sorted-cli-options-for-ch-remote)
- [Notable Bug Fixes](#notable-bug-fixes)
- [Deprecations](#deprecations)
- [Contributors](#contributors)
- [v46.0](#v460)
- [File-level Locking Support with `--disk`](#file-level-locking-support-with---disk)
- [Improved Error Reporting with VM Resizing](#improved-error-reporting-with-vm-resizing)
- [IPv6 Address Support with `--net`](#ipv6-address-support-with---net)
- [Experimental AArch64 Support with the MSHV Hypervisor](#experimental-aarch64-support-with-the-mshv-hypervisor)
- [Deprecated SGX Support](#deprecated-sgx-support)
- [Notable Bug Fixes](#notable-bug-fixes)
- [Contributors](#contributors)
- [Notable Bug Fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-1)
- [v45.0](#v450)
- [Experimental `riscv64` Architecture Support](#experimental-riscv64-architecture-support)
- [Alphabetically Sorted CLI Options](#alphabetically-sorted-cli-options)
- [Improved Downtime of VM Live Migration](#improved-downtime-of-vm-live-migration)
- [Notable Bug Fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-1)
- [Notable Bug Fixes](#notable-bug-fixes-2)
- [Contributors](#contributors-2)
- [v44.0](#v440)
- [Configurable `virtio-iommu` Address Width](#configurable-virtio-iommu-address-width)
- [Notable Performance Improvements](#notable-performance-improvements)
- [New Fuzzers](#new-fuzzers)
- [Notable Bug Fixes](#notable-bug-fixes-2)
- [Contributors](#contributors-2)
- [Notable Bug Fixes](#notable-bug-fixes-3)
- [Contributors](#contributors-3)
- [v43.0](#v430)
- [Live Migration over TCP Connections](#live-migration-over-tcp-connections)
- [Notable Performance Improvements](#notable-performance-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-3)
- [Contributors](#contributors-3)
- [Notable Bug Fixes](#notable-bug-fixes-4)
- [Contributors](#contributors-4)
- [v42.0](#v420)
- [SVE/SVE2 Support on AArch64](#svesve2-support-on-aarch64)
- [Notable Bug Fixes](#notable-bug-fixes-4)
- [Notable Bug Fixes](#notable-bug-fixes-5)
- [Sponsorships](#sponsorships)
- [Contributors](#contributors-4)
- [Contributors](#contributors-5)
- [v41.0](#v410)
- [Experimental "Pvmemcontrol" Support](#experimental-pvmemcontrol-support)
- [Sandboxing With Landlock Support](#sandboxing-with-landlock-support)
- [Notable Performance Improvements](#notable-performance-improvements-2)
- [Notable Bug Fixes](#notable-bug-fixes-5)
- [Contributors](#contributors-5)
- [v40.0](#v400)
- [Support for Restoring File Descriptor Backed Network Devices](#support-for-restoring-file-descriptor-backed-network-devices)
- [Notable Bug Fixes](#notable-bug-fixes-6)
- [Contributors](#contributors-6)
- [v40.0](#v400)
- [Support for Restoring File Descriptor Backed Network Devices](#support-for-restoring-file-descriptor-backed-network-devices)
- [Notable Bug Fixes](#notable-bug-fixes-7)
- [Contributors](#contributors-7)
- [v39.0](#v390)
- [Variable Sizing of PCI Apertures for Segments](#variable-sizing-of-pci-apertures-for-segments)
- [Direct Booting with bzImages](#direct-booting-with-bzimages)
- [Support for NVIDIA GPUDirect P2P Support](#support-for-nvidia-gpudirect-p2p-support)
- [Guest NMI Injection Support](#guest-nmi-injection-support)
- [Notable Bug Fixes](#notable-bug-fixes-7)
- [Contributors](#contributors-7)
- [Notable Bug Fixes](#notable-bug-fixes-8)
- [Contributors](#contributors-8)
- [v38.0](#v380)
- [Group Rate Limiter on Block Devices](#group-rate-limiter-on-block-devices)
- [CPU Pinning Support for Block Device Worker Thread](#cpu-pinning-support-for-block-device-worker-thread)
@@ -52,16 +59,16 @@
- [New 'debug-console' Device](#new-debug-console-device)
- [Improved VFIO Device Support](#improved-vfio-device-support)
- [Extended CPU Affinity Support](#extended-cpu-affinity-support)
- [Notable Bug Fixes](#notable-bug-fixes-8)
- [Contributors](#contributors-8)
- [Notable Bug Fixes](#notable-bug-fixes-9)
- [Contributors](#contributors-9)
- [v37.0](#v370)
- [Long Term Support (LTS) Release](#long-term-support-lts-release)
- [Multiple PCI segments Support for 32-bit VFIO devices](#multiple-pci-segments-support-for-32-bit-vfio-devices)
- [Configurable Named TAP Devices](#configurable-named-tap-devices)
- [TTY Output from Both Serial Device and Virtio Console](#tty-output-from-both-serial-device-and-virtio-console)
- [Faster VM Restoration from Snapshots](#faster-vm-restoration-from-snapshots)
- [Notable Bug Fixes](#notable-bug-fixes-9)
- [Contributors](#contributors-9)
- [Notable Bug Fixes](#notable-bug-fixes-10)
- [Contributors](#contributors-10)
- [v36.0](#v360)
- [Command Line Changes](#command-line-changes)
- [Enabled Features Reported via API Endpoint and CLI](#enabled-features-reported-via-api-endpoint-and-cli)
@@ -70,31 +77,31 @@
- [Unix Socket Backend for Serial Port](#unix-socket-backend-for-serial-port)
- [AIO Backend for Block Devices](#aio-backend-for-block-devices)
- [Documentation Improvements](#documentation-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-10)
- [Contributors](#contributors-10)
- [Notable Bug Fixes](#notable-bug-fixes-11)
- [Contributors](#contributors-11)
- [v35.0](#v350)
- [`virtio-vsock` Support for Linux Guest Kernel v6.3+](#virtio-vsock-support-for-linux-guest-kernel-v63)
- [User Specified Serial Number for `virtio-block`](#user-specified-serial-number-for-virtio-block)
- [vCPU TSC Frequency Included in Migration State](#vcpu-tsc-frequency-included-in-migration-state)
- [Notable Bug Fixes](#notable-bug-fixes-11)
- [Contributors](#contributors-11)
- [Notable Bug Fixes](#notable-bug-fixes-12)
- [Contributors](#contributors-12)
- [v34.0](#v340)
- [Paravirtualised Panic Device Support](#paravirtualised-panic-device-support)
- [Improvements to VM Core Dump](#improvements-to-vm-core-dump)
- [QCOW2 Support for Backing Files](#qcow2-support-for-backing-files)
- [Minimum Host Kernel Bump](#minimum-host-kernel-bump)
- [Notable Bug Fixes](#notable-bug-fixes-12)
- [Contributors](#contributors-12)
- [Notable Bug Fixes](#notable-bug-fixes-13)
- [Contributors](#contributors-13)
- [v33.0](#v330)
- [D-Bus based API](#d-bus-based-api)
- [Expose Host CPU Cache Details for AArch64](#expose-host-cpu-cache-details-for-aarch64)
- [Notable Bug Fixes](#notable-bug-fixes-13)
- [Contributors](#contributors-13)
- [Notable Bug Fixes](#notable-bug-fixes-14)
- [Contributors](#contributors-14)
- [v32.0](#v320)
- [Increased PCI Segment Limit](#increased-pci-segment-limit)
- [API Changes](#api-changes)
- [Notable Bug Fixes](#notable-bug-fixes-14)
- [Contributors](#contributors-14)
- [Notable Bug Fixes](#notable-bug-fixes-15)
- [Contributors](#contributors-15)
- [v31.1](#v311)
- [v31.0](#v310)
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
@@ -102,15 +109,15 @@
- [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler)
- [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile)
- [Documentation Improvements](#documentation-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-15)
- [Contributors](#contributors-15)
- [Notable Bug Fixes](#notable-bug-fixes-16)
- [Contributors](#contributors-16)
- [v30.0](#v300)
- [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size)
- [Basic vfio-user Server Support](#basic-vfio-user-server-support)
- [Heap Profiling Support](#heap-profiling-support)
- [Documentation Improvements](#documentation-improvements-2)
- [Notable Bug Fixes](#notable-bug-fixes-16)
- [Contributors](#contributors-16)
- [Notable Bug Fixes](#notable-bug-fixes-17)
- [Contributors](#contributors-17)
- [v28.2](#v282)
- [v29.0](#v290)
- [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm)
@@ -120,10 +127,10 @@
- [`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-17)
- [Notable Bug Fixes](#notable-bug-fixes-18)
- [Removals](#removals)
- [Deprecations](#deprecations)
- [Contributors](#contributors-17)
- [Deprecations](#deprecations-1)
- [Contributors](#contributors-18)
- [v28.1](#v281)
- [v28.0](#v280)
- [Community Engagement (Reminder)](#community-engagement-reminder)
@@ -131,9 +138,9 @@
- [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-18)
- [Notable Bug Fixes](#notable-bug-fixes-19)
- [Removals](#removals-1)
- [Contributors](#contributors-18)
- [Contributors](#contributors-19)
- [v27.0](#v270)
- [Community Engagement](#community-engagement)
- [Prebuilt Packages](#prebuilt-packages)
@@ -142,41 +149,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-19)
- [Deprecations](#deprecations-1)
- [Contributors](#contributors-19)
- [Notable Bug Fixes](#notable-bug-fixes-20)
- [Deprecations](#deprecations-2)
- [Contributors](#contributors-20)
- [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-20)
- [Deprecations](#deprecations-2)
- [Notable Bug Fixes](#notable-bug-fixes-21)
- [Deprecations](#deprecations-3)
- [Removals](#removals-2)
- [Contributors](#contributors-20)
- [Contributors](#contributors-21)
- [v25.0](#v250)
- [`ch-remote` Improvements](#ch-remote-improvements-1)
- [VM "Coredump" Support](#vm-coredump-support)
- [Notable Bug Fixes](#notable-bug-fixes-21)
- [Notable Bug Fixes](#notable-bug-fixes-22)
- [Removals](#removals-3)
- [Contributors](#contributors-21)
- [Contributors](#contributors-22)
- [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-22)
- [Notable Bug Fixes](#notable-bug-fixes-23)
- [Notable Improvements](#notable-improvements)
- [Deprecations](#deprecations-3)
- [Deprecations](#deprecations-4)
- [New on the Website](#new-on-the-website)
- [Contributors](#contributors-22)
- [Contributors](#contributors-23)
- [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-23)
- [Deprecations](#deprecations-4)
- [Contributors](#contributors-23)
- [Notable Bug Fixes](#notable-bug-fixes-24)
- [Deprecations](#deprecations-5)
- [Contributors](#contributors-24)
- [v22.1](#v221)
- [v22.0](#v220)
- [GDB Debug Stub Support](#gdb-debug-stub-support)
@@ -187,13 +194,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-24)
- [Contributors](#contributors-24)
- [Notable Bug Fixes](#notable-bug-fixes-25)
- [Contributors](#contributors-25)
- [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-25)
- [Contributors](#contributors-25)
- [Notable Bug fixes](#notable-bug-fixes-26)
- [Contributors](#contributors-26)
- [v20.2](#v202)
- [v20.1](#v201)
- [v20.0](#v200)
@@ -202,8 +209,8 @@
- [Improved VFIO support](#improved-vfio-support)
- [Safer code](#safer-code)
- [Extended documentation](#extended-documentation)
- [Notable bug fixes](#notable-bug-fixes-26)
- [Contributors](#contributors-26)
- [Notable bug fixes](#notable-bug-fixes-27)
- [Contributors](#contributors-27)
- [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)
@@ -211,8 +218,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-27)
- [Contributors](#contributors-27)
- [Notable bug fixes](#notable-bug-fixes-28)
- [Contributors](#contributors-28)
- [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)
@@ -222,31 +229,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-28)
- [Contributors](#contributors-28)
- [Notable bug fixes](#notable-bug-fixes-29)
- [Contributors](#contributors-29)
- [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-29)
- [Contributors](#contributors-29)
- [Notable bug fixes](#notable-bug-fixes-30)
- [Contributors](#contributors-30)
- [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-30)
- [Notable bug fixes](#notable-bug-fixes-31)
- [Removed functionality](#removed-functionality)
- [Contributors](#contributors-30)
- [Contributors](#contributors-31)
- [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-5)
- [Contributors](#contributors-31)
- [Deprecations](#deprecations-6)
- [Contributors](#contributors-32)
- [v0.14.1](#v0141)
- [v0.14.0](#v0140)
- [Structured event monitoring](#structured-event-monitoring)
@@ -255,8 +262,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-6)
- [Contributors](#contributors-32)
- [Deprecations](#deprecations-7)
- [Contributors](#contributors-33)
- [v0.13.0](#v0130)
- [Wider VFIO device support](#wider-vfio-device-support)
- [Improved huge page support](#improved-huge-page-support)
@@ -264,13 +271,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-33)
- [Contributors](#contributors-34)
- [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-34)
- [Contributors](#contributors-35)
- [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)
@@ -282,15 +289,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-31)
- [Contributors](#contributors-35)
- [Notable Bug Fixes](#notable-bug-fixes-32)
- [Contributors](#contributors-36)
- [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-32)
- [Contributors](#contributors-36)
- [Notable Bug Fixes](#notable-bug-fixes-33)
- [Contributors](#contributors-37)
- [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)
@@ -303,17 +310,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-33)
- [Contributors](#contributors-37)
- [Notable Bug Fixes](#notable-bug-fixes-34)
- [Contributors](#contributors-38)
- [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-34)
- [Notable Bug Fixes](#notable-bug-fixes-35)
- [Command Line and API Changes](#command-line-and-api-changes)
- [Contributors](#contributors-38)
- [Contributors](#contributors-39)
- [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)
@@ -323,14 +330,14 @@
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
- [Updated Distribution Support](#updated-distribution-support)
- [Command Line and API Changes](#command-line-and-api-changes-1)
- [Contributors](#contributors-39)
- [Contributors](#contributors-40)
- [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-40)
- [Contributors](#contributors-41)
- [v0.5.1](#v051)
- [v0.5.0](#v050)
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
@@ -338,7 +345,7 @@
- [New Interrupt Management Framework](#new-interrupt-management-framework)
- [Development Tools](#development-tools)
- [Kata Containers Integration](#kata-containers-integration)
- [Contributors](#contributors-41)
- [Contributors](#contributors-42)
- [v0.4.0](#v040)
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
@@ -347,7 +354,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-42)
- [Contributors](#contributors-43)
- [v0.3.0](#v030)
- [Block device offloading](#block-device-offloading)
- [Network device backend](#network-device-backend)
@@ -374,6 +381,66 @@
- [Unit testing](#unit-testing)
- [Integration tests parallelization](#integration-tests-parallelization)
# v47.0
This release has been tracked in [v47.0
group](https://github.com/orgs/cloud-hypervisor/projects/6/views/4?filterQuery=release%3A%22Release+47%22)
of our [roadmap project](https://github.com/orgs/cloud-hypervisor/projects/6/).
### Block Device Error Reporting to the Guest
Instead of exiting on I/O errors, the `virtio-block` device now reports
errors to the guest using `VIRTIO_BLK_S_IOERR`. It improves the user
experience particularly when the guest rootfs is not backed by the
affected block device. (#7107)
### Nice Error Messages on Exit
We now have the chain of errors being reported and printed nicely, when
Cloud Hypervisor or ch-remote exits on errors. (#7066)
### Alphabetically Sorted CLI Options for ch-remote
To improve readability, ch-remote now prints help information in
alphabetical order. (#7130)
### Notable Bug Fixes
* Error out early when block device serial is too long (#7124)
* Fix partial commands being discarded for `virtio-vsock` (#7195)
* Disable the broken interrupt support for the `rtc_pl031` device to
prevent spurious guest interrupts (#7199)
### Deprecations
* A default IP (`192.168.249.1`) and mask (`255.255.255.0`) are
currently assigned to the `virtio-net` device if no value is specified
by users. Such behavior is now deprecated. Users of this behavior will
receive a warning message and should make adjustments. The behavior
will be removed in two release cycles (v49.0).
### Contributors
Many thanks to everyone who has contributed to our release:
* Alyssa Ross <hi@alyssa.is>
* Bo Chen <bchen@crusoe.ai>
* Demi Marie Obenour <demiobenour@gmail.com>
* Gauthier Jolly <contact@gjolly.fr>
* Hengqi Chen <hengqi.chen@gmail.com>
* Jinank Jain <jinankjain@microsoft.com>
* Jinrong Liang <cloudliang@tencent.com>
* Jean-Philippe Brucker <jean-philippe@linaro.org>
* Maximilian Güntner <code@mguentner.de>
* Muminul Islam <muislam@microsoft.com>
* Nuno Das Neves <nunodasneves@linux.microsoft.com>
* Philipp Schuster <philipp.schuster@cyberus-technology.de>
* Ruoqing He <heruoqing@iscas.ac.cn>
* Songqian Li <sionli@tencent.com>
* Wei Liu <liuwe@microsoft.com>
* Yi Wang <foxywang@tencent.com>
* ninollei <ninollx@hotmail.com>
# v46.0
This release has been tracked in [v46.0

View File

@@ -56,6 +56,7 @@ class TitleStartsWithComponent(LineRule):
'README',
'resources',
'scripts',
'seccomp',
'serial_buffer',
'test_data',
'test_infra',

View File

@@ -137,7 +137,7 @@ update_workloads() {
mkdir -p "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"
# Mount the 'raw' image, replace the compressed kernel file and umount the working folder
guestmount -a "$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_NAME" -m /dev/sda1 "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR" || exit 1
cp "$WORKLOADS_DIR"/Image.gz "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"/boot/vmlinuz
cp "$WORKLOADS_DIR"/Image-arm64.gz "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"/boot/vmlinuz
guestunmount "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"
# Build virtiofsd

View File

@@ -54,7 +54,7 @@ chmod +x $CH_RELEASE_NAME
popd || exit
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux-x86_64"
if [ ! -f "$VMLINUX_IMAGE" ]; then
# Prepare linux image (build from source or download pre-built)
prepare_linux

View File

@@ -100,7 +100,7 @@ fi
popd || exit
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux-x86_64"
if [ ! -f "$VMLINUX_IMAGE" ]; then
# Prepare linux image (build from source or download pre-built)
prepare_linux

View File

@@ -1,4 +1,6 @@
#!/usr/bin/env bash
set -x
hypervisor="kvm"
test_filter=""
build_kernel=false
@@ -56,11 +58,11 @@ build_custom_linux() {
make ch_defconfig
make -j "$(nproc)"
if [ "${ARCH}" == "x86_64" ]; then
cp vmlinux "$WORKLOADS_DIR/" || exit 1
cp arch/x86/boot/bzImage "$WORKLOADS_DIR/" || exit 1
cp vmlinux "$WORKLOADS_DIR/vmlinux-x86_64" || exit 1
cp arch/x86/boot/bzImage "$WORKLOADS_DIR/bzImage-x86_64" || exit 1
elif [ "${ARCH}" == "aarch64" ]; then
cp arch/arm64/boot/Image "$WORKLOADS_DIR/" || exit 1
cp arch/arm64/boot/Image.gz "$WORKLOADS_DIR/" || exit 1
cp arch/arm64/boot/Image "$WORKLOADS_DIR/Image-arm64" || exit 1
cp arch/arm64/boot/Image.gz "$WORKLOADS_DIR/Image-arm64.gz" || exit 1
fi
popd || exit
}
@@ -138,7 +140,7 @@ download_hypervisor_fw() {
}
download_linux() {
KERNEL_TAG="ch-release-v6.12.8-20250114"
KERNEL_TAG="ch-release-v6.12.8-20250613"
if [ -n "$AUTH_DOWNLOAD_TOKEN" ]; then
echo "Using authenticated download from GitHub"
KERNEL_URLS=$(curl --silent https://api.github.com/repos/cloud-hypervisor/linux/releases/tags/${KERNEL_TAG} \

View File

@@ -3,6 +3,10 @@
// SPDX-License-Identifier: Apache-2.0
//
#[cfg(test)]
#[path = "../test_util.rs"]
mod test_util;
use std::io::Read;
use std::marker::PhantomData;
use std::os::unix::net::UnixStream;
@@ -13,6 +17,7 @@ use api_client::{
Error as ApiClientError,
};
use clap::{Arg, ArgAction, ArgMatches, Command};
use log::error;
use option_parser::{ByteSized, ByteSizedParseError};
use thiserror::Error;
use vmm::config::RestoreConfig;
@@ -27,38 +32,38 @@ type ApiResult = Result<(), Error>;
#[derive(Error, Debug)]
enum Error {
#[error("http client error: {0}")]
#[error("http client error")]
HttpApiClient(#[source] ApiClientError),
#[cfg(feature = "dbus_api")]
#[error("dbus api client error: {0}")]
#[error("dbus api client error")]
DBusApiClient(#[source] zbus::Error),
#[error("Error parsing CPU count: {0}")]
#[error("Error parsing CPU count")]
InvalidCpuCount(#[source] std::num::ParseIntError),
#[error("Error parsing memory size: {0}")]
#[error("Error parsing memory size")]
InvalidMemorySize(#[source] ByteSizedParseError),
#[error("Error parsing balloon size: {0}")]
#[error("Error parsing balloon size")]
InvalidBalloonSize(#[source] ByteSizedParseError),
#[error("Error parsing device syntax: {0}")]
#[error("Error parsing device syntax")]
AddDeviceConfig(#[source] vmm::config::Error),
#[error("Error parsing disk syntax: {0}")]
#[error("Error parsing disk syntax")]
AddDiskConfig(#[source] vmm::config::Error),
#[error("Error parsing filesystem syntax: {0}")]
#[error("Error parsing filesystem syntax")]
AddFsConfig(#[source] vmm::config::Error),
#[error("Error parsing persistent memory syntax: {0}")]
#[error("Error parsing persistent memory syntax")]
AddPmemConfig(#[source] vmm::config::Error),
#[error("Error parsing network syntax: {0}")]
#[error("Error parsing network syntax")]
AddNetConfig(#[source] vmm::config::Error),
#[error("Error parsing user device syntax: {0}")]
#[error("Error parsing user device syntax")]
AddUserDeviceConfig(#[source] vmm::config::Error),
#[error("Error parsing vDPA device syntax: {0}")]
#[error("Error parsing vDPA device syntax")]
AddVdpaConfig(#[source] vmm::config::Error),
#[error("Error parsing vsock syntax: {0}")]
#[error("Error parsing vsock syntax")]
AddVsockConfig(#[source] vmm::config::Error),
#[error("Error parsing restore syntax: {0}")]
#[error("Error parsing restore syntax")]
Restore(#[source] vmm::config::Error),
#[error("Error reading from stdin: {0}")]
#[error("Error reading from stdin")]
ReadingStdin(#[source] std::io::Error),
#[error("Error reading from file: {0}")]
#[error("Error reading from file")]
ReadingFile(#[source] std::io::Error),
}
@@ -899,196 +904,183 @@ fn create_data(path: &str) -> Result<String, Error> {
Ok(data)
}
/// Returns all [`Arg`]s in alphabetical order.
///
/// This is the order used in the `--help` output.
fn get_cli_args() -> Box<[Arg]> {
[
Arg::new("api-socket")
.long("api-socket")
.help("HTTP API socket path (UNIX domain socket).")
.num_args(1),
#[cfg(feature = "dbus_api")]
Arg::new("dbus-object-path")
.long("dbus-object-path")
.help("Object path which the interface is being served at")
.num_args(1),
#[cfg(feature = "dbus_api")]
Arg::new("dbus-service-name")
.long("dbus-service-name")
.help("Well known name of the dbus service")
.num_args(1),
#[cfg(feature = "dbus_api")]
Arg::new("dbus-system-bus")
.long("dbus-system-bus")
.action(ArgAction::SetTrue)
.num_args(0)
.help("Use the system bus instead of a session bus"),
]
.to_vec()
.into_boxed_slice()
}
/// Returns all [`Command`]s in alphabetical order.
///
/// This is the order used in the `--help` output.
fn get_cli_commands_sorted() -> Box<[Command]> {
[
Command::new("add-device").about("Add VFIO device").arg(
Arg::new("device_config")
.index(1)
.help(DeviceConfig::SYNTAX),
),
Command::new("add-disk")
.about("Add block device")
.arg(Arg::new("disk_config").index(1).help(DiskConfig::SYNTAX)),
Command::new("add-fs")
.about("Add virtio-fs backed fs device")
.arg(
Arg::new("fs_config")
.index(1)
.help(vmm::vm_config::FsConfig::SYNTAX),
),
Command::new("add-net")
.about("Add network device")
.arg(Arg::new("net_config").index(1).help(NetConfig::SYNTAX)),
Command::new("add-pmem")
.about("Add persistent memory device")
.arg(
Arg::new("pmem_config")
.index(1)
.help(vmm::vm_config::PmemConfig::SYNTAX),
),
Command::new("add-user-device")
.about("Add userspace device")
.arg(
Arg::new("device_config")
.index(1)
.help(UserDeviceConfig::SYNTAX),
),
Command::new("add-vdpa")
.about("Add vDPA device")
.arg(Arg::new("vdpa_config").index(1).help(VdpaConfig::SYNTAX)),
Command::new("add-vsock")
.about("Add vsock device")
.arg(Arg::new("vsock_config").index(1).help(VsockConfig::SYNTAX)),
Command::new("boot").about("Boot a created VM"),
Command::new("coredump")
.about("Create a coredump from VM")
.arg(Arg::new("coredump_config").index(1).help("<file_path>")),
Command::new("counters").about("Counters from the VM"),
Command::new("create")
.about("Create VM from a JSON configuration")
.arg(Arg::new("path").index(1).default_value("-")),
Command::new("delete").about("Delete a VM"),
Command::new("info").about("Info on the VM"),
Command::new("nmi").about("Trigger NMI"),
Command::new("pause").about("Pause the VM"),
Command::new("ping").about("Ping the VMM to check for API server availability"),
Command::new("power-button").about("Trigger a power button in the VM"),
Command::new("reboot").about("Reboot the VM"),
Command::new("receive-migration")
.about("Receive a VM migration")
.arg(
Arg::new("receive_migration_config")
.index(1)
.help("<receiver_url>"),
),
Command::new("remove-device")
.about("Remove VFIO and PCI device")
.arg(Arg::new("id").index(1).help("<device_id>")),
Command::new("resize")
.about("Resize the VM")
.arg(
Arg::new("balloon")
.long("balloon")
.help("New balloon size in bytes (supports K/M/G suffix)")
.num_args(1),
)
.arg(
Arg::new("cpus")
.long("cpus")
.help("New vCPUs count")
.num_args(1),
)
.arg(
Arg::new("memory")
.long("memory")
.help("New memory size in bytes (supports K/M/G suffix)")
.num_args(1),
),
Command::new("resize-zone")
.about("Resize a memory zone")
.arg(
Arg::new("id")
.long("id")
.help("Memory zone identifier")
.num_args(1),
)
.arg(
Arg::new("size")
.long("size")
.help("New memory zone size in bytes (supports K/M/G suffix)")
.num_args(1),
),
Command::new("restore")
.about("Restore VM from a snapshot")
.arg(
Arg::new("restore_config")
.index(1)
.help(RestoreConfig::SYNTAX),
),
Command::new("resume").about("Resume the VM"),
Command::new("send-migration")
.about("Initiate a VM migration")
.arg(
Arg::new("send_migration_config")
.index(1)
.help("<destination_url>"),
)
.arg(
Arg::new("send_migration_local")
.long("local")
.num_args(0)
.action(ArgAction::SetTrue),
),
Command::new("shutdown").about("Shutdown the VM"),
Command::new("shutdown-vmm").about("Shutdown the VMM"),
Command::new("snapshot")
.about("Create a snapshot from VM")
.arg(
Arg::new("snapshot_config")
.index(1)
.help("<destination_url>"),
),
]
.to_vec()
.into_boxed_slice()
}
fn main() {
env_logger::init();
let app = Command::new("ch-remote")
.author(env!("CARGO_PKG_AUTHORS"))
.version(env!("BUILD_VERSION"))
.about("Remotely control a cloud-hypervisor VMM.")
.arg_required_else_help(true)
.subcommand_required(true)
.args([
Arg::new("api-socket")
.long("api-socket")
.help("HTTP API socket path (UNIX domain socket).")
.num_args(1),
#[cfg(feature = "dbus_api")]
Arg::new("dbus-service-name")
.long("dbus-service-name")
.help("Well known name of the dbus service")
.num_args(1),
#[cfg(feature = "dbus_api")]
Arg::new("dbus-object-path")
.long("dbus-object-path")
.help("Object path which the interface is being served at")
.num_args(1),
#[cfg(feature = "dbus_api")]
Arg::new("dbus-system-bus")
.long("dbus-system-bus")
.action(ArgAction::SetTrue)
.num_args(0)
.help("Use the system bus instead of a session bus"),
])
.subcommand(
Command::new("add-device").about("Add VFIO device").arg(
Arg::new("device_config")
.index(1)
.help(DeviceConfig::SYNTAX),
),
)
.subcommand(
Command::new("add-disk")
.about("Add block device")
.arg(Arg::new("disk_config").index(1).help(DiskConfig::SYNTAX)),
)
.subcommand(
Command::new("add-fs")
.about("Add virtio-fs backed fs device")
.arg(
Arg::new("fs_config")
.index(1)
.help(vmm::vm_config::FsConfig::SYNTAX),
),
)
.subcommand(
Command::new("add-pmem")
.about("Add persistent memory device")
.arg(
Arg::new("pmem_config")
.index(1)
.help(vmm::vm_config::PmemConfig::SYNTAX),
),
)
.subcommand(
Command::new("add-net")
.about("Add network device")
.arg(Arg::new("net_config").index(1).help(NetConfig::SYNTAX)),
)
.subcommand(
Command::new("add-user-device")
.about("Add userspace device")
.arg(
Arg::new("device_config")
.index(1)
.help(UserDeviceConfig::SYNTAX),
),
)
.subcommand(
Command::new("add-vdpa")
.about("Add vDPA device")
.arg(Arg::new("vdpa_config").index(1).help(VdpaConfig::SYNTAX)),
)
.subcommand(
Command::new("add-vsock")
.about("Add vsock device")
.arg(Arg::new("vsock_config").index(1).help(VsockConfig::SYNTAX)),
)
.subcommand(
Command::new("remove-device")
.about("Remove VFIO and PCI device")
.arg(Arg::new("id").index(1).help("<device_id>")),
)
.subcommand(Command::new("info").about("Info on the VM"))
.subcommand(Command::new("counters").about("Counters from the VM"))
.subcommand(Command::new("pause").about("Pause the VM"))
.subcommand(Command::new("reboot").about("Reboot the VM"))
.subcommand(Command::new("power-button").about("Trigger a power button in the VM"))
.subcommand(
Command::new("resize")
.about("Resize the VM")
.arg(
Arg::new("cpus")
.long("cpus")
.help("New vCPUs count")
.num_args(1),
)
.arg(
Arg::new("memory")
.long("memory")
.help("New memory size in bytes (supports K/M/G suffix)")
.num_args(1),
)
.arg(
Arg::new("balloon")
.long("balloon")
.help("New balloon size in bytes (supports K/M/G suffix)")
.num_args(1),
),
)
.subcommand(
Command::new("resize-zone")
.about("Resize a memory zone")
.arg(
Arg::new("id")
.long("id")
.help("Memory zone identifier")
.num_args(1),
)
.arg(
Arg::new("size")
.long("size")
.help("New memory zone size in bytes (supports K/M/G suffix)")
.num_args(1),
),
)
.subcommand(Command::new("resume").about("Resume the VM"))
.subcommand(Command::new("boot").about("Boot a created VM"))
.subcommand(Command::new("delete").about("Delete a VM"))
.subcommand(Command::new("shutdown").about("Shutdown the VM"))
.subcommand(
Command::new("snapshot")
.about("Create a snapshot from VM")
.arg(
Arg::new("snapshot_config")
.index(1)
.help("<destination_url>"),
),
)
.subcommand(
Command::new("restore")
.about("Restore VM from a snapshot")
.arg(
Arg::new("restore_config")
.index(1)
.help(RestoreConfig::SYNTAX),
),
)
.subcommand(
Command::new("coredump")
.about("Create a coredump from VM")
.arg(Arg::new("coredump_config").index(1).help("<file_path>")),
)
.subcommand(
Command::new("send-migration")
.about("Initiate a VM migration")
.arg(
Arg::new("send_migration_config")
.index(1)
.help("<destination_url>"),
)
.arg(
Arg::new("send_migration_local")
.long("local")
.num_args(0)
.action(ArgAction::SetTrue),
),
)
.subcommand(
Command::new("receive-migration")
.about("Receive a VM migration")
.arg(
Arg::new("receive_migration_config")
.index(1)
.help("<receiver_url>"),
),
)
.subcommand(
Command::new("create")
.about("Create VM from a JSON configuration")
.arg(Arg::new("path").index(1).default_value("-")),
)
.subcommand(Command::new("ping").about("Ping the VMM to check for API server availability"))
.subcommand(Command::new("shutdown-vmm").about("Shutdown the VMM"))
.subcommand(Command::new("nmi").about("Trigger NMI"));
.args(get_cli_args())
.subcommands(get_cli_commands_sorted());
let matches = app.get_matches();
@@ -1102,7 +1094,7 @@ fn main() {
#[cfg(not(feature = "dbus_api"))]
(Some(api_sock),) => TargetApi::HttpApi(
UnixStream::connect(api_sock).unwrap_or_else(|e| {
eprintln!("Error opening HTTP socket: {e}");
error!("Error opening HTTP socket: {e}");
process::exit(1)
}),
PhantomData,
@@ -1110,7 +1102,7 @@ fn main() {
#[cfg(feature = "dbus_api")]
(Some(api_sock), None, None) => TargetApi::HttpApi(
UnixStream::connect(api_sock).unwrap_or_else(|e| {
eprintln!("Error opening HTTP socket: {e}");
error!("Error opening HTTP socket: {e}");
process::exit(1)
}),
PhantomData,
@@ -1124,25 +1116,124 @@ fn main() {
)
.map_err(Error::DBusApiClient)
.unwrap_or_else(|e| {
eprintln!("Error creating D-Bus proxy: {e}");
error!("Error creating D-Bus proxy: {e}");
process::exit(1)
}),
),
#[cfg(feature = "dbus_api")]
(Some(_), Some(_) | None, Some(_) | None) => {
println!(
error!(
"`api-socket` and (dbus-service-name or dbus-object-path) are mutually exclusive"
);
process::exit(1);
}
_ => {
println!("Please either provide the api-socket option or dbus-service-name and dbus-object-path options");
error!("Please either provide the api-socket option or dbus-service-name and dbus-object-path options");
process::exit(1);
}
};
if let Err(e) = target_api.do_command(&matches) {
eprintln!("Error running command: {e}");
if let Err(top_error) = target_api.do_command(&matches) {
// Helper to join strings with a newline.
fn join_strs(mut acc: String, next: String) -> String {
if !acc.is_empty() {
acc.push('\n');
}
acc.push_str(&next);
acc
}
// This function helps to modify the Display representation of remote
// API failures so that it aligns with the regular output of error
// messages. As we transfer a deep/rich chain of errors as String via
// the HTTP API, the nested error chain is lost. We retrieve it from
// the error response.
//
// In case the repose itself is broken, the error is printed directly
// by using the `X` level.
fn server_api_error_display_modifier(
level: usize,
indention: usize,
error: &(dyn std::error::Error + 'static),
) -> Option<String> {
if let Some(api_client::Error::ServerResponse(status_code, body)) =
error.downcast_ref::<api_client::Error>()
{
let body = body.as_ref().map(|body| body.as_str()).unwrap_or("");
// Retrieve the list of error messages back.
let lines: Vec<&str> = match serde_json::from_str(body) {
Ok(json) => json,
Err(e) => {
return Some(format!(
"{idention}X: Can't get remote's error messages from JSON response: {e}: body='{body}'",
idention = " ".repeat(indention)
));
}
};
let error_status = format!("Server responded with {status_code:?}");
// Prepend the error status line to the lines iter.
let lines = std::iter::once(error_status.as_str()).chain(lines);
let error_msg_multiline = lines
.enumerate()
.map(|(index, error_msg)| (index + level, error_msg))
.map(|(level, error_msg)| {
format!(
"{idention}{level}: {error_msg}",
idention = " ".repeat(indention)
)
})
.fold(String::new(), join_strs);
return Some(error_msg_multiline);
}
None
}
let top_error: &dyn std::error::Error = &top_error;
cloud_hypervisor::cli_print_error_chain(
top_error,
"ch-remote",
server_api_error_display_modifier,
);
process::exit(1)
};
}
#[cfg(test)]
mod tests {
use std::cmp::Ordering;
use super::*;
use crate::test_util::assert_args_sorted;
#[test]
fn test_cli_args_sorted() {
let args = get_cli_args();
assert_args_sorted(|| args.iter());
}
#[test]
fn test_cli_commands_sorted() {
let commands = get_cli_commands_sorted();
// check commands itself are sorted
let iter = commands.iter().zip(commands.iter().skip(1));
for (command, next) in iter {
assert_ne!(
command.get_name().cmp(next.get_name()),
Ordering::Greater,
"commands not alphabetically sorted: command={}, next={}",
command.get_name(),
next.get_name()
);
}
// check args of commands sorted
for command in commands {
assert_args_sorted(|| command.get_arguments());
}
}
}

46
src/lib.rs Normal file
View File

@@ -0,0 +1,46 @@
// Copyright © 2025 Cyberus Technology GmbH
//
// SPDX-License-Identifier: Apache-2.0
use std::error::Error;
use log::error;
/// Prints a chain of errors to the user in a consistent manner.
/// The user will see a clear chain of errors, followed by debug output
/// for opening issues.
pub fn cli_print_error_chain<'a>(
top_error: &'a (dyn Error + 'static),
component: &str,
// Function optionally returning the display representation of an error.
display_modifier: impl Fn(
/* level */ usize,
/*indention */ usize,
&'a (dyn Error + 'static),
) -> Option<String>,
) {
let msg = format!("Error: {component} exited with the following");
if top_error.source().is_none() {
error!("{msg} error:");
error!(" {top_error}");
} else {
error!("{msg} chain of errors:");
std::iter::successors(Some(top_error), |sub_error| {
// Dereference necessary to mitigate rustc compiler bug.
// See <https://github.com/rust-lang/rust/issues/141673>
(*sub_error).source()
})
.enumerate()
.for_each(|(level, error)| {
// Special case: handling of HTTP Server responses in ch-remote
if let Some(message) = display_modifier(level, 2, error) {
error!("{message}");
} else {
error!(" {level}: {error}");
}
});
}
error!("");
error!("Debug Info: {top_error:?}");
}

View File

@@ -3,6 +3,9 @@
// SPDX-License-Identifier: Apache-2.0
//
#[cfg(test)]
mod test_util;
use std::fs::File;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::sync::mpsc::channel;
@@ -12,7 +15,7 @@ use std::{env, io};
use clap::{Arg, ArgAction, ArgGroup, ArgMatches, Command};
use event_monitor::event;
use libc::EFD_NONBLOCK;
use log::{warn, LevelFilter};
use log::{error, warn, LevelFilter};
use option_parser::OptionParser;
use seccompiler::SeccompAction;
use signal_hook::consts::SIGSYS;
@@ -40,34 +43,34 @@ static ALLOC: dhat::Alloc = dhat::Alloc;
#[derive(Error, Debug)]
enum Error {
#[error("Failed to create API EventFd: {0}")]
#[error("Failed to create API EventFd")]
CreateApiEventFd(#[source] std::io::Error),
#[cfg(feature = "guest_debug")]
#[error("Failed to create Debug EventFd: {0}")]
#[error("Failed to create Debug EventFd")]
CreateDebugEventFd(#[source] std::io::Error),
#[error("Failed to create exit EventFd: {0}")]
#[error("Failed to create exit EventFd")]
CreateExitEventFd(#[source] std::io::Error),
#[error("Failed to open hypervisor interface (is hypervisor interface available?): {0}")]
#[error("Failed to open hypervisor interface (is hypervisor interface available?)")]
CreateHypervisor(#[source] hypervisor::HypervisorError),
#[error("Failed to start the VMM thread: {0}")]
#[error("Failed to start the VMM thread")]
StartVmmThread(#[source] vmm::Error),
#[error("Error parsing config: {0}")]
#[error("Error parsing config")]
ParsingConfig(#[source] vmm::config::Error),
#[error("Error creating VM: {0:?}")]
#[error("Error creating VM")]
VmCreate(#[source] vmm::api::ApiError),
#[error("Error booting VM: {0:?}")]
#[error("Error booting VM")]
VmBoot(#[source] vmm::api::ApiError),
#[error("Error restoring VM: {0:?}")]
#[error("Error restoring VM")]
VmRestore(#[source] vmm::api::ApiError),
#[error("Error parsing restore: {0}")]
#[error("Error parsing restore")]
ParsingRestore(#[source] vmm::config::Error),
#[error("Failed to join on VMM thread: {0:?}")]
ThreadJoin(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
#[error("VMM thread exited with error: {0}")]
#[error("VMM thread exited with error")]
VmmThread(#[source] vmm::Error),
#[error("Error parsing --api-socket: {0}")]
#[error("Error parsing --api-socket")]
ParsingApiSocket(#[source] std::num::ParseIntError),
#[error("Error parsing --event-monitor: {0}")]
#[error("Error parsing --event-monitor")]
ParsingEventMonitor(#[source] option_parser::OptionParserError),
#[cfg(feature = "dbus_api")]
#[error("`--dbus-object-path` option isn't provided")]
@@ -77,37 +80,37 @@ enum Error {
MissingDBusServiceName,
#[error("Error parsing --event-monitor: path or fd required")]
BareEventMonitor,
#[error("Error doing event monitor I/O: {0}")]
#[error("Error doing event monitor I/O")]
EventMonitorIo(#[source] std::io::Error),
#[error("Event monitor thread failed: {0}")]
#[error("Event monitor thread failed")]
EventMonitorThread(#[source] vmm::Error),
#[cfg(feature = "guest_debug")]
#[error("Error parsing --gdb: {0}")]
#[error("Error parsing --gdb")]
ParsingGdb(#[source] option_parser::OptionParserError),
#[cfg(feature = "guest_debug")]
#[error("Error parsing --gdb: path required")]
BareGdb,
#[error("Error creating log file: {0}")]
#[error("Error creating log file")]
LogFileCreation(#[source] std::io::Error),
#[error("Error setting up logger: {0}")]
#[error("Error setting up logger")]
LoggerSetup(#[source] log::SetLoggerError),
#[error("Failed to gracefully shutdown http api: {0}")]
#[error("Failed to gracefully shutdown http api")]
HttpApiShutdown(#[source] vmm::Error),
#[error("Failed to create Landlock object: {0}")]
#[error("Failed to create Landlock object")]
CreateLandlock(#[source] LandlockError),
#[error("Failed to apply Landlock: {0}")]
#[error("Failed to apply Landlock")]
ApplyLandlock(#[source] LandlockError),
}
#[derive(Error, Debug)]
enum FdTableError {
#[error("Failed to create event fd: {0}")]
#[error("Failed to create event fd")]
CreateEventFd(#[source] std::io::Error),
#[error("Failed to obtain file limit: {0}")]
#[error("Failed to obtain file limit")]
GetRLimit(#[source] std::io::Error),
#[error("Error calling fcntl with F_GETFD: {0}")]
#[error("Error calling fcntl with F_GETFD")]
GetFd(#[source] std::io::Error),
#[error("Failed to duplicate file handle: {0}")]
#[error("Failed to duplicate file handle")]
Dup2(#[source] std::io::Error),
}
@@ -558,7 +561,7 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
signal_hook::low_level::emulate_default_handler(SIGSYS).unwrap();
})
}
.map_err(|e| eprintln!("Error adding SIGSYS signal handler: {e}"))
.map_err(|e| error!("Error adding SIGSYS signal handler: {e}"))
.ok();
}
@@ -572,13 +575,13 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
// dedicated signal handling thread we'll start in a bit.
for sig in &vmm::vm::Vm::HANDLED_SIGNALS {
if let Err(e) = block_signal(*sig) {
eprintln!("Error blocking signals: {e}");
error!("Error blocking signals: {e}");
}
}
for sig in &vmm::Vmm::HANDLED_SIGNALS {
if let Err(e) = block_signal(*sig) {
eprintln!("Error blocking signals: {e}");
error!("Error blocking signals: {e}");
}
}
@@ -880,8 +883,8 @@ fn main() {
path.map(|s| std::fs::remove_file(s).ok());
0
}
Err(e) => {
eprintln!("{e}");
Err(top_error) => {
cloud_hypervisor::cli_print_error_chain(&top_error, "Cloud Hypervisor", |_, _, _| None);
1
}
};
@@ -894,7 +897,6 @@ fn main() {
#[cfg(test)]
mod unit_tests {
use std::cmp::Ordering;
use std::path::PathBuf;
use vmm::config::VmParams;
@@ -905,6 +907,7 @@ mod unit_tests {
PayloadConfig, RngConfig, VmConfig,
};
use crate::test_util::assert_args_sorted;
use crate::{create_app, get_cli_options_sorted, prepare_default_values};
fn get_vm_config_from_vec(args: &[&str]) -> VmConfig {
@@ -2014,15 +2017,6 @@ mod unit_tests {
let (default_vcpus, default_memory, default_rng) = prepare_default_values();
let args = get_cli_options_sorted(default_vcpus, default_memory, default_rng);
let iter = args.iter().zip(args.iter().skip(1));
for (elem, next) in iter {
assert_ne!(
elem.get_id().cmp(next.get_id()),
Ordering::Greater,
"items not alphabetically sorted: elem={}, next={}",
elem.get_id(),
next.get_id()
);
}
assert_args_sorted(|| args.iter())
}
}

24
src/test_util.rs Normal file
View File

@@ -0,0 +1,24 @@
// Copyright © 2025 Cyberus Technology GmbH
//
// SPDX-License-Identifier: Apache-2.0
//
//! Test utilities.
use std::cmp::Ordering;
use clap::Arg;
/// Ensures that all [`Arg`]s are sorted alphabetically.
pub fn assert_args_sorted<'a, F: Fn() -> R, R: Iterator<Item = &'a Arg>>(get_base_iter: F) {
let iter = get_base_iter().zip(get_base_iter().skip(1));
for (arg, next) in iter {
assert_ne!(
arg.get_id().cmp(next.get_id()),
Ordering::Greater,
"args not alphabetically sorted: arg={}, next={}",
arg.get_id(),
next.get_id()
);
}
}

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