Compare commits

..

93 Commits
v42.0 ... v43.0

Author SHA1 Message Date
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
76 changed files with 4091 additions and 717 deletions

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

@@ -28,7 +28,7 @@ jobs:
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' }}

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.77.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)"

346
Cargo.lock generated
View File

@@ -7,23 +7,23 @@ name = "acpi_tables"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#e268627630839bd22f1c13e7e81ec70c7e9b73d6"
dependencies = [
"zerocopy",
"zerocopy 0.7.35",
]
[[package]]
name = "addr2line"
version = "0.22.0"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
name = "adler2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "aho-corasick"
@@ -57,9 +57,9 @@ checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
[[package]]
name = "anstyle-parse"
version = "0.2.3"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
@@ -85,15 +85,15 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.87"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8"
checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
[[package]]
name = "api_client"
version = "0.1.0"
dependencies = [
"thiserror",
"thiserror 1.0.62",
"vmm-sys-util",
]
@@ -115,7 +115,7 @@ dependencies = [
"linux-loader",
"log",
"serde",
"thiserror",
"thiserror 1.0.62",
"uuid",
"vm-fdt",
"vm-memory",
@@ -125,9 +125,9 @@ dependencies = [
[[package]]
name = "async-broadcast"
version = "0.7.0"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "258b52a1aa741b9f09783b2d86cf0aeeb617bbf847f6933340a39644227acbdb"
checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e"
dependencies = [
"event-listener",
"event-listener-strategy",
@@ -204,9 +204,9 @@ dependencies = [
[[package]]
name = "async-process"
version = "2.2.2"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a53fc6301894e04a92cb2584fedde80cb25ba8e02d9dc39d4a87d036e22f397d"
checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb"
dependencies = [
"async-channel",
"async-io",
@@ -219,7 +219,6 @@ dependencies = [
"futures-lite",
"rustix",
"tracing",
"windows-sys 0.52.0",
]
[[package]]
@@ -235,9 +234,9 @@ dependencies = [
[[package]]
name = "async-signal"
version = "0.2.6"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afe66191c335039c7bb78f99dc7520b0cbb166b3a1cb33a03f53d8a1c6f2afda"
checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3"
dependencies = [
"async-io",
"async-lock",
@@ -248,7 +247,7 @@ dependencies = [
"rustix",
"signal-hook-registry",
"slab",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -259,9 +258,9 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
[[package]]
name = "async-trait"
version = "0.1.80"
version = "0.1.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
dependencies = [
"proc-macro2",
"quote",
@@ -282,17 +281,17 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "backtrace"
version = "0.3.73"
version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-targets 0.52.6",
]
[[package]]
@@ -330,7 +329,7 @@ dependencies = [
"remain",
"serde",
"smallvec",
"thiserror",
"thiserror 1.0.62",
"uuid",
"virtio-bindings",
"virtio-queue",
@@ -421,7 +420,7 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "cloud-hypervisor"
version = "42.0.0"
version = "43.0.0"
dependencies = [
"anyhow",
"api_client",
@@ -440,7 +439,7 @@ dependencies = [
"serde_json",
"signal-hook",
"test_infra",
"thiserror",
"thiserror 1.0.62",
"tpm",
"tracer",
"vm-memory",
@@ -477,9 +476,9 @@ dependencies = [
[[package]]
name = "cpufeatures"
version = "0.2.12"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
dependencies = [
"libc",
]
@@ -575,7 +574,7 @@ dependencies = [
"num_enum",
"pci",
"serde",
"thiserror",
"thiserror 1.0.62",
"tpm",
"vm-allocator",
"vm-device",
@@ -720,9 +719,9 @@ dependencies = [
[[package]]
name = "event-listener-strategy"
version = "0.5.1"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "332f51cb23d20b0de8458b86580878211da09bcd4503cb579c225b3d124cabb3"
checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2"
dependencies = [
"event-listener",
"pin-project-lite",
@@ -741,9 +740,9 @@ dependencies = [
[[package]]
name = "fastrand"
version = "2.1.1"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
[[package]]
name = "fdt"
@@ -753,9 +752,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",
@@ -796,9 +795,9 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-executor"
@@ -907,9 +906,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.14"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"js-sys",
@@ -920,9 +919,9 @@ dependencies = [
[[package]]
name = "gimli"
version = "0.29.0"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "glob"
@@ -959,6 +958,7 @@ name = "hypervisor"
version = "0.1.0"
dependencies = [
"anyhow",
"arc-swap",
"byteorder",
"cfg-if",
"concat-idents",
@@ -974,7 +974,7 @@ dependencies = [
"mshv-ioctls",
"serde",
"serde_with",
"thiserror",
"thiserror 1.0.62",
"vfio-ioctls",
"vm-memory",
"vmm-sys-util",
@@ -1007,9 +1007,9 @@ dependencies = [
"igvm_defs",
"open-enum",
"range_map_vec",
"thiserror",
"thiserror 1.0.62",
"tracing",
"zerocopy",
"zerocopy 0.7.35",
]
[[package]]
@@ -1021,7 +1021,7 @@ dependencies = [
"bitfield-struct",
"open-enum",
"static_assertions",
"zerocopy",
"zerocopy 0.7.35",
]
[[package]]
@@ -1085,20 +1085,20 @@ 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.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92c2176b91f68903b54ac8c6185bada7d607ca6110998976ff15c032f88a7d39"
checksum = "337d1afa126368bbd6a5c328048f71a69a737e9afe7e436b392a8f8d770c9171"
dependencies = [
"bitflags 2.6.0",
"kvm-bindings",
@@ -1114,7 +1114,7 @@ checksum = "dafb8a4afee64f167eb2b52d32f0eea002e41a7a6450e68c799c8ec3a81a634c"
dependencies = [
"enumflags2",
"libc",
"thiserror",
"thiserror 1.0.62",
]
[[package]]
@@ -1125,9 +1125,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.158"
version = "0.2.167"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
[[package]]
name = "libredox"
@@ -1167,9 +1167,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",
]
@@ -1182,9 +1182,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "lock_api"
version = "0.4.11"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
@@ -1228,11 +1228,11 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.7.2"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
dependencies = [
"adler",
"adler2",
]
[[package]]
@@ -1243,25 +1243,27 @@ checksum = "9bec4598fddb13cc7b528819e697852653252b760f1228b7642679bf2ff2cd07"
[[package]]
name = "mshv-bindings"
version = "0.3.0"
source = "git+https://github.com/rust-vmm/mshv?tag=v0.3.0#fda05380ea4c68b807996299d5ffb2854ca6d01d"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0cb5031f3243a7459b7c13d960d25420980874eebda816db24ce6077e21d43"
dependencies = [
"libc",
"num_enum",
"serde",
"serde_derive",
"vmm-sys-util",
"zerocopy",
"zerocopy 0.8.8",
]
[[package]]
name = "mshv-ioctls"
version = "0.3.0"
source = "git+https://github.com/rust-vmm/mshv?tag=v0.3.0#fda05380ea4c68b807996299d5ffb2854ca6d01d"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89abe853221fa6f14ad4066affb9abda241a03d65622887d5794e1422d0bd75a"
dependencies = [
"libc",
"mshv-bindings",
"thiserror",
"thiserror 2.0.6",
"vmm-sys-util",
]
@@ -1296,7 +1298,7 @@ dependencies = [
"rate_limiter",
"serde",
"serde_json",
"thiserror",
"thiserror 1.0.62",
"virtio-bindings",
"virtio-queue",
"vm-memory",
@@ -1355,9 +1357,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.36.1"
version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
dependencies = [
"memchr",
]
@@ -1399,9 +1401,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
version = "0.9.102"
version = "0.9.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2"
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
dependencies = [
"cc",
"libc",
@@ -1500,7 +1502,7 @@ dependencies = [
"libc",
"log",
"serde",
"thiserror",
"thiserror 1.0.62",
"vfio-bindings",
"vfio-ioctls",
"vfio_user",
@@ -1520,15 +1522,15 @@ dependencies = [
"serde",
"serde_json",
"test_infra",
"thiserror",
"thiserror 1.0.62",
"wait-timeout",
]
[[package]]
name = "pin-project-lite"
version = "0.2.14"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
[[package]]
name = "pin-utils"
@@ -1549,9 +1551,9 @@ dependencies = [
[[package]]
name = "pkg-config"
version = "0.3.30"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "pnet"
@@ -1665,7 +1667,7 @@ version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy",
"zerocopy 0.7.35",
]
[[package]]
@@ -1738,7 +1740,7 @@ dependencies = [
"epoll",
"libc",
"log",
"thiserror",
"thiserror 1.0.62",
"vmm-sys-util",
]
@@ -1768,14 +1770,14 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom",
"libredox",
"thiserror",
"thiserror 1.0.62",
]
[[package]]
name = "regex"
version = "1.10.5"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
@@ -1785,9 +1787,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.7"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
@@ -1796,9 +1798,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.8.3"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "remain"
@@ -2006,9 +2008,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.66"
version = "2.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
dependencies = [
"proc-macro2",
"quote",
@@ -2059,7 +2061,16 @@ version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb"
dependencies = [
"thiserror-impl",
"thiserror-impl 1.0.62",
]
[[package]]
name = "thiserror"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47"
dependencies = [
"thiserror-impl 2.0.6",
]
[[package]]
@@ -2073,6 +2084,17 @@ dependencies = [
"syn",
]
[[package]]
name = "thiserror-impl"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thousands"
version = "0.2.0"
@@ -2105,7 +2127,7 @@ dependencies = [
"libc",
"log",
"net_gen",
"thiserror",
"thiserror 1.0.62",
"vmm-sys-util",
]
@@ -2210,14 +2232,14 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.4"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[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#e71efe41d59adf23377f7066a49903c6c19f5ac3"
dependencies = [
"vmm-sys-util",
]
@@ -2225,7 +2247,7 @@ 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#e71efe41d59adf23377f7066a49903c6c19f5ac3"
dependencies = [
"byteorder",
"kvm-bindings",
@@ -2234,7 +2256,7 @@ dependencies = [
"log",
"mshv-bindings",
"mshv-ioctls",
"thiserror",
"thiserror 1.0.62",
"vfio-bindings",
"vm-memory",
"vmm-sys-util",
@@ -2243,7 +2265,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",
@@ -2251,7 +2273,7 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"thiserror",
"thiserror 1.0.62",
"vfio-bindings",
"vm-memory",
"vmm-sys-util",
@@ -2259,9 +2281,8 @@ 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",
"libc",
@@ -2272,9 +2293,8 @@ dependencies = [
[[package]]
name = "vhost-user-backend"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73768c8584e0be5ed8feb063785910cabe3f1af6661a5953fd3247fa611ddfaf"
version = "0.16.1"
source = "git+https://github.com/rust-vmm/vhost?rev=d983ae0#d983ae07f78663b7d24059667376992460b571a2"
dependencies = [
"libc",
"log",
@@ -2324,9 +2344,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"
@@ -2350,7 +2370,7 @@ dependencies = [
"serde_json",
"serde_with",
"serial_buffer",
"thiserror",
"thiserror 1.0.62",
"vhost",
"virtio-bindings",
"virtio-queue",
@@ -2364,9 +2384,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",
@@ -2390,7 +2410,7 @@ dependencies = [
"anyhow",
"hypervisor",
"serde",
"thiserror",
"thiserror 1.0.62",
"vfio-ioctls",
"vm-memory",
"vmm-sys-util",
@@ -2403,13 +2423,13 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#ef5bd734f5f66fb0772
[[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.62",
"winapi",
]
@@ -2420,7 +2440,7 @@ dependencies = [
"anyhow",
"serde",
"serde_json",
"thiserror",
"thiserror 1.0.62",
"vm-memory",
]
@@ -2475,7 +2495,7 @@ dependencies = [
"serde_json",
"serial_buffer",
"signal-hook",
"thiserror",
"thiserror 1.0.62",
"tracer",
"uuid",
"vfio-ioctls",
@@ -2489,7 +2509,7 @@ dependencies = [
"vm-virtio",
"vmm-sys-util",
"zbus",
"zerocopy",
"zerocopy 0.7.35",
]
[[package]]
@@ -2610,7 +2630,16 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.4",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
@@ -2630,17 +2659,18 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.52.4"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.52.4",
"windows_aarch64_msvc 0.52.4",
"windows_i686_gnu 0.52.4",
"windows_i686_msvc 0.52.4",
"windows_x86_64_gnu 0.52.4",
"windows_x86_64_gnullvm 0.52.4",
"windows_x86_64_msvc 0.52.4",
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
@@ -2651,9 +2681,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.4"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
@@ -2663,9 +2693,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.4"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
@@ -2675,9 +2705,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.4"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
@@ -2687,9 +2723,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.4"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
@@ -2699,9 +2735,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.4"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
@@ -2711,9 +2747,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.4"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
@@ -2723,9 +2759,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.4"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
@@ -2738,12 +2774,12 @@ dependencies = [
[[package]]
name = "xdg-home"
version = "1.2.0"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca91dcf8f93db085f3a0a29358cd0b9d670915468f4290e8b85d118a34211ab8"
checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -2815,7 +2851,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.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a4e33e6dce36f2adba29746927f8e848ba70989fdb61c772773bbdda8b5d6a7"
dependencies = [
"zerocopy-derive 0.8.8",
]
[[package]]
@@ -2829,6 +2874,17 @@ dependencies = [
"syn",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cd137b4cc21bde6ecce3bbbb3350130872cda0be2c6888874279ea76e17d4c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "zvariant"
version = "4.2.0"

View File

@@ -7,7 +7,7 @@ edition = "2021"
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
license = "Apache-2.0 AND BSD-3-Clause"
name = "cloud-hypervisor"
version = "42.0.0"
version = "43.0.0"
# Minimum buildable version:
# Keep in sync with version in .github/workflows/build.yaml
# Policy on MSRV (see #4318):
@@ -29,14 +29,14 @@ 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 }
@@ -103,18 +103,19 @@ members = [
[workspace.dependencies]
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" }
kvm-bindings = "0.10.0"
kvm-ioctls = "0.19.0"
linux-loader = "0.13.0"
mshv-bindings = "0.3.2"
mshv-ioctls = "0.3.2"
seccompiler = "0.4.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"

View File

@@ -11,10 +11,10 @@ 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"] }
@@ -24,6 +24,6 @@ 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

@@ -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;
@@ -32,6 +33,9 @@ pub enum Error {
#[cfg(target_arch = "aarch64")]
#[error("Platform specific error (aarch64): {0:?}")]
PlatformSpecific(aarch64::Error),
#[cfg(target_arch = "riscv64")]
#[error("Platform specific error (riscv64): {0:?}")]
PlatformSpecific(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(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(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(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

@@ -12,7 +12,7 @@ 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"] }

View File

@@ -6,13 +6,13 @@ version = "0.1.0"
[dependencies]
acpi_tables = { workspace = true }
anyhow = "1.0.87"
anyhow = "1.0.94"
arch = { path = "../arch" }
bitflags = "2.6.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" }
@@ -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

@@ -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
@@ -41,6 +42,14 @@ pub enum Error {
/// Failed restoring GIC device.
#[error("Failed restoring GIC device: {0}")]
RestoreGic(hypervisor::arch::aarch64::gic::Error),
#[cfg(target_arch = "riscv64")]
/// Failed creating AIA device.
#[error("Failed creating AIA device: {0}")]
CreateAia(hypervisor::HypervisorVmError),
#[cfg(target_arch = "riscv64")]
/// Failed restoring AIA device.
#[error("Failed restoring AIA device: {0}")]
RestoreAia(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

@@ -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

@@ -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,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

@@ -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"

47
fuzz/Cargo.lock generated
View File

@@ -5,7 +5,7 @@ version = 3
[[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#849d5950196f66dd10f2b2606d8fe8c7cb39ec24"
dependencies = [
"zerocopy",
]
@@ -361,9 +361,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",
@@ -500,9 +500,9 @@ 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",
@@ -511,9 +511,9 @@ dependencies = [
[[package]]
name = "kvm-ioctls"
version = "0.18.0"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92c2176b91f68903b54ac8c6185bada7d607ca6110998976ff15c032f88a7d39"
checksum = "337d1afa126368bbd6a5c328048f71a69a737e9afe7e436b392a8f8d770c9171"
dependencies = [
"bitflags 2.6.0",
"kvm-bindings",
@@ -551,9 +551,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",
]
@@ -662,9 +662,9 @@ 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 = "option_parser"
@@ -1020,7 +1020,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,7 +1028,7 @@ 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",
@@ -1044,7 +1044,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",
@@ -1060,9 +1060,8 @@ 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",
"libc",
@@ -1073,9 +1072,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"
@@ -1112,9 +1111,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",
@@ -1147,13 +1146,13 @@ 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.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a320fc11792e063174402ff444aa3c80363cbf1e31c47b5ef74124406c334ce6"
checksum = "e2919f87420b6998a131eb7c78843890295e91a3f8f786ccc925c8d387b75121"
dependencies = [
"arc-swap",
"libc",

View File

@@ -18,15 +18,15 @@ devices = { path = "../devices" }
epoll = "4.3.3"
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" }
net_util = { path = "../net_util" }
once_cell = "1.19.0"
seccompiler = "0.4.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"] }

View File

@@ -12,7 +12,8 @@ sev_snp = ["igvm", "igvm_defs"]
tdx = []
[dependencies]
anyhow = "1.0.87"
anyhow = "1.0.94"
arc-swap = "1.7.1"
byteorder = "1.5.0"
cfg-if = "1.0.0"
concat-idents = "1.1.5"
@@ -20,7 +21,7 @@ igvm = { version = "0.3.3", optional = true }
igvm_defs = { version = "0.3.1", 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",
@@ -33,7 +34,11 @@ serde_with = { version = "3.9.0", default-features = false, features = [
] }
thiserror = "1.0.62"
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"] }
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]

View File

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

View File

@@ -0,0 +1,63 @@
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0
use std::any::Any;
use std::result;
use thiserror::Error;
use crate::{AiaState, HypervisorDeviceError, HypervisorVmError};
/// Errors thrown while setting up the VAIA.
#[derive(Debug, Error)]
pub enum Error {
/// Error while calling KVM ioctl for setting up the global interrupt controller.
#[error("Failed creating AIA device: {0}")]
CreateAia(HypervisorVmError),
/// Error while setting device attributes for the AIA.
#[error("Failed setting device attributes for the AIA: {0}")]
SetDeviceAttribute(HypervisorDeviceError),
/// Error while getting device attributes for the AIA.
#[error("Failed getting device attributes for the AIA: {0}")]
GetDeviceAttribute(HypervisorDeviceError),
}
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug)]
pub struct VaiaConfig {
pub vcpu_count: u32,
pub aplic_addr: u64,
pub imsic_addr: u64,
pub nr_irqs: u32,
}
/// Hypervisor agnostic interface for a virtualized AIA
pub trait Vaia: Send + Sync {
/// Returns the compatibility property of APLIC
fn aplic_compatibility(&self) -> &str;
/// Returns an array with APLIC device properties
fn aplic_properties(&self) -> [u32; 4];
/// Returns the compatibility property of IMSIC
fn imsic_compatibility(&self) -> &str;
/// Returns an array with IMSIC device properties
fn imsic_properties(&self) -> [u32; 4];
/// Returns the number of vCPUs this AIA handles
fn vcpu_count(&self) -> u32;
/// Returns whether the AIA device is MSI compatible or not
fn msi_compatible(&self) -> bool;
/// Downcast the trait object to its concrete type.
fn as_any_concrete_mut(&mut self) -> &mut dyn Any;
/// Save the state of AiaImsics.
fn state(&self) -> Result<AiaState>;
/// Restore the state of AiaImsics.
fn set_state(&mut self, state: &AiaState) -> Result<()>;
}

View File

@@ -0,0 +1,5 @@
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0
pub mod aia;

View File

@@ -1,3 +1,5 @@
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
//
// Copyright © 2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
@@ -9,6 +11,7 @@
//
use thiserror::Error;
#[cfg(not(target_arch = "riscv64"))]
use vm_memory::GuestAddress;
#[cfg(target_arch = "aarch64")]
@@ -17,6 +20,8 @@ use crate::aarch64::{RegList, VcpuInit};
use crate::arch::x86::{CpuIdEntry, FpuState, LapicState, MsrEntry, SpecialRegisters};
#[cfg(feature = "tdx")]
use crate::kvm::{TdxExitDetails, TdxExitStatus};
#[cfg(target_arch = "riscv64")]
use crate::riscv64::RegList;
use crate::{CpuState, MpState, StandardRegisters};
#[cfg(target_arch = "x86_64")]
@@ -216,6 +221,16 @@ pub enum HypervisorCpuError {
#[error("Failed to set aarch64 core register: {0}")]
SetAarchCoreRegister(#[source] anyhow::Error),
///
/// Getting RISC-V 64-bit core register error
///
#[error("Failed to get riscv64 core register: {0}")]
GetRiscvCoreRegister(#[source] anyhow::Error),
///
/// Setting RISC-V 64-bit core register error
///
#[error("Failed to set riscv64 core register: {0}")]
SetRiscvCoreRegister(#[source] anyhow::Error),
///
/// Getting registers list error
///
#[error("Failed to retrieve list of registers: {0}")]
@@ -231,6 +246,16 @@ pub enum HypervisorCpuError {
#[error("Failed to set system register: {0}")]
SetSysRegister(#[source] anyhow::Error),
///
/// Getting RISC-V 64-bit non-core register error
///
#[error("Failed to get non-core register: {0}")]
GetNonCoreRegister(#[source] anyhow::Error),
///
/// Setting RISC-V 64-bit non-core register error
///
#[error("Failed to set non-core register: {0}")]
SetNonCoreRegister(#[source] anyhow::Error),
///
/// GVA translation error
///
#[error("Failed to translate GVA: {0}")]
@@ -412,6 +437,7 @@ pub trait Vcpu: Send + Sync {
///
/// Sets debug registers to set hardware breakpoints and/or enable single step.
///
#[cfg(not(target_arch = "riscv64"))]
fn set_guest_debug(&self, _addrs: &[GuestAddress], _singlestep: bool) -> Result<()> {
Err(HypervisorCpuError::SetDebugRegs(anyhow!("unimplemented")))
}
@@ -428,7 +454,7 @@ pub trait Vcpu: Send + Sync {
/// Gets a list of the guest registers that are supported for the
/// KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
///
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
fn get_reg_list(&self, reg_list: &mut RegList) -> Result<()>;
///
/// Gets the value of a system register
@@ -436,9 +462,14 @@ pub trait Vcpu: Send + Sync {
#[cfg(target_arch = "aarch64")]
fn get_sys_reg(&self, sys_reg: u32) -> Result<u64>;
///
/// Gets the value of a non-core register on RISC-V 64-bit
///
#[cfg(target_arch = "riscv64")]
fn get_non_core_reg(&self, non_core_reg: u32) -> Result<u64>;
///
/// Configure core registers for a given CPU.
///
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> Result<()>;
///
/// Check if the CPU supports PMU

View File

@@ -118,6 +118,17 @@ pub trait Hypervisor: Send + Sync {
fn create_vm_with_type(&self, _vm_type: u64) -> Result<Arc<dyn Vm>> {
unreachable!()
}
///
/// Create a Vm of a specific type using the underlying hypervisor, passing memory size
/// Return a hypervisor-agnostic Vm trait object
///
fn create_vm_with_type_and_memory(
&self,
_vm_type: u64,
#[cfg(feature = "sev_snp")] _mem_size: u64,
) -> Result<Arc<dyn Vm>> {
unreachable!()
}
#[cfg(target_arch = "x86_64")]
///
/// Get the supported CpuID

View File

@@ -103,9 +103,8 @@ fn dist_attr_get(gic: &DeviceFd, offset: u32) -> Result<u32> {
flags: 0,
};
// get_device_attr should be marked as unsafe, and will be in future.
// SAFETY: gic_dist_attr.addr is safe to write to.
gic.get_device_attr(&mut gic_dist_attr).map_err(|e| {
unsafe { gic.get_device_attr(&mut gic_dist_attr) }.map_err(|e| {
Error::GetDeviceAttribute(HypervisorDeviceError::GetDeviceAttribute(e.into()))
})?;
@@ -131,9 +130,8 @@ fn get_interrupts_num(gic: &DeviceFd) -> Result<u32> {
addr: &mut num_irq as *mut u32 as u64,
flags: 0,
};
// get_device_attr should be marked as unsafe, and will be in future.
// SAFETY: nr_irqs_attr.addr is safe to write to.
gic.get_device_attr(&mut nr_irqs_attr).map_err(|e| {
unsafe { gic.get_device_attr(&mut nr_irqs_attr) }.map_err(|e| {
Error::GetDeviceAttribute(HypervisorDeviceError::GetDeviceAttribute(e.into()))
})?;
Ok(num_irq)

View File

@@ -105,9 +105,8 @@ fn icc_attr_get(gic: &DeviceFd, offset: u64, typer: u64) -> Result<u32> {
flags: 0,
};
// get_device_attr should be marked as unsafe, and will be in future.
// SAFETY: gic_icc_attr.addr is safe to write to.
gic.get_device_attr(&mut gic_icc_attr).map_err(|e| {
unsafe { gic.get_device_attr(&mut gic_icc_attr) }.map_err(|e| {
Error::GetDeviceAttribute(HypervisorDeviceError::GetDeviceAttribute(e.into()))
})?;

View File

@@ -49,13 +49,10 @@ fn gicv3_its_attr_get(its_device: &DeviceFd, group: u32, attr: u32) -> Result<u6
flags: 0,
};
// get_device_attr should be marked as unsafe, and will be in future.
// SAFETY: gicv3_its_attr.addr is safe to write to.
its_device
.get_device_attr(&mut gicv3_its_attr)
.map_err(|e| {
Error::GetDeviceAttribute(HypervisorDeviceError::GetDeviceAttribute(e.into()))
})?;
unsafe { its_device.get_device_attr(&mut gicv3_its_attr) }.map_err(|e| {
Error::GetDeviceAttribute(HypervisorDeviceError::GetDeviceAttribute(e.into()))
})?;
Ok(val)
}

View File

@@ -121,9 +121,8 @@ fn redist_attr_get(gic: &DeviceFd, offset: u32, typer: u64) -> Result<u32> {
flags: 0,
};
// get_device_attr should be marked as unsafe, and will be in future.
// SAFETY: gic_redist_attr.addr is safe to write to.
gic.get_device_attr(&mut gic_redist_attr).map_err(|e| {
unsafe { gic.get_device_attr(&mut gic_redist_attr) }.map_err(|e| {
Error::GetDeviceAttribute(HypervisorDeviceError::GetDeviceAttribute(e.into()))
})?;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,274 @@
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0
use std::any::Any;
use kvm_ioctls::DeviceFd;
use serde::{Deserialize, Serialize};
use crate::arch::riscv64::aia::{Error, Result, Vaia, VaiaConfig};
use crate::device::HypervisorDeviceError;
use crate::kvm::KvmVm;
use crate::Vm;
pub struct KvmAiaImsics {
/// The KVM device for the Aia
device: DeviceFd,
/// AIA APLIC address
aplic_addr: u64,
/// AIA IMSIC address
imsic_addr: u64,
/// Number of CPUs handled by the device
vcpu_count: u32,
}
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct AiaImsicsState {}
impl KvmAiaImsics {
/// Device trees specific constants
fn version() -> u32 {
kvm_bindings::kvm_device_type_KVM_DEV_TYPE_RISCV_AIA
}
/// Setup the device-specific attributes
fn init_device_attributes(&mut self, nr_irqs: u32) -> Result<()> {
// AIA part attributes
// Getting the working mode of RISC-V AIA, defaults to EMUL, passible
// variants are EMUL, HW_ACCL, AUTO
let mut aia_mode = kvm_bindings::KVM_DEV_RISCV_AIA_MODE_EMUL;
Self::get_device_attribute(
&self.device,
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CONFIG,
u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CONFIG_MODE),
&mut aia_mode as *mut u32 as u64,
0,
)?;
// Report AIA MODE
// Setting up the number of wired interrupt sources
Self::set_device_attribute(
&self.device,
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CONFIG,
u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CONFIG_SRCS),
&nr_irqs as *const u32 as u64,
0,
)?;
// Getting the number of ids
let mut aia_nr_ids: u32 = 0;
Self::get_device_attribute(
&self.device,
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CONFIG,
u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CONFIG_IDS),
&mut aia_nr_ids as *mut u32 as u64,
0,
)?;
// Report NR_IDS
// Setting up hart_bits
let max_hart_index = self.vcpu_count as u64 - 1;
let hart_bits = std::cmp::max(64 - max_hart_index.leading_zeros(), 1);
Self::set_device_attribute(
&self.device,
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CONFIG,
u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CONFIG_HART_BITS),
&hart_bits as *const u32 as u64,
0,
)?;
// Designate addresses of APLIC and IMSICS
// Setting up RISC-V APLIC
Self::set_device_attribute(
&self.device,
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_ADDR,
u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_ADDR_APLIC),
&self.aplic_addr as *const u64 as u64,
0,
)?;
// Helpers to calculate address and attribute of IMSIC of each vCPU
let riscv_imsic_addr_of = |cpu_index: u32| -> u64 {
self.imsic_addr + (cpu_index * kvm_bindings::KVM_DEV_RISCV_IMSIC_SIZE) as u64
};
let riscv_imsic_attr_of = |cpu_index: u32| -> u64 { cpu_index as u64 };
// Setting up RISC-V IMSICs
for cpu_index in 0..self.vcpu_count {
let cpu_imsic_addr = riscv_imsic_addr_of(cpu_index);
Self::set_device_attribute(
&self.device,
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_ADDR,
riscv_imsic_attr_of(cpu_index),
&cpu_imsic_addr as *const u64 as u64,
0,
)?;
}
// Finalizing the AIA device
Self::set_device_attribute(
&self.device,
kvm_bindings::KVM_DEV_RISCV_AIA_GRP_CTRL,
u64::from(kvm_bindings::KVM_DEV_RISCV_AIA_CTRL_INIT),
0,
0,
)
}
/// Create a KVM Vaia device
fn create_device(vm: &KvmVm) -> Result<DeviceFd> {
let mut aia_device = kvm_bindings::kvm_create_device {
type_: Self::version(),
fd: 0,
flags: 0,
};
let device_fd = vm
.create_device(&mut aia_device)
.map_err(Error::CreateAia)?;
// We know for sure this is a KVM fd
Ok(device_fd.to_kvm().unwrap())
}
/// Get an AIA device attribute
fn get_device_attribute(
device: &DeviceFd,
group: u32,
attr: u64,
addr: u64,
flags: u32,
) -> Result<()> {
let mut attr = kvm_bindings::kvm_device_attr {
flags,
group,
attr,
addr,
};
// SAFETY: attr.addr is safe to write to.
unsafe {
device.get_device_attr(&mut attr).map_err(|e| {
Error::GetDeviceAttribute(HypervisorDeviceError::GetDeviceAttribute(e.into()))
})
}
}
/// Set an AIA device attribute
fn set_device_attribute(
device: &DeviceFd,
group: u32,
attr: u64,
addr: u64,
flags: u32,
) -> Result<()> {
let attr = kvm_bindings::kvm_device_attr {
flags,
group,
attr,
addr,
};
device.set_device_attr(&attr).map_err(|e| {
Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into()))
})
}
/// Method to initialize the AIA device
pub fn new(vm: &dyn Vm, config: VaiaConfig) -> Result<KvmAiaImsics> {
// This is inside KVM module
let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?");
let vaia = Self::create_device(vm)?;
let mut aia_device = KvmAiaImsics {
device: vaia,
vcpu_count: config.vcpu_count,
aplic_addr: config.aplic_addr,
imsic_addr: config.imsic_addr,
};
aia_device.init_device_attributes(config.nr_irqs)?;
Ok(aia_device)
}
}
impl Vaia for KvmAiaImsics {
fn aplic_compatibility(&self) -> &str {
"riscv,aplic"
}
fn aplic_properties(&self) -> [u32; 4] {
[
0,
self.aplic_addr as u32,
0,
kvm_bindings::KVM_DEV_RISCV_APLIC_SIZE,
]
}
fn imsic_compatibility(&self) -> &str {
"riscv,imsics"
}
fn imsic_properties(&self) -> [u32; 4] {
[
0,
self.imsic_addr as u32,
0,
kvm_bindings::KVM_DEV_RISCV_IMSIC_SIZE * self.vcpu_count,
]
}
fn vcpu_count(&self) -> u32 {
self.vcpu_count
}
fn msi_compatible(&self) -> bool {
true
}
fn as_any_concrete_mut(&mut self) -> &mut dyn Any {
self
}
/// Save the state of AIA.
fn state(&self) -> Result<AiaImsicsState> {
unimplemented!()
}
/// Restore the state of AIA_IMSICs.
fn set_state(&mut self, _state: &AiaImsicsState) -> Result<()> {
unimplemented!()
}
}
#[cfg(test)]
mod tests {
use crate::arch::riscv64::aia::VaiaConfig;
use crate::kvm::KvmAiaImsics;
fn create_test_vaia_config() -> VaiaConfig {
VaiaConfig {
vcpu_count: 1,
aplic_addr: 0xd000000,
imsic_addr: 0x2800000,
nr_irqs: 256,
}
}
#[test]
fn test_create_aia() {
let hv = crate::new().unwrap();
let vm = hv.create_vm().unwrap();
assert!(KvmAiaImsics::new(&*vm, create_test_vaia_config()).is_ok());
}
}

View File

@@ -0,0 +1,163 @@
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0
pub mod aia;
use kvm_bindings::{
kvm_mp_state, kvm_one_reg, kvm_riscv_core, KVM_REG_RISCV_CORE, KVM_REG_RISCV_TYPE_MASK,
KVM_REG_SIZE_MASK, KVM_REG_SIZE_U64,
};
pub use kvm_bindings::{kvm_one_reg as Register, RegList};
pub use kvm_ioctls::{Cap, Kvm};
use serde::{Deserialize, Serialize};
use crate::kvm::{KvmError, KvmResult};
// This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having
// an instance of that structure.
#[macro_export]
macro_rules! _offset_of {
($str:ty, $field:ident) => {{
let tmp: std::mem::MaybeUninit<$str> = std::mem::MaybeUninit::uninit();
let base = tmp.as_ptr();
// Avoid warnings when nesting `unsafe` blocks.
#[allow(unused_unsafe)]
// SAFETY: The pointer is valid and aligned, just not initialised. Using `addr_of` ensures
// that we don't actually read from `base` (which would be UB) nor create an intermediate
// reference.
let member = unsafe { core::ptr::addr_of!((*base).$field) } as *const u8;
// Avoid warnings when nesting `unsafe` blocks.
#[allow(unused_unsafe)]
// SAFETY: The two pointers are within the same allocated object `tmp`. All requirements
// from offset_from are upheld.
unsafe {
member.offset_from(base as *const u8) as usize
}
}};
}
#[macro_export]
macro_rules! offset_of {
($reg_struct:ty, $field:ident) => {
$crate::_offset_of!($reg_struct, $field)
};
($outer_reg_struct:ty, $outer_field:ident, $($inner_reg_struct:ty, $inner_field:ident), +) => {
$crate::_offset_of!($outer_reg_struct, $outer_field) + offset_of!($($inner_reg_struct, $inner_field), +)
};
}
// Following are macros that help with getting the ID of a riscv64 register, including config registers, core registers and timer registers.
// The register of core registers are wrapped in the `user_regs_struct` structure. See:
// https://elixir.bootlin.com/linux/v6.10/source/arch/riscv/include/uapi/asm/kvm.h#L62
// Get the ID of a register
#[macro_export]
macro_rules! riscv64_reg_id {
($reg_type: tt, $offset: tt) => {
// The core registers of an riscv64 machine are represented
// in kernel by the `kvm_riscv_core` structure:
//
// struct kvm_riscv_core {
// struct user_regs_struct regs;
// unsigned long mode;
// };
//
// struct user_regs_struct {
// unsigned long pc;
// unsigned long ra;
// unsigned long sp;
// unsigned long gp;
// unsigned long tp;
// unsigned long t0;
// unsigned long t1;
// unsigned long t2;
// unsigned long s0;
// unsigned long s1;
// unsigned long a0;
// unsigned long a1;
// unsigned long a2;
// unsigned long a3;
// unsigned long a4;
// unsigned long a5;
// unsigned long a6;
// unsigned long a7;
// unsigned long s2;
// unsigned long s3;
// unsigned long s4;
// unsigned long s5;
// unsigned long s6;
// unsigned long s7;
// unsigned long s8;
// unsigned long s9;
// unsigned long s10;
// unsigned long s11;
// unsigned long t3;
// unsigned long t4;
// unsigned long t5;
// unsigned long t6;
// };
// The id of a core register can be obtained like this: offset = id &
// ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_RISCV_CORE). Thus,
// id = KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_CORE | offset
//
// To generalize, the id of a register can be obtained by:
// id = KVM_REG_RISCV | KVM_REG_SIZE_U64 |
// KVM_REG_RISCV_CORE/KVM_REG_RISCV_CONFIG/KVM_REG_RISCV_TIMER |
// offset
kvm_bindings::KVM_REG_RISCV as u64
| u64::from($reg_type)
| u64::from(kvm_bindings::KVM_REG_SIZE_U64)
| (($offset / std::mem::size_of::<u64>()) as u64)
};
}
/// Specifies whether a particular register is a core register or not.
///
/// # Arguments
///
/// * `regid` - The index of the register we are checking.
pub fn is_non_core_register(regid: u64) -> bool {
if (regid & KVM_REG_RISCV_TYPE_MASK as u64) == KVM_REG_RISCV_CORE as u64 {
return false;
}
let size = regid & KVM_REG_SIZE_MASK;
assert!(
size == KVM_REG_SIZE_U64,
"Unexpected register size for system register {size}"
);
true
}
pub fn check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()> {
macro_rules! check_extension {
($cap:expr) => {
if !kvm.check_extension($cap) {
return Err(KvmError::CapabilityMissing($cap));
}
};
}
// SetGuestDebug is required but some kernels have it implemented without the capability flag.
check_extension!(Cap::ImmediateExit);
check_extension!(Cap::Ioeventfd);
check_extension!(Cap::Irqchip);
check_extension!(Cap::Irqfd);
check_extension!(Cap::IrqRouting);
check_extension!(Cap::MpState);
check_extension!(Cap::OneReg);
check_extension!(Cap::UserMemory);
Ok(())
}
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct VcpuKvmState {
pub mp_state: kvm_mp_state,
pub core_regs: kvm_riscv_core,
pub non_core_regs: Vec<kvm_one_reg>,
}

View File

@@ -1,3 +1,5 @@
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
//
// Copyright © 2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
@@ -16,6 +18,7 @@
//!
//! - x86_64
//! - arm64
//! - riscv64 (experimental)
//!
#[macro_use]
@@ -57,6 +60,8 @@ pub use cpu::{HypervisorCpuError, Vcpu, VmExit};
pub use device::HypervisorDeviceError;
#[cfg(all(feature = "kvm", target_arch = "aarch64"))]
pub use kvm::{aarch64, GicState};
#[cfg(all(feature = "kvm", target_arch = "riscv64"))]
pub use kvm::{riscv64, AiaState};
pub use vm::{
DataMatch, HypervisorVmError, InterruptSourceConfig, LegacyIrqSourceConfig, MsiIrqSourceConfig,
Vm, VmOps,
@@ -193,8 +198,10 @@ pub enum IrqRoutingEntry {
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum StandardRegisters {
#[cfg(feature = "kvm")]
#[cfg(all(feature = "kvm", not(target_arch = "riscv64")))]
Kvm(kvm_bindings::kvm_regs),
#[cfg(all(feature = "kvm", target_arch = "riscv64"))]
Kvm(kvm_bindings::kvm_riscv_core),
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
Mshv(mshv_bindings::StandardRegisters),
}
@@ -314,3 +321,125 @@ get_aarch64_reg!(regs, [u64; 31usize]);
get_aarch64_reg!(sp, u64);
get_aarch64_reg!(pc, u64);
get_aarch64_reg!(pstate, u64);
macro_rules! set_riscv64_reg {
(mode) => {
#[cfg(target_arch = "riscv64")]
impl StandardRegisters {
pub fn set_mode(&mut self, val: u64) {
match self {
#[cfg(feature = "kvm")]
StandardRegisters::Kvm(s) => s.mode = val,
}
}
}
};
($reg_name:ident) => {
concat_idents!(method_name = "set_", $reg_name {
#[cfg(target_arch = "riscv64")]
impl StandardRegisters {
pub fn method_name(&mut self, val: u64) {
match self {
#[cfg(feature = "kvm")]
StandardRegisters::Kvm(s) => s.regs.$reg_name = val,
}
}
}
});
}
}
macro_rules! get_riscv64_reg {
(mode) => {
#[cfg(target_arch = "riscv64")]
impl StandardRegisters {
pub fn get_mode(&self) -> u64 {
match self {
#[cfg(feature = "kvm")]
StandardRegisters::Kvm(s) => s.mode,
}
}
}
};
($reg_name:ident) => {
concat_idents!(method_name = "get_", $reg_name {
#[cfg(target_arch = "riscv64")]
impl StandardRegisters {
pub fn method_name(&self) -> u64 {
match self {
#[cfg(feature = "kvm")]
StandardRegisters::Kvm(s) => s.regs.$reg_name,
}
}
}
});
}
}
set_riscv64_reg!(pc);
set_riscv64_reg!(ra);
set_riscv64_reg!(sp);
set_riscv64_reg!(gp);
set_riscv64_reg!(tp);
set_riscv64_reg!(t0);
set_riscv64_reg!(t1);
set_riscv64_reg!(t2);
set_riscv64_reg!(s0);
set_riscv64_reg!(s1);
set_riscv64_reg!(a0);
set_riscv64_reg!(a1);
set_riscv64_reg!(a2);
set_riscv64_reg!(a3);
set_riscv64_reg!(a4);
set_riscv64_reg!(a5);
set_riscv64_reg!(a6);
set_riscv64_reg!(a7);
set_riscv64_reg!(s2);
set_riscv64_reg!(s3);
set_riscv64_reg!(s4);
set_riscv64_reg!(s5);
set_riscv64_reg!(s6);
set_riscv64_reg!(s7);
set_riscv64_reg!(s8);
set_riscv64_reg!(s9);
set_riscv64_reg!(s10);
set_riscv64_reg!(s11);
set_riscv64_reg!(t3);
set_riscv64_reg!(t4);
set_riscv64_reg!(t5);
set_riscv64_reg!(t6);
set_riscv64_reg!(mode);
get_riscv64_reg!(pc);
get_riscv64_reg!(ra);
get_riscv64_reg!(sp);
get_riscv64_reg!(gp);
get_riscv64_reg!(tp);
get_riscv64_reg!(t0);
get_riscv64_reg!(t1);
get_riscv64_reg!(t2);
get_riscv64_reg!(s0);
get_riscv64_reg!(s1);
get_riscv64_reg!(a0);
get_riscv64_reg!(a1);
get_riscv64_reg!(a2);
get_riscv64_reg!(a3);
get_riscv64_reg!(a4);
get_riscv64_reg!(a5);
get_riscv64_reg!(a6);
get_riscv64_reg!(a7);
get_riscv64_reg!(s2);
get_riscv64_reg!(s3);
get_riscv64_reg!(s4);
get_riscv64_reg!(s5);
get_riscv64_reg!(s6);
get_riscv64_reg!(s7);
get_riscv64_reg!(s8);
get_riscv64_reg!(s9);
get_riscv64_reg!(s10);
get_riscv64_reg!(s11);
get_riscv64_reg!(t3);
get_riscv64_reg!(t4);
get_riscv64_reg!(t5);
get_riscv64_reg!(t6);
get_riscv64_reg!(mode);

View File

@@ -5,12 +5,18 @@
use std::any::Any;
use std::collections::HashMap;
#[cfg(feature = "sev_snp")]
use std::num::NonZeroUsize;
use std::sync::{Arc, RwLock};
#[cfg(feature = "sev_snp")]
use arc_swap::ArcSwap;
use mshv_bindings::*;
use mshv_ioctls::{set_registers_64, InterruptRequest, Mshv, NoDatamatch, VcpuFd, VmFd, VmType};
use vfio_ioctls::VfioDeviceFd;
use vm::DataMatch;
#[cfg(feature = "sev_snp")]
use vm_memory::bitmap::AtomicBitmap;
use crate::arch::emulator::PlatformEmulator;
#[cfg(target_arch = "x86_64")]
@@ -205,48 +211,12 @@ impl MshvHypervisor {
.get_msr_index_list()
.map_err(|e| hypervisor::HypervisorError::GetMsrList(e.into()))
}
}
impl MshvHypervisor {
/// Create a hypervisor based on Mshv
#[allow(clippy::new_ret_no_self)]
pub fn new() -> hypervisor::Result<Arc<dyn hypervisor::Hypervisor>> {
let mshv_obj =
Mshv::new().map_err(|e| hypervisor::HypervisorError::HypervisorCreate(e.into()))?;
Ok(Arc::new(MshvHypervisor { mshv: mshv_obj }))
}
/// Check if the hypervisor is available
pub fn is_available() -> hypervisor::Result<bool> {
match std::fs::metadata("/dev/mshv") {
Ok(_) => Ok(true),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(false),
Err(err) => Err(hypervisor::HypervisorError::HypervisorAvailableCheck(
err.into(),
)),
}
}
}
/// Implementation of Hypervisor trait for Mshv
///
/// # Examples
///
/// ```
/// # use hypervisor::mshv::MshvHypervisor;
/// # use std::sync::Arc;
/// let mshv = MshvHypervisor::new().unwrap();
/// let hypervisor = Arc::new(mshv);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// ```
impl hypervisor::Hypervisor for MshvHypervisor {
///
/// Returns the type of the hypervisor
///
fn hypervisor_type(&self) -> HypervisorType {
HypervisorType::Mshv
}
fn create_vm_with_type(&self, vm_type: u64) -> hypervisor::Result<Arc<dyn crate::Vm>> {
fn create_vm_with_type_and_memory_int(
&self,
vm_type: u64,
#[cfg(feature = "sev_snp")] _mem_size: Option<u64>,
) -> hypervisor::Result<Arc<dyn crate::Vm>> {
let mshv_vm_type: VmType = match VmType::try_from(vm_type) {
Ok(vm_type) => vm_type,
Err(_) => return Err(hypervisor::HypervisorError::UnsupportedVmType()),
@@ -339,6 +309,14 @@ impl hypervisor::Hypervisor for MshvHypervisor {
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
#[cfg(feature = "sev_snp")]
sev_snp_enabled: mshv_vm_type == VmType::Snp,
#[cfg(feature = "sev_snp")]
host_access_pages: ArcSwap::new(
AtomicBitmap::new(
_mem_size.unwrap_or_default() as usize,
NonZeroUsize::new(HV_PAGE_SIZE).unwrap(),
)
.into(),
),
}))
}
@@ -350,6 +328,78 @@ impl hypervisor::Hypervisor for MshvHypervisor {
}))
}
}
}
impl MshvHypervisor {
/// Create a hypervisor based on Mshv
#[allow(clippy::new_ret_no_self)]
pub fn new() -> hypervisor::Result<Arc<dyn hypervisor::Hypervisor>> {
let mshv_obj =
Mshv::new().map_err(|e| hypervisor::HypervisorError::HypervisorCreate(e.into()))?;
Ok(Arc::new(MshvHypervisor { mshv: mshv_obj }))
}
/// Check if the hypervisor is available
pub fn is_available() -> hypervisor::Result<bool> {
match std::fs::metadata("/dev/mshv") {
Ok(_) => Ok(true),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(false),
Err(err) => Err(hypervisor::HypervisorError::HypervisorAvailableCheck(
err.into(),
)),
}
}
}
/// Implementation of Hypervisor trait for Mshv
///
/// # Examples
///
/// ```
/// use hypervisor::mshv::MshvHypervisor;
/// use std::sync::Arc;
/// let mshv = MshvHypervisor::new().unwrap();
/// let hypervisor = Arc::new(mshv);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// ```
impl hypervisor::Hypervisor for MshvHypervisor {
///
/// Returns the type of the hypervisor
///
fn hypervisor_type(&self) -> HypervisorType {
HypervisorType::Mshv
}
///
/// Create a Vm of a specific type using the underlying hypervisor, passing memory size
/// Return a hypervisor-agnostic Vm trait object
///
/// # Examples
///
/// ```
/// use hypervisor::kvm::KvmHypervisor;
/// use hypervisor::kvm::KvmVm;
/// let hypervisor = KvmHypervisor::new().unwrap();
/// let vm = hypervisor.create_vm_with_type(0, 512*1024*1024).unwrap();
/// ```
fn create_vm_with_type_and_memory(
&self,
vm_type: u64,
#[cfg(feature = "sev_snp")] _mem_size: u64,
) -> hypervisor::Result<Arc<dyn vm::Vm>> {
self.create_vm_with_type_and_memory_int(
vm_type,
#[cfg(feature = "sev_snp")]
Some(_mem_size),
)
}
fn create_vm_with_type(&self, vm_type: u64) -> hypervisor::Result<Arc<dyn crate::Vm>> {
self.create_vm_with_type_and_memory_int(
vm_type,
#[cfg(feature = "sev_snp")]
None,
)
}
/// Create a mshv vm object and return the object as Vm trait object
///
@@ -357,7 +407,7 @@ impl hypervisor::Hypervisor for MshvHypervisor {
///
/// ```
/// # extern crate hypervisor;
/// # use hypervisor::mshv::MshvHypervisor;
/// use hypervisor::mshv::MshvHypervisor;
/// use hypervisor::mshv::MshvVm;
/// let hypervisor = MshvHypervisor::new().unwrap();
/// let vm = hypervisor.create_vm().unwrap();
@@ -395,6 +445,20 @@ impl hypervisor::Hypervisor for MshvHypervisor {
}
}
#[cfg(feature = "sev_snp")]
struct Ghcb(*mut svm_ghcb_base);
#[cfg(feature = "sev_snp")]
// SAFETY: struct is based on GHCB page in the hypervisor,
// safe to Send across threads
unsafe impl Send for Ghcb {}
#[cfg(feature = "sev_snp")]
// SAFETY: struct is based on GHCB page in the hypervisor,
// safe to Sync across threads as this is only required for Vcpu trait
// functionally not used anyway
unsafe impl Sync for Ghcb {}
/// Vcpu struct for Microsoft Hypervisor
pub struct MshvVcpu {
fd: VcpuFd,
@@ -405,6 +469,10 @@ pub struct MshvVcpu {
msrs: Vec<MsrEntry>,
vm_ops: Option<Arc<dyn vm::VmOps>>,
vm_fd: Arc<VmFd>,
#[cfg(feature = "sev_snp")]
ghcb: Option<Ghcb>,
#[cfg(feature = "sev_snp")]
host_access_pages: ArcSwap<AtomicBitmap>,
}
/// Implementation of Vcpu trait for Microsoft Hypervisor
@@ -412,8 +480,8 @@ pub struct MshvVcpu {
/// # Examples
///
/// ```
/// # use hypervisor::mshv::MshvHypervisor;
/// # use std::sync::Arc;
/// use hypervisor::mshv::MshvHypervisor;
/// use std::sync::Arc;
/// let mshv = MshvHypervisor::new().unwrap();
/// let hypervisor = Arc::new(mshv);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
@@ -732,6 +800,12 @@ impl cpu::Vcpu for MshvVcpu {
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(anyhow!(
"Unhandled VCPU exit: attribute intercept - couldn't modify host access {}", e
)))?;
// Guest is revoking the shared access, so we need to update the bitmap
self.host_access_pages.rcu(|_bitmap| {
let bm = self.host_access_pages.load().as_ref().clone();
bm.reset_addr_range(gpa_start as usize, gfn_count as usize);
bm
});
Ok(cpu::VmExit::Ignore)
}
#[cfg(target_arch = "x86_64")]
@@ -789,6 +863,10 @@ impl cpu::Vcpu for MshvVcpu {
let ghcb_msr = svm_ghcb_msr {
as_uint64: info.ghcb_msr,
};
// Safe to use unwrap, for sev_snp guest we already have the
// GHCB pointer wrapped in the option, otherwise this place is not reached.
let ghcb = self.ghcb.as_ref().unwrap().0;
// SAFETY: Accessing a union element from bindgen generated bindings.
let ghcb_op = unsafe { ghcb_msr.__bindgen_anon_2.ghcb_info() as u32 };
// Sanity check on the header fields before handling other operations.
@@ -887,9 +965,7 @@ impl cpu::Vcpu for MshvVcpu {
GHCB_INFO_NORMAL => {
let exit_code =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_code as u32;
// SAFETY: Accessing a union element from bindgen generated bindings.
let pfn = unsafe { ghcb_msr.__bindgen_anon_2.gpa_page_number() };
let ghcb_gpa = pfn << GHCB_INFO_BIT_WIDTH;
match exit_code {
SVM_EXITCODE_HV_DOORBELL_PAGE => {
let exit_info1 =
@@ -898,10 +974,11 @@ impl cpu::Vcpu for MshvVcpu {
SVM_NAE_HV_DOORBELL_PAGE_GET_PREFERRED => {
// Hypervisor does not have any preference for doorbell GPA.
let preferred_doorbell_gpa: u64 = 0xFFFFFFFFFFFFFFFF;
self.gpa_write(
ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
&preferred_doorbell_gpa.to_le_bytes(),
)?;
set_svm_field_u64_ptr!(
ghcb,
exit_info2,
preferred_doorbell_gpa
);
}
SVM_NAE_HV_DOORBELL_PAGE_SET => {
let exit_info2 = info
@@ -928,13 +1005,10 @@ impl cpu::Vcpu for MshvVcpu {
cpu::HypervisorCpuError::SetRegister(e.into())
})?;
self.gpa_write(
ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
&exit_info2.to_le_bytes(),
)?;
set_svm_field_u64_ptr!(ghcb, exit_info2, exit_info2);
// Clear the SW_EXIT_INFO1 register to indicate no error
self.clear_swexit_info1(ghcb_gpa)?;
self.clear_swexit_info1()?;
}
SVM_NAE_HV_DOORBELL_PAGE_QUERY => {
let mut reg_assocs = [ hv_register_assoc {
@@ -945,19 +1019,13 @@ impl cpu::Vcpu for MshvVcpu {
// SAFETY: Accessing a union element from bindgen generated bindings.
let doorbell_gpa = unsafe { reg_assocs[0].value.reg64 };
self.gpa_write(
ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
&doorbell_gpa.to_le_bytes(),
)?;
set_svm_field_u64_ptr!(ghcb, exit_info2, doorbell_gpa);
// Clear the SW_EXIT_INFO1 register to indicate no error
self.clear_swexit_info1(ghcb_gpa)?;
self.clear_swexit_info1()?;
}
SVM_NAE_HV_DOORBELL_PAGE_CLEAR => {
self.gpa_write(
ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
&[0; 8],
)?;
set_svm_field_u64_ptr!(ghcb, exit_info2, 0);
}
_ => {
panic!(
@@ -991,9 +1059,8 @@ impl cpu::Vcpu for MshvVcpu {
let is_write =
// SAFETY: Accessing a union element from bindgen generated bindings.
unsafe { port_info.__bindgen_anon_1.access_type() == 0 };
let mut data = [0; 8];
self.gpa_read(ghcb_gpa + GHCB_RAX_OFFSET, &mut data)?;
// SAFETY: Accessing the field from a mapped address
let mut data = unsafe { (*ghcb).rax.to_le_bytes() };
if is_write {
if let Some(vm_ops) = &self.vm_ops {
@@ -1009,17 +1076,15 @@ impl cpu::Vcpu for MshvVcpu {
cpu::HypervisorCpuError::RunVcpu(e.into())
})?;
}
self.gpa_write(ghcb_gpa + GHCB_RAX_OFFSET, &data)?;
set_svm_field_u64_ptr!(ghcb, rax, u64::from_le_bytes(data));
}
// Clear the SW_EXIT_INFO1 register to indicate no error
self.clear_swexit_info1(ghcb_gpa)?;
self.clear_swexit_info1()?;
}
SVM_EXITCODE_MMIO_READ => {
let src_gpa =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1;
let dst_gpa = info.__bindgen_anon_2.__bindgen_anon_1.sw_scratch;
let data_len =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2
as usize;
@@ -1032,16 +1097,18 @@ impl cpu::Vcpu for MshvVcpu {
cpu::HypervisorCpuError::RunVcpu(e.into())
})?;
}
self.gpa_write(dst_gpa, &data)?;
// Copy the data to the shared buffer of the GHCB page
let mut buffer_data = [0; 8];
buffer_data[..data_len].copy_from_slice(&data[..data_len]);
// SAFETY: Updating the value of mapped area
unsafe { (*ghcb).shared[0] = u64::from_le_bytes(buffer_data) };
// Clear the SW_EXIT_INFO1 register to indicate no error
self.clear_swexit_info1(ghcb_gpa)?;
self.clear_swexit_info1()?;
}
SVM_EXITCODE_MMIO_WRITE => {
let dst_gpa =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1;
let src_gpa = info.__bindgen_anon_2.__bindgen_anon_1.sw_scratch;
let data_len =
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2
as usize;
@@ -1049,7 +1116,10 @@ impl cpu::Vcpu for MshvVcpu {
assert!(data_len <= 0x8);
let mut data = vec![0; data_len];
self.gpa_read(src_gpa, &mut data)?;
// SAFETY: Accessing data from a mapped address
let bytes_shared_ghcb =
unsafe { (*ghcb).shared[0].to_le_bytes() };
data.copy_from_slice(&bytes_shared_ghcb[..data_len]);
if let Some(vm_ops) = &self.vm_ops {
vm_ops.mmio_write(dst_gpa, &data).map_err(|e| {
@@ -1058,7 +1128,7 @@ impl cpu::Vcpu for MshvVcpu {
}
// Clear the SW_EXIT_INFO1 register to indicate no error
self.clear_swexit_info1(ghcb_gpa)?;
self.clear_swexit_info1()?;
}
SVM_EXITCODE_SNP_GUEST_REQUEST
| SVM_EXITCODE_SNP_EXTENDED_GUEST_REQUEST => {
@@ -1067,15 +1137,16 @@ impl cpu::Vcpu for MshvVcpu {
// We don't support extended guest request, so we just write empty data.
// This matches the behavior of KVM in Linux 6.11.
// Read RAX & RBX from the GHCB.
let mut data = [0; 8];
self.gpa_read(ghcb_gpa + GHCB_RAX_OFFSET, &mut data)?;
let data_gpa = u64::from_le_bytes(data);
self.gpa_read(ghcb_gpa + GHCB_RBX_OFFSET, &mut data)?;
let data_npages = u64::from_le_bytes(data);
// Read RBX from the GHCB.
// SAFETY: Accessing data from a mapped address
let data_gpa = unsafe { (*ghcb).rax };
// SAFETY: Accessing data from a mapped address
let data_npages = unsafe { (*ghcb).rbx };
if data_npages > 0 {
// The certificates are terminated by 24 zero bytes.
// TODO: Need to check if data_gpa is the address of the shared buffer in the GHCB page
// in that case we should clear the shared buffer(24 bytes)
self.gpa_write(data_gpa, &[0; 24])?;
}
}
@@ -1096,7 +1167,7 @@ impl cpu::Vcpu for MshvVcpu {
req_gpa, rsp_gpa
);
self.gpa_write(ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET, &[0; 8])?;
set_svm_field_u64_ptr!(ghcb, exit_info2, 0);
}
SVM_EXITCODE_SNP_AP_CREATION => {
let vmsa_gpa =
@@ -1117,7 +1188,7 @@ impl cpu::Vcpu for MshvVcpu {
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
// Clear the SW_EXIT_INFO1 register to indicate no error
self.clear_swexit_info1(ghcb_gpa)?;
self.clear_swexit_info1()?;
}
_ => panic!(
"GHCB_INFO_NORMAL: Unhandled exit code: {:0x}",
@@ -1495,37 +1566,16 @@ impl MshvVcpu {
/// Clear SW_EXIT_INFO1 register for SEV-SNP guests.
///
#[cfg(feature = "sev_snp")]
fn clear_swexit_info1(
&self,
ghcb_gpa: u64,
) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
fn clear_swexit_info1(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
// Clear the SW_EXIT_INFO1 register to indicate no error
self.gpa_write(ghcb_gpa + GHCB_SW_EXITINFO1_OFFSET, &[0; 4])?;
// Safe to use unwrap, for sev_snp guest we already have the
// GHCB pointer wrapped in the option, otherwise this place is not reached.
let ghcb = self.ghcb.as_ref().unwrap().0;
set_svm_field_u64_ptr!(ghcb, exit_info1, 0);
Ok(cpu::VmExit::Ignore)
}
#[cfg(feature = "sev_snp")]
fn gpa_read(&self, gpa: u64, data: &mut [u8]) -> cpu::Result<()> {
for (gpa, chunk) in (gpa..)
.step_by(HV_READ_WRITE_GPA_MAX_SIZE as usize)
.zip(data.chunks_mut(HV_READ_WRITE_GPA_MAX_SIZE as usize))
{
let mut rw_gpa_arg = mshv_bindings::mshv_read_write_gpa {
base_gpa: gpa,
byte_count: chunk.len() as u32,
..Default::default()
};
self.fd
.gpa_read(&mut rw_gpa_arg)
.map_err(|e| cpu::HypervisorCpuError::GpaRead(e.into()))?;
chunk.copy_from_slice(&rw_gpa_arg.data[..chunk.len()]);
}
Ok(())
}
#[cfg(feature = "sev_snp")]
fn gpa_write(&self, gpa: u64, data: &[u8]) -> cpu::Result<()> {
for (gpa, chunk) in (gpa..)
@@ -1558,6 +1608,8 @@ pub struct MshvVm {
dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>,
#[cfg(feature = "sev_snp")]
sev_snp_enabled: bool,
#[cfg(feature = "sev_snp")]
host_access_pages: ArcSwap<AtomicBitmap>,
}
impl MshvVm {
@@ -1580,9 +1632,9 @@ impl MshvVm {
/// # Examples
///
/// ```
/// # extern crate hypervisor;
/// # use hypervisor::mshv::MshvHypervisor;
/// # use std::sync::Arc;
/// extern crate hypervisor;
/// use hypervisor::mshv::MshvHypervisor;
/// use std::sync::Arc;
/// let mshv = MshvHypervisor::new().unwrap();
/// let hypervisor = Arc::new(mshv);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
@@ -1649,6 +1701,34 @@ impl vm::Vm for MshvVm {
.fd
.create_vcpu(id)
.map_err(|e| vm::HypervisorVmError::CreateVcpu(e.into()))?;
/* Map the GHCB page to the VMM(root) address space
* The map is available after the vcpu creation. This address is mapped
* to the overlay ghcb page of the Microsoft Hypervisor, don't have
* to worry about the scenario when a guest changes the GHCB mapping.
*/
#[cfg(feature = "sev_snp")]
let ghcb = if self.sev_snp_enabled {
// SAFETY: Safe to call as VCPU has this map already available upon creation
let addr = unsafe {
libc::mmap(
std::ptr::null_mut(),
HV_PAGE_SIZE,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_SHARED,
vcpu_fd.as_raw_fd(),
MSHV_VP_MMAP_OFFSET_GHCB as i64 * libc::sysconf(libc::_SC_PAGE_SIZE),
)
};
if addr == libc::MAP_FAILED {
// No point of continuing, without this mmap VMGEXIT will fail anyway
// Return error
return Err(vm::HypervisorVmError::MmapToRoot);
}
Some(Ghcb(addr as *mut svm_ghcb_base))
} else {
None
};
let vcpu = MshvVcpu {
fd: vcpu_fd,
vp_index: id,
@@ -1658,6 +1738,10 @@ impl vm::Vm for MshvVm {
msrs: self.msrs.clone(),
vm_ops,
vm_fd: self.fd.clone(),
#[cfg(feature = "sev_snp")]
ghcb,
#[cfg(feature = "sev_snp")]
host_access_pages: ArcSwap::new(self.host_access_pages.load().clone()),
};
Ok(Arc::new(vcpu))
}
@@ -2050,6 +2134,7 @@ impl vm::Vm for MshvVm {
#[cfg(feature = "sev_snp")]
fn gain_page_access(&self, gpa: u64, size: u32) -> vm::Result<()> {
use mshv_ioctls::set_bits;
const ONE_GB: usize = 1024 * 1024 * 1024;
if !self.sev_snp_enabled {
return Ok(());
@@ -2058,7 +2143,25 @@ impl vm::Vm for MshvVm {
let start_gpfn: u64 = gpa >> PAGE_SHIFT;
let end_gpfn: u64 = (gpa + size as u64 - 1) >> PAGE_SHIFT;
let gpas: Vec<u64> = (start_gpfn..=end_gpfn).map(|x| x << PAGE_SHIFT).collect();
// Enlarge the bitmap if the PFN is greater than the bitmap length
if end_gpfn >= self.host_access_pages.load().as_ref().len() as u64 {
self.host_access_pages.rcu(|bitmap| {
let mut bm = bitmap.as_ref().clone();
bm.enlarge(ONE_GB);
bm
});
}
let gpas: Vec<u64> = (start_gpfn..=end_gpfn)
.filter(|x| {
!self
.host_access_pages
.load()
.as_ref()
.is_bit_set(*x as usize)
})
.map(|x| x << PAGE_SHIFT)
.collect();
if !gpas.is_empty() {
let mut gpa_list = vec_with_array_field::<mshv_modify_gpa_host_access, u64>(gpas.len());
@@ -2081,6 +2184,14 @@ impl vm::Vm for MshvVm {
self.fd
.modify_gpa_host_access(&gpa_list[0])
.map_err(|e| vm::HypervisorVmError::ModifyGpaHostAccess(e.into()))?;
for acquired_gpa in gpas {
self.host_access_pages.rcu(|bitmap| {
let bm = bitmap.clone();
bm.set_bit((acquired_gpa >> PAGE_SHIFT) as usize);
bm
});
}
}
Ok(())

View File

@@ -16,10 +16,3 @@ pub const ECDSA_SIG_X_COMPONENT_END: usize =
pub const ECDSA_SIG_Y_COMPONENT_START: usize = ECDSA_SIG_X_COMPONENT_END;
pub const ECDSA_SIG_Y_COMPONENT_END: usize =
ECDSA_SIG_X_COMPONENT_END + ECDSA_SIG_Y_COMPONENT_SIZE_IN_BYTES;
// These constants are derived from GHCB spec Sect. 2.6 Table 3 GHCB Layout
// Link: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/56421.pdf
pub const GHCB_RAX_OFFSET: u64 = 0x01F8;
pub const GHCB_RBX_OFFSET: u64 = 0x0318;
pub const GHCB_SW_EXITINFO1_OFFSET: u64 = 0x398;
pub const GHCB_SW_EXITINFO2_OFFSET: u64 = 0x3A0;

View File

@@ -1,3 +1,5 @@
// Copyright © 2024 Institute of Software, CAS. All rights reserved.
//
// Copyright © 2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
@@ -12,7 +14,7 @@ use std::any::Any;
#[cfg(target_arch = "x86_64")]
use std::fs::File;
use std::sync::Arc;
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
use std::sync::Mutex;
#[cfg(feature = "sev_snp")]
@@ -24,6 +26,8 @@ use vmm_sys_util::eventfd::EventFd;
use crate::aarch64::VcpuInit;
#[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::gic::{Vgic, VgicConfig};
#[cfg(target_arch = "riscv64")]
use crate::arch::riscv64::aia::{Vaia, VaiaConfig};
#[cfg(feature = "tdx")]
use crate::arch::x86::CpuIdEntry;
use crate::cpu::Vcpu;
@@ -224,6 +228,11 @@ pub enum HypervisorVmError {
#[error("Failed to create Vgic: {0}")]
CreateVgic(#[source] anyhow::Error),
///
/// Create Vaia error
///
#[error("Failed to create Vaia: {0}")]
CreateVaia(#[source] anyhow::Error),
///
/// Import isolated pages error
///
#[error("Failed to import isolated pages: {0}")]
@@ -242,6 +251,12 @@ pub enum HypervisorVmError {
#[cfg(feature = "sev_snp")]
#[error("Failed to modify GPA host access: {0}")]
ModifyGpaHostAccess(#[source] anyhow::Error),
///
/// Failed to mmap
///
#[cfg(feature = "sev_snp")]
#[error("Failed to mmap:")]
MmapToRoot,
}
///
/// Result type for returning from a function
@@ -293,6 +308,7 @@ pub trait Vm: Send + Sync + Any {
#[cfg(target_arch = "x86_64")]
/// Sets the address of the three-page region in the VM's address space.
fn set_tss_address(&self, offset: usize) -> Result<()>;
#[cfg(not(target_arch = "riscv64"))]
/// Creates an in-kernel interrupt controller.
fn create_irq_chip(&self) -> Result<()>;
/// Registers an event that will, when signaled, trigger the `gsi` IRQ.
@@ -303,6 +319,8 @@ pub trait Vm: Send + Sync + Any {
fn create_vcpu(&self, id: u8, vm_ops: Option<Arc<dyn VmOps>>) -> Result<Arc<dyn Vcpu>>;
#[cfg(target_arch = "aarch64")]
fn create_vgic(&self, config: VgicConfig) -> Result<Arc<Mutex<dyn Vgic>>>;
#[cfg(target_arch = "riscv64")]
fn create_vaia(&self, config: VaiaConfig) -> Result<Arc<Mutex<dyn Vaia>>>;
/// Registers an event to be signaled whenever a certain address is written to.
fn register_ioevent(

View File

@@ -6,8 +6,8 @@ version = "0.1.0"
[dependencies]
epoll = "4.3.3"
getrandom = "0.2.14"
libc = "0.2.158"
getrandom = "0.2.15"
libc = "0.2.167"
log = "0.4.22"
net_gen = { path = "../net_gen" }
rate_limiter = { path = "../rate_limiter" }

View File

@@ -75,9 +75,7 @@ pub fn open_tap(
let mut ifname: String = String::new();
let vnet_hdr_size = vnet_hdr_len() as i32;
// Check if the given interface exists before we create it.
let tap_existed = if_name.map_or(false, |n| {
Path::new(&format!("/sys/class/net/{n}")).exists()
});
let tap_existed = if_name.is_some_and(|n| Path::new(&format!("/sys/class/net/{n}")).exists());
// In case the tap interface already exists, check if the number of
// queues is appropriate. The tap might not support multiqueue while

View File

@@ -468,7 +468,7 @@ impl NetQueuePair {
let rate_limit_reached = self
.rx_rate_limiter
.as_ref()
.map_or(false, |r| r.is_blocked());
.is_some_and(|r| r.is_blocked());
// Stop listening on the `RX_TAP_EVENT` when:
// 1) there is no available describes, or

View File

@@ -10,10 +10,10 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"]
[dependencies]
anyhow = "1.0.87"
anyhow = "1.0.94"
byteorder = "1.5.0"
hypervisor = { path = "../hypervisor" }
libc = "0.2.158"
libc = "0.2.167"
log = "0.4.22"
serde = { version = "1.0.208", features = ["derive"] }
thiserror = "1.0.62"

View File

@@ -125,19 +125,16 @@ impl PciBus {
pub fn register_mapping(
&self,
dev: Arc<dyn BusDeviceSync>,
#[cfg(target_arch = "x86_64")] io_bus: &Bus,
io_bus: &Bus,
mmio_bus: &Bus,
bars: Vec<PciBarConfiguration>,
) -> Result<()> {
for bar in bars {
match bar.region_type() {
PciBarRegionType::IoRegion => {
#[cfg(target_arch = "x86_64")]
io_bus
.insert(dev.clone(), bar.addr(), bar.size())
.map_err(PciRootError::PioInsert)?;
#[cfg(not(target_arch = "x86_64"))]
error!("I/O region is not supported");
}
PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
mmio_bus

View File

@@ -23,7 +23,7 @@ use vfio_ioctls::{
use vm_allocator::page_size::{
align_page_size_down, align_page_size_up, is_4k_aligned, is_4k_multiple, is_page_size_aligned,
};
use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_allocator::{AddressAllocator, MemorySlotAllocator, SystemAllocator};
use vm_device::dma_mapping::ExternalDmaMapping;
use vm_device::interrupt::{
InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig,
@@ -713,11 +713,7 @@ impl VfioCommon {
let bar_addr = match region_type {
PciBarRegionType::IoRegion => {
#[cfg(not(target_arch = "x86_64"))]
unimplemented!();
// The address needs to be 4 bytes aligned.
#[cfg(target_arch = "x86_64")]
allocator
.lock()
.unwrap()
@@ -795,10 +791,7 @@ impl VfioCommon {
for region in self.mmio_regions.iter() {
match region.type_ {
PciBarRegionType::IoRegion => {
#[cfg(target_arch = "x86_64")]
allocator.free_io_addresses(region.start, region.length);
#[cfg(not(target_arch = "x86_64"))]
error!("I/O region is not supported");
}
PciBarRegionType::Memory32BitRegion => {
mmio32_allocator.free(region.start, region.length);
@@ -1416,7 +1409,7 @@ pub struct VfioPciDevice {
container: Arc<VfioContainer>,
common: VfioCommon,
iommu_attached: bool,
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
memory_slot_allocator: MemorySlotAllocator,
}
impl VfioPciDevice {
@@ -1431,7 +1424,7 @@ impl VfioPciDevice {
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
iommu_attached: bool,
bdf: PciBdf,
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
memory_slot_allocator: MemorySlotAllocator,
snapshot: Option<Snapshot>,
x_nv_gpudirect_clique: Option<u8>,
) -> Result<Self, VfioPciError> {
@@ -1457,7 +1450,7 @@ impl VfioPciDevice {
container,
common,
iommu_attached,
memory_slot,
memory_slot_allocator,
};
Ok(vfio_pci_device)
@@ -1635,7 +1628,7 @@ impl VfioPciDevice {
}
let user_memory_region = UserMemoryRegion {
slot: (self.memory_slot)(),
slot: self.memory_slot_allocator.next_memory_slot(),
start: region.start.0 + area.offset,
size: area.size,
host_addr: host_addr as u64,
@@ -1699,6 +1692,9 @@ impl VfioPciDevice {
error!("Could not remove the userspace memory region: {}", e);
}
self.memory_slot_allocator
.free_memory_slot(user_memory_region.slot);
// SAFETY: FFI call with correct arguments
let ret = unsafe {
libc::munmap(

View File

@@ -13,7 +13,7 @@ use thiserror::Error;
use vfio_bindings::bindings::vfio::*;
use vfio_ioctls::VfioIrq;
use vfio_user::{Client, Error as VfioUserError};
use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_allocator::{AddressAllocator, MemorySlotAllocator, SystemAllocator};
use vm_device::dma_mapping::ExternalDmaMapping;
use vm_device::interrupt::{InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig};
use vm_device::{BusDevice, Resource};
@@ -35,7 +35,7 @@ pub struct VfioUserPciDevice {
vm: Arc<dyn hypervisor::Vm>,
client: Arc<Mutex<Client>>,
common: VfioCommon,
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
memory_slot_allocator: MemorySlotAllocator,
}
#[derive(Error, Debug)]
@@ -74,7 +74,7 @@ impl VfioUserPciDevice {
msi_interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
bdf: PciBdf,
memory_slot: Arc<dyn Fn() -> u32 + Send + Sync>,
memory_slot_allocator: MemorySlotAllocator,
snapshot: Option<Snapshot>,
) -> Result<Self, VfioUserPciDeviceError> {
let resettable = client.lock().unwrap().resettable();
@@ -106,7 +106,7 @@ impl VfioUserPciDevice {
vm: vm.clone(),
client,
common,
memory_slot,
memory_slot_allocator,
})
}
@@ -178,7 +178,7 @@ impl VfioUserPciDevice {
}
let user_memory_region = UserMemoryRegion {
slot: (self.memory_slot)(),
slot: self.memory_slot_allocator.next_memory_slot(),
start: mmio_region.start.0 + s.offset,
size: s.size,
host_addr: host_addr as u64,
@@ -222,6 +222,9 @@ impl VfioUserPciDevice {
error!("Could not remove the userspace memory region: {}", e);
}
self.memory_slot_allocator
.free_memory_slot(user_memory_region.slot);
// Remove mmaps
// SAFETY: FFI call with correct arguments
let ret = unsafe {

View File

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

View File

@@ -1,25 +1,30 @@
- [v43.0](#v430)
- [Live Migration over TCP Connections](#live-migration-over-tcp-connections)
- [Notable Performance Improvements](#notable-performance-improvements)
- [Notable Bug Fixes](#notable-bug-fixes)
- [Contributors](#contributors)
- [v42.0](#v420)
- [SVE/SVE2 Support on AArch64](#svesve2-support-on-aarch64)
- [Notable Bug Fixes](#notable-bug-fixes)
- [Notable Bug Fixes](#notable-bug-fixes-1)
- [Sponsorships](#sponsorships)
- [Contributors](#contributors)
- [Contributors](#contributors-1)
- [v41.0](#v410)
- [Experimental "Pvmemcontrol" Support](#experimental-pvmemcontrol-support)
- [Sandboxing With Landlock Support](#sandboxing-with-landlock-support)
- [Notable Performance Improvements](#notable-performance-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-1)
- [v40.0](#v400)
- [Support for Restoring File Descriptor Backed Network Devices](#support-for-restoring-file-descriptor-backed-network-devices)
- [Notable Performance Improvements](#notable-performance-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-2)
- [Contributors](#contributors-2)
- [v40.0](#v400)
- [Support for Restoring File Descriptor Backed Network Devices](#support-for-restoring-file-descriptor-backed-network-devices)
- [Notable Bug Fixes](#notable-bug-fixes-3)
- [Contributors](#contributors-3)
- [v39.0](#v390)
- [Variable Sizing of PCI Apertures for Segments](#variable-sizing-of-pci-apertures-for-segments)
- [Direct Booting with bzImages](#direct-booting-with-bzimages)
- [Support for NVIDIA GPUDirect P2P Support](#support-for-nvidia-gpudirect-p2p-support)
- [Guest NMI Injection Support](#guest-nmi-injection-support)
- [Notable Bug Fixes](#notable-bug-fixes-3)
- [Contributors](#contributors-3)
- [Notable Bug Fixes](#notable-bug-fixes-4)
- [Contributors](#contributors-4)
- [v38.0](#v380)
- [Group Rate Limiter on Block Devices](#group-rate-limiter-on-block-devices)
- [CPU Pinning Support for Block Device Worker Thread](#cpu-pinning-support-for-block-device-worker-thread)
@@ -27,16 +32,16 @@
- [New 'debug-console' Device](#new-debug-console-device)
- [Improved VFIO Device Support](#improved-vfio-device-support)
- [Extended CPU Affinity Support](#extended-cpu-affinity-support)
- [Notable Bug Fixes](#notable-bug-fixes-4)
- [Contributors](#contributors-4)
- [Notable Bug Fixes](#notable-bug-fixes-5)
- [Contributors](#contributors-5)
- [v37.0](#v370)
- [Long Term Support (LTS) Release](#long-term-support-lts-release)
- [Multiple PCI segments Support for 32-bit VFIO devices](#multiple-pci-segments-support-for-32-bit-vfio-devices)
- [Configurable Named TAP Devices](#configurable-named-tap-devices)
- [TTY Output from Both Serial Device and Virtio Console](#tty-output-from-both-serial-device-and-virtio-console)
- [Faster VM Restoration from Snapshots](#faster-vm-restoration-from-snapshots)
- [Notable Bug Fixes](#notable-bug-fixes-5)
- [Contributors](#contributors-5)
- [Notable Bug Fixes](#notable-bug-fixes-6)
- [Contributors](#contributors-6)
- [v36.0](#v360)
- [Command Line Changes](#command-line-changes)
- [Enabled Features Reported via API Endpoint and CLI](#enabled-features-reported-via-api-endpoint-and-cli)
@@ -45,31 +50,31 @@
- [Unix Socket Backend for Serial Port](#unix-socket-backend-for-serial-port)
- [AIO Backend for Block Devices](#aio-backend-for-block-devices)
- [Documentation Improvements](#documentation-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-6)
- [Contributors](#contributors-6)
- [Notable Bug Fixes](#notable-bug-fixes-7)
- [Contributors](#contributors-7)
- [v35.0](#v350)
- [`virtio-vsock` Support for Linux Guest Kernel v6.3+](#virtio-vsock-support-for-linux-guest-kernel-v63)
- [User Specified Serial Number for `virtio-block`](#user-specified-serial-number-for-virtio-block)
- [vCPU TSC Frequency Included in Migration State](#vcpu-tsc-frequency-included-in-migration-state)
- [Notable Bug Fixes](#notable-bug-fixes-7)
- [Contributors](#contributors-7)
- [Notable Bug Fixes](#notable-bug-fixes-8)
- [Contributors](#contributors-8)
- [v34.0](#v340)
- [Paravirtualised Panic Device Support](#paravirtualised-panic-device-support)
- [Improvements to VM Core Dump](#improvements-to-vm-core-dump)
- [QCOW2 Support for Backing Files](#qcow2-support-for-backing-files)
- [Minimum Host Kernel Bump](#minimum-host-kernel-bump)
- [Notable Bug Fixes](#notable-bug-fixes-8)
- [Contributors](#contributors-8)
- [Notable Bug Fixes](#notable-bug-fixes-9)
- [Contributors](#contributors-9)
- [v33.0](#v330)
- [D-Bus based API](#d-bus-based-api)
- [Expose Host CPU Cache Details for AArch64](#expose-host-cpu-cache-details-for-aarch64)
- [Notable Bug Fixes](#notable-bug-fixes-9)
- [Contributors](#contributors-9)
- [Notable Bug Fixes](#notable-bug-fixes-10)
- [Contributors](#contributors-10)
- [v32.0](#v320)
- [Increased PCI Segment Limit](#increased-pci-segment-limit)
- [API Changes](#api-changes)
- [Notable Bug Fixes](#notable-bug-fixes-10)
- [Contributors](#contributors-10)
- [Notable Bug Fixes](#notable-bug-fixes-11)
- [Contributors](#contributors-11)
- [v31.1](#v311)
- [v31.0](#v310)
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
@@ -77,15 +82,15 @@
- [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler)
- [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile)
- [Documentation Improvements](#documentation-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-11)
- [Contributors](#contributors-11)
- [Notable Bug Fixes](#notable-bug-fixes-12)
- [Contributors](#contributors-12)
- [v30.0](#v300)
- [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size)
- [Basic vfio-user Server Support](#basic-vfio-user-server-support)
- [Heap Profiling Support](#heap-profiling-support)
- [Documentation Improvements](#documentation-improvements-2)
- [Notable Bug Fixes](#notable-bug-fixes-12)
- [Contributors](#contributors-12)
- [Notable Bug Fixes](#notable-bug-fixes-13)
- [Contributors](#contributors-13)
- [v28.2](#v282)
- [v29.0](#v290)
- [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm)
@@ -95,10 +100,10 @@
- [`AArch64` Documentation Integration](#aarch64-documentation-integration)
- [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement)
- [TCP Offload Control](#tcp-offload-control)
- [Notable Bug Fixes](#notable-bug-fixes-13)
- [Notable Bug Fixes](#notable-bug-fixes-14)
- [Removals](#removals)
- [Deprecations](#deprecations)
- [Contributors](#contributors-13)
- [Contributors](#contributors-14)
- [v28.1](#v281)
- [v28.0](#v280)
- [Community Engagement (Reminder)](#community-engagement-reminder)
@@ -106,9 +111,9 @@
- [Virtualised TPM Support](#virtualised-tpm-support)
- [Transparent Huge Page Support](#transparent-huge-page-support)
- [README Quick Start Improved](#readme-quick-start-improved)
- [Notable Bug Fixes](#notable-bug-fixes-14)
- [Notable Bug Fixes](#notable-bug-fixes-15)
- [Removals](#removals-1)
- [Contributors](#contributors-14)
- [Contributors](#contributors-15)
- [v27.0](#v270)
- [Community Engagement](#community-engagement)
- [Prebuilt Packages](#prebuilt-packages)
@@ -117,41 +122,41 @@
- [Simplified Build Feature Flags](#simplified-build-feature-flags)
- [Asynchronous Kernel Loading](#asynchronous-kernel-loading)
- [GDB Support for AArch64](#gdb-support-for-aarch64)
- [Notable Bug Fixes](#notable-bug-fixes-15)
- [Notable Bug Fixes](#notable-bug-fixes-16)
- [Deprecations](#deprecations-1)
- [Contributors](#contributors-15)
- [Contributors](#contributors-16)
- [v26.0](#v260)
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform)
- [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support)
- [Notable Bug Fixes](#notable-bug-fixes-16)
- [Notable Bug Fixes](#notable-bug-fixes-17)
- [Deprecations](#deprecations-2)
- [Removals](#removals-2)
- [Contributors](#contributors-16)
- [Contributors](#contributors-17)
- [v25.0](#v250)
- [`ch-remote` Improvements](#ch-remote-improvements-1)
- [VM "Coredump" Support](#vm-coredump-support)
- [Notable Bug Fixes](#notable-bug-fixes-17)
- [Notable Bug Fixes](#notable-bug-fixes-18)
- [Removals](#removals-3)
- [Contributors](#contributors-17)
- [Contributors](#contributors-18)
- [v24.0](#v240)
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
- [Sparse Mmap support](#sparse-mmap-support)
- [Expose Platform Serial Number](#expose-platform-serial-number)
- [Notable Bug Fixes](#notable-bug-fixes-18)
- [Notable Bug Fixes](#notable-bug-fixes-19)
- [Notable Improvements](#notable-improvements)
- [Deprecations](#deprecations-3)
- [New on the Website](#new-on-the-website)
- [Contributors](#contributors-18)
- [Contributors](#contributors-19)
- [v23.1](#v231)
- [v23.0](#v230)
- [vDPA Support](#vdpa-support)
- [Updated OS Support list](#updated-os-support-list)
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
- [`AMX` Support](#amx-support)
- [Notable Bug Fixes](#notable-bug-fixes-19)
- [Notable Bug Fixes](#notable-bug-fixes-20)
- [Deprecations](#deprecations-4)
- [Contributors](#contributors-19)
- [Contributors](#contributors-20)
- [v22.1](#v221)
- [v22.0](#v220)
- [GDB Debug Stub Support](#gdb-debug-stub-support)
@@ -162,13 +167,13 @@
- [PMU Support for AArch64](#pmu-support-for-aarch64)
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
- [Notable Bug Fixes](#notable-bug-fixes-20)
- [Contributors](#contributors-20)
- [Notable Bug Fixes](#notable-bug-fixes-21)
- [Contributors](#contributors-21)
- [v21.0](#v210)
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
- [Notable Bug fixes](#notable-bug-fixes-21)
- [Contributors](#contributors-21)
- [Notable Bug fixes](#notable-bug-fixes-22)
- [Contributors](#contributors-22)
- [v20.2](#v202)
- [v20.1](#v201)
- [v20.0](#v200)
@@ -177,8 +182,8 @@
- [Improved VFIO support](#improved-vfio-support)
- [Safer code](#safer-code)
- [Extended documentation](#extended-documentation)
- [Notable bug fixes](#notable-bug-fixes-22)
- [Contributors](#contributors-22)
- [Notable bug fixes](#notable-bug-fixes-23)
- [Contributors](#contributors-23)
- [v19.0](#v190)
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
- [PCI boot time optimisations](#pci-boot-time-optimisations)
@@ -186,8 +191,8 @@
- [Live migration enhancements](#live-migration-enhancements)
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
- [Notable bug fixes](#notable-bug-fixes-23)
- [Contributors](#contributors-23)
- [Notable bug fixes](#notable-bug-fixes-24)
- [Contributors](#contributors-24)
- [v18.0](#v180)
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
@@ -197,23 +202,23 @@
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
- [Power button support on AArch64](#power-button-support-on-aarch64)
- [Notable bug fixes](#notable-bug-fixes-24)
- [Contributors](#contributors-24)
- [Notable bug fixes](#notable-bug-fixes-25)
- [Contributors](#contributors-25)
- [v17.0](#v170)
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
- [Improved SGX support](#improved-sgx-support)
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
- [Notable bug fixes](#notable-bug-fixes-25)
- [Contributors](#contributors-25)
- [Notable bug fixes](#notable-bug-fixes-26)
- [Contributors](#contributors-26)
- [v16.0](#v160)
- [Improved live migration support](#improved-live-migration-support)
- [Improved `vhost-user` support](#improved-vhost-user-support)
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
- [Notable bug fixes](#notable-bug-fixes-26)
- [Notable bug fixes](#notable-bug-fixes-27)
- [Removed functionality](#removed-functionality)
- [Contributors](#contributors-26)
- [Contributors](#contributors-27)
- [v15.0](#v150)
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
- [Network device rate limiting](#network-device-rate-limiting)
@@ -221,7 +226,7 @@
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
- [Bug fixes](#bug-fixes)
- [Deprecations](#deprecations-5)
- [Contributors](#contributors-27)
- [Contributors](#contributors-28)
- [v0.14.1](#v0141)
- [v0.14.0](#v0140)
- [Structured event monitoring](#structured-event-monitoring)
@@ -231,7 +236,7 @@
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
- [Block device rate limiting](#block-device-rate-limiting)
- [Deprecations](#deprecations-6)
- [Contributors](#contributors-28)
- [Contributors](#contributors-29)
- [v0.13.0](#v0130)
- [Wider VFIO device support](#wider-vfio-device-support)
- [Improved huge page support](#improved-huge-page-support)
@@ -239,13 +244,13 @@
- [VHD disk image support](#vhd-disk-image-support)
- [Improved Virtio device threading](#improved-virtio-device-threading)
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
- [Contributors](#contributors-29)
- [Contributors](#contributors-30)
- [v0.12.0](#v0120)
- [ARM64 enhancements](#arm64-enhancements)
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
- [Enhanced "info" API](#enhanced-info-api)
- [Contributors](#contributors-30)
- [Contributors](#contributors-31)
- [v0.11.0](#v0110)
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
- [Windows Guest Support](#windows-guest-support)
@@ -257,15 +262,15 @@
- [Default Log Level Changed](#default-log-level-changed)
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
- [Notable Bug Fixes](#notable-bug-fixes-27)
- [Contributors](#contributors-31)
- [Notable Bug Fixes](#notable-bug-fixes-28)
- [Contributors](#contributors-32)
- [v0.10.0](#v0100)
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
- [Memory Zones](#memory-zones)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
- [Notable Bug Fixes](#notable-bug-fixes-28)
- [Contributors](#contributors-32)
- [Notable Bug Fixes](#notable-bug-fixes-29)
- [Contributors](#contributors-33)
- [v0.9.0](#v090)
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
- [Block and Network Device Statistics](#block-and-network-device-statistics)
@@ -278,17 +283,17 @@
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
- [Intel SGX Support](#intel-sgx-support)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-29)
- [Contributors](#contributors-33)
- [Notable Bug Fixes](#notable-bug-fixes-30)
- [Contributors](#contributors-34)
- [v0.8.0](#v080)
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
- [Experimental ARM64 Support](#experimental-arm64-support)
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-30)
- [Notable Bug Fixes](#notable-bug-fixes-31)
- [Command Line and API Changes](#command-line-and-api-changes)
- [Contributors](#contributors-34)
- [Contributors](#contributors-35)
- [v0.7.0](#v070)
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
- [Alternative `libc` Support](#alternative-libc-support)
@@ -298,14 +303,14 @@
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
- [Updated Distribution Support](#updated-distribution-support)
- [Command Line and API Changes](#command-line-and-api-changes-1)
- [Contributors](#contributors-35)
- [Contributors](#contributors-36)
- [v0.6.0](#v060)
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
- [Command Line Interface](#command-line-interface)
- [PVH Boot](#pvh-boot)
- [Contributors](#contributors-36)
- [Contributors](#contributors-37)
- [v0.5.1](#v051)
- [v0.5.0](#v050)
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
@@ -313,7 +318,7 @@
- [New Interrupt Management Framework](#new-interrupt-management-framework)
- [Development Tools](#development-tools)
- [Kata Containers Integration](#kata-containers-integration)
- [Contributors](#contributors-37)
- [Contributors](#contributors-38)
- [v0.4.0](#v040)
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
@@ -322,7 +327,7 @@
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
- [PCI BAR reprogramming](#pci-bar-reprogramming)
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
- [Contributors](#contributors-38)
- [Contributors](#contributors-39)
- [v0.3.0](#v030)
- [Block device offloading](#block-device-offloading)
- [Network device backend](#network-device-backend)
@@ -349,6 +354,48 @@
- [Unit testing](#unit-testing)
- [Integration tests parallelization](#integration-tests-parallelization)
# v43.0
This release has been tracked in our [roadmap
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
v43.0. The following user visible changes have been made:
### Live Migration over TCP Connections
Support has been added to enable direct live migration from two hosts via TCP
connections. This supplements the existing support for migrating over a UNIX
socket which can then be tunnelled as desired. The documentation has been
updated. (#6850)
### Notable Performance Improvements
The `VIRTIO_RING_F_INDIRECT_DESC` feature has been enabled for `virtio-block`
devices. This significantly increases the throughput of the devices with a
small negative impact on latency. (#6826)
### Notable Bug Fixes
* Cloud Hypervisor now accepts VFIO devices that use I/O PCI BARs on non x86-64
architectures. Whether they function depends on the host PCI host bridge
support - previously they would be rejected even if the driver did not use
these BARs. (#6871)
* Command line groups were adjusted to ensure that at least one payload
parameter was provided if any other VM parameters provided. (#6832)
### Contributors
Many thanks to everyone who has contributed to our release:
* Alyssa Ross <hi@alyssa.is>
* Andrew Consroe <aconz2@gmail.com>
* Bo Chen <bo.arvin.chen@gmail.com>
* Jinrong Liang <cloudliang@tencent.com>
* Julian Stecklina <julian.stecklina@cyberus-technology.de>
* Muminul Islam <muislam@microsoft.com>
* Rob Bradford <rbradford@rivosinc.com>
* Ruoqing He <heruoqing@iscas.ac.cn>
* Wojtek Czekalski <wczekalski@me.com>
# v42.0
This release has been tracked in our [roadmap

View File

@@ -0,0 +1,83 @@
#!/bin/env python3
#
# Copyright © 2024 Institute of Software, CAS. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
import subprocess
import json
from argparse import ArgumentParser
from collections import defaultdict
def get_cargo_metadata():
result = subprocess.run(
['cargo', 'metadata', '--format-version=1'],
capture_output=True,
text=True
)
if result.returncode != 0:
exit(1)
metadata = json.loads(result.stdout)
return metadata
def find_dependents_of_package(metadata, package_source):
"""Find dependencies based on the provided source identifier and return related package info."""
packages = defaultdict(list)
direct_dependents = defaultdict(list)
# Identify packages from the given package source and record version
for pkg in metadata['packages']:
repository = pkg['repository'] or ''
if package_source in repository:
packages[pkg['name']].append(pkg['version'])
# Find packages that immediately depend on the identified source packages
for node in metadata['resolve']['nodes']:
current_pkg = next(pkg for pkg in metadata['packages'] if pkg['id'] == node['id'])
current_pkg_name = current_pkg['name']
current_pkg_version = current_pkg['version']
for dep_id in node['dependencies']:
dep_pkg = next(pkg for pkg in metadata['packages'] if pkg['id'] == dep_id)
dep_name = dep_pkg['name']
dep_version = dep_pkg['version']
if dep_name in packages:
direct_dependents[(dep_name, dep_version)].append((current_pkg_name, current_pkg_version))
return packages, direct_dependents
def check_for_version_conflicts(packages, direct_dependents):
"""Check if there are multiple versions of dependencies, and return True if conflicts are found."""
has_conflicts = False
for pkg_name, versions in packages.items():
if len(set(versions)) > 1:
has_conflicts = True
print(f"Error: Multiple versions detected for {pkg_name}: {set(versions)}")
for version in set(versions):
print(f" Version {version} used by:")
for dependent, dep_version in direct_dependents[(pkg_name, version)]:
print(f" - {dependent} v{dep_version}")
return has_conflicts
if __name__ == '__main__':
parser = ArgumentParser(description='Cargo dependency conflict checker.')
parser.add_argument('package_source', type=str, help='A keyword used to match the repository URL field')
args = parser.parse_args()
metadata = get_cargo_metadata()
if metadata is None:
print("Error: Metadata is empty")
exit(1)
packages, direct_dependents = find_dependents_of_package(metadata, args.package_source)
has_conflicts = check_for_version_conflicts(packages, direct_dependents)
if has_conflicts:
exit(1)

View File

@@ -154,8 +154,8 @@ update_workloads() {
fi
popd || exit
# Download prebuild linux binaries
download_linux
# Prepare linux image (build from source or download pre-built)
prepare_linux
# Update the kernel in the cloud image for some tests that requires recent kernel version
FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_NAME="focal-server-cloudimg-arm64-custom-20210929-0-update-kernel.raw"

View File

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

View File

@@ -44,8 +44,8 @@ if ! grep focal sha1sums-x86_64 | sha1sum --check; then
fi
popd || exit
# Download prebuild linux binaries
download_linux
# Prepare linux image (build from source or download pre-built)
prepare_linux
CFLAGS=""
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then

View File

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

View File

@@ -80,8 +80,8 @@ if [ "${TEST_ARCH}" == "aarch64" ]; then
guestunmount "$FOCAL_OS_RAW_IMAGE_UPDATE_TOOL_ROOT_DIR"
fi
# Download prebuild linux binaries
download_linux
# Prepare linux image (build from source or download pre-built)
prepare_linux
CFLAGS=""
if [[ "${BUILD_TARGET}" == "${TEST_ARCH}-unknown-linux-musl" ]]; then

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env bash
hypervisor="kvm"
test_filter=""
build_kernel=false
# Checkout source code of a GIT repo with specified branch and commit
# Args:
@@ -75,11 +76,13 @@ cmd_help() {
echo ""
echo " --hypervisor Underlying hypervisor. Options kvm, mshv"
echo " --test-filter Tests to run"
echo " --build-guest-kernel Build guest kernel from source instead of downloading pre-built"
echo ""
echo " --help Display this help message."
echo ""
}
# shellcheck disable=SC2034
process_common_args() {
while [ $# -gt 0 ]; do
case "$1" in
@@ -93,9 +96,11 @@ process_common_args() {
;;
"--test-filter")
shift
# shellcheck disable=SC2034
test_filter="$1"
;;
"--build-guest-kernel")
build_kernel=true
;;
"--") {
shift
break
@@ -115,14 +120,17 @@ process_common_args() {
}
download_hypervisor_fw() {
FW_TAG="0.5.0"
if [ -n "$AUTH_DOWNLOAD_TOKEN" ]; then
echo "Using authenticated download from GitHub"
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest \
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/tags/${FW_TAG} \
--header "Authorization: Token $AUTH_DOWNLOAD_TOKEN" \
--header "X-GitHub-Api-Version: 2022-11-28" | grep "browser_download_url" | grep -o 'https://.*[^ "]')
--header "X-GitHub-Api-Version: 2022-11-28" | grep "browser_download_url" |
grep -oP '"https://[^"]*hypervisor-fw"' | sed -e 's/^"//' -e 's/"$//')
else
echo "Using anonymous download from GitHub"
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/tags/${FW_TAG} |
grep "browser_download_url" | grep -oP '"https://[^"]*hypervisor-fw"' | sed -e 's/^"//' -e 's/"$//')
fi
FW="$WORKLOADS_DIR/hypervisor-fw"
pushd "$WORKLOADS_DIR" || exit
@@ -149,6 +157,18 @@ download_linux() {
popd || exit
}
prepare_linux() {
if [ "$build_kernel" = true ]; then
echo "Building kernel from source"
build_custom_linux
echo "Using kernel built from source"
else
echo "Downloading pre-built kernel from GitHub"
download_linux
echo "Using kernel downloaded from GitHub"
fi
}
download_ovmf() {
OVMF_FW_TAG="ch-6624aa331f"
OVMF_FW_URL="https://github.com/cloud-hypervisor/edk2/releases/download/$OVMF_FW_TAG/CLOUDHV.fd"

View File

@@ -184,9 +184,10 @@ fn create_app(default_vcpus: String, default_memory: String, default_rng: String
.author(env!("CARGO_PKG_AUTHORS"))
.about("Launch a cloud-hypervisor VMM.")
.arg_required_else_help(true)
.group(ArgGroup::new("vm-config").multiple(true))
.group(ArgGroup::new("vm-config").multiple(true).requires("vm-payload"))
.group(ArgGroup::new("vmm-config").multiple(true))
.group(ArgGroup::new("logging").multiple(true))
.group(ArgGroup::new("vm-payload").multiple(true))
.arg(
Arg::new("cpus")
.long("cpus")
@@ -243,7 +244,7 @@ fn create_app(default_vcpus: String, default_memory: String, default_rng: String
.long("firmware")
.help("Path to firmware that is loaded in an architectural specific way")
.num_args(1)
.group("vm-config"),
.group("vm-payload"),
)
.arg(
Arg::new("kernel")
@@ -253,7 +254,7 @@ fn create_app(default_vcpus: String, default_memory: String, default_rng: String
entry point (e.g. vmlinux) or architecture equivalent",
)
.num_args(1)
.group("vm-config"),
.group("vm-payload"),
)
.arg(
Arg::new("initramfs")
@@ -459,7 +460,7 @@ fn create_app(default_vcpus: String, default_memory: String, default_rng: String
.long("tpm")
.num_args(1)
.help(TpmConfig::SYNTAX)
.group("vmm-config"),
.group("vm-config"),
);
#[cfg(target_arch = "x86_64")]
@@ -519,7 +520,7 @@ fn create_app(default_vcpus: String, default_memory: String, default_rng: String
.long("igvm")
.help("Path to IGVM file to load.")
.num_args(1)
.group("vm-config"),
.group("vm-payload"),
);
#[cfg(feature = "sev_snp")]
let app = app.arg(

View File

@@ -7,7 +7,7 @@ version = "0.1.0"
[dependencies]
dirs = "5.0.1"
epoll = "4.3.3"
libc = "0.2.158"
libc = "0.2.167"
once_cell = "1.20.2"
serde = { version = "1.0.208", features = ["derive", "rc"] }
serde_json = "1.0.120"

View File

@@ -12,12 +12,14 @@ extern crate test_infra;
use std::collections::HashMap;
use std::io::{BufRead, Read, Seek, Write};
use std::net::TcpListener;
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use std::process::{Child, Command, Stdio};
use std::string::String;
use std::sync::mpsc::Receiver;
use std::sync::{mpsc, Mutex};
use std::time::Duration;
use std::{fs, io, thread};
use net_util::MacAddr;
@@ -9401,7 +9403,7 @@ mod live_migration {
// Check the source vm has been terminated successful (give it '3s' to settle)
thread::sleep(std::time::Duration::new(3, 0));
if !src_child.try_wait().unwrap().map_or(false, |s| s.success()) {
if !src_child.try_wait().unwrap().is_some_and(|s| s.success()) {
print_and_panic(
src_child,
dest_child,
@@ -9575,7 +9577,7 @@ mod live_migration {
// Check the source vm has been terminated successful (give it '3s' to settle)
thread::sleep(std::time::Duration::new(3, 0));
if !src_child.try_wait().unwrap().map_or(false, |s| s.success()) {
if !src_child.try_wait().unwrap().is_some_and(|s| s.success()) {
print_and_panic(
src_child,
dest_child,
@@ -9793,7 +9795,7 @@ mod live_migration {
// Check the source vm has been terminated successful (give it '3s' to settle)
thread::sleep(std::time::Duration::new(3, 0));
if !src_child.try_wait().unwrap().map_or(false, |s| s.success()) {
if !src_child.try_wait().unwrap().is_some_and(|s| s.success()) {
print_and_panic(
src_child,
dest_child,
@@ -10009,7 +10011,7 @@ mod live_migration {
// Check the source vm has been terminated successful (give it '3s' to settle)
thread::sleep(std::time::Duration::new(3, 0));
if !src_child.try_wait().unwrap().map_or(false, |s| s.success()) {
if !src_child.try_wait().unwrap().is_some_and(|s| s.success()) {
print_and_panic(
src_child,
dest_child,
@@ -10119,7 +10121,7 @@ mod live_migration {
// Check the source vm has been terminated successful (give it '3s' to settle)
thread::sleep(std::time::Duration::new(3, 0));
if !src_child.try_wait().unwrap().map_or(false, |s| s.success()) {
if !src_child.try_wait().unwrap().is_some_and(|s| s.success()) {
print_and_panic(
src_child,
dest_child,
@@ -10266,7 +10268,7 @@ mod live_migration {
// Check the source vm has been terminated successful (give it '3s' to settle)
thread::sleep(std::time::Duration::new(3, 0));
if !src_child.try_wait().unwrap().map_or(false, |s| s.success()) {
if !src_child.try_wait().unwrap().is_some_and(|s| s.success()) {
print_and_panic(
src_child,
dest_child,
@@ -10295,6 +10297,220 @@ mod live_migration {
handle_child_output(r, &dest_output);
}
// Function to get an available port
fn get_available_port() -> u16 {
TcpListener::bind("127.0.0.1:0")
.expect("Failed to bind to address")
.local_addr()
.unwrap()
.port()
}
fn start_live_migration_tcp(src_api_socket: &str, dest_api_socket: &str) -> bool {
// Get an available TCP port
let migration_port = get_available_port();
let host_ip = "127.0.0.1";
// Start the 'receive-migration' command on the destination
let mut receive_migration = Command::new(clh_command("ch-remote"))
.args([
&format!("--api-socket={}", dest_api_socket),
"receive-migration",
&format!("tcp:0.0.0.0:{}", migration_port),
])
.stdin(Stdio::null())
.stderr(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap();
// Give the destination some time to start listening
thread::sleep(Duration::from_secs(1));
// Start the 'send-migration' command on the source
let mut send_migration = Command::new(clh_command("ch-remote"))
.args([
&format!("--api-socket={}", src_api_socket),
"send-migration",
&format!("tcp:{}:{}", host_ip, migration_port),
])
.stdin(Stdio::null())
.stderr(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap();
// Check if the 'send-migration' command executed successfully
let send_success = if let Some(status) = send_migration
.wait_timeout(Duration::from_secs(60))
.unwrap()
{
status.success()
} else {
false
};
if !send_success {
let _ = send_migration.kill();
let output = send_migration.wait_with_output().unwrap();
eprintln!(
"\n\n==== Start 'send_migration' output ====\n\n---stdout---\n{}\n\n---stderr---\n{}\n\n==== End 'send_migration' output ====\n\n",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
// Check if the 'receive-migration' command executed successfully
let receive_success = if let Some(status) = receive_migration
.wait_timeout(Duration::from_secs(60))
.unwrap()
{
status.success()
} else {
false
};
if !receive_success {
let _ = receive_migration.kill();
let output = receive_migration.wait_with_output().unwrap();
eprintln!(
"\n\n==== Start 'receive_migration' output ====\n\n---stdout---\n{}\n\n---stderr---\n{}\n\n==== End 'receive_migration' output ====\n\n",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
send_success && receive_success
}
fn _test_live_migration_tcp() {
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = Guest::new(Box::new(focal));
let kernel_path = direct_kernel_boot_path();
let console_text = String::from("On a branch floating down river a cricket, singing.");
let net_id = "net123";
let net_params = format!(
"id={},tap=,mac={},ip={},mask=255.255.255.0",
net_id, guest.network.guest_mac, guest.network.host_ip
);
let memory_param: &[&str] = &["--memory", "size=4G,shared=on"];
let boot_vcpus = 2;
let max_vcpus = 4;
let pmem_temp_file = TempFile::new().unwrap();
pmem_temp_file.as_file().set_len(128 << 20).unwrap();
std::process::Command::new("mkfs.ext4")
.arg(pmem_temp_file.as_path())
.output()
.expect("Expect creating disk image to succeed");
let pmem_path = String::from("/dev/pmem0");
// Start the source VM
let src_vm_path = clh_command("cloud-hypervisor");
let src_api_socket = temp_api_path(&guest.tmp_dir);
let mut src_vm_cmd = GuestCommand::new_with_binary_path(&guest, &src_vm_path);
src_vm_cmd
.args([
"--cpus",
format!("boot={},max={}", boot_vcpus, max_vcpus).as_str(),
])
.args(memory_param)
.args(["--kernel", kernel_path.to_str().unwrap()])
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
.default_disks()
.args(["--net", net_params.as_str()])
.args(["--api-socket", &src_api_socket])
.args([
"--pmem",
format!(
"file={},discard_writes=on",
pmem_temp_file.as_path().to_str().unwrap(),
)
.as_str(),
])
.capture_output();
let mut src_child = src_vm_cmd.spawn().unwrap();
// Start the destination VM
let mut dest_api_socket = temp_api_path(&guest.tmp_dir);
dest_api_socket.push_str(".dest");
let mut dest_child = GuestCommand::new(&guest)
.args(["--api-socket", &dest_api_socket])
.capture_output()
.spawn()
.unwrap();
let r = std::panic::catch_unwind(|| {
guest.wait_vm_boot(None).unwrap();
// Ensure the source VM is running normally
assert_eq!(guest.get_cpu_count().unwrap_or_default(), boot_vcpus);
assert!(guest.get_total_memory().unwrap_or_default() > 3_840_000);
guest.check_devices_common(None, Some(&console_text), Some(&pmem_path));
// On x86_64 architecture, remove and re-add the virtio-net device
#[cfg(target_arch = "x86_64")]
{
assert!(remote_command(
&src_api_socket,
"remove-device",
Some(net_id),
));
thread::sleep(Duration::new(10, 0));
// Re-add the virtio-net device
assert!(remote_command(
&src_api_socket,
"add-net",
Some(net_params.as_str()),
));
thread::sleep(Duration::new(10, 0));
}
// Start TCP live migration
assert!(
start_live_migration_tcp(&src_api_socket, &dest_api_socket),
"Unsuccessful command: 'send-migration' or 'receive-migration'."
);
});
// Check and report any errors that occurred during live migration
if r.is_err() {
print_and_panic(
src_child,
dest_child,
None,
"Error occurred during live-migration",
);
}
// Check the source vm has been terminated successful (give it '3s' to settle)
thread::sleep(std::time::Duration::new(3, 0));
if !src_child.try_wait().unwrap().is_some_and(|s| s.success()) {
print_and_panic(
src_child,
dest_child,
None,
"Source VM was not terminated successfully.",
);
};
// After live migration, ensure the destination VM is running normally
let r = std::panic::catch_unwind(|| {
// Perform the same checks to ensure the VM has migrated correctly
assert_eq!(guest.get_cpu_count().unwrap_or_default(), boot_vcpus);
assert!(guest.get_total_memory().unwrap_or_default() > 3_840_000);
guest.check_devices_common(None, Some(&console_text), Some(&pmem_path));
});
// Clean up the destination VM and ensure it terminates properly
let _ = dest_child.kill();
let dest_output = dest_child.wait_with_output().unwrap();
handle_child_output(r, &dest_output);
// Check if the expected `console_text` is present in the destination VM's output
let r = std::panic::catch_unwind(|| {
assert!(String::from_utf8_lossy(&dest_output.stdout).contains(&console_text));
});
handle_child_output(r, &dest_output);
}
mod live_migration_parallel {
use super::*;
#[test]
@@ -10307,6 +10523,11 @@ mod live_migration {
_test_live_migration(false, true)
}
#[test]
fn test_live_migration_tcp() {
_test_live_migration_tcp();
}
#[test]
fn test_live_migration_watchdog() {
_test_live_migration_watchdog(false, false)

View File

@@ -5,7 +5,7 @@ name = "tracer"
version = "0.1.0"
[dependencies]
libc = "0.2.158"
libc = "0.2.167"
log = "0.4.22"
once_cell = "1.20.2"
serde = { version = "1.0.208", features = ["derive", "rc"] }

View File

@@ -10,11 +10,11 @@ block = { path = "../block" }
clap = { version = "4.5.13", features = ["cargo", "wrap_help"] }
env_logger = "0.11.3"
epoll = "4.3.3"
libc = "0.2.158"
libc = "0.2.167"
log = "0.4.22"
option_parser = { path = "../option_parser" }
vhost = { workspace = true, features = ["vhost-user-backend"] }
vhost-user-backend = "0.16.0"
vhost-user-backend = { workspace = true }
virtio-bindings = { workspace = true }
virtio-queue = { workspace = true }
vm-memory = { workspace = true }

View File

@@ -9,12 +9,12 @@ version = "0.1.0"
clap = { version = "4.5.13", features = ["cargo", "wrap_help"] }
env_logger = "0.11.3"
epoll = "4.3.3"
libc = "0.2.158"
libc = "0.2.167"
log = "0.4.22"
net_util = { path = "../net_util" }
option_parser = { path = "../option_parser" }
vhost = { workspace = true, features = ["vhost-user-backend"] }
vhost-user-backend = "0.16.0"
vhost-user-backend = { workspace = true }
virtio-bindings = { workspace = true }
vm-memory = { workspace = true }
vmm-sys-util = { workspace = true }

View File

@@ -9,13 +9,13 @@ default = []
sev_snp = ["mshv-ioctls"]
[dependencies]
anyhow = "1.0.87"
anyhow = "1.0.94"
arc-swap = "1.7.1"
block = { path = "../block" }
byteorder = "1.5.0"
epoll = "4.3.3"
event_monitor = { path = "../event_monitor" }
libc = "0.2.158"
libc = "0.2.167"
log = "0.4.22"
mshv-ioctls = { workspace = true, optional = true }
net_gen = { path = "../net_gen" }

View File

@@ -27,7 +27,7 @@ use serde::{Deserialize, Serialize};
use thiserror::Error;
use virtio_bindings::virtio_blk::*;
use virtio_bindings::virtio_config::*;
use virtio_bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
use virtio_bindings::virtio_ring::{VIRTIO_RING_F_EVENT_IDX, VIRTIO_RING_F_INDIRECT_DESC};
use virtio_queue::{Queue, QueueOwnedT, QueueT};
use vm_memory::{ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryError};
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
@@ -489,8 +489,7 @@ impl EpollHelperHandler for BlockEpollHandler {
EpollHelperError::HandleEvent(anyhow!("Failed to get queue event: {:?}", e))
})?;
let rate_limit_reached =
self.rate_limiter.as_ref().map_or(false, |r| r.is_blocked());
let rate_limit_reached = self.rate_limiter.as_ref().is_some_and(|r| r.is_blocked());
// Process the queue only when the rate limit is not reached
if !rate_limit_reached {
@@ -509,8 +508,7 @@ impl EpollHelperHandler for BlockEpollHandler {
))
})?;
let rate_limit_reached =
self.rate_limiter.as_ref().map_or(false, |r| r.is_blocked());
let rate_limit_reached = self.rate_limiter.as_ref().is_some_and(|r| r.is_blocked());
// Process the queue only when the rate limit is not reached
if !rate_limit_reached {
@@ -627,8 +625,8 @@ impl Block {
| (1u64 << VIRTIO_BLK_F_CONFIG_WCE)
| (1u64 << VIRTIO_BLK_F_BLK_SIZE)
| (1u64 << VIRTIO_BLK_F_TOPOLOGY)
| (1u64 << VIRTIO_RING_F_EVENT_IDX);
| (1u64 << VIRTIO_RING_F_EVENT_IDX)
| (1u64 << VIRTIO_RING_F_INDIRECT_DESC);
if iommu {
avail_features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM;
}

View File

@@ -201,7 +201,7 @@ impl NetEpollHandler {
.net
.rx_rate_limiter
.as_ref()
.map_or(false, |r| r.is_blocked());
.is_some_and(|r| r.is_blocked());
// Start to listen on RX_TAP_EVENT only when the rate limit is not reached
if !self.net.rx_tap_listening && !rate_limit_reached {
@@ -238,7 +238,7 @@ impl NetEpollHandler {
.net
.tx_rate_limiter
.as_ref()
.map_or(false, |r| r.is_blocked());
.is_some_and(|r| r.is_blocked());
if !rate_limit_reached {
self.process_tx()?;

View File

@@ -4,9 +4,13 @@ edition = "2021"
name = "vm-allocator"
version = "0.1.0"
[features]
default = []
kvm = ["arch/kvm"]
[dependencies]
libc = "0.2.158"
libc = "0.2.167"
vm-memory = { workspace = true }
[target.'cfg(target_arch = "aarch64")'.dependencies]
[target.'cfg(any(target_arch = "aarch64", target_arch = "riscv64"))'.dependencies]
arch = { path = "../arch" }

View File

@@ -62,7 +62,7 @@ impl GsiAllocator {
allocator
}
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
/// New GSI allocator
pub fn new() -> Self {
GsiAllocator {
@@ -97,7 +97,7 @@ impl GsiAllocator {
Ok(irq)
}
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
/// Allocate an IRQ
pub fn allocate_irq(&mut self) -> Result<u32> {
let irq = self.next_irq;
@@ -106,7 +106,7 @@ impl GsiAllocator {
}
}
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
impl Default for GsiAllocator {
fn default() -> Self {
GsiAllocator::new()

View File

@@ -21,3 +21,5 @@ pub use crate::gsi::GsiAllocator;
#[cfg(target_arch = "x86_64")]
pub use crate::gsi::GsiApic;
pub use crate::system::SystemAllocator;
mod memory_slot;
pub use memory_slot::MemorySlotAllocator;

View File

@@ -0,0 +1,39 @@
// Copyright © 2024 Rivos Inc
//
// SPDX-License-Identifier: Apache-2.0
//
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{Arc, Mutex};
/// Allocator for KVM memory slots
pub struct MemorySlotAllocator {
next_memory_slot: Arc<AtomicU32>,
memory_slot_free_list: Arc<Mutex<Vec<u32>>>,
}
impl MemorySlotAllocator {
/// Next free memory slot
pub fn next_memory_slot(&self) -> u32 {
if let Some(slot_id) = self.memory_slot_free_list.lock().unwrap().pop() {
return slot_id;
}
self.next_memory_slot.fetch_add(1, Ordering::SeqCst)
}
/// Release memory slot for reuse
pub fn free_memory_slot(&mut self, slot: u32) {
self.memory_slot_free_list.lock().unwrap().push(slot)
}
/// Instantiate struct
pub fn new(
next_memory_slot: Arc<AtomicU32>,
memory_slot_free_list: Arc<Mutex<Vec<u32>>>,
) -> Self {
Self {
next_memory_slot,
memory_slot_free_list,
}
}
}

View File

@@ -22,27 +22,30 @@ use crate::page_size::get_page_size;
/// ```
/// # #[cfg(target_arch = "x86_64")]
/// # use vm_allocator::{GsiApic, SystemAllocator};
/// # #[cfg(target_arch = "aarch64")]
/// # #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
/// # use vm_allocator::SystemAllocator;
/// # use vm_memory::{Address, GuestAddress, GuestUsize};
/// let mut allocator = SystemAllocator::new(
/// #[cfg(target_arch = "x86_64")] GuestAddress(0x1000),
/// #[cfg(target_arch = "x86_64")] 0x10000,
/// GuestAddress(0x1000),
/// 0x10000,
/// GuestAddress(0x10000000), 0x10000000,
/// #[cfg(target_arch = "x86_64")] vec![GsiApic::new(5, 19)]).unwrap();
/// #[cfg(target_arch = "x86_64")]
/// assert_eq!(allocator.allocate_irq(), Some(5));
/// #[cfg(target_arch = "aarch64")]
/// assert_eq!(allocator.allocate_irq(), Some(32));
/// #[cfg(target_arch = "riscv64")]
/// assert_eq!(allocator.allocate_irq(), Some(0));
/// #[cfg(target_arch = "x86_64")]
/// assert_eq!(allocator.allocate_irq(), Some(6));
/// #[cfg(target_arch = "aarch64")]
/// assert_eq!(allocator.allocate_irq(), Some(33));
/// #[cfg(target_arch = "riscv64")]
/// assert_eq!(allocator.allocate_irq(), Some(1));
/// assert_eq!(allocator.allocate_platform_mmio_addresses(None, 0x1000, Some(0x1000)), Some(GuestAddress(0x1fff_f000)));
///
/// ```
pub struct SystemAllocator {
#[cfg(target_arch = "x86_64")]
io_address_space: AddressAllocator,
platform_mmio_address_space: AddressAllocator,
gsi_allocator: GsiAllocator,
@@ -59,14 +62,13 @@ impl SystemAllocator {
/// * `apics` - (X86) Vector of APIC's.
///
pub fn new(
#[cfg(target_arch = "x86_64")] io_base: GuestAddress,
#[cfg(target_arch = "x86_64")] io_size: GuestUsize,
io_base: GuestAddress,
io_size: GuestUsize,
platform_mmio_base: GuestAddress,
platform_mmio_size: GuestUsize,
#[cfg(target_arch = "x86_64")] apics: Vec<GsiApic>,
) -> Option<Self> {
Some(SystemAllocator {
#[cfg(target_arch = "x86_64")]
io_address_space: AddressAllocator::new(io_base, io_size)?,
platform_mmio_address_space: AddressAllocator::new(
platform_mmio_base,
@@ -74,7 +76,7 @@ impl SystemAllocator {
)?,
#[cfg(target_arch = "x86_64")]
gsi_allocator: GsiAllocator::new(apics),
#[cfg(target_arch = "aarch64")]
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
gsi_allocator: GsiAllocator::new(),
})
}
@@ -89,7 +91,6 @@ impl SystemAllocator {
self.gsi_allocator.allocate_gsi().ok()
}
#[cfg(target_arch = "x86_64")]
/// Reserves a section of `size` bytes of IO address space.
pub fn allocate_io_addresses(
&mut self,
@@ -115,7 +116,6 @@ impl SystemAllocator {
)
}
#[cfg(target_arch = "x86_64")]
/// Free an IO address range.
/// We can only free a range if it matches exactly an already allocated range.
pub fn free_io_addresses(&mut self, address: GuestAddress, size: GuestUsize) {

View File

@@ -10,7 +10,7 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"]
[dependencies]
anyhow = "1.0.87"
anyhow = "1.0.94"
hypervisor = { path = "../hypervisor" }
serde = { version = "1.0.208", features = ["derive", "rc"] }
thiserror = "1.0.62"

View File

@@ -5,7 +5,7 @@ name = "vm-migration"
version = "0.1.0"
[dependencies]
anyhow = "1.0.87"
anyhow = "1.0.94"
serde = { version = "1.0.208", features = ["derive", "rc"] }
serde_json = "1.0.120"
thiserror = "1.0.62"

View File

@@ -26,7 +26,7 @@ tracing = ["tracer/tracing"]
[dependencies]
acpi_tables = { workspace = true }
anyhow = "1.0.87"
anyhow = "1.0.94"
arc-swap = "1.7.1"
arch = { path = "../arch" }
bitflags = "2.6.0"
@@ -38,7 +38,7 @@ devices = { path = "../devices" }
dhat = { version = "0.3.3", optional = true }
epoll = "4.3.3"
event_monitor = { path = "../event_monitor" }
flume = "0.11.0"
flume = "0.11.1"
futures = { version = "0.3.30", optional = true }
gdbstub = { version = "0.7.1", optional = true }
gdbstub_arch = { version = "0.3.0", optional = true }
@@ -47,7 +47,7 @@ hypervisor = { path = "../hypervisor" }
igvm = { version = "0.3.3", optional = true }
igvm_defs = { version = "0.3.1", optional = true }
landlock = "0.4.0"
libc = "0.2.158"
libc = "0.2.167"
linux-loader = { workspace = true, features = ["bzimage", "elf", "pe"] }
log = "0.4.22"
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }

View File

@@ -1144,7 +1144,8 @@ impl DiskConfig {
bw_size=<bytes>,bw_one_time_burst=<bytes>,bw_refill_time=<ms>,\
ops_size=<io_ops>,ops_one_time_burst=<io_ops>,ops_refill_time=<ms>,\
id=<device_id>,pci_segment=<segment_id>,rate_limit_group=<group_id>,\
queue_affinity=<list_of_queue_indices_with_their_associated_cpuset>";
queue_affinity=<list_of_queue_indices_with_their_associated_cpuset>,\
serial=<serial_number>";
pub fn parse(disk: &str) -> Result<Self> {
let mut parser = OptionParser::new();

View File

@@ -536,7 +536,6 @@ impl Console {
pub(crate) struct AddressManager {
pub(crate) allocator: Arc<Mutex<SystemAllocator>>,
#[cfg(target_arch = "x86_64")]
pub(crate) io_bus: Arc<Bus>,
pub(crate) mmio_bus: Arc<Bus>,
pub(crate) vm: Arc<dyn hypervisor::Vm>,
@@ -556,33 +555,24 @@ impl DeviceRelocation for AddressManager {
) -> std::result::Result<(), std::io::Error> {
match region_type {
PciBarRegionType::IoRegion => {
#[cfg(target_arch = "x86_64")]
{
// Update system allocator
self.allocator
.lock()
.unwrap()
.free_io_addresses(GuestAddress(old_base), len as GuestUsize);
// Update system allocator
self.allocator
.lock()
.unwrap()
.free_io_addresses(GuestAddress(old_base), len as GuestUsize);
self.allocator
.lock()
.unwrap()
.allocate_io_addresses(
Some(GuestAddress(new_base)),
len as GuestUsize,
None,
)
.ok_or_else(|| {
io::Error::new(io::ErrorKind::Other, "failed allocating new IO range")
})?;
self.allocator
.lock()
.unwrap()
.allocate_io_addresses(Some(GuestAddress(new_base)), len as GuestUsize, None)
.ok_or_else(|| {
io::Error::new(io::ErrorKind::Other, "failed allocating new IO range")
})?;
// Update PIO bus
self.io_bus
.update_range(old_base, len, new_base, len)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
}
#[cfg(target_arch = "aarch64")]
error!("I/O region is not supported");
// Update PIO bus
self.io_bus
.update_range(old_base, len, new_base, len)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
}
PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
let allocators = if region_type == PciBarRegionType::Memory32BitRegion {
@@ -992,7 +982,7 @@ fn create_mmio_allocators(
impl DeviceManager {
#[allow(clippy::too_many_arguments)]
pub fn new(
#[cfg(target_arch = "x86_64")] io_bus: Arc<Bus>,
io_bus: Arc<Bus>,
mmio_bus: Arc<Bus>,
vm: Arc<dyn hypervisor::Vm>,
config: Arc<Mutex<VmConfig>>,
@@ -1072,7 +1062,6 @@ impl DeviceManager {
let address_manager = Arc::new(AddressManager {
allocator: memory_manager.lock().unwrap().allocator(),
#[cfg(target_arch = "x86_64")]
io_bus,
mmio_bus,
vm: vm.clone(),
@@ -3432,7 +3421,7 @@ impl DeviceManager {
legacy_interrupt_group,
device_cfg.iommu,
pci_device_bdf,
Arc::new(move || memory_manager.lock().unwrap().allocate_memory_slot()),
memory_manager.lock().unwrap().memory_slot_allocator(),
vm_migration::snapshot_from_id(self.snapshot.as_ref(), vfio_name.as_str()),
device_cfg.x_nv_gpudirect_clique,
)
@@ -3512,7 +3501,6 @@ impl DeviceManager {
pci_bus
.register_mapping(
bus_device,
#[cfg(target_arch = "x86_64")]
self.address_manager.io_bus.as_ref(),
self.address_manager.mmio_bus.as_ref(),
bars.clone(),
@@ -3596,7 +3584,7 @@ impl DeviceManager {
self.msi_interrupt_manager.clone(),
legacy_interrupt_group,
pci_device_bdf,
Arc::new(move || memory_manager.lock().unwrap().allocate_memory_slot()),
memory_manager.lock().unwrap().memory_slot_allocator(),
vm_migration::snapshot_from_id(self.snapshot.as_ref(), vfio_user_name.as_str()),
)
.map_err(DeviceManagerError::VfioUserCreate)?;

View File

@@ -11,6 +11,7 @@ extern crate log;
use std::collections::HashMap;
use std::fs::File;
use std::io::{stdout, Read, Write};
use std::net::{TcpListener, TcpStream};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::os::unix::net::{UnixListener, UnixStream};
use std::panic::AssertUnwindSafe;
@@ -36,8 +37,8 @@ use serde::{Deserialize, Serialize};
use signal_hook::iterator::{Handle, Signals};
use thiserror::Error;
use tracer::trace_scoped;
use vm_memory::bitmap::AtomicBitmap;
use vm_memory::{ReadVolatile, WriteVolatile};
use vm_memory::bitmap::{AtomicBitmap, BitmapSlice};
use vm_memory::{ReadVolatile, VolatileMemoryError, VolatileSlice, WriteVolatile};
use vm_migration::protocol::*;
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
use vmm_sys_util::eventfd::EventFd;
@@ -235,6 +236,89 @@ impl From<u64> for EpollDispatch {
}
}
enum SocketStream {
Unix(UnixStream),
Tcp(TcpStream),
}
impl Read for SocketStream {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self {
SocketStream::Unix(stream) => stream.read(buf),
SocketStream::Tcp(stream) => stream.read(buf),
}
}
}
impl Write for SocketStream {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
match self {
SocketStream::Unix(stream) => stream.write(buf),
SocketStream::Tcp(stream) => stream.write(buf),
}
}
fn flush(&mut self) -> std::io::Result<()> {
match self {
SocketStream::Unix(stream) => stream.flush(),
SocketStream::Tcp(stream) => stream.flush(),
}
}
}
impl AsRawFd for SocketStream {
fn as_raw_fd(&self) -> RawFd {
match self {
SocketStream::Unix(s) => s.as_raw_fd(),
SocketStream::Tcp(s) => s.as_raw_fd(),
}
}
}
impl ReadVolatile for SocketStream {
fn read_volatile<B: BitmapSlice>(
&mut self,
buf: &mut VolatileSlice<B>,
) -> std::result::Result<usize, VolatileMemoryError> {
match self {
SocketStream::Unix(s) => s.read_volatile(buf),
SocketStream::Tcp(s) => s.read_volatile(buf),
}
}
fn read_exact_volatile<B: BitmapSlice>(
&mut self,
buf: &mut VolatileSlice<B>,
) -> std::result::Result<(), VolatileMemoryError> {
match self {
SocketStream::Unix(s) => s.read_exact_volatile(buf),
SocketStream::Tcp(s) => s.read_exact_volatile(buf),
}
}
}
impl WriteVolatile for SocketStream {
fn write_volatile<B: BitmapSlice>(
&mut self,
buf: &VolatileSlice<B>,
) -> std::result::Result<usize, VolatileMemoryError> {
match self {
SocketStream::Unix(s) => s.write_volatile(buf),
SocketStream::Tcp(s) => s.write_volatile(buf),
}
}
fn write_all_volatile<B: BitmapSlice>(
&mut self,
buf: &VolatileSlice<B>,
) -> std::result::Result<(), VolatileMemoryError> {
match self {
SocketStream::Unix(s) => s.write_all_volatile(buf),
SocketStream::Tcp(s) => s.write_all_volatile(buf),
}
}
}
pub struct EpollContext {
epoll_file: File,
}
@@ -786,6 +870,8 @@ impl Vmm {
false,
#[cfg(feature = "sev_snp")]
false,
#[cfg(feature = "sev_snp")]
config.lock().unwrap().memory.total_size(),
)
.map_err(|e| {
MigratableError::MigrateReceive(anyhow!(
@@ -919,14 +1005,72 @@ impl Vmm {
.map(|s| s.into())
}
fn send_migration_socket(
destination_url: &str,
) -> std::result::Result<SocketStream, MigratableError> {
if let Some(address) = destination_url.strip_prefix("tcp:") {
info!("Connecting to TCP socket at {}", address);
let socket = TcpStream::connect(address).map_err(|e| {
MigratableError::MigrateSend(anyhow!("Error connecting to TCP socket: {}", e))
})?;
Ok(SocketStream::Tcp(socket))
} else {
let path = Vmm::socket_url_to_path(destination_url)?;
info!("Connecting to UNIX socket at {:?}", path);
let socket = UnixStream::connect(&path).map_err(|e| {
MigratableError::MigrateSend(anyhow!("Error connecting to UNIX socket: {}", e))
})?;
Ok(SocketStream::Unix(socket))
}
}
fn receive_migration_socket(
receiver_url: &str,
) -> std::result::Result<SocketStream, MigratableError> {
if let Some(address) = receiver_url.strip_prefix("tcp:") {
let listener = TcpListener::bind(address).map_err(|e| {
MigratableError::MigrateReceive(anyhow!("Error binding to TCP socket: {}", e))
})?;
let (socket, _addr) = listener.accept().map_err(|e| {
MigratableError::MigrateReceive(anyhow!(
"Error accepting connection on TCP socket: {}",
e
))
})?;
Ok(SocketStream::Tcp(socket))
} else {
let path = Vmm::socket_url_to_path(receiver_url)?;
let listener = UnixListener::bind(&path).map_err(|e| {
MigratableError::MigrateReceive(anyhow!("Error binding to UNIX socket: {}", e))
})?;
let (socket, _addr) = listener.accept().map_err(|e| {
MigratableError::MigrateReceive(anyhow!(
"Error accepting connection on UNIX socket: {}",
e
))
})?;
// Remove the UNIX socket file after accepting the connection
std::fs::remove_file(&path).map_err(|e| {
MigratableError::MigrateReceive(anyhow!("Error removing UNIX socket file: {}", e))
})?;
Ok(SocketStream::Unix(socket))
}
}
// Returns true if there were dirty pages to send
fn vm_maybe_send_dirty_pages<T>(
fn vm_maybe_send_dirty_pages(
vm: &mut Vm,
socket: &mut T,
) -> result::Result<bool, MigratableError>
where
T: Read + Write + WriteVolatile,
{
socket: &mut SocketStream,
) -> result::Result<bool, MigratableError> {
// Send (dirty) memory table
let table = vm.dirty_log()?;
@@ -954,10 +1098,8 @@ impl Vmm {
>,
send_data_migration: VmSendMigrationData,
) -> result::Result<(), MigratableError> {
let path = Self::socket_url_to_path(&send_data_migration.destination_url)?;
let mut socket = UnixStream::connect(path).map_err(|e| {
MigratableError::MigrateSend(anyhow!("Error connecting to UNIX socket: {}", e))
})?;
// Set up the socket connection
let mut socket = Self::send_migration_socket(&send_data_migration.destination_url)?;
// Start the migration
Request::start().write_to(&mut socket)?;
@@ -997,7 +1139,17 @@ impl Vmm {
};
if send_data_migration.local {
vm.send_memory_fds(&mut socket)?;
match &mut socket {
SocketStream::Unix(unix_socket) => {
// Proceed with sending memory file descriptors over UNIX socket
vm.send_memory_fds(unix_socket)?;
}
SocketStream::Tcp(_tcp_socket) => {
return Err(MigratableError::MigrateSend(anyhow!(
"--local option is not supported with TCP sockets",
)));
}
}
}
let vm_migration_config = VmMigrationConfig {
@@ -1958,16 +2110,8 @@ impl RequestHandler for Vmm {
receive_data_migration.receiver_url
);
let path = Self::socket_url_to_path(&receive_data_migration.receiver_url)?;
let listener = UnixListener::bind(&path).map_err(|e| {
MigratableError::MigrateReceive(anyhow!("Error binding to UNIX socket: {}", e))
})?;
let (mut socket, _addr) = listener.accept().map_err(|e| {
MigratableError::MigrateReceive(anyhow!("Error accepting on UNIX socket: {}", e))
})?;
std::fs::remove_file(&path).map_err(|e| {
MigratableError::MigrateReceive(anyhow!("Error unlinking UNIX socket: {}", e))
})?;
// Accept the connection and get the socket
let mut socket = Vmm::receive_migration_socket(&receive_data_migration.receiver_url)?;
let mut started = false;
let mut memory_manager: Option<Arc<Mutex<MemoryManager>>> = None;
@@ -2035,24 +2179,35 @@ impl RequestHandler for Vmm {
continue;
}
let mut buf = [0u8; 4];
let (_, file) = socket.recv_with_fd(&mut buf).map_err(|e| {
MigratableError::MigrateReceive(anyhow!(
"Error receiving slot from socket: {}",
e
))
})?;
match &mut socket {
SocketStream::Unix(unix_socket) => {
let mut buf = [0u8; 4];
let (_, file) = unix_socket.recv_with_fd(&mut buf).map_err(|e| {
MigratableError::MigrateReceive(anyhow!(
"Error receiving slot from socket: {}",
e
))
})?;
if existing_memory_files.is_none() {
existing_memory_files = Some(HashMap::default())
if existing_memory_files.is_none() {
existing_memory_files = Some(HashMap::default())
}
if let Some(ref mut existing_memory_files) = existing_memory_files {
let slot = u32::from_le_bytes(buf);
existing_memory_files.insert(slot, file.unwrap());
}
Response::ok().write_to(&mut socket)?;
}
SocketStream::Tcp(_tcp_socket) => {
// For TCP sockets, we cannot transfer file descriptors
warn!(
"MemoryFd command received over TCP socket, which is not supported"
);
Response::error().write_to(&mut socket)?;
}
}
if let Some(ref mut existing_memory_files) = existing_memory_files {
let slot = u32::from_le_bytes(buf);
existing_memory_files.insert(slot, file.unwrap());
}
Response::ok().write_to(&mut socket)?;
}
Command::Complete => {
info!("Complete Command Received");

View File

@@ -13,6 +13,7 @@ use std::ops::{BitAnd, Deref, Not, Sub};
use std::os::fd::AsFd;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::path::PathBuf;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{Arc, Barrier, Mutex};
use std::{ffi, result, thread};
@@ -33,7 +34,7 @@ use tracer::trace_scoped;
use virtio_devices::BlocksState;
#[cfg(target_arch = "x86_64")]
use vm_allocator::GsiApic;
use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_allocator::{AddressAllocator, MemorySlotAllocator, SystemAllocator};
use vm_device::BusDevice;
use vm_memory::bitmap::AtomicBitmap;
use vm_memory::guest_memory::FileOffset;
@@ -162,7 +163,8 @@ struct ArchMemRegion {
pub struct MemoryManager {
boot_guest_memory: GuestMemoryMmap,
guest_memory: GuestMemoryAtomic<GuestMemoryMmap>,
next_memory_slot: u32,
next_memory_slot: Arc<AtomicU32>,
memory_slot_free_list: Arc<Mutex<Vec<u32>>>,
start_of_device_area: GuestAddress,
end_of_device_area: GuestAddress,
end_of_ram_area: GuestAddress,
@@ -1155,17 +1157,10 @@ impl MemoryManager {
let guest_memory = GuestMemoryAtomic::new(guest_memory);
// Both MMIO and PIO address spaces start at address 0.
let allocator = Arc::new(Mutex::new(
SystemAllocator::new(
#[cfg(target_arch = "x86_64")]
{
GuestAddress(0)
},
#[cfg(target_arch = "x86_64")]
{
1 << 16
},
GuestAddress(0),
1 << 16,
start_of_platform_device_area,
PLATFORM_DEVICE_AREA_SIZE,
#[cfg(target_arch = "x86_64")]
@@ -1205,7 +1200,8 @@ impl MemoryManager {
let mut memory_manager = MemoryManager {
boot_guest_memory,
guest_memory,
next_memory_slot,
next_memory_slot: Arc::new(AtomicU32::new(next_memory_slot)),
memory_slot_free_list: Arc::new(Mutex::new(Vec::new())),
start_of_device_area,
end_of_device_area,
end_of_ram_area,
@@ -1729,10 +1725,14 @@ impl MemoryManager {
self.end_of_device_area
}
pub fn memory_slot_allocator(&mut self) -> MemorySlotAllocator {
let memory_slot_free_list = Arc::clone(&self.memory_slot_free_list);
let next_memory_slot = Arc::clone(&self.next_memory_slot);
MemorySlotAllocator::new(next_memory_slot, memory_slot_free_list)
}
pub fn allocate_memory_slot(&mut self) -> u32 {
let slot_id = self.next_memory_slot;
self.next_memory_slot += 1;
slot_id
self.memory_slot_allocator().next_memory_slot()
}
pub fn create_userspace_mapping(
@@ -2120,7 +2120,7 @@ impl MemoryManager {
current_ram: self.current_ram,
arch_mem_regions: self.arch_mem_regions.clone(),
hotplug_slots: self.hotplug_slots.clone(),
next_memory_slot: self.next_memory_slot,
next_memory_slot: self.next_memory_slot.load(Ordering::SeqCst),
selected_slot: self.selected_slot,
next_hotplug_slot: self.next_hotplug_slot,
}

View File

@@ -531,7 +531,6 @@ impl Vm {
let stop_on_boot = false;
let memory = memory_manager.lock().unwrap().guest_memory();
#[cfg(target_arch = "x86_64")]
let io_bus = Arc::new(Bus::new());
let mmio_bus = Arc::new(Bus::new());
@@ -622,7 +621,6 @@ impl Vm {
let dynamic = true;
let device_manager = DeviceManager::new(
#[cfg(target_arch = "x86_64")]
io_bus,
mmio_bus,
vm.clone(),
@@ -827,6 +825,8 @@ impl Vm {
tdx_enabled,
#[cfg(feature = "sev_snp")]
sev_snp_enabled,
#[cfg(feature = "sev_snp")]
vm_config.lock().unwrap().memory.total_size(),
)?;
let phys_bits = physical_bits(&hypervisor, vm_config.lock().unwrap().cpus.max_phys_bits);
@@ -885,6 +885,7 @@ impl Vm {
hypervisor: &Arc<dyn hypervisor::Hypervisor>,
#[cfg(feature = "tdx")] tdx_enabled: bool,
#[cfg(feature = "sev_snp")] sev_snp_enabled: bool,
#[cfg(feature = "sev_snp")] mem_size: u64,
) -> Result<Arc<dyn hypervisor::Vm>> {
hypervisor.check_required_extensions().unwrap();
@@ -901,7 +902,7 @@ impl Vm {
// Otherwise SEV_SNP_DISABLED: 0
// value of sev_snp_enabled is mapped to SEV_SNP_ENABLED for true or SEV_SNP_DISABLED for false
let vm = hypervisor
.create_vm_with_type(u64::from(sev_snp_enabled))
.create_vm_with_type_and_memory(u64::from(sev_snp_enabled), mem_size)
.unwrap();
} else {
let vm = hypervisor.create_vm().unwrap();