Compare commits

..

364 Commits
v42.0 ... v46.0

Author SHA1 Message Date
Bo Chen
c9a39cf5b5 build: Release v46.0
Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-05-23 18:29:42 +00:00
dependabot[bot]
f6326df68b build: Bump cc from 1.0.99 to 1.2.23
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.0.99 to 1.2.23.
- [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/1.0.99...cc-v1.2.23)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-22 23:53:39 +00:00
Bo Chen
7571e93a69 vmm: Deprecate SGX support
This commit adds the warning to deprecate the SGX support with the
intention to remove the support from code base in two release cycles.

See: #6960

Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-05-22 17:41:32 +00:00
Philipp Schuster
ab6e1bd2d8 misc: ch-remote: streamline #[source] and Error impl
This streamlines the Error implementation in the Cloud Hypervisor code
base to match the remaining parts so that everything follows the agreed
conventions. These are leftovers missed in the previous commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-22 15:13:27 +00:00
Philipp Schuster
517ea00bd9 misc: vmm/api: streamline #[source] and Error impl
This streamlines the Error implementation in the Cloud Hypervisor code
base to match the remaining parts so that everything follows the agreed
conventions. These are leftovers missed in the previous commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-22 15:13:27 +00:00
Philipp Schuster
ea6d5a04fa misc: net_util: streamline #[source] and Error impl
This streamlines the Error implementation in the Cloud Hypervisor code
base to match the remaining parts so that everything follows the agreed
conventions. These are leftovers missed in the previous commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-22 12:17:13 +00:00
Philipp Schuster
799336459d misc: performance-metrics: streamline #[source] and Error impl
This streamlines the Error implementation in the Cloud Hypervisor code
base to match the remaining parts so that everything follows the agreed
conventions. These are leftovers missed in the previous commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-22 12:17:13 +00:00
Philipp Schuster
f934e142ba misc: rate_limiter: streamline #[source] and Error impl
This streamlines the Error implementation in the Cloud Hypervisor code
base to match the remaining parts so that everything follows the agreed
conventions. These are leftovers missed in the previous commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-22 12:17:13 +00:00
Philipp Schuster
0cde3df44a misc: test_infra: streamline #[source] and Error impl
This streamlines the Error implementation in the Cloud Hypervisor code
base to match the remaining parts so that everything follows the agreed
conventions. These are leftovers missed in the previous commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-22 12:17:13 +00:00
Philipp Schuster
7585e16f9d misc: option_parser: streamline #[source] and Error impl
This streamlines the Error implementation in the Cloud Hypervisor code
base to match the remaining parts so that everything follows the agreed
conventions. These are leftovers missed in the previous commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-22 12:17:13 +00:00
Philipp Schuster
ab575a54b9 misc: devices: streamline #[source] and Error impl
This streamlines the Error implementation in the Cloud Hypervisor code
base to match the remaining parts so that everything follows the agreed
conventions. These are leftovers missed in the previous commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-22 12:17:13 +00:00
Philipp Schuster
d2ca7b0e87 misc: arch: streamline #[source] and Error impl
This streamlines the Error implementation in the Cloud Hypervisor code
base to match the remaining parts so that everything follows the agreed
conventions. These are leftovers missed in the previous commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-22 12:17:13 +00:00
Philipp Schuster
dd9bce31e8 misc: block: streamline #[source] and Error impl
This streamlines the Error implementation in the Cloud Hypervisor code
base to match the remaining parts so that everything follows the agreed
conventions. These are leftovers missed in the previous commits.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-22 12:17:13 +00:00
dependabot[bot]
a6370b74d9 build: Bump signal-hook from 0.3.17 to 0.3.18
Bumps [signal-hook](https://github.com/vorner/signal-hook) from 0.3.17 to 0.3.18.
- [Changelog](https://github.com/vorner/signal-hook/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vorner/signal-hook/compare/v0.3.17...v0.3.18)

---
updated-dependencies:
- dependency-name: signal-hook
  dependency-version: 0.3.18
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-22 00:34:40 +00:00
Thomas Prescher
d172a5dddb arch: fix extended topology enumeration leaf
When booting a Linux guest in SMP configuration,
the following kernel warning can be observed:

[Firmware Bug]: CPUID leaf 0xb subleaf 1 APIC ID mismatch 1 != 0

The reason is that we announce the presence of the extended topology
leaf, but fail to announce the x2apic ID in EDX.

Signed-off-by: Thomas Prescher <thomas.prescher@cyberus-technology.de>
On-behalf-of: SAP thomas.prescher@sap.com
2025-05-21 23:30:13 +00:00
Thomas Prescher
d46517559b vmm: don't allow resizing to 0 vCPUs
No sane guest OS will allow hotplugging all cpus.
However, the REST API currently allows specifying
`ch-remote resize --cpus 0`.

On Linux, we can then observe the following error in the kernel log:

processor cpu0: Offline failed.

Subsequent resize commands via ch-remote will then fail with
VcpuPendingRemovedVcpu because the removal of cpu0 was never
successful.

Fix this by disallowing resizing to zero vCPUs.

Signed-off-by: Thomas Prescher <thomas.prescher@cyberus-technology.de>
On-behalf-of: SAP thomas.prescher@sap.com
2025-05-21 15:28:22 +00:00
Paolo Bonzini
0463f4f156 vmm: use MmapRegion::bitmap() directly
For use in QEMU, I would like GuestMemoryRegion to return a BitmapSlice
instead of a &Bitmap.  This adds some flexibility that QEMU needs in
order to support a single global dirty bitmap that is sliced by the
various GuestMemoryRegions.

However, this removes access to the methods of AtomicBitmap, and in
particular reset() and get_and_reset().  Fortunately, cloud-hypervisor
always uses GuestMemoryMmap, and therefore `region` is known to be a
&GuestRegionMmap.  Dereferencing it returns the MmapRegion to which the
bitmap is attached, thus calling MmapRegion::bitmap(); this has the
same effect as `<GuestRegionMmap as GuestRegion>::bitmap()`, and works
both with or without https://github.com/rust-vmm/vm-memory/pull/324.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2025-05-21 13:00:07 +00:00
Philipp Schuster
fff62d9302 misc: vmm: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
5db92f79bf misc: arch: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
06f3049d24 misc: arch/x86_64: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
28e0a95450 misc: virtio-devices: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
a615c809eb misc: vsock: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
a3dcaedf7e misc: vhost_user_net: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
eb0b14f70e misc: vhost_user_block: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
80e66657cc misc: pci: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
fd5cfb75f3 misc: net_util: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
8696bc6604 misc: hypervisor: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
93b599e59e misc: devices: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
01761c2596 misc: block: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
a212343908 misc: arch/riscv64: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
d1a406143d misc: arch/aarch64: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
38380198e1 misc: api_client: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
Philipp Schuster
0e40a50407 misc: option_parser: streamline #[source] and Error
This streamlines the code base to follow best practices for
error handling in Rust: Each error struct implements
std::error::Error (most due via thiserror::Error derive macro)
and sets its source accordingly.

This allows future work that nicely prints the error chains,
for example.

So far, the convention is that each error prints its
sub error as part of its Display::fmt() impl.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-21 09:09:30 +00:00
dependabot[bot]
262984f8fc build: Bump miniz_oxide from 0.8.0 to 0.8.8
Bumps [miniz_oxide](https://github.com/Frommi/miniz_oxide) from 0.8.0 to 0.8.8.
- [Changelog](https://github.com/Frommi/miniz_oxide/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Frommi/miniz_oxide/compare/0.8.0...0.8.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-21 00:11:41 +00:00
Gregory Anders
dce82a34d0 net_util: add support for IPv6 addresses on tap interfaces
Allow tap interfaces to be configured with an IPv6 address. The change
is fairly straightforward: we need to update the API types and CLI
parsing to accept either an IPv6 or IPv4 and then match on the IP
address type when the tap device is configured.

For IPv6 addresses, the netmask (prefix) must be provided at the same
time as the address itself (in the SIOCSIFADDR ioctl). They cannot be
configured separately. So we remove the separate "set_netmask" function
and convert "set_ip_addr" to also accept a netmask. For IPv4 addresses,
the IP address and netmask were already always set together, so this
should have no functional impact for users of IPv4 addresses.

Signed-off-by: Gregory Anders <ganders@cloudflare.com>
2025-05-20 16:41:04 +00:00
dependabot[bot]
1454d39b28 build: Bump igvm_defs from d062818 to 01daa63
Bumps [igvm_defs](https://github.com/microsoft/igvm) from `d062818` to `01daa63`.
- [Release notes](https://github.com/microsoft/igvm/releases)
- [Commits](d062818ffb...01daa631a5)

---
updated-dependencies:
- dependency-name: igvm_defs
  dependency-version: 01daa631a596459cb4de58505881007dd13d4410
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-20 01:28:42 +00:00
dependabot[bot]
2588fc9e42 build: Bump vfio-bindings from 21d06ce to 3d158a1
Bumps [vfio-bindings](https://github.com/rust-vmm/vfio) from `21d06ce` to `3d158a1`.
- [Release notes](https://github.com/rust-vmm/vfio/releases)
- [Commits](21d06ceb91...3d158a1446)

---
updated-dependencies:
- dependency-name: vfio-bindings
  dependency-version: 3d158a14460cac7ca3c99c2effa0a46880935cb0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 23:56:55 +00:00
Philipp Schuster
67793ca375 vmm: improve disk locking error message
This adds guidance on how to resolve the issue.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-19 15:13:01 +01:00
Philipp Schuster
96deca9dc9 vmm: streamline display format for DeviceManagerError
This format is also used elsewhere.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>

On-behalf-of: SAP <philipp.schuster@sap.com>
2025-05-16 11:42:01 +00:00
Philipp Schuster
78b0f68b21 vmm: Error for MemoryManagerError
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>

On-behalf-of: SAP <philipp.schuster@sap.com>
2025-05-16 11:42:01 +00:00
Philipp Schuster
a007b750ff vmm: Error for PciDeviceError and PciRootError
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>

On-behalf-of: SAP <philipp.schuster@sap.com>
2025-05-16 11:42:01 +00:00
Philipp Schuster
b2993fb2fa vmm: Error for vsock::unix::Error
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-16 11:42:01 +00:00
Philipp Schuster
8d11bf7979 vmm: Error for DeviceManagerError
The DeviceManagerError type is among the types missing the Error trait
so far. To streamline the code and to simplify usage on higher levels
of this error type, this type now implements Display and Error.

As not all variant values are Error yet, `#[source]` is not everywhere
where it could be. This is done in the next commits.

The high level goal is: Enable future work to improve the error output
of cloud hypervisor.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-16 11:42:01 +00:00
Philipp Schuster
d4718a9bc8 tests: fix parallel rw disk access
The new locking behavior uncovered that unfortunate test situation:
Many tests running in parallel access the same disk image with
rw permissions. Luckily, none of the tests actually writes to
the disk. Therefore, we can set it to readonly=true. In case this
changes, the test needs to be moved to the sequential test module.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-16 08:07:32 +00:00
Philipp Schuster
05968f5c2c block: introduce advisory locks for disk image files
# What

This commit introduces file-based advisory locking for the files backing
up the block devices by using the fcntl() syscall with OFD locks. The
per-open-file-descriptor (OFD) locks are more robust than traditional
POSIX locks (F_SETLK) as they are not tied to process IDs and avoid
common issues in multithreaded or multi-fd scenarios [1]. Therefore,
we don't use `std::fs::File::try_lock()`, which is backed by F_SETLKW.

The locking mechanism is aware of the `readonly` property and allows
`n` readers or `1` writer (exclusive mode).

As the locks are advisory, multiple cloud-hypervisor processes can
prevent themselves from writing to the same file. However, this is not
a system-wide file-system level locking mechanism preventing to open()
a file.

The introduced new locking mechanism does not cover vhost-user devices.

# Why

To prevent misconfiguration and improve safety, it is good practice to
protect disk image files with a locking mechanism. Experience and common
best practices suggest that advisory locks are preferable over mandatory
locks due to better compatibility and fewer pitfalls (in fs space).

The introduced functionality is aligned with the approach taken by
QEMU [0], and is also recommended in [1].

# Implementation Details

We need to ensure that not only normal operation keeps working but also
state save/resume and live-migration. Especially for live migration,
it is crucial that the sender VMM releases the locks when the VM stops
so the receiver VMM can acquire them right after that.

Therefore, the locking and releasing happen directly on the block
device struct. The device manager knows all block devices and can
forward requests to these types.

Last but not least, this commit uses on explicit lock acquiring
but implicit lock releasing (FD close). It only explicitly releases
the locks where this integrates more smoothly into the existing
code.

# Testing

I tested
- normal operation
- state save/resume,
- device hot plugging,
- and live-migration
with read/shared and write/exclusive locks.

One can use the `fcntl-tool` to test if locks are actually acquired
or released [2].

# Links

[0] 825b96dbce/util/osdep.c (L266)
[1] https://apenwarr.ca/log/20101213
[2] https://crates.io/crates/fcntl-tool

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-16 08:07:32 +00:00
Philipp Schuster
71a36e0c69 block: add fcntl module for locking
This is a prerequisite for the next steps.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-16 08:07:32 +00:00
Philipp Schuster
2da5e10689 block: bind FD lifetime of DiskFile
As we can't use BorrowedFd, we should at least create a similar
safe alternative.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-16 08:07:32 +00:00
Philipp Schuster
a647d7863c block: enable to get a raw FD of each block device's DiskFile
This is a prerequisite for the next steps.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-16 08:07:32 +00:00
Philipp Schuster
a23d4b7cf2 block: fixing typo, increase clarity
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-16 08:07:32 +00:00
Philipp Schuster
f3209e4f78 devices: silence IRQ debug!() spam
This simplifies debugging of running VMs.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-16 08:07:32 +00:00
Bo Chen
596d6453c5 vmm: Allow 'VFIO_IOMMU_MAP_DMA' ioctl from the vcpu worker thread
Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-05-15 20:11:48 +00:00
Bo Chen
1307d31ede pci: vfio: Report more information with failed vfio_dma_unmap
Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-05-15 20:11:48 +00:00
Bo Chen
2f21827430 pci: vfio: Update IOMMU mappings of MMIO regions with BAR reprogram
To support PCIe P2P between VFIO devices, we populate IOMMU mappings for
the non-emulated MMIO regions of all VFIO devices via
`VFIO_IOMMU_MAP_DMA` (f0c1f8d), but the patch did not properly update
the IOMMU mappings with BAR reprogramming.

Fixes: #7027

Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-05-15 20:11:48 +00:00
Bo Chen
8da7c13e26 pci: Handle pending BAR reprogramming for VFIO devices properly
The way how we handle PCI configuration space for vfio and vfio-user
devices are different from the rest of PCI devices. Besides accesses to
BAR registers (trapped to access the shadowing PCI config space we
maintained), accesses to other registers (including the COMMAND
register) are handled directly by the underline vfio or vfio-user
device.

This patch adds the proper handling of pending BAR reprogramming for
vfio and vfio-user devices.

Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-05-15 17:35:44 +00:00
Bo Chen
aaf86ef209 pci: Reprogram device BAR when its MSE bit is set
The Memory Space Enable (MSE) bit from the COMMAND register in the
PCI configuration space controls whether a PCI device responds to memory
space accesses, e.g. read and write cycles to the device MMIO regions
defined by its BARs. The MSE bit is used by the device drivers to ensure
the correctness of BAR reprogramming. A common workflow is, the driver
first clears the MSE bit, then writes new values to the BAR registers,
and finally set the MSE bit to finish the BAR reprogramming.

This patch changes how we handle BAR reprogramming for all PCI
devices (e.g. virtio-pci, vfio, vfio-user, etc.), so that we follow the
same convention, e.g. moving PCI BARs when its MSE bit is set.

Note that some device drivers (such as edk2) only clear and set MSE once
while reprogramming multiple BARs of a single device. To support such
behavior, this patch adds support for multiple pending BAR reprogramming.

See: https://github.com/cloud-hypervisor/cloud-hypervisor/issues/7027#issuecomment-2853642959

Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-05-15 17:35:44 +00:00
Bo Chen
59f98a2edc pci: configuration: Log BAR reprogramming correctly
Use the right bar index and bar address maintained internally by the
VMM when logging BAR reprogramming.

Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-05-15 15:04:01 +00:00
Bo Chen
cb52cf91df pci: Keep detect_bar_reprogramming internal to PciConfiguration
A BAR reprogramming of a PCI device will only happen when the (guest)
kernel write to its PCI config space, e.g. the detection of bar
reprogramming (`detect_bar_repgraomming()`) can be embedded to the PCI
config space write (`write_config_register()`). It simplifies APIs
exposed by the `struct PciConfiguration` and `trait PciDevice`. It also
prepares for easier handling of pending bar reprogramming when the MSE
bit of the COMMAND register is not enabled at the time of changing BAR
registers.

See: https://github.com/cloud-hypervisor/cloud-hypervisor/issues/7027#issuecomment-2853642959

Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-05-15 15:04:01 +00:00
Muminul Islam
5814193722 build: Bump mshv crates from 0.5.0 to 0.5.1
This release has critical bug fixes IOCTL changes.
No API changes.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-05-15 06:39:22 +00:00
Bo Chen
10ee003d66 misc: Fix beta clippy issues
Fixing the following clippy issue using `cargo clippy --fix`:

error: variables can be used directly in the `format!` string
  --> build.rs:25:27
   |
25 |         version.push_str(&format!("-{}", extra_version));
   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args

Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-05-14 03:44:12 +00:00
Jinank Jain
8f402687ce hypervisor: mshv: Add missing implementation
Currently a lot of functions are stubbed out with unimplemented feature
tag. Add the missing implementation to successfully boot ARM64 guests on
MSHV.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-05-09 16:06:12 +00:00
Jinank Jain
f72f16ee50 arch: Fix incorrect FDT generation
Num SPI and Base SPI nodes should be added before the end node to be
included in the device tree generation.

Fixes: eac44e6 (arch: Extend FDT for GICv2M device for ARM64 on MSHV)
Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-05-09 16:06:12 +00:00
Jinank Jain
034aa514d7 vmm: Unify address space allocation
It seems like address allocation has been spread into different files
and different location for x86 vs ARM. This makes it hard to follow the
code. Thus, unify it a single location which satisfies all the
requirement.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-05-09 16:06:12 +00:00
Jinank Jain
4e48f429eb vmm: Unify loading of payload for IGVM and non-IGVM
It just simplifies code and improves the code read-ability without much
affecting the boot performance.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-05-09 16:06:12 +00:00
Jinank Jain
50b0493371 vmm: Move vm init after interrupt controller init
This will satisfy the requirement of MSHV i.e., setting the GICD base
address before initializing the VM.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-05-09 16:06:12 +00:00
Jinank Jain
df418a2153 vmm: Split device creation from interrupt controller creation
For MSHV guests, we would need interrupt controller to be initialized
before the VM gets initialized. This is because we are registering the
base address of GIC distributor with MSHV as part of interrupt
controller initialization workflow. And MSHV mandates that this property
is set before we initialize the VM.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-05-09 16:06:12 +00:00
Jinank Jain
a072b9a356 hypervisor: Set additional partition property for MSHV guest
For ARM64 guests we need to set three important partition property:

1) PPI interrupt ID for timer interrupt
2) PPI interrupt ID for PMU interrupts.
3) Hiding LPI support from the guest because MSHV does emulate ITS for
   the guest.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-05-09 16:06:12 +00:00
Jinank Jain
691fe0ca68 hypervisor: arch: Move PMU IRQ definition from arch to hypervisor crate
Since this would be used in other places inside the hypervisor and
hypervisor crate cannot take a dependency on arch crate, as that creates
cyclic dependency.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-05-09 16:06:12 +00:00
Jinank Jain
aaa3a114dd arch: hypervisor: Define PPI constants for ARM arch timer
Currently PPI interrupt ID are hardcoded as numbers, it would be ideal
to define them as constants and could be reused in other parts of the
hypervisor crate.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-05-09 16:06:12 +00:00
Philipp Schuster
77e042237d ci: improve gitlint (max line length in body with exceptions)
Follow-up of 5aa1540c5d but way more
mature. We now use custom gitlint rules written in Python to better
handle the max line length, with respect to a few valid exceptions.
Recognizing code blocks or compiler output, as discussed, is not
trivial and hard to get right for all corner-cases. Therefore, this
commit is a pragmatic way forward. The CI job should be kept optional.

Allowed exceptions for the 72 line length limit are now:

1. links in the following three common patterns:
https://example.com/very-long-links/very-long-links/very-long-links/very-long-links/very-long-links/very-long-links/very-long-links
[0] https://example.com/very-long-links/very-long-links/very-long-links/very-long-links/very-long-links/very-long-links/very-long-links
[0]: https://example.com/very-long-links/very-long-links/very-long-links/very-long-links/very-long-links/very-long-links/very-long-links

2. code blocks (anything between the three backticks)

```
let x = "very_long_very_long_very_long_very_long_very_long_very_long_very_long_very_long_very_long_very_long_"
```

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-05-09 14:50:23 +01:00
Jinank Jain
f16d45e86e build: Bump mshv crates from 0.4.0 to 0.5.0
Along with also bump the vfio-bindings crates to use the latest
mshv-bindings.

There is a breaking change in the new mshv crate which requires an
additional step to initialize vm after creating it.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-05-05 17:42:30 +00:00
Jinank Jain
3eb6b69dd2 hypervisor: Extend interrupt handling for legacy IRQ
On x86 MSHV guests only used to support MSI based interrupts via IOAPIC
but ARM64 guests uses legacy interrupt for its functioning. Thus, extend
the logic to create routing entry to support legacy interrupts for ARM64
guests on MSHV.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-05-05 10:44:16 +00:00
Jinank Jain
fa2b5ca12b vmm: hypervisor: Add a new interface to setup GICR for vcpus
For MSHV arm64 guest, there is an in-hypervisor GICv2M emulation and for
that to work, it needs to be enlightened with the base address of GIC
redistributor exposed to guest via FDT.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-05-05 09:57:21 +00:00
Jinank Jain
eac44e6af0 arch: Extend FDT for GICv2M device for ARM64 on MSHV
GICv2M requires two additional properties to be exposed via FDT:
1) Base SPI number and 2) Total number of SPIs. SPIs in general starts
from 32 and goes upto 1019. But currently we are limiting the range to
96 as that should be good enough for any normal Linux guest to function.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-05-05 09:05:02 +00:00
abm-77
40055595ff docs: Update riscv docs for developing in QEMU VM
Since there are not a wide availability of RISC-V boards available at
the moment, it is easiest to develop with a QEMU virtual machine. I had
a hard time setting one up, but with the assistance of Ruoqing, I was
able to get one running. These are the steps I took to do so.

Signed-off-by: abm-77 <andrewmiller77@protonmail.com>
2025-05-03 11:11:05 +00:00
Bingxin Li
149c08981b README: Update ubuntu support status
Ubuntu 24.04 LTS (Noble Numbat) is tested against cloud-hypervisor v45.0
release and it is working, document status in README.md.

Signed-off-by: Bingxin Li <bl497@cam.ac.uk>
2025-05-02 07:58:04 +00:00
Jinank Jain
f1f6814774 hypervisor: Implement support for fetching sys regs on MSHV
ARM64 system register constants are not 1:1 mapped to MSHV definition of
those registers so we need a small helper function to translate that
mapping before retrieving those system registers.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-30 06:11:26 +00:00
Jinank Jain
58f71b0c44 hypervisor: arch: Move common regs from arch to hypervisor crate
There are other potential users of these registers definitions in the
hypervisor crate. And hypervisor crate cannot use definitions from arch
crate because it creates cyclic dependency.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-30 06:11:26 +00:00
Fabiano Fidêncio
1968805ba2 api_client: Add TooManyRequests status code
In order to be on-pair with what's we're using from micro-http, let's
also add the proper status code here as well (as it will be used by
`ch-remote`).

Signed-off-by: Fabiano Fidêncio <fidencio@northflank.com>
2025-04-28 16:24:10 +00:00
Fabiano Fidêncio
d0225fe68f vmm: api: Be more specific on "Still pending remove vcpu" errors
Although the CPU manager gives us a quite descriptive error, on the
application side (the part calling Cloud Hypervisor) we have absolutely
no way to distinguish such error from any other error that may happen
when resizing a VM.

With this in mind, let's be more specific and return a TooManyRequests
(429) error, allowing the caller to have a chance to decide whether they
want to retry the operation or not.

https://datatracker.ietf.org/doc/html/rfc6585#section-4

Signed-off-by: Fabiano Fidêncio <fidencio@northflank.com>
2025-04-28 16:24:10 +00:00
Fabiano Fidêncio
87007a288f build: Bump micro-http crate
As the coming patches in this series will take advantage of a status
code that was recently added there.

Signed-off-by: Fabiano Fidêncio <fidencio@northflank.com>
2025-04-28 16:24:10 +00:00
Muminul Islam
f67484a714 hypervisor: mshv: advance_rip_rax after port handle
Call function to advance RIP and RAX after handling the
port.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-04-26 21:18:22 +00:00
Muminul Islam
3c63779302 hypervisor: mshv: function to advance RIP and RAX
A separate function to advance RIP and RAX based on
register page.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-04-26 21:18:22 +00:00
Muminul Islam
1c22c4a57b misc: docs: Fix broken link of dpdk.org
Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-04-24 23:23:15 +00:00
Muminul Islam
4af98f4cb2 hypervisor: mshv: get_msr_list return vector instead fam-wrapper
New MSHV version updates the get_msr_list output as
vector instead of fam-wrapper. It avoids unnecessary
conversions.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-04-24 23:23:15 +00:00
Muminul Islam
c58c686f3e hypervisor: mshv: fix clippy warnings for latest mshv crates
Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-04-24 23:23:15 +00:00
Muminul Islam
9b13d63f28 build: update mshv crates to the latest release
Latest mshv crates contains some IOCTL changes that
enhances VM creation and configures the features in correct
way. Also adds some features that improves register access.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-04-24 23:23:15 +00:00
Muminul Islam
b5aeb1f63c hypervisor: mshv: use mapped register page for port handling
MSHV allows VMM to map the VP register page into root.
This feature helps VMM to faster process most of the frequent
used registers. This patch uses the VP register page for port
handling in CPU run method.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2025-04-24 20:37:19 +00:00
Jinank Jain
af2ce3e0cc hypervisor: Basic implementation of setup_regs for MSHV ARM64 guests
As part of this configure the program counter, pstate and X0 registers.
Program counter will point to the start address of the kernel/firmware
in the guest memory. X0 will point to start of the FDT.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-23 07:42:29 +00:00
Jinank Jain
7fd1b9a284 hypervisor: Configure VGIC for MSHV guests
As part of this configuration, two things are being done:

1. Setting up the base address of GIC Distributor
2. Setting up the base address of GIC Interrupt Translator

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-23 07:42:29 +00:00
Jinank Jain
e69acd1dc3 hypervisor: Refactor common PSTATE register definition
Initial PSTATE value would be same for both KVM and MSHV. Thus, move it
to common register definition pool.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-23 07:42:29 +00:00
Julian Stecklina
de764456ce pci: reduce visibility of VfioCommon internals
There are a lot of internal functions that are not and probably should
not be called from other places.

Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2025-04-18 18:25:37 +00:00
Julian Stecklina
0095556847 pci: gracefully handle devices that return 0xff as a capability pointer
If a device returns 0xff as a capability pointer bad things happen.
The code before the previous commits would crash in debug builds due
to integer overflow. With the two lowest bits masked out, it sends the
code into an endless loop.

Be more robust by at least handling the case where the capability
appears to point to itself.

Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2025-04-18 18:25:37 +00:00
Julian Stecklina
a0065452d8 pci: mask out lower 2 bits in capability list pointers
The PCI standard mandates that the lower bits of the capability
pointer are masked out before using the pointer. See PCI Local Bus
Specification 3.0 Chapter 6.7 "Capabilities List".

Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2025-04-18 18:25:37 +00:00
Julian Stecklina
56ca26e72c pci: only parse capabilities if the device claims to have some
Currently, the code tries to follow the PCI capabilities list in
offset 0x34 in the config space regardless of whether the status
registers says this is valid. Fix by adding the appropriate check.

Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2025-04-18 18:25:37 +00:00
Julian Stecklina
21b9806cad ci: Exclude osdev.org from link check
OSDev has cranked up its bot protection. The following link works for
me locally after clicking the "I'm a human" button. I guess the CI
fails this check...

Without this exception the CI fails the link check stage:

* [403] [https://wiki.osdev.org/IOAPIC](https://wiki.osdev.org/IOAPIC) | Network error: Forbidden

Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2025-04-18 18:25:37 +00:00
Jinank Jain
d374101f38 hypervisor: Use instruction emulator to handle unmapped gpa
Use the context from Unmapped Gpa exit from the hypervisor to initialize
the MshvEmulatorContext and later call the emulator to decode the
instruction.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-17 13:11:23 +00:00
Jinank Jain
461e31e6d8 hypervisor: Instruction emulator for ARM64 guest on MSHV
Currently it would be using the syndrome register for instruction
decoding which is what KVM has been using in-kernel to decode
instructions for ARM64 guests. In future, it could be extended with an
actual instruction emulator if required. But most Linux guests works
well with the instruction decoder using syndrome register.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-17 13:11:23 +00:00
Jinank Jain
d22e7e2638 hypervisor: Add definition for parsing EsrEl2 register
This helps in implementing an instruction decoder for MSVH which does
not support in-kernel instruction decoding like KVM.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-17 13:11:23 +00:00
Jinank Jain
960d702255 hypervisor: Enable MSHV compilation on ARM64
Along with it also enable clippy tests on MSHV aarch64 builds.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-16 03:36:12 +00:00
Jinank Jain
1105243aca vmm: Guard KVM specific unit test with feature guard
Some tests are specifically designed for KVM hypervisor platform. Thus,
guard them using appropriate feature flags.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-16 03:36:12 +00:00
Jinank Jain
317f8002d7 hypervisor: Silence compiler warning for unused variables
There are a bunch of unused variables as of now on the MSHV side and
compiler warns about them. Thus, mark them as unused for the time being.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-16 03:36:12 +00:00
dependabot[bot]
278b57ba49 build: Bump equivalent from 1.0.1 to 1.0.2
Bumps [equivalent](https://github.com/indexmap-rs/equivalent) from 1.0.1 to 1.0.2.
- [Commits](https://github.com/indexmap-rs/equivalent/compare/v1.0.1...v1.0.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-15 23:57:05 +00:00
Jinank Jain
d7f87425cd build: Bump mshv crates from 0.3.3 to 0.3.5
Latest mshv crates contains some binding changes required for supporting
ARM64 guests on MSHV.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-15 07:23:44 +00:00
dependabot[bot]
573868c035 build: Bump bitflags from 2.6.0 to 2.9.0
Bumps [bitflags](https://github.com/bitflags/bitflags) from 2.6.0 to 2.9.0.
- [Release notes](https://github.com/bitflags/bitflags/releases)
- [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md)
- [Commits](https://github.com/bitflags/bitflags/compare/2.6.0...2.9.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-15 00:35:22 +00:00
Jinank Jain
2798286278 hypervisor: Add GICv2M support for MSHV ARM64 guest
MSHV does not emulate a GICv3-ITS for guests to support MSI interrupts,
instead it exposes a GICv2m device. Currently adding a skeleton code
which would be modified later on with complete implementation.

With this we can start compiling cloud-hypervisor for MSHV on ARM64.
This will make sure that we don't regress in future in terms of basic
compilation test.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-14 16:33:10 +00:00
Ruoqing He
bcc314eb8b build: Manually bump igvm crates to d062818
`zerocopy` is bumped to 0.8.x after 0.3.4 of igvm crates, bump to rev
d062818 to capture `zerocopy` upgrade, but we should bump to 0.3.5
later.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-04-13 08:06:11 +00:00
Ruoqing He
af28569611 build: Bump zerocopy and acpi_tables
Manually bump zerocopy to 0.8.24 since our dependabot could not perform
the upgrade properly.

Manually bump acpi_tabls as well since it's depending on zerocopy.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-04-13 08:06:11 +00:00
Rob Bradford
1a5dcc5e70 build: Clarify that MSRV bump is an OR of potential reasons
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-04-13 07:39:00 +00:00
Rob Bradford
29b089296d tests: Move test_virtio_pmem_persist_writes to sequential group
This test has been generating a flaky OOM situation when run in the
parallel group.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-04-13 07:38:42 +00:00
Ruoqing He
6e4bf84383 hypervisor: Fix clippy empty_line_after_doc_comments
Fix clippy warning empty_line_after_doc_comments reported by rustc
1.83.0 (90b35a623 2024-11-26).

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-04-12 18:31:02 +01:00
Ruoqing He
226ecf47bb build: Bump MSRV to 1.83.0
The dependency `bitfield-struct` 0.10.x of `igvm` 0.3.5 requires MSRV
1.83.0, bump to catch up.

Update image to 20250412-0 because MSRV in Dockerfile is updated.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-04-12 18:31:02 +01:00
Bo Chen
0e3733e938 vmm: openapi: Remove path as required for DiskConfig
This aligns with our CLI syntax. The correctness of `DiskConfig` will be
ensured via `VmConfig::validate()`, e.g. `path` and `socket` are
mutually exclusive.

Fixes: #7016

Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-04-09 16:03:12 +00:00
Jinank Jain
f811e36443 hypervisor: Add support for get/set regs for ARM guest on MSHV
Enable getting and setting registers for ARM64 guests on MSHV.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-03 16:46:23 +00:00
Jinank Jain
a64ba04e78 pci: Fix clippy warning while comparing raw pointers
Use the builtin function instead of using `==` operator.

Warning from the beta compiler:

error: use `std::ptr::eq` when comparing raw pointers
--> pci/src/vfio.rs:1616:24

if host_addr == libc::MAP_FAILED {
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    help: try: `std::ptr::eq(host_addr, libc::MAP_FAILED)`

 = help: for further information visit
 = https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
 = note: `-D clippy::ptr-eq` implied by `-D warnings`
 = help: to override `-D warnings` add `#[allow(clippy::ptr_eq)]`

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-03 13:11:49 +00:00
Jinank Jain
b686a5bb24 vm-allocator: Fix clippy warning for implicit saturating sub
Use the builtin function to improve the readability of the code.

Warning from beta compiler:

error: manual arithmetic check found
--> vm-allocator/src/address.rs:151:30
|
|let adjust = if alignment > 1 { alignment - 1 } else { 0 };
|             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|             help: replace it with: `alignment.saturating_sub(1)`
|
= help: for further information visit
https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
= note: `-D clippy::implicit-saturating-sub` implied by `-D warnings`
= help: to override `-D warnings` add`#[allow(clippy::implicit_saturating_sub)]`

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-03 13:11:49 +00:00
Jinank Jain
ea4693a091 misc: Fix clippy error from beta compiler
Rust has a new way of constructing other error and clippy complains if
we are still using the older way to construct error message. Thus,
migrate to the new approach suggested by the clippy.

Warning from beta compiler:

error: this can be `std::io::Error::other(_)`
--> block/src/vhdx/mod.rs:142:17
 |
 | /                 std::io::Error::new(
 | |                     std::io::ErrorKind::Other,
 | |                     format!("Failed to update VHDx header: {e}"),
 | |                 )
 | |_________________^
 |
 = help: for further information visit
https://rust-lang.github.io/rust-clippy/master/index.html#io_other_error
help: use `std::io::Error::other`

                 std::io::Error::other(
                     format!("Failed to update VHDx header: {e}"),

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-03 13:11:49 +00:00
Jinank Jain
3698b8e74c build: Centralize serde_json crate to workspace
`serde_json` crate is referenced by multiple components, centralize it
to workspace to better manage this crate.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-04-02 06:20:54 +00:00
Jinank Jain
6bb33601d0 hypervisor: Avoid leaking KVM GIC state into common GIC state
KVM supports GICv3-ITS emulation and the current GicState is modelled
around the KVM implementation. We should refactor this to accomodate
other hypervisor requirements. For example, MSHV only support GICv2M
emulation for guests for delivering MSI interrupts instead of GICv3-ITS.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-03-30 06:18:58 +00:00
Bo Chen
3d88996e5b build: Release v45.0
Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-03-29 16:44:09 +00:00
Ruoqing He
3899cd0e30 docs: Add guide for direct boot VM on riscv64
Add `riscv.md` to guide developers/users on preparing guest kernel,
image, and direct boot VM on riscv64 platforms; document support status
and known limitations.

Co-authored-by: Bo Chen <bchen@crusoe.ai>
Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-29 03:58:12 +00:00
Jinrong Liang
9d93df4c8f vm-migration: Optimize downtime by moving stop_dirty_log()
The larger the VM memory, the greater the memory pressure, and the
greater the stop_dirty_log() overhead. Moving stop_dirty_log() outside
the downtime period can reduce downtime.

Signed-off-by: Jinrong Liang <cloudliang@tencent.com>
2025-03-27 21:08:33 +00:00
Jinrong Liang
4c27572b87 vm-migration: Avoid stop_dirty_log() during local migration
Starting and stopping logging dirty pages only occurs during cross-host
migrations.

Signed-off-by: Jinrong Liang <cloudliang@tencent.com>
2025-03-27 21:08:33 +00:00
Ruoqing He
19fea1ad88 hypervisor: Simplify riscv64 set_regs implementation
Use `riscv64_set_one_reg_from_vcpu!` macro to simplify `set_regs` for
riscv64.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-27 00:27:05 +00:00
Ruoqing He
9a96ea44be hypervisor: Introduce riscv64_set_one_reg_to_vcpu macro
`riscv64_set_one_reg_to_vcpu` macro is used to set value of specific
RISC-V `$reg_name` stored in `state` to KVM Vcpu.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-27 00:27:05 +00:00
Ruoqing He
e11b9d6449 hypervisor: Simplify riscv64 get_regs implementation
Use `riscv64_get_one_reg_from_vcpu!` macro to simplify `get_regs` for
riscv64.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-27 00:27:05 +00:00
Ruoqing He
ce5fe7f89d hypervisor: Introduce riscv64_get_one_reg_from_vcpu macro
`riscv64_get_one_reg_from_vcpu` macro is used to extract RISC-V register
data from KVM Vcpu according to `$reg_name` provided to `state`.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-27 00:27:05 +00:00
Ruoqing He
0dd0364bf8 build: Centralize igvm crates to workspace
`igvm` crates are referenced by multiple components, centralize them to
workspace to better manage those crates.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-24 18:01:03 +00:00
Jinank Jain
3081d01fc3 vmm: Fix compilation on aarch64 MSHV
Certain MSHV ioctls are only available on x86 architecture. Thus,
conditionally compile seccomp filter for x86 and in general enable
seccomp filters when compiling for MSHV on aarch64.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-03-21 03:50:59 +00:00
Philipp Schuster
fa58b725cb vmm: alphabetically sort CLI options in --help output
The CLI has grown to a big variety of options. clap prints them in the
help message (--help) in the order they were defined. We now are at a
point where grouping things logically together doesn't work well.
Further, there is no support by clap for logical grouping and the
current code base wasn't consistent. Therefore, this commit introduces
two changes:

- a new structure to define arguments (all in an array)
- an alphabetical ordering of the arguments

No other changes have been made. No options have been altered.

This significantly improves:
- code maintainability and extensibility
- readability of the --help output

A unit test ensures they stay sorted. A better approach to check if the
list of arguments (known at build time) is sorted would be a compile
time check (`const`), but this currently isn't possible in stable Rust.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-03-20 08:43:09 +00:00
Andrew Consroe
a38b4c7f17 vmm: tighten landlock rule for PmemConfig
when discard_writes is true, only grant read access in landlock

Signed-off-by: Andrew Consroe <aconz2@gmail.com>
2025-03-20 01:58:10 +00:00
Philipp Schuster
5aa1540c5d ci: gitlint now ignores long lines from links
This helps to prevent annoying CI failures when one adds useful resources into
a commit message, such as [0].

One can test this locally using: `gitlint --commits HEAD~1..HEAD`

[0]
https://example.com/?lorem-ipsum-lorem-ipsum-lorem-ipsum-lorem-ipsum-lorem-ipsum-lorem-ipsum-lorem-ipsum-lorem-ipsum-lorem-ipsum-lorem-ipsum-lorem-ipsum-lorem-ipsum-lorem-ipsum-lorem-ipsum

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
2025-03-19 16:11:26 +00:00
Jinank Jain
7da8ae9c0f hypervisor: Fix MSHV compilation on aarch64
Use the definitions from the rust-vmm/mshv crate for various
datastructures such as StandardRegisters, RegList, VcpuInit etc.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-03-19 06:58:52 +00:00
Wei Liu
108e8f9dff hypervisor: mshv: handle cross-page access in emulator
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-03-17 21:40:24 +00:00
dependabot[bot]
5ab2feae70 build: Bump anstyle-query from 1.1.1 to 1.1.2
Bumps [anstyle-query](https://github.com/rust-cli/anstyle) from 1.1.1 to 1.1.2.
- [Commits](https://github.com/rust-cli/anstyle/compare/anstyle-query-v1.1.1...anstyle-query-v1.1.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-15 00:15:13 +00:00
Ruoqing He
c99660a8f9 vmm: Introduce riscv64 architecture support
Integrate all works done previously to enable booting riscv linux on
riscv platforms, example command:

```console
./target/debug/cloud-hypervisor \
        --kernel path/to/kernel \
        --disk path=path/to/disk \
        --cmdline "console=hvc0 root=/dev/vda rw" \
        --cpus boot=1 \
        --memory size=1024M \
        --seccomp false
```

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-14 17:00:57 +00:00
Ruoqing He
08c1bb4b00 ci: Enable retry for Link Check
Link check is likely to fail due to connectivity reasons, retry three
times before it fails.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-14 16:56:12 +00:00
Bo Chen
5bd177dde8 ci: Move metrics and rate-limiter workers
We are moving the metrics and rate-limiter workers to a bare-metal
system, so that we can have more consistent results (particularly for
the block device metrics)

Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-03-14 10:15:21 +00:00
dependabot[bot]
52ed1082fb build: Bump igvm from 0.3.3 to 0.3.4
Bumps [igvm](https://github.com/microsoft/igvm) from 0.3.3 to 0.3.4.
- [Release notes](https://github.com/microsoft/igvm/releases)
- [Commits](https://github.com/microsoft/igvm/compare/igvm-v0.3.3...igvm-v0.3.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-14 00:28:53 +00:00
dependabot[bot]
03a23309b9 build: Bump async-channel from 2.3.0 to 2.3.1
Bumps [async-channel](https://github.com/smol-rs/async-channel) from 2.3.0 to 2.3.1.
- [Release notes](https://github.com/smol-rs/async-channel/releases)
- [Changelog](https://github.com/smol-rs/async-channel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/smol-rs/async-channel/compare/v2.3.0...v2.3.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-13 01:45:20 +00:00
dependabot[bot]
fa0965a11a build: Bump indexmap from 2.7.1 to 2.8.0
Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.7.1 to 2.8.0.
- [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md)
- [Commits](https://github.com/indexmap-rs/indexmap/compare/2.7.1...2.8.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-12 00:02:27 +00:00
Anatol Belski
524f26abef vmm: api: Expose SEV-SNP and igvm related options
This involves the platform  and VM config.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2025-03-11 17:22:20 +00:00
dependabot[bot]
846d0976e3 build: Bump unicode-ident from 1.0.12 to 1.0.18
Bumps [unicode-ident](https://github.com/dtolnay/unicode-ident) from 1.0.12 to 1.0.18.
- [Release notes](https://github.com/dtolnay/unicode-ident/releases)
- [Commits](https://github.com/dtolnay/unicode-ident/compare/1.0.12...1.0.18)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-11 00:33:12 +00:00
Ruoqing He
4718dc1b72 build: Manually bump seccompiler to 0.5.0
v0.5.0 of `seccompiler` has supported riscv64, let's bump from v0.4.0 to
v0.5.0 to capture that support.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-10 17:38:56 +00:00
dependabot[bot]
0a9895e009 build: Bump ryu from 1.0.18 to 1.0.20
Bumps [ryu](https://github.com/dtolnay/ryu) from 1.0.18 to 1.0.20.
- [Release notes](https://github.com/dtolnay/ryu/releases)
- [Commits](https://github.com/dtolnay/ryu/compare/1.0.18...1.0.20)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-10 09:43:34 +00:00
Bo Chen
297b41d615 pci, vmm: vfio: Report device path on host with DMA map/unmap errors
In addition to the BDF information on the guest, reporting the device
path of the VFIO device on the host is more useful when it comes to
debug DMA map/unmap errors particularly ones caused by failing hardware
on the host.

Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-03-08 10:00:34 +00:00
Ruoqing He
396aba7a52 tests: Skip test_snapshot_restore_with_fd on aarch64
`test_snapshot_restore_with_fd` uses unsafe file descriptors and with
rust 1.82.0 it errors with:

```
fatal runtime error: IO Safety violation: owned file descriptor already
closed
```

so has been skipped for now.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-07 15:09:14 +00:00
Ruoqing He
35aaa1333a misc: Fix clippy - more concise repeat().take()
Reported by 1.86.0-beta.1 (f0cb41030 2025-02-17).

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-07 15:09:14 +00:00
Ruoqing He
6768a13d95 build: Bump MSRV to 1.82.0
We are having complains from Rust 1.86.0-beta.1 (f0cb41030 2025-02-17)'
clippy, which suggests us to replace `repeat().take()` with
`repeat_n()`. While `repeat_n()` is stablized in Rust 1.82.0.

Update image to 20250307-2 because MSRV in Dockerfile is updated.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-07 15:09:14 +00:00
Ruoqing He
0d50d0b257 build: Add force-non-host to install minimal toolchain
While executing `rustup toolchain add --profile minimal
1.82.0-x86_64-unknown-linux-musl`, it errors out with:

```
error: toolchain '1.82.0-x86_64-unknown-linux-musl' may not be able to
run on this system
note: add the `--force-non-host` flag to install the toolchain anyway
```

Add `--force-non-host` to install minimal musl toolchain for x86_64.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-07 15:09:14 +00:00
Jinank Jain
f5a2f8473b hypervisor: Add a basic implementation of MshvVcpuState for aarch64
Currently we are just storing the StandardRegisters in the Vcpu state
which would be required for saving and restoring the ARM64 guest on
MSHV.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-03-06 11:14:16 +00:00
Stefan Kober
03bb59db69 seccomp: Allow clock_gettime() on http api thread
Signed-off-by: Stefan Kober <stefan.kober@cyberus-technology.de>
2025-03-05 15:35:37 +00:00
Ruoqing He
9e1fb3bfa1 misc: Fix clippy - manual implementation of ok
Reported by 1.86.0-beta.1 (f0cb41030 2025-02-17).

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-01 01:02:17 +00:00
Ruoqing He
4de422ad69 misc: Fix clippy - manually reimplementing div_ceil
Reported by 1.86.0-beta.1 (f0cb41030 2025-02-17).

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-01 01:02:17 +00:00
Ruoqing He
c441bb2968 misc: Fix clippy - doc list item overindented
Reported by 1.86.0-beta.1 (f0cb41030 2025-02-17).

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-03-01 01:02:17 +00:00
Ruoqing He
5cb5115456 build: Fix spdk in linux/arm64 image
The reason `test_vfio_user` fails is as @likebreath pointed: our ARM
host does not support SVE, while the nvme_tgt binary built from the
container image requires it. As a result, we encountered a SIGILL when
running the nvme_tgt binary. This also explains why this is not
happening when the container is built on the same host itself.

And quote from @rbradford:

When a job is run on one of the workers it looks to see if there is a
container locally matching the name as specified in the dev_cli.sh
script - if there is then it uses it. Otherwise it will try and download
it from the container registry - if that fails then it will built
locally. For the x86-64 workers started dynamically it will never have a
local version as they are a fresh VM. But on the ARM64 builder is a
local container image cache.

This can lead to an issue where if the image is build with one version
(a handcrafted datestamp) and then the Dockerfile is changed without
changing the timestamp then an old version may be fetched from the cache
or server. It is there for essential to always bump the datestamp (there
is a number after the - that can be used for this.)

However there is also the added complexity that image that is build and
uploaded to the container registry is not the same as the built locally
and thus used for the initial testing of the Dockerfile change. This
leads to the issue we have seen where different CPU compiler flags (from
-march=native) from the QEMU cross build in the hosted GHA action and
the local ARM64 build. Resulting in a binary in the remotely built
container not working locally.

We end up specifying TARGET_ARCHITECTURE="armv8.2-a" for building spdk,
and put built `python/spdk/` folder into `/usr/local/bin/spdk-nvme`.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-28 18:34:23 +00:00
Ruoqing He
0fbba66b21 scripts: Remove SPDK build in aarch64 test script
We already build `SPDK` for `linux/arm64` in our `Dockerfile`, no need
to build it here anymore.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-24 14:41:46 +00:00
Ruoqing He
5388fa1ced build: Build SPDK for arm64 docker image
Enable `SPDK` build (with DPDK for `generic` arm64 platform) for
`linux/arm64` image.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-24 14:41:46 +00:00
Ruoqing He
655d512523 build: Upgrade to 24.04 in Dockerfile
`arm64` build in ubuntu:22.04 errors out with `error processing package
libc-bin`. This issue is a known issue between the binfmt (running
different architectures via QEMU) and the libc ldconfig binary running
in container. We're "suddenly" having issues as ubuntu-latest (which is
the OS version we run the GH action container with) was recently changed
from 22.04 to 24.04 and hence why upgrading the container userspace from
22.04 to 24.04 solves the problem.

Removed deprecated package `python3-distutils`.

Update image name from `20250111-0` to `20250222-0`.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-24 14:41:46 +00:00
Ruoqing He
7d45473ff7 ci: Update docker actions to latest
Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-24 14:41:46 +00:00
Ruoqing He
294d5fbb08 misc: Fix clippy - operator precedence can trip the unwary
Reported by 1.85.0-stable (4d91de4e4 2025-02-17), fix accordingly.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-21 23:15:04 +00:00
Jinank Jain
8c796e6d5d hypervisor: Add MSHV implementation of VcpuInit
Extend the VcpuInit interface to accomodate changes for MSHV on aarch64.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-02-19 23:23:45 +00:00
Jinank Jain
630f5c1f14 hypervisor: Add MSHV implementation of RegList
Extend the RegList interface to accomodate changes for MSHV on aarch64.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-02-19 23:23:45 +00:00
Jinank Jain
5cbf907200 hypervisor: Add implementation to fetch host IPA limit on MSHV
This fixes an compilation error when we try to compile CloudHypervisor
for MSHV on aarch64.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-02-19 09:39:21 +00:00
dependabot[bot]
bfeab76059 build: Bump async-trait from 0.1.85 to 0.1.86
Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.85 to 0.1.86.
- [Release notes](https://github.com/dtolnay/async-trait/releases)
- [Commits](https://github.com/dtolnay/async-trait/compare/0.1.85...0.1.86)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-19 04:30:55 +00:00
dependabot[bot]
12143ca72f build: Bump proc-macro2 from 1.0.92 to 1.0.93
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.92 to 1.0.93.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.92...1.0.93)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-18 00:27:36 +00:00
dependabot[bot]
ba05bdd085 build: Bump proc-macro-crate from 3.1.0 to 3.2.0
Bumps [proc-macro-crate](https://github.com/bkchr/proc-macro-crate) from 3.1.0 to 3.2.0.
- [Release notes](https://github.com/bkchr/proc-macro-crate/releases)
- [Commits](https://github.com/bkchr/proc-macro-crate/commits/v3.2.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 12:07:24 +00:00
Jinank Jain
171b28ce52 hypervisor, vmm: Avoid leaking hypervisor specific data structure
Currently a bunch of KVM specific interfaces are leaked into the vmm
crate which should ideally does not contain any hypervisor specific data
structures.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-02-12 23:08:43 +00:00
Jinank Jain
5b929cb277 hypervisor: Implement hypervisor agnostic variant of VcpuInit
This will help in fixing the build issue for MSHV on ARM64.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-02-12 23:08:43 +00:00
Jinank Jain
ee0b0d43d8 hypervisor: Implement hypervisor agnostic variant of RegList
This helps in unification of RegList across different platforms.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-02-12 23:08:43 +00:00
Jinank Jain
061482340e hypervisor: Implement hypervisor agnostic Register interface
This will help in fixing the build issue for MSHV on ARM64.

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-02-12 23:08:43 +00:00
dependabot[bot]
c43ae1dc9d build: Bump dirs from 5.0.1 to 6.0.0
Bumps [dirs](https://github.com/soc/dirs-rs) from 5.0.1 to 6.0.0.
- [Commits](https://github.com/soc/dirs-rs/commits)

---
updated-dependencies:
- dependency-name: dirs
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-11 23:57:37 +00:00
Jinank Jain
7db3002e1d build: Bump mshv crate to latest version
Move mshv crates from v0.3.2 to v0.3.3

Signed-off-by: Jinank Jain <jinankjain@microsoft.com>
2025-02-11 14:31:48 +00:00
Ruoqing He
07b7457c2e build: Bump getrandom from 0.2.15 to 0.3.1
Manually bump `getrandom` due to API changes.

Bumps [getrandom](https://github.com/rust-random/getrandom) from 0.2.15 to 0.3.1.
- [Changelog](https://github.com/rust-random/getrandom/blob/master/CHANGELOG.md)
- [Commits](rust-random/getrandom@v0.2.15...v0.3.1)

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-11 07:40:16 +08:00
Ruoqing He
dc9142f86c ci: Introduce lychee to check links
Use `lychee` to check availability of links in cloud-hypervisor.

The urls explictly excluded in config file are manually checked.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-08 22:11:19 +08:00
Ruoqing He
6fa7c84d2e misc: Update link in release-note.md
We have lost track to releases before v27.0 since these projects no
longer exists. Delete links to those projects.

Update links to a detailed view specific to each group of release.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-08 17:32:54 +08:00
Ruoqing He
cc734e2e44 docs: Fix broken to fedora 36 artifacts
Content of fedora 36 have been moved to fedora archives [1], update
accordingly.

Format `README.md` using `mdformat` with GitHub Flavored Markdown
(GFM).

[1] http://archives.fedoraproject.org/pub/archive/fedora/

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-08 16:47:14 +08:00
Ruoqing He
e3e83362d6 docs: Fix broken link in CONTRIBUTING.md
Previous repo hosts details of `Rust Style` is removed, point `Rust
Style` to `style-guide` in `rust-lang/rust` repo.

Link to provide illustration on `signed-off-by language` is also
removed, use a snapshot found in web archive [1] instead.

Format `CONTRIBUTING.md` using `mdformat` with GitHub Flavored Markdown
(GFM).

[1] https://web.archive.org

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-08 16:40:57 +08:00
Ruoqing He
730cf1e944 docs: Fix broken link to intel 0x80 debug port
Previous link to provide details of `0x80 debug port` is removed, which
could no longer be found on intel site [1]. Use snapshot found in web
archive [2] to fix this link.

Format `debug-port.md` using `mdformat` with GitHub Flavored Markdown
(GFM).

[1] https://www.intel.com/content/www/us/en/homepage.html
[2] https://web.archive.org

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-08 16:40:44 +08:00
Ruoqing He
1caa69d0cc docs: Update outdated intel_sgx.md
TDX homepage was moved to elsewhere, and `sgx` support is upstreamed
since v5.11 kernel.

Format `intel_sgx.md` using `mdformat` with GitHub Flavored Markdown
(GFM).

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-08 16:39:16 +08:00
Ruoqing He
abcbf43433 docs: Update outdated intel_tdx.md
TDX homepage was moved to elsewhere, and `tdx-tools` repo was removed.

Provide a valid link of TDX homepage and change all reference to
`tdx-tools` to `tdx-linux`.

Format `intel_tdx.md` using `mdformat` with GitHub Flavored Markdown
(GFM).

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-08 16:38:46 +08:00
Ruoqing He
af74de2779 docs: Fix broken link in io_throttling.md
There is a link referencing `rate-limiter` module of `firecracker`, but
that module no longer exsits.

Point the link to a commit with the same date in `firecracker` when this
commit was merged to `cloud-hypervisor`.

Format `io_throttling.md` using `mdformat` with GitHub Flavored Markdown
(GFM).

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-08 16:38:22 +08:00
Ruoqing He
dfebc8929d docs: Fix broken link to docs/arm64.md
`docs/arm64.md` was removed and splited into `README.md`, `building.md`
and `uefi.md` in #4991.

Let's point it to
`8ab15b9a98/docs/arm64.md`
the commit right before `docs/arm64.md` was removed in main branch.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-08 16:37:50 +08:00
Ruoqing He
9988379f6b docs: Fix link to docs/logging.md
Previous link `docs/logging` is not valid, replacing `docs/logging` with
`docs/logging.md`.

Format `logging.md` using `mdformat` with GitHub Flavored Markdown
(GFM).

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-08 16:37:03 +08:00
Ruoqing He
4d12192490 docs: Fix broken link in amd_sev_snp.md
Previous link to details of SNP is now broken, pointing that section to
a valid link [1].

Format `amd_sev_snp.md` using `mdformat` with GitHub Flavored Markdown
(GFM).

[1] https://www.amd.com/content/dam/amd/en/documents/epyc-business-docs/solution-briefs/amd-secure-encrypted-virtualization-solution-brief.pdf

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-02-08 16:36:48 +08:00
Wei Liu
9f9cfeb5be build: Provide CH_EXTRA_VERSION
Use this to add any extra versioning information to the binary. It is
useful when packaging Cloud Hypervisor.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-02-04 19:33:10 +00:00
Bo Chen
3fa1e77adc build: Release v44.0
Signed-off-by: Bo Chen <bchen@crusoe.ai>
2025-02-03 18:09:27 +00:00
dependabot[bot]
b8424ea506 build: Bump colorchoice from 1.0.2 to 1.0.3
Bumps [colorchoice](https://github.com/rust-cli/anstyle) from 1.0.2 to 1.0.3.
- [Commits](https://github.com/rust-cli/anstyle/compare/colorchoice-v1.0.2...colorchoice-v1.0.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-24 23:56:13 +00:00
Ruoqing He
0c2fe29f61 arch: riscv64: Fix interrupt-controller FDT property
This is a typo here, `interrupt-controller` attribute of each CPU node
should not have a `#` prepended.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-01-24 12:24:02 +00:00
dependabot[bot]
b445d219ca build: Bump uuid from 1.8.0 to 1.12.1
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.8.0 to 1.12.1.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.8.0...1.12.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-24 00:40:22 +00:00
dependabot[bot]
6de283f42c build: Bump micro_http from ef43cef to ef96f62
Bumps [micro_http](https://github.com/firecracker-microvm/micro-http) from `ef43cef` to `ef96f62`.
- [Commits](ef43cef716...ef96f623c4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-22 23:49:15 +00:00
Rob Bradford
f892789481 docs: Update documentation for new kernel configuration
Replace the use of a reference kernel configuration file from this
repository with the use of a defconfig from the linux fork.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-22 17:45:32 +00:00
dependabot[bot]
f96554cbe9 build: Bump clap_lex from 0.7.2 to 0.7.4
Bumps [clap_lex](https://github.com/clap-rs/clap) from 0.7.2 to 0.7.4.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_lex-v0.7.2...clap_lex-v0.7.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-21 23:48:31 +00:00
Ruoqing He
3509b5bf4a hypervisor: Create vcpu before initialize AIA
Create a corresponding `vcpu` in `test_create_aia`  to capture wrongly
configured RISC-V IMSIC attr.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-01-21 12:53:54 +00:00
Ruoqing He
cf463b88b7 hypervisor: Fix AIA IMSIC attr calculation
The IMSIC attr of RISC-V AIA is wrongly configured to start from 0, which
would error out with `os error 22` (invalid argument).

```console
Error booting VM: VmBoot(DeviceManager(CreateInterruptController(CreateAia(CreateVaia(Vaia error SetDeviceAttribute(SetDeviceAttribute(Invalid argument (os error 22))))))))
```

`riscv_imsic_attr_of` should shift `cpu_index` by 1 here to produce
correct IMSIC attr.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2025-01-21 12:53:54 +00:00
dependabot[bot]
ca8eda5399 build: Bump autocfg from 1.3.0 to 1.4.0
Bumps [autocfg](https://github.com/cuviper/autocfg) from 1.3.0 to 1.4.0.
- [Commits](https://github.com/cuviper/autocfg/compare/1.3.0...1.4.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-21 00:08:19 +00:00
dependabot[bot]
45b770ea9f build: Bump fastrand from 2.2.0 to 2.3.0
Bumps [fastrand](https://github.com/smol-rs/fastrand) from 2.2.0 to 2.3.0.
- [Release notes](https://github.com/smol-rs/fastrand/releases)
- [Changelog](https://github.com/smol-rs/fastrand/blob/master/CHANGELOG.md)
- [Commits](https://github.com/smol-rs/fastrand/compare/v2.2.0...v2.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-19 09:51:20 +00:00
dependabot[bot]
d2c4ceb99a build: Bump uuid-macro-internal from 1.10.0 to 1.12.0
Bumps [uuid-macro-internal](https://github.com/uuid-rs/uuid) from 1.10.0 to 1.12.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.10.0...1.12.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-17 00:32:04 +00:00
dependabot[bot]
caf7cae2fa build: Bump async-executor from 1.11.0 to 1.13.1
Bumps [async-executor](https://github.com/smol-rs/async-executor) from 1.11.0 to 1.13.1.
- [Release notes](https://github.com/smol-rs/async-executor/releases)
- [Changelog](https://github.com/smol-rs/async-executor/blob/master/CHANGELOG.md)
- [Commits](https://github.com/smol-rs/async-executor/compare/v1.11.0...v1.13.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-16 00:08:08 +00:00
Arvind Vasudev
81eca69b40 pci: Adding support for printing the device's address on a DMA map and unmap errors
Signed-off-by: Arvind Vasudev <avasudev@crusoeenergy.com>
2025-01-15 18:14:35 +00:00
Arvind Vasudev
8c07294691 pci: Implementing Debug for PciBdf to aid with debugging
Signed-off-by: Arvind Vasudev <avasudev@crusoeenergy.com>
2025-01-15 18:14:35 +00:00
Rob Bradford
2f9436bc12 build: Switch to named released kernel binary
For more control over updating the guest kernel use a fixed tag name
rather than fetching the latest.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-15 09:21:16 +00:00
dependabot[bot]
62fade97d1 build: Bump tempfile from 3.11.0 to 3.12.0
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.11.0 to 3.12.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.11.0...v3.12.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-14 23:49:04 +00:00
Nikolay Edigaryev
5a8df3622c tests: ensure that IOMMU maximum address width in bits is respected
Signed-off-by: Nikolay Edigaryev <edigaryev@gmail.com>
2025-01-14 21:31:47 +00:00
Nikolay Edigaryev
27fda753e1 virtio-devices: iommu: allow limiting maximum address width in bits
Currently, Cloud Hypervisor does not set a VIRTIO_IOMMU_F_INPUT_RANGE
feature bit for the VirtIO IOMMU device, which, according to spec[1],
means that the guest may use the whole 64-bit address space is for
IOMMU purposes:

>If the feature is not offered, virtual mappings span over the whole
>64-bit address space (start = 0, end = 0xffffffff ffffffff)

As far as I am aware, there are currently no host platforms on
the market capable of addressing the whole 64-bit address space.

For example, I am currently working with a host platform that reports
39-bit address space for IOMMU purposes:

>DMAR: Host address width 39

When running a VFIO pass-through guest on such a platform, NVIDIA
driver in guest gets DMA mapping failures when working with large data,
and this results in Cloud Hypervisor exiting with the following error:

>cloud-hypervisor: 1501.220535s: <__iommu>
>ERROR:virtio-devices/src/thread_helper.rs:53 -- Error running worker:
>HandleEvent(Failed to process request queue : ExternalMapping(Custom
>{ kind: Other, error: "failed to map memory for VFIO container, iova
>0x7fff00000000, gpa 0x24ce25000, size 0x1000: IommuDmaMap(Error(22))"
>}))

Passing "--platform iommu_address_width=39" to Cloud Hypervisor built
with this change fixes this.

[1]: https://docs.oasis-open.org/virtio/virtio/v1.3/csd01/
virtio-v1.3-csd01.html#x1-5420006

Signed-off-by: Nikolay Edigaryev <edigaryev@gmail.com>
2025-01-14 21:31:47 +00:00
Nikolay Edigaryev
74ca38f7a9 vmm: introduce platform option to limit maximum IOMMU address width
Signed-off-by: Nikolay Edigaryev <edigaryev@gmail.com>
2025-01-14 21:31:47 +00:00
Rob Bradford
fa686fdfc7 tests: Bump OVMF version
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-14 17:53:43 +00:00
Wei Liu
c827a1c009 fuzz: build x86emul by default
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-14 17:37:57 +00:00
dependabot[bot]
eefd7fcaaf build: Bump linux-raw-sys from 0.4.14 to 0.4.15
Bumps [linux-raw-sys](https://github.com/sunfishcode/linux-raw-sys) from 0.4.14 to 0.4.15.
- [Commits](https://github.com/sunfishcode/linux-raw-sys/compare/v0.4.14...v0.4.15)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-14 16:01:22 +00:00
Rob Bradford
62303d8c33 arch: x86_64: Log the cpuid per vCPU
This will aid debugging issues related to CPUID.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-14 12:52:55 +00:00
Rob Bradford
293cf90e3d hypervisor: Implement fmt::Display for CpuIdEntry
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-14 12:52:55 +00:00
Bo Chen
8f98fabd0b vmm: Cleanup VM being created when VM restore fails
When VM restore fails, the VMM state is left with some side-effects,
such as a VM being created. It would prevent the VMM from creating and
booting a new VM or restoring from a VM snapshot.

To fix this issue, this patch explicitly handles the side effects to the
VMM state when VM restore fails, e.g. clear the VmConfig and shutdown
the VM being created.

Fixes: #6869

Signed-off-by: Bo Chen <bo.arvin.chen@gmail.com>
2025-01-14 00:45:03 +00:00
Bo Chen
07821c08c0 vmm: Always re-generate the 'console_info' with VM restore
With VM restore, the VMM is always re-creating a VM based on the
restored `VmConfig`. We should always re-generate the 'console_info'
from the `Vmm` struct to stay consistent with the new VM being created.

Signed-off-by: Bo Chen <bo.arvin.chen@gmail.com>
2025-01-14 00:45:03 +00:00
Wei Liu
0cb2c86ff4 fuzz: introduce a virtio vsock fuzzer
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-14 00:26:01 +00:00
Wei Liu
d359c8cdce virtio-devices: vsock: allow fuzzer to use TestBackend
Instead of reinventing this mock infrastructure in the upcoming fuzzer,
reuse the one that is already available.

However this change makes Clippy complain that TestBackend and
TestContext don't implement Default. This is just test code, we can
suppress Clippy in this case.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-14 00:26:01 +00:00
Rob Bradford
c801929fd1 tests: Update interrupt group name on ARM
This has changed with kernel 6.12.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-13 21:46:23 +00:00
Rob Bradford
66da3b9970 scripts: Temporarily build kernel as part of CI
Updating the kernel to v6.12 has shown up a flaw in the workflow for our
binary kernel releases. The CI job that builds the binary kernel in the
cloud-hypervisor/linux repository fetches the config from the main
branch of the cloud-hypervisor/cloud-hypervisor repository. However the
CI job to update the kernel version to use is in the cloud-hypervisor
repository.

As a workaround - update the kernel config and version in the
cloud-hypervisor repository to point to v6.12 and use the ability to
build the kernel during the CI run. Once merged to main a new release
can be made in the linux respository which will build a binary asset
using the new config. After that release the CI jobs on the
cloud-hypervisor repository can changed back to using the binary kernel
assets.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-13 21:46:23 +00:00
Rob Bradford
6ddbd60d9d build: Update kernel to v6.12
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-13 21:46:23 +00:00
Rob Bradford
2fc4de6c65 virtio-devices: iommu: Use hex formatting in log messages
This means that the the addresses are more easily readable.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-13 21:46:23 +00:00
Rob Bradford
03eeb36b74 virtio-devices: iommu: Search full range for GVA conversion
Remove an erroneous optimisation that used the page size mask to reduce
the range to iterate through on the set of mappings. This doesn't work
as the virtio-iommu ranges are larger than a single page. This may have
worked in the past when the mappings were limited to a single page.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-13 21:46:23 +00:00
Rob Bradford
2fe7f54ece build: Bump version number of Docker image
No change to the Dockerfile but I observed that the 20251022-0 image was
not available in the repository.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-11 15:03:01 +00:00
Rob Bradford
1cc540c880 build: Update github artifact action version
The v3 version is now deprecated. Tested by creating a dummy tag and
validating the results.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-09 22:25:35 +00:00
Wei Liu
a1af4238ae virtio-devices: make ioeventfds() return an iterator
MSHV's SEV-SNP implementation calls ioeventfds whenever there is an
event.

This change removes the need frequent allocation and deallocation of a
vector, while at the same time makes sure other call sites are
unaffected.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-09 21:28:46 +00:00
Wei Liu
d2e798944a virtio-devices: rename two variables
They are used. No need to start their names with an underscore.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-09 21:28:46 +00:00
Wei Liu
d99f294281 pci: rename as_any to as_any_mut
That trait function returns a mutable reference. Rename it to follow
Rust's convention.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-09 21:28:46 +00:00
dependabot[bot]
44c9ce598d build: Bump anstyle-wincon from 3.0.4 to 3.0.6
Bumps [anstyle-wincon](https://github.com/rust-cli/anstyle) from 3.0.4 to 3.0.6.
- [Commits](https://github.com/rust-cli/anstyle/compare/anstyle-wincon-v3.0.4...anstyle-wincon-v3.0.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-09 13:57:10 +00:00
Wei Liu
5b42aa0bcf hypervisor: kvm: fix an operator precedence clippy warning
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-09 13:51:42 +00:00
Wei Liu
703e0cab04 vmm: use C ABI-qualification for packed structures
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-09 13:51:42 +00:00
Wei Liu
abb88cf47f arch: tdx: use proper repr qualifications
They should be packed and use C ABI.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-09 13:51:42 +00:00
Wei Liu
2e22b8bc3a pci: use C ABI-qualification for a packed structure
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-09 13:51:42 +00:00
Wei Liu
778c05d678 virtio-devices: use C ABI-qualification for packed structures
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-09 13:51:42 +00:00
Wei Liu
5b29eba636 block: vhdx: use C ABI-qualification for packed structures
This fixes the following issue from beta Clippy:

error: item uses `packed` representation without ABI-qualification
Error:    --> block/src/vhdx/vhdx_header.rs:333:1
    |
331 |   #[repr(packed)]
    |          ------ `packed` representation set here
332 |   #[derive(Clone, Copy, Debug)]
333 | / pub struct RegionTableEntry {
334 | |     pub guid: Uuid,
335 | |     pub file_offset: u64,
336 | |     pub length: u32,
337 | |     pub required: u32,
338 | | }
    | |_^
    |
    = warning: unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI
    = help: qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#repr_packed_without_abi

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-09 13:51:42 +00:00
Wei Liu
e6e78e5986 block: vhdx: reject zero size virtual disk
Some calculation down the road depends on that value not being zero.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-08 22:45:58 +00:00
Wei Liu
a2df4d7660 fuzz: explicitly keep or reject input for vhdx fuzzer
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-08 22:45:58 +00:00
Wei Liu
bc4a1fd16c block: vhdx: use checked_add in read and write functions
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-08 22:45:58 +00:00
Wei Liu
463c9b8e56 block: vhdx: hoist a check out of IO loops
This reduces one indentation level in the IO loops in the read and write
functions.

No functional change.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-08 22:45:58 +00:00
dependabot[bot]
835847bea5 build: Bump async-trait from 0.1.83 to 0.1.85
Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.83 to 0.1.85.
- [Release notes](https://github.com/dtolnay/async-trait/releases)
- [Commits](https://github.com/dtolnay/async-trait/compare/0.1.83...0.1.85)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-08 15:17:36 +00:00
Rob Bradford
3e4ed5621e vmm: Automatically fix operator precedence clippy warning
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-07 17:44:41 +00:00
Rob Bradford
2624f17ffe virtio-devices: Automatically fix operator precedence clippy warning
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-07 17:44:41 +00:00
Rob Bradford
21f05ebb4f vhost_user_block: Automatically fix operator precedence clippy warning
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-07 17:44:41 +00:00
Rob Bradford
1485e17268 vhost_user_net: Automatically fix operator precedence clippy warning
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-07 17:44:41 +00:00
Rob Bradford
b57cc3d79f pci: Automatically fix operator precedence clippy warning
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-07 17:44:41 +00:00
Rob Bradford
a322e2d6f4 hypervisor: Automatically fix operator precedence clippy warning
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-07 17:44:41 +00:00
Rob Bradford
dd0b95ba5c devices: Automatically fix operator precedence clippy warning
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-07 17:44:41 +00:00
Rob Bradford
b6667f948e arch: Fix operator precedence clippy warning
With manual (to ensure comment preservation) and automatic fixes.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-07 17:44:41 +00:00
dependabot[bot]
4f22f67307 build: Bump proc-macro2 from 1.0.86 to 1.0.92
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.86 to 1.0.92.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.86...1.0.92)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-07 00:15:47 +00:00
Rob Bradford
eeae63b459 build: Bump thiserror version
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-06 17:39:45 +00:00
Rob Bradford
abf5748f64 block: qcow: Use constant in error message
This avoids ambiguity of parameters:

error: ambiguous reference to positional arguments by number in a tuple variant; change this to a named argument
  --> block/src/qcow/mod.rs:48:48
   |
48 |     #[error("File larger than max of {}: {0}", MAX_QCOW_FILE_SIZE)]
   |                                                ^^^^^^^^^^^^^^^^^^

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2025-01-06 17:39:45 +00:00
dependabot[bot]
23b5f7b1c5 build: Bump futures from 0.3.30 to 0.3.31
Bumps [futures](https://github.com/rust-lang/futures-rs) from 0.3.30 to 0.3.31.
- [Release notes](https://github.com/rust-lang/futures-rs/releases)
- [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.30...0.3.31)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-06 15:05:55 +00:00
Wei Liu
a66fef407c block: vhdx: properly account for bytes read and written
The counter value in vhdx_io::{read,write} should've been accumulated
over the loop.

Fixes: #6897
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-03 10:25:53 +00:00
Wei Liu
7c39f37855 fuzz: introduce an x86 instruction emulator fuzzer
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-02 22:43:59 +00:00
Wei Liu
fe24a7a24f hypervisor: introduce an mshv_emulator feature
This will become useful when we build the fuzzing target for the
instruction emulator, because there is no need to pull in the rest of
the hypervisor crate in that situation.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-02 22:43:59 +00:00
Wei Liu
73e1451a12 hypervisor: emulator: use wrapping arithmetic
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-02 22:43:59 +00:00
Wei Liu
1180f757b3 hypervisor: emulator: adjust iced-x86 feature flags
The fastfmt feature and VEX support use techniques that appear to leak
memory in the eye of LLVM's address sanitizer.

While at it, disable a bunch of instruction set decoding support we
never intend to support.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-02 22:43:59 +00:00
Wei Liu
2932658acd fuzz: update Cargo.lock
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-02 22:43:59 +00:00
Wei Liu
1f7b809619 block: increase the size of temporary vectors
The size was set to one because without VIRTIO_BLK_F_SEG_MAX, the guest
only used one data descriptor per request.

The value 32 is empirically derived from booting a guest. This value
eliminates all SmallVec allocations observable by DHAT.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-01 18:50:39 +00:00
Wei Liu
32482f6634 block: make available VIRTIO_BLK_F_SEG_MAX
This allows the guest to put in more than one segment per request. It
can improve the throughput of the system.

Introduce a new check to make sure the queue size configured by the user
is large enough to hold at least one segment.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2025-01-01 18:50:39 +00:00
Wei Liu
6fd5b0f696 fuzz: explicitly keep or reject fuzzer corpus
When the main fuzzer function returns (), it is equivalent to
returning Corpus::Keep.

In some of the return paths, we want to reject the input so that the
libfuzzer won't spend more time mutating them.

The should make fuzzing more efficient. No functional change intended.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-12-31 19:49:48 +00:00
Wei Liu
ef88b2778e block: vhdx: advance file offset after read and write
This is needed to handle multiple reads or writes in a loop.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-12-28 23:59:59 +00:00
Wei Liu
8b55d1e2d4 block: vhdx: rename Header::get_header_as_buffer
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-12-28 23:59:59 +00:00
Wei Liu
2df285effd block: vhdx: use calculate_checksum in Header::update_header
It doesn't make sense to open code the same calculation when there is
already a helper function.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-12-28 23:59:59 +00:00
Wei Liu
4ea4391f45 block: vhdx: adjust calculate_checksum
It doesn't need to be public. None of its code path returns an error.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-12-28 23:59:59 +00:00
Wei Liu
8f8d3c0139 block: vhdx: fix checksum calculation
The checksum field in the original buffer should be zeroed.

The code was zeroing a temporary buffer. That's wrong.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-12-28 23:59:59 +00:00
Wei Liu
408467a05f block: vhdx: do not update the VHDX header during parsing
The original code was buggy. It always attempted to update the header,
even when the file was opened as read-only. That led to an error.

The specification states that the headers should be updated when the
first user visible write happens. We can just drop the incorrect code.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-12-28 23:59:59 +00:00
Wei Liu
f27b028c18 block: vhdx: drop pub keyword from update_header
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-12-28 23:59:59 +00:00
dependabot[bot]
eaa2194699 build: Bump kvm-ioctls from 0.19.0 to 0.19.1
Bumps [kvm-ioctls](https://github.com/rust-vmm/kvm-ioctls) from 0.19.0 to 0.19.1.
- [Release notes](https://github.com/rust-vmm/kvm-ioctls/releases)
- [Changelog](https://github.com/rust-vmm/kvm/blob/v0.19.1/CHANGELOG.md)
- [Commits](https://github.com/rust-vmm/kvm-ioctls/compare/v0.19.0...v0.19.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-23 20:18:18 +00:00
Wei Liu
9973d28849 block: drop unused function create_disk_file
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-12-21 20:20:29 +00:00
dependabot[bot]
1cdb91a40f build: Bump vfio-ioctls from e71efe4 to bdbb1cd
Bumps [vfio-ioctls](https://github.com/rust-vmm/vfio) from `e71efe4` to `bdbb1cd`.
- [Release notes](https://github.com/rust-vmm/vfio/releases)
- [Commits](e71efe41d5...bdbb1cd486)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-21 11:51:17 +00:00
Wei Liu
57e331db0e block: drop the ASYNC flag from io_uring entries
The ASYNC flag forces requests to go to worker threads. Worker threads
are expensive. Let the kernel decide what to do.

With this change, I no longer see an excessive amount of io_uring worker
threads.

Quote from the manual for io_uring_sqe_set_flags(3):

```
   IOSQE_ASYNC
          Normal operation for io_uring is to try and issue an sqe
          as non-blocking first, and if that fails, execute it in an
          async manner. To support more efficient overlapped
          operation of requests that the application knows/assumes
          will always (or most of the time) block, the application
          can ask for an sqe to be issued async from the start. Note
          that this flag immediately causes the SQE to be offloaded
          to an async helper thread with no initial non-blocking
          attempt.  This may be less efficient and should not be
          used liberally or without understanding the performance
          and efficiency tradeoffs.
```

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-12-21 10:47:29 +00:00
Wei Liu
090fcebfec block: do not ignore failures when pushing to io_uring submission queue
Instead of silently ignoring the error, return an error to the callers.

This in practice should never happen, because the submission queue size
(ring depth) is the same as the virtio queue size. Virtio queue won't
push more requests than there are submission queue entries.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-12-21 10:47:29 +00:00
Wei Liu
b2f40afc69 block: fix short read and short write in AsyncAdaptor
The original code relied on the default `read_vectored` or
`write_vectored` implementations from the standard library.

The default implementation of those functions only uses the first
non-empty buffer. That's not correct when there are more than one
buffers.

Fixes: #6876
Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-12-21 10:46:16 +00:00
Rob Bradford
72452707ee scripts: Reduce number of parallel jobs on ARM64 CI
This system is erroring out on jobs due to insufficient memory - reduce
parallelism to allow CI jobs to complete.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2024-12-20 10:36:13 +00:00
Rob Bradford
49a389ff12 build: Release v43.0
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2024-12-18 17:28:48 +00:00
dependabot[bot]
2a9b60dcce build: Bump object from 0.36.1 to 0.36.5
Bumps [object](https://github.com/gimli-rs/object) from 0.36.1 to 0.36.5.
- [Changelog](https://github.com/gimli-rs/object/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gimli-rs/object/compare/0.36.1...0.36.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-18 16:16:59 +00:00
Jinrong Liang
bbd8d3b71d tests: live-migration: Add integration test for tcp live migration
Add integration test for tcp live migration to ensure live migration
functions as expected.

Signed-off-by: Jinrong Liang <cloudliang@tencent.com>
2024-12-18 14:02:38 +00:00
Jinrong Liang
b9163bf431 docs: Add documentation for cross-host TCP live migration
Updated the live migration documentation to include instructions for
performing cross-host live migrations over TCP connections.

Signed-off-by: Jinrong Liang <cloudliang@tencent.com>
2024-12-18 14:02:38 +00:00
Jinrong Liang
909e1bc3f0 vmm: Add support for cross-host live migration over TCP
Add support for cross-host live migration over TCP, which
significantly improves performance in cross-host live migration
scenarios compared to the Unix socket forwarding method.

Signed-off-by: Jinrong Liang <cloudliang@tencent.com>
2024-12-18 14:02:38 +00:00
Jinrong Liang
4f18476cca build: Bump vm-memory from 0.16.0 to 0.16.1
Bump vm-memory from 0.16.0 to 0.16.1 to include the implementations of
ReadVolatile and WriteVolatile for TcpStream.

Signed-off-by: Jinrong Liang <cloudliang@tencent.com>
2024-12-18 14:02:38 +00:00
dependabot[bot]
3d7661664d build: Bump getrandom from 0.2.14 to 0.2.15
Bumps [getrandom](https://github.com/rust-random/getrandom) from 0.2.14 to 0.2.15.
- [Changelog](https://github.com/rust-random/getrandom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/getrandom/compare/v0.2.14...v0.2.15)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-14 15:13:09 +00:00
Alyssa Ross
50bac1694f vmm: support PCI I/O regions on all architectures
While non-Intel CPU architectures don't have a special concept of IO
address space, support for PCI I/O regions is still needed to be able
to handle PCI devices that use them.

With this change, I'm able to pass through an e1000e device from QEMU
to a cloud-hypervisor VM on aarch64 and use it in the cloud-hypervisor
guest.  Previously, it would hit the unimplemented!().

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2024-12-14 14:12:00 +00:00
Alyssa Ross
dd8a5a7de8 vmm: remove outdated comment
Fixes: def98faf ("vmm, vm-allocator: Introduce an allocator for platform devices")
Signed-off-by: Alyssa Ross <hi@alyssa.is>
2024-12-14 14:12:00 +00:00
dependabot[bot]
dba92c28f7 build: Bump event-listener-strategy from 0.5.1 to 0.5.3
Bumps [event-listener-strategy](https://github.com/smol-rs/event-listener-strategy) from 0.5.1 to 0.5.3.
- [Release notes](https://github.com/smol-rs/event-listener-strategy/releases)
- [Changelog](https://github.com/smol-rs/event-listener-strategy/blob/main/CHANGELOG.md)
- [Commits](https://github.com/smol-rs/event-listener-strategy/compare/v0.5.1...v0.5.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-13 01:55:30 +00:00
Muminul Islam
4e298d1abf hypervisor: maintain a bitmap for SEV-SNP VM on MSHV
Add a bitmap to MshvVM struct for caching the pages
that the VMM got shared access from the guest.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2024-12-12 03:32:22 +00:00
Muminul Islam
149c342867 vmm: pass memory size during VM creation
Pass memory size from vmm crate to hypervisor VM
creation API so use for creating Bitmap for SEV-SNP
guest.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2024-12-12 03:32:22 +00:00
Muminul Islam
4054a49e2d hypervisor: use memory size during VM creation
For SEV-SNP VM on MSHV we need to request page access during
IO, we want to avoid such request for the page that have already
been requested. In order to maintain the bitmap we need the memory size
during bitmap creation.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2024-12-12 03:32:22 +00:00
dependabot[bot]
1001d807ff build: Bump version_check from 0.9.4 to 0.9.5
Bumps [version_check](https://github.com/SergioBenitez/version_check) from 0.9.4 to 0.9.5.
- [Commits](https://github.com/SergioBenitez/version_check/compare/v0.9.4...v0.9.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-12 02:56:45 +00:00
Muminul Islam
e4a5219f53 hypervisor: mshv: modify GuestRequest handling for CVM
VMM needs to handle VMG exit for guest request. This patch
removes the old method that uses gpa_read/write(IOCTL and hypercall),
which is expensive and update the GHCB page using
mapped(root partition) struct.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2024-12-11 21:06:06 +00:00
Muminul Islam
a458351d8b hypervisor: mshv: modify MMIO exit handling for CVM
VMM needs to handle VMG exit for MMIO. This patch
removes the old method that uses gpa_read/write(IOCTL and hypercall),
which is expensive and update the GHCB page using
mapped(root partition) struct.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2024-12-11 21:06:06 +00:00
Muminul Islam
5a27bf878c hypervisor: mshv: modify IoPort handling for CVM
VMM needs to handle VMG exit for IO Port. This patch
removes the old method that uses gpa_read/write(IOCTL and hypercall),
which is expensive and update the GHCB page using
mapped(root partition) struct.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2024-12-11 21:06:06 +00:00
Muminul Islam
310dafb4d7 hypervisor: mshv: modify doorbell page handling for CVM
VMM needs to handle VMG exit for doorbell page. This patch
removes the old method that uses gpa_read/write(IOCTL and hypercall),
which is expensive and update the GHCB page using
mapped(root partition) struct.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2024-12-11 21:06:06 +00:00
Muminul Islam
78895dcc37 hypervisor: mshv: clear exitinfo1 using mapped ghcb address
After handling the VMG exit vmm needs to clear the exitinfo1
into the GHCB page. This patch replaces the old
method(gpa_write) and clear the exitinfo1 using mapped GHCB struct.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2024-12-11 21:06:06 +00:00
Muminul Islam
1757d83db3 hypervisor: Keep GHCB mapped address for each VCPU on MSHV
For confidential VM on MSHV, GHCB page is the communication
method between guest and host. All the CVM exits, VMM
needs to read and write to the GHCB page. MSHV provides
an option to remap the page to the root partition. This
way VMM could directly read and write to the page and
skip extra IOCTL and hypercall. This improvement makes
the IO 10% faster.

Signed-off-by: Muminul Islam <muislam@microsoft.com>
2024-12-11 21:06:06 +00:00
Muminul Islam
9cef779cc7 build: use latest version of mshv and vfio crates
Signed-off-by: Muminul Islam <muislam@microsoft.com>
2024-12-11 21:06:06 +00:00
dependabot[bot]
a10d1ed78e build: Bump openssl-sys from 0.9.102 to 0.9.104
Bumps [openssl-sys](https://github.com/sfackler/rust-openssl) from 0.9.102 to 0.9.104.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.102...openssl-sys-v0.9.104)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-10 23:57:33 +00:00
dependabot[bot]
dc7f0a42bc build: Bump regex from 1.10.5 to 1.11.1
Bumps [regex](https://github.com/rust-lang/regex) from 1.10.5 to 1.11.1.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.10.5...1.11.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-10 00:39:08 +00:00
dependabot[bot]
53098ae40f build: Bump backtrace from 0.3.73 to 0.3.74
Bumps [backtrace](https://github.com/rust-lang/backtrace-rs) from 0.3.73 to 0.3.74.
- [Release notes](https://github.com/rust-lang/backtrace-rs/releases)
- [Commits](https://github.com/rust-lang/backtrace-rs/compare/0.3.73...0.3.74)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-09 11:48:05 +00:00
Ruoqing He
51cf346828 ci: Enable riscv64 CI of devices module
Enable build, clippy and unit-test on devices module.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-06 16:24:41 +00:00
Ruoqing He
0042447fb9 devices: Disable tpm module for riscv64
TPM support on RISC-V is not scheduled in this stage, we will come back
when it's ready and we have workloads to verify it on RISC-V.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-06 16:24:41 +00:00
Ruoqing He
e8c330e220 devices: Introduce RISC-V AIA interrupt device
Introduce definitions, implementations and error variants of RISC-V AIA
(Advance Interrupt Architecture) interrupt controller.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-06 16:24:41 +00:00
Ruoqing He
ba78e331c6 devices: Enable build with kvm feature
Currently `devices` module cannot be solely built, by specifying
`arch/kvm` to turn on the features required for its dependency - `arch`
crate to build. Thus enabling `devices` crate to be built and tested
with command:

```sh
cargo build -p devices --features kvm
```

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-06 16:24:41 +00:00
Ruoqing He
b6d2ac2c2e devices: Enable arch module for riscv64
`arch` module are required for devices module to build. Enabling `arch`
module in target specific dependencies section.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-06 16:24:41 +00:00
dependabot[bot]
f6fb442fa3 build: Bump cpufeatures from 0.2.12 to 0.2.16
Bumps [cpufeatures](https://github.com/RustCrypto/utils) from 0.2.12 to 0.2.16.
- [Commits](https://github.com/RustCrypto/utils/compare/cpufeatures-v0.2.12...cpufeatures-v0.2.16)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-06 00:47:03 +00:00
dependabot[bot]
0c2f2d3ec1 build: Bump anyhow from 1.0.87 to 1.0.94
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.87 to 1.0.94.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.87...1.0.94)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-05 00:30:01 +00:00
Ruoqing He
584c088094 ci: Enable riscv64 CI of vm-allocator module
Enable build, clippy, doc-test and unit-test on vm-allocator module.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-04 09:29:56 +00:00
Ruoqing He
5b715f483d vm-allocator: Introduce RISC-V architecture
Provide implementation for GSI allocator to work on riscv64
architecture, and doc comment for riscv64 as well.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-04 09:29:56 +00:00
Ruoqing He
1e602bd9a6 vm-allocator: Enable build with kvm feature
Currently `vm-allocator` module cannot be solely built, by add
`features` section and specifying `arch/kvm` to turn on the features
required for its dependency - `arch` module to build. Thus enabling
`vm-allocator` crate to be built and tested with command:

```sh
cargo build -p vm-allocator --features kvm
```

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-04 09:29:56 +00:00
Ruoqing He
6b57f301db vm-allocator: Enable arch module for riscv64
`arch` module are required to provide definitions for riscv64 system irq
and memroy allocation, enabling `arch` module in target specific
dependencies section.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-04 09:29:56 +00:00
dependabot[bot]
cd0db3146f build: Bump async-signal from 0.2.6 to 0.2.10
Bumps [async-signal](https://github.com/smol-rs/async-signal) from 0.2.6 to 0.2.10.
- [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.6...v0.2.10)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-04 00:10:04 +00:00
Ruoqing He
ac3ef0849e ci: Enable riscv64 CI of arch module
Enable build, clippy and unit-test on arch module.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-03 22:13:37 +00:00
Ruoqing He
bd8db86b0c arch: Introduce RISC-V architecture
Integrate fdt setup and layout for `riscv64` to `arch` crate, provide
definitions of `riscv64` platform specific error and reuse
`MmioDeviceInfo`, `PciSpaceInfo` structures and `DeviceInfoForFdt` impl
block for `riscv64`.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-03 22:13:37 +00:00
Ruoqing He
7b5f06788a arch: Introduce fdt setup for riscv64
Introduce `cpu`, `memory`, `chosen`, `aia` and `pci` node setup for
`riscv64`.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-03 22:13:37 +00:00
Ruoqing He
9a7f278716 arch: Introduce RISC-V 64-bit layout
Reused layout set for `aarch64` as much as possible to provide a concise
and compatible (for devices) layout for RISC-V 64-bit.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-03 22:13:37 +00:00
Ruoqing He
fb457954bb arch: Enable fdt_parser and vm-fdt for riscv64
`fdt_parser` and `vm-fdt` crates are required to setup fdt used to boot
riscv64 virtual machines, enabling the two crates in target specific
dependencies section.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-03 22:13:37 +00:00
Ruoqing He
c4063d26be hypervisor: Set pc and a1 for all vcpu
It turns out we need to setup `a0`, `pc` and `a1` for all vcpus before
we run them, remove predicates used to set `pc` and `a1` for `vcpu0`.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-03 22:13:37 +00:00
Ruoqing He
9006013c60 hypervisor: Tune Vaia trait to work with fdt setup
Previous `Vaia` implementation uses types as it is, thus the property
string generated for fdt setup requires additional type conversion.
Change the types used in the methods of `Vaia` trait to provide a
concise fdt setup process.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-03 22:13:37 +00:00
dependabot[bot]
30cf1eed5e build: Bump libc from 0.2.158 to 0.2.167
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.158 to 0.2.167.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.167/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.158...0.2.167)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-03 01:15:36 +00:00
dependabot[bot]
c6b023e58d build: Bump async-process from 2.2.2 to 2.3.0
Bumps [async-process](https://github.com/smol-rs/async-process) from 2.2.2 to 2.3.0.
- [Release notes](https://github.com/smol-rs/async-process/releases)
- [Changelog](https://github.com/smol-rs/async-process/blob/master/CHANGELOG.md)
- [Commits](https://github.com/smol-rs/async-process/compare/v2.2.2...v2.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-02 15:10:37 +00:00
Bo Chen
46f0e0d14a ci: Increase rate-limiter worker timeout
The rate-limiter worker was moved to use small Azure VMs (#6731) and now
requires more time to complete.

Increasing its timeout to stablize this worker.

Signed-off-by: Bo Chen <bo.arvin.chen@gmail.com>
2024-12-02 15:11:24 +00:00
Ruoqing He
261bfac4d4 ci: Constrain FW_URL to x86_64 one
With 0.5.0 release of `rust-hypervisor-firmware`, `aarch64` binary were
added to assets, which causes the `FW_URL` to have multiple download url
separated by a white space, thus our integration tests would fail.

Constrain `FW_URL` to `hypervisor-fw` to resolve this.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-12-02 14:14:57 +00:00
dependabot[bot]
ec9b9ab542 build: Bump async-broadcast from 0.7.0 to 0.7.1
Bumps [async-broadcast](https://github.com/smol-rs/async-broadcast) from 0.7.0 to 0.7.1.
- [Release notes](https://github.com/smol-rs/async-broadcast/releases)
- [Changelog](https://github.com/smol-rs/async-broadcast/blob/master/CHANGELOG.md)
- [Commits](https://github.com/smol-rs/async-broadcast/compare/0.7.0...v0.7.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-29 16:10:28 +00:00
Julian Stecklina
8c9b34c9f1 docs: rewrite cross-host migration docs
The previous docs were very developer centric and have led several
people to believe that cross-machine migration is not supported at
all.

Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2024-11-29 15:42:23 +00:00
Julian Stecklina
5b822191c0 docs: apply style fixes to live migration docs
I've added newlines between paragraphs and code blocks for easier
reading. I've also changed the code blocks to use the correct
highlighting.

Signed-off-by: Julian Stecklina <julian.stecklina@cyberus-technology.de>
2024-11-29 15:42:23 +00:00
Ruoqing He
ab7b294688 misc: Replace map_or on false with is_some_and
Replace `map_or()` on false condition with `is_some_and` to provide
better readability, as suggestted by v1.84.0-beta.1 `cargo clippy`.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-29 12:44:33 +00:00
dependabot[bot]
7e419784cd build: Bump fastrand from 2.1.1 to 2.2.0
Bumps [fastrand](https://github.com/smol-rs/fastrand) from 2.1.1 to 2.2.0.
- [Release notes](https://github.com/smol-rs/fastrand/releases)
- [Changelog](https://github.com/smol-rs/fastrand/blob/master/CHANGELOG.md)
- [Commits](https://github.com/smol-rs/fastrand/compare/v2.1.1...v2.2.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-28 15:03:52 +00:00
dependabot[bot]
48bed965c0 build: Bump syn from 2.0.66 to 2.0.87
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.66 to 2.0.87.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.66...2.0.87)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-26 22:10:11 +00:00
Rob Bradford
0d6cef4521 pci: vfio: Release memory slots upon unmap
This prevents starvation of the limited set of memory slots in the
kernel.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2024-11-24 10:45:15 +00:00
Rob Bradford
81f8a27ef6 pci: vfio: Use MemorySlotAllocator for allocating memory slots
Adapt the existing code to replace the closure with the new of the new
MemorySlotAllocator.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2024-11-24 10:45:15 +00:00
Rob Bradford
e3bd5e9b35 vmm: memory_manager: Adapt for new MemorySlotAllocator
Adapt the existing code to transparently the MemorySlotAllocator. The
MemoryManager is the canonical holder of the these values with them
turned into a MemoryAllocator on demand.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2024-11-24 10:45:15 +00:00
Rob Bradford
80b2c98a68 vm-allocator: Add an allocator KVM memory slots
Add an allocator for KVM memory slots, a finite resource in the kernel
- these need to be manipulated across different crates with a common
dependency on this crate.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2024-11-24 10:45:15 +00:00
Ruoqing He
3c05626ad1 scripts: Replace download_linux with prepare_linux
`prepare_linux` is capable of determining whether we need to invoke
`build_custom_linux` for building linux from source or `download_linux`
for downloading pre-built.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-12 16:27:20 +00:00
Ruoqing He
906580ee92 scripts: Add prepare_linux function
`prepare_linux` checks if a `--build-guest-kernel` option is present,
and build kernel from `cloud-hypervisor/linux.git`. Otherwise, it will
invoke `download_linux` to use pre-built kernel.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-12 16:27:20 +00:00
dependabot[bot]
c6889388a3 build: Bump anstyle-parse from 0.2.3 to 0.2.6
Bumps [anstyle-parse](https://github.com/rust-cli/anstyle) from 0.2.3 to 0.2.6.
- [Commits](https://github.com/rust-cli/anstyle/compare/anstyle-parse-v0.2.3...anstyle-parse-v0.2.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-11 10:47:03 +00:00
Rob Bradford
f38fc94115 build: Increase ARM64 CI build timeouts
The builds are flaking due to reaching the timeouts.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2024-11-11 10:45:58 +00:00
dependabot[bot]
6ecca29aa6 build: Bump pkg-config from 0.3.30 to 0.3.31
Bumps [pkg-config](https://github.com/rust-lang/pkg-config-rs) from 0.3.30 to 0.3.31.
- [Changelog](https://github.com/rust-lang/pkg-config-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/pkg-config-rs/compare/0.3.30...0.3.31)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-08 00:50:27 +00:00
Rob Bradford
2ef04671be main: Place --tpm in the correct argument group
Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2024-11-08 00:12:23 +00:00
Rob Bradford
453bc31994 main: Require a payload to boot when any VM argument provided
If any VM argument (e.g. --disk) is provided require some payload (e.g.
--kernel or --firmware) when parsing the command line arguments.

See: #6831

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2024-11-08 00:12:23 +00:00
dependabot[bot]
6e6966df8f build: Bump xdg-home from 1.2.0 to 1.3.0
Bumps [xdg-home](https://github.com/zeenix/xdg-home) from 1.2.0 to 1.3.0.
- [Release notes](https://github.com/zeenix/xdg-home/releases)
- [Commits](https://github.com/zeenix/xdg-home/compare/1.2.0...1.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-07 09:23:49 +00:00
dependabot[bot]
f32c2638f6 build: Bump futures-core from 0.3.30 to 0.3.31
Bumps [futures-core](https://github.com/rust-lang/futures-rs) from 0.3.30 to 0.3.31.
- [Release notes](https://github.com/rust-lang/futures-rs/releases)
- [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.30...0.3.31)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-06 15:14:55 +00:00
Ruoqing He
fbe1cd6404 hypervisor: kvm: Add g/set_regs unit-test on riscv64
Add unit-test to make sure get_regs and set_regs on riscv64 architecture
work as expected, effectively avoiding typos in register names.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-06 14:32:39 +00:00
Ruoqing He
778a72f52f ci: Enable riscv64 CI of hypervisor module
Integrate machine provided by @ISRC-CAS to run build, clippy and
unit-test on hypervisor module.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-06 14:32:39 +00:00
Ruoqing He
76256230d6 hypervisor: kvm: Complement create_standard_regs
Complement `create_standard_regs` implementation on RISC-V platform to
work with `From` trait of `kvm_riscv_core`.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-06 14:32:39 +00:00
Ruoqing He
8cd80ea36b hypervisor: Introduce RISC-V architecture
Introduce cpu, vm, kvm, arch module RISC-V platform support. Add macro
definitions to implement methods interacting with RISC-V registers.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-06 14:32:39 +00:00
Ruoqing He
5e937c8b88 hypervisor: vm: Introduce RISC-V Vm trait
Introduce RISC-V specific Vm traits and error variant, disable
`create_irq_chip` on RISC-V platform.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-06 14:32:39 +00:00
Ruoqing He
710535343b hypervisor: cpu: Introduce RISC-V Vcpu trait
Add RISC-V specific Vcpu trait. Disable `set_guest_debug` on RISC-V
platform.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-06 14:32:39 +00:00
Ruoqing He
59c5b0a1cd hypervisor: kvm: Integrate riscv64 regs & AIA
Incorporates riscv64 register interaction and AIA creation to kvm
module. Complete `Vcpu` trait on RISC-V platform.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-06 14:32:39 +00:00
Ruoqing He
c13019d5b5 hypervisor: cpu: Introduce RISC-V specific error
Add error variants specific to RISC-V architecture.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-06 14:32:39 +00:00
Ruoqing He
c5774685f4 hypervisor: kvm: Introduce AIA creation
Implement definition required to work with KVM in-kernel AIA device,
construction procedure of AIA.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-06 14:32:39 +00:00
Ruoqing He
2df8d2fa1e hypervisor: kvm: Introduce riscv64 register g/set
Implement macros to calculate register ID on riscv64, definition of
RISC-V `VcpuKvmState`.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-06 14:32:39 +00:00
Ruoqing He
dd00bd6ef2 hypervisor: arch: Integrate riscv64 to arch module
Integrate `aia` module into `riscv64` module, and enable `riscv64`
module if target architecture is RISC-V 64-bit.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-06 14:32:39 +00:00
Ruoqing He
2752149bb0 hypervisor: arch: Introduce riscv64 AIA
Introduce definitions, traits relate to RISC-V AIA (Advanced Interrupt
Architecutre) construction.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-06 14:32:39 +00:00
Andrew Consroe
1bc74e43f8 docs: remove old --api-socket behavior
default --api-socket removed in 78f9ddc6be

Signed-off-by: Andrew Consroe <aconz2@gmail.com>
2024-11-06 08:33:27 +00:00
Wojtek Czekalski
8acaeb5c82 vmm: Add serial option to the disk config doc
Signed-off-by: Wojtek Czekalski <wczekalski@me.com>
2024-11-05 19:48:25 +00:00
dependabot[bot]
5eaf510f90 build: Bump async-trait from 0.1.80 to 0.1.83
Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.80 to 0.1.83.
- [Release notes](https://github.com/dtolnay/async-trait/releases)
- [Commits](https://github.com/dtolnay/async-trait/compare/0.1.80...0.1.83)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-05 15:44:55 +00:00
Rob Bradford
df1d6eaaee virtio-devices: Enable VIRTIO_RING_F_INDIRECT_DESC
This improves sequential write performance using fio (2888MiB/s ->
3293MiB/s)

VM config: cloud-hypervisor --disk path=~/workloads/jammy.raw,direct=on path=~/workloads/big-disk.img,direct=on --cpus boot=1 --memory size=2G,shared=on --serial tty --console off --seccomp log --kernel ~/workloads/hypervisor-fw

Host: fio --filename=big-disk.img --direct=1 --rw=write --bs=256k --ioengine=libaio --iodepth=64 --runtime=120 --numjobs=1 --time_based --group_reporting --name=throughput-test-job --eta-newline=1

VM:  fio --filename=/dev/vdb --direct=1 --rw=write --bs=256k --ioengine=libaio --iodepth=64 --runtime=120 --numjobs=1 --time_based --group_reporting --name=throughput-test-job --eta-newline=1

Baseline (file on filesystem on host used as backing store for block
device):

throughput-test-job: (groupid=0, jobs=1): err= 0: pid=10169: Tue Nov  5 09:31:55 2024
  write: IOPS=13.5k, BW=3385MiB/s (3549MB/s)(397GiB/120008msec); 0 zone resets
    slat (usec): min=4, max=10222, avg=20.25, stdev=29.01
    clat (usec): min=984, max=45599, avg=4706.01, stdev=2278.11
     lat (usec): min=1002, max=45610, avg=4726.27, stdev=2278.77
    clat percentiles (usec):
     |  1.00th=[ 3195],  5.00th=[ 3228], 10.00th=[ 3261], 20.00th=[ 3261],
     | 30.00th=[ 3261], 40.00th=[ 3261], 50.00th=[ 3294], 60.00th=[ 3916],
     | 70.00th=[ 5014], 80.00th=[ 7308], 90.00th=[ 7635], 95.00th=[ 7898],
     | 99.00th=[ 8586], 99.50th=[ 8979], 99.90th=[36439], 99.95th=[36963],
     | 99.99th=[43779]
   bw (  MiB/s): min= 1934, max= 4821, per=100.00%, avg=3391.67, stdev=1266.42, samples=239
   iops        : min= 7738, max=19286, avg=13566.67, stdev=5065.65, samples=239
  lat (usec)   : 1000=0.01%
  lat (msec)   : 2=0.03%, 4=61.10%, 10=38.62%, 20=0.11%, 50=0.15%
  cpu          : usr=17.13%, sys=14.38%, ctx=1352501, majf=0, minf=11
  IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, >=64=100.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.1%, >=64=0.0%
     issued rwts: total=0,1624829,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=64

Run status group 0 (all jobs):
  WRITE: bw=3385MiB/s (3549MB/s), 3385MiB/s-3385MiB/s (3549MB/s-3549MB/s), io=397GiB (426GB), run=120008-120008msec

Disk stats (read/write):
    dm-2: ios=129/1624787, sectors=1872/831364040, merge=0/0, ticks=185/6960387, in_queue=6960572, util=100.00%, aggrios=130/1626025, aggsectors=1880/831915888, aggrmerge=0/0, aggrticks=194/6967818, aggrin_queue=6968012, aggrutil=99.97%
    dm-0: ios=130/1626025, sectors=1880/831915888, merge=0/0, ticks=194/6967818, in_queue=6968012, util=99.97%, aggrios=130/1606095, aggsectors=1880/831915888, aggrmerge=0/19930, aggrticks=204/6634488, aggrin_queue=6635288, aggrutil=58.59%
  nvme0n1: ios=130/1606095, sectors=1880/831915888, merge=0/19930, ticks=204/6634488, in_queue=6635288, util=58.59%

On block device in VM:

throughput-test-job: (groupid=0, jobs=1): err= 0: pid=667: Tue Nov  5 09:53:19 2024
  write: IOPS=13.2k, BW=3293MiB/s (3453MB/s)(386GiB/120008msec); 0 zone resets
    slat (usec): min=4, max=3518, avg=27.77, stdev=35.32
    clat (usec): min=723, max=44252, avg=4829.82, stdev=2222.41
     lat (usec): min=735, max=44270, avg=4857.85, stdev=2223.45
    clat percentiles (usec):
     |  1.00th=[ 3097],  5.00th=[ 3195], 10.00th=[ 3195], 20.00th=[ 3228],
     | 30.00th=[ 3261], 40.00th=[ 3294], 50.00th=[ 3621], 60.00th=[ 4555],
     | 70.00th=[ 5997], 80.00th=[ 7242], 90.00th=[ 7570], 95.00th=[ 7898],
     | 99.00th=[ 8586], 99.50th=[ 8848], 99.90th=[36439], 99.95th=[36963],
     | 99.99th=[40633]
   bw (  MiB/s): min= 1914, max= 4857, per=100.00%, avg=3299.46, stdev=1180.81, samples=239
   iops        : min= 7658, max=19430, avg=13197.77, stdev=4723.22, samples=239
  lat (usec)   : 750=0.01%, 1000=0.01%
  lat (msec)   : 2=0.01%, 4=52.79%, 10=46.95%, 20=0.10%, 50=0.14%
  cpu          : usr=25.95%, sys=16.71%, ctx=1111821, majf=0, minf=10
  IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, >=64=100.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.1%, >=64=0.0%
     issued rwts: total=0,1580693,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=64

Run status group 0 (all jobs):
  WRITE: bw=3293MiB/s (3453MB/s), 3293MiB/s-3293MiB/s (3453MB/s-3453MB/s), io=386GiB (414GB), run=120008-120008msec

Disk stats (read/write):
  vdb: ios=60/1953213, merge=0/0, ticks=14/8229134, in_queue=8229149, util=100.00%

Prior to change:

throughput-test-job: (groupid=0, jobs=1): err= 0: pid=667: Tue Nov  5 09:37:45 2024
  write: IOPS=11.6k, BW=2888MiB/s (3028MB/s)(338GiB/120008msec); 0 zone resets
    slat (usec): min=3, max=3200, avg=18.48, stdev=24.54
    clat (usec): min=1237, max=46575, avg=5521.41, stdev=2641.99
     lat (usec): min=1249, max=46591, avg=5540.06, stdev=2643.54
    clat percentiles (usec):
     |  1.00th=[ 2999],  5.00th=[ 3163], 10.00th=[ 3195], 20.00th=[ 3261],
     | 30.00th=[ 3294], 40.00th=[ 3359], 50.00th=[ 6063], 60.00th=[ 7111],
     | 70.00th=[ 7373], 80.00th=[ 7570], 90.00th=[ 7832], 95.00th=[ 8094],
     | 99.00th=[ 8717], 99.50th=[ 9241], 99.90th=[36963], 99.95th=[37487],
     | 99.99th=[41157]
   bw (  MiB/s): min= 1936, max= 4826, per=100.00%, avg=2892.43, stdev=1202.99, samples=239
   iops        : min= 7746, max=19306, avg=11569.68, stdev=4811.98, samples=239
  lat (msec)   : 2=0.01%, 4=46.26%, 10=53.38%, 20=0.09%, 50=0.26%
  cpu          : usr=14.20%, sys=8.59%, ctx=1246257, majf=0, minf=12
  IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, >=64=100.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.1%, >=64=0.0%
     issued rwts: total=0,1386102,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=64

Run status group 0 (all jobs):
  WRITE: bw=2888MiB/s (3028MB/s), 2888MiB/s-2888MiB/s (3028MB/s-3028MB/s), io=338GiB (363GB), run=120008-120008msec

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2024-11-05 15:44:41 +00:00
Ruoqing He
a6a3d247da ci: Enable consistency check for fuzz workspace
`fuzz` is a separate workspace, enable consistency check on rust-vmm
crates in `fuzz` to keep stuffs in sync with root workspace.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-04 11:08:29 +00:00
Ruoqing He
838a857311 hypervisor: Wrap get_device_attr with unsafe
`get_device_attr` in 0.19.0 kvm-ioctls is marked as unsafe, wrap
invokation of `get_device_attr` with `unsafe` block.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-04 11:08:29 +00:00
Ruoqing He
95229b24ab build: Bump rust-vmm crates
- Bump kvm-bindings from 0.9.1 to 0.10.0
- Bump kvm-ioctls from 0.18.0 to 0.19.0
- Bump vm-memory from 0.15.0 to 0.16.0
- Bump linux-loader from 0.12.0 to 0.13.0
- Bump virtio-bindings from 0.2.1 to 0.2.4
- Bump virtio-queue from 0.13.0 to 0.14.0
- Pin mshv-bindings to 0.3.1
- Pin mshv-ioctls to 0.3.1
- Pin vhost to rev "d983ae0"
- Pin vhost-user-backend to rev "d983ae0"

Since vhost 0.12.0 and vhost-user-backend 0.16.0 are going to be yanked,
temporarily pin these two to "d983ae0", which are expected to be
replaced by 0.13.0 vhost and 0.17.0 vhost-user-backend after released.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-04 11:08:29 +00:00
Ruoqing He
71b0eb3c21 ci: Enable consistency check for rust-vmm packages
Enable `package-consistency` check to prevent contributor or dependabot
accidentally break `rust-vmm` consistency.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-02 16:09:09 +00:00
Ruoqing He
337cbf3d33 scripts: Add consistency check script
Add `package-consistency-check.py` script to prevent #6809 and #6815
from happening. This script takes a string present in the repository
field of packages to identify pacakges from a specific source.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-02 16:09:09 +00:00
dependabot[bot]
675140f627 build: Bump lock_api from 0.4.11 to 0.4.12
Bumps [lock_api](https://github.com/Amanieu/parking_lot) from 0.4.11 to 0.4.12.
- [Changelog](https://github.com/Amanieu/parking_lot/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Amanieu/parking_lot/compare/lock_api-0.4.11...lock_api-0.4.12)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-02 10:14:51 +00:00
Ruoqing He
894a4dee6e build: Centralize vhost-user-backend to workspace
`vhost-user-backend` is left behind in #6764, move it to root workspace.

Signed-off-by: Ruoqing He <heruoqing@iscas.ac.cn>
2024-11-02 08:08:51 +00:00
Rob Bradford
f57d00cd66 build: Revert "build: Bump vfio_user from bf7d7e8 to 3febcdd"
This reverts commit 39ab10244b.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2024-11-02 08:57:36 +00:00
dependabot[bot]
59a1719b6e build: Bump flume from 0.11.0 to 0.11.1
Bumps [flume](https://github.com/zesterer/flume) from 0.11.0 to 0.11.1.
- [Changelog](https://github.com/zesterer/flume/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zesterer/flume/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-30 00:41:24 +00:00
dependabot[bot]
39ab10244b build: Bump vfio_user from bf7d7e8 to 3febcdd
Bumps [vfio_user](https://github.com/rust-vmm/vfio-user) from `bf7d7e8` to `3febcdd`.
- [Commits](bf7d7e851b...3febcdd3fa)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-29 00:35:41 +00:00
dependabot[bot]
b5d856b31a build: Bump pin-project-lite from 0.2.14 to 0.2.15
Bumps [pin-project-lite](https://github.com/taiki-e/pin-project-lite) from 0.2.14 to 0.2.15.
- [Release notes](https://github.com/taiki-e/pin-project-lite/releases)
- [Changelog](https://github.com/taiki-e/pin-project-lite/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/pin-project-lite/compare/v0.2.14...v0.2.15)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-26 00:01:51 +00:00
227 changed files with 9990 additions and 10330 deletions

View File

@@ -15,7 +15,7 @@ jobs:
- stable
- beta
- nightly
- "1.77.0"
- "1.83.0"
target:
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl

View File

@@ -21,13 +21,13 @@ jobs:
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Login to ghcr
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -36,17 +36,17 @@ jobs:
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# generate Docker tags based on the following events/attributes
tags: |
type=raw,value=20241022-0
type=raw,value=20250412-0
type=sha
- name: Build and push
if: ${{ github.event_name == 'push' }}
uses: docker/build-push-action@v2
uses: docker/build-push-action@v6
with:
file: ./resources/Dockerfile
platforms: linux/amd64,linux/arm64
@@ -55,7 +55,7 @@ jobs:
- name: Build only
if: ${{ github.event_name == 'pull_request' }}
uses: docker/build-push-action@v2
uses: docker/build-push-action@v6
with:
file: ./resources/Dockerfile
platforms: linux/amd64,linux/arm64

View File

@@ -6,7 +6,7 @@ concurrency:
jobs:
build:
timeout-minutes: 60
timeout-minutes: 120
name: Tests (ARM64)
runs-on: bookworm-arm64
steps:
@@ -21,7 +21,7 @@ jobs:
- name: Load openvswitch module
run: sudo modprobe openvswitch
- name: Run integration tests (musl)
timeout-minutes: 30
timeout-minutes: 60
run: scripts/dev_cli.sh tests --integration --libc musl
- name: Install Azure CLI
if: ${{ github.event_name != 'pull_request' }}

View File

@@ -7,7 +7,7 @@ on:
jobs:
build:
name: Tests (Metrics)
runs-on: garm-jammy-16
runs-on: bare-metal-9950x
env:
METRICS_PUBLISH_KEY: ${{ secrets.METRICS_PUBLISH_KEY }}
steps:
@@ -15,15 +15,6 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Docker
run: |
sudo apt-get update
sudo apt-get -y install ca-certificates curl gnupg
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
sudo chmod a+r /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt install -y docker-ce docker-ce-cli
- name: Run metrics tests
timeout-minutes: 60
run: scripts/dev_cli.sh tests --metrics -- -- --report-file /root/workloads/metrics.json

View File

@@ -7,7 +7,7 @@ concurrency:
jobs:
build:
name: Tests (Rate-Limiter)
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'garm-jammy-16' }}
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || 'bare-metal-9950x' }}
env:
AUTH_DOWNLOAD_TOKEN: ${{ secrets.AUTH_DOWNLOAD_TOKEN }}
steps:
@@ -16,19 +16,9 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Docker
if: ${{ github.event_name != 'pull_request' }}
run: |
sudo apt-get update
sudo apt-get -y install ca-certificates curl gnupg
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
sudo chmod a+r /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt install -y docker-ce docker-ce-cli
- name: Run rate-limiter integration tests
if: ${{ github.event_name != 'pull_request' }}
timeout-minutes: 10
timeout-minutes: 20
run: scripts/dev_cli.sh tests --integration-rate-limiter
- name: Skipping build for PR
if: ${{ github.event_name == 'pull_request' }}

16
.github/workflows/lychee.yaml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: Link Check (lychee)
on:
pull_request
jobs:
link_check:
name: Link Check
runs-on: ubuntu-latest
steps:
- name: Code checkout
uses: actions/checkout@v4
- name: Link Availability Check
uses: lycheeverse/lychee-action@master
with:
args: --verbose --config .lychee.toml .

View File

@@ -0,0 +1,32 @@
name: Cloud Hypervisor Consistency
on: [pull_request, merge_group]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: Rust VMM Consistency Check
runs-on: ubuntu-latest
steps:
- name: Code checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install dependencies
run: sudo apt install -y python3
- name: Install Rust toolchain stable
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: Check Rust VMM Package Consistency of root Workspace
run: python3 scripts/package-consistency-check.py github.com/rust-vmm
- name: Check Rust VMM Package Consistency of fuzz Workspace
run: |
pushd fuzz
python3 ../scripts/package-consistency-check.py github.com/rust-vmm
popd

39
.github/workflows/preview-riscv64.yaml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: Cloud Hypervisor RISC-V 64-bit Preview
on: [pull_request, merge_group]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: Cargo
runs-on: riscv64-qemu-host
strategy:
fail-fast: false
matrix:
module:
- hypervisor
- arch
- vm-allocator
- devices
steps:
- name: Code checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Rust toolchain
run: /opt/scripts/exec-in-qemu.sh rustup default 1.83.0
- name: Build ${{ matrix.module }} Module (kvm)
run: /opt/scripts/exec-in-qemu.sh cargo rustc --locked -p ${{ matrix.module }} --no-default-features --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Clippy ${{ matrix.module }} Module (kvm)
run: /opt/scripts/exec-in-qemu.sh cargo clippy --locked -p ${{ matrix.module }} --no-default-features --features "kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks -W clippy::assertions_on_result_states
- name: Test ${{ matrix.module }} Module (kvm)
run: /opt/scripts/exec-in-qemu.sh cargo test --locked -p ${{ matrix.module }} --no-default-features --features "kvm"
- name: Check no files were modified
run: test -z "$(git status --porcelain)"

View File

@@ -56,6 +56,20 @@ jobs:
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
- name: Clippy (mshv)
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 --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
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
- name: Clippy (default features)
uses: actions-rs/cargo@v1
with:

View File

@@ -45,7 +45,7 @@ jobs:
target: ${{ matrix.platform.target }}
args: ${{ matrix.platform.args }}
strip: true
toolchain: "1.77.0"
toolchain: "1.83.0"
- name: Copy Release Binaries
if: github.event_name == 'create' && github.event.ref_type == 'tag'
shell: bash
@@ -54,7 +54,7 @@ jobs:
cp target/${{ matrix.platform.target }}/release/ch-remote ./${{ matrix.platform.name_ch_remote }}
- name: Upload Release Artifacts
if: github.event_name == 'create' && github.event.ref_type == 'tag'
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Artifacts for ${{ matrix.platform.target }}
path: |
@@ -80,7 +80,7 @@ jobs:
github.event_name == 'create' && github.event.ref_type == 'tag' &&
matrix.platform.target == 'x86_64-unknown-linux-gnu'
id: upload-release-cloud-hypervisor-vendored-sources
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
path: cloud-hypervisor-${{ github.event.ref }}.tar.xz
name: cloud-hypervisor-${{ github.event.ref }}.tar.xz

View File

@@ -1,6 +1,7 @@
[general]
extra-path=scripts/gitlint/rules.py
extra-path=scripts/gitlint/rules
regex-style-search=true
ignore=body-max-line-length
[ignore-by-author-name]
regex=dependabot
@@ -10,6 +11,3 @@ ignore=all
[title-max-length]
line-length=72
# default 80
[body-max-line-length]
line-length=72

21
.lychee.toml Normal file
View File

@@ -0,0 +1,21 @@
verbose = "info"
exclude = [
# Availability of links below should be manually verified.
# Page for intel SGX support, returns 403 while querying.
'^https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/linux-overview.html',
# Page for intel TDX support, returns 403 while querying.
'^https://www.intel.com/content/www/us/en/developer/tools/trust-domain-extensions/overview.html',
# Page for TPM, returns 403 while querying.
'^https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p05p_r14_pub.pdf',
# GitHub user smibarber referenced in `CREDITS.md` no longer exist
'^https://github.com/smibarber',
# OSDev has added bot protection and accesses my result in 403 Forbidden.
'^https://wiki.osdev.org',
]
max_retries = 3
retry_wait_time = 5

View File

@@ -15,6 +15,7 @@ EXTINT = "EXTINT"
INOUT = "INOUT"
liness = "liness"
outout = "outout"
TRANSLATER = "TRANSLATER"
[default.extend-identifiers]
fo = "fo"

View File

@@ -13,7 +13,7 @@ License](https://opensource.org/licenses/Apache-2.0).
## Coding Style
We follow the [Rust Style](https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/guide.md)
We follow the [Rust Style](https://github.com/rust-lang/rust/tree/HEAD/src/doc/style-guide/src)
convention and enforce it through the Continuous Integration (CI) process calling into `rustfmt`
for each submitted Pull Request (PR).
@@ -36,7 +36,7 @@ commit you make.
## Certificate of Origin
In order to get a clear contribution chain of trust we use the [signed-off-by language](https://01.org/community/signed-process)
In order to get a clear contribution chain of trust we use the [signed-off-by language](https://web.archive.org/web/20230406041855/https://01.org/community/signed-process)
used by the Linux kernel project.
## Patch format
@@ -79,12 +79,12 @@ you want to merge your changes to `cloud-hypervisor`:
1. Fork the [cloud-hypervisor](https://github.com/cloud-hypervisor/cloud-hypervisor) project
into your github organization.
2. Within your fork, create a branch for your contribution.
3. [Create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)
1. Within your fork, create a branch for your contribution.
1. [Create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)
against the main branch of the Cloud Hypervisor repository.
4. To update your pull request amend existing commits whenever applicable and
1. To update your pull request amend existing commits whenever applicable and
then push the new changes to your pull request branch.
5. Once the pull request is approved it can be integrated.
1. Once the pull request is approved it can be integrated.
## Issue tracking

603
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,15 +7,15 @@ edition = "2021"
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
license = "Apache-2.0 AND BSD-3-Clause"
name = "cloud-hypervisor"
version = "42.0.0"
version = "46.0.0"
# Minimum buildable version:
# Keep in sync with version in .github/workflows/build.yaml
# Policy on MSRV (see #4318):
# Can only be bumped by:
# Can only be bumped if satisfying any of the following:
# a.) A dependency requires it,
# b.) If we want to use a new feature and that MSRV is at least 6 months old,
# c.) There is a security issue that is addressed by the toolchain update.
rust-version = "1.77.0"
rust-version = "1.83.0"
[profile.release]
codegen-units = 1
@@ -29,20 +29,20 @@ inherits = "release"
strip = false
[dependencies]
anyhow = "1.0.87"
anyhow = "1.0.94"
api_client = { path = "api_client" }
clap = { version = "4.5.13", features = ["string"] }
dhat = { version = "0.3.3", optional = true }
epoll = "4.3.3"
event_monitor = { path = "event_monitor" }
hypervisor = { path = "hypervisor" }
libc = "0.2.158"
libc = "0.2.167"
log = { version = "0.4.22", features = ["std"] }
option_parser = { path = "option_parser" }
seccompiler = { workspace = true }
serde_json = "1.0.120"
signal-hook = "0.3.17"
thiserror = "1.0.62"
serde_json = { workspace = true }
signal-hook = "0.3.18"
thiserror = "2.0.6"
tpm = { path = "tpm" }
tracer = { path = "tracer" }
vm-memory = { workspace = true }
@@ -51,10 +51,10 @@ vmm-sys-util = { workspace = true }
zbus = { version = "4.4.0", optional = true }
[dev-dependencies]
dirs = "5.0.1"
dirs = "6.0.0"
net_util = { path = "net_util" }
once_cell = "1.20.2"
serde_json = "1.0.120"
serde_json = { workspace = true }
test_infra = { path = "test_infra" }
wait-timeout = "0.2.0"
@@ -102,19 +102,29 @@ members = [
]
[workspace.dependencies]
# rust-vmm crates
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
kvm-bindings = "0.9.1"
kvm-ioctls = "0.18.0"
linux-loader = "0.12.0"
mshv-bindings = { git = "https://github.com/rust-vmm/mshv", tag = "v0.3.0" }
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", tag = "v0.3.0" }
seccompiler = "0.4.0"
kvm-bindings = "0.10.0"
kvm-ioctls = "0.19.1"
linux-loader = "0.13.0"
mshv-bindings = "0.5.1"
mshv-ioctls = "0.5.1"
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 = "0.12.0"
virtio-bindings = "0.2.2"
virtio-queue = "0.13.0"
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"
vm-fdt = { git = "https://github.com/rust-vmm/vm-fdt", branch = "main" }
vm-memory = "0.15.0"
vm-memory = "0.16.1"
vmm-sys-util = "0.12.1"
# igvm crates
# TODO: bump to 0.3.5 release
igvm = { git = "https://github.com/microsoft/igvm", branch = "main" }
igvm_defs = { git = "https://github.com/microsoft/igvm", branch = "main" }
# serde crates
serde_json = "1.0.120"

View File

@@ -59,9 +59,13 @@ based on the [Rust VMM](https://github.com/rust-vmm) crates.
### Architectures
Cloud Hypervisor supports the `x86-64` and `AArch64` architectures. There are
minor differences in functionality between the two architectures
(see [#1125](https://github.com/cloud-hypervisor/cloud-hypervisor/issues/1125)).
Cloud Hypervisor supports the `x86-64`, `AArch64` and `riscv64`
architectures, with functionality varying across these platforms. The
functionality differences between `x86-64` and `AArch64` are documented
in [#1125](https://github.com/cloud-hypervisor/cloud-hypervisor/issues/1125).
The `riscv64` architecture support is experimental and offers limited
functionality. For more details and instructions, please refer to [riscv
documentation](docs/riscv.md).
### Guest OS
@@ -181,14 +185,9 @@ To build the kernel:
```shell
# Clone the Cloud Hypervisor Linux branch
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-6.2 linux-cloud-hypervisor
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-6.12.8 linux-cloud-hypervisor
$ pushd linux-cloud-hypervisor
# Use the x86-64 cloud-hypervisor kernel config to build your kernel for x86-64
$ wget https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/main/resources/linux-config-x86_64
# Use the AArch64 cloud-hypervisor kernel config to build your kernel for AArch64
$ wget https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/main/resources/linux-config-aarch64
$ cp linux-config-x86_64 .config # x86-64
$ cp linux-config-aarch64 .config # AArch64
$ make ch_defconfig
# Do native build of the x86-64 kernel
$ KCFLAGS="-Wa,-mx86-used-note=no" make bzImage -j `nproc`
# Do native build of the AArch64 kernel
@@ -302,8 +301,9 @@ Further details can be found in the [release documentation](docs/releases.md).
As of 2023-01-03, the following cloud images are supported:
- [Ubuntu Focal](https://cloud-images.ubuntu.com/focal/current/) (focal-server-cloudimg-{amd64,arm64}.img)
- [Ubuntu Jammy](https://cloud-images.ubuntu.com/jammy/current/) (jammy-server-cloudimg-{amd64,arm64}.img )
- [Fedora 36](https://fedora.mirrorservice.org/fedora/linux/releases/36/Cloud/) ([Fedora-Cloud-Base-36-1.5.x86_64.raw.xz](https://fedora.mirrorservice.org/fedora/linux/releases/36/Cloud/x86_64/images/) / [Fedora-Cloud-Base-36-1.5.aarch64.raw.xz](https://fedora.mirrorservice.org/fedora/linux/releases/36/Cloud/aarch64/images/))
- [Ubuntu Jammy](https://cloud-images.ubuntu.com/jammy/current/) (jammy-server-cloudimg-{amd64,arm64}.img)
- [Ubuntu Noble](https://cloud-images.ubuntu.com/noble/current/) (noble-server-cloudimg-{amd64,arm64}.img)
- [Fedora 36](https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/36/Cloud/) ([Fedora-Cloud-Base-36-1.5.x86_64.raw.xz](https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/36/Cloud/x86_64/images/) / [Fedora-Cloud-Base-36-1.5.aarch64.raw.xz](https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/36/Cloud/aarch64/images/))
Direct kernel boot to userspace should work with a rootfs from most
distributions although you may need to enable exotic filesystem types in the

View File

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

View File

@@ -12,15 +12,15 @@ use vmm_sys_util::sock_ctrl_msg::ScmSocket;
#[derive(Debug, Error)]
pub enum Error {
#[error("Error writing to or reading from HTTP socket: {0}")]
Socket(std::io::Error),
Socket(#[source] std::io::Error),
#[error("Error sending file descriptors: {0}")]
SocketSendFds(vmm_sys_util::errno::Error),
SocketSendFds(#[source] vmm_sys_util::errno::Error),
#[error("Error parsing HTTP status code: {0}")]
StatusCodeParsing(std::num::ParseIntError),
StatusCodeParsing(#[source] std::num::ParseIntError),
#[error("HTTP output is missing protocol statement")]
MissingProtocol,
#[error("Error parsing HTTP Content-Length field: {0}")]
ContentLengthParsing(std::num::ParseIntError),
ContentLengthParsing(#[source] std::num::ParseIntError),
#[error("Server responded with an error: {0:?}: {1:?}")]
ServerResponse(StatusCode, Option<String>),
}
@@ -32,6 +32,7 @@ pub enum StatusCode {
NoContent,
BadRequest,
NotFound,
TooManyRequests,
InternalServerError,
NotImplemented,
Unknown,
@@ -45,6 +46,7 @@ impl StatusCode {
204 => StatusCode::NoContent,
400 => StatusCode::BadRequest,
404 => StatusCode::NotFound,
429 => StatusCode::TooManyRequests,
500 => StatusCode::InternalServerError,
501 => StatusCode::NotImplemented,
_ => StatusCode::Unknown,

View File

@@ -11,19 +11,19 @@ sev_snp = []
tdx = []
[dependencies]
anyhow = "1.0.87"
anyhow = "1.0.94"
byteorder = "1.5.0"
hypervisor = { path = "../hypervisor" }
libc = "0.2.158"
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 = "1.0.62"
uuid = "1.8.0"
thiserror = "2.0.6"
uuid = "1.12.1"
vm-memory = { workspace = true, features = ["backend-bitmap", "backend-mmap"] }
vm-migration = { path = "../vm-migration" }
vmm-sys-util = { workspace = true, features = ["with-serde"] }
[target.'cfg(target_arch = "aarch64")'.dependencies]
[target.'cfg(any(target_arch = "aarch64", target_arch = "riscv64"))'.dependencies]
fdt_parser = { version = "0.1.5", package = "fdt" }
vm-fdt = { workspace = true }

View File

@@ -15,14 +15,18 @@ use std::{cmp, fs, result, str};
use byteorder::{BigEndian, ByteOrder};
use hypervisor::arch::aarch64::gic::Vgic;
use hypervisor::arch::aarch64::regs::{
AARCH64_ARCH_TIMER_HYP_IRQ, AARCH64_ARCH_TIMER_PHYS_NONSECURE_IRQ,
AARCH64_ARCH_TIMER_PHYS_SECURE_IRQ, AARCH64_ARCH_TIMER_VIRT_IRQ, AARCH64_PMU_IRQ,
};
use thiserror::Error;
use vm_fdt::{FdtWriter, FdtWriterResult};
use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError, GuestMemoryRegion};
use super::super::{DeviceType, GuestMemoryMmap, InitramfsConfig};
use super::layout::{
IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START,
PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
GIC_V2M_COMPATIBLE, IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE,
MEM_PCI_IO_START, PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT, SPI_BASE, SPI_NUM,
};
use crate::{NumaNodes, PciSpaceInfo};
@@ -59,9 +63,6 @@ const GIC_FDT_IRQ_TYPE_PPI: u32 = 1;
const IRQ_TYPE_EDGE_RISING: u32 = 1;
const IRQ_TYPE_LEVEL_HI: u32 = 4;
// PMU PPI interrupt number
pub const AARCH64_PMU_IRQ: u32 = 7;
// Keys and Buttons
// System Power Down
const KEY_POWER: u32 = 116;
@@ -81,7 +82,7 @@ pub trait DeviceInfoForFdt {
pub enum Error {
/// Failure in writing FDT in memory.
#[error("Failure in writing FDT in memory: {0}")]
WriteFdtToMemory(GuestMemoryError),
WriteFdtToMemory(#[source] GuestMemoryError),
}
type Result<T> = result::Result<T, Error>;
@@ -585,15 +586,14 @@ fn create_memory_node(
&& (first_region_end <= &mem_32bit_reserved_start))
{
panic!(
"Unexpected first memory region layout: (start: 0x{:08x}, end: 0x{:08x}).
ram_start: 0x{:08x}, mem_32bit_reserved_start: 0x{:08x}",
first_region_start, first_region_end, ram_start, mem_32bit_reserved_start
"Unexpected first memory region layout: (start: 0x{first_region_start:08x}, end: 0x{first_region_end:08x}).
ram_start: 0x{ram_start:08x}, mem_32bit_reserved_start: 0x{mem_32bit_reserved_start:08x}"
);
}
let mem_size = first_region_end - ram_start;
let mem_reg_prop = [ram_start, mem_size];
let memory_node_name = format!("memory@{:x}", ram_start);
let memory_node_name = format!("memory@{ram_start:x}");
let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;
@@ -606,14 +606,13 @@ fn create_memory_node(
if second_region_start != &ram_64bit_start {
panic!(
"Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
second_region_start, ram_64bit_start
"Unexpected second memory region layout: start: 0x{second_region_start:08x}, ram_64bit_start: 0x{ram_64bit_start:08x}"
);
}
let mem_size = second_region_end - ram_64bit_start;
let mem_reg_prop = [ram_64bit_start, mem_size];
let memory_node_name = format!("memory@{:x}", ram_64bit_start);
let memory_node_name = format!("memory@{ram_64bit_start:x}");
let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;
@@ -670,11 +669,19 @@ fn create_gic_node(fdt: &mut FdtWriter, gic_device: &Arc<Mutex<dyn Vgic>>) -> Fd
if gic_device.lock().unwrap().msi_compatible() {
let msic_node = fdt.begin_node("msic")?;
fdt.property_string("compatible", gic_device.lock().unwrap().msi_compatibility())?;
let msi_compatibility = gic_device.lock().unwrap().msi_compatibility().to_string();
fdt.property_string("compatible", msi_compatibility.as_str())?;
fdt.property_null("msi-controller")?;
fdt.property_u32("phandle", MSI_PHANDLE)?;
let msi_reg_prop = gic_device.lock().unwrap().msi_properties();
fdt.property_array_u64("reg", &msi_reg_prop)?;
if msi_compatibility == GIC_V2M_COMPATIBLE {
fdt.property_u32("arm,msi-base-spi", SPI_BASE)?;
fdt.property_u32("arm,msi-num-spis", SPI_NUM)?;
}
fdt.end_node(msic_node)?;
}
@@ -701,9 +708,14 @@ fn create_clock_node(fdt: &mut FdtWriter) -> FdtWriterResult<()> {
fn create_timer_node(fdt: &mut FdtWriter) -> FdtWriterResult<()> {
// See
// https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/interrupt-controller/arch_timer.txt
// https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/timer/arm%2Carch_timer.yaml
// These are fixed interrupt numbers for the timer device.
let irqs = [13, 14, 11, 10];
let irqs = [
AARCH64_ARCH_TIMER_PHYS_SECURE_IRQ,
AARCH64_ARCH_TIMER_PHYS_NONSECURE_IRQ,
AARCH64_ARCH_TIMER_VIRT_IRQ,
AARCH64_ARCH_TIMER_HYP_IRQ,
];
let compatible = "arm,armv8-timer";
let mut timer_reg_cells: Vec<u32> = Vec::new();
@@ -1109,10 +1121,7 @@ fn print_node(node: fdt_parser::node::FdtNode<'_, '_>, n_spaces: usize) {
// - At first, try to convert it to CStr and print,
// - If failed, print it as u32 array.
let value_result = match CStr::from_bytes_with_nul(value) {
Ok(value_cstr) => match value_cstr.to_str() {
Ok(value_str) => Some(value_str),
Err(_e) => None,
},
Ok(value_cstr) => value_cstr.to_str().ok(),
Err(_e) => None,
};

View File

@@ -138,3 +138,12 @@ pub const IRQ_BASE: u32 = 32;
/// Number of supported interrupts
pub const IRQ_NUM: u32 = 256;
/// Base SPI interrupt number
pub const SPI_BASE: u32 = 32;
/// Total number of SPIs
pub const SPI_NUM: u32 = 64;
/// GICv2M compatible string
pub const GIC_V2M_COMPATIBLE: &str = "arm,gic-v2m-frame";

View File

@@ -6,8 +6,6 @@
pub mod fdt;
/// Layout for this aarch64 system.
pub mod layout;
/// Module for system registers definition
pub mod regs;
/// Module for loading UEFI binary.
pub mod uefi;
@@ -16,6 +14,7 @@ use std::fmt::Debug;
use std::sync::{Arc, Mutex};
use hypervisor::arch::aarch64::gic::Vgic;
use hypervisor::arch::aarch64::regs::MPIDR_EL1;
use log::{log_enabled, Level};
use thiserror::Error;
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic};
@@ -34,7 +33,7 @@ pub enum Error {
/// Failed to write FDT to memory.
#[error("Failed to write FDT to memory: {0}")]
WriteFdtToMemory(fdt::Error),
WriteFdtToMemory(#[source] fdt::Error),
/// Failed to create a GIC.
#[error("Failed to create a GIC")]
@@ -46,11 +45,11 @@ pub enum Error {
/// Error configuring the general purpose registers
#[error("Error configuring the general purpose registers: {0}")]
RegsConfiguration(hypervisor::HypervisorCpuError),
RegsConfiguration(#[source] hypervisor::HypervisorCpuError),
/// Error configuring the MPIDR register
#[error("Error configuring the MPIDR register: {0}")]
VcpuRegMpidr(hypervisor::HypervisorCpuError),
VcpuRegMpidr(#[source] hypervisor::HypervisorCpuError),
/// Error initializing PMU for vcpu
#[error("Error initializing PMU for vcpu")]
@@ -86,9 +85,7 @@ pub fn configure_vcpu(
.map_err(Error::RegsConfiguration)?;
}
let mpidr = vcpu
.get_sys_reg(regs::MPIDR_EL1)
.map_err(Error::VcpuRegMpidr)?;
let mpidr = vcpu.get_sys_reg(MPIDR_EL1).map_err(Error::VcpuRegMpidr)?;
Ok(mpidr)
}

View File

@@ -1,43 +0,0 @@
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
// SPDX-License-Identifier: Apache-2.0
// AArch64 system register encoding:
// See https://developer.arm.com/documentation/ddi0487 (chapter D12)
//
// 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
// +----------+---+-----+-----+-----+-----+-----+----+
// |1101010100| L | op0 | op1 | CRn | CRm | op2 | Rt |
// +----------+---+-----+-----+-----+-----+-----+----+
//
// Notes:
// - L and Rt are reserved as implementation defined fields, ignored.
const SYSREG_HEAD: u32 = 0b1101010100u32 << 22;
const SYSREG_OP0_SHIFT: u32 = 19;
const SYSREG_OP0_MASK: u32 = 0b11u32 << 19;
const SYSREG_OP1_SHIFT: u32 = 16;
const SYSREG_OP1_MASK: u32 = 0b111u32 << 16;
const SYSREG_CRN_SHIFT: u32 = 12;
const SYSREG_CRN_MASK: u32 = 0b1111u32 << 12;
const SYSREG_CRM_SHIFT: u32 = 8;
const SYSREG_CRM_MASK: u32 = 0b1111u32 << 8;
const SYSREG_OP2_SHIFT: u32 = 5;
const SYSREG_OP2_MASK: u32 = 0b111u32 << 5;
/// Define the ID of system registers
#[macro_export]
macro_rules! arm64_sys_reg {
($name: tt, $op0: tt, $op1: tt, $crn: tt, $crm: tt, $op2: tt) => {
pub const $name: u32 = SYSREG_HEAD
| ((($op0 as u32) << SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK as u32)
| ((($op1 as u32) << SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK as u32)
| ((($crn as u32) << SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK as u32)
| ((($crm as u32) << SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK as u32)
| ((($op2 as u32) << SYSREG_OP2_SHIFT) & SYSREG_OP2_MASK as u32);
};
}
arm64_sys_reg!(MPIDR_EL1, 3, 0, 0, 0, 5);
arm64_sys_reg!(ID_AA64MMFR0_EL1, 3, 0, 0, 7, 0);
arm64_sys_reg!(TTBR1_EL1, 3, 0, 2, 0, 1);
arm64_sys_reg!(TCR_EL1, 3, 0, 2, 0, 2);

View File

@@ -1,3 +1,4 @@
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
// Copyright © 2020, Oracle and/or its affiliates.
//
@@ -5,7 +6,7 @@
// SPDX-License-Identifier: Apache-2.0
//! Implements platform specific functionality.
//! Supported platforms: x86_64, aarch64.
//! Supported platforms: x86_64, aarch64, riscv64.
#[macro_use]
extern crate log;
@@ -27,11 +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(x86_64::Error),
#[error("Platform specific error (x86_64): {0}")]
PlatformSpecific(#[source] x86_64::Error),
#[cfg(target_arch = "aarch64")]
#[error("Platform specific error (aarch64): {0:?}")]
PlatformSpecific(aarch64::Error),
PlatformSpecific(#[source] aarch64::Error),
#[cfg(target_arch = "riscv64")]
#[error("Platform specific error (riscv64): {0:?}")]
PlatformSpecific(#[source] riscv64::Error),
#[error("The memory map table extends past the end of guest memory")]
MemmapTablePastRamEnd,
#[error("Error writing memory map table to guest memory")]
@@ -85,6 +89,17 @@ pub use aarch64::{
layout::IRQ_BASE, uefi, EntryPoint, _NSIG,
};
/// Module for riscv64 related functionality.
#[cfg(target_arch = "riscv64")]
pub mod riscv64;
#[cfg(target_arch = "riscv64")]
pub use riscv64::{
arch_memory_regions, configure_system, configure_vcpu, fdt::DeviceInfoForFdt,
get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
layout::IRQ_BASE, EntryPoint, _NSIG,
};
#[cfg(target_arch = "x86_64")]
pub mod x86_64;
@@ -132,7 +147,7 @@ pub enum DeviceType {
/// Device Type: Virtio.
Virtio(u32),
/// Device Type: Serial.
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
Serial,
/// Device Type: RTC.
#[cfg(target_arch = "aarch64")]
@@ -153,7 +168,7 @@ impl fmt::Display for DeviceType {
/// Structure to describe MMIO device information
#[derive(Clone, Debug)]
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
pub struct MmioDeviceInfo {
pub addr: u64,
pub len: u64,
@@ -162,7 +177,7 @@ pub struct MmioDeviceInfo {
/// Structure to describe PCI space information
#[derive(Clone, Debug)]
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
pub struct PciSpaceInfo {
pub pci_segment_id: u16,
pub mmio_config_address: u64,
@@ -170,7 +185,7 @@ pub struct PciSpaceInfo {
pub pci_device_space_size: u64,
}
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
impl DeviceInfoForFdt for MmioDeviceInfo {
fn addr(&self) -> u64 {
self.addr

484
arch/src/riscv64/fdt.rs Normal file
View File

@@ -0,0 +1,484 @@
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.
use std::collections::HashMap;
use std::ffi::CStr;
use std::fmt::Debug;
use std::sync::{Arc, Mutex};
use std::{cmp, result, str};
use byteorder::{BigEndian, ByteOrder};
use hypervisor::arch::riscv64::aia::Vaia;
use thiserror::Error;
use vm_fdt::{FdtWriter, FdtWriterResult};
use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError, GuestMemoryRegion};
use super::super::{DeviceType, GuestMemoryMmap, InitramfsConfig};
use super::layout::{
IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START,
PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
};
use crate::PciSpaceInfo;
const AIA_APLIC_PHANDLE: u32 = 1;
const AIA_IMSIC_PHANDLE: u32 = 2;
const CPU_INTC_BASE_PHANDLE: u32 = 3;
const CPU_BASE_PHANDLE: u32 = 256 + CPU_INTC_BASE_PHANDLE;
// Read the documentation specified when appending the root node to the FDT.
const ADDRESS_CELLS: u32 = 0x2;
const SIZE_CELLS: u32 = 0x2;
// From https://elixir.bootlin.com/linux/v6.10/source/include/dt-bindings/interrupt-controller/irq.h#L14
const _IRQ_TYPE_EDGE_RISING: u32 = 1;
const IRQ_TYPE_LEVEL_HI: u32 = 4;
const S_MODE_EXT_IRQ: u32 = 9;
/// Trait for devices to be added to the Flattened Device Tree.
pub trait DeviceInfoForFdt {
/// Returns the address where this device will be loaded.
fn addr(&self) -> u64;
/// Returns the associated interrupt for this device.
fn irq(&self) -> u32;
/// Returns the amount of memory that needs to be reserved for this device.
fn length(&self) -> u64;
}
/// Errors thrown while configuring the Flattened Device Tree for riscv64.
#[derive(Debug, Error)]
pub enum Error {
/// Failure in writing FDT in memory.
#[error("Failure in writing FDT in memory: {0}")]
WriteFdtToMemory(#[source] GuestMemoryError),
}
type Result<T> = result::Result<T, Error>;
/// Creates the flattened device tree for this riscv64 VM.
#[allow(clippy::too_many_arguments)]
pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
guest_mem: &GuestMemoryMmap,
cmdline: &str,
num_vcpu: u32,
device_info: &HashMap<(DeviceType, String), T, S>,
aia_device: &Arc<Mutex<dyn Vaia>>,
initrd: &Option<InitramfsConfig>,
pci_space_info: &[PciSpaceInfo],
) -> FdtWriterResult<Vec<u8>> {
// Allocate stuff necessary for the holding the blob.
let mut fdt = FdtWriter::new()?;
// For an explanation why these nodes were introduced in the blob take a look at
// https://github.com/devicetree-org/devicetree-specification/releases/tag/v0.4
// In chapter 3.
// Header or the root node as per above mentioned documentation.
let root_node = fdt.begin_node("")?;
fdt.property_string("compatible", "linux,dummy-virt")?;
// For info on #address-cells and size-cells resort to Table 3.1 Root Node
// Properties
fdt.property_u32("#address-cells", ADDRESS_CELLS)?;
fdt.property_u32("#size-cells", SIZE_CELLS)?;
create_cpu_nodes(&mut fdt, num_vcpu)?;
create_memory_node(&mut fdt, guest_mem)?;
create_chosen_node(&mut fdt, cmdline, initrd)?;
create_aia_node(&mut fdt, aia_device)?;
create_devices_node(&mut fdt, device_info)?;
create_pci_nodes(&mut fdt, pci_space_info)?;
// End Header node.
fdt.end_node(root_node)?;
let fdt_final = fdt.finish()?;
Ok(fdt_final)
}
pub fn write_fdt_to_memory(fdt_final: Vec<u8>, guest_mem: &GuestMemoryMmap) -> Result<()> {
// Write FDT to memory.
guest_mem
.write_slice(fdt_final.as_slice(), super::layout::FDT_START)
.map_err(Error::WriteFdtToMemory)?;
Ok(())
}
// Following are the auxiliary function for creating the different nodes that we append to our FDT.
fn create_cpu_nodes(fdt: &mut FdtWriter, num_cpus: u32) -> FdtWriterResult<()> {
// See https://elixir.bootlin.com/linux/v6.10/source/Documentation/devicetree/bindings/riscv/cpus.yaml
let cpus = fdt.begin_node("cpus")?;
// As per documentation, on RISC-V 64-bit systems value should be set to 1.
fdt.property_u32("#address-cells", 0x01)?;
fdt.property_u32("#size-cells", 0x0)?;
// TODO: Retrieve CPU frequency from cpu timer regs
let timebase_frequency: u32 = 0x989680;
fdt.property_u32("timebase-frequency", timebase_frequency)?;
for cpu_index in 0..num_cpus {
let cpu = fdt.begin_node(&format!("cpu@{:x}", cpu_index))?;
fdt.property_string("device_type", "cpu")?;
fdt.property_string("compatible", "riscv")?;
fdt.property_string("mmu-type", "sv48")?;
fdt.property_string("riscv,isa", "rv64imafdc_smaia_ssaia")?;
fdt.property_string("status", "okay")?;
fdt.property_u32("reg", cpu_index)?;
fdt.property_u32("phandle", CPU_BASE_PHANDLE + cpu_index)?;
// interrupt controller node
let intc_node = fdt.begin_node("interrupt-controller")?;
fdt.property_string("compatible", "riscv,cpu-intc")?;
fdt.property_u32("#interrupt-cells", 1u32)?;
fdt.property_null("interrupt-controller")?;
fdt.property_u32("phandle", CPU_INTC_BASE_PHANDLE + cpu_index)?;
fdt.end_node(intc_node)?;
fdt.end_node(cpu)?;
}
fdt.end_node(cpus)?;
Ok(())
}
fn create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemoryMmap) -> FdtWriterResult<()> {
// Note: memory regions from "GuestMemory" are sorted and non-zero sized.
let ram_regions = {
let mut ram_regions = Vec::new();
let mut current_start = guest_mem
.iter()
.next()
.map(GuestMemoryRegion::start_addr)
.expect("GuestMemory must have one memory region at least")
.raw_value();
let mut current_end = current_start;
for (start, size) in guest_mem
.iter()
.map(|m| (m.start_addr().raw_value(), m.len()))
{
if current_end == start {
// This zone is continuous with the previous one.
current_end += size;
} else {
ram_regions.push((current_start, current_end));
current_start = start;
current_end = start + size;
}
}
ram_regions.push((current_start, current_end));
ram_regions
};
let mut mem_reg_property = Vec::new();
for region in ram_regions {
let mem_size = region.1 - region.0;
mem_reg_property.push(region.0);
mem_reg_property.push(mem_size);
}
let ram_start = super::layout::RAM_START.raw_value();
let memory_node_name = format!("memory@{:x}", ram_start);
let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_property)?;
fdt.end_node(memory_node)?;
Ok(())
}
fn create_chosen_node(
fdt: &mut FdtWriter,
cmdline: &str,
initrd: &Option<InitramfsConfig>,
) -> FdtWriterResult<()> {
let chosen_node = fdt.begin_node("chosen")?;
fdt.property_string("bootargs", cmdline)?;
if let Some(initrd_config) = initrd {
let initrd_start = initrd_config.address.raw_value();
let initrd_end = initrd_config.address.raw_value() + initrd_config.size as u64;
fdt.property_u64("linux,initrd-start", initrd_start)?;
fdt.property_u64("linux,initrd-end", initrd_end)?;
}
fdt.end_node(chosen_node)?;
Ok(())
}
fn create_aia_node(fdt: &mut FdtWriter, aia_device: &Arc<Mutex<dyn Vaia>>) -> FdtWriterResult<()> {
// IMSIC
if aia_device.lock().unwrap().msi_compatible() {
use super::layout::IMSIC_START;
let imsic_name = format!("imsics@{:x}", IMSIC_START.0);
let imsic_node = fdt.begin_node(&imsic_name)?;
fdt.property_string(
"compatible",
aia_device.lock().unwrap().imsic_compatibility(),
)?;
let imsic_reg_prop = aia_device.lock().unwrap().imsic_properties();
fdt.property_array_u32("reg", &imsic_reg_prop)?;
fdt.property_u32("#interrupt-cells", 0u32)?;
fdt.property_null("interrupt-controller")?;
fdt.property_null("msi-controller")?;
// TODO complete num-ids
fdt.property_u32("riscv,num-ids", 2047u32)?;
fdt.property_u32("phandle", AIA_IMSIC_PHANDLE)?;
let mut irq_cells = Vec::new();
let num_cpus = aia_device.lock().unwrap().vcpu_count();
for i in 0..num_cpus {
irq_cells.push(CPU_INTC_BASE_PHANDLE + i);
irq_cells.push(S_MODE_EXT_IRQ);
}
fdt.property_array_u32("interrupts-extended", &irq_cells)?;
fdt.end_node(imsic_node)?;
}
// APLIC
use super::layout::APLIC_START;
let aplic_name = format!("aplic@{:x}", APLIC_START.0);
let aplic_node = fdt.begin_node(&aplic_name)?;
fdt.property_string(
"compatible",
aia_device.lock().unwrap().aplic_compatibility(),
)?;
let reg_cells = aia_device.lock().unwrap().aplic_properties();
fdt.property_array_u32("reg", &reg_cells)?;
fdt.property_u32("#interrupt-cells", 2u32)?;
fdt.property_null("interrupt-controller")?;
// TODO complete num-srcs
fdt.property_u32("riscv,num-sources", 96u32)?;
fdt.property_u32("phandle", AIA_APLIC_PHANDLE)?;
fdt.property_u32("msi-parent", AIA_IMSIC_PHANDLE)?;
fdt.end_node(aplic_node)?;
Ok(())
}
fn create_serial_node<T: DeviceInfoForFdt + Clone + Debug>(
fdt: &mut FdtWriter,
dev_info: &T,
) -> FdtWriterResult<()> {
let serial_reg_prop = [dev_info.addr(), dev_info.length()];
let irq = [dev_info.irq() - IRQ_BASE, IRQ_TYPE_LEVEL_HI];
let serial_node = fdt.begin_node(&format!("serial@{:x}", dev_info.addr()))?;
fdt.property_string("compatible", "ns16550a")?;
fdt.property_array_u64("reg", &serial_reg_prop)?;
fdt.property_u32("clock-frequency", 3686400)?;
fdt.property_u32("interrupt-parent", AIA_APLIC_PHANDLE)?;
fdt.property_array_u32("interrupts", &irq)?;
fdt.end_node(serial_node)?;
Ok(())
}
fn create_devices_node<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
fdt: &mut FdtWriter,
dev_info: &HashMap<(DeviceType, String), T, S>,
) -> FdtWriterResult<()> {
for ((device_type, _device_id), info) in dev_info {
match device_type {
DeviceType::Serial => create_serial_node(fdt, info)?,
DeviceType::Virtio(_) => unreachable!(),
}
}
Ok(())
}
fn create_pci_nodes(fdt: &mut FdtWriter, pci_device_info: &[PciSpaceInfo]) -> FdtWriterResult<()> {
// Add node for PCIe controller.
// See Documentation/devicetree/bindings/pci/host-generic-pci.txt in the kernel
// and https://elinux.org/Device_Tree_Usage.
// In multiple PCI segments setup, each PCI segment needs a PCI node.
for pci_device_info_elem in pci_device_info.iter() {
// EDK2 requires the PCIe high space above 4G address.
// The actual space in CLH follows the RAM. If the RAM space is small, the PCIe high space
// could fall below 4G.
// Here we cut off PCI device space below 8G in FDT to workaround the EDK2 check.
// But the address written in ACPI is not impacted.
let (pci_device_base_64bit, pci_device_size_64bit) =
if pci_device_info_elem.pci_device_space_start < PCI_HIGH_BASE.raw_value() {
(
PCI_HIGH_BASE.raw_value(),
pci_device_info_elem.pci_device_space_size
- (PCI_HIGH_BASE.raw_value() - pci_device_info_elem.pci_device_space_start),
)
} else {
(
pci_device_info_elem.pci_device_space_start,
pci_device_info_elem.pci_device_space_size,
)
};
// There is no specific requirement of the 32bit MMIO range, and
// therefore at least we can make these ranges 4K aligned.
let pci_device_size_32bit: u64 =
MEM_32BIT_DEVICES_SIZE / ((1 << 12) * pci_device_info.len() as u64) * (1 << 12);
let pci_device_base_32bit: u64 = MEM_32BIT_DEVICES_START.0
+ pci_device_size_32bit * pci_device_info_elem.pci_segment_id as u64;
let ranges = [
// io addresses. Since AArch64 will not use IO address,
// we can set the same IO address range for every segment.
0x1000000,
0_u32,
0_u32,
(MEM_PCI_IO_START.0 >> 32) as u32,
MEM_PCI_IO_START.0 as u32,
(MEM_PCI_IO_SIZE >> 32) as u32,
MEM_PCI_IO_SIZE as u32,
// mmio addresses
0x2000000, // (ss = 10: 32-bit memory space)
(pci_device_base_32bit >> 32) as u32, // PCI address
pci_device_base_32bit as u32,
(pci_device_base_32bit >> 32) as u32, // CPU address
pci_device_base_32bit as u32,
(pci_device_size_32bit >> 32) as u32, // size
pci_device_size_32bit as u32,
// device addresses
0x3000000, // (ss = 11: 64-bit memory space)
(pci_device_base_64bit >> 32) as u32, // PCI address
pci_device_base_64bit as u32,
(pci_device_base_64bit >> 32) as u32, // CPU address
pci_device_base_64bit as u32,
(pci_device_size_64bit >> 32) as u32, // size
pci_device_size_64bit as u32,
];
let bus_range = [0, 0]; // Only bus 0
let reg = [
pci_device_info_elem.mmio_config_address,
PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
];
// See kernel document Documentation/devicetree/bindings/pci/pci-msi.txt
let msi_map = [
// rid-base: A single cell describing the first RID matched by the entry.
0x0,
// msi-controller: A single phandle to an MSI controller.
AIA_IMSIC_PHANDLE,
// msi-base: An msi-specifier describing the msi-specifier produced for the
// first RID matched by the entry.
(pci_device_info_elem.pci_segment_id as u32) << 8,
// length: A single cell describing how many consecutive RIDs are matched
// following the rid-base.
0x100,
];
let pci_node_name = format!("pci@{:x}", pci_device_info_elem.mmio_config_address);
let pci_node = fdt.begin_node(&pci_node_name)?;
fdt.property_string("compatible", "pci-host-ecam-generic")?;
fdt.property_string("device_type", "pci")?;
fdt.property_array_u32("ranges", &ranges)?;
fdt.property_array_u32("bus-range", &bus_range)?;
fdt.property_u32(
"linux,pci-domain",
pci_device_info_elem.pci_segment_id as u32,
)?;
fdt.property_u32("#address-cells", 3)?;
fdt.property_u32("#size-cells", 2)?;
fdt.property_array_u64("reg", &reg)?;
fdt.property_u32("#interrupt-cells", 1)?;
fdt.property_null("interrupt-map")?;
fdt.property_null("interrupt-map-mask")?;
fdt.property_null("dma-coherent")?;
fdt.property_array_u32("msi-map", &msi_map)?;
fdt.property_u32("msi-parent", AIA_IMSIC_PHANDLE)?;
fdt.end_node(pci_node)?;
}
Ok(())
}
// Parse the DTB binary and print for debugging
pub fn print_fdt(dtb: &[u8]) {
match fdt_parser::Fdt::new(dtb) {
Ok(fdt) => {
if let Some(root) = fdt.find_node("/") {
debug!("Printing the FDT:");
print_node(root, 0);
} else {
debug!("Failed to find root node in FDT for debugging.");
}
}
Err(_) => debug!("Failed to parse FDT for debugging."),
}
}
fn print_node(node: fdt_parser::node::FdtNode<'_, '_>, n_spaces: usize) {
debug!("{:indent$}{}/", "", node.name, indent = n_spaces);
for property in node.properties() {
let name = property.name;
// If the property is 'compatible', its value requires special handling.
// The u8 array could contain multiple null-terminated strings.
// We copy the original array and simply replace all 'null' characters with spaces.
let value = if name == "compatible" {
let mut compatible = vec![0u8; 256];
let handled_value = property
.value
.iter()
.map(|&c| if c == 0 { b' ' } else { c })
.collect::<Vec<_>>();
let len = cmp::min(255, handled_value.len());
compatible[..len].copy_from_slice(&handled_value[..len]);
compatible[..(len + 1)].to_vec()
} else {
property.value.to_vec()
};
let value = &value;
// Now the value can be either:
// - A null-terminated C string, or
// - Binary data
// We follow a very simple logic to present the value:
// - At first, try to convert it to CStr and print,
// - If failed, print it as u32 array.
let value_result = match CStr::from_bytes_with_nul(value) {
Ok(value_cstr) => match value_cstr.to_str() {
Ok(value_str) => Some(value_str),
Err(_e) => None,
},
Err(_e) => None,
};
if let Some(value_str) = value_result {
debug!(
"{:indent$}{} : {:#?}",
"",
name,
value_str,
indent = (n_spaces + 2)
);
} else {
let mut array = Vec::with_capacity(256);
array.resize(value.len() / 4, 0u32);
BigEndian::read_u32_into(value, &mut array);
debug!(
"{:indent$}{} : {:X?}",
"",
name,
array,
indent = (n_spaces + 2)
);
};
}
// Print children nodes if there is any
for child in node.children() {
print_node(child, n_spaces + 2);
}
}

105
arch/src/riscv64/layout.rs Normal file
View File

@@ -0,0 +1,105 @@
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Memory layout of RISC-V 64-bit guest:
//
// Physical +---------------------------------------------------------------+
// address | |
// end | |
// ~ ~ ~ ~
// | |
// | Highmem PCI MMIO space |
// | |
// RAM end +---------------------------------------------------------------+
// (dynamic, | |
// including | |
// hotplug ~ ~ ~ ~
// memory) | |
// | DRAM |
// | |
// | |
// | |
// | |
// 1 GB +---------------------------------------------------------------+
// | |
// | PCI MMCONFIG space |
// | |
// 768 MB +---------------------------------------------------------------+
// | |
// | |
// | PCI MMIO space |
// | |
// 256 MB +---------------------------------------------------------------|
// | |
// | Legacy devices space |
// | |
// 128 MB +---------------------------------------------------------------|
// | |
// | IMSICs |
// | |
// 64 MB +---------------------------------------------------------------+
// | |
// | APLICs |
// | |
// 0 GB +---------------------------------------------------------------+
//
//
use vm_memory::GuestAddress;
/// AIA related devices
/// See https://elixir.bootlin.com/linux/v6.10/source/arch/riscv/include/uapi/asm/kvm.h
/// 0x0 ~ 0x0400_0000 (64 MiB) resides APLICs
pub const APLIC_START: GuestAddress = GuestAddress(0);
pub const APLIC_SIZE: u64 = 0x4000;
/// 0x0400_0000 ~ 0x0800_0000 (64 MiB) resides IMSICs
pub const IMSIC_START: GuestAddress = GuestAddress(0x0400_0000);
pub const IMSIC_SIZE: u64 = 0x1000;
/// Below this address will reside the AIA, above this address will reside the MMIO devices.
const MAPPED_IO_START: GuestAddress = GuestAddress(0x0800_0000);
/// Space 0x0800_0000 ~ 0x1000_0000 is reserved for legacy devices.
pub const LEGACY_SERIAL_MAPPED_IO_START: GuestAddress = MAPPED_IO_START;
/// Space 0x0905_0000 ~ 0x0906_0000 is reserved for pcie io address
pub const MEM_PCI_IO_START: GuestAddress = GuestAddress(0x0905_0000);
pub const MEM_PCI_IO_SIZE: u64 = 0x1_0000;
/// Starting from 0x1000_0000 (256MiB) to 0x3000_0000 (768MiB) is used for PCIE MMIO
pub const MEM_32BIT_DEVICES_START: GuestAddress = GuestAddress(0x1000_0000);
pub const MEM_32BIT_DEVICES_SIZE: u64 = 0x2000_0000;
/// PCI MMCONFIG space (start: after the device space at 768MiB, length: 256MiB)
pub const PCI_MMCONFIG_START: GuestAddress = GuestAddress(0x3000_0000);
pub const PCI_MMCONFIG_SIZE: u64 = 256 << 20;
// One bus with potentially 256 devices (32 slots x 8 functions).
pub const PCI_MMIO_CONFIG_SIZE_PER_SEGMENT: u64 = 4096 * 256;
/// Start of RAM.
pub const RAM_START: GuestAddress = GuestAddress(0x4000_0000);
/// Kernel command line maximum size on RISC-V.
/// See https://elixir.bootlin.com/linux/v6.10/source/arch/riscv/include/uapi/asm/setup.h
pub const CMDLINE_MAX_SIZE: usize = 1024;
/// FDT is at the beginning of RAM.
pub const FDT_START: GuestAddress = RAM_START;
pub const FDT_MAX_SIZE: u64 = 0x1_0000;
/// Kernel start after FDT
pub const KERNEL_START: GuestAddress = GuestAddress(RAM_START.0 + FDT_MAX_SIZE);
/// Pci high memory base
pub const PCI_HIGH_BASE: GuestAddress = GuestAddress(0x2_0000_0000);
/// First usable interrupt on riscv64
pub const IRQ_BASE: u32 = 0;
// As per https://elixir.bootlin.com/linux/v6.10/source/arch/riscv/include/asm/kvm_host.h#L31
/// Number of supported interrupts
pub const IRQ_NUM: u32 = 1023;

173
arch/src/riscv64/mod.rs Normal file
View File

@@ -0,0 +1,173 @@
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
/// Module for the flattened device tree.
pub mod fdt;
/// Layout for this riscv64 system.
pub mod layout;
use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::{Arc, Mutex};
use hypervisor::arch::riscv64::aia::Vaia;
use log::{log_enabled, Level};
use thiserror::Error;
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic};
pub use self::fdt::DeviceInfoForFdt;
use crate::{DeviceType, GuestMemoryMmap, PciSpaceInfo, RegionType};
pub const _NSIG: i32 = 65;
/// Errors thrown while configuring riscv64 system.
#[derive(Debug, Error)]
pub enum Error {
/// Failed to create a FDT.
#[error("Failed to create a FDT")]
SetupFdt,
/// Failed to write FDT to memory.
#[error("Failed to write FDT to memory: {0}")]
WriteFdtToMemory(#[source] fdt::Error),
/// Failed to create a AIA.
#[error("Failed to create a AIA")]
SetupAia,
/// Failed to compute the initramfs address.
#[error("Failed to compute the initramfs address")]
InitramfsAddress,
/// Error configuring the general purpose registers
#[error("Error configuring the general purpose registers: {0}")]
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.
pub struct EntryPoint {
/// Address in guest memory where the guest must start execution
pub entry_addr: GuestAddress,
}
/// Configure the specified VCPU, and return its MPIDR.
pub fn configure_vcpu(
vcpu: &Arc<dyn hypervisor::Vcpu>,
id: u8,
boot_setup: Option<(EntryPoint, &GuestMemoryAtomic<GuestMemoryMmap>)>,
) -> super::Result<()> {
if let Some((kernel_entry_point, _guest_memory)) = boot_setup {
vcpu.setup_regs(
id,
kernel_entry_point.entry_addr.raw_value(),
layout::FDT_START.raw_value(),
)
.map_err(Error::RegsConfiguration)?;
}
Ok(())
}
pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
vec![
// 0 MiB ~ 256 MiB: AIA and legacy devices
(
GuestAddress(0),
layout::MEM_32BIT_DEVICES_START.0 as usize,
RegionType::Reserved,
),
// 256 MiB ~ 768 MiB: MMIO space
(
layout::MEM_32BIT_DEVICES_START,
layout::MEM_32BIT_DEVICES_SIZE as usize,
RegionType::SubRegion,
),
// 768 MiB ~ 1 GiB: reserved. The leading 256M for PCIe MMCONFIG space
(
layout::PCI_MMCONFIG_START,
layout::PCI_MMCONFIG_SIZE as usize,
RegionType::Reserved,
),
// 1GiB ~ inf: RAM
(layout::RAM_START, usize::MAX, RegionType::Ram),
]
}
/// Configures the system and should be called once per vm before starting vcpu threads.
#[allow(clippy::too_many_arguments)]
pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
guest_mem: &GuestMemoryMmap,
cmdline: &str,
num_vcpu: u32,
device_info: &HashMap<(DeviceType, String), T, S>,
initrd: &Option<super::InitramfsConfig>,
pci_space_info: &[PciSpaceInfo],
aia_device: &Arc<Mutex<dyn Vaia>>,
) -> super::Result<()> {
let fdt_final = fdt::create_fdt(
guest_mem,
cmdline,
num_vcpu,
device_info,
aia_device,
initrd,
pci_space_info,
)
.map_err(|_| Error::SetupFdt)?;
if log_enabled!(Level::Debug) {
fdt::print_fdt(&fdt_final);
}
fdt::write_fdt_to_memory(fdt_final, guest_mem).map_err(Error::WriteFdtToMemory)?;
Ok(())
}
/// Returns the memory address where the initramfs could be loaded.
pub fn initramfs_load_addr(
guest_mem: &GuestMemoryMmap,
initramfs_size: usize,
) -> super::Result<u64> {
let round_to_pagesize = |size| (size + (super::PAGE_SIZE - 1)) & !(super::PAGE_SIZE - 1);
match guest_mem
.last_addr()
.checked_sub(round_to_pagesize(initramfs_size) as u64 - 1)
{
Some(offset) => {
if guest_mem.address_in_range(offset) {
Ok(offset.raw_value())
} else {
Err(super::Error::PlatformSpecific(Error::InitramfsAddress))
}
}
None => Err(super::Error::PlatformSpecific(Error::InitramfsAddress)),
}
}
pub fn get_host_cpu_phys_bits(_hypervisor: &Arc<dyn hypervisor::Hypervisor>) -> u8 {
40
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_arch_memory_regions_dram() {
let regions = arch_memory_regions();
assert_eq!(4, regions.len());
assert_eq!(layout::RAM_START, regions[3].0);
assert_eq!(RegionType::Ram, regions[3].2);
}
}

View File

@@ -133,35 +133,35 @@ pub struct CpuidConfig {
pub enum Error {
/// Error writing MP table to memory.
#[error("Error writing MP table to memory: {0}")]
MpTableSetup(mptable::Error),
MpTableSetup(#[source] mptable::Error),
/// Error configuring the general purpose registers
#[error("Error configuring the general purpose registers: {0}")]
RegsConfiguration(regs::Error),
RegsConfiguration(#[source] regs::Error),
/// Error configuring the special registers
#[error("Error configuring the special registers: {0}")]
SregsConfiguration(regs::Error),
SregsConfiguration(#[source] regs::Error),
/// Error configuring the floating point related registers
#[error("Error configuring the floating point related registers: {0}")]
FpuConfiguration(regs::Error),
FpuConfiguration(#[source] regs::Error),
/// Error configuring the MSR registers
#[error("Error configuring the MSR registers: {0}")]
MsrsConfiguration(regs::Error),
MsrsConfiguration(#[source] regs::Error),
/// Failed to set supported CPUs.
#[error("Failed to set supported CPUs: {0}")]
SetSupportedCpusFailed(anyhow::Error),
SetSupportedCpusFailed(#[source] anyhow::Error),
/// Cannot set the local interruption due to bad configuration.
#[error("Cannot set the local interruption due to bad configuration: {0}")]
LocalIntConfiguration(anyhow::Error),
LocalIntConfiguration(#[source] anyhow::Error),
/// Error setting up SMBIOS table
#[error("Error setting up SMBIOS table: {0}")]
SmbiosSetup(smbios::Error),
SmbiosSetup(#[source] smbios::Error),
/// Could not find any SGX EPC section
#[error("Could not find any SGX EPC section")]
@@ -177,15 +177,15 @@ pub enum Error {
/// Error getting supported CPUID through the hypervisor (kvm/mshv) API
#[error("Error getting supported CPUID through the hypervisor API: {0}")]
CpuidGetSupported(HypervisorError),
CpuidGetSupported(#[source] HypervisorError),
/// Error populating CPUID with KVM HyperV emulation details
#[error("Error populating CPUID with KVM HyperV emulation details: {0}")]
CpuidKvmHyperV(vmm_sys_util::fam::Error),
CpuidKvmHyperV(#[source] vmm_sys_util::fam::Error),
/// Error populating CPUID with CPU identification
#[error("Error populating CPUID with CPU identification: {0}")]
CpuidIdentification(vmm_sys_util::fam::Error),
CpuidIdentification(#[source] vmm_sys_util::fam::Error),
/// Error checking CPUID compatibility
#[error("Error checking CPUID compatibility")]
@@ -193,16 +193,16 @@ pub enum Error {
// Error writing EBDA address
#[error("Error writing EBDA address: {0}")]
EbdaSetup(vm_memory::GuestMemoryError),
EbdaSetup(#[source] vm_memory::GuestMemoryError),
// Error getting CPU TSC frequency
#[error("Error getting CPU TSC frequency: {0}")]
GetTscFrequency(HypervisorCpuError),
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}")]
TdxCapabilities(HypervisorError),
TdxCapabilities(#[source] HypervisorError),
/// Failed to configure E820 map for bzImage
#[error("Failed to configure E820 map for bzImage")]
@@ -601,7 +601,7 @@ pub fn generate_common_cpuid(
config: &CpuidConfig,
) -> super::Result<Vec<CpuIdEntry>> {
// SAFETY: cpuid called with valid leaves
if unsafe { x86_64::__cpuid(1) }.ecx & 1 << HYPERVISOR_ECX_BIT == 1 << HYPERVISOR_ECX_BIT {
if unsafe { x86_64::__cpuid(1) }.ecx & (1 << HYPERVISOR_ECX_BIT) == 1 << HYPERVISOR_ECX_BIT {
// SAFETY: cpuid called with valid leaves
let hypervisor_cpuid = unsafe { x86_64::__cpuid(0x4000_0000) };
@@ -689,7 +689,7 @@ pub fn generate_common_cpuid(
// Clear AMX related bits if the AMX feature is not enabled
0x7 => {
if !config.amx && entry.index == 0 {
entry.edx &= !(1 << AMX_BF16 | 1 << AMX_TILE | 1 << AMX_INT8)
entry.edx &= !((1 << AMX_BF16) | (1 << AMX_TILE) | (1 << AMX_INT8))
}
}
0xd =>
@@ -747,12 +747,12 @@ pub fn generate_common_cpuid(
// These features are not supported by TDX
#[cfg(feature = "tdx")]
if config.tdx {
entry.eax &= !(1 << KVM_FEATURE_CLOCKSOURCE_BIT
| 1 << KVM_FEATURE_CLOCKSOURCE2_BIT
| 1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT
| 1 << KVM_FEATURE_ASYNC_PF_BIT
| 1 << KVM_FEATURE_ASYNC_PF_VMEXIT_BIT
| 1 << KVM_FEATURE_STEAL_TIME_BIT)
entry.eax &= !((1 << KVM_FEATURE_CLOCKSOURCE_BIT)
| (1 << KVM_FEATURE_CLOCKSOURCE2_BIT)
| (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT)
| (1 << KVM_FEATURE_ASYNC_PF_BIT)
| (1 << KVM_FEATURE_ASYNC_PF_VMEXIT_BIT)
| (1 << KVM_FEATURE_STEAL_TIME_BIT))
}
}
_ => {}
@@ -801,10 +801,10 @@ pub fn generate_common_cpuid(
});
cpuid.push(CpuIdEntry {
function: 0x4000_0003,
eax: 1 << 1 // AccessPartitionReferenceCounter
| 1 << 2 // AccessSynicRegs
| 1 << 3 // AccessSyntheticTimerRegs
| 1 << 9, // AccessPartitionReferenceTsc
eax: (1 << 1) // AccessPartitionReferenceCounter
| (1 << 2) // AccessSynicRegs
| (1 << 3) // AccessSyntheticTimerRegs
| (1 << 9), // AccessPartitionReferenceTsc
edx: 1 << 3, // CPU dynamic partitioning
..Default::default()
});
@@ -887,6 +887,10 @@ pub fn configure_vcpu(
}
}
for c in &cpuid {
info!("{}", c);
}
vcpu.set_cpuid2(&cpuid)
.map_err(|e| Error::SetSupportedCpusFailed(e.into()))?;
@@ -1380,7 +1384,7 @@ fn update_cpuid_topology(
let mut cpu_ebx = CpuidPatch::get_cpuid_reg(cpuid, 0x1, None, CpuidReg::EBX).unwrap_or(0);
cpu_ebx |= ((dies_per_package as u32) * (cores_per_die as u32) * (threads_per_core as u32))
& 0xff << 16;
& (0xff << 16);
CpuidPatch::set_cpuid_reg(cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
let mut cpu_edx = CpuidPatch::get_cpuid_reg(cpuid, 0x1, None, CpuidReg::EDX).unwrap_or(0);
@@ -1407,6 +1411,7 @@ fn update_cpuid_topology(
u32::from(dies_per_package * cores_per_die * threads_per_core),
);
CpuidPatch::set_cpuid_reg(cpuid, 0xb, Some(1), CpuidReg::ECX, 2 << 8);
CpuidPatch::set_cpuid_reg(cpuid, 0xb, Some(1), CpuidReg::EDX, x2apic_id);
// CPU Topology leaf 0x1f
CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(0), CpuidReg::EAX, thread_width);

View File

@@ -60,31 +60,31 @@ pub enum Error {
AddressOverflow,
/// Failure while zeroing out the memory for the MP table.
#[error("Failure while zeroing out the memory for the MP table: {0}")]
Clear(GuestMemoryError),
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}")]
WriteMpfIntel(GuestMemoryError),
WriteMpfIntel(#[source] GuestMemoryError),
/// Failure to write MP CPU entry.
#[error("Failure to write MP CPU entry: {0}")]
WriteMpcCpu(GuestMemoryError),
WriteMpcCpu(#[source] GuestMemoryError),
/// Failure to write MP ioapic entry.
#[error("Failure to write MP ioapic entry: {0}")]
WriteMpcIoapic(GuestMemoryError),
WriteMpcIoapic(#[source] GuestMemoryError),
/// Failure to write MP bus entry.
#[error("Failure to write MP bus entry: {0}")]
WriteMpcBus(GuestMemoryError),
WriteMpcBus(#[source] GuestMemoryError),
/// Failure to write MP interrupt source entry.
#[error("Failure to write MP interrupt source entry: {0}")]
WriteMpcIntsrc(GuestMemoryError),
WriteMpcIntsrc(#[source] GuestMemoryError),
/// Failure to write MP local interrupt source entry.
#[error("Failure to write MP local interrupt source entry: {0}")]
WriteMpcLintsrc(GuestMemoryError),
WriteMpcLintsrc(#[source] GuestMemoryError),
/// Failure to write MP table header.
#[error("Failure to write MP table header: {0}")]
WriteMpcTable(GuestMemoryError),
WriteMpcTable(#[source] GuestMemoryError),
}
pub type Result<T> = result::Result<T, Error>;

View File

@@ -24,40 +24,40 @@ use crate::{EntryPoint, GuestMemoryMmap};
pub enum Error {
/// Failed to get SREGs for this CPU.
#[error("Failed to get SREGs for this CPU: {0}")]
GetStatusRegisters(hypervisor::HypervisorCpuError),
GetStatusRegisters(#[source] hypervisor::HypervisorCpuError),
/// Failed to set base registers for this CPU.
#[error("Failed to set base registers for this CPU: {0}")]
SetBaseRegisters(hypervisor::HypervisorCpuError),
SetBaseRegisters(#[source] hypervisor::HypervisorCpuError),
/// Failed to configure the FPU.
#[error("Failed to configure the FPU: {0}")]
SetFpuRegisters(hypervisor::HypervisorCpuError),
SetFpuRegisters(#[source] hypervisor::HypervisorCpuError),
/// Setting up MSRs failed.
#[error("Setting up MSRs failed: {0}")]
SetModelSpecificRegisters(hypervisor::HypervisorCpuError),
SetModelSpecificRegisters(#[source] hypervisor::HypervisorCpuError),
/// Failed to set SREGs for this CPU.
#[error("Failed to set SREGs for this CPU: {0}")]
SetStatusRegisters(hypervisor::HypervisorCpuError),
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}")]
WriteGdt(GuestMemoryError),
WriteGdt(#[source] GuestMemoryError),
/// Writing the IDT to RAM failed.
#[error("Writing the IDT to RAM failed: {0}")]
WriteIdt(GuestMemoryError),
WriteIdt(#[source] GuestMemoryError),
/// Writing PDPTE to RAM failed.
#[error("Writing PDPTE to RAM failed: {0}")]
WritePdpteAddress(GuestMemoryError),
WritePdpteAddress(#[source] GuestMemoryError),
/// Writing PDE to RAM failed.
#[error("Writing PDE to RAM failed: {0}")]
WritePdeAddress(GuestMemoryError),
WritePdeAddress(#[source] GuestMemoryError),
/// Writing PML4 to RAM failed.
#[error("Writing PML4 to RAM failed: {0}")]
WritePml4Address(GuestMemoryError),
WritePml4Address(#[source] GuestMemoryError),
/// Writing PML5 to RAM failed.
#[error("Writing PML5 to RAM failed: {0}")]
WritePml5Address(GuestMemoryError),
WritePml5Address(#[source] GuestMemoryError),
}
pub type Result<T> = result::Result<T, Error>;

View File

@@ -34,7 +34,7 @@ pub enum Error {
WriteData,
/// Failure to parse uuid, uuid format may be error
#[error("Failure to parse uuid: {0}")]
ParseUuid(uuid::Error),
ParseUuid(#[source] uuid::Error),
}
pub type Result<T> = result::Result<T, Error>;

View File

@@ -35,7 +35,7 @@ const TABLE_FOOTER_GUID: &str = "96b582de-1fb2-45f7-baea-a366c55a082d";
const TDVF_METADATA_OFFSET_GUID: &str = "e47a6535-984a-4798-865e-4685a7bf8ec2";
// TDVF_DESCRIPTOR
#[repr(packed)]
#[repr(C, packed)]
#[derive(Default)]
pub struct TdvfDescriptor {
signature: [u8; 4],
@@ -45,7 +45,7 @@ pub struct TdvfDescriptor {
}
// TDVF_SECTION
#[repr(packed)]
#[repr(C, packed)]
#[derive(Clone, Copy, Default, Debug)]
pub struct TdvfSection {
pub data_offset: u32,
@@ -209,7 +209,7 @@ enum HobType {
EndOfHobList = 0xffff,
}
#[repr(C)]
#[repr(C, packed)]
#[derive(Copy, Clone, Default, Debug)]
struct HobHeader {
r#type: HobType,
@@ -217,7 +217,7 @@ struct HobHeader {
reserved: u32,
}
#[repr(C)]
#[repr(C, packed)]
#[derive(Copy, Clone, Default, Debug)]
struct HobHandoffInfoTable {
header: HobHeader,
@@ -230,7 +230,7 @@ struct HobHandoffInfoTable {
efi_end_of_hob_list: u64,
}
#[repr(C)]
#[repr(C, packed)]
#[derive(Copy, Clone, Default, Debug)]
struct EfiGuid {
data1: u32,
@@ -239,7 +239,7 @@ struct EfiGuid {
data4: [u8; 8],
}
#[repr(C)]
#[repr(C, packed)]
#[derive(Copy, Clone, Default, Debug)]
struct HobResourceDescriptor {
header: HobHeader,
@@ -250,7 +250,7 @@ struct HobResourceDescriptor {
resource_length: u64,
}
#[repr(C)]
#[repr(C, packed)]
#[derive(Copy, Clone, Default, Debug)]
struct HobGuidType {
header: HobHeader,
@@ -266,14 +266,14 @@ pub enum PayloadImageType {
RawVmLinux,
}
#[repr(C)]
#[repr(C, packed)]
#[derive(Copy, Clone, Default, Debug)]
pub struct PayloadInfo {
pub image_type: PayloadImageType,
pub entry_point: u64,
}
#[repr(C)]
#[repr(C, packed)]
#[derive(Copy, Clone, Default, Debug)]
struct TdPayload {
guid_type: HobGuidType,
@@ -299,7 +299,7 @@ pub struct TdHob {
}
fn align_hob(v: u64) -> u64 {
(v + 7) / 8 * 8
v.div_ceil(8) * 8
}
impl TdHob {

View File

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

View File

@@ -2,6 +2,9 @@
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use std::marker::PhantomData;
use std::os::fd::{AsRawFd, OwnedFd, RawFd};
use thiserror::Error;
use vmm_sys_util::eventfd::EventFd;
@@ -19,12 +22,50 @@ pub enum DiskFileError {
pub type DiskFileResult<T> = std::result::Result<T, DiskFileError>;
/// A wrapper for [`RawFd`] capturing the lifetime of a corresponding [`DiskFile`].
///
/// This fulfills the same role as [`BorrowedFd`] but is tailored to the limitations
/// by some implementations of [`DiskFile`], which wrap the effective [`File`]
/// in an `Arc<Mutex<T>>`, making the use of [`BorrowedFd`] impossible.
///
/// [`BorrowedFd`]: std::os::fd::BorrowedFd
#[derive(Copy, Clone, Debug)]
pub struct BorrowedDiskFd<'fd> {
raw_fd: RawFd,
_lifetime: PhantomData<&'fd OwnedFd>,
}
impl BorrowedDiskFd<'_> {
pub(super) fn new(raw_fd: RawFd) -> Self {
Self {
raw_fd,
_lifetime: PhantomData,
}
}
}
impl AsRawFd for BorrowedDiskFd<'_> {
fn as_raw_fd(&self) -> RawFd {
self.raw_fd
}
}
/// Abstraction over the effective [`File`] backing up a block device,
/// with support for synchronous and asynchronous I/O.
///
/// This allows abstracting over raw image formats as well as structured
/// image formats.
pub trait DiskFile: Send {
fn size(&mut self) -> DiskFileResult<u64>;
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>>;
fn topology(&mut self) -> DiskTopology {
DiskTopology::default()
}
/// Returns the file descriptor of the underlying disk image file.
///
/// The file descriptor is supposed to be used for `fcntl()` calls but no
/// other operation.
fn fd(&mut self) -> BorrowedDiskFd;
}
#[derive(Error, Debug)]

173
block/src/fcntl.rs Normal file
View File

@@ -0,0 +1,173 @@
// Copyright © 2025 Cyberus Technology GmbH
//
// SPDX-License-Identifier: Apache-2.0
//
//! Helpers for advisory file locking.
//!
//! Under the hood, the implementation uses OFD locks for the entire file,
//! as described in [[0]]. The advantage over `F_SETLKW` (currently used by
//! Rust std: `File::try_lock()`) is that only the very last `close()` on a
//! file descriptor releases the lock. This prevents mistakes and unexpected
//! behavior.
//!
//! [0]: <https://apenwarr.ca/log/20101213>.
use std::fmt::Debug;
use std::io;
use std::os::fd::{AsRawFd, RawFd};
use thiserror::Error;
/// Errors that can happen when working with file locks.
#[derive(Error, Debug)]
pub enum LockError {
/// The file is already locked.
///
/// A call to [`get_lock_state`] can help to identify the reason.
#[error("The file is already locked")]
AlreadyLocked,
/// IO error.
#[error("The lock state could not be checked or set: {0}")]
Io(#[source] io::Error),
}
/// Commands for use with [`fcntl`].
#[allow(non_camel_case_types)]
enum FcntlArg<'a> {
/// Set an OFD lock from the given lock description.
F_OFD_SETLK(&'a libc::flock),
/// Get the first OFD lock for the given lock description.
F_OFD_GETLK(&'a mut libc::flock),
}
/// Wrapper for [`libc::fcntl`] that properly sets the function arguments.
fn fcntl(fd: RawFd, arg: FcntlArg) -> libc::c_int {
// SAFETY: We use a valid FD.
unsafe {
match arg {
FcntlArg::F_OFD_SETLK(flock) => libc::fcntl(fd, libc::F_OFD_SETLK, flock),
FcntlArg::F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock),
}
}
}
/// Describes the type of lock you want to set.
#[derive(Clone, Copy, Debug)]
pub enum LockType {
/// Clear a lock.
Unlock,
/// Set a write lock (exclusive).
Write,
/// Set a read lock (shared).
Read,
}
impl LockType {
pub const fn to_libc_val(self) -> libc::c_int {
match self {
Self::Unlock => libc::F_UNLCK as libc::c_int,
Self::Write => libc::F_WRLCK as libc::c_int,
Self::Read => libc::F_RDLCK as libc::c_int,
}
}
}
/// Describes the current state of a lock.
#[derive(Debug)]
pub enum LockState {
/// No lock set.
Unlocked,
/// Locked for reading (non-exclusive).
SharedRead,
/// Locked for writing (exclusive mode).
ExclusiveWrite,
}
impl LockState {
fn new(value: libc::c_int) -> Self {
const F_UNLCK: libc::c_int = libc::F_UNLCK as libc::c_int;
const F_WRLCK: libc::c_int = libc::F_WRLCK as libc::c_int;
const F_RDLCK: libc::c_int = libc::F_RDLCK as libc::c_int;
match value {
F_UNLCK => Self::Unlocked,
F_WRLCK => Self::ExclusiveWrite,
F_RDLCK => Self::SharedRead,
// This is so unlikely that we want to avoid the complexity of
// coping with this error case. Can only fail if either Linux
// is broken or memory is messed up.
other => panic!("Unexpected lock state: {other}"),
}
}
}
/// Returns a [`struct@libc::flock`] structure for the whole file.
const fn get_flock(lock_type: LockType) -> libc::flock {
libc::flock {
l_type: lock_type.to_libc_val() as libc::c_short,
l_whence: libc::SEEK_SET as libc::c_short,
l_start: 0,
l_len: 0, /* EOF */
l_pid: 0, /* filled by callee */
}
}
/// Tries to acquire a lock using [`fcntl`] with respect to the given
/// parameters.
///
/// Please note that `fcntl()` OFD locks are **advisory locks**, which do not
/// prevent to `open()` a file if a lock is already placed.
///
/// # Parameters
/// - `file`: The file to acquire a lock for [`LockType`]. The file's state will
/// be logically mutated, but not technically.
/// - `lock_type`: The [`LockType`]
pub fn try_acquire_lock<Fd: AsRawFd>(file: Fd, lock_type: LockType) -> Result<(), LockError> {
let flock = get_flock(lock_type);
let res = fcntl(file.as_raw_fd(), FcntlArg::F_OFD_SETLK(&flock));
match res {
0 => Ok(()),
-1 => {
let io_error = io::Error::last_os_error();
let errno = io_error.raw_os_error().unwrap();
match errno {
// See man page for error code:
// <https://man7.org/linux/man-pages/man2/fcntl.2.html>
libc::EAGAIN | libc::EACCES => Err(LockError::AlreadyLocked),
_ => Err(LockError::Io(io_error)),
}
}
val => panic!("Unexpected return value from fcntl(): {val}"),
}
}
/// Clears a lock.
///
/// # Parameters
/// - `file`: The file to clear all locks for [`LockType`].
pub fn clear_lock<Fd: AsRawFd>(file: Fd) -> Result<(), LockError> {
try_acquire_lock(file, LockType::Unlock)
}
/// Returns the current lock state using [`fcntl`] with respect to the given
/// parameters.
///
/// # Parameters
/// - `file`: The file for which to get the lock state.
pub fn get_lock_state<Fd: AsRawFd>(file: Fd) -> Result<LockState, LockError> {
let mut flock = get_flock(LockType::Write);
let res = fcntl(file.as_raw_fd(), FcntlArg::F_OFD_GETLK(&mut flock));
match res {
0 => {
let state = flock.l_type as libc::c_int;
let state = LockState::new(state);
Ok(state)
}
-1 => {
let io_error = io::Error::last_os_error();
Err(LockError::Io(io_error))
}
val => panic!("Unexpected return value from fcntl(): {val}"),
}
}

View File

@@ -8,7 +8,7 @@ use std::os::unix::io::{AsRawFd, RawFd};
use vmm_sys_util::eventfd::EventFd;
use crate::async_io::{
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult,
AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
};
use crate::fixed_vhd::FixedVhd;
use crate::raw_async::RawFileAsync;
@@ -33,6 +33,10 @@ impl DiskFile for FixedVhdDiskAsync {
.map_err(DiskFileError::NewAsyncIo)?,
) as Box<dyn AsyncIo>)
}
fn fd(&mut self) -> BorrowedDiskFd {
BorrowedDiskFd::new(self.0.as_raw_fd())
}
}
pub struct FixedVhdAsync {

View File

@@ -8,7 +8,7 @@ use std::os::unix::io::{AsRawFd, RawFd};
use vmm_sys_util::eventfd::EventFd;
use crate::async_io::{
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult,
AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
};
use crate::fixed_vhd::FixedVhd;
use crate::raw_sync::RawFileSync;
@@ -33,6 +33,10 @@ impl DiskFile for FixedVhdDiskSync {
.map_err(DiskFileError::NewAsyncIo)?,
) as Box<dyn AsyncIo>)
}
fn fd(&mut self) -> BorrowedDiskFd {
BorrowedDiskFd::new(self.0.as_raw_fd())
}
}
pub struct FixedVhdSync {

View File

@@ -12,6 +12,7 @@
extern crate log;
pub mod async_io;
pub mod fcntl;
pub mod fixed_vhd;
#[cfg(feature = "io_uring")]
/// Enabled with the `"io_uring"` feature
@@ -59,9 +60,7 @@ use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::{aio, ioctl_io_nr, ioctl_ioc_nr};
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult};
use crate::fixed_vhd::FixedVhd;
use crate::qcow::{QcowFile, RawFile};
use crate::vhdx::{Vhdx, VhdxError};
use crate::vhdx::VhdxError;
const SECTOR_SHIFT: u8 = 9;
pub const SECTOR_SIZE: u64 = 0x01 << SECTOR_SHIFT;
@@ -69,9 +68,9 @@ pub const SECTOR_SIZE: u64 = 0x01 << SECTOR_SHIFT;
#[derive(Error, Debug)]
pub enum Error {
#[error("Guest gave us bad memory addresses")]
GuestMemory(GuestMemoryError),
GuestMemory(#[source] GuestMemoryError),
#[error("Guest gave us offsets that would have overflowed a usize")]
CheckedOffset(GuestAddress, usize),
CheckedOffset(GuestAddress, usize /* sector offset */),
#[error("Guest gave us a write only descriptor that protocol says to read from")]
UnexpectedWriteOnlyDescriptor,
#[error("Guest gave us a read only descriptor that protocol says to write to")]
@@ -81,21 +80,21 @@ pub enum Error {
#[error("Guest gave us a descriptor that was too short to use")]
DescriptorLengthTooSmall,
#[error("Failed to detect image type: {0}")]
DetectImageType(std::io::Error),
DetectImageType(#[source] std::io::Error),
#[error("Failure in fixed vhd: {0}")]
FixedVhdError(std::io::Error),
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}")]
QcowError(qcow::Error),
QcowError(#[source] qcow::Error),
#[error("Failure in raw file: {0}")]
RawFileError(std::io::Error),
RawFileError(#[source] std::io::Error),
#[error("The requested operation does not support multiple descriptors")]
TooManyDescriptors,
#[error("Failure in vhdx: {0}")]
VhdxError(VhdxError),
VhdxError(#[source] VhdxError),
}
fn build_device_id(disk_path: &Path) -> result::Result<String, Error> {
@@ -133,33 +132,33 @@ pub fn build_serial(disk_path: &Path) -> Vec<u8> {
#[derive(Error, Debug)]
pub enum ExecuteError {
#[error("Bad request: {0}")]
BadRequest(Error),
BadRequest(#[source] Error),
#[error("Failed to flush: {0}")]
Flush(io::Error),
Flush(#[source] io::Error),
#[error("Failed to read: {0}")]
Read(GuestMemoryError),
Read(#[source] GuestMemoryError),
#[error("Failed to read_exact: {0}")]
ReadExact(io::Error),
ReadExact(#[source] io::Error),
#[error("Failed to seek: {0}")]
Seek(io::Error),
Seek(#[source] io::Error),
#[error("Failed to write: {0}")]
Write(GuestMemoryError),
Write(#[source] GuestMemoryError),
#[error("Failed to write_all: {0}")]
WriteAll(io::Error),
WriteAll(#[source] io::Error),
#[error("Unsupported request: {0}")]
Unsupported(u32),
#[error("Failed to submit io uring: {0}")]
SubmitIoUring(io::Error),
SubmitIoUring(#[source] io::Error),
#[error("Failed to get guest address: {0}")]
GetHostAddress(GuestMemoryError),
GetHostAddress(#[source] GuestMemoryError),
#[error("Failed to async read: {0}")]
AsyncRead(AsyncIoError),
AsyncRead(#[source] AsyncIoError),
#[error("Failed to async write: {0}")]
AsyncWrite(AsyncIoError),
AsyncWrite(#[source] AsyncIoError),
#[error("failed to async flush: {0}")]
AsyncFlush(AsyncIoError),
AsyncFlush(#[source] AsyncIoError),
#[error("Failed allocating a temporary buffer: {0}")]
TemporaryBufferAllocation(io::Error),
TemporaryBufferAllocation(#[source] io::Error),
}
impl ExecuteError {
@@ -220,6 +219,8 @@ fn sector<B: Bitmap + 'static>(
mem.read_obj(addr).map_err(Error::GuestMemory)
}
const DEFAULT_DESCRIPTOR_VEC_SIZE: usize = 32;
#[derive(Debug)]
pub struct AlignedOperation {
origin_ptr: u64,
@@ -232,10 +233,10 @@ pub struct AlignedOperation {
pub struct Request {
pub request_type: RequestType,
pub sector: u64,
pub data_descriptors: SmallVec<[(GuestAddress, u32); 1]>,
pub data_descriptors: SmallVec<[(GuestAddress, u32); DEFAULT_DESCRIPTOR_VEC_SIZE]>,
pub status_addr: GuestAddress,
pub writeback: bool,
pub aligned_operations: SmallVec<[AlignedOperation; 1]>,
pub aligned_operations: SmallVec<[AlignedOperation; DEFAULT_DESCRIPTOR_VEC_SIZE]>,
pub start: Instant,
}
@@ -263,10 +264,10 @@ impl Request {
let mut req = Request {
request_type: request_type(desc_chain.memory(), hdr_desc_addr)?,
sector: sector(desc_chain.memory(), hdr_desc_addr)?,
data_descriptors: SmallVec::with_capacity(1),
data_descriptors: SmallVec::with_capacity(DEFAULT_DESCRIPTOR_VEC_SIZE),
status_addr: GuestAddress(0),
writeback: true,
aligned_operations: SmallVec::with_capacity(1),
aligned_operations: SmallVec::with_capacity(DEFAULT_DESCRIPTOR_VEC_SIZE),
start: Instant::now(),
};
@@ -398,7 +399,7 @@ impl Request {
let request_type = self.request_type;
let offset = (sector << SECTOR_SHIFT) as libc::off_t;
let mut iovecs: SmallVec<[libc::iovec; 1]> =
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 {
@@ -653,7 +654,8 @@ where
completion_list: &mut VecDeque<(u64, i32)>,
) -> AsyncIoResult<()> {
// Convert libc::iovec into IoSliceMut
let mut slices: SmallVec<[IoSliceMut; 1]> = SmallVec::with_capacity(iovecs.len());
let mut slices: SmallVec<[IoSliceMut; DEFAULT_DESCRIPTOR_VEC_SIZE]> =
SmallVec::with_capacity(iovecs.len());
for iovec in iovecs.iter() {
// SAFETY: on Linux IoSliceMut wraps around libc::iovec
slices.push(IoSliceMut::new(unsafe {
@@ -668,9 +670,11 @@ where
file.seek(SeekFrom::Start(offset as u64))
.map_err(AsyncIoError::ReadVectored)?;
// Read vectored
file.read_vectored(slices.as_mut_slice())
.map_err(AsyncIoError::ReadVectored)?
let mut r = 0;
for b in slices.iter_mut() {
r += file.read(b).map_err(AsyncIoError::ReadVectored)?;
}
r
};
completion_list.push_back((user_data, result as i32));
@@ -688,7 +692,8 @@ where
completion_list: &mut VecDeque<(u64, i32)>,
) -> AsyncIoResult<()> {
// Convert libc::iovec into IoSlice
let mut slices: SmallVec<[IoSlice; 1]> = SmallVec::with_capacity(iovecs.len());
let mut slices: SmallVec<[IoSlice; DEFAULT_DESCRIPTOR_VEC_SIZE]> =
SmallVec::with_capacity(iovecs.len());
for iovec in iovecs.iter() {
// SAFETY: on Linux IoSlice wraps around libc::iovec
slices.push(IoSlice::new(unsafe {
@@ -703,9 +708,11 @@ where
file.seek(SeekFrom::Start(offset as u64))
.map_err(AsyncIoError::WriteVectored)?;
// Write vectored
file.write_vectored(slices.as_slice())
.map_err(AsyncIoError::WriteVectored)?
let mut r = 0;
for b in slices.iter() {
r += file.write(b).map_err(AsyncIoError::WriteVectored)?;
}
r
};
completion_list.push_back((user_data, result as i32));
@@ -789,25 +796,6 @@ pub trait BlockBackend: Read + Write + Seek + Send + Debug {
fn size(&self) -> Result<u64, Error>;
}
/// Inspect the image file type and create an appropriate disk file to match it.
pub fn create_disk_file(mut file: File, direct_io: bool) -> Result<Box<dyn BlockBackend>, Error> {
let image_type = detect_image_type(&mut file).map_err(Error::DetectImageType)?;
Ok(match image_type {
ImageType::Qcow2 => {
Box::new(QcowFile::from(RawFile::new(file, direct_io)).map_err(Error::QcowError)?)
as Box<dyn BlockBackend>
}
ImageType::FixedVhd => {
Box::new(FixedVhd::new(file).map_err(Error::FixedVhdError)?) as Box<dyn BlockBackend>
}
ImageType::Vhdx => {
Box::new(Vhdx::new(file).map_err(Error::VhdxError)?) as Box<dyn BlockBackend>
}
ImageType::Raw => Box::new(RawFile::new(file, direct_io)) as Box<dyn BlockBackend>,
})
}
#[derive(Debug)]
pub struct DiskTopology {
pub logical_block_size: u64,

View File

@@ -13,6 +13,7 @@ use std::cmp::{max, min};
use std::fs::OpenOptions;
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::mem::size_of;
use std::os::fd::{AsRawFd, RawFd};
use std::str;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
@@ -36,23 +37,23 @@ const MAX_NESTING_DEPTH: u32 = 10;
#[derive(Debug, Error)]
pub enum Error {
#[error("Backing file io error: {0}")]
BackingFileIo(io::Error),
BackingFileIo(#[source] io::Error),
#[error("Backing file open error: {0}")]
BackingFileOpen(Box<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}")]
EvictingCache(io::Error),
#[error("File larger than max of {}: {0}", MAX_QCOW_FILE_SIZE)]
EvictingCache(#[source] io::Error),
#[error("File larger than max of {MAX_QCOW_FILE_SIZE}: {0}")]
FileTooBig(u64),
#[error("Failed to get file size: {0}")]
GettingFileSize(io::Error),
GettingFileSize(#[source] io::Error),
#[error("Failed to get refcount: {0}")]
GettingRefcount(refcount::Error),
GettingRefcount(#[source] refcount::Error),
#[error("Failed to parse filename: {0}")]
InvalidBackingFileName(str::Utf8Error),
InvalidBackingFileName(#[source] str::Utf8Error),
#[error("Invalid cluster index")]
InvalidClusterIndex,
#[error("Invalid cluster size")]
@@ -80,29 +81,29 @@ pub enum Error {
#[error("Not enough space for refcounts")]
NotEnoughSpaceForRefcounts,
#[error("Failed to open file {0}")]
OpeningFile(io::Error),
OpeningFile(#[source] io::Error),
#[error("Failed to read data: {0}")]
ReadingData(io::Error),
ReadingData(#[source] io::Error),
#[error("Failed to read header: {0}")]
ReadingHeader(io::Error),
ReadingHeader(#[source] io::Error),
#[error("Failed to read pointers: {0}")]
ReadingPointers(io::Error),
ReadingPointers(#[source] io::Error),
#[error("Failed to read ref count block: {0}")]
ReadingRefCountBlock(refcount::Error),
ReadingRefCountBlock(#[source] refcount::Error),
#[error("Failed to read ref counts: {0}")]
ReadingRefCounts(io::Error),
ReadingRefCounts(#[source] io::Error),
#[error("Failed to rebuild ref counts: {0}")]
RebuildingRefCounts(io::Error),
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}")]
SeekingFile(io::Error),
SeekingFile(#[source] io::Error),
#[error("Failed to set file size: {0}")]
SettingFileSize(io::Error),
SettingFileSize(#[source] io::Error),
#[error("Failed to set refcount refcount: {0}")]
SettingRefcountRefcount(io::Error),
SettingRefcountRefcount(#[source] io::Error),
#[error("Size too small for number of clusters")]
SizeTooSmallForNumberOfClusters,
#[error("L1 entry table too large: {0}")]
@@ -114,9 +115,9 @@ pub enum Error {
#[error("Unsupported version: {0}")]
UnsupportedVersion(u32),
#[error("Failed to write data: {0}")]
WritingData(io::Error),
WritingData(#[source] io::Error),
#[error("Failed to write header: {0}")]
WritingHeader(io::Error),
WritingHeader(#[source] io::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
@@ -378,7 +379,7 @@ impl QcowHeader {
}
if let Some(backing_file_path) = self.backing_file_path.as_ref() {
write!(file, "{}", backing_file_path).map_err(Error::WritingHeader)?;
write!(file, "{backing_file_path}").map_err(Error::WritingHeader)?;
}
// Set the file length by seeking and writing a zero to the last byte. This avoids needing
@@ -502,7 +503,7 @@ impl QcowFile {
if refcount_bits != 16 {
return Err(Error::UnsupportedRefcountOrder);
}
let refcount_bytes = (refcount_bits + 7) / 8;
let refcount_bytes = refcount_bits.div_ceil(8);
// Need at least one refcount cluster
if header.refcount_table_clusters == 0 {
@@ -1516,6 +1517,12 @@ impl QcowFile {
}
}
impl AsRawFd for QcowFile {
fn as_raw_fd(&self) -> RawFd {
self.raw_file.as_raw_fd()
}
}
impl Drop for QcowFile {
fn drop(&mut self) {
let _ = self.sync_caches();
@@ -1625,8 +1632,7 @@ impl FileSync for QcowFile {
impl FileSetLen for QcowFile {
fn set_len(&self, _len: u64) -> std::io::Result<()> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
Err(std::io::Error::other(
"set_len() not supported for QcowFile",
))
}

View File

@@ -6,6 +6,7 @@
use std::io::{self, BufWriter, Seek, SeekFrom, Write};
use std::mem::size_of;
use std::os::fd::{AsRawFd, RawFd};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use vmm_sys_util::write_zeroes::WriteZeroes;
@@ -159,3 +160,9 @@ impl Clone for QcowRawFile {
}
}
}
impl AsRawFd for QcowRawFile {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}

View File

@@ -369,3 +369,9 @@ impl Clone for RawFile {
}
}
}
impl AsRawFd for RawFile {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}

View File

@@ -16,7 +16,7 @@ use crate::qcow::vec_cache::{CacheMap, Cacheable, VecCache};
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}")]
EvictingRefCounts(io::Error),
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")]
InvalidIndex,
@@ -28,7 +28,7 @@ pub enum Error {
NeedNewCluster,
/// `ReadingRefCounts` - Error reading the file into the refcount cache.
#[error("Failed to read the file into the refcount cache: {0}")]
ReadingRefCounts(io::Error),
ReadingRefCounts(#[source] io::Error),
}
pub type Result<T> = std::result::Result<T, Error>;

View File

@@ -5,11 +5,14 @@
use std::collections::VecDeque;
use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::os::fd::AsRawFd;
use std::sync::{Arc, Mutex, MutexGuard};
use vmm_sys_util::eventfd::EventFd;
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
use crate::async_io::{
AsyncIo, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
};
use crate::qcow::{QcowFile, RawFile, Result as QcowResult};
use crate::AsyncAdaptor;
@@ -35,6 +38,11 @@ impl DiskFile for QcowDiskSync {
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(QcowSync::new(self.qcow_file.clone())) as Box<dyn AsyncIo>)
}
fn fd(&mut self) -> BorrowedDiskFd {
let lock = self.qcow_file.lock().unwrap();
BorrowedDiskFd::new(lock.as_raw_fd())
}
}
pub struct QcowSync {

View File

@@ -3,14 +3,14 @@
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::io::{Error, Seek, SeekFrom};
use std::os::unix::io::{AsRawFd, RawFd};
use io_uring::{opcode, squeue, types, IoUring};
use io_uring::{opcode, types, IoUring};
use vmm_sys_util::eventfd::EventFd;
use crate::async_io::{
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult,
AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
};
use crate::DiskTopology;
@@ -46,6 +46,10 @@ impl DiskFile for RawFileDisk {
DiskTopology::default()
}
}
fn fd(&mut self) -> BorrowedDiskFd {
BorrowedDiskFd::new(self.file.as_raw_fd())
}
}
pub struct RawFileAsync {
@@ -86,14 +90,14 @@ impl AsyncIo for RawFileAsync {
// SAFETY: we know the file descriptor is valid and we
// relied on vm-memory to provide the buffer address.
let _ = unsafe {
unsafe {
sq.push(
&opcode::Readv::new(types::Fd(self.fd), iovecs.as_ptr(), iovecs.len() as u32)
.offset(offset.try_into().unwrap())
.build()
.flags(squeue::Flags::ASYNC)
.user_data(user_data),
)
.map_err(|_| AsyncIoError::ReadVectored(Error::other("Submission queue is full")))?
};
// Update the submission queue and submit new operations to the
@@ -114,14 +118,14 @@ impl AsyncIo for RawFileAsync {
// SAFETY: we know the file descriptor is valid and we
// relied on vm-memory to provide the buffer address.
let _ = unsafe {
unsafe {
sq.push(
&opcode::Writev::new(types::Fd(self.fd), iovecs.as_ptr(), iovecs.len() as u32)
.offset(offset.try_into().unwrap())
.build()
.flags(squeue::Flags::ASYNC)
.user_data(user_data),
)
.map_err(|_| AsyncIoError::WriteVectored(Error::other("Submission queue is full")))?
};
// Update the submission queue and submit new operations to the
@@ -137,13 +141,13 @@ impl AsyncIo for RawFileAsync {
let (submitter, mut sq, _) = self.io_uring.split();
// SAFETY: we know the file descriptor is valid.
let _ = unsafe {
unsafe {
sq.push(
&opcode::Fsync::new(types::Fd(self.fd))
.build()
.flags(squeue::Flags::ASYNC)
.user_data(user_data),
)
.map_err(|_| AsyncIoError::Fsync(Error::other("Submission queue is full")))?
};
// Update the submission queue and submit new operations to the

View File

@@ -13,7 +13,7 @@ use vmm_sys_util::aio;
use vmm_sys_util::eventfd::EventFd;
use crate::async_io::{
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult,
AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
};
use crate::DiskTopology;
@@ -49,6 +49,10 @@ impl DiskFile for RawFileDiskAio {
DiskTopology::default()
}
}
fn fd(&mut self) -> BorrowedDiskFd {
BorrowedDiskFd::new(self.file.as_raw_fd())
}
}
pub struct RawFileAsyncAio {

View File

@@ -10,7 +10,7 @@ use std::os::unix::io::{AsRawFd, RawFd};
use vmm_sys_util::eventfd::EventFd;
use crate::async_io::{
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult,
AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
};
use crate::DiskTopology;
@@ -43,6 +43,10 @@ impl DiskFile for RawFileDiskSync {
DiskTopology::default()
}
}
fn fd(&mut self) -> BorrowedDiskFd {
BorrowedDiskFd::new(self.file.as_raw_fd())
}
}
pub struct RawFileSync {

View File

@@ -5,6 +5,7 @@
use std::collections::btree_map::BTreeMap;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom, Write};
use std::os::fd::{AsRawFd, RawFd};
use byteorder::{BigEndian, ByteOrder};
use remain::sorted;
@@ -25,19 +26,19 @@ mod vhdx_metadata;
#[sorted]
#[derive(Error, Debug)]
pub enum VhdxError {
#[error("Not a VHDx file {0}")]
#[error("Not a VHDx file: {0}")]
NotVhdx(#[source] VhdxHeaderError),
#[error("Failed to parse VHDx header {0}")]
#[error("Failed to parse VHDx header: {0}")]
ParseVhdxHeader(#[source] VhdxHeaderError),
#[error("Failed to parse VHDx metadata {0}")]
#[error("Failed to parse VHDx metadata: {0}")]
ParseVhdxMetadata(#[source] VhdxMetadataError),
#[error("Failed to parse VHDx region entries {0}")]
#[error("Failed to parse VHDx region entries: {0}")]
ParseVhdxRegionEntry(#[source] VhdxHeaderError),
#[error("Failed reading metadata {0}")]
#[error("Failed reading metadata: {0}")]
ReadBatEntry(#[source] VhdxBatError),
#[error("Failed reading sector from disk {0}")]
#[error("Failed reading sector from disk: {0}")]
ReadFailed(#[source] VhdxIoError),
#[error("Failed writing to sector on disk {0}")]
#[error("Failed writing to sector on disk: {0}")]
WriteFailed(#[source] VhdxIoError),
}
@@ -102,7 +103,7 @@ impl Read for Vhdx {
let sector_count = (buf.len() as u64).div_ceil(self.disk_spec.logical_sector_size as u64);
let sector_index = self.current_offset / self.disk_spec.logical_sector_size as u64;
vhdx_io::read(
let result = vhdx_io::read(
&mut self.file,
buf,
&self.disk_spec,
@@ -111,13 +112,14 @@ impl Read for Vhdx {
sector_count,
)
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"Failed reading {sector_count} sectors from VHDx at index {sector_index}: {e}"
),
)
})
std::io::Error::other(format!(
"Failed reading {sector_count} sectors from VHDx at index {sector_index}: {e}"
))
})?;
self.current_offset = self.current_offset.checked_add(result as u64).unwrap();
Ok(result)
}
}
@@ -134,15 +136,12 @@ impl Write for Vhdx {
if self.first_write {
self.first_write = false;
self.vhdx_header.update(&mut self.file).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Failed to update VHDx header: {e}"),
)
})?;
self.vhdx_header
.update(&mut self.file)
.map_err(|e| std::io::Error::other(format!("Failed to update VHDx header: {e}")))?;
}
vhdx_io::write(
let result = vhdx_io::write(
&mut self.file,
buf,
&mut self.disk_spec,
@@ -152,13 +151,14 @@ impl Write for Vhdx {
sector_count,
)
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"Failed writing {sector_count} sectors on VHDx at index {sector_index}: {e}"
),
)
})
std::io::Error::other(format!(
"Failed writing {sector_count} sectors on VHDx at index {sector_index}: {e}"
))
})?;
self.current_offset = self.current_offset.checked_add(result as u64).unwrap();
Ok(result)
}
}
@@ -223,6 +223,12 @@ impl Clone for Vhdx {
}
}
impl AsRawFd for Vhdx {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}
pub(crate) fn uuid_from_guid(buf: &[u8]) -> Uuid {
// The first 3 fields of UUID are stored in Big Endian format, and
// the last 8 bytes are stored as byte array. Therefore, we read the

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: {0}")]
ReadBat(#[source] io::Error),
#[error("Failed to write BAT entry {0}")]
#[error("Failed to write BAT entry: {0}")]
WriteBat(#[source] io::Error),
}

View File

@@ -110,7 +110,7 @@ impl FileTypeIdentifier {
}
}
#[repr(packed)]
#[repr(C, packed)]
#[derive(Clone, Copy, Debug)]
pub struct Header {
pub signature: u32,
@@ -142,7 +142,7 @@ impl Header {
return Err(VhdxHeaderError::InvalidHeaderSign);
}
let new_checksum = calculate_checksum(&mut buffer, size_of::<u32>())?;
let new_checksum = calculate_checksum(&mut buffer, size_of::<u32>());
if header.checksum != new_checksum {
return Err(VhdxHeaderError::InvalidChecksum(String::from("Header")));
}
@@ -151,7 +151,7 @@ impl Header {
}
/// Converts the header structure into a buffer
fn get_header_as_buffer(&self, buffer: &mut [u8; HEADER_SIZE as usize]) {
fn write_to_buffer(&self, buffer: &mut [u8; HEADER_SIZE as usize]) {
// SAFETY: self is a valid header.
let reference = unsafe {
std::slice::from_raw_parts(self as *const Header as *const u8, HEADER_SIZE as usize)
@@ -160,7 +160,7 @@ impl Header {
}
/// Creates and returns new updated header from the provided current header
pub fn update_header(
fn update_header(
f: &mut File,
current_header: &Header,
change_data_guid: bool,
@@ -191,11 +191,9 @@ impl Header {
log_offset: current_header.log_offset,
};
new_header.get_header_as_buffer(&mut buffer);
let mut crc = crc_any::CRC::crc32c();
crc.digest(&buffer);
new_header.checksum = crc.get_crc() as u32;
new_header.get_header_as_buffer(&mut buffer);
new_header.write_to_buffer(&mut buffer);
new_header.checksum = calculate_checksum(&mut buffer, size_of::<u32>());
new_header.write_to_buffer(&mut buffer);
f.seek(SeekFrom::Start(start))
.map_err(VhdxHeaderError::SeekHeader)?;
@@ -205,7 +203,7 @@ impl Header {
}
}
#[repr(packed)]
#[repr(C, packed)]
#[derive(Clone, Copy, Debug)]
struct RegionTableHeader {
pub signature: u32,
@@ -231,7 +229,7 @@ impl RegionTableHeader {
return Err(VhdxHeaderError::InvalidRegionSign);
}
let new_checksum = calculate_checksum(&mut buffer, size_of::<u32>())?;
let new_checksum = calculate_checksum(&mut buffer, size_of::<u32>());
if region_table_header.checksum != new_checksum {
return Err(VhdxHeaderError::InvalidChecksum(String::from("Region")));
}
@@ -330,7 +328,7 @@ impl RegionInfo {
}
}
#[repr(packed)]
#[repr(C, packed)]
#[derive(Clone, Copy, Debug)]
pub struct RegionTableEntry {
pub guid: Uuid,
@@ -371,22 +369,10 @@ pub struct VhdxHeader {
impl VhdxHeader {
/// Creates a VhdxHeader from a reference to a file
pub fn new(f: &mut File) -> Result<VhdxHeader> {
let _file_type_identifier: FileTypeIdentifier = FileTypeIdentifier::new(f)?;
let header_1 = Header::new(f, HEADER_1_START);
let header_2 = Header::new(f, HEADER_2_START);
let mut file_write_guid: u128 = 0;
let metadata = f.metadata().map_err(VhdxHeaderError::ReadMetadata)?;
if !metadata.permissions().readonly() {
file_write_guid = Uuid::new_v4().as_u128();
}
let (header_1, header_2) =
VhdxHeader::update_headers(f, header_1, header_2, file_write_guid)?;
Ok(VhdxHeader {
_file_type_identifier,
header_1,
header_2,
_file_type_identifier: FileTypeIdentifier::new(f)?,
header_1: Header::new(f, HEADER_1_START)?,
header_2: Header::new(f, HEADER_2_START)?,
region_table_1: RegionTableHeader::new(f, REGION_TABLE_1_START)?,
_region_table_2: RegionTableHeader::new(f, REGION_TABLE_2_START)?,
})
@@ -468,13 +454,11 @@ impl VhdxHeader {
/// Therefore, before calculating, the existing checksum is retrieved and the
/// corresponding field is made zero. After the calculation, the existing checksum
/// is put back to the buffer.
pub fn calculate_checksum(buffer: &mut [u8], csum_offset: usize) -> Result<u32> {
// Read the checksum into a mutable slice
let csum_buf = &mut buffer[csum_offset..csum_offset + 4];
// Convert the checksum chunk into a u32 integer
let orig_csum = LittleEndian::read_u32(csum_buf);
fn calculate_checksum(buffer: &mut [u8], csum_offset: usize) -> u32 {
// Read the original checksum from the buffer
let orig_csum = LittleEndian::read_u32(&buffer[csum_offset..csum_offset + 4]);
// Zero the checksum in the buffer
LittleEndian::write_u32(csum_buf, 0);
LittleEndian::write_u32(&mut buffer[csum_offset..csum_offset + 4], 0);
// Calculate the checksum on the resulting buffer
let mut crc = crc_any::CRC::crc32c();
crc.digest(&buffer);
@@ -483,5 +467,5 @@ pub fn calculate_checksum(buffer: &mut [u8], csum_offset: usize) -> Result<u32>
// Put back the original checksum in the buffer
LittleEndian::write_u32(&mut buffer[csum_offset..csum_offset + 4], orig_csum);
Ok(new_csum)
new_csum
}

View File

@@ -95,46 +95,45 @@ pub fn read(
mut sector_index: u64,
mut sector_count: u64,
) -> Result<usize> {
if disk_spec.has_parent {
return Err(VhdxIoError::UnsupportedMode);
}
let mut read_count: usize = 0;
while sector_count > 0 {
if disk_spec.has_parent {
return Err(VhdxIoError::UnsupportedMode);
} else {
let sector = Sector::new(disk_spec, bat, sector_index, sector_count)?;
let sector = Sector::new(disk_spec, bat, sector_index, sector_count)?;
let bat_entry = match bat.get(sector.bat_index as usize) {
Some(entry) => entry.0,
None => {
return Err(VhdxIoError::InvalidBatIndex);
}
};
match bat_entry & vhdx_bat::BAT_STATE_BIT_MASK {
vhdx_bat::PAYLOAD_BLOCK_NOT_PRESENT
| vhdx_bat::PAYLOAD_BLOCK_UNDEFINED
| vhdx_bat::PAYLOAD_BLOCK_UNMAPPED
| vhdx_bat::PAYLOAD_BLOCK_ZERO => {}
vhdx_bat::PAYLOAD_BLOCK_FULLY_PRESENT => {
f.seek(SeekFrom::Start(sector.file_offset))
.map_err(VhdxIoError::ReadSectorBlock)?;
f.read_exact(
&mut buf[read_count
..(read_count + (sector.free_sectors * SECTOR_SIZE) as usize)],
)
.map_err(VhdxIoError::ReadSectorBlock)?;
}
vhdx_bat::PAYLOAD_BLOCK_PARTIALLY_PRESENT => {
return Err(VhdxIoError::UnsupportedMode);
}
_ => {
return Err(VhdxIoError::InvalidBatEntryState);
}
};
sector_count -= sector.free_sectors;
sector_index += sector.free_sectors;
read_count = sector.free_bytes as usize;
let bat_entry = match bat.get(sector.bat_index as usize) {
Some(entry) => entry.0,
None => {
return Err(VhdxIoError::InvalidBatIndex);
}
};
match bat_entry & vhdx_bat::BAT_STATE_BIT_MASK {
vhdx_bat::PAYLOAD_BLOCK_NOT_PRESENT
| vhdx_bat::PAYLOAD_BLOCK_UNDEFINED
| vhdx_bat::PAYLOAD_BLOCK_UNMAPPED
| vhdx_bat::PAYLOAD_BLOCK_ZERO => {}
vhdx_bat::PAYLOAD_BLOCK_FULLY_PRESENT => {
f.seek(SeekFrom::Start(sector.file_offset))
.map_err(VhdxIoError::ReadSectorBlock)?;
f.read_exact(
&mut buf
[read_count..(read_count + (sector.free_sectors * SECTOR_SIZE) as usize)],
)
.map_err(VhdxIoError::ReadSectorBlock)?;
}
vhdx_bat::PAYLOAD_BLOCK_PARTIALLY_PRESENT => {
return Err(VhdxIoError::UnsupportedMode);
}
_ => {
return Err(VhdxIoError::InvalidBatEntryState);
}
};
sector_count -= sector.free_sectors;
sector_index += sector.free_sectors;
read_count += sector.free_bytes as usize;
}
Ok(read_count)
}
@@ -150,77 +149,73 @@ pub fn write(
mut sector_index: u64,
mut sector_count: u64,
) -> Result<usize> {
if disk_spec.has_parent {
return Err(VhdxIoError::UnsupportedMode);
}
let mut write_count: usize = 0;
while sector_count > 0 {
if disk_spec.has_parent {
return Err(VhdxIoError::UnsupportedMode);
} else {
let sector = Sector::new(disk_spec, bat, sector_index, sector_count)?;
let sector = Sector::new(disk_spec, bat, sector_index, sector_count)?;
let bat_entry = match bat.get(sector.bat_index as usize) {
Some(entry) => entry.0,
None => {
return Err(VhdxIoError::InvalidBatIndex);
}
};
match bat_entry & vhdx_bat::BAT_STATE_BIT_MASK {
vhdx_bat::PAYLOAD_BLOCK_NOT_PRESENT
| vhdx_bat::PAYLOAD_BLOCK_UNDEFINED
| vhdx_bat::PAYLOAD_BLOCK_UNMAPPED
| vhdx_bat::PAYLOAD_BLOCK_ZERO => {
let file_offset =
align!(disk_spec.image_size, vhdx_metadata::BLOCK_SIZE_MIN as u64);
let new_size = file_offset
.checked_add(disk_spec.block_size as u64)
.ok_or(VhdxIoError::InvalidDiskSize)?;
f.set_len(new_size).map_err(VhdxIoError::ResizeFile)?;
disk_spec.image_size = new_size;
let new_bat_entry = file_offset
| (vhdx_bat::PAYLOAD_BLOCK_FULLY_PRESENT & vhdx_bat::BAT_STATE_BIT_MASK);
bat[sector.bat_index as usize] = BatEntry(new_bat_entry);
BatEntry::write_bat_entries(f, bat_offset, bat)
.map_err(VhdxIoError::WriteBat)?;
if file_offset < vhdx_metadata::BLOCK_SIZE_MIN as u64 {
break;
}
f.seek(SeekFrom::Start(file_offset))
.map_err(VhdxIoError::ReadSectorBlock)?;
f.write_all(
&buf[write_count
..(write_count + (sector.free_sectors * SECTOR_SIZE) as usize)],
)
.map_err(VhdxIoError::ReadSectorBlock)?;
}
vhdx_bat::PAYLOAD_BLOCK_FULLY_PRESENT => {
if sector.file_offset < vhdx_metadata::BLOCK_SIZE_MIN as u64 {
break;
}
f.seek(SeekFrom::Start(sector.file_offset))
.map_err(VhdxIoError::ReadSectorBlock)?;
f.write_all(
&buf[write_count
..(write_count + (sector.free_sectors * SECTOR_SIZE) as usize)],
)
.map_err(VhdxIoError::ReadSectorBlock)?;
}
vhdx_bat::PAYLOAD_BLOCK_PARTIALLY_PRESENT => {
return Err(VhdxIoError::UnsupportedMode);
}
_ => {
return Err(VhdxIoError::InvalidBatEntryState);
}
};
sector_count -= sector.free_sectors;
sector_index += sector.free_sectors;
write_count = sector.free_bytes as usize;
let bat_entry = match bat.get(sector.bat_index as usize) {
Some(entry) => entry.0,
None => {
return Err(VhdxIoError::InvalidBatIndex);
}
};
match bat_entry & vhdx_bat::BAT_STATE_BIT_MASK {
vhdx_bat::PAYLOAD_BLOCK_NOT_PRESENT
| vhdx_bat::PAYLOAD_BLOCK_UNDEFINED
| vhdx_bat::PAYLOAD_BLOCK_UNMAPPED
| vhdx_bat::PAYLOAD_BLOCK_ZERO => {
let file_offset =
align!(disk_spec.image_size, vhdx_metadata::BLOCK_SIZE_MIN as u64);
let new_size = file_offset
.checked_add(disk_spec.block_size as u64)
.ok_or(VhdxIoError::InvalidDiskSize)?;
f.set_len(new_size).map_err(VhdxIoError::ResizeFile)?;
disk_spec.image_size = new_size;
let new_bat_entry = file_offset
| (vhdx_bat::PAYLOAD_BLOCK_FULLY_PRESENT & vhdx_bat::BAT_STATE_BIT_MASK);
bat[sector.bat_index as usize] = BatEntry(new_bat_entry);
BatEntry::write_bat_entries(f, bat_offset, bat).map_err(VhdxIoError::WriteBat)?;
if file_offset < vhdx_metadata::BLOCK_SIZE_MIN as u64 {
break;
}
f.seek(SeekFrom::Start(file_offset))
.map_err(VhdxIoError::ReadSectorBlock)?;
f.write_all(
&buf[write_count..(write_count + (sector.free_sectors * SECTOR_SIZE) as usize)],
)
.map_err(VhdxIoError::ReadSectorBlock)?;
}
vhdx_bat::PAYLOAD_BLOCK_FULLY_PRESENT => {
if sector.file_offset < vhdx_metadata::BLOCK_SIZE_MIN as u64 {
break;
}
f.seek(SeekFrom::Start(sector.file_offset))
.map_err(VhdxIoError::ReadSectorBlock)?;
f.write_all(
&buf[write_count..(write_count + (sector.free_sectors * SECTOR_SIZE) as usize)],
)
.map_err(VhdxIoError::ReadSectorBlock)?;
}
vhdx_bat::PAYLOAD_BLOCK_PARTIALLY_PRESENT => {
return Err(VhdxIoError::UnsupportedMode);
}
_ => {
return Err(VhdxIoError::InvalidBatEntryState);
}
};
sector_count -= sector.free_sectors;
sector_index += sector.free_sectors;
write_count += sector.free_bytes as usize;
}
Ok(write_count)
}

View File

@@ -55,6 +55,8 @@ const METADATA_LENGTH_MAX: u32 = 1 << 20; // 1 MiB
pub enum VhdxMetadataError {
#[error("Invalid block size count")]
InvalidBlockSize,
#[error("Invalid disk size {0}")]
InvalidDiskSize(u64),
#[error("Invalid metadata entry count")]
InvalidEntryCount,
#[error("Invalid logical sector size")]
@@ -214,6 +216,14 @@ impl DiskSpec {
if metadata_presence != METADATA_ALL_PRESENT {
return Err(VhdxMetadataError::MissingMetadata);
}
// Make sure virtual disk size is not zero
if (metadata_presence & METADATA_VIRTUAL_DISK_SIZE_PRESENT != 0)
&& disk_spec.virtual_disk_size == 0
{
return Err(VhdxMetadataError::InvalidDiskSize(
disk_spec.virtual_disk_size,
));
}
// Check if the virtual disk size is a multiple of the logical sector
// size.
if ((metadata_presence & METADATA_LOGICAL_SECTOR_SIZE_PRESENT) != 0)
@@ -257,7 +267,7 @@ impl DiskSpec {
}
}
#[repr(packed)]
#[repr(C, packed)]
#[derive(Default, Debug, Clone, Copy)]
struct MetadataTableHeader {
signature: u64,
@@ -288,7 +298,7 @@ impl MetadataTableHeader {
}
}
#[repr(packed)]
#[repr(C, packed)]
#[derive(Default, Debug, Clone, Copy)]
pub struct MetadataTableEntry {
item_id: Uuid,

View File

@@ -4,11 +4,14 @@
use std::collections::VecDeque;
use std::fs::File;
use std::os::fd::AsRawFd;
use std::sync::{Arc, Mutex, MutexGuard};
use vmm_sys_util::eventfd::EventFd;
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
use crate::async_io::{
AsyncIo, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
};
use crate::vhdx::{Result as VhdxResult, Vhdx};
use crate::AsyncAdaptor;
@@ -35,6 +38,11 @@ impl DiskFile for VhdxDiskSync {
as Box<dyn AsyncIo>,
)
}
fn fd(&mut self) -> BorrowedDiskFd {
let lock = self.vhdx_file.lock().unwrap();
BorrowedDiskFd::new(lock.as_raw_fd())
}
}
pub struct VhdxSync {

View File

@@ -3,6 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
use std::env;
use std::process::Command;
fn main() {
@@ -12,10 +13,18 @@ fn main() {
if git_out.status.success() {
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
version = git_out_str;
// Pop the trailing newline.
version.pop();
}
}
}
// Append CH_EXTRA_VERSION to version if it is set.
if let Ok(extra_version) = env::var("CH_EXTRA_VERSION") {
println!("cargo:rerun-if-env-changed=CH_EXTRA_VERSION");
version.push_str(&format!("-{extra_version}"));
}
// This println!() has a special behavior, as it will set the environment
// variable BUILD_VERSION, so that it can be reused from the binary.
// Particularly, this is used from src/main.rs to display the exact

View File

@@ -6,18 +6,18 @@ version = "0.1.0"
[dependencies]
acpi_tables = { workspace = true }
anyhow = "1.0.87"
anyhow = "1.0.94"
arch = { path = "../arch" }
bitflags = "2.6.0"
bitflags = "2.9.0"
byteorder = "1.5.0"
event_monitor = { path = "../event_monitor" }
hypervisor = { path = "../hypervisor" }
libc = "0.2.158"
libc = "0.2.167"
log = "0.4.22"
num_enum = "0.7.2"
pci = { path = "../pci" }
serde = { version = "1.0.208", features = ["derive"] }
thiserror = "1.0.62"
thiserror = "2.0.6"
tpm = { path = "../tpm" }
vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" }
@@ -29,9 +29,10 @@ vm-memory = { workspace = true, features = [
vm-migration = { path = "../vm-migration" }
vmm-sys-util = { workspace = true }
[target.'cfg(target_arch = "aarch64")'.dependencies]
[target.'cfg(any(target_arch = "aarch64", target_arch = "riscv64"))'.dependencies]
arch = { path = "../arch" }
[features]
default = []
kvm = ["arch/kvm"]
pvmemcontrol = []

144
devices/src/aia.rs Normal file
View File

@@ -0,0 +1,144 @@
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
// Copyright 2020, ARM Limited.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use super::interrupt_controller::{Error, InterruptController};
extern crate arch;
use std::result;
use std::sync::{Arc, Mutex};
use arch::layout;
use hypervisor::arch::riscv64::aia::{Vaia, VaiaConfig};
use hypervisor::{AiaState, CpuState};
use vm_device::interrupt::{
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
LegacyIrqSourceConfig, MsiIrqGroupConfig,
};
use vm_memory::address::Address;
use vm_migration::{Migratable, Pausable, Snapshottable, Transportable};
use vmm_sys_util::eventfd::EventFd;
type Result<T> = result::Result<T, Error>;
// Reserve 32 IRQs for legacy devices.
pub const IRQ_LEGACY_BASE: usize = layout::IRQ_BASE as usize;
pub const IRQ_LEGACY_COUNT: usize = 32;
// TODO: AIA snapshotting is not yet completed.
pub const _AIA_SNAPSHOT_ID: &str = "";
// Aia (Advance Interrupt Architecture) struct provides all the functionality of a
// AIA device. It wraps a hypervisor-emulated AIA device (Vaia) provided by the
// `hypervisor` crate.
// Aia struct also implements InterruptController to provide interrupt delivery
// service.
pub struct Aia {
interrupt_source_group: Arc<dyn InterruptSourceGroup>,
// The hypervisor agnostic virtual AIA
vaia: Arc<Mutex<dyn Vaia>>,
}
impl Aia {
pub fn new(
vcpu_count: u8,
interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
vm: Arc<dyn hypervisor::Vm>,
) -> Result<Aia> {
let interrupt_source_group = interrupt_manager
.create_group(MsiIrqGroupConfig {
base: IRQ_LEGACY_BASE as InterruptIndex,
count: IRQ_LEGACY_COUNT as InterruptIndex,
})
.map_err(Error::CreateInterruptSourceGroup)?;
let vaia = vm
.create_vaia(Aia::create_default_config(vcpu_count as u64))
.map_err(Error::CreateAia)?;
let aia = Aia {
interrupt_source_group,
vaia,
};
aia.enable()?;
Ok(aia)
}
pub fn restore_vaia(
&mut self,
state: Option<AiaState>,
_saved_vcpu_states: &[CpuState],
) -> Result<()> {
self.vaia
.clone()
.lock()
.unwrap()
.set_state(&state.unwrap())
.map_err(Error::RestoreAia)
}
fn enable(&self) -> Result<()> {
// Set irqfd for legacy interrupts
self.interrupt_source_group
.enable()
.map_err(Error::EnableInterrupt)?;
// Set irq_routing for legacy interrupts.
// irqchip: Hardcode to 0 as we support only 1 APLIC
// pin: Use irq number as pin
for i in IRQ_LEGACY_BASE..(IRQ_LEGACY_BASE + IRQ_LEGACY_COUNT) {
let config = LegacyIrqSourceConfig {
irqchip: 0,
pin: (i - IRQ_LEGACY_BASE) as u32,
};
self.interrupt_source_group
.update(
i as InterruptIndex,
InterruptSourceConfig::LegacyIrq(config),
false,
false,
)
.map_err(Error::EnableInterrupt)?;
}
self.interrupt_source_group
.set_gsi()
.map_err(Error::EnableInterrupt)?;
Ok(())
}
/// Default config implied by arch::layout
pub fn create_default_config(vcpu_count: u64) -> VaiaConfig {
VaiaConfig {
vcpu_count: vcpu_count as u32,
aplic_addr: layout::APLIC_START.raw_value(),
imsic_addr: layout::IMSIC_START.raw_value(),
nr_irqs: layout::IRQ_NUM,
}
}
pub fn get_vaia(&mut self) -> Result<Arc<Mutex<dyn Vaia>>> {
Ok(self.vaia.clone())
}
}
impl InterruptController for Aia {
// This should be called anytime an interrupt needs to be injected into the
// running guest.
fn service_irq(&mut self, irq: usize) -> Result<()> {
self.interrupt_source_group
.trigger(irq as InterruptIndex)
.map_err(Error::TriggerInterrupt)?;
Ok(())
}
fn notifier(&self, irq: usize) -> Option<EventFd> {
self.interrupt_source_group.notifier(irq as InterruptIndex)
}
}
impl Snapshottable for Aia {}
impl Pausable for Aia {}
impl Transportable for Aia {}
impl Migratable for Aia {}

View File

@@ -9,8 +9,8 @@ use std::sync::{Arc, Mutex};
use anyhow::anyhow;
use arch::layout;
use hypervisor::arch::aarch64::gic::{Vgic, VgicConfig};
use hypervisor::{CpuState, GicState};
use hypervisor::arch::aarch64::gic::{GicState, Vgic, VgicConfig};
use hypervisor::CpuState;
use vm_device::interrupt::{
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
LegacyIrqSourceConfig, MsiIrqGroupConfig,

View File

@@ -1,3 +1,4 @@
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
// Copyright 2020, ARM Limited.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
@@ -17,30 +18,38 @@ pub enum Error {
InvalidDeliveryMode,
/// Failed creating the interrupt source group.
#[error("Failed creating the interrupt source group: {0}")]
CreateInterruptSourceGroup(io::Error),
CreateInterruptSourceGroup(#[source] io::Error),
/// Failed triggering the interrupt.
#[error("Failed triggering the interrupt: {0}")]
TriggerInterrupt(io::Error),
TriggerInterrupt(#[source] io::Error),
/// Failed masking the interrupt.
#[error("Failed masking the interrupt: {0}")]
MaskInterrupt(io::Error),
MaskInterrupt(#[source] io::Error),
/// Failed unmasking the interrupt.
#[error("Failed unmasking the interrupt: {0}")]
UnmaskInterrupt(io::Error),
UnmaskInterrupt(#[source] io::Error),
/// Failed updating the interrupt.
#[error("Failed updating the interrupt: {0}")]
UpdateInterrupt(io::Error),
UpdateInterrupt(#[source] io::Error),
/// Failed enabling the interrupt.
#[error("Failed enabling the interrupt: {0}")]
EnableInterrupt(io::Error),
EnableInterrupt(#[source] io::Error),
#[cfg(target_arch = "aarch64")]
/// Failed creating GIC device.
#[error("Failed creating GIC device: {0}")]
CreateGic(hypervisor::HypervisorVmError),
CreateGic(#[source] hypervisor::HypervisorVmError),
#[cfg(target_arch = "aarch64")]
/// Failed restoring GIC device.
#[error("Failed restoring GIC device: {0}")]
RestoreGic(hypervisor::arch::aarch64::gic::Error),
RestoreGic(#[source] hypervisor::arch::aarch64::gic::Error),
#[cfg(target_arch = "riscv64")]
/// Failed creating AIA device.
#[error("Failed creating AIA device: {0}")]
CreateAia(#[source] hypervisor::HypervisorVmError),
#[cfg(target_arch = "riscv64")]
/// Failed restoring AIA device.
#[error("Failed restoring AIA device: {0}")]
RestoreAia(#[source] hypervisor::arch::riscv64::aia::Error),
}
type Result<T> = result::Result<T, Error>;
@@ -67,7 +76,7 @@ pub struct MsiMessage {
// Introduce trait InterruptController to uniform the interrupt
// service provided for devices.
// Device manager uses this trait without caring whether it is a
// IOAPIC (X86) or GIC (Arm).
// IOAPIC (X86), GIC (Arm) or AIA (RISC-V).
pub trait InterruptController: Send {
fn service_irq(&mut self, irq: usize) -> Result<()>;
#[cfg(target_arch = "x86_64")]

View File

@@ -346,9 +346,9 @@ impl Ioapic {
// Generate MSI message address
let low_addr: u32 = self.apic_address.0 as u32
| u32::from(destination_id) << 12
| u32::from(redirection_hint) << 3
| u32::from(destination_mode) << 2;
| (u32::from(destination_id) << 12)
| (u32::from(redirection_hint) << 3)
| (u32::from(destination_mode) << 2);
// Validate Trigger Mode value
let trigger_mode = trigger_mode(entry);
@@ -372,9 +372,9 @@ impl Ioapic {
}
// Generate MSI message data
let data: u32 = u32::from(trigger_mode) << 15
| u32::from(remote_irr(entry)) << 14
| u32::from(delivery_mode) << 8
let data: u32 = (u32::from(trigger_mode) << 15)
| (u32::from(remote_irr(entry)) << 14)
| (u32::from(delivery_mode) << 8)
| u32::from(vector(entry));
let config = MsiIrqSourceConfig {
@@ -418,7 +418,7 @@ impl InterruptController for Ioapic {
self.interrupt_source_group
.trigger(irq as InterruptIndex)
.map_err(Error::TriggerInterrupt)?;
debug!("Interrupt {irq} successfully delivered");
trace!("Interrupt {irq} successfully delivered");
// If trigger mode is level sensitive, set the Remote IRR bit.
// It will be cleared when the EOI is received.

View File

@@ -152,7 +152,7 @@ impl BusDevice for Cmos {
0x08 => to_bcd(month as u8),
0x09 => to_bcd((year % 100) as u8),
// Bit 5 for 32kHz clock. Bit 7 for Update in Progress
0x0a => 1 << 5 | (update_in_progress as u8) << 7,
0x0a => (1 << 5) | ((update_in_progress as u8) << 7),
// Bit 0-6 are reserved and must be 0.
// Bit 7 must be 1 (CMOS has power)
0x0d => 1 << 7,

View File

@@ -43,11 +43,11 @@ const N_GPIOS: u32 = 8;
pub enum Error {
#[error("Bad Write Offset: {0}")]
BadWriteOffset(u64),
#[error("GPIO interrupt disabled by guest driver.")]
#[error("GPIO interrupt disabled by guest driver")]
GpioInterruptDisabled,
#[error("Could not trigger GPIO interrupt: {0}.")]
GpioInterruptFailure(io::Error),
#[error("Invalid GPIO Input key triggered: {0}.")]
#[error("Could not trigger GPIO interrupt: {0}")]
GpioInterruptFailure(#[source] io::Error),
#[error("Invalid GPIO Input key triggered: {0}")]
GpioTriggerKeyFailure(u32),
}

View File

@@ -46,7 +46,7 @@ pub enum Error {
#[error("Bad Write Offset: {0}")]
BadWriteOffset(u64),
#[error("Failed to trigger interrupt: {0}")]
InterruptFailure(io::Error),
InterruptFailure(#[source] io::Error),
}
type Result<T> = result::Result<T, Error>;

View File

@@ -51,14 +51,14 @@ const AMBA_ID_HIGH: u64 = 0x401;
pub enum Error {
#[error("pl011_write: Bad Write Offset: {0}")]
BadWriteOffset(u64),
#[error("pl011: DMA not implemented.")]
#[error("pl011: DMA not implemented")]
DmaNotImplemented,
#[error("Failed to trigger interrupt: {0}")]
InterruptFailure(io::Error),
InterruptFailure(#[source] io::Error),
#[error("Failed to write: {0}")]
WriteAllFailure(io::Error),
WriteAllFailure(#[source] io::Error),
#[error("Failed to flush: {0}")]
FlushFailure(io::Error),
FlushFailure(#[source] io::Error),
}
type Result<T> = result::Result<T, Error>;

View File

@@ -15,6 +15,8 @@ extern crate event_monitor;
extern crate log;
pub mod acpi;
#[cfg(target_arch = "riscv64")]
pub mod aia;
#[cfg(target_arch = "x86_64")]
pub mod debug_console;
#[cfg(target_arch = "aarch64")]
@@ -26,6 +28,8 @@ pub mod legacy;
#[cfg(feature = "pvmemcontrol")]
pub mod pvmemcontrol;
pub mod pvpanic;
// TODO: TPM is not yet supported
#[cfg(not(target_arch = "riscv64"))]
pub mod tpm;
pub use self::acpi::{AcpiGedDevice, AcpiPmTimerDevice, AcpiShutdownDevice};

View File

@@ -484,7 +484,7 @@ impl PvmemcontrolBusDevice {
}
fn set_vma_anon_name(&self, addr: u64, length: u64, name: u64) -> result::Result<(), Error> {
let name = (name != 0).then(|| CString::new(format!("pvmemcontrol-{}", name)).unwrap());
let name = (name != 0).then(|| CString::new(format!("pvmemcontrol-{name}")).unwrap());
let name_ptr = if let Some(name) = &name {
name.as_ptr()
} else {
@@ -698,17 +698,19 @@ impl PciDevice for PvmemcontrolPciDevice {
reg_idx: usize,
offset: u64,
data: &[u8],
) -> Option<Arc<Barrier>> {
self.configuration
.write_config_register(reg_idx, offset, data);
None
) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>) {
(
self.configuration
.write_config_register(reg_idx, offset, data),
None,
)
}
fn read_config_register(&mut self, reg_idx: usize) -> u32 {
self.configuration.read_config_register(reg_idx)
}
fn as_any(&mut self) -> &mut dyn std::any::Any {
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
@@ -716,14 +718,6 @@ impl PciDevice for PvmemcontrolPciDevice {
Some(self.id.clone())
}
fn detect_bar_reprogramming(
&mut self,
reg_idx: usize,
data: &[u8],
) -> Option<BarReprogrammingParams> {
self.configuration.detect_bar_reprogramming(reg_idx, data)
}
fn allocate_bars(
&mut self,
_allocator: &Arc<Mutex<SystemAllocator>>,

View File

@@ -88,7 +88,11 @@ impl PvPanicDevice {
);
let command: [u8; 2] = [0x03, 0x01];
configuration.write_config_register(1, 0, &command);
let bar_reprogram = configuration.write_config_register(1, 0, &command);
assert!(
bar_reprogram.is_empty(),
"No bar reprogrammig is expected from writing to the COMMAND register"
);
let state: Option<PvPanicDeviceState> = snapshot
.as_ref()
@@ -156,24 +160,18 @@ impl PciDevice for PvPanicDevice {
reg_idx: usize,
offset: u64,
data: &[u8],
) -> Option<Arc<Barrier>> {
self.configuration
.write_config_register(reg_idx, offset, data);
None
) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>) {
(
self.configuration
.write_config_register(reg_idx, offset, data),
None,
)
}
fn read_config_register(&mut self, reg_idx: usize) -> u32 {
self.configuration.read_reg(reg_idx)
}
fn detect_bar_reprogramming(
&mut self,
reg_idx: usize,
data: &[u8],
) -> Option<BarReprogrammingParams> {
self.configuration.detect_bar_reprogramming(reg_idx, data)
}
fn allocate_bars(
&mut self,
_allocator: &Arc<Mutex<SystemAllocator>>,
@@ -237,7 +235,7 @@ impl PciDevice for PvPanicDevice {
data[0] = self.events;
}
fn as_any(&mut self) -> &mut dyn Any {
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}

View File

@@ -1,6 +1,7 @@
# AMD SEV-SNP
### WARNING
This feature is only currently supported on MSHV.
AMD Secure Encrypted Virtualization & Secure Nested Paging (SEV-SNP) is an AMD
@@ -9,8 +10,8 @@ malicious hypervisor-based attacks like data replay, memory-remapping and more
in order to create an isolated execution environment. Here are some useful
links:
* [SNP Homepage] (https://www.amd.com/en/processors/amd-secure-encrypted-virtualization)
more information about SEV-SNP technical aspects, design and specification.
- [SNP Homepage](https://www.amd.com/content/dam/amd/en/documents/epyc-business-docs/solution-briefs/amd-secure-encrypted-virtualization-solution-brief.pdf):
more information about SEV-SNP technical aspects, design and specification.
## Cloud Hypervisor support

View File

@@ -50,17 +50,12 @@ for more details about the API payloads and responses.
#### REST API Location and availability
The REST API is available as soon as the Cloud Hypervisor binary is started,
through a local UNIX socket.
By default, it is located at `/run/user/{user ID}/cloud-hypervisor.{Cloud Hypervisor PID}`.
For example, if you launched Cloud Hypervisor as user ID 1000 and its PID is
123456, the Cloud Hypervisor REST API will be available at `/run/user/1000/cloud-hypervisor.123456`.
The REST API default URL can be overridden through the Cloud Hypervisor
option `--api-socket`:
The REST API, if enabled, is available as soon as the Cloud Hypervisor binary is started,
through either a local UNIX socket as given in the Cloud Hypervisor option `--api-socket path=...`
or a fd with `--api-socket fd=...`.
```
$ ./target/debug/cloud-hypervisor --api-socket /tmp/cloud-hypervisor.sock
$ ./target/debug/cloud-hypervisor --api-socket path=/tmp/cloud-hypervisor.sock
Cloud Hypervisor Guest
API server: /tmp/cloud-hypervisor.sock
vCPUs: 1

View File

@@ -1,8 +1,9 @@
# `cloud-hypervisor` debug IO ports
When running x86 guests, `cloud-hypervisor` provides different kinds of debug ports:
- [`0x80` debug port](https://www.intel.com/content/www/us/en/support/articles/000005500/boards-and-kits.html)
- Debug console (by default at `0xe9`).
- [`0x80` debug port](https://web.archive.org/web/20211028033025/https://www.intel.com/content/www/us/en/support/articles/000005500/boards-and-kits.html)
- Debug console (by default at `0xe9`).
- Firmware debug port at `0x402`.
All of them can be used to trace user-defined guest events and all of them can
@@ -25,13 +26,13 @@ for debugging specific components of the guest software stack. When logging a
write of one of those codes to the debug port, `cloud-hypervisor` adds a
pre-defined string to the logs.
| Code Range | Component | Log string |
| ---------------- | ----------- | ------------ |
| `0x00` to `0x1f` | Firmware | `Firmware` |
| `0x20` to `0x3f` | Bootloader | `Bootloader` |
| `0x40` to `0x5f` | Kernel | `Kernel` |
| `0x60` to `0x7f` | Userspace | `Userspace` |
| `0x80` to `0xff` | Custom | `Custom` |
| Code Range | Component | Log string |
| ---------------- | ---------- | ------------ |
| `0x00` to `0x1f` | Firmware | `Firmware` |
| `0x20` to `0x3f` | Bootloader | `Bootloader` |
| `0x40` to `0x5f` | Kernel | `Kernel` |
| `0x60` to `0x7f` | Userspace | `Userspace` |
| `0x80` to `0xff` | Custom | `Custom` |
One typical use case is guest boot time measurement and tracing. By writing
different values to the debug I/O port at different boot process steps, the
@@ -71,8 +72,8 @@ cloud-hypervisor: 403.499628ms: DEBUG:vmm/src/vm.rs:510 -- [Debug I/O port: Firm
### Debug console port
The debug console is inspired by QEMU and Bochs, which have a similar feature.
By default, the I/O port `0xe9` is used. This port can be configured like a
The debug console is inspired by QEMU and Bochs, which have a similar feature.
By default, the I/O port `0xe9` is used. This port can be configured like a
console. Thus, it can print to a tty, a file, or a pty, for example.
### Firmware debug port
@@ -83,7 +84,7 @@ it. The firmware debug port only prints to stdout.
## When do I need these ports?
The ports are on the one hand interesting for firmware or kernel developers, as
they provide an easy way to print debug information from within a guest.
they provide an easy way to print debug information from within a guest.
Furthermore, you can patch "normal" software to measure certain events, such as
the boot time of a guest.
@@ -91,6 +92,6 @@ the boot time of a guest.
The `0x80` debug port and the port of the firmware debug device are always
available. The debug console must be activated via the command line, but
provides more configuration options.
provides more configuration options.
You can use different ports for different aspect of your logging messages.
You can use different ports for different aspect of your logging messages.

View File

@@ -8,11 +8,12 @@ the host kernel. The required Linux and KVM changes can be found in the
[KVM SGX Tree](https://github.com/intel/kvm-sgx).
Utilizing SGX in the guest requires a kernel/OS with SGX support, e.g. a kernel
built using the [SGX Linux Development Tree](https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-sgx.git)
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.
For more information about SGX, please refer to the [SGX Homepage](https://software.intel.com/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).
For more information about SGX SDK and how to test SGX, please refer to the
following [instructions](https://github.com/intel/linux-sgx).

View File

@@ -4,21 +4,21 @@ Intel® Trust Domain Extensions (Intel® TDX) is an Intel technology designed to
isolate virtual machines from the VMM, hypervisor and any other software on the
host platform. Here are some useful links:
* [TDX Homepage](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-trust-domain-extensions.html):
more information about TDX technical aspects, design and specification
- [TDX Homepage](https://www.intel.com/content/www/us/en/developer/tools/trust-domain-extensions/overview.html):
more information about TDX technical aspects, design and specification
* [KVM TDX tree](https://github.com/intel/tdx/tree/kvm): the required
- [KVM TDX tree](https://github.com/intel/tdx/tree/kvm): the required
Linux kernel changes for the host side
* [Guest TDX tree](https://github.com/intel/tdx/tree/guest): the Linux
- [Guest TDX tree](https://github.com/intel/tdx/tree/guest): the Linux
kernel changes for the guest side
* [EDK2 project](https://github.com/tianocore/edk2): the TDVF firmware
- [EDK2 project](https://github.com/tianocore/edk2): the TDVF firmware
* [Confidential Containers project](https://github.com/confidential-containers/td-shim):
- [Confidential Containers project](https://github.com/confidential-containers/td-shim):
the TDShim firmware
* [TDX Tools](https://github.com/intel/tdx-tools): a collection of tools
- [TDX Linux](https://github.com/intel/tdx-linux): a collection of tools
and scripts to setup TDX environment for testing purpose (such as
installing required packages on the host, creating guest images, and
building the custom Linux kernel for TDX host and guest)
@@ -27,17 +27,13 @@ more information about TDX technical aspects, design and specification
It is required to use a machine with TDX enabled in hardware and
with the host OS compiled from the [KVM TDX tree](https://github.com/intel/tdx/tree/kvm).
The host environment can also be setup with the [TDX Tools](https://github.com/intel/tdx-tools).
The host environment can also be setup with the [TDX Linux](https://github.com/intel/tdx-linux).
Cloud Hypervisor can run TDX VM (Trust Domain) by loading a TD firmware ([TDVF](https://github.com/tianocore/edk2)),
which will then load the guest kernel from the image. The image must be custom
as it must include a kernel built from the [Guest TDX tree](https://github.com/intel/tdx/tree/guest).
Cloud Hypervisor can also boot a TDX VM with direct kernel boot using [TDshim](https://github.com/confidential-containers/td-shim).
The custom Linux kernel for the guest can be built with the [TDX Tools](https://github.com/intel/tdx-tools).
> **Note**
> The latest version of custom host and guest kernel being tested is
> from [TDX Tools - 2023ww01](https://github.com/intel/tdx-tools/commits/2023ww01).
The custom Linux kernel for the guest can be built with the [TDX Linux](https://github.com/intel/tdx-linux).
### TDVF
@@ -110,6 +106,7 @@ direct kernel boot, which is useful for containers use cases.
To build TDShim from source, it is required to install `Rust`, `NASM`,
and `LLVM` first. The TDshim can be build as follows:
```bash
git clone https://github.com/confidential-containers/td-shim
cd td-shim
@@ -126,13 +123,14 @@ cargo image --release
If debug logs from the TDShim is needed, here are the alternative
commands:
```bash
cargo image
```
And run a TDX VM by providing the firmware previously built, along with a guest
kernel built from the [Guest TDX tree](https://github.com/intel/tdx/tree/guest)
or the [TDX Tools](https://github.com/intel/tdx-tools).
or the [TDX Linux](https://github.com/intel/tdx-linux).
The appropriate kernel boot options must be provided through the `--cmdline`
option as well.

View File

@@ -1,7 +1,7 @@
# I/O Throttling
Cloud Hypervisor now supports I/O throttling on virtio-block and virtio-net
devices. This support is based on the [`rate-limiter` module](https://github.com/firecracker-microvm/firecracker/tree/master/src/rate_limiter)
devices. This support is based on the [`rate-limiter` module](https://github.com/firecracker-microvm/firecracker/tree/7a1231b141e958d15d5b2c079dd5e0880528b4b0/src/rate_limiter)
from Firecracker. This document explains the user interface of this
feature, and highlights some internal implementations that can help users
better understand the expected behavior of I/O throttling in practice.
@@ -44,10 +44,12 @@ generally advisable to keep `bw/ops_refill_time` larger than `100 ms`
expectation ("refill-rate").
## Rate Limit Groups
It is possible to throttle the aggregate bandwidth or operations
of multiple virtio-blk devices using a `rate_limit_group`. virtio-blk devices may be
dynamically added and removed from a `rate_limit_group`. The following example
demonstrates how to throttle the aggregate bandwidth of two disks to 10 MiB/s.
```
--disk path=disk0.raw,rate_limit_group=group0 \
path=disk1.raw,rate_limit_group=group0 \

View File

@@ -1,16 +1,19 @@
# Live Migration
This document gives two examples of how to use the live migration
support in Cloud Hypervisor:
This document gives examples of how to use the live migration support
in Cloud Hypervisor:
1. local migration - migrating between two VMs running on the same
machine;
1. nested-vm migration - migrating between two nested VMs whose host VMs
are running on the same machine.
1. local migration - migrating a VM from one Cloud Hypervisor instance to another on the same machine;
1. remote migration - migrating a VM between two machines;
> :warning: These examples place sockets /tmp. This is done for
> simplicity and should not be done in production.
## Local Migration (Suitable for Live Upgrade of VMM)
Launch the source VM (on the host machine):
```bash
```console
$ target/release/cloud-hypervisor
--kernel ~/workloads/vmlinux \
--disk path=~/workloads/focal.raw \
@@ -20,17 +23,20 @@ $ target/release/cloud-hypervisor
```
Launch the destination VM from the same directory (on the host machine):
```bash
```console
$ target/release/cloud-hypervisor --api-socket=/tmp/api2
```
Get ready for receiving migration for the destination VM (on the host machine):
```bash
```console
$ target/release/ch-remote --api-socket=/tmp/api2 receive-migration unix:/tmp/sock
```
Start to send migration for the source VM (on the host machine):
```bash
```console
$ target/release/ch-remote --api-socket=/tmp/api1 send-migration --local unix:/tmp/sock
```
@@ -38,102 +44,139 @@ When the above commands completed, the source VM should be successfully
migrated to the destination VM. Now the destination VM is running while
the source VM is terminated gracefully.
## Nested-VM Migration
## Remote Migration
Launch VM 1 (on the host machine) with an extra virtio-blk device for
exposing a guest image for the nested source VM:
> Note: the example below also attached an additional virtio-blk device
> with a dummy image for testing purpose (which is optional).
```bash
$ head -c 1M < /dev/urandom > tmp.img # create a dummy image for testing
$ sudo /target/release/cloud-hypervisor \
In this example, we will migrate a VM from one machine (`src`) to
another (`dst`) across the network. To keep it simple, we will use a
minimal VM setup without storage.
### Preparation
Make sure that `src` and `dst` can reach each other via the
network. You should be able to ping each machine. Also each machine
should have an open TCP port.
You will need a kernel and initramfs for a minimal Linux system. For
this example, we will use the Debian netboot image.
Place the kernel and initramfs into the _same directory_ on both
machines. This is important for the migration to succeed. We will use
`/var/images`:
```console
src $ export DEBIAN=https://ftp.debian.org/debian/dists/stable/main/installer-amd64/current/images/netboot/debian-installer/amd64
src $ mkdir -p /var/images
src $ curl $DEBIAN/linux > /var/images/linux
src $ curl $DEBIAN/initrd.gz > /var/images/initrd
```
Repeat the above steps on the destination host.
### Unix Socket Migration
If Unix socket is selected for migration, we can tunnel traffic through "socat".
#### Starting the Receiver VM
On the receiver side, we prepare an empty VM:
```console
dst $ cloud-hypervisor --api-socket /tmp/api
```
In a different terminal, configure the VM as a migration target:
```console
dst $ ch-remote --api-socket=/tmp/api receive-migration unix:/tmp/sock
```
In yet another terminal, forward TCP connections to the Unix domain socket:
```console
dst $ socat TCP-LISTEN:{port},reuseaddr UNIX-CLIENT:/tmp/sock
```
#### Starting the Sender VM
Let's start the VM on the source machine:
```console
src $ cloud-hypervisor \
--serial tty --console off \
--cpus boot=1 --memory size=512M \
--kernel vmlinux \
--cmdline "root=/dev/vda1 console=ttyS0" \
--disk path=focal-1.raw path=focal-nested.raw path=tmp.img\
--net ip=192.168.101.1
--cpus boot=2 --memory size=4G \
--kernel /var/images/linux \
--initramfs /var/images/initrd \
--cmdline "console=ttyS0" \
--api-socket /tmp/api
```
Launch VM 2 (on the host machine) with an extra virtio-blk device for
exposing the same guest image for the nested destination VM:
```bash
$ sudo /target/release/cloud-hypervisor \
After a few seconds the VM should be up and you can interact with it.
#### Performing the Migration
First, we start `socat`:
```console
src $ socat UNIX-LISTEN:/tmp/sock,reuseaddr TCP:{dst}:{port}
```
> Replace {dst}:{port} with the actual IP address and port of your destination host.
Then we kick-off the migration itself:
```console
src $ ch-remote --api-socket=/tmp/api send-migration unix:/tmp/sock
```
When the above commands completed, the VM should be successfully
migrated to the destination machine without interrupting the workload.
### TCP Socket Migration
If TCP socket is selected for migration, we need to consider migrating
in a trusted network.
#### Starting the Receiver VM
On the receiver side, we prepare an empty VM:
```console
dst $ cloud-hypervisor --api-socket /tmp/api
```
In a different terminal, prepare to receive the migration:
```console
dst $ ch-remote --api-socket=/tmp/api receive-migration tcp:0.0.0.0:{port}
```
#### Starting the Sender VM
Let's start the VM on the source machine:
```console
src $ cloud-hypervisor \
--serial tty --console off \
--cpus boot=1 --memory size=512M \
--kernel vmlinux \
--cmdline "root=/dev/vda1 console=ttyS0" \
--disk path=focal-2.raw path=focal-nested.raw path=tmp.img\
--net ip=192.168.102.1
--cpus boot=2 --memory size=4G \
--kernel /var/images/linux \
--initramfs /var/images/initrd \
--cmdline "console=ttyS0" \
--api-socket /tmp/api
```
Launch the nested source VM (inside the guest OS of the VM 1) :
```bash
vm-1:~$ sudo ./cloud-hypervisor \
--serial tty --console off \
--memory size=128M \
--kernel vmlinux \
--cmdline "console=ttyS0 root=/dev/vda1" \
--disk path=/dev/vdb path=/dev/vdc \
--api-socket=/tmp/api1 \
--net ip=192.168.100.1
vm-1:~$ # setup the guest network if needed
vm-1:~$ sudo ip addr add 192.168.101.2/24 dev ens4
vm-1:~$ sudo ip link set up dev ens4
vm-1:~$ sudo ip r add default via 192.168.101.1
```
Optional: Run the guest workload below (on the guest OS of the nested source VM),
which performs intensive virtio-blk operations. Now the console of the nested
source VM should repeatedly print `"equal"`, and our goal is migrating
this VM and the running workload without interruption.
```bash
#/bin/bash
After a few seconds the VM should be up and you can interact with it.
# On the guest OS of the nested source VM
#### Performing the Migration
input="/dev/vdb"
result=$(md5sum $input)
tmp=$(md5sum $input)
Initiate the Migration over TCP:
while [[ "$result" == "$tmp" ]]
do
echo "equal"
tmp=$(md5sum $input)
done
echo "not equal"
echo "result = $result"
echo "tmp = $tmp"
```console
src $ ch-remote --api-socket=/tmp/api send-migration tcp:{dst}:{port}
```
Launch the nested destination VM (inside the guest OS of the VM 2):
```bash
vm-2:~$ sudo ./cloud-hypervisor --api-socket=/tmp/api2
vm-2:~$ # setup the guest network with the following commands if needed
vm-2:~$ sudo ip addr add 192.168.102.2/24 dev ens4
vm-2:~$ sudo ip link set up dev ens4
vm-2:~$ sudo ip r add default via 192.168.102.1
vm-2:~$ ping 192.168.101.2 # This should succeed
```
> Note: If the above ping failed, please check the iptables rule on the
> host machine, e.g. whether the policy for the `FORWARD` chain is set
> to `DROP` (which is the default setting configured by Docker).
> Replace {dst}:{port} with the actual IP address and port of your destination host.
Get ready for receiving migration for the nested destination VM (inside
the guest OS of the VM 2):
```bash
vm-2:~$ sudo ./ch-remote --api-socket=/tmp/api2 receive-migration unix:/tmp/sock2
vm-2:~$ sudo socat TCP-LISTEN:6000,reuseaddr UNIX-CLIENT:/tmp/sock2
```
Start to send migration for the nested source VM (inside the guest OS of
the VM 1):
```bash
vm-1:~$ sudo socat UNIX-LISTEN:/tmp/sock1,reuseaddr TCP:192.168.102.2:6000
vm-1:~$ sudo ./ch-remote --api-socket=/tmp/api1 send-migration unix:/tmp/sock1
```
When the above commands completed, the source VM should be successfully
migrated to the destination VM without interrupting our testing guest
workload. Now the destination VM is running the testing guest workload
while the source VM is terminated gracefully.
After completing the above commands, the source VM will be migrated to
the destination host and continue running there. The source VM instance
will terminate normally. All ongoing processes and connections within
the VM should remain intact after the migration.

View File

@@ -2,8 +2,8 @@
The target audience of this document is both:
* Developers who want to understand what log level to use and when,
* Users who want to debug issues with running their workloads in Cloud Hypervisor
- Developers who want to understand what log level to use and when,
- Users who want to debug issues with running their workloads in Cloud Hypervisor
## Control
@@ -29,7 +29,6 @@ A typical example of where this level of message should be generated is during a
The user should investigate the meaning of this warning and take steps to ensure the correct functionality.
### `info!()`
Use `-v` to enable.
@@ -40,4 +39,4 @@ This level is for the benefit of developers. It should be used for sporadic and
Use `-vv` to enable.
For the most verbose of logging messages. It is acceptable to "spam" the log with repeated invocations of the same message. This level of logging would be combined with `--log-file`.
For the most verbose of logging messages. It is acceptable to "spam" the log with repeated invocations of the same message. This level of logging would be combined with `--log-file`.

168
docs/riscv.md Normal file
View File

@@ -0,0 +1,168 @@
# How to build and test Cloud Hypervisor on riscv64
This document introduces how to build and test Cloud Hypervisor on `riscv64`.
All instructions here are tested with Ubuntu 24.04.2 as the host OS.
## Hardware requirements
- riscv64 servers (recommended) or development boards equipped with the AIA
(Advance Interrupt Architecture) interrupt controller.
## Getting started
We create a folder to build and run Cloud Hypervisor at `$HOME/cloud-hypervisor`
```console
export CLOUDH=$HOME/cloud-hypervisor
mkdir $CLOUDH
```
## Prerequisites
You need to install some prerequisite packages to build and test Cloud Hypervisor.
### Tools
```console
# Install rust tool chain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Install the tools used for building guest kernel, EDK2 and converting guest disk
sudo apt-get update
sudo apt-get install git build-essential m4 bison flex uuid-dev qemu-utils
```
### Building Cloud Hypervisor
```console
pushd $CLOUDH
git clone https://github.com/cloud-hypervisor/cloud-hypervisor.git
cd cloud-hypervisor
cargo build
popd
```
### Disk image
Download the Ubuntu cloud image and convert the image type.
```console
pushd $CLOUDH
wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-riscv64.img
qemu-img convert -p -f qcow2 -O raw jammy-server-cloudimg-riscv64.img jammy-server-cloudimg-riscv64.raw
popd
```
## Direct-kernel booting
### Building kernel
```console
pushd $CLOUDH
git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b ch-6.12.8
cd linux
make ch_defconfig
make -j `nproc`
popd
```
### Booting the guest VM
```console
pushd $CLOUDH
sudo $CLOUDH/cloud-hypervisor/target/debug/cloud-hypervisor \
--kernel $CLOUDH/linux/arch/riscv64/boot/Image \
--disk path=jammy-server-cloudimg-riscv64.raw \
--cmdline "console=hvc0 root=/dev/vda rw" \
--cpus boot=1 \
--memory size=1024M \
--seccomp false \
--log-file boot.log -vv
popd
```
## Virtualized Development Setup
Since there are few RISC-V development boards on the market and not
many details about the AIA interrupt controller featured in product listings,
QEMU is a popular and viable choice for creating a RISC-V development environment.
Below are the steps used to create a QEMU virtual machine that can be used for
cloud-hypervisor RISC-V development:
### Install Dependencies
```console
sudo apt update
sudo apt install opensbi qemu-system-misc u-boot-qemu
```
### Download and Build QEMU (>=v9.2.0)
Older versions of QEMU may not have support for the AIA
interrupt controller.
```console
wget https://download.qemu.org/qemu-10.0.0.tar.xz
tar xvJf qemu-10.0.0.tar.xz
cd qemu-10.0.0
./configure --target-list=riscv64-softmmu
make -j $(nproc)
sudo make install
```
### Download Ubuntu Server Image
At the time of writing, the best results have been seen with
the Ubuntu 24.10 (Oracular) server image. Ex:
```console
wget https://cdimage.ubuntu.com/releases/oracular/release/ubuntu-24.10-preinstalled-server-riscv64.img.xz
xz -dk ubuntu-24.10-preinstalled-server-riscv64.img.xz
```
### (Optional) Resize Disk
If you would like a larger disk, you can resize it now.
```console
qemu-img resize -f raw <ubuntu-image> +5G
```
### Boot VM
Note the inclusion of the AIA interrupt controller in the
invocation.
```console
qemu-system-riscv64 \
-machine virt,aia=aplic-imsic \
-nographic -m 1G -smp 8 \
-kernel /usr/lib/u-boot/qemu-riscv64_smode/uboot.elf \
-device virtio-rng-pci \
-device virtio-net-device,netdev=eth0 -netdev user,id=eth0 \
-drive file=<ubuntu-image>,format=raw,if=virtio
```
### Install KVM Kernel Module Within VM
KVM is not enabled within the VM by default, so we must enable
it manually.
```console
sudo modprobe kvm
```
From this point, you can continue with the above steps from the beginning.
### Sources
https://risc-v-getting-started-guide.readthedocs.io/en/latest/linux-qemu.html
https://canonical-ubuntu-boards.readthedocs-hosted.com/en/latest/how-to/qemu-riscv/#using-the-live-server-image
https://www.qemu.org/docs/master/specs/riscv-aia.html
## Known limitations
- Direct kernel boot only
- `64-bit Linux` guest OS only
- For more details, see
[here](https://github.com/cloud-hypervisor/cloud-hypervisor/issues/6978).

View File

@@ -5,8 +5,8 @@ name = "event_monitor"
version = "0.1.0"
[dependencies]
flume = "0.11.0"
libc = "0.2.158"
flume = "0.11.1"
libc = "0.2.167"
once_cell = "1.20.2"
serde = { version = "1.0.208", features = ["derive", "rc"] }
serde_json = "1.0.120"
serde_json = { workspace = true }

309
fuzz/Cargo.lock generated
View File

@@ -1,13 +1,13 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "acpi_tables"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#ca1a473fe73cdd8eb49c1449faad7aaac06f32c2"
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#e08a3f0b0a59b98859dbf59f5aa7fd4d2eb4018a"
dependencies = [
"zerocopy",
"zerocopy 0.8.24",
]
[[package]]
@@ -61,15 +61,15 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.87"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]]
name = "arbitrary"
version = "1.3.2"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
[[package]]
name = "arc-swap"
@@ -89,7 +89,7 @@ dependencies = [
"linux-loader",
"log",
"serde",
"thiserror",
"thiserror 2.0.9",
"uuid",
"vm-fdt",
"vm-memory",
@@ -103,6 +103,17 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "bitfield-struct"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2be5a46ba01b60005ae2c51a36a29cfe134bcacae2dd5cedcd4615fbaad1494b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -111,9 +122,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.6.0"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "block"
@@ -126,7 +137,7 @@ dependencies = [
"remain",
"serde",
"smallvec",
"thiserror",
"thiserror 2.0.9",
"uuid",
"virtio-bindings",
"virtio-queue",
@@ -195,13 +206,16 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
name = "cloud-hypervisor-fuzz"
version = "0.0.0"
dependencies = [
"arbitrary",
"block",
"devices",
"epoll",
"hypervisor",
"libc",
"libfuzzer-sys",
"linux-loader",
"micro_http",
"mshv-bindings",
"net_util",
"once_cell",
"seccompiler",
@@ -288,7 +302,7 @@ dependencies = [
"acpi_tables",
"anyhow",
"arch",
"bitflags 2.6.0",
"bitflags 2.9.0",
"byteorder",
"event_monitor",
"hypervisor",
@@ -297,7 +311,7 @@ dependencies = [
"num_enum",
"pci",
"serde",
"thiserror",
"thiserror 2.0.9",
"tpm",
"vm-allocator",
"vm-device",
@@ -332,7 +346,7 @@ version = "4.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74351c3392ea1ff6cd2628e0042d268ac2371cb613252ff383b6dfa50d22fa79"
dependencies = [
"bitflags 2.6.0",
"bitflags 2.9.0",
"libc",
]
@@ -361,9 +375,9 @@ checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
[[package]]
name = "flume"
version = "0.11.0"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"
checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
dependencies = [
"futures-core",
"futures-sink",
@@ -395,7 +409,7 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbcc892208d6998fb57e7c3e05883def66f8130924bba066beb0cfe71566a9f6"
dependencies = [
"bitflags 2.6.0",
"bitflags 2.9.0",
"cfg-if",
"log",
"managed",
@@ -422,10 +436,22 @@ dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
"wasm-bindgen",
]
[[package]]
name = "getrandom"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
dependencies = [
"cfg-if",
"libc",
"wasi 0.13.3+wasi-0.2.2",
"windows-targets",
]
[[package]]
name = "hashbrown"
version = "0.14.5"
@@ -437,19 +463,35 @@ name = "hypervisor"
version = "0.1.0"
dependencies = [
"anyhow",
"arc-swap",
"bitfield-struct",
"byteorder",
"cfg-if",
"concat-idents",
"iced-x86",
"kvm-bindings",
"kvm-ioctls",
"libc",
"log",
"mshv-bindings",
"open-enum",
"serde",
"serde_json",
"serde_with",
"thiserror",
"thiserror 2.0.9",
"vfio-ioctls",
"vm-memory",
"vmm-sys-util",
"zerocopy 0.8.24",
]
[[package]]
name = "iced-x86"
version = "1.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c447cff8c7f384a7d4f741cfcff32f75f3ad02b406432e8d6c878d56b1edf6b"
dependencies = [
"lazy_static",
]
[[package]]
@@ -500,22 +542,22 @@ dependencies = [
[[package]]
name = "kvm-bindings"
version = "0.9.1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2efe3f1a4437bffe000e6297a593b98184213cd27486776c335f95ab53d48e3a"
checksum = "fa4933174d0cc4b77b958578cd45784071cc5ae212c2d78fbd755aaaa6dfa71a"
dependencies = [
"serde",
"vmm-sys-util",
"zerocopy",
"zerocopy 0.7.35",
]
[[package]]
name = "kvm-ioctls"
version = "0.18.0"
version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92c2176b91f68903b54ac8c6185bada7d607ca6110998976ff15c032f88a7d39"
checksum = "e013ae7fcd2c6a8f384104d16afe7ea02969301ea2bb2a56e44b011ebc907cab"
dependencies = [
"bitflags 2.6.0",
"bitflags 2.9.0",
"kvm-bindings",
"libc",
"vmm-sys-util",
@@ -529,14 +571,20 @@ checksum = "18738c5d4c7fae6727a96adb94722ef7ce82f3eafea0a11777e258a93816537e"
dependencies = [
"enumflags2",
"libc",
"thiserror",
"thiserror 1.0.64",
]
[[package]]
name = "libc"
version = "0.2.158"
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "libfuzzer-sys"
@@ -551,9 +599,9 @@ dependencies = [
[[package]]
name = "linux-loader"
version = "0.12.0"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d379d0089d0fbf4161c35a4fdfd76125923f1a93632c49195f5372b4c0b1472"
checksum = "870c3814345f050991f99869417779f6062542bcf4ed81db7a1b926ad1306638"
dependencies = [
"vm-memory",
]
@@ -589,19 +637,33 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "micro_http"
version = "0.1.0"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#8182cd5523b63ceb52ad9d0e7eb6fb95683e6d1b"
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#4f621532e81ee2ad096a9c9592fdacc40d19de48"
dependencies = [
"libc",
"vmm-sys-util",
]
[[package]]
name = "mshv-bindings"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "577073a0abbf515d17bfe96ca2ce49c44a68454d4179e95ce1244e858a9ebd4e"
dependencies = [
"libc",
"num_enum",
"serde",
"serde_derive",
"vmm-sys-util",
"zerocopy 0.8.24",
]
[[package]]
name = "nanorand"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
dependencies = [
"getrandom",
"getrandom 0.2.15",
]
[[package]]
@@ -616,13 +678,13 @@ name = "net_util"
version = "0.1.0"
dependencies = [
"epoll",
"getrandom",
"getrandom 0.3.1",
"libc",
"log",
"net_gen",
"rate_limiter",
"serde",
"thiserror",
"thiserror 2.0.9",
"virtio-bindings",
"virtio-queue",
"vm-memory",
@@ -662,9 +724,29 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.19.0"
version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "open-enum"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb2508143a400b3361812094d987dd5adc81f0f5294a46491be648d6c94cab5"
dependencies = [
"open-enum-derive",
]
[[package]]
name = "open-enum-derive"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d1296fab5231654a5aec8bf9e87ba4e3938c502fc4c3c0425a00084c78944be"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "option_parser"
@@ -686,7 +768,7 @@ dependencies = [
"libc",
"log",
"serde",
"thiserror",
"thiserror 2.0.9",
"vfio-bindings",
"vfio-ioctls",
"vfio_user",
@@ -703,7 +785,7 @@ version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy",
"zerocopy 0.7.35",
]
[[package]]
@@ -717,9 +799,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.86"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
@@ -735,20 +817,20 @@ dependencies = [
[[package]]
name = "rand"
version = "0.8.5"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
"zerocopy 0.8.24",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
@@ -756,11 +838,11 @@ dependencies = [
[[package]]
name = "rand_core"
version = "0.6.4"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom",
"getrandom 0.3.1",
]
[[package]]
@@ -770,7 +852,7 @@ dependencies = [
"epoll",
"libc",
"log",
"thiserror",
"thiserror 2.0.9",
"vmm-sys-util",
]
@@ -799,9 +881,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "seccompiler"
version = "0.4.0"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "345a3e4dddf721a478089d4697b83c6c0a8f5bf16086f6c13397e4534eb6e2e5"
checksum = "a4ae55de56877481d112a559bbc12667635fdaf5e005712fd4e2b2fa50ffc884"
dependencies = [
"libc",
]
@@ -913,9 +995,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.77"
version = "2.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a"
dependencies = [
"proc-macro2",
"quote",
@@ -928,7 +1010,16 @@ version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
dependencies = [
"thiserror-impl",
"thiserror-impl 1.0.64",
]
[[package]]
name = "thiserror"
version = "2.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc"
dependencies = [
"thiserror-impl 2.0.9",
]
[[package]]
@@ -942,6 +1033,17 @@ dependencies = [
"syn",
]
[[package]]
name = "thiserror-impl"
version = "2.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "toml_datetime"
version = "0.6.8"
@@ -968,7 +1070,7 @@ dependencies = [
"libc",
"log",
"net_gen",
"thiserror",
"thiserror 2.0.9",
"vmm-sys-util",
]
@@ -997,20 +1099,20 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.10.0"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587"
dependencies = [
"getrandom",
"getrandom 0.3.1",
"rand",
"uuid-macro-internal",
]
[[package]]
name = "uuid-macro-internal"
version = "1.10.0"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee1cd046f83ea2c4e920d6ee9f7c3537ef928d75dce5d84a87c2c5d6b3999a3a"
checksum = "9521621447c21497fac206ffe6e9f642f977c4f82eeba9201055f64884d9cb01"
dependencies = [
"proc-macro2",
"quote",
@@ -1020,7 +1122,7 @@ dependencies = [
[[package]]
name = "vfio-bindings"
version = "0.4.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#a51a4746b0d317bfc21fa49d40f9287f3b8137fd"
source = "git+https://github.com/rust-vmm/vfio?branch=main#b135b8305c2cc8ec333e0cf77a780445cc98dcee"
dependencies = [
"vmm-sys-util",
]
@@ -1028,14 +1130,14 @@ dependencies = [
[[package]]
name = "vfio-ioctls"
version = "0.2.0"
source = "git+https://github.com/rust-vmm/vfio?branch=main#a51a4746b0d317bfc21fa49d40f9287f3b8137fd"
source = "git+https://github.com/rust-vmm/vfio?branch=main#b135b8305c2cc8ec333e0cf77a780445cc98dcee"
dependencies = [
"byteorder",
"kvm-bindings",
"kvm-ioctls",
"libc",
"log",
"thiserror",
"thiserror 1.0.64",
"vfio-bindings",
"vm-memory",
"vmm-sys-util",
@@ -1044,7 +1146,7 @@ dependencies = [
[[package]]
name = "vfio_user"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#bf7d7e851b604d8414a7960fb9137b59fc42421d"
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#3febcdd3fa2531623865663ca1721e1962ed9979"
dependencies = [
"bitflags 1.3.2",
"libc",
@@ -1052,7 +1154,7 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"thiserror",
"thiserror 1.0.64",
"vfio-bindings",
"vm-memory",
"vmm-sys-util",
@@ -1060,11 +1162,10 @@ dependencies = [
[[package]]
name = "vhost"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c1c4c6c9f79fbe3150d9a403008ca416d34c489897effdda28b646f09900aad"
version = "0.12.1"
source = "git+https://github.com/rust-vmm/vhost?rev=d983ae0#d983ae07f78663b7d24059667376992460b571a2"
dependencies = [
"bitflags 2.6.0",
"bitflags 2.9.0",
"libc",
"uuid",
"vm-memory",
@@ -1073,9 +1174,9 @@ dependencies = [
[[package]]
name = "virtio-bindings"
version = "0.2.3"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68d0df4f5ad79b1dc81b5913ac737e24a84dcd5100f36ed953a1faec18aba241"
checksum = "1711e61c00f8cb450bd15368152a1e37a12ef195008ddc7d0f4812f9e2b30a68"
[[package]]
name = "virtio-devices"
@@ -1098,7 +1199,7 @@ dependencies = [
"serde_json",
"serde_with",
"serial_buffer",
"thiserror",
"thiserror 2.0.9",
"vhost",
"virtio-bindings",
"virtio-queue",
@@ -1112,9 +1213,9 @@ dependencies = [
[[package]]
name = "virtio-queue"
version = "0.13.0"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb1761348d3b5e82131379b9373435b48dc8333100bff3f1cdf9cc541a0ad83"
checksum = "872e2f3fbd70a7e6f01689720cce3d5c2c5efe52b484dd07b674246ada0e9a8d"
dependencies = [
"log",
"virtio-bindings",
@@ -1138,7 +1239,7 @@ dependencies = [
"anyhow",
"hypervisor",
"serde",
"thiserror",
"thiserror 2.0.9",
"vfio-ioctls",
"vm-memory",
"vmm-sys-util",
@@ -1147,17 +1248,17 @@ dependencies = [
[[package]]
name = "vm-fdt"
version = "0.3.0"
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#982fb8d9c8cd7f53520d7e304b39ff307fa3a641"
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#ef5bd734f5f66fb07722d766981adbc915f0d941"
[[package]]
name = "vm-memory"
version = "0.15.0"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a320fc11792e063174402ff444aa3c80363cbf1e31c47b5ef74124406c334ce6"
checksum = "f1720e7240cdc739f935456eb77f370d7e9b2a3909204da1e2b47bef1137a013"
dependencies = [
"arc-swap",
"libc",
"thiserror",
"thiserror 1.0.64",
"winapi",
]
@@ -1168,7 +1269,7 @@ dependencies = [
"anyhow",
"serde",
"serde_json",
"thiserror",
"thiserror 2.0.9",
"vm-memory",
]
@@ -1189,7 +1290,7 @@ dependencies = [
"anyhow",
"arc-swap",
"arch",
"bitflags 2.6.0",
"bitflags 2.9.0",
"block",
"cfg-if",
"clap",
@@ -1215,7 +1316,7 @@ dependencies = [
"serde_json",
"serial_buffer",
"signal-hook",
"thiserror",
"thiserror 2.0.9",
"tracer",
"uuid",
"vfio-ioctls",
@@ -1228,7 +1329,7 @@ dependencies = [
"vm-migration",
"vm-virtio",
"vmm-sys-util",
"zerocopy",
"zerocopy 0.8.24",
]
[[package]]
@@ -1249,6 +1350,15 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasi"
version = "0.13.3+wasi-0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.93"
@@ -1408,6 +1518,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
dependencies = [
"bitflags 2.9.0",
]
[[package]]
name = "zerocopy"
version = "0.7.35"
@@ -1415,7 +1534,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
"zerocopy-derive 0.7.35",
]
[[package]]
name = "zerocopy"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
dependencies = [
"zerocopy-derive 0.8.24",
]
[[package]]
@@ -1428,3 +1556,14 @@ dependencies = [
"quote",
"syn",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View File

@@ -9,24 +9,29 @@ version = "0.0.0"
cargo-fuzz = true
[features]
default = ["mshv_emulator"]
igvm = []
mshv_emulator = ["hypervisor/mshv_emulator"]
pvmemcontrol = []
[dependencies]
arbitrary = "1.4.1"
block = { path = "../block" }
devices = { path = "../devices" }
epoll = "4.3.3"
hypervisor = { path = "../hypervisor", features = ["mshv_emulator"] }
libc = "0.2.155"
libfuzzer-sys = "0.4.7"
linux-loader = { version = "0.12.0", features = ["bzimage", "elf", "pe"] }
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"
net_util = { path = "../net_util" }
once_cell = "1.19.0"
seccompiler = "0.4.0"
seccompiler = "0.5.0"
virtio-devices = { path = "../virtio-devices" }
virtio-queue = "0.13.0"
virtio-queue = "0.14.0"
vm-device = { path = "../vm-device" }
vm-memory = "0.15.0"
vm-memory = "0.16.0"
vm-migration = { path = "../vm-migration" }
vm-virtio = { path = "../vm-virtio" }
vmm = { path = "../vmm", features = ["guest_debug"] }
@@ -126,8 +131,21 @@ name = "vhdx"
path = "fuzz_targets/vhdx.rs"
test = false
[[bin]]
doc = false
name = "vsock"
path = "fuzz_targets/vsock.rs"
test = false
[[bin]]
doc = false
name = "watchdog"
path = "fuzz_targets/watchdog.rs"
test = false
[[bin]]
doc = false
name = "x86emul"
path = "fuzz_targets/x86emul.rs"
required-features = ["mshv_emulator"]
test = false

View File

@@ -7,7 +7,7 @@
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::Arc;
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
use seccompiler::SeccompAction;
use virtio_devices::{VirtioDevice, VirtioInterrupt, VirtioInterruptType};
use virtio_queue::{Queue, QueueT};
@@ -37,11 +37,11 @@ const AVAIL_RING_SIZE: u64 = 6_u64 + 2 * QUEUE_SIZE as u64;
// Used ring size
const USED_RING_SIZE: u64 = 6_u64 + 8 * QUEUE_SIZE as u64;
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
if bytes.len() < QUEUE_DATA_SIZE * QUEUE_NUM
|| bytes.len() > (QUEUE_DATA_SIZE * QUEUE_NUM + MEM_SIZE)
{
return;
return Corpus::Reject;
}
let mut balloon = virtio_devices::Balloon::new(
@@ -61,7 +61,7 @@ fuzz_target!(|bytes| {
// Setup the guest memory with the input bytes
let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM_SIZE)]).unwrap();
if mem.write_slice(mem_bytes, GuestAddress(0 as u64)).is_err() {
return;
return Corpus::Reject;
}
let guest_memory = GuestMemoryAtomic::new(mem);
@@ -108,6 +108,8 @@ fuzz_target!(|bytes| {
// Wait for the events to finish and balloon device worker thread to return
balloon.wait_for_epoll_threads();
Corpus::Keep
});
pub struct NoopVirtioInterrupt {}

View File

@@ -17,7 +17,7 @@ use std::{ffi, io};
use block::async_io::DiskFile;
use block::raw_sync::RawFileDiskSync;
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
use seccompiler::SeccompAction;
use virtio_devices::{Block, VirtioDevice, VirtioInterrupt, VirtioInterruptType};
use virtio_queue::{Queue, QueueT};
@@ -40,9 +40,9 @@ const AVAIL_RING_SIZE: u64 = 6_u64 + 2 * QUEUE_SIZE as u64;
// Guest physical address for used ring (requires to 4-bytes aligned)
const USED_RING_ADDR: u64 = (AVAIL_RING_ADDR + AVAIL_RING_SIZE + 3) & !3_u64;
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
if bytes.len() < QUEUE_DATA_SIZE || bytes.len() > (QUEUE_DATA_SIZE + MEM_SIZE) {
return;
return Corpus::Reject;
}
let queue_data = &bytes[..QUEUE_DATA_SIZE];
@@ -76,7 +76,7 @@ fuzz_target!(|bytes| {
// Setup the guest memory with the input bytes
let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM_SIZE)]).unwrap();
if mem.write_slice(mem_bytes, GuestAddress(0 as u64)).is_err() {
return;
return Corpus::Reject;
}
let guest_memory = GuestMemoryAtomic::new(mem);
@@ -96,6 +96,8 @@ fuzz_target!(|bytes| {
// Wait for the events to finish and block device worker thread to return
block.wait_for_epoll_threads();
Corpus::Keep
});
fn memfd_create(name: &ffi::CStr, flags: u32) -> Result<RawFd, io::Error> {

View File

@@ -5,14 +5,14 @@
#![no_main]
use devices::legacy::Cmos;
use libc::EFD_NONBLOCK;
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
use vm_device::BusDevice;
use vmm_sys_util::eventfd::EventFd;
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
// Need at least 16 bytes for the test
if bytes.len() < 16 {
return;
return Corpus::Reject;
}
let mut below_4g = [0u8; 8];
@@ -46,4 +46,6 @@ fuzz_target!(|bytes| {
cmos.write(0, offset, &data);
}
}
Corpus::Keep
});

View File

@@ -9,7 +9,7 @@ use std::io::Write;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::sync::Arc;
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
use seccompiler::SeccompAction;
use virtio_devices::{VirtioDevice, VirtioInterrupt, VirtioInterruptType};
use virtio_queue::{Queue, QueueT};
@@ -54,12 +54,12 @@ const QUEUE_BYTES_SIZE: usize = align!(
DESC_TABLE_ALIGN_SIZE
) as usize;
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
if bytes.len() < (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE) * QUEUE_NUM + CONSOLE_INPUT_SIZE
|| bytes.len()
> (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE) * QUEUE_NUM + CONSOLE_INPUT_SIZE + MEM_SIZE
{
return;
return Corpus::Reject;
}
let (pipe_rx, mut pipe_tx) = create_pipe().unwrap();
@@ -108,10 +108,10 @@ fuzz_target!(|bytes| {
.write_slice(queue_bytes, GuestAddress(BASE_VIRT_QUEUE_ADDR))
.is_err()
{
return;
return Corpus::Reject;
}
if mem.write_slice(mem_bytes, GuestAddress(0 as u64)).is_err() {
return;
return Corpus::Reject;
}
let guest_memory = GuestMemoryAtomic::new(mem);
@@ -137,6 +137,8 @@ fuzz_target!(|bytes| {
// Wait for the events to finish and console device worker thread to return
console.wait_for_epoll_threads();
Corpus::Keep
});
pub struct NoopVirtioInterrupt {}

View File

@@ -8,7 +8,7 @@ use std::path::PathBuf;
use std::sync::mpsc::{channel, Receiver};
use std::thread;
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
use micro_http::Request;
use once_cell::sync::Lazy;
use vm_migration::MigratableError;
@@ -27,9 +27,9 @@ use vmm_sys_util::eventfd::EventFd;
static ROUTES: Lazy<Vec<&Box<dyn EndpointHandler + Sync + Send>>> =
Lazy::new(|| HTTP_ROUTES.routes.values().collect());
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
if bytes.len() < 2 {
return;
return Corpus::Reject;
}
let route = ROUTES[bytes[0] as usize % ROUTES.len()];
@@ -53,6 +53,8 @@ fuzz_target!(|bytes| {
exit_evt.write(1).ok();
http_receiver_thread.join().unwrap();
};
Corpus::Keep
});
fn generate_request(bytes: &[u8]) -> Option<Request> {

View File

@@ -7,7 +7,7 @@
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::Arc;
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
use seccompiler::SeccompAction;
use virtio_devices::{VirtioDevice, VirtioInterrupt, VirtioInterruptType};
use virtio_queue::{Queue, QueueT};
@@ -54,11 +54,11 @@ const USED_RING_ADDR: u64 = align!(AVAIL_RING_ADDR + AVAIL_RING_SIZE, USED_RING_
// Virtio-queue size in bytes
const QUEUE_BYTES_SIZE: usize = (USED_RING_ADDR + USED_RING_SIZE - DESC_TABLE_ADDR) as usize;
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
if bytes.len() < (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE)
|| bytes.len() > (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE + MEM_SIZE)
{
return;
return Corpus::Reject;
}
let (mut iommu, _) = virtio_devices::Iommu::new(
@@ -66,6 +66,7 @@ fuzz_target!(|bytes| {
SeccompAction::Allow,
EventFd::new(EFD_NONBLOCK).unwrap(),
((MEM_SIZE - IOVA_SPACE_SIZE) as u64, (MEM_SIZE - 1) as u64),
64,
None,
)
.unwrap();
@@ -91,10 +92,10 @@ fuzz_target!(|bytes| {
.write_slice(queue_bytes, GuestAddress(DESC_TABLE_ADDR))
.is_err()
{
return;
return Corpus::Reject;
}
if mem.write_slice(mem_bytes, GuestAddress(0 as u64)).is_err() {
return;
return Corpus::Reject;
}
let guest_memory = GuestMemoryAtomic::new(mem);
@@ -118,6 +119,8 @@ fuzz_target!(|bytes| {
// Wait for the events to finish and vIOMMU device worker thread to return
iommu.wait_for_epoll_threads();
Corpus::Keep
});
pub struct NoopVirtioInterrupt {}

View File

@@ -8,7 +8,7 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
use vm_memory::bitmap::AtomicBitmap;
use vm_memory::GuestAddress;
@@ -18,7 +18,7 @@ const MEM_SIZE: usize = 256 * 1024 * 1024;
// From 'arch::x86_64::layout::CMDLINE_START'
const CMDLINE_START: GuestAddress = GuestAddress(0x20000);
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
let payload_config = vmm::vm_config::PayloadConfig {
firmware: None,
kernel: None,
@@ -29,9 +29,11 @@ fuzz_target!(|bytes| {
};
let kernel_cmdline = match vmm::vm::Vm::generate_cmdline(&payload_config) {
Ok(cmdline) => cmdline,
_ => return,
_ => return Corpus::Reject,
};
let guest_memory = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM_SIZE)]).unwrap();
linux_loader::loader::load_cmdline(&guest_memory, CMDLINE_START, &kernel_cmdline).ok();
Corpus::Keep
});

View File

@@ -7,7 +7,7 @@
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::{Arc, Mutex};
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
use seccompiler::SeccompAction;
use virtio_devices::{BlocksState, Mem, VirtioDevice, VirtioInterrupt, VirtioInterruptType};
use virtio_queue::{Queue, QueueT};
@@ -57,11 +57,11 @@ const USED_RING_ADDR: u64 = align!(AVAIL_RING_ADDR + AVAIL_RING_SIZE, USED_RING_
// Virtio-queue size in bytes
const QUEUE_BYTES_SIZE: usize = (USED_RING_ADDR + USED_RING_SIZE - DESC_TABLE_ADDR) as usize;
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
if bytes.len() < VIRTIO_MEM_DATA_SIZE + QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE
|| bytes.len() > (VIRTIO_MEM_DATA_SIZE + QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE + MEM_SIZE)
{
return;
return Corpus::Reject;
}
let virtio_mem_data = &bytes[..VIRTIO_MEM_DATA_SIZE];
@@ -86,7 +86,7 @@ fuzz_target!(|bytes| {
.write_slice(queue_bytes, GuestAddress(DESC_TABLE_ADDR))
.is_err()
{
return;
return Corpus::Reject;
}
// Add the memory region for the virtio-mem device
let mem = mem.insert_region(virtio_mem_region).unwrap();
@@ -94,7 +94,7 @@ fuzz_target!(|bytes| {
.write_slice(mem_bytes, GuestAddress(VIRTIO_MEM_REGION_ADDRESS))
.is_err()
{
return;
return Corpus::Reject;
}
let guest_memory = GuestMemoryAtomic::new(mem);
@@ -114,6 +114,8 @@ fuzz_target!(|bytes| {
// Wait for the events to finish and virtio-mem device worker thread to return
virtio_mem.wait_for_epoll_threads();
return Corpus::Keep;
});
pub struct NoopVirtioInterrupt {}

View File

@@ -9,7 +9,7 @@ use std::io::{Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::Arc;
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
use seccompiler::SeccompAction;
use virtio_devices::{VirtioDevice, VirtioInterrupt, VirtioInterruptType};
use virtio_queue::{Queue, QueueT};
@@ -55,12 +55,12 @@ const QUEUE_BYTES_SIZE: usize = align!(
DESC_TABLE_ALIGN_SIZE
) as usize;
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
if bytes.len() < TAP_INPUT_SIZE + (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE) * QUEUE_NUM
|| bytes.len()
> TAP_INPUT_SIZE + (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE) * QUEUE_NUM + MEM_SIZE
{
return;
return Corpus::Reject;
}
let (dummy_tap_frontend, dummy_tap_backend) = create_socketpair().unwrap();
@@ -111,10 +111,10 @@ fuzz_target!(|bytes| {
.write_slice(queue_bytes, GuestAddress(BASE_VIRT_QUEUE_ADDR))
.is_err()
{
return;
return Corpus::Reject;
}
if mem.write_slice(mem_bytes, GuestAddress(0 as u64)).is_err() {
return;
return Corpus::Reject;
}
let guest_memory = GuestMemoryAtomic::new(mem);
@@ -155,6 +155,8 @@ fuzz_target!(|bytes| {
// Terminate the thread for the dummy tap backend
exit_evt.write(1).ok();
tap_backend_thread.join().unwrap();
return Corpus::Keep;
});
pub struct NoopVirtioInterrupt {}

View File

@@ -10,7 +10,7 @@ use std::sync::Arc;
use std::{ffi, io};
use libc::{MAP_NORESERVE, MAP_PRIVATE, PROT_READ, PROT_WRITE};
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
use seccompiler::SeccompAction;
use virtio_devices::{Pmem, UserspaceMapping, VirtioDevice, VirtioInterrupt, VirtioInterruptType};
use virtio_queue::{Queue, QueueT};
@@ -35,9 +35,9 @@ const AVAIL_RING_SIZE: u64 = 6_u64 + 2 * QUEUE_SIZE as u64;
// Guest physical address for used ring (requires to 4-bytes aligned)
const USED_RING_ADDR: u64 = (AVAIL_RING_ADDR + AVAIL_RING_SIZE + 3) & !3_u64;
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
if bytes.len() < QUEUE_DATA_SIZE || bytes.len() > (QUEUE_DATA_SIZE + MEM_SIZE) {
return;
return Corpus::Reject;
}
let mut pmem = create_dummy_pmem();
@@ -50,7 +50,7 @@ fuzz_target!(|bytes| {
// Setup the guest memory with the input bytes
let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM_SIZE)]).unwrap();
if mem.write_slice(mem_bytes, GuestAddress(0 as u64)).is_err() {
return;
return Corpus::Reject;
}
let guest_memory = GuestMemoryAtomic::new(mem);
@@ -69,6 +69,8 @@ fuzz_target!(|bytes| {
// Wait for the events to finish and pmem device worker thread to return
pmem.wait_for_epoll_threads();
Corpus::Keep
});
fn memfd_create_with_size(name: &ffi::CStr, flags: u32, size: usize) -> Result<RawFd, io::Error> {

View File

@@ -12,14 +12,14 @@ use std::mem::size_of;
use std::os::unix::io::{FromRawFd, RawFd};
use block::qcow::{QcowFile, RawFile};
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
// Take the first 64 bits of data as an address and the next 64 bits as data to
// store there. The rest of the data is used as a qcow image.
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
if bytes.len() < 16 {
// Need an address and data, each are 8 bytes.
return;
return Corpus::Reject;
}
let mut disk_image = Cursor::new(bytes);
let addr = read_u64(&mut disk_image);
@@ -33,6 +33,8 @@ fuzz_target!(|bytes| {
let _ = qcow.write_all(&value.to_le_bytes());
}
}
Corpus::Keep
});
fn read_u64<T: Read>(readable: &mut T) -> u64 {

View File

@@ -7,7 +7,7 @@
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::Arc;
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
use seccompiler::SeccompAction;
use virtio_devices::{VirtioDevice, VirtioInterrupt, VirtioInterruptType};
use virtio_queue::{Queue, QueueT};
@@ -52,11 +52,11 @@ const USED_RING_ADDR: u64 = align!(AVAIL_RING_ADDR + AVAIL_RING_SIZE, USED_RING_
// Virtio-queue size in bytes
const QUEUE_BYTES_SIZE: usize = (USED_RING_ADDR + USED_RING_SIZE - DESC_TABLE_ADDR) as usize;
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
if bytes.len() < (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE)
|| bytes.len() > (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE + MEM_SIZE)
{
return;
return Corpus::Reject;
}
let mut rng = virtio_devices::Rng::new(
@@ -86,10 +86,10 @@ fuzz_target!(|bytes| {
.write_slice(queue_bytes, GuestAddress(DESC_TABLE_ADDR))
.is_err()
{
return;
return Corpus::Reject;
}
if mem.write_slice(mem_bytes, GuestAddress(0 as u64)).is_err() {
return;
return Corpus::Reject;
}
let guest_memory = GuestMemoryAtomic::new(mem);
@@ -108,6 +108,8 @@ fuzz_target!(|bytes| {
// Wait for the events to finish and rng device worker thread to return
rng.wait_for_epoll_threads();
Corpus::Keep
});
pub struct NoopVirtioInterrupt {}

View File

@@ -9,38 +9,47 @@ use std::io::{self, Read, Seek, SeekFrom, Write};
use std::os::unix::io::{FromRawFd, RawFd};
use block::vhdx::Vhdx;
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
// Populate the corpus directory with a test file:
// truncate -s 16M /tmp/source
// qemu-img convert -O vhdx /tmp/source fuzz/corpus/vhdx/test.vhdx
// Run with:
// cargo fuzz run vhdx -j 32 -- -max_len=16777216
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap();
let mut disk_file: File = unsafe { File::from_raw_fd(shm) };
disk_file.write_all(&bytes[..]).unwrap();
disk_file.seek(SeekFrom::Start(0)).unwrap();
if let Ok(mut vhdx) = Vhdx::new(disk_file) {
if vhdx.seek(SeekFrom::Start(0)).is_ok() {
let mut offset = 0;
while offset < bytes.len() {
let mut data = vec![0; 8192];
vhdx.read_exact(&mut data).ok();
offset += data.len();
}
}
let mut vhdx = match Vhdx::new(disk_file) {
Ok(vhdx) => vhdx,
Err(_) => return Corpus::Reject,
};
if vhdx.seek(SeekFrom::Start(0)).is_ok() {
let mut offset = 0;
while offset < bytes.len() {
let data = vec![0; 8192];
vhdx.write_all(&data).ok();
offset += data.len();
}
}
if matches!(vhdx.seek(SeekFrom::Start(0)).is_err(), true) {
return Corpus::Reject;
};
let mut offset = 0;
while offset < bytes.len() {
let mut data = vec![0; 8192];
vhdx.read_exact(&mut data).ok();
offset += data.len();
}
if matches!(vhdx.seek(SeekFrom::Start(0)).is_err(), true) {
return Corpus::Reject;
};
offset = 0;
while offset < bytes.len() {
let data = vec![0; 8192];
vhdx.write_all(&data).ok();
offset += data.len();
}
Corpus::Keep
});
fn memfd_create(name: &ffi::CStr, flags: u32) -> Result<RawFd, io::Error> {

148
fuzz/fuzz_targets/vsock.rs Normal file
View File

@@ -0,0 +1,148 @@
// Copyright © 2025 Microsoft
//
// SPDX-License-Identifier: Apache-2.0
#![no_main]
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::Arc;
use libfuzzer_sys::{fuzz_target, Corpus};
use seccompiler::SeccompAction;
use virtio_devices::vsock::tests::TestBackend;
use virtio_devices::{VirtioDevice, VirtioInterrupt, VirtioInterruptType};
use virtio_queue::{Queue, QueueT};
use vm_memory::bitmap::AtomicBitmap;
use vm_memory::{Bytes, GuestAddress, GuestMemoryAtomic};
use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
use vmm_sys_util::tempdir::TempDir;
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
macro_rules! align {
($n:expr, $align:expr) => {{
$n.div_ceil($align) * $align
}};
}
const QUEUE_DATA_SIZE: usize = 4;
const MEM_SIZE: usize = 1 * 1024 * 1024;
// Max entries in the queue.
const QUEUE_SIZE: u16 = 256;
// Descriptor table alignment
const DESC_TABLE_ALIGN_SIZE: u64 = 16;
// Available ring alignment
const AVAIL_RING_ALIGN_SIZE: u64 = 2;
// Used ring alignment
const USED_RING_ALIGN_SIZE: u64 = 4;
// Descriptor table size
const DESC_TABLE_SIZE: u64 = 16_u64 * QUEUE_SIZE as u64;
// Available ring size
const AVAIL_RING_SIZE: u64 = 6_u64 + 2 * QUEUE_SIZE as u64;
// Used ring size
const USED_RING_SIZE: u64 = 6_u64 + 8 * QUEUE_SIZE as u64;
// Guest memory gap
const GUEST_MEM_GAP: u64 = 1 * 1024 * 1024;
// Guest physical address for descriptor table.
const DESC_TABLE_ADDR: u64 = align!(MEM_SIZE as u64 + GUEST_MEM_GAP, DESC_TABLE_ALIGN_SIZE);
// Guest physical address for available ring
const AVAIL_RING_ADDR: u64 = align!(DESC_TABLE_ADDR + DESC_TABLE_SIZE, AVAIL_RING_ALIGN_SIZE);
// Guest physical address for used ring
const USED_RING_ADDR: u64 = align!(AVAIL_RING_ADDR + AVAIL_RING_SIZE, USED_RING_ALIGN_SIZE);
// Virtio-queue size in bytes
const QUEUE_BYTES_SIZE: usize = (USED_RING_ADDR + USED_RING_SIZE - DESC_TABLE_ADDR) as usize;
fuzz_target!(|bytes: &[u8]| -> Corpus {
if bytes.len() < (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE)
|| bytes.len() > (QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE + MEM_SIZE)
{
return Corpus::Reject;
}
let queue_data = &bytes[..QUEUE_DATA_SIZE];
let queue_bytes = &bytes[QUEUE_DATA_SIZE..QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE];
let mem_bytes = &bytes[QUEUE_DATA_SIZE + QUEUE_BYTES_SIZE..];
let q = setup_virt_queue(queue_data.try_into().unwrap());
let tmp_dir = TempDir::new_with_prefix("/tmp/fuzz_virtio_vsock").unwrap();
let vsock_path = tmp_dir.as_path().join("vsock.sock");
let backend = TestBackend::new();
// Setup the guest memory with the input bytes
let mem = GuestMemoryMmap::from_ranges(&[
(GuestAddress(0), MEM_SIZE),
(GuestAddress(DESC_TABLE_ADDR), QUEUE_BYTES_SIZE),
])
.unwrap();
if mem
.write_slice(queue_bytes, GuestAddress(DESC_TABLE_ADDR))
.is_err()
{
return Corpus::Reject;
}
if mem.write_slice(mem_bytes, GuestAddress(0 as u64)).is_err() {
return Corpus::Reject;
}
let guest_memory = GuestMemoryAtomic::new(mem);
let evt = EventFd::new(0).unwrap();
let queue_evt = unsafe { EventFd::from_raw_fd(libc::dup(evt.as_raw_fd())) };
// Kick the 'queue' event before activate the rng device
queue_evt.write(1).unwrap();
let mut vsock = virtio_devices::Vsock::new(
"fuzzer_vsock".to_owned(),
0,
vsock_path,
backend,
false,
SeccompAction::Allow,
EventFd::new(EFD_NONBLOCK).unwrap(),
None,
)
.unwrap();
vsock
.activate(
guest_memory,
Arc::new(NoopVirtioInterrupt {}),
vec![(0, q, evt)],
)
.ok();
// Wait for the events to finish and vsock device worker thread to return
vsock.wait_for_epoll_threads();
Corpus::Keep
});
pub struct NoopVirtioInterrupt {}
impl VirtioInterrupt for NoopVirtioInterrupt {
fn trigger(&self, _int_type: VirtioInterruptType) -> std::result::Result<(), std::io::Error> {
Ok(())
}
}
fn setup_virt_queue(bytes: &[u8; QUEUE_DATA_SIZE]) -> Queue {
let mut q = Queue::new(QUEUE_SIZE).unwrap();
q.set_next_avail(bytes[0] as u16); // 'u8' is enough given the 'QUEUE_SIZE' is small
q.set_next_used(bytes[1] as u16);
q.set_event_idx(bytes[2] % 2 != 0);
q.set_size(bytes[3] as u16 % QUEUE_SIZE);
q.try_set_desc_table_address(GuestAddress(DESC_TABLE_ADDR))
.unwrap();
q.try_set_avail_ring_address(GuestAddress(AVAIL_RING_ADDR))
.unwrap();
q.try_set_used_ring_address(GuestAddress(USED_RING_ADDR))
.unwrap();
q.set_ready(true);
q
}

View File

@@ -7,7 +7,7 @@
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::Arc;
use libfuzzer_sys::fuzz_target;
use libfuzzer_sys::{fuzz_target, Corpus};
use seccompiler::SeccompAction;
use virtio_devices::{VirtioDevice, VirtioInterrupt, VirtioInterruptType};
use virtio_queue::{Queue, QueueT};
@@ -30,9 +30,9 @@ const AVAIL_RING_SIZE: u64 = 6_u64 + 2 * QUEUE_SIZE as u64;
// Guest physical address for used ring (requires to 4-bytes aligned)
const USED_RING_ADDR: u64 = (AVAIL_RING_ADDR + AVAIL_RING_SIZE + 3) & !3_u64;
fuzz_target!(|bytes| {
fuzz_target!(|bytes: &[u8]| -> Corpus {
if bytes.len() < QUEUE_DATA_SIZE || bytes.len() > (QUEUE_DATA_SIZE + MEM_SIZE) {
return;
return Corpus::Reject;
}
let mut watchdog = virtio_devices::Watchdog::new(
@@ -53,7 +53,7 @@ fuzz_target!(|bytes| {
// Setup the guest memory with the input bytes
let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM_SIZE)]).unwrap();
if mem.write_slice(mem_bytes, GuestAddress(0 as u64)).is_err() {
return;
return Corpus::Reject;
}
let guest_memory = GuestMemoryAtomic::new(mem);
@@ -73,6 +73,8 @@ fuzz_target!(|bytes| {
// Wait for the events to finish and watchdog device worker thread to return
watchdog.wait_for_epoll_threads();
Corpus::Keep
});
pub struct NoopVirtioInterrupt {}

View File

@@ -0,0 +1,153 @@
// Copyright © 2025 Microsoft Corporation
//
// SPDX-License-Identifier: Apache-2.0
#![no_main]
use hypervisor::arch::emulator::{PlatformEmulator, PlatformError};
use hypervisor::arch::x86::emulator::{Emulator, EmulatorCpuState};
use hypervisor::arch::x86::{DescriptorTable, SegmentRegister, SpecialRegisters};
use hypervisor::StandardRegisters;
use libfuzzer_sys::{fuzz_target, Corpus};
#[derive(Debug)]
struct EmulatorContext {
state: EmulatorCpuState,
memory: [u8; 8],
}
impl PlatformEmulator for EmulatorContext {
type CpuState = EmulatorCpuState;
fn read_memory(&self, _gva: u64, data: &mut [u8]) -> Result<(), PlatformError> {
data.copy_from_slice(&self.memory[..data.len()]);
Ok(())
}
fn write_memory(&mut self, _gva: u64, _data: &[u8]) -> Result<(), PlatformError> {
// Discard writes
Ok(())
}
fn cpu_state(&self, _cpu_id: usize) -> Result<Self::CpuState, PlatformError> {
Ok(self.state.clone())
}
fn set_cpu_state(&self, _cpu_id: usize, _state: Self::CpuState) -> Result<(), PlatformError> {
// Ignore
Ok(())
}
fn fetch(&self, _ip: u64, _data: &mut [u8]) -> Result<(), PlatformError> {
// The fuzzer already provides 16 bytes of data, we don't need to fetch anything
panic!("fetch should not be called");
}
}
fuzz_target!(|bytes: &[u8]| -> Corpus {
let (mut ctx, insn) = match generate_context_and_instruction(bytes) {
Ok((ctx, insn)) => (ctx, insn),
Err(_) => return Corpus::Reject,
};
let mut e = Emulator::new(&mut ctx);
if e.emulate_first_insn(0, &insn).is_err() {
return Corpus::Reject;
}
Corpus::Keep
});
// Helper functions to generate structures from fuzzer input below
fn generate_segment_register(
u: &mut arbitrary::Unstructured<'_>,
) -> arbitrary::Result<SegmentRegister> {
Ok(SegmentRegister {
base: u.arbitrary()?,
limit: u.arbitrary()?,
selector: u.arbitrary()?,
avl: u.arbitrary()?,
dpl: u.arbitrary()?,
db: u.arbitrary()?,
g: u.arbitrary()?,
l: u.arbitrary()?,
present: u.arbitrary()?,
s: u.arbitrary()?,
type_: u.arbitrary()?,
unusable: u.arbitrary()?,
})
}
fn generate_descriptor_table(
u: &mut arbitrary::Unstructured<'_>,
) -> arbitrary::Result<DescriptorTable> {
Ok(DescriptorTable {
base: u.arbitrary()?,
limit: u.arbitrary()?,
})
}
fn generate_context_and_instruction(
bytes: &[u8],
) -> arbitrary::Result<(EmulatorContext, [u8; 16])> {
let mut u = arbitrary::Unstructured::new(bytes);
let mut regs = mshv_bindings::StandardRegisters {
rax: u.arbitrary()?,
rbx: u.arbitrary()?,
rcx: u.arbitrary()?,
rdx: u.arbitrary()?,
rsi: u.arbitrary()?,
rdi: u.arbitrary()?,
rsp: u.arbitrary()?,
rbp: u.arbitrary()?,
r8: u.arbitrary()?,
r9: u.arbitrary()?,
r10: u.arbitrary()?,
r11: u.arbitrary()?,
r12: u.arbitrary()?,
r13: u.arbitrary()?,
r14: u.arbitrary()?,
r15: u.arbitrary()?,
rip: u.arbitrary()?,
rflags: u.arbitrary()?,
};
// Cap RCX to avoid looping for too long for reps instructions.
regs.rcx &= 0xFFFFu64;
let regs = StandardRegisters::Mshv(regs);
let sregs = SpecialRegisters {
cs: generate_segment_register(&mut u)?,
ds: generate_segment_register(&mut u)?,
es: generate_segment_register(&mut u)?,
fs: generate_segment_register(&mut u)?,
gs: generate_segment_register(&mut u)?,
ss: generate_segment_register(&mut u)?,
tr: generate_segment_register(&mut u)?,
ldt: generate_segment_register(&mut u)?,
gdt: generate_descriptor_table(&mut u)?,
idt: generate_descriptor_table(&mut u)?,
cr0: u.arbitrary()?,
cr2: u.arbitrary()?,
cr3: u.arbitrary()?,
cr4: u.arbitrary()?,
cr8: u.arbitrary()?,
efer: u.arbitrary()?,
apic_base: u.arbitrary()?,
interrupt_bitmap: u.arbitrary()?,
};
let memory = u.arbitrary::<[u8; 8]>()?;
let insn = u.arbitrary::<[u8; 16]>()?;
let ctx = EmulatorContext {
state: EmulatorCpuState { regs, sregs },
memory,
};
Ok((ctx, insn))
}

View File

@@ -7,38 +7,57 @@ version = "0.1.0"
[features]
kvm = ["kvm-bindings", "kvm-ioctls", "vfio-ioctls/kvm"]
mshv = ["iced-x86", "mshv-bindings", "mshv-ioctls", "vfio-ioctls/mshv"]
mshv = ["mshv-bindings", "mshv-ioctls", "mshv_emulator", "vfio-ioctls/mshv"]
mshv_emulator = ["iced-x86", "mshv-bindings"]
sev_snp = ["igvm", "igvm_defs"]
tdx = []
[dependencies]
anyhow = "1.0.87"
anyhow = "1.0.94"
arc-swap = "1.7.1"
bitfield-struct = "0.10.1"
byteorder = "1.5.0"
cfg-if = "1.0.0"
concat-idents = "1.1.5"
igvm = { version = "0.3.3", optional = true }
igvm_defs = { version = "0.3.1", optional = true }
igvm = { workspace = true, optional = true }
igvm_defs = { workspace = true, optional = true }
kvm-bindings = { workspace = true, optional = true, features = ["serde"] }
kvm-ioctls = { workspace = true, optional = true }
libc = "0.2.158"
libc = "0.2.167"
log = "0.4.22"
mshv-bindings = { workspace = true, features = [
"fam-wrappers",
"with-serde",
], optional = true }
mshv-ioctls = { workspace = true, optional = true }
open-enum = "0.5.2"
serde = { version = "1.0.208", features = ["derive", "rc"] }
serde_json = { workspace = true }
serde_with = { version = "3.9.0", default-features = false, features = [
"macros",
] }
thiserror = "1.0.62"
thiserror = "2.0.6"
vfio-ioctls = { workspace = true, default-features = false }
vm-memory = { workspace = true, features = ["backend-atomic", "backend-mmap"] }
vm-memory = { workspace = true, features = [
"backend-atomic",
"backend-bitmap",
"backend-mmap",
] }
vmm-sys-util = { workspace = true, features = ["with-serde"] }
zerocopy = { version = "0.8.24", features = ["derive"] }
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
default-features = false
features = ["decoder", "fast_fmt", "instr_info", "op_code_info", "std"]
features = [
"decoder",
"instr_info",
"no_d3now",
"no_evex",
"no_vex",
"no_xop",
"op_code_info",
"std",
]
optional = true
version = "1.21.0"

View File

@@ -5,22 +5,25 @@
use std::any::Any;
use std::result;
use serde::de::Error as SerdeError;
use serde::{Deserialize, Serialize};
use serde_json;
use thiserror::Error;
use crate::{CpuState, GicState, HypervisorDeviceError, HypervisorVmError};
use crate::{CpuState, HypervisorDeviceError, HypervisorVmError};
/// Errors thrown while setting up the VGIC.
#[derive(Debug, Error)]
pub enum Error {
/// Error while calling KVM ioctl for setting up the global interrupt controller.
#[error("Failed creating GIC device: {0}")]
CreateGic(HypervisorVmError),
CreateGic(#[source] HypervisorVmError),
/// Error while setting device attributes for the GIC.
#[error("Failed setting device attributes for the GIC: {0}")]
SetDeviceAttribute(HypervisorDeviceError),
SetDeviceAttribute(#[source] HypervisorDeviceError),
/// Error while getting device attributes for the GIC.
#[error("Failed getting device attributes for the GIC: {0}")]
GetDeviceAttribute(HypervisorDeviceError),
GetDeviceAttribute(#[source] HypervisorDeviceError),
}
pub type Result<T> = result::Result<T, Error>;
@@ -36,6 +39,56 @@ pub struct VgicConfig {
pub nr_irqs: u32,
}
#[derive(Clone, Serialize)]
pub enum GicState {
#[cfg(feature = "kvm")]
Kvm(crate::kvm::aarch64::gic::Gicv3ItsState),
#[cfg(feature = "mshv")]
MshvGicV2M(crate::mshv::aarch64::gic::MshvGicV2MState),
}
impl<'de> Deserialize<'de> for GicState {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
// GicStateDefaultDeserialize is a helper enum that mirrors GicState but also derives the Deserialize trait.
// This enables backward-compatible deserialization of GicState, facilitating live-upgrade scenarios.
#[derive(Deserialize)]
pub enum GicStateDefaultDeserialize {
#[cfg(feature = "kvm")]
Kvm(crate::kvm::aarch64::gic::Gicv3ItsState),
#[cfg(feature = "mshv")]
MshvGicV2M(crate::mshv::aarch64::gic::MshvGicV2MState),
}
const {
assert!(
std::mem::size_of::<GicStateDefaultDeserialize>()
== std::mem::size_of::<GicState>()
)
};
let value: serde_json::Value = Deserialize::deserialize(deserializer)?;
#[cfg(feature = "kvm")]
if let Ok(gicv3_its_state) =
crate::kvm::aarch64::gic::Gicv3ItsState::deserialize(value.clone())
{
return Ok(GicState::Kvm(gicv3_its_state));
}
if let Ok(gic_state_de) = GicStateDefaultDeserialize::deserialize(value.clone()) {
return match gic_state_de {
#[cfg(feature = "kvm")]
GicStateDefaultDeserialize::Kvm(state) => Ok(GicState::Kvm(state)),
#[cfg(feature = "mshv")]
GicStateDefaultDeserialize::MshvGicV2M(state) => Ok(GicState::MshvGicV2M(state)),
};
}
Err(SerdeError::custom("Failed to deserialize GicState"))
}
}
/// Hypervisor agnostic interface for a virtualized GIC
pub trait Vgic: Send + Sync {
/// Returns the fdt compatibility property of the device

View File

@@ -3,3 +3,4 @@
// SPDX-License-Identifier: Apache-2.0
pub mod gic;
pub mod regs;

View File

@@ -0,0 +1,228 @@
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
//
// Copyright © 2025, Microsoft Corporation
//
use bitfield_struct::bitfield;
use open_enum::open_enum;
use zerocopy::{FromBytes, IntoBytes};
/// ESR_EL2, exception syndrome register.
#[bitfield(u64)]
#[derive(IntoBytes, FromBytes)]
pub struct EsrEl2 {
#[bits(25)]
pub iss: u32,
pub il: bool,
#[bits(6)]
pub ec: u8,
#[bits(5)]
pub iss2: u8,
#[bits(27)]
_rsvd: u32,
}
#[open_enum]
#[derive(Debug)]
#[repr(u8)]
pub enum FaultStatusCode {
ADDRESS_SIZE_FAULT_LEVEL0 = 0b000000,
ADDRESS_SIZE_FAULT_LEVEL1 = 0b000001,
ADDRESS_SIZE_FAULT_LEVEL2 = 0b000010,
ADDRESS_SIZE_FAULT_LEVEL3 = 0b000011,
TRANSLATION_FAULT_LEVEL0 = 0b000100,
TRANSLATION_FAULT_LEVEL1 = 0b000101,
TRANSLATION_FAULT_LEVEL2 = 0b000110,
TRANSLATION_FAULT_LEVEL3 = 0b000111,
ACCESS_FLAG_FAULT_LEVEL0 = 0b001000,
ACCESS_FLAG_FAULT_LEVEL1 = 0b001001,
ACCESS_FLAG_FAULT_LEVEL2 = 0b001010,
ACCESS_FLAG_FAULT_LEVEL3 = 0b001011,
PERMISSION_FAULT_LEVEL0 = 0b001100,
PERMISSION_FAULT_LEVEL1 = 0b001101,
PERMISSION_FAULT_LEVEL2 = 0b001110,
PERMISSION_FAULT_LEVEL3 = 0b001111,
SYNCHRONOUS_EXTERNAL_ABORT = 0b010000,
SYNC_TAG_CHECK_FAULT = 0b010001,
SEA_TTW_LEVEL_NEG1 = 0b010011,
SEA_TTW_LEVEL0 = 0b010100,
SEA_TTW_LEVEL1 = 0b010101,
SEA_TTW_LEVEL2 = 0b010110,
SEA_TTW_LEVEL3 = 0b010111,
ECC_PARITY = 0b011000,
ECC_PARITY_TTW_LEVEL_NEG1 = 0b011011,
ECC_PARITY_TTW_LEVEL0 = 0b011100,
ECC_PARITY_TTW_LEVEL1 = 0b011101,
ECC_PARITY_TTW_LEVEL2 = 0b011110,
ECC_PARITY_TTW_LEVEL3 = 0b011111,
/// Valid only for data fault.
ALIGNMENT_FAULT = 0b100001,
/// Valid only for instruction fault.
GRANULE_PROTECTION_FAULT_LEVEL_NEG = 0b100011,
/// Valid only for instruction fault.
GRANULE_PROTECTION_FAULT_LEVEL0 = 0b100100,
/// Valid only for instruction fault.
GRANULE_PROTECTION_FAULT_LEVEL1 = 0b100101,
/// Valid only for instruction fault.
GRANULE_PROTECTION_FAULT_LEVEL2 = 0b100110,
/// Valid only for instruction fault.
GRANULE_PROTECTION_FAULT_LEVEL3 = 0b100111,
ADDRESS_SIZE_FAULT_LEVEL_NEG1 = 0b101001,
TRANSLATION_FAULT_LEVEL_NEG1 = 0b101011,
TLB_CONFLICT_ABORT = 0b110000,
UNSUPPORTED_HW_UPDATE_FAULT = 0b110001,
}
/// Support for embedding within IssDataAbort/IssInstructionAbort
impl FaultStatusCode {
const fn from_bits(bits: u32) -> Self {
FaultStatusCode((bits & 0x3f) as u8)
}
const fn into_bits(self) -> u32 {
self.0 as u32
}
}
#[bitfield(u32)]
pub struct IssDataAbort {
#[bits(6)]
pub dfsc: FaultStatusCode,
// Write operation (write not read)
pub wnr: bool,
pub s1ptw: bool,
pub cm: bool,
pub ea: bool,
/// FAR not valid
pub fnv: bool,
#[bits(2)]
pub set: u8,
pub vncr: bool,
/// Acquire/release
pub ar: bool,
/// (ISV==1) 64-bit, (ISV==0) FAR is approximate
pub sf: bool,
#[bits(5)]
/// Register index.
pub srt: u8,
/// Sign extended.
pub sse: bool,
#[bits(2)]
/// access width log2
pub sas: u8,
/// Valid ESREL2 iss field.
pub isv: bool,
#[bits(7)]
_unused: u8,
}
#[open_enum]
#[repr(u8)]
pub enum ExceptionClass {
UNKNOWN = 0b000000,
WFI = 0b000001,
MCR_MRC_COPROC_15 = 0b000011,
MCRR_MRRC_COPROC_15 = 0b000100,
MCR_MRC_COPROC_14 = 0b000101,
LDC_STC = 0b000110,
FP_OR_SIMD = 0b000111,
VMRS = 0b001000,
POINTER_AUTH_HCR_OR_SCR = 0b001001,
LS64 = 0b001010,
MRRC_COPROC_14 = 0b001100,
BRANCH_TARGET = 0b001101,
ILLEGAL_STATE = 0b001110,
SVC32 = 0b010001,
HVC32 = 0b010010,
SMC32 = 0b010011,
SVC = 0b010101,
HVC = 0b010110,
SMC = 0b010111,
SYSTEM = 0b011000,
SVE = 0b011001,
ERET = 0b011010,
TSTART = 0b011011,
POINTER_AUTH = 0b011100,
SME = 0b011101,
INSTRUCTION_ABORT_LOWER = 0b100000,
INSTRUCTION_ABORT = 0b100001,
PC_ALIGNMENT = 0b100010,
DATA_ABORT_LOWER = 0b100100,
DATA_ABORT = 0b100101,
SP_ALIGNMENT_FAULT = 0b100110,
MEMORY_OP = 0b100111,
FP_EXCEPTION_32 = 0b101000,
FP_EXCEPTION_64 = 0b101100,
SERROR = 0b101111,
BREAKPOINT_LOWER = 0b110000,
BREAKPOINT = 0b110001,
STEP_LOWER = 0b110010,
STEP = 0b110011,
WATCHPOINT_LOWER = 0b110100,
WATCHPOINT = 0b110101,
BRK32 = 0b111000,
VECTOR_CATCH_32 = 0b111010,
BRK = 0b111100,
}
#[allow(non_upper_case_globals)]
// PSR (Processor State Register) bits.
// Taken from arch/arm64/include/uapi/asm/ptrace.h.
const PSR_MODE_EL1h: u64 = 0x0000_0005;
const PSR_F_BIT: u64 = 0x0000_0040;
const PSR_I_BIT: u64 = 0x0000_0080;
const PSR_A_BIT: u64 = 0x0000_0100;
const PSR_D_BIT: u64 = 0x0000_0200;
// Taken from arch/arm64/kvm/inject_fault.c.
pub const PSTATE_FAULT_BITS_64: u64 = PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT;
// AArch64 system register encoding:
// See https://developer.arm.com/documentation/ddi0487 (chapter D12)
//
// 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
// +----------+---+-----+-----+-----+-----+-----+----+
// |1101010100| L | op0 | op1 | CRn | CRm | op2 | Rt |
// +----------+---+-----+-----+-----+-----+-----+----+
//
// Notes:
// - L and Rt are reserved as implementation defined fields, ignored.
const SYSREG_HEAD: u32 = 0b1101010100u32 << 22;
const SYSREG_OP0_SHIFT: u32 = 19;
const SYSREG_OP0_MASK: u32 = 0b11u32 << 19;
const SYSREG_OP1_SHIFT: u32 = 16;
const SYSREG_OP1_MASK: u32 = 0b111u32 << 16;
const SYSREG_CRN_SHIFT: u32 = 12;
const SYSREG_CRN_MASK: u32 = 0b1111u32 << 12;
const SYSREG_CRM_SHIFT: u32 = 8;
const SYSREG_CRM_MASK: u32 = 0b1111u32 << 8;
const SYSREG_OP2_SHIFT: u32 = 5;
const SYSREG_OP2_MASK: u32 = 0b111u32 << 5;
/// Define the ID of system registers
#[macro_export]
macro_rules! arm64_sys_reg {
($name: tt, $op0: tt, $op1: tt, $crn: tt, $crm: tt, $op2: tt) => {
pub const $name: u32 = SYSREG_HEAD
| ((($op0 as u32) << SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK as u32)
| ((($op1 as u32) << SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK as u32)
| ((($crn as u32) << SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK as u32)
| ((($crm as u32) << SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK as u32)
| ((($op2 as u32) << SYSREG_OP2_SHIFT) & SYSREG_OP2_MASK as u32);
};
}
arm64_sys_reg!(MPIDR_EL1, 3, 0, 0, 0, 5);
arm64_sys_reg!(ID_AA64MMFR0_EL1, 3, 0, 0, 7, 0);
arm64_sys_reg!(TTBR1_EL1, 3, 0, 2, 0, 1);
arm64_sys_reg!(TCR_EL1, 3, 0, 2, 0, 2);
pub const AARCH64_ARCH_TIMER_PHYS_SECURE_IRQ: u32 = 13;
pub const AARCH64_ARCH_TIMER_PHYS_NONSECURE_IRQ: u32 = 14;
pub const AARCH64_ARCH_TIMER_VIRT_IRQ: u32 = 11;
pub const AARCH64_ARCH_TIMER_HYP_IRQ: u32 = 10;
// PMU PPI interrupt number
pub const AARCH64_PMU_IRQ: u32 = 7;
pub const AARCH64_MIN_PPI_IRQ: u32 = 16;

View File

@@ -82,13 +82,13 @@ pub enum EmulationError<T: Debug> {
WrongNumberOperands(#[source] anyhow::Error),
#[error("Instruction Exception: {0}")]
InstructionException(Exception<T>),
InstructionException(#[source] Exception<T>),
#[error("Instruction fetching error: {0}")]
InstructionFetchingError(#[source] anyhow::Error),
#[error("Platform emulation error: {0}")]
PlatformEmulationError(PlatformError),
PlatformEmulationError(#[source] PlatformError),
#[error(transparent)]
EmulationError(#[from] anyhow::Error),

View File

@@ -21,3 +21,6 @@ pub mod x86;
#[cfg(target_arch = "aarch64")]
pub mod aarch64;
#[cfg(target_arch = "riscv64")]
pub mod riscv64;

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